From d1b9f9b3e640ccf688af7cbd2d34d07589a6f1ac Mon Sep 17 00:00:00 2001 From: HLWeil Date: Tue, 6 Aug 2024 13:46:44 +0200 Subject: [PATCH] fix multi annotationTable writing and unify API #423 --- src/ARCtrl/ARC.fs | 4 +- src/Spreadsheet/AnnotationTable/ArcTable.fs | 10 ++- src/Spreadsheet/ArcAssay.fs | 10 ++- src/Spreadsheet/ArcInvestigation.fs | 67 ++++++++++++------- src/Spreadsheet/ArcStudy.fs | 7 +- src/Spreadsheet/Template.fs | 4 +- tests/Spreadsheet/ArcTableTests.fs | 22 +++--- .../Spreadsheet.Study.fs | 4 +- 8 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs index 02901a93..b0bebd84 100644 --- a/src/ARCtrl/ARC.fs +++ b/src/ARCtrl/ARC.fs @@ -329,7 +329,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) = let workbooks = System.Collections.Generic.Dictionary() match this.ISA with | Some inv -> - let investigationConverter = Spreadsheet.ArcInvestigation.toFsWorkbook + let investigationConverter = ArcInvestigation.toFsWorkbook workbooks.Add (InvestigationFileName, (DTOType.ISA_Investigation, investigationConverter inv)) inv.StaticHash <- inv.GetLightHashCode() inv.Studies @@ -365,7 +365,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) = | None -> //printfn "ARC contains no ISA part." - workbooks.Add (InvestigationFileName, (DTOType.ISA_Investigation, Spreadsheet.ArcInvestigation.toFsWorkbook (ArcInvestigation.create(Identifier.MISSING_IDENTIFIER)))) + workbooks.Add (InvestigationFileName, (DTOType.ISA_Investigation, ArcInvestigation.toFsWorkbook (ArcInvestigation.create(Identifier.MISSING_IDENTIFIER)))) // Iterates over filesystem and creates a write contract for every file. If possible, include DTO. _fs.Tree.ToFilePaths(true) diff --git a/src/Spreadsheet/AnnotationTable/ArcTable.fs b/src/Spreadsheet/AnnotationTable/ArcTable.fs index 2bdd3a69..89832e97 100644 --- a/src/Spreadsheet/AnnotationTable/ArcTable.fs +++ b/src/Spreadsheet/AnnotationTable/ArcTable.fs @@ -1,4 +1,4 @@ -module ARCtrl.Spreadsheet.ArcTable +module ARCtrl.Spreadsheet.ArcTable open ARCtrl open ARCtrl.Helper @@ -121,7 +121,7 @@ let tryFromFsWorksheet (sheet : FsWorksheet) = | err -> failwithf "Could not parse table with name \"%s\":\n%s" sheet.Name err.Message -let toFsWorksheet (table : ArcTable) = +let toFsWorksheet (index : int option) (table : ArcTable) = /// This dictionary is used to add spaces at the end of duplicate headers. let stringCount = System.Collections.Generic.Dictionary() let ws = FsWorksheet(table.Name) @@ -137,7 +137,11 @@ let toFsWorksheet (table : ArcTable) = |> List.collect CompositeColumn.toStringCellColumns let maxRow = columns.Head.Length let maxCol = columns.Length - let fsTable = ws.Table("annotationTable",FsRangeAddress(FsAddress(1,1),FsAddress(maxRow,maxCol))) + let name = + match index with + | Some i -> $"{annotationTablePrefix}{i}" + | None -> annotationTablePrefix + let fsTable = ws.Table(name,FsRangeAddress(FsAddress(1,1),FsAddress(maxRow,maxCol))) columns |> List.iteri (fun colI col -> col diff --git a/src/Spreadsheet/ArcAssay.fs b/src/Spreadsheet/ArcAssay.fs index e737cb17..287ce5de 100644 --- a/src/Spreadsheet/ArcAssay.fs +++ b/src/Spreadsheet/ArcAssay.fs @@ -133,6 +133,12 @@ module ArcAssayExtensions = |> Option.iter (DataMapTable.toFsWorksheet >> doc.AddWorksheet) assay.Tables - |> Seq.iter (ArcTable.toFsWorksheet >> doc.AddWorksheet) + |> Seq.iteri (fun i -> ArcTable.toFsWorksheet (Some i) >> doc.AddWorksheet) - doc \ No newline at end of file + doc + + /// Write an assay to a spreadsheet + /// + /// If datamapSheet is true, the datamap will be written to a worksheet inside assay workbook. + member this.ToFsWorkbook (?datamapSheet: bool) = + ArcAssay.toFsWorkbook (this, ?datamapSheet = datamapSheet) \ No newline at end of file diff --git a/src/Spreadsheet/ArcInvestigation.fs b/src/Spreadsheet/ArcInvestigation.fs index 588549c4..8e008d53 100644 --- a/src/Spreadsheet/ArcInvestigation.fs +++ b/src/Spreadsheet/ArcInvestigation.fs @@ -24,8 +24,8 @@ module ArcInvestigation = let [] publicationsLabelPrefix = "Investigation Publication" let [] contactsLabelPrefix = "Investigation Person" - let [] metaDataSheetName = "isa_investigation" - let [] metaDataSheetName_deprecated = "Investigation" + let [] metadataSheetName = "isa_investigation" + let [] obsoleteMetadataSheetName = "Investigation" type InvestigationInfo = @@ -202,28 +202,45 @@ module ArcInvestigation = |> insertRemarks (List.ofSeq investigation.Remarks) |> seq - let fromFsWorkbook (doc:FsWorkbook) = - try - match doc.TryGetWorksheetByName metaDataSheetName with - | Some sheet -> sheet - | None -> - match doc.TryGetWorksheetByName metaDataSheetName_deprecated with + let isMetadataSheetName (name : string) = + name = metadataSheetName || name = obsoleteMetadataSheetName + + let isMetadataSheet (sheet : FsWorksheet) = + isMetadataSheetName sheet.Name + + let tryGetMetadataSheet (doc:FsWorkbook) = + doc.GetWorksheets() + |> Seq.tryFind isMetadataSheet + + +[] +module ArcInvestigationExtensions = + + open ArcInvestigation + + type ArcInvestigation with + + static member fromFsWorkbook (doc:FsWorkbook) = + try + match ArcInvestigation.tryGetMetadataSheet doc with | Some sheet -> sheet | None -> failwith "Could not find metadata sheet with sheetname \"isa_investigation\" or deprecated sheetname \"Investigation\"" - |> FsWorksheet.getRows - |> Seq.map SparseRow.fromFsRow - |> fromRows - with - | err -> failwithf "Could not read investigation from spreadsheet: %s" err.Message - - let toFsWorkbook (investigation:ArcInvestigation) : FsWorkbook = - try - let wb = new FsWorkbook() - let sheet = FsWorksheet(metaDataSheetName) - investigation - |> toRows - |> Seq.iteri (fun rowI r -> SparseRow.writeToSheet (rowI + 1) r sheet) - wb.AddWorksheet(sheet) - wb - with - | err -> failwithf "Could not write investigation to spreadsheet: %s" err.Message + |> FsWorksheet.getRows + |> Seq.map SparseRow.fromFsRow + |> fromRows + with + | err -> failwithf "Could not read investigation from spreadsheet: %s" err.Message + + static member toFsWorkbook (investigation:ArcInvestigation) : FsWorkbook = + try + let wb = new FsWorkbook() + let sheet = FsWorksheet(metadataSheetName) + investigation + |> toRows + |> Seq.iteri (fun rowI r -> SparseRow.writeToSheet (rowI + 1) r sheet) + wb.AddWorksheet(sheet) + wb + with + | err -> failwithf "Could not write investigation to spreadsheet: %s" err.Message + + member this.ToFsWorkbook() = ArcInvestigation.toFsWorkbook this \ No newline at end of file diff --git a/src/Spreadsheet/ArcStudy.fs b/src/Spreadsheet/ArcStudy.fs index cb6420da..c8e7e321 100644 --- a/src/Spreadsheet/ArcStudy.fs +++ b/src/Spreadsheet/ArcStudy.fs @@ -108,6 +108,9 @@ module ArcStudyExtensions = |> Option.iter (DataMapTable.toFsWorksheet >> doc.AddWorksheet) study.Tables - |> ResizeArray.iter (ArcTable.toFsWorksheet >> doc.AddWorksheet) + |> Seq.iteri (fun i -> ArcTable.toFsWorksheet (Some i) >> doc.AddWorksheet) - doc \ No newline at end of file + doc + + member this.ToFsWorkbook (?assays : ArcAssay list, ?datamapSheet: bool) = + ArcStudy.toFsWorkbook (this, ?assays = assays, ?datamapSheet = datamapSheet) \ No newline at end of file diff --git a/src/Spreadsheet/Template.fs b/src/Spreadsheet/Template.fs index c0d6154e..063b994d 100644 --- a/src/Spreadsheet/Template.fs +++ b/src/Spreadsheet/Template.fs @@ -1,4 +1,4 @@ -namespace ARCtrl.Spreadsheet +namespace ARCtrl.Spreadsheet open FsSpreadsheet open ARCtrl.Helper @@ -300,7 +300,7 @@ module Template = doc.AddWorksheet metaDataSheet template.Table - |> ArcTable.toFsWorksheet + |> ArcTable.toFsWorksheet None |> doc.AddWorksheet doc diff --git a/tests/Spreadsheet/ArcTableTests.fs b/tests/Spreadsheet/ArcTableTests.fs index c7ce677c..4cecbcaf 100644 --- a/tests/Spreadsheet/ArcTableTests.fs +++ b/tests/Spreadsheet/ArcTableTests.fs @@ -13,13 +13,13 @@ let private dataColumnsTable = testCase "Only Freetext" <| fun _ -> let table = ArcTable.init("MyTable") table.AddColumn(CompositeHeader.Input(IOType.Data), [|for i in 1 .. 5 do mkInputStr i |> CompositeCell.FreeText|]) - let fsws = ArcTable.toFsWorksheet table + let fsws = ArcTable.toFsWorksheet None table let actualColValues = (fsws.Column(1).Cells |> Seq.map (fun c -> c.ValueAsString())) Expect.sequenceEqual actualColValues ["Input [Data]"; "Input_1"; "Input_2"; "Input_3"; "Input_4"; "Input_5"] "" testCase "Only Data" <| fun _ -> let table = ArcTable.init("MyTable") table.AddColumn(CompositeHeader.Input(IOType.Data), [|for i in 1 .. 5 do CompositeCell.createData (Data(name = mkDataNameStr i, format = "text/csv", selectorFormat = "MySelector"))|]) - let fsws = ArcTable.toFsWorksheet table + let fsws = ArcTable.toFsWorksheet None table fsws.RescanRows() let rows = fsws.Rows |> Seq.map (fun x -> x.Cells |> Seq.map (fun c -> c.ValueAsString()) |> Array.ofSeq) |> Array.ofSeq Expect.equal rows.[0].Length 3 "col count" @@ -37,7 +37,7 @@ let private dataColumnsTable = mkInputStr i |> CompositeCell.FreeText |] ) - let fsws = ArcTable.toFsWorksheet table + let fsws = ArcTable.toFsWorksheet None table fsws.RescanRows() let rows = fsws.Rows |> Seq.map (fun x -> x.Cells |> Seq.map (fun c -> c.ValueAsString()) |> Array.ofSeq) |> Array.ofSeq Expect.equal rows.[0].Length 3 "col count" @@ -170,7 +170,7 @@ let private simpleTable = let table = ArcTable.tryFromFsWorksheet ws Expect.isSome table "Table was not created" - let out = ArcTable.toFsWorksheet table.Value + let out = ArcTable.toFsWorksheet None table.Value Expect.workSheetEqual out ws "Worksheet was not correctly written" ) @@ -262,7 +262,7 @@ let private mixedTable = let table = ArcTable.tryFromFsWorksheet ws Expect.isSome table "Table was not created" - let out = ArcTable.toFsWorksheet table.Value + let out = ArcTable.toFsWorksheet None table.Value Expect.workSheetEqual out ws "Worksheet was not correctly written" ) @@ -317,7 +317,7 @@ let private ioTable = let table = ArcTable.tryFromFsWorksheet ws Expect.isSome table "Table was not created" - let out = ArcTable.toFsWorksheet table.Value + let out = ArcTable.toFsWorksheet None table.Value Expect.workSheetEqual out ws "Worksheet was not correctly written" ) @@ -366,7 +366,7 @@ let private fullDataTable = let table = ArcTable.tryFromFsWorksheet ws Expect.isSome table "Table was not created" - let out = ArcTable.toFsWorksheet table.Value + let out = ArcTable.toFsWorksheet None table.Value Expect.workSheetEqual out ws "Worksheet was not correctly written" ) @@ -414,7 +414,7 @@ let private commentTable = let table = ArcTable.tryFromFsWorksheet ws Expect.isSome table "Table was not created" - let out = ArcTable.toFsWorksheet table.Value + let out = ArcTable.toFsWorksheet None table.Value Expect.workSheetEqual out ws "Worksheet was not correctly written" ) @@ -483,7 +483,7 @@ let private writeOrder = ] let mixedTable = ArcTable.tryFromFsWorksheet mixedWs |> Option.get - let mixedOut = ArcTable.toFsWorksheet mixedTable + let mixedOut = ArcTable.toFsWorksheet None mixedTable let orderedWs = initWorksheet wsName @@ -506,12 +506,12 @@ let private emptyTable = let name = "EmptyTable" let t = ArcTable.init(name) testCase "Write" (fun () -> - let sheet = ArcTable.toFsWorksheet t + let sheet = ArcTable.toFsWorksheet None t Expect.equal name sheet.Name "Worksheet name did not match" Expect.equal 0 sheet.Rows.Count "Row count should be 0" ) testCase "Read" (fun () -> - let sheet = ArcTable.toFsWorksheet t + let sheet = ArcTable.toFsWorksheet None t Expect.isNone (ArcTable.tryFromFsWorksheet sheet) "Table was not created" ) ] diff --git a/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.Study.fs b/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.Study.fs index 2a87b144..9d799662 100644 --- a/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.Study.fs +++ b/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.Study.fs @@ -1,4 +1,4 @@ -module TestObjects.Spreadsheet.Study +module TestObjects.Spreadsheet.Study open FsSpreadsheet @@ -539,7 +539,7 @@ module LargeFile = | Some t -> t | None -> createTable() - let fsws_large = Spreadsheet.ArcTable.toFsWorksheet table + let fsws_large = Spreadsheet.ArcTable.toFsWorksheet None table Workbook.AddWorksheet(fsws_large) Workbook.AddWorksheet studyMetadataEmpty