diff --git a/src/ARCtrl/ARC.fs b/src/ARCtrl/ARC.fs
index 9723bd84..b2d80f02 100644
--- a/src/ARCtrl/ARC.fs
+++ b/src/ARCtrl/ARC.fs
@@ -15,28 +15,41 @@ module ARCAux =
contracts
|> Array.choose ArcAssay.tryFromReadContract
+ let getAssayDataMapFromContracts (assayIdentifier) (contracts: Contract []) =
+ contracts
+ |> Array.tryPick (DataMap.tryFromReadContractForAssay assayIdentifier)
// No idea where to move this
let getArcStudiesFromContracts (contracts: Contract []) =
contracts
|> Array.choose ArcStudy.tryFromReadContract
+ let getStudyDataMapFromContracts (studyIdentifier) (contracts: Contract []) =
+ contracts
+ |> Array.tryPick (DataMap.tryFromReadContractForStudy studyIdentifier)
+
let getArcInvestigationFromContracts (contracts: Contract []) =
contracts
|> Array.choose ArcInvestigation.tryFromReadContract
|> Array.exactlyOne
let updateFSByISA (isa : ArcInvestigation option) (fs : FileSystem) =
- let (studyNames,assayNames) =
+ let (studies,assays) =
match isa with
| Some inv ->
- inv.StudyIdentifiers |> Seq.toArray, inv.AssayIdentifiers |> Seq.toArray
+ inv.Studies |> Seq.toArray, inv.Assays |> Seq.toArray
| None -> ([||],[||])
- let assays = FileSystemTree.createAssaysFolder (assayNames |> Array.map FileSystemTree.createAssayFolder)
- let studies = FileSystemTree.createStudiesFolder (studyNames |> Array.map FileSystemTree.createStudyFolder)
+ let assaysFolder =
+ assays
+ |> Array.map (fun a -> FileSystemTree.createAssayFolder(a.Identifier,a.DataMap.IsSome))
+ |> FileSystemTree.createAssaysFolder
+ let studiesFolder =
+ studies
+ |> Array.map (fun s -> FileSystemTree.createStudyFolder(s.Identifier,s.DataMap.IsSome))
+ |> FileSystemTree.createStudiesFolder
let investigation = FileSystemTree.createInvestigationFile()
let tree =
- FileSystemTree.createRootFolder [|investigation;assays;studies|]
+ FileSystemTree.createRootFolder [|investigation;assaysFolder;studiesFolder|]
|> FileSystem.create
fs.Union(tree)
@@ -219,7 +232,7 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) =
investigation.DeleteStudy(si)
)
- studies |> Array.iter (fun study ->
+ studies |> Array.iter (fun study ->
/// Try find registered study in parsed READ contracts
let registeredStudyOpt = investigation.Studies |> Seq.tryFind (fun s -> s.Identifier = study.Identifier)
match registeredStudyOpt with
@@ -227,6 +240,8 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) =
registeredStudy.UpdateReferenceByStudyFile(study,true)
| None ->
investigation.AddStudy(study)
+ let datamap = ARCAux.getAssayDataMapFromContracts study.Identifier contracts
+ study.DataMap <- datamap
study.StaticHash <- study.GetLightHashCode()
)
assays |> Array.iter (fun assay ->
@@ -243,9 +258,11 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) =
|> Array.fold (fun tables study ->
ArcTables.updateReferenceTablesBySheets(ArcTables(study.Tables),tables,false)
) (ArcTables(assay.Tables))
+ let datamap = ARCAux.getAssayDataMapFromContracts assay.Identifier contracts
+ assay.DataMap <- datamap
assay.Tables <- updatedTables.Tables
)
- investigation.Assays |> Seq.iter (fun a -> a.StaticHash <- a.GetHashCode())
+ investigation.Assays |> Seq.iter (fun a -> a.StaticHash <- a.GetLightHashCode())
investigation.Studies |> Seq.iter (fun s -> s.StaticHash <- s.GetLightHashCode())
investigation.StaticHash <- investigation.GetLightHashCode()
this.ISA <- Some investigation
@@ -275,13 +292,28 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) =
Identifier.Study.fileNameFromIdentifier s.Identifier,
(DTOType.ISA_Study, ArcStudy.toFsWorkbook s)
)
+ if s.DataMap.IsSome then
+ let dm = s.DataMap.Value
+ dm.StaticHash <- dm.GetHashCode()
+ workbooks.Add (
+ Identifier.Study.datamapFileNameFromIdentifier s.Identifier,
+ (DTOType.ISA_Datamap, Spreadsheet.DataMap.toFsWorkbook dm)
+ )
+
)
inv.Assays
|> Seq.iter (fun a ->
- a.StaticHash <- a.GetHashCode()
+ a.StaticHash <- a.GetLightHashCode()
workbooks.Add (
Identifier.Assay.fileNameFromIdentifier a.Identifier,
- (DTOType.ISA_Assay, Spreadsheet.ArcAssay.toFsWorkbook a))
+ (DTOType.ISA_Assay, Spreadsheet.ArcAssay.toFsWorkbook a))
+ if a.DataMap.IsSome then
+ let dm = a.DataMap.Value
+ dm.StaticHash <- dm.GetHashCode()
+ workbooks.Add (
+ Identifier.Assay.datamapFileNameFromIdentifier a.Identifier,
+ (DTOType.ISA_Datamap, Spreadsheet.DataMap.toFsWorkbook dm)
+ )
)
| None ->
@@ -329,15 +361,33 @@ type ARC(?isa : ArcInvestigation, ?cwl : CWL.CWL, ?fs : FileSystem.FileSystem) =
elif s.StaticHash <> hash then
yield s.ToUpdateContract()
s.StaticHash <- hash
+
+ match s.DataMap with
+ | Some dm when dm.StaticHash = 0 ->
+ yield dm.ToCreateContractForStudy(s.Identifier)
+ dm.StaticHash <- dm.GetHashCode()
+ | Some dm when dm.StaticHash <> dm.GetHashCode() ->
+ yield dm.ToUpdateContractForStudy(s.Identifier)
+ dm.StaticHash <- dm.GetHashCode()
+ | _ -> ()
// Get Assay contracts
for a in inv.Assays do
- let hash = a.GetHashCode()
+ let hash = a.GetLightHashCode()
if a.StaticHash = 0 then
yield! a.ToCreateContract(WithFolder = true)
elif a.StaticHash <> hash then
yield a.ToUpdateContract()
a.StaticHash <- hash
+
+ match a.DataMap with
+ | Some dm when dm.StaticHash = 0 ->
+ yield dm.ToCreateContractForAssay(a.Identifier)
+ dm.StaticHash <- dm.GetHashCode()
+ | Some dm when dm.StaticHash <> dm.GetHashCode() ->
+ yield dm.ToUpdateContractForAssay(a.Identifier)
+ dm.StaticHash <- dm.GetHashCode()
+ | _ -> ()
|]
diff --git a/src/ARCtrl/ARCtrl.fsproj b/src/ARCtrl/ARCtrl.fsproj
index 911cff74..90c2db6a 100644
--- a/src/ARCtrl/ARCtrl.fsproj
+++ b/src/ARCtrl/ARCtrl.fsproj
@@ -47,5 +47,7 @@
-
+
+
+
\ No newline at end of file
diff --git a/src/ARCtrl/Xlsx.fs b/src/ARCtrl/Xlsx.fs
index 2b54c7ea..488681f6 100644
--- a/src/ARCtrl/Xlsx.fs
+++ b/src/ARCtrl/Xlsx.fs
@@ -7,6 +7,11 @@ open FsSpreadsheet
module XlsxHelper =
+ []
+ type DatamapXlsx() =
+ member _.fromFsWorkbook (fswb: FsWorkbook) = DataMap.fromFsWorkbook fswb
+ member _.toFsWorkbook (datamap: DataMap) = DataMap.toFsWorkbook datamap
+
[]
type AssayXlsx() =
member _.fromFsWorkbook (fswb: FsWorkbook) = ArcAssay.fromFsWorkbook fswb
@@ -28,6 +33,7 @@ open XlsxHelper
[]
type XlsxController =
+ static member Datamap = DatamapXlsx()
static member Assay = AssayXlsx()
static member Study = StudyXlsx()
static member Investigation = InvestigationXlsx()
\ No newline at end of file
diff --git a/src/Contract/ARC.fs b/src/Contract/ARC.fs
index a8e972ba..726872eb 100644
--- a/src/Contract/ARC.fs
+++ b/src/Contract/ARC.fs
@@ -21,6 +21,8 @@ let tryISAReadContractFromPath (path: string) =
Some <| Contract.createRead(p, DTOType.ISA_Assay)
| StudyPath p ->
Some <| Contract.createRead(p, DTOType.ISA_Study)
+ | DatamapPath p ->
+ Some <| Contract.createRead(p, DTOType.ISA_Datamap)
| anyElse ->
None
diff --git a/src/Contract/ARCtrl.Contract.fsproj b/src/Contract/ARCtrl.Contract.fsproj
index c5d5d73a..801ae242 100644
--- a/src/Contract/ARCtrl.Contract.fsproj
+++ b/src/Contract/ARCtrl.Contract.fsproj
@@ -7,6 +7,7 @@
+
@@ -19,9 +20,11 @@
-
+
+
+
nfdi4plants, Kevin Frey, Lukas Weil, Kevin Schneider, Oliver Maus
ARC helper functions for contracts management.
diff --git a/src/Contract/Contract.fs b/src/Contract/Contract.fs
index 45628e83..4a9b5f66 100644
--- a/src/Contract/Contract.fs
+++ b/src/Contract/Contract.fs
@@ -9,8 +9,9 @@ open Fable.Core.JsInterop
[]
type DTOType =
| [] ISA_Assay // isa.assay.xlsx
- | [] ISA_Study
- | [] ISA_Investigation
+ | [] ISA_Study // isa.study.xlsx
+ | [] ISA_Investigation // isa.investigation.xlsx
+ | [] ISA_Datamap // isa.datamap.xlsx
| [] JSON // arc.json
| [] Markdown // README.md
| [] CWL // workflow.cwl, might be a new DTO once we
diff --git a/src/Contract/Datamap.fs b/src/Contract/Datamap.fs
new file mode 100644
index 00000000..29e56bbd
--- /dev/null
+++ b/src/Contract/Datamap.fs
@@ -0,0 +1,92 @@
+namespace ARCtrl.Contract
+
+open ARCtrl.FileSystem
+open ARCtrl.Path
+open ARCtrl.Spreadsheet
+open ARCtrl
+open ARCtrl.Helper
+open FsSpreadsheet
+
+[]
+module DatamapContractExtensions =
+
+ let (|DatamapPath|_|) (input) =
+ match input with
+ | [|AssaysFolderName; anyAssayName; DataMapFileName|] ->
+ let path = ARCtrl.Path.combineMany input
+ Some path
+ | [|StudiesFolderName; anyStudyName; DataMapFileName|] ->
+ let path = ARCtrl.Path.combineMany input
+ Some path
+ | _ -> None
+
+ type DataMap with
+
+ member this.ToCreateContractForAssay (assayIdentifier : string) =
+ let path = Identifier.Assay.datamapFileNameFromIdentifier assayIdentifier
+ Contract.createCreate(path, DTOType.ISA_Datamap, DTO.Spreadsheet (this |> DataMap.toFsWorkbook))
+
+ member this.ToUpdateContractForAssay (assayIdentifier : string) =
+ let path = Identifier.Assay.datamapFileNameFromIdentifier assayIdentifier
+ let c = Contract.createUpdate(path, DTOType.ISA_Datamap, DTO.Spreadsheet (this |> DataMap.toFsWorkbook))
+ c
+
+ member this.ToDeleteContractForAssay (assayIdentifier : string) =
+ let path = Identifier.Assay.datamapFileNameFromIdentifier assayIdentifier
+ let c = Contract.createDelete(path)
+ c
+
+ static member toDeleteContractForAssay (assayIdentifier : string) =
+ fun (dataMap : DataMap) ->
+ dataMap.ToDeleteContractForAssay(assayIdentifier)
+
+ static member toUpdateContractForAssay (assayIdentifier : string) =
+ fun (dataMap : DataMap) ->
+ dataMap.ToUpdateContractForAssay(assayIdentifier)
+
+ static member tryFromReadContractForAssay (assayIdentifier : string) (c:Contract) =
+ let path = Identifier.Assay.datamapFileNameFromIdentifier assayIdentifier
+ match c with
+ | {Path = p; Operation = READ; DTOType = Some DTOType.ISA_Datamap; DTO = Some (DTO.Spreadsheet fsworkbook)} when p = path ->
+ let dm =
+ fsworkbook :?> FsWorkbook
+ |> DataMap.fromFsWorkbook
+ dm.StaticHash <- dm.GetHashCode()
+ dm
+ |> Some
+ | _ -> None
+
+
+ member this.ToCreateContractForStudy (studyIdentifier : string) =
+ let path = Identifier.Study.datamapFileNameFromIdentifier studyIdentifier
+ Contract.createCreate(path, DTOType.ISA_Datamap, DTO.Spreadsheet (this |> DataMap.toFsWorkbook))
+
+ member this.ToUpdateContractForStudy (studyIdentifier : string) =
+ let path = Identifier.Study.datamapFileNameFromIdentifier studyIdentifier
+ let c = Contract.createUpdate(path, DTOType.ISA_Datamap, DTO.Spreadsheet (this |> DataMap.toFsWorkbook))
+ c
+
+ member this.ToDeleteContractForStudy (studyIdentifier : string) =
+ let path = Identifier.Study.datamapFileNameFromIdentifier studyIdentifier
+ let c = Contract.createDelete(path)
+ c
+
+ static member toDeleteContractForStudy (studyIdentifier : string) =
+ fun (dataMap : DataMap) ->
+ dataMap.ToDeleteContractForStudy(studyIdentifier)
+
+ static member toUpdateContractForStudy (studyIdentifier : string) =
+ fun (dataMap : DataMap) ->
+ dataMap.ToUpdateContractForStudy(studyIdentifier)
+
+
+ static member tryFromReadContractForStudy (studyIdentifier : string) (c:Contract) =
+ let path = Identifier.Study.datamapFileNameFromIdentifier studyIdentifier
+ match c with
+ | {Path = p; Operation = READ; DTOType = Some DTOType.ISA_Datamap; DTO = Some (DTO.Spreadsheet fsworkbook)} when p = path->
+ let dm =
+ fsworkbook :?> FsWorkbook
+ |> DataMap.fromFsWorkbook
+ dm.StaticHash <- dm.GetHashCode()
+ Some (dm)
+ | _ -> None
diff --git a/src/Core/ARCtrl.Core.fsproj b/src/Core/ARCtrl.Core.fsproj
index 2bccaabf..d6ac0db3 100644
--- a/src/Core/ARCtrl.Core.fsproj
+++ b/src/Core/ARCtrl.Core.fsproj
@@ -16,6 +16,8 @@
+
+
@@ -29,8 +31,6 @@
-
-
@@ -46,6 +46,7 @@
+
@@ -57,9 +58,11 @@
-
+
+
+
nfdi4plants, Lukas Weil, Kevin Frey, Kevin Schneider, Oliver Maus
ARC and ISA compliant experimental metadata toolkit in F#. This project is meant as an easy means to open, manipulate and save ISA (Investigation,Study,Assay) metadata files in the dotnet environment.
diff --git a/src/Core/ArcTypes.fs b/src/Core/ArcTypes.fs
index bbc35b26..2ca42abc 100644
--- a/src/Core/ArcTypes.fs
+++ b/src/Core/ArcTypes.fs
@@ -101,7 +101,7 @@ module ArcTypesAux =
[]
-type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?tables: ResizeArray, ?performers : ResizeArray, ?comments : ResizeArray) =
+type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?tables: ResizeArray, ?datamap : DataMap, ?performers : ResizeArray, ?comments : ResizeArray) =
inherit ArcTables(defaultArg tables <| ResizeArray())
let performers = defaultArg performers <| ResizeArray()
@@ -111,6 +111,7 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
let mutable measurementType : OntologyAnnotation option = measurementType
let mutable technologyType : OntologyAnnotation option = technologyType
let mutable technologyPlatform : OntologyAnnotation option = technologyPlatform
+ let mutable dataMap : DataMap option = datamap
let mutable performers = performers
let mutable comments = comments
let mutable staticHash : int = 0
@@ -122,13 +123,14 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
member this.MeasurementType with get() = measurementType and set(n) = measurementType <- n
member this.TechnologyType with get() = technologyType and set(n) = technologyType <- n
member this.TechnologyPlatform with get() = technologyPlatform and set(n) = technologyPlatform <- n
+ member this.DataMap with get() = dataMap and set(n) = dataMap <- n
member this.Performers with get() = performers and set(n) = performers <- n
member this.Comments with get() = comments and set(n) = comments <- n
member this.StaticHash with get() = staticHash and set(h) = staticHash <- h
static member init (identifier : string) = ArcAssay(identifier)
- static member create (identifier: string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?tables: ResizeArray, ?performers : ResizeArray, ?comments : ResizeArray) =
- ArcAssay(identifier = identifier, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, ?tables =tables, ?performers = performers, ?comments = comments)
+ static member create (identifier: string, ?measurementType : OntologyAnnotation, ?technologyType : OntologyAnnotation, ?technologyPlatform : OntologyAnnotation, ?tables: ResizeArray, ?datamap : DataMap, ?performers : ResizeArray, ?comments : ResizeArray) =
+ ArcAssay(identifier = identifier, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, ?tables =tables, ?datamap = datamap, ?performers = performers, ?comments = comments)
static member make
(identifier : string)
@@ -136,9 +138,10 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
(technologyType : OntologyAnnotation option)
(technologyPlatform : OntologyAnnotation option)
(tables : ResizeArray)
+ (datamap : DataMap option)
(performers : ResizeArray)
(comments : ResizeArray) =
- ArcAssay(identifier = identifier, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, tables =tables, performers = performers, comments = comments)
+ ArcAssay(identifier = identifier, ?measurementType = measurementType, ?technologyType = technologyType, ?technologyPlatform = technologyPlatform, tables =tables, ?datamap = datamap, performers = performers, comments = comments)
static member FileName = ARCtrl.Path.AssayFileName
member this.StudiesRegisteredIn
@@ -380,6 +383,7 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
let copy = table.Copy()
nextTables.Add(copy)
let nextComments = this.Comments |> ResizeArray.map (fun c -> c.Copy())
+ let nextDataMap = this.DataMap |> Option.map (fun d -> d.Copy())
let nextPerformers = this.Performers |> ResizeArray.map (fun c -> c.Copy())
ArcAssay.make
this.Identifier
@@ -387,6 +391,7 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
this.TechnologyType
this.TechnologyPlatform
nextTables
+ nextDataMap
nextPerformers
nextComments
@@ -455,7 +460,8 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
if assay.Tables.Count <> 0 || updateAlways then
this.Tables <- assay.Tables
if assay.Comments.Count <> 0 || updateAlways then
- this.Comments <- assay.Comments
+ this.Comments <- assay.Comments
+ this.DataMap <- assay.DataMap
if assay.Performers.Count <> 0 || updateAlways then
this.Performers <- assay.Performers
@@ -464,11 +470,12 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
let mst = this.MeasurementType = other.MeasurementType
let tt = this.TechnologyType = other.TechnologyType
let tp = this.TechnologyPlatform = other.TechnologyPlatform
+ let dm = this.DataMap = other.DataMap
let tables = Seq.compare this.Tables other.Tables
let perf = Seq.compare this.Performers other.Performers
let comments = Seq.compare this.Comments other.Comments
// Todo maybe add reflection check to prove that all members are compared?
- [|i; mst; tt; tp; tables; perf; comments|] |> Seq.forall (fun x -> x = true)
+ [|i; mst; tt; tp; dm; tables; perf; comments|] |> Seq.forall (fun x -> x = true)
///
/// Use this function to check if this ArcAssay and the input ArcAssay refer to the same object.
@@ -485,12 +492,27 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
this.StructurallyEquals(assay)
| _ -> false
+ // Hashcode without Datamap
+ member this.GetLightHashCode() =
+ [|
+ box this.Identifier
+ HashCodes.boxHashOption this.MeasurementType
+ HashCodes.boxHashOption this.TechnologyType
+ HashCodes.boxHashOption this.TechnologyPlatform
+ HashCodes.boxHashSeq this.Tables
+ HashCodes.boxHashSeq this.Performers
+ HashCodes.boxHashSeq this.Comments
+ |]
+ |> HashCodes.boxHashArray
+ |> fun x -> x :?> int
+
override this.GetHashCode() =
[|
box this.Identifier
HashCodes.boxHashOption this.MeasurementType
HashCodes.boxHashOption this.TechnologyType
HashCodes.boxHashOption this.TechnologyPlatform
+ HashCodes.boxHashOption this.DataMap
HashCodes.boxHashSeq this.Tables
HashCodes.boxHashSeq this.Performers
HashCodes.boxHashSeq this.Comments
@@ -499,7 +521,7 @@ type ArcAssay(identifier: string, ?measurementType : OntologyAnnotation, ?techno
|> fun x -> x :?> int
[]
-type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publicReleaseDate, ?publications, ?contacts, ?studyDesignDescriptors, ?tables, ?registeredAssayIdentifiers: ResizeArray, ?comments) =
+type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publicReleaseDate, ?publications, ?contacts, ?studyDesignDescriptors, ?tables, ?datamap, ?registeredAssayIdentifiers: ResizeArray, ?comments) =
inherit ArcTables(defaultArg tables <| ResizeArray())
let publications = defaultArg publications <| ResizeArray()
@@ -517,6 +539,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
let mutable publications : ResizeArray = publications
let mutable contacts : ResizeArray = contacts
let mutable studyDesignDescriptors : ResizeArray = studyDesignDescriptors
+ let mutable datamap : DataMap option = datamap
let mutable registeredAssayIdentifiers : ResizeArray = registeredAssayIdentifiers
let mutable comments : ResizeArray = comments
let mutable staticHash : int = 0
@@ -532,17 +555,18 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
member this.Publications with get() = publications and set(n) = publications <- n
member this.Contacts with get() = contacts and set(n) = contacts <- n
member this.StudyDesignDescriptors with get() = studyDesignDescriptors and set(n) = studyDesignDescriptors <- n
+ member this.DataMap with get() = datamap and set(n) = datamap <- n
member this.RegisteredAssayIdentifiers with get() = registeredAssayIdentifiers and set(n) = registeredAssayIdentifiers <- n
member this.Comments with get() = comments and set(n) = comments <- n
member this.StaticHash with get() = staticHash and set(h) = staticHash <- h
static member init(identifier : string) = ArcStudy identifier
- static member create(identifier : string, ?title, ?description, ?submissionDate, ?publicReleaseDate, ?publications, ?contacts, ?studyDesignDescriptors, ?tables, ?registeredAssayIdentifiers, ?comments) =
- ArcStudy(identifier, ?title = title, ?description = description, ?submissionDate = submissionDate, ?publicReleaseDate = publicReleaseDate, ?publications = publications, ?contacts = contacts, ?studyDesignDescriptors = studyDesignDescriptors, ?tables = tables, ?registeredAssayIdentifiers = registeredAssayIdentifiers, ?comments = comments)
+ static member create(identifier : string, ?title, ?description, ?submissionDate, ?publicReleaseDate, ?publications, ?contacts, ?studyDesignDescriptors, ?tables, ?datamap, ?registeredAssayIdentifiers, ?comments) =
+ ArcStudy(identifier, ?title = title, ?description = description, ?submissionDate = submissionDate, ?publicReleaseDate = publicReleaseDate, ?publications = publications, ?contacts = contacts, ?studyDesignDescriptors = studyDesignDescriptors, ?tables = tables, ?datamap = datamap, ?registeredAssayIdentifiers = registeredAssayIdentifiers, ?comments = comments)
- static member make identifier title description submissionDate publicReleaseDate publications contacts studyDesignDescriptors tables registeredAssayIdentifiers comments =
- ArcStudy(identifier, ?title = title, ?description = description, ?submissionDate = submissionDate, ?publicReleaseDate = publicReleaseDate, publications = publications, contacts = contacts, studyDesignDescriptors = studyDesignDescriptors, tables = tables, registeredAssayIdentifiers = registeredAssayIdentifiers, comments = comments)
+ static member make identifier title description submissionDate publicReleaseDate publications contacts studyDesignDescriptors tables datamap registeredAssayIdentifiers comments =
+ ArcStudy(identifier, ?title = title, ?description = description, ?submissionDate = submissionDate, ?publicReleaseDate = publicReleaseDate, publications = publications, contacts = contacts, studyDesignDescriptors = studyDesignDescriptors, tables = tables, ?datamap = datamap, registeredAssayIdentifiers = registeredAssayIdentifiers, comments = comments)
///
/// Returns true if all fields are None/ empty sequences **except** Identifier.
@@ -929,6 +953,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
let nextContacts = this.Contacts |> ResizeArray.map (fun c -> c.Copy())
let nextPublications = this.Publications |> ResizeArray.map (fun c -> c.Copy())
let nextStudyDesignDescriptors = this.StudyDesignDescriptors |> ResizeArray.map (fun c -> c.Copy())
+ let nextDataMap = this.DataMap |> Option.map (fun d -> d.Copy())
let study =
ArcStudy.make
this.Identifier
@@ -940,6 +965,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
nextContacts
nextStudyDesignDescriptors
nextTables
+ nextDataMap
nextAssayIdentifiers
nextComments
if copyInvestigationRef then study.Investigation <- this.Investigation
@@ -970,6 +996,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
if study.Tables.Count <> 0 || updateAlways then
let tables = ArcTables.updateReferenceTablesBySheets(ArcTables(this.Tables),ArcTables(study.Tables),?keepUnusedRefTables = keepUnusedRefTables)
this.Tables <- tables.Tables
+ this.DataMap <- study.DataMap
if study.RegisteredAssayIdentifiers.Count <> 0 || updateAlways then
this.RegisteredAssayIdentifiers <- study.RegisteredAssayIdentifiers
if study.Comments.Count <> 0 || updateAlways then
@@ -981,6 +1008,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
let d = this.Description = other.Description
let sd = this.SubmissionDate = other.SubmissionDate
let prd = this.PublicReleaseDate = other.PublicReleaseDate
+ let dm = this.DataMap = other.DataMap
let pub = Seq.compare this.Publications other.Publications
let con = Seq.compare this.Contacts other.Contacts
let sdd = Seq.compare this.StudyDesignDescriptors other.StudyDesignDescriptors
@@ -988,7 +1016,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
let reg_tables = Seq.compare this.RegisteredAssayIdentifiers other.RegisteredAssayIdentifiers
let comments = Seq.compare this.Comments other.Comments
// Todo maybe add reflection check to prove that all members are compared?
- [|i; t; d; sd; prd; pub; con; sdd; tables; reg_tables; comments|] |> Seq.forall (fun x -> x = true)
+ [|i; t; d; sd; prd; dm; pub; con; sdd; tables; reg_tables; comments|] |> Seq.forall (fun x -> x = true)
///
/// Use this function to check if this ArcStudy and the input ArcStudy refer to the same object.
@@ -1040,6 +1068,7 @@ type ArcStudy(identifier : string, ?title, ?description, ?submissionDate, ?publi
HashCodes.boxHashOption this.Description
HashCodes.boxHashOption this.SubmissionDate
HashCodes.boxHashOption this.PublicReleaseDate
+ HashCodes.boxHashOption this.DataMap
HashCodes.boxHashSeq this.Publications
HashCodes.boxHashSeq this.Contacts
HashCodes.boxHashSeq this.StudyDesignDescriptors
diff --git a/src/Core/Conversion.fs b/src/Core/Conversion.fs
index 9fd97ffa..929ebb23 100644
--- a/src/Core/Conversion.fs
+++ b/src/Core/Conversion.fs
@@ -75,6 +75,7 @@ module JsonTypes =
| CompositeCell.Unitized (text,unit) ->
(if text = "" then None else Value.fromString text |> Some),
if unit.isEmpty() then None else unit |> Some
+ | CompositeCell.Data (data) -> failwith "Data cell should not be parsed to isa value"
/// Convert a CompositeHeader and Cell tuple to a ISA Component
let composeComponent (header : CompositeHeader) (value : CompositeCell) : Component =
@@ -105,9 +106,7 @@ module JsonTypes =
| CompositeHeader.Input IOType.Source -> ProcessInput.createSource(value.ToString())
| CompositeHeader.Input IOType.Sample -> ProcessInput.createSample(value.ToString())
| CompositeHeader.Input IOType.Material -> ProcessInput.createMaterial(value.ToString())
- | CompositeHeader.Input IOType.ImageFile -> ProcessInput.createImageFile(value.ToString())
- | CompositeHeader.Input IOType.RawDataFile -> ProcessInput.createRawData(value.ToString())
- | CompositeHeader.Input IOType.DerivedDataFile -> ProcessInput.createDerivedData(value.ToString())
+ | CompositeHeader.Input IOType.Data -> ProcessInput.createRawData(value.ToString())
| _ ->
failwithf "Could not parse input header %O" header
@@ -117,9 +116,7 @@ module JsonTypes =
match header with
| CompositeHeader.Output IOType.Sample -> ProcessOutput.createSample(value.ToString())
| CompositeHeader.Output IOType.Material -> ProcessOutput.createMaterial(value.ToString())
- | CompositeHeader.Output IOType.ImageFile -> ProcessOutput.createImageFile(value.ToString())
- | CompositeHeader.Output IOType.RawDataFile -> ProcessOutput.createRawData(value.ToString())
- | CompositeHeader.Output IOType.DerivedDataFile -> ProcessOutput.createDerivedData(value.ToString())
+ | CompositeHeader.Output IOType.Data -> ProcessOutput.createRawData(value.ToString())
| _ ->
failwithf "Could not parse output header %O" header
@@ -167,9 +164,9 @@ module JsonTypes =
| ProcessInput.Data d ->
let dataType = d.DataType.Value
match dataType with
- | DataFile.ImageFile -> CompositeHeader.Input IOType.ImageFile, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
- | DataFile.RawDataFile -> CompositeHeader.Input IOType.RawDataFile, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
- | DataFile.DerivedDataFile -> CompositeHeader.Input IOType.DerivedDataFile, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
+ | DataFile.ImageFile -> CompositeHeader.Input IOType.Data, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
+ | DataFile.RawDataFile -> CompositeHeader.Input IOType.Data, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
+ | DataFile.DerivedDataFile -> CompositeHeader.Input IOType.Data, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
/// Convert an ISA ProcessOutput to a CompositeHeader and Cell tuple
let decomposeProcessOutput (po : ProcessOutput) : CompositeHeader*CompositeCell =
@@ -179,9 +176,9 @@ module JsonTypes =
| ProcessOutput.Data d ->
let dataType = d.DataType.Value
match dataType with
- | DataFile.ImageFile -> CompositeHeader.Output IOType.ImageFile, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
- | DataFile.RawDataFile -> CompositeHeader.Output IOType.RawDataFile, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
- | DataFile.DerivedDataFile -> CompositeHeader.Output IOType.DerivedDataFile, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
+ | DataFile.ImageFile -> CompositeHeader.Output IOType.Data, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
+ | DataFile.RawDataFile -> CompositeHeader.Output IOType.Data, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
+ | DataFile.DerivedDataFile -> CompositeHeader.Output IOType.Data, CompositeCell.FreeText (d.Name |> Option.defaultValue "")
/// This function creates a string containing the name and the ontology short-string of the given ontology annotation term
diff --git a/src/Core/Data.fs b/src/Core/Data.fs
new file mode 100644
index 00000000..18649f6d
--- /dev/null
+++ b/src/Core/Data.fs
@@ -0,0 +1,81 @@
+namespace ARCtrl
+
+open ARCtrl
+open ARCtrl.Helper
+open Fable.Core
+
+[]
+type Data(?id,?name,?dataType,?format,?selectorFormat,?comments) =
+
+ let mutable _id : URI option = id
+ let mutable _name : string option = name
+ let mutable _dataType : DataFile option = dataType
+ let mutable _format : string option = format
+ let mutable _selectorFormat : URI option = selectorFormat
+ let mutable _comments : Comment ResizeArray = Option.defaultValue (ResizeArray()) comments
+
+ member this.ID
+ with get() = _id
+ and set(id) = _id <- id
+
+ member this.Name
+ with get() = _name
+ and set(name) = _name <- name
+
+ member this.DataType
+ with get() = _dataType
+ and set(dataType) = _dataType <- dataType
+
+ member this.Format
+ with get() = _format
+ and set(format) = _format <- format
+
+ member this.SelectorFormat
+ with get() = _selectorFormat
+ and set(selectorFormat) = _selectorFormat <- selectorFormat
+
+ member this.Comments
+ with get() = _comments
+ and set(comments) = _comments <- comments
+
+
+ static member make id name dataType format selectorFormat comments =
+ Data(?id=id,?name=name,?dataType=dataType,?format=format,?selectorFormat=selectorFormat,?comments=comments)
+
+ static member create (?Id,?Name,?DataType,?Format,?SelectorFormat,?Comments) =
+ Data.make Id Name DataType Format SelectorFormat Comments
+
+ static member empty =
+ Data.create()
+
+ member this.NameText =
+ this.Name
+ |> Option.defaultValue ""
+
+ member this.Copy() =
+ let nextComments = this.Comments |> ResizeArray.map (fun c -> c.Copy())
+ Data(?id=this.ID,?name=this.Name,?dataType=this.DataType,?format=this.Format,?selectorFormat=this.SelectorFormat,comments=nextComments)
+
+ override this.GetHashCode() =
+ [|
+ HashCodes.boxHashOption this.ID
+ HashCodes.boxHashOption this.Name
+ HashCodes.boxHashOption this.DataType
+ HashCodes.boxHashOption this.Format
+ HashCodes.boxHashOption this.SelectorFormat
+ HashCodes.boxHashSeq this.Comments
+ |]
+ |> HashCodes.boxHashArray
+ |> fun x -> x :?> int
+
+ override this.Equals(obj) =
+ HashCodes.hash this = HashCodes.hash obj
+
+ interface IISAPrintable with
+ member this.Print() =
+ this.ToString()
+ member this.PrintCompact() =
+ match this.DataType with
+ | Some t ->
+ sprintf "%s [%s]" this.NameText t.AsString
+ | None -> sprintf "%s" this.NameText
diff --git a/src/Core/Process/DataFile.fs b/src/Core/DataFile.fs
similarity index 96%
rename from src/Core/Process/DataFile.fs
rename to src/Core/DataFile.fs
index 79118b1a..b8c3ecef 100644
--- a/src/Core/Process/DataFile.fs
+++ b/src/Core/DataFile.fs
@@ -1,4 +1,4 @@
-namespace ARCtrl.Process
+namespace ARCtrl
open ARCtrl
diff --git a/src/Core/Helper/Identifier.fs b/src/Core/Helper/Identifier.fs
index 411c4baa..ff9ed736 100644
--- a/src/Core/Helper/Identifier.fs
+++ b/src/Core/Helper/Identifier.fs
@@ -88,6 +88,24 @@ module Assay =
else None
+ ///
+ /// On writing a xlsx file we unify our output to a relative path to ARC root. So: `assays/assayIdentifier/isa.datamap.xlsx`.
+ ///
+ /// Any correct assay identifier
+ let datamapFileNameFromIdentifier (identifier: string) : string =
+ checkValidCharacters (identifier)
+ ARCtrl.Path.combineMany [|ARCtrl.Path.AssaysFolderName; identifier; ARCtrl.Path.DataMapFileName|]
+
+ ///
+ /// On writing a xlsx file we unify our output to a relative path to ARC root. So: `assays/assayIdentifier/isa.datamap.xlsx`.
+ ///
+ /// Any correct assay identifier
+ let tryDatamapFileNameFromIdentifier (identifier: string) : string option =
+ if tryCheckValidCharacters (identifier) then
+ ARCtrl.Path.combineMany [|ARCtrl.Path.AssaysFolderName; identifier; ARCtrl.Path.DataMapFileName|]
+ |> Some
+ else None
+
/// Assay only contains "FileName" in isa.assay.xlsx. To unify naming in our model, on read-in we transform fileName to identifier and reverse for writing.
[]
module Study =
@@ -135,4 +153,22 @@ module Study =
if tryCheckValidCharacters (identifier) then
ARCtrl.Path.combineMany [|ARCtrl.Path.StudiesFolderName; identifier; ARCtrl.Path.StudyFileName|]
|> Some
+ else None
+
+ ///
+ /// On writing a xlsx file we unify our output to a relative path to ARC root. So: `studies/studyIdentifier/isa.investigation.xlsx`.
+ ///
+ /// Any correct study identifier
+ let datamapFileNameFromIdentifier (identifier: string) : string =
+ checkValidCharacters (identifier)
+ ARCtrl.Path.combineMany [|ARCtrl.Path.StudiesFolderName; identifier; ARCtrl.Path.DataMapFileName|]
+
+ ///
+ /// On writing a xlsx file we unify our output to a relative path to ARC root. So: `studies/studyIdentifier/isa.investigation.xlsx`.
+ ///
+ /// Any correct study identifier
+ let tryDatamapFileNameFromIdentifier (identifier: string) : string option =
+ if tryCheckValidCharacters (identifier) then
+ ARCtrl.Path.combineMany [|ARCtrl.Path.StudiesFolderName; identifier; ARCtrl.Path.DataMapFileName|]
+ |> Some
else None
\ No newline at end of file
diff --git a/src/Core/Process/Data.fs b/src/Core/Process/Data.fs
deleted file mode 100644
index ae2b87a0..00000000
--- a/src/Core/Process/Data.fs
+++ /dev/null
@@ -1,39 +0,0 @@
-namespace ARCtrl.Process
-
-open ARCtrl
-open ARCtrl.Helper
-
-type Data =
- {
- ID : URI option
- Name : string option
- DataType : DataFile option
- Comments : Comment list option
- }
-
- static member make id name dataType comments =
- {
- ID = id
- Name = name
- DataType = dataType
- Comments = comments
- }
-
- static member create (?Id,?Name,?DataType,?Comments) =
- Data.make Id Name DataType Comments
-
- static member empty =
- Data.create()
-
- member this.NameAsString =
- this.Name
- |> Option.defaultValue ""
-
- interface IISAPrintable with
- member this.Print() =
- this.ToString()
- member this.PrintCompact() =
- match this.DataType with
- | Some t ->
- sprintf "%s [%s]" this.NameAsString t.AsString
- | None -> sprintf "%s" this.NameAsString
diff --git a/src/Core/Table/ArcTableAux.fs b/src/Core/Table/ArcTableAux.fs
index 82895f8d..106e1bc4 100644
--- a/src/Core/Table/ArcTableAux.fs
+++ b/src/Core/Table/ArcTableAux.fs
@@ -113,10 +113,15 @@ module SanityChecks =
while isValid && en.MoveNext() do
let (ci,_),cell = en.Current.Key,en.Current.Value
let header = headers.[ci]
- let headerIsFreetext = not header.IsTermColumn
+ let headerIsData = header.IsDataColumn
+ let headerIsFreetext = (not header.IsTermColumn) && (not header.IsDataColumn)
let cellIsNotFreetext = not cell.isFreeText
+ let cellIsNotData = not cell.isData
+ if headerIsData && (cellIsNotData && cellIsNotFreetext) then
+ (if raiseException then failwith else printfn "%s") $"Invalid combination of header `{header}` and cell `{cell}`. Data header should contain either Data or Freetext cells."
+ isValid <- false
if headerIsFreetext && cellIsNotFreetext then
- (if raiseException then failwith else printfn "%s") $"Invalid combination of header `{header}` and cell `{cell}`."
+ (if raiseException then failwith else printfn "%s") $"Invalid combination of header `{header}` and cell `{cell}`. Freetext header should not contain non-freetext cells."
isValid <- false
isValid
diff --git a/src/Core/Table/CompositeCell.fs b/src/Core/Table/CompositeCell.fs
index af4a7d3d..2a5dd8fa 100644
--- a/src/Core/Table/CompositeCell.fs
+++ b/src/Core/Table/CompositeCell.fs
@@ -15,10 +15,12 @@ type CompositeCell =
///
/// https://isa-specs.readthedocs.io/en/latest/isatab.html#unit
| Unitized of string*OntologyAnnotation
+ | Data of Data
member this.isUnitized = match this with | Unitized _ -> true | _ -> false
member this.isTerm = match this with | Term _ -> true | _ -> false
member this.isFreeText = match this with | FreeText _ -> true | _ -> false
+ member this.isData = match this with | Data _ -> true | _ -> false
///
/// This returns the default empty cell from an existing CompositeCell.
@@ -28,6 +30,7 @@ type CompositeCell =
| CompositeCell.Term _ -> CompositeCell.emptyTerm
| CompositeCell.Unitized _ -> CompositeCell.emptyUnitized
| CompositeCell.FreeText _ -> CompositeCell.emptyFreeText
+ | CompositeCell.Data _ -> CompositeCell.emptyData
///
/// This function returns an array of all values as string
@@ -44,6 +47,7 @@ type CompositeCell =
| FreeText s -> [|s|]
| Term oa -> [| oa.NameText; defaultArg oa.TermSourceREF ""; defaultArg oa.TermAccessionNumber ""|]
| Unitized (v,oa) -> [| v; oa.NameText; defaultArg oa.TermSourceREF ""; defaultArg oa.TermAccessionNumber ""|]
+ | Data d -> [| defaultArg d.Name ""; defaultArg d.Format ""; defaultArg d.SelectorFormat ""|]
/// FreeText string will be converted to unit term name.
///
@@ -53,6 +57,7 @@ type CompositeCell =
| Unitized _ -> this
| FreeText text -> CompositeCell.Unitized ("", OntologyAnnotation.create(text))
| Term term -> CompositeCell.Unitized ("", term)
+ | Data d -> failwith "Data cell cannot be converted to Unitized cell."
/// FreeText string will be converted to term name.
///
@@ -62,6 +67,7 @@ type CompositeCell =
| Term _ -> this
| Unitized (_,unit) -> CompositeCell.Term unit
| FreeText text -> CompositeCell.Term(OntologyAnnotation.create(text))
+ | Data d -> failwith "Data cell cannot be converted to Term cell."
/// Will always keep `OntologyAnnotation.NameText` from Term or Unit.
member this.ToFreeTextCell() =
@@ -69,6 +75,7 @@ type CompositeCell =
| FreeText _ -> this
| Term term -> FreeText(term.NameText)
| Unitized (v,unit) -> FreeText(unit.NameText)
+ | Data d -> FreeText (Option.defaultValue "" d.Name)
// Suggest this syntax for easy "of-something" access
member this.AsUnitized =
@@ -79,12 +86,17 @@ type CompositeCell =
member this.AsTerm =
match this with
| Term c -> c
- | _ -> failwith "Not a Swate TermCell."
+ | _ -> failwith "Not a Term Cell."
member this.AsFreeText =
match this with
| FreeText c -> c
- | _ -> failwith "Not a Swate TermCell."
+ | _ -> failwith "Not a FreeText Cell."
+
+ member this.AsData =
+ match this with
+ | Data d -> d
+ | _ -> failwith "Not a Data Cell."
// TODO: i would really love to have an overload here accepting string input
static member createTerm (oa:OntologyAnnotation) = Term oa
@@ -99,9 +111,15 @@ type CompositeCell =
static member createFreeText (value: string) = FreeText value
+ static member createData (d:Data) = Data d
+
+ static member createDataFromString (value : string, ?format : string, ?selectorFormat : string) =
+ Data(Data.create(Name = value, ?Format = format, ?SelectorFormat = selectorFormat))
+
static member emptyTerm = Term (OntologyAnnotation())
static member emptyFreeText = FreeText ""
static member emptyUnitized = Unitized ("", OntologyAnnotation())
+ static member emptyData = Data(Data.create())
///
/// Updates current CompositeCell with information from OntologyAnnotation.
@@ -115,6 +133,7 @@ type CompositeCell =
| CompositeCell.Term _ -> CompositeCell.createTerm oa
| CompositeCell.Unitized (v,_) -> CompositeCell.createUnitized (v,oa)
| CompositeCell.FreeText _ -> CompositeCell.createFreeText oa.NameText
+ | CompositeCell.Data d -> failwith "Data cell cannot be updated with OntologyAnnotation."
///
/// Updates current CompositeCell with information from OntologyAnnotation.
@@ -132,6 +151,7 @@ type CompositeCell =
| Term oa -> $"{oa.NameText}"
| FreeText s -> s
| Unitized (v,oa) -> $"{v} {oa.NameText}"
+ | Data d -> $"{d.NameText}"
#if FABLE_COMPILER
//[]
@@ -143,5 +163,7 @@ type CompositeCell =
//[]
static member unitized (v:string, oa:OntologyAnnotation) = CompositeCell.Unitized(v, oa)
+ //[]
+ static member data (d:Data) = CompositeCell.Data(d)
#else
#endif
\ No newline at end of file
diff --git a/src/Core/Table/CompositeColumn.fs b/src/Core/Table/CompositeColumn.fs
index 29567b96..0b79e8a2 100644
--- a/src/Core/Table/CompositeColumn.fs
+++ b/src/Core/Table/CompositeColumn.fs
@@ -26,9 +26,17 @@ type CompositeColumn = {
// no cell values will be handled later and is no error case
| _, emptyCell when cells.Length = 0 ->
true
+ | isData when header.IsDataColumn && (cells.[0].isData || cells.[0].isFreeText) ->
+ true
+ | isData when header.IsDataColumn ->
+ if raiseExeption then
+ let exampleCells = cells.[0]
+ let msg = $"Invalid combination of header `{header}` and cells `{exampleCells}`, Data header should have either Data or Freetext cells"
+ failwith msg
+ false
| isTerm when header.IsTermColumn && (cells.[0].isTerm || cells.[0].isUnitized) ->
true
- | isNotTerm when not header.IsTermColumn && cells.[0].isFreeText ->
+ | isNotTerm when (not header.IsTermColumn) && cells.[0].isFreeText ->
true
| h, c ->
if raiseExeption then
diff --git a/src/Core/Table/CompositeHeader.fs b/src/Core/Table/CompositeHeader.fs
index b6e0f308..97bea594 100644
--- a/src/Core/Table/CompositeHeader.fs
+++ b/src/Core/Table/CompositeHeader.fs
@@ -9,9 +9,7 @@ open ARCtrl.Helper
type IOType =
| Source
| Sample
- | RawDataFile
- | DerivedDataFile
- | ImageFile
+ | Data
| Material
| FreeText of string
@@ -21,9 +19,7 @@ type IOType =
static member All = [|
Source
Sample
- RawDataFile
- DerivedDataFile
- ImageFile
+ Data
Material
|]
@@ -52,21 +48,8 @@ type IOType =
| FreeText s1, FreeText s2 when s1 = s2 -> FreeText (s1)
| FreeText s1, FreeText s2 -> failwith $"FreeText IO column names {s1} and {s2} do differ"
| FreeText s, _ -> failwith $"FreeText IO column and {other} can not be merged"
- | ImageFile, Source -> ImageFile
- | ImageFile, RawDataFile -> ImageFile
- | ImageFile, DerivedDataFile -> ImageFile
- | ImageFile, ImageFile -> ImageFile
- | ImageFile, _ -> failwith $"ImageFile IO column and {other} can not be merged"
- | DerivedDataFile, Source -> DerivedDataFile
- | DerivedDataFile, RawDataFile -> DerivedDataFile
- | DerivedDataFile, DerivedDataFile -> DerivedDataFile
- | DerivedDataFile, ImageFile -> ImageFile
- | DerivedDataFile, _ -> failwith $"DerivedDataFile IO column and {other} can not be merged"
- | RawDataFile, Source -> RawDataFile
- | RawDataFile, RawDataFile -> RawDataFile
- | RawDataFile, DerivedDataFile -> DerivedDataFile
- | RawDataFile, ImageFile -> ImageFile
- | RawDataFile, _ -> failwith $"RawDataFile IO column and {other} can not be merged"
+ | Data, Source -> Data
+ | Data, _ -> failwith $"Data IO column and {other} can not be merged"
| Sample, Source -> Sample
| Sample, Sample -> Sample
| Sample, _ -> failwith $"Sample IO column and {other} can not be merged"
@@ -79,13 +62,11 @@ type IOType =
override this.ToString() =
match this with
- | Source -> "Source Name"
- | Sample -> "Sample Name"
- | RawDataFile -> "Raw Data File"
- | DerivedDataFile -> "Derived Data File"
- | ImageFile -> "Image File"
- | Material -> "Material"
- | FreeText s -> s
+ | Source -> "Source Name"
+ | Sample -> "Sample Name"
+ | Data -> "Data"
+ | Material -> "Material"
+ | FreeText s -> s
/// Used to match only(!) IOType string to IOType (without Input/Output). This matching is case sensitive.
///
@@ -96,9 +77,10 @@ type IOType =
match str with
| "Source" | "Source Name" -> Source
| "Sample" | "Sample Name" -> Sample
- | "RawDataFile" | "Raw Data File" -> RawDataFile
- | "DerivedDataFile" | "Derived Data File" -> DerivedDataFile
- | "ImageFile" | "Image File" -> ImageFile
+ | "RawDataFile" | "Raw Data File"
+ | "DerivedDataFile" | "Derived Data File"
+ | "ImageFile" | "Image File"
+ | "Data" -> Data
| "Material" -> Material
| _ -> FreeText str // use str to not store `str.ToLower()`
@@ -118,29 +100,24 @@ type IOType =
"The source value must be a unique identifier for an organism or a sample."
| U2.Case1 Sample | U2.Case2 "Sample" ->
"The Sample Name column describes specifc laboratory samples with a unique identifier."
- | U2.Case1 RawDataFile | U2.Case2 "RawDataFile" ->
+ | U2.Case1 Data | U2.Case2 "RawDataFile" ->
"The Raw Data File column defines untransformed and unprocessed data files."
- | U2.Case1 DerivedDataFile | U2.Case2 "DerivedDataFile" ->
+ | U2.Case1 Data | U2.Case2 "DerivedDataFile" ->
"The Derived Data File column defines transformed and/or processed data files."
- | U2.Case1 ImageFile | U2.Case2 "ImageFile" ->
+ | U2.Case1 Data | U2.Case2 "ImageFile" ->
"Placeholder"
| U2.Case1 Material | U2.Case2 "Material" ->
"Placeholder"
| U2.Case1 (FreeText _) | U2.Case2 "FreeText" ->
"Placeholder"
| _ -> failwith $"Unable to parse combination to existing IOType: `{iotype}`"
-
#if FABLE_COMPILER
static member source() = IOType.Source
static member sample() = IOType.Sample
- static member rawDataFile() = IOType.RawDataFile
-
- static member derivedDataFile() = IOType.DerivedDataFile
-
- static member imageFile() = IOType.ImageFile
+ static member data() = IOType.Data
static member material() = IOType.Material
@@ -310,6 +287,11 @@ type CompositeHeader =
| ProtocolType -> true
| anythingElse -> false
+ member this.IsDataColumn =
+ match this with
+ | Input IOType.Data | Output IOType.Data -> true
+ | anythingElse -> false
+
///
/// Is true if the Building Block type is a FeaturedColumn.
///
diff --git a/src/Core/Table/DataMap.fs b/src/Core/Table/DataMap.fs
new file mode 100644
index 00000000..3b7fedb3
--- /dev/null
+++ b/src/Core/Table/DataMap.fs
@@ -0,0 +1,138 @@
+namespace ARCtrl
+
+open System.Collections.Generic
+open ARCtrl.Helper
+open ARCtrl
+open Fable.Core
+
+
+[]
+module DataMapAux =
+
+ []
+ let dataMapName = "DataMap"
+
+ let dataHeader = CompositeHeader.Input IOType.Data
+
+ []
+ let dataShortHand = "Data"
+
+ let explication = OntologyAnnotation("Clarification","NCIT","http://purl.obolibrary.org/obo/NCIT_C94778")
+
+ []
+ let explicationShortHand = "Explication"
+
+ let explicationHeader = CompositeHeader.Parameter explication
+
+ let unit = OntologyAnnotation("Unit","UO","http://purl.obolibrary.org/obo/UO_0000000")
+
+ []
+ let unitShortHand = "Unit"
+
+ let unitHeader = CompositeHeader.Parameter unit
+
+ let objectType = OntologyAnnotation("Data Type","NCIT","http://purl.obolibrary.org/obo/NCIT_C42645")
+
+ let objectTypeHeader = CompositeHeader.Parameter objectType
+
+ []
+ let objectTypeShortHand = "Object Type"
+
+ let descriptionHeader = CompositeHeader.FreeText "Description"
+
+ []
+ let descriptionShortHand = "Description"
+
+ let generatedByHeader = CompositeHeader.FreeText "Generated By"
+
+ []
+ let generatedByShortHand = "Generated By"
+
+ let allowedHeaders =
+ [dataHeader; explicationHeader; unitHeader; objectTypeHeader; descriptionHeader; generatedByHeader]
+
+ let validate (headers : ResizeArray) (values : System.Collections.Generic.Dictionary) (raiseException : bool) =
+ let headersAreValid =
+ headers
+ |> Seq.exists (fun h ->
+ let hasForeignHeader =
+ not (allowedHeaders |> List.exists (fun ah -> ah = h))
+ if raiseException && hasForeignHeader then
+ failwithf "Header %O is not allowed in DataMap" h
+ hasForeignHeader
+ )
+ let tableIsValid = ArcTableAux.SanityChecks.validate headers values raiseException
+ headersAreValid && tableIsValid
+
+type DataMap(headers: ResizeArray, values: System.Collections.Generic.Dictionary) =
+
+ let _ = DataMapAux.validate headers values true
+
+ let table = ArcTable(DataMapAux.dataMapName, headers, values)
+ let mutable staticHash = 0
+
+ member this.Headers = table.Headers
+ member this.Values = table.Values
+ member this.StaticHash with get() = staticHash and set(value) = staticHash <- value
+
+ static member init() = DataMap(ResizeArray(),Dictionary())
+
+ member this.AddColumns(columns : CompositeColumn [], ?skipFillMissing : bool) =
+ columns |> Array.iter (fun c -> c.Validate(true) |> ignore)
+ table.AddColumns(columns, ?skipFillMissing = skipFillMissing)
+ DataMapAux.validate table.Headers table.Values true |> ignore
+
+ static member addColumns (columns : CompositeColumn [], ?skipFillMissing : bool) =
+ fun (dm : DataMap) ->
+ let dm : DataMap = dm.Copy()
+ dm.AddColumns(columns, ?skipFillMissing = skipFillMissing)
+ dm
+
+ member this.Table = table
+
+ member this.TryGetCellAt (row: int, column: int) = table.TryGetCellAt(row, column)
+
+ member this.GetExplicationColumn() =
+ table.GetColumnByHeader(DataMapAux.explicationHeader)
+
+ member this.AddExplicationColumn(cells : CompositeCell []) =
+ table.AddColumn(DataMapAux.explicationHeader, cells)
+
+ member this.GetUnitColumn() =
+ table.GetColumnByHeader(DataMapAux.unitHeader)
+
+ member this.AddUnitColumn(cells : CompositeCell []) =
+ table.AddColumn(DataMapAux.unitHeader, cells)
+
+ member this.GetDataTypeColumn() =
+ table.GetColumnByHeader(DataMapAux.objectTypeHeader)
+
+ member this.AddDataTypeColumn(cells : CompositeCell []) =
+ table.AddColumn(DataMapAux.objectTypeHeader, cells)
+
+ member this.GetDescriptionColumn() =
+ table.GetColumnByHeader(DataMapAux.descriptionHeader)
+
+ member this.AddDescriptionColumn(cells : CompositeCell []) =
+ table.AddColumn(DataMapAux.descriptionHeader, cells)
+
+
+ member this.GetRow(row: int, ?SkipValidation) = table.GetRow(row,?SkipValidation = SkipValidation)
+
+ static member getRow(row: int, ?SkipValidation) =
+ fun (dm : DataMap) -> dm.GetRow(row,?SkipValidation = SkipValidation)
+
+ member this.Copy() =
+ DataMap(
+ ResizeArray(this.Headers),
+ Dictionary(this.Values)
+ )
+
+ override this.Equals(obj) =
+ match obj with
+ | :? DataMap as dm ->
+ this.Table.Equals(dm.Table)
+ | _ -> false
+
+ override this.GetHashCode() =
+ this.Table.GetHashCode()
\ No newline at end of file
diff --git a/src/FileSystem/FileSystemTree.fs b/src/FileSystem/FileSystemTree.fs
index 01ba3c33..daac3433 100644
--- a/src/FileSystem/FileSystemTree.fs
+++ b/src/FileSystem/FileSystemTree.fs
@@ -195,19 +195,29 @@ type FileSystemTree =
static member createEmptyFolder (name : string) =
FileSystemTree.createFolder(name, [|FileSystemTree.createGitKeepFile()|])
- static member createAssayFolder(assayName : string) =
+ static member createAssayFolder(assayName : string, ?hasDataMap) =
+ let hasDataMap = defaultArg hasDataMap false
let dataset = FileSystemTree.createEmptyFolder ARCtrl.Path.AssayDatasetFolderName
let protocols = FileSystemTree.createEmptyFolder ARCtrl.Path.AssayProtocolsFolderName
let readme = FileSystemTree.createReadmeFile()
let assayFile = FileSystemTree.createFile ARCtrl.Path.AssayFileName
- FileSystemTree.createFolder(assayName, [|dataset; protocols; assayFile; readme|])
+ if hasDataMap then
+ let dataMapFile = FileSystemTree.createFile ARCtrl.Path.DataMapFileName
+ FileSystemTree.createFolder(assayName, [|dataset; protocols; assayFile; readme; dataMapFile|])
+ else
+ FileSystemTree.createFolder(assayName, [|dataset; protocols; assayFile; readme|])
- static member createStudyFolder(studyName : string) =
+ static member createStudyFolder(studyName : string, ?hasDataMap) =
+ let hasDataMap = defaultArg hasDataMap false
let resources = FileSystemTree.createEmptyFolder ARCtrl.Path.StudiesResourcesFolderName
let protocols = FileSystemTree.createEmptyFolder ARCtrl.Path.StudiesProtocolsFolderName
let readme = FileSystemTree.createReadmeFile()
let studyFile = FileSystemTree.createFile ARCtrl.Path.StudyFileName
- FileSystemTree.createFolder(studyName, [|resources; protocols; studyFile; readme|])
+ if hasDataMap then
+ let dataMapFile = FileSystemTree.createFile ARCtrl.Path.DataMapFileName
+ FileSystemTree.createFolder(studyName, [|resources; protocols; studyFile; readme; dataMapFile|])
+ else
+ FileSystemTree.createFolder(studyName, [|resources; protocols; studyFile; readme|])
static member createInvestigationFile() =
FileSystemTree.createFile ARCtrl.Path.InvestigationFileName
diff --git a/src/FileSystem/Path.fs b/src/FileSystem/Path.fs
index 3b2aad05..36953def 100644
--- a/src/FileSystem/Path.fs
+++ b/src/FileSystem/Path.fs
@@ -9,6 +9,7 @@ let seperators = [|PathSeperator; PathSeperatorWindows|]
// Files
+let [] DataMapFileName = "isa.datamap.xlsx"
let [] AssayFileName = "isa.assay.xlsx"
let [] StudyFileName = "isa.study.xlsx"
let [] InvestigationFileName = "isa.investigation.xlsx"
diff --git a/src/Json/ARCtrl.Json.fsproj b/src/Json/ARCtrl.Json.fsproj
index 392c447f..fc08786d 100644
--- a/src/Json/ARCtrl.Json.fsproj
+++ b/src/Json/ARCtrl.Json.fsproj
@@ -87,6 +87,9 @@
+
+
+
nfdi4plants, Lukas Weil, Florian Wetzels, Kevin Frey
ARC and ISA json compliant parser for experimental metadata toolkit in F#. This project is meant as an easy means to open, manipulate and save ISA (Investigation,Study,Assay) metadata files in isa-json format.
diff --git a/src/Json/Assay.fs b/src/Json/Assay.fs
index 8014406a..93c1d81b 100644
--- a/src/Json/Assay.fs
+++ b/src/Json/Assay.fs
@@ -189,7 +189,7 @@ module AssayExtensions =
Decode.fromJsonString Assay.ROCrate.decoder s
/// exports in json-ld format
- static member toROCrateJsonString(studyName, ?spaces) =
+ static member toROCrateJsonString(?studyName, ?spaces) =
fun (obj: ArcAssay) ->
Assay.ROCrate.encoder studyName obj
|> Encode.toJsonString (Encode.defaultSpaces spaces)
diff --git a/src/Json/Process/Data.fs b/src/Json/Process/Data.fs
index 5c3088a5..7e372445 100644
--- a/src/Json/Process/Data.fs
+++ b/src/Json/Process/Data.fs
@@ -2,11 +2,69 @@ namespace ARCtrl.Json
open Thoth.Json.Core
+open StringTable
+
open ARCtrl
open ARCtrl.Process
module Data =
+ // let mutable _id : URI option = id
+ // let mutable _name : string option = name
+ // let mutable _dataType : DataFile option = dataType
+ // let mutable _format : string option = format
+ // let mutable _selectorFormat : URI option = selectorFormat
+ // let mutable _comments : Comment list option = comments
+ let encoder (d : Data) =
+ [
+ Encode.tryInclude "@id" Encode.string d.ID
+ Encode.tryInclude "name" Encode.string d.Name
+ Encode.tryInclude "dataType" DataFile.ISAJson.encoder d.DataType
+ Encode.tryInclude "format" Encode.string d.Format
+ Encode.tryInclude "selectorFormat" Encode.string d.SelectorFormat
+ Encode.tryIncludeSeq "comments" Comment.encoder d.Comments
+ ]
+ |> Encode.choose
+ |> Encode.object
+
+
+ let decoder : Decoder =
+ Decode.object (fun get ->
+ Data(
+ ?id = get.Optional.Field "@id" Decode.uri,
+ ?name = get.Optional.Field "name" Decode.string,
+ ?dataType = get.Optional.Field "dataType" DataFile.ISAJson.decoder,
+ ?format = get.Optional.Field "format" Decode.string,
+ ?selectorFormat = get.Optional.Field "selectorFormat" Decode.uri,
+ ?comments = get.Optional.Field "comments" (Decode.resizeArray Comment.decoder)
+ )
+ )
+
+ let compressedEncoder (stringTable : StringTableMap) (d : Data) =
+ [
+ Encode.tryInclude "i" (StringTable.encodeString stringTable) d.ID
+ Encode.tryInclude "n" (StringTable.encodeString stringTable) d.Name
+ Encode.tryInclude "d" DataFile.ISAJson.encoder d.DataType
+ Encode.tryInclude "f" (StringTable.encodeString stringTable) d.Format
+ Encode.tryInclude "s" (StringTable.encodeString stringTable) d.SelectorFormat
+ Encode.tryIncludeSeq "c" Comment.encoder d.Comments
+ ]
+ |> Encode.choose
+ |> Encode.object
+
+
+ let compressedDecoder (stringTable : StringTableArray) : Decoder =
+ Decode.object (fun get ->
+ Data(
+ ?id = get.Optional.Field "i" (StringTable.decodeString stringTable),
+ ?name = get.Optional.Field "n" (StringTable.decodeString stringTable),
+ ?dataType = get.Optional.Field "d" DataFile.ISAJson.decoder,
+ ?format = get.Optional.Field "f" (StringTable.decodeString stringTable),
+ ?selectorFormat = get.Optional.Field "s" (StringTable.decodeString stringTable),
+ ?comments = get.Optional.Field "c" (Decode.resizeArray Comment.decoder)
+ )
+ )
+
module ROCrate =
let genID (d:Data) : string =
@@ -22,7 +80,9 @@ module Data =
"@type", (Encode.list [Encode.string "Data"])
Encode.tryInclude "name" Encode.string (oa.Name)
Encode.tryInclude "type" DataFile.ROCrate.encoder oa.DataType
- Encode.tryIncludeListOpt "comments" Comment.ROCrate.encoder oa.Comments
+ Encode.tryInclude "encodingFormat" Encode.string oa.Format
+ Encode.tryInclude "usageInfo" Encode.string oa.SelectorFormat
+ Encode.tryIncludeSeq "comments" Comment.ROCrate.encoder oa.Comments
"@context", ROCrateContext.Data.context_jsonvalue
]
|> Encode.choose
@@ -30,12 +90,14 @@ module Data =
let decoder : Decoder =
Decode.object (fun get ->
- {
- ID = get.Optional.Field "@id" Decode.uri
- Name = get.Optional.Field "name" Decode.string
- DataType = get.Optional.Field "type" DataFile.ROCrate.decoder
- Comments = get.Optional.Field "comments" (Decode.list Comment.ROCrate.decoder)
- }
+ Data(
+ ?id = get.Optional.Field "@id" Decode.uri,
+ ?name = get.Optional.Field "name" Decode.string,
+ ?dataType = get.Optional.Field "type" DataFile.ROCrate.decoder,
+ ?format = get.Optional.Field "encodingFormat" Decode.string,
+ ?selectorFormat = get.Optional.Field "usageInfo" Decode.uri,
+ ?comments = get.Optional.Field "comments" (Decode.resizeArray Comment.ROCrate.decoder)
+ )
)
@@ -47,7 +109,7 @@ module Data =
Encode.tryInclude "@id" Encode.string oa.ID
Encode.tryInclude "name" Encode.string oa.Name
Encode.tryInclude "type" DataFile.ISAJson.encoder oa.DataType
- Encode.tryIncludeListOpt "comments" Comment.ISAJson.encoder oa.Comments
+ Encode.tryIncludeSeq "comments" Comment.ISAJson.encoder oa.Comments
]
|> Encode.choose
|> Encode.object
@@ -56,12 +118,12 @@ module Data =
let decoder: Decoder =
Decode.objectNoAdditionalProperties allowedFields (fun get ->
- {
- ID = get.Optional.Field "@id" Decode.uri
- Name = get.Optional.Field "name" Decode.string
- DataType = get.Optional.Field "type" DataFile.ISAJson.decoder
- Comments = get.Optional.Field "comments" (Decode.list Comment.ISAJson.decoder)
- }
+ Data(
+ ?id = get.Optional.Field "@id" Decode.uri,
+ ?name = get.Optional.Field "name" Decode.string,
+ ?dataType = get.Optional.Field "type" DataFile.ISAJson.decoder,
+ ?comments = get.Optional.Field "comments" (Decode.resizeArray Comment.ISAJson.decoder)
+ )
)
[]
diff --git a/src/Json/Table/CompositeCell.fs b/src/Json/Table/CompositeCell.fs
index e989b8f0..2f076dde 100644
--- a/src/Json/Table/CompositeCell.fs
+++ b/src/Json/Table/CompositeCell.fs
@@ -15,11 +15,13 @@ module CompositeCell =
let encoder (cc: CompositeCell) =
let oaToJsonString (oa:OntologyAnnotation) = OntologyAnnotation.encoder oa
+
let t, v =
match cc with
| CompositeCell.FreeText s-> "FreeText", [Encode.string s]
| CompositeCell.Term t -> "Term", [oaToJsonString t]
| CompositeCell.Unitized (v, unit) -> "Unitized", [Encode.string v; oaToJsonString unit]
+ | CompositeCell.Data d -> "Data", [Data.encoder d]
Encode.object [
CellType, Encode.string t
CellValues, v |> Encode.list
@@ -38,6 +40,9 @@ module CompositeCell =
let v = get.Required.Field (CellValues) (Decode.index 0 Decode.string)
let oa = get.Required.Field (CellValues) (Decode.index 1 OntologyAnnotation.decoder)
CompositeCell.Unitized (v, oa)
+ | "Data" ->
+ let d = get.Required.Field (CellValues) (Decode.index 0 Data.decoder)
+ CompositeCell.Data d
| anyelse -> failwithf "Error reading CompositeCell from json string: %A" anyelse
)
@@ -50,6 +55,7 @@ module CompositeCell =
| CompositeCell.FreeText s -> "FreeText", [StringTable.encodeString stringTable s]
| CompositeCell.Term t -> "Term", [OATable.encodeOA oaTable t]
| CompositeCell.Unitized (v, unit) -> "Unitized", [StringTable.encodeString stringTable v; OATable.encodeOA oaTable unit]
+ | CompositeCell.Data d -> "Data", [Data.compressedEncoder stringTable d]
Encode.object [
CompressedCellType, StringTable.encodeString stringTable t
CompressedCellValues, v |> Encode.list
@@ -69,6 +75,9 @@ module CompositeCell =
let v = get.Required.Field (CompressedCellValues) (Decode.index 0 <| (StringTable.decodeString stringTable) )
let oa = get.Required.Field (CompressedCellValues) (Decode.index 1 <| OATable.decodeOA oaTable )
CompositeCell.Unitized (v, oa)
+ | "Data" ->
+ let d = get.Required.Field (CompressedCellValues) (Decode.index 0 <| Data.compressedDecoder stringTable)
+ CompositeCell.Data d
| anyelse -> failwithf "Error reading CompositeCell from json string: %A" anyelse
)
diff --git a/src/Spreadsheet/ARCtrl.Spreadsheet.fsproj b/src/Spreadsheet/ARCtrl.Spreadsheet.fsproj
index 826c3ec6..0ed1fe7d 100644
--- a/src/Spreadsheet/ARCtrl.Spreadsheet.fsproj
+++ b/src/Spreadsheet/ARCtrl.Spreadsheet.fsproj
@@ -19,20 +19,23 @@
-
+
+
+
+
+
-
+
-
@@ -42,6 +45,9 @@
+
+
+
nfdi4plants, Lukas Weil
ARC and ISA xlsx compliant parser for experimental metadata toolkit in F#. This project is meant as an easy means to open, manipulate and save ISA (Investigation,Study,Assay) metadata files in isa-xlsx format.
diff --git a/src/Spreadsheet/AnnotationTable/ArcTable.fs b/src/Spreadsheet/AnnotationTable/ArcTable.fs
index e7573d0a..3a7e5212 100644
--- a/src/Spreadsheet/AnnotationTable/ArcTable.fs
+++ b/src/Spreadsheet/AnnotationTable/ArcTable.fs
@@ -61,14 +61,22 @@ let classifyColumnOrder (column : CompositeColumn) =
[]
let annotationTablePrefix = "annotationTable"
+let helperColumnStrings =
+ [
+ "Term Source REF"
+ "Term Accession Number"
+ "Unit"
+ "Data Format"
+ "Data Selector Format"
+ ]
+
let groupColumnsByHeader (columns : list) =
columns
|> Aux.List.groupWhen (fun c ->
let v = c.[1].ValueAsString()
- Regex.tryParseReferenceColumnHeader v
- |> Option.isNone
- &&
- (v.StartsWith "Unit" |> not)
+ helperColumnStrings
+ |> List.exists (fun s -> v.StartsWith s)
+ |> not
)
/// Returns the annotation table of the worksheet if it exists, else returns None
diff --git a/src/Spreadsheet/AnnotationTable/CompositeCell.fs b/src/Spreadsheet/AnnotationTable/CompositeCell.fs
index da43f5b3..74d0e294 100644
--- a/src/Spreadsheet/AnnotationTable/CompositeCell.fs
+++ b/src/Spreadsheet/AnnotationTable/CompositeCell.fs
@@ -4,14 +4,38 @@ open ARCtrl
open ARCtrl.Helper
open FsSpreadsheet
-let fromFsCells (cells : list) : CompositeCell =
+//let fromFsCells (cells : list) : CompositeCell =
+// let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+// match cellValues with
+// | [v] -> CompositeCell.createFreeText v
+// | [v1;v2;v3] -> CompositeCell.createTermFromString(v1,v2,v3)
+// | [v1;v2;v3;v4] -> CompositeCell.createUnitizedFromString(v1,v2,v3,v4)
+// | _ ->
+// failwithf "Dafuq"
+
+let termFromFsCells (tsrCol : int option) (tanCol : int option ) (cells : list) : CompositeCell=
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ let tan = Option.map (fun i -> cellValues.[i]) tanCol
+ let tsr = Option.map (fun i -> cellValues.[i]) tsrCol
+ CompositeCell.createTermFromString(cellValues.[0],?tsr = tsr, ?tan = tan)
+
+let unitizedFromFsCells (unitCol : int) (tsrCol : int option ) (tanCol : int option) (cells : list) : CompositeCell =
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ let unit = cellValues.[unitCol]
+ let tan = Option.map (fun i -> cellValues.[i]) tanCol
+ let tsr = Option.map (fun i -> cellValues.[i]) tsrCol
+ CompositeCell.createUnitizedFromString(cellValues.[0],unit,?tsr = tsr, ?tan = tan)
+
+let freeTextFromFsCells (cells : list) : CompositeCell =
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ CompositeCell.createFreeText cellValues.[0]
+
+let dataFromFsCells (format : int option) (selectorFormat : int option) (cells : list) : CompositeCell =
let cellValues = cells |> List.map (fun c -> c.ValueAsString())
- match cellValues with
- | [v] -> CompositeCell.createFreeText v
- | [v1;v2;v3] -> CompositeCell.createTermFromString(v1,v2,v3)
- | [v1;v2;v3;v4] -> CompositeCell.createUnitizedFromString(v1,v2,v3,v4)
- | _ ->
- failwithf "Dafuq"
+ let format = Option.map (fun i -> cellValues.[i]) format
+ let selectorFormat = Option.map (fun i -> cellValues.[i]) selectorFormat
+ CompositeCell.createDataFromString(cellValues.[0],?format = format, ?selectorFormat = selectorFormat)
+
let toFsCells isTerm hasUnit (cell : CompositeCell) : list =
match cell with
@@ -22,4 +46,8 @@ let toFsCells isTerm hasUnit (cell : CompositeCell) : list =
| CompositeCell.Term v when hasUnit -> [FsCell(v.NameText); FsCell(""); FsCell(Option.defaultValue "" v.TermSourceREF); FsCell(v.TermAccessionOntobeeUrl)]
| CompositeCell.Term v -> [FsCell(v.NameText); FsCell(Option.defaultValue "" v.TermSourceREF); FsCell(v.TermAccessionOntobeeUrl)]
- | CompositeCell.Unitized (v,unit) -> [FsCell(v); FsCell(unit.NameText); FsCell(Option.defaultValue "" unit.TermSourceREF); FsCell(unit.TermAccessionOntobeeUrl)]
\ No newline at end of file
+ | CompositeCell.Unitized (v,unit) -> [FsCell(v); FsCell(unit.NameText); FsCell(Option.defaultValue "" unit.TermSourceREF); FsCell(unit.TermAccessionOntobeeUrl)]
+ | CompositeCell.Data d ->
+ let format = d.Format |> Option.defaultValue "" |> FsCell
+ let selectorFormat = d.SelectorFormat |> Option.defaultValue "" |> FsCell
+ [FsCell(d.Name |> Option.defaultValue ""); format; selectorFormat]
\ No newline at end of file
diff --git a/src/Spreadsheet/AnnotationTable/CompositeColumn.fs b/src/Spreadsheet/AnnotationTable/CompositeColumn.fs
index 4cc5e7d9..5126de73 100644
--- a/src/Spreadsheet/AnnotationTable/CompositeColumn.fs
+++ b/src/Spreadsheet/AnnotationTable/CompositeColumn.fs
@@ -22,7 +22,7 @@ let fixDeprecatedIOHeader (col : FsColumn) =
col
let fromFsColumns (columns : list) : CompositeColumn =
- let header =
+ let header, cellParser =
columns
|> List.map (fun c -> c.[1])
|> CompositeHeader.fromFsCells
@@ -32,7 +32,7 @@ let fromFsColumns (columns : list) : CompositeColumn =
for i = 2 to l do
columns
|> List.map (fun c -> c.[i])
- |> CompositeCell.fromFsCells
+ |> cellParser
|]
CompositeColumn.create(header,cells)
@@ -40,6 +40,7 @@ let fromFsColumns (columns : list) : CompositeColumn =
let toFsColumns (column : CompositeColumn) : FsCell list list =
let hasUnit = column.Cells |> Seq.exists (fun c -> c.isUnitized)
let isTerm = column.Header.IsTermColumn
+ let isData = column.Header.IsDataColumn
let header = CompositeHeader.toFsCells hasUnit column.Header
let cells = column.Cells |> Array.map (CompositeCell.toFsCells isTerm hasUnit)
if hasUnit then
@@ -55,6 +56,17 @@ let toFsColumns (column : CompositeColumn) : FsCell list list =
[header.[1]; for i = 0 to column.Cells.Length - 1 do cells.[i].[1]]
[header.[2]; for i = 0 to column.Cells.Length - 1 do cells.[i].[2]]
]
+ elif isData then
+ let hasFormat = column.Cells |> Seq.exists (fun c -> c.AsData.Format.IsSome)
+ let hasSelectorFormat = column.Cells |> Seq.exists (fun c -> c.AsData.SelectorFormat.IsSome)
+
+ [
+ [header.[0]; for i = 0 to column.Cells.Length - 1 do cells.[i].[0]]
+ if hasFormat then
+ [header.[1]; for i = 0 to column.Cells.Length - 1 do cells.[i].[1]]
+ if hasSelectorFormat then
+ [header.[2]; for i = 0 to column.Cells.Length - 1 do cells.[i].[2]]
+ ]
else
[
[header.[0]; for i = 0 to column.Cells.Length - 1 do cells.[i].[0]]
diff --git a/src/Spreadsheet/AnnotationTable/CompositeHeader.fs b/src/Spreadsheet/AnnotationTable/CompositeHeader.fs
index 74e83ffa..31921c68 100644
--- a/src/Spreadsheet/AnnotationTable/CompositeHeader.fs
+++ b/src/Spreadsheet/AnnotationTable/CompositeHeader.fs
@@ -13,22 +13,34 @@ module ActivePattern =
if localID1 <> localID2 then failwithf "LocalID %s and %s do not match" localID1 localID2
{|TermSourceRef = idSpace1; TermAccessionNumber = $"{idSpace1}:{localID1}"|}
- let (|Term|_|) (categoryParser : string -> string option) (f : OntologyAnnotation -> CompositeHeader) (cells : FsCell list) =
+ let (|Term|_|) (categoryParser : string -> string option) (f : OntologyAnnotation -> CompositeHeader) (cells : FsCell list) : (CompositeHeader*(FsCell list -> CompositeCell)) option =
let (|AC|_|) s =
categoryParser s
let cellValues = cells |> List.map (fun c -> c.ValueAsString())
match cellValues with
| [AC name] ->
let ont = OntologyAnnotation.create(name)
- f ont
+ (f ont, CompositeCell.termFromFsCells None None)
+ |> Some
+ | [AC name; TSRColumnHeader term1; TANColumnHeader term2] ->
+ let term = mergeIDInfo term1.IDSpace term1.LocalID term2.IDSpace term2.LocalID
+ let ont = OntologyAnnotation.create(name, term.TermSourceRef, term.TermAccessionNumber)
+ (f ont, CompositeCell.termFromFsCells (Some 1) (Some 2))
+ |> Some
+ | [AC name; TANColumnHeader term2; TSRColumnHeader term1] ->
+ let term = mergeIDInfo term1.IDSpace term1.LocalID term2.IDSpace term2.LocalID
+ let ont = OntologyAnnotation.create(name, term.TermSourceRef, term.TermAccessionNumber)
+ (f ont, CompositeCell.termFromFsCells (Some 2) (Some 1))
|> Some
- | [AC name; TSRColumnHeader term1; TANColumnHeader term2]
- //| [AC name; TermAccessionNumber term1; TermSourceREF term2]
- //| [AC name; Unit; TermAccessionNumber term1; TermSourceREF term2]
| [AC name; UnitColumnHeader _; TSRColumnHeader term1; TANColumnHeader term2] ->
let term = mergeIDInfo term1.IDSpace term1.LocalID term2.IDSpace term2.LocalID
let ont = OntologyAnnotation.create(name, term.TermSourceRef, term.TermAccessionNumber)
- f ont
+ (f ont, CompositeCell.unitizedFromFsCells 1 (Some 2) (Some 3))
+ |> Some
+ | [AC name; UnitColumnHeader _; TANColumnHeader term2; TSRColumnHeader term1] ->
+ let term = mergeIDInfo term1.IDSpace term1.LocalID term2.IDSpace term2.LocalID
+ let ont = OntologyAnnotation.create(name, term.TermSourceRef, term.TermAccessionNumber)
+ (f ont, CompositeCell.unitizedFromFsCells 1 (Some 3) (Some 2))
|> Some
| _ -> None
@@ -59,45 +71,62 @@ module ActivePattern =
let (|Input|_|) (cells : FsCell list) =
let cellValues = cells |> List.map (fun c -> c.ValueAsString())
match cellValues with
- | [InputColumnHeader ioType] ->
- IOType.ofString ioType
- |> CompositeHeader.Input
- |> Some
+ | InputColumnHeader ioType :: cols ->
+ match IOType.ofString ioType with
+ | IOType.Data ->
+ let format = cols |> List.tryFindIndex (fun s -> s.StartsWith("Data Format")) |> Option.map ((+) 1)
+ let selectorFormat = cols |> List.tryFindIndex (fun s -> s.StartsWith("Data Selector Format")) |> Option.map ((+) 1)
+ (CompositeHeader.Input (IOType.Data), CompositeCell.dataFromFsCells format selectorFormat)
+ |> Some
+ | ioType ->
+ (CompositeHeader.Input ioType, CompositeCell.freeTextFromFsCells)
+ |> Some
| _ -> None
let (|Output|_|) (cells : FsCell list) =
let cellValues = cells |> List.map (fun c -> c.ValueAsString())
match cellValues with
- | [OutputColumnHeader ioType] ->
- IOType.ofString ioType
- |> CompositeHeader.Output
- |> Some
+ | OutputColumnHeader ioType :: cols ->
+ match IOType.ofString ioType with
+ | IOType.Data ->
+ let format = cols |> List.tryFindIndex (fun s -> s.StartsWith("Data Format")) |> Option.map ((+) 1)
+ let selectorFormat = cols |> List.tryFindIndex (fun s -> s.StartsWith("Data Selector Format")) |> Option.map ((+) 1)
+ (CompositeHeader.Output (IOType.Data), CompositeCell.dataFromFsCells format selectorFormat)
+ |> Some
+ | ioType ->
+ (CompositeHeader.Output ioType, CompositeCell.freeTextFromFsCells)
+ |> Some
+ | _ -> None
+
+ let (|ProtocolType|_|) (cells : FsCell list) =
+ let parser s = if s = "Protocol Type" then Some s else None
+ let header _ = CompositeHeader.ProtocolType
+ match cells with
+ | Term parser header r -> Some r
| _ -> None
let (|ProtocolHeader|_|) (cells : FsCell list) =
let cellValues = cells |> List.map (fun c -> c.ValueAsString())
match cellValues with
- | "Protocol Type" :: _ ->
- Some CompositeHeader.ProtocolType
- | ["Protocol REF"] -> Some CompositeHeader.ProtocolREF
- | ["Protocol Description"] -> Some CompositeHeader.ProtocolDescription
- | ["Protocol Uri"] -> Some CompositeHeader.ProtocolUri
- | ["Protocol Version"] -> Some CompositeHeader.ProtocolVersion
- | ["Performer"] -> Some CompositeHeader.Performer
- | ["Date"] -> Some CompositeHeader.Date
+ | ["Protocol REF"] -> Some (CompositeHeader.ProtocolREF, CompositeCell.freeTextFromFsCells)
+ | ["Protocol Description"] -> Some (CompositeHeader.ProtocolDescription, CompositeCell.freeTextFromFsCells)
+ | ["Protocol Uri"] -> Some (CompositeHeader.ProtocolUri, CompositeCell.freeTextFromFsCells)
+ | ["Protocol Version"] -> Some (CompositeHeader.ProtocolVersion, CompositeCell.freeTextFromFsCells)
+ | ["Performer"] -> Some (CompositeHeader.Performer, CompositeCell.freeTextFromFsCells)
+ | ["Date"] -> Some (CompositeHeader.Date, CompositeCell.freeTextFromFsCells)
| _ -> None
let (|FreeText|_|) (cells : FsCell list) =
let cellValues = cells |> List.map (fun c -> c.ValueAsString())
match cellValues with
| [text] ->
- CompositeHeader.FreeText text
+ (CompositeHeader.FreeText text, CompositeCell.freeTextFromFsCells)
|> Some
| _ -> None
open ActivePattern
-let fromFsCells (cells : list) : CompositeHeader =
+let fromFsCells (cells : list) : CompositeHeader*(FsCell list -> CompositeCell) =
match cells with
| Parameter p -> p
| Factor f -> f
@@ -105,13 +134,16 @@ let fromFsCells (cells : list) : CompositeHeader =
| Component c -> c
| Input i -> i
| Output o -> o
+ | ProtocolType pt -> pt
| ProtocolHeader ph -> ph
| FreeText ft -> ft
| _ -> failwithf "Could not parse header group %O" cells
let toFsCells (hasUnit : bool) (header : CompositeHeader) : list =
- if header.IsSingleColumn then
+ if header.IsDataColumn then
+ [FsCell(header.ToString()); FsCell "Data Format"; FsCell "Data Selector Format"]
+ elif header.IsSingleColumn then
[FsCell(header.ToString())]
elif header.IsTermColumn then
[
diff --git a/src/Spreadsheet/DataMap.fs b/src/Spreadsheet/DataMap.fs
new file mode 100644
index 00000000..b1c21e67
--- /dev/null
+++ b/src/Spreadsheet/DataMap.fs
@@ -0,0 +1,25 @@
+module ARCtrl.Spreadsheet.DataMap
+
+open ARCtrl
+open ArcTable
+open FsSpreadsheet
+
+
+/// Reads an assay from a spreadsheet
+let fromFsWorkbook (doc:FsWorkbook) =
+ try
+ let dataMapTable =
+ doc.GetWorksheets()
+ |> Seq.tryPick DataMapTable.tryFromFsWorksheet
+ match dataMapTable with
+ | Some table -> table
+ | None -> failwith "No DataMapTable found in workbook"
+ with
+ | err -> failwithf "Could not parse datamap: \n%s" err.Message
+
+let toFsWorkbook (dataMap : DataMap) =
+ let doc = new FsWorkbook()
+
+ DataMapTable.toFsWorksheet dataMap
+ |> doc.AddWorksheet
+ doc
\ No newline at end of file
diff --git a/src/Spreadsheet/DataMapTable/DataMapColumn.fs b/src/Spreadsheet/DataMapTable/DataMapColumn.fs
new file mode 100644
index 00000000..84b97854
--- /dev/null
+++ b/src/Spreadsheet/DataMapTable/DataMapColumn.fs
@@ -0,0 +1,48 @@
+module ARCtrl.Spreadsheet.DataMapColumn
+
+open ARCtrl
+open ArcTable
+open FsSpreadsheet
+
+let fromFsColumns (columns : list) : CompositeColumn =
+ let header, cellParser =
+ columns
+ |> List.map (fun c -> c.[1])
+ |> DataMapHeader.fromFsCells
+ let l = columns.[0].RangeAddress.LastAddress.RowNumber
+ let cells =
+ [|
+ for i = 2 to l do
+ columns
+ |> List.map (fun c -> c.[i])
+ |> cellParser
+ |]
+ CompositeColumn.create(header,cells)
+
+
+let toFsColumns (column : CompositeColumn) : FsCell list list =
+ let isTerm = column.Header.IsTermColumn
+ let isData = column.Header.IsDataColumn
+ let header = DataMapHeader.toFsCells column.Header
+ let cells = column.Cells |> Array.map (CompositeCell.toFsCells isTerm false)
+ if isTerm then
+ [
+ [header.[0]; for i = 0 to column.Cells.Length - 1 do cells.[i].[0]]
+ [header.[1]; for i = 0 to column.Cells.Length - 1 do cells.[i].[1]]
+ [header.[2]; for i = 0 to column.Cells.Length - 1 do cells.[i].[2]]
+ ]
+ elif isData then
+ let hasFormat = column.Cells |> Seq.exists (fun c -> c.AsData.Format.IsSome)
+ let hasSelectorFormat = column.Cells |> Seq.exists (fun c -> c.AsData.SelectorFormat.IsSome)
+
+ [
+ [header.[0]; for i = 0 to column.Cells.Length - 1 do cells.[i].[0]]
+ if hasFormat then
+ [header.[1]; for i = 0 to column.Cells.Length - 1 do cells.[i].[1]]
+ if hasSelectorFormat then
+ [header.[2]; for i = 0 to column.Cells.Length - 1 do cells.[i].[2]]
+ ]
+ else
+ [
+ [header.[0]; for i = 0 to column.Cells.Length - 1 do cells.[i].[0]]
+ ]
\ No newline at end of file
diff --git a/src/Spreadsheet/DataMapTable/DataMapHeader.fs b/src/Spreadsheet/DataMapTable/DataMapHeader.fs
new file mode 100644
index 00000000..013f60f2
--- /dev/null
+++ b/src/Spreadsheet/DataMapTable/DataMapHeader.fs
@@ -0,0 +1,122 @@
+module ARCtrl.Spreadsheet.DataMapHeader
+
+open ARCtrl
+open ARCtrl.Helper
+open FsSpreadsheet
+
+module ActivePattern =
+
+ open Regex.ActivePatterns
+
+ let (|Term|_|) (categoryString : string) (categoryHeader : CompositeHeader) (cells : FsCell list) : (CompositeHeader*(FsCell list -> CompositeCell)) option =
+ let (|AC|_|) s =
+ if s = categoryString then Some categoryHeader else None
+ let (|TSRColumnHeaderRaw|_|) (s : string) =
+ if s.StartsWith("Term Source REF") then Some s else None
+ let (|TANColumnHeaderRaw|_|) (s : string) =
+ if s.StartsWith("Term Accession Number") then Some s else None
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ match cellValues with
+ | [AC header] ->
+ (header, CompositeCell.termFromFsCells None None)
+ |> Some
+ | [AC header; TSRColumnHeaderRaw _; TANColumnHeaderRaw _] ->
+ (header, CompositeCell.termFromFsCells (Some 1) (Some 2))
+ |> Some
+ | [AC header; TANColumnHeaderRaw _; TSRColumnHeaderRaw _] ->
+ (header, CompositeCell.termFromFsCells (Some 2) (Some 1))
+ |> Some
+ | _ -> None
+
+ let (|Explication|_|) (cells : FsCell list) =
+ match cells with
+ | Term DataMapAux.explicationShortHand DataMapAux.explicationHeader r ->
+ Some r
+ | _ -> None
+
+ let (|Unit|_|) (cells : FsCell list) =
+ match cells with
+ | Term DataMapAux.unitShortHand DataMapAux.unitHeader r ->
+ Some r
+ | _ -> None
+
+ let (|ObjectType|_|) (cells : FsCell list) =
+ match cells with
+ | Term DataMapAux.objectTypeShortHand DataMapAux.objectTypeHeader r ->
+ Some r
+ | _ -> None
+
+ let (|Description|_|) (cells : FsCell list) =
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ match cellValues with
+ | [DataMapAux.descriptionShortHand] -> Some(DataMapAux.descriptionHeader, CompositeCell.freeTextFromFsCells)
+ | _ -> None
+
+ let (|GeneratedBy|_|) (cells : FsCell list) =
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ match cellValues with
+ | [DataMapAux.generatedByShortHand] -> Some(DataMapAux.generatedByHeader, CompositeCell.freeTextFromFsCells)
+ | _ -> None
+
+ let (|Data|_|) (cells : FsCell list) =
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ match cellValues with
+ | DataMapAux.dataShortHand :: cols ->
+
+ let format = cols |> List.tryFindIndex (fun s -> s.StartsWith("Data Format")) |> Option.map ((+) 1)
+ let selectorFormat = cols |> List.tryFindIndex (fun s -> s.StartsWith("Data Selector Format")) |> Option.map ((+) 1)
+ (CompositeHeader.Input (IOType.Data), CompositeCell.dataFromFsCells format selectorFormat)
+ |> Some
+
+ | _ -> None
+
+ let (|FreeText|_|) (cells : FsCell list) =
+ let cellValues = cells |> List.map (fun c -> c.ValueAsString())
+ match cellValues with
+ | [text] ->
+ (CompositeHeader.FreeText text, CompositeCell.freeTextFromFsCells)
+ |> Some
+ | _ -> None
+
+open ActivePattern
+
+let fromFsCells (cells : list) : CompositeHeader*(FsCell list -> CompositeCell) =
+ match cells with
+ | Data d -> d
+ | Explication e -> e
+ | Unit u -> u
+ | ObjectType ot -> ot
+ | Description d -> d
+ | GeneratedBy gb -> gb
+ | FreeText ft -> ft
+ | _ -> failwithf "Could not parse header group %O" cells
+
+let toFsCells (header : CompositeHeader) : list =
+ match header with
+ | CompositeHeader.Input IOType.Data ->
+ [
+ FsCell("Data")
+ FsCell("Data Format")
+ FsCell("Data Selector Format")
+ ]
+ | h when h = DataMapAux.explicationHeader ->
+ [
+ FsCell(DataMapAux.explicationShortHand)
+ FsCell("Term Source REF")
+ FsCell("Term Accession Number")
+ ]
+ | h when h = DataMapAux.unitHeader ->
+ [
+ FsCell(DataMapAux.unitShortHand)
+ FsCell("Term Source REF")
+ FsCell("Term Accession Number")
+ ]
+ | h when h = DataMapAux.objectTypeHeader ->
+ [
+ FsCell(DataMapAux.objectTypeShortHand)
+ FsCell("Term Source REF")
+ FsCell("Term Accession Number")
+ ]
+ | CompositeHeader.FreeText text ->
+ [FsCell(text)]
+ | _ -> failwithf "Could not parse DataMap header %O." header
diff --git a/src/Spreadsheet/DataMapTable/DataMapTable.fs b/src/Spreadsheet/DataMapTable/DataMapTable.fs
new file mode 100644
index 00000000..b188e514
--- /dev/null
+++ b/src/Spreadsheet/DataMapTable/DataMapTable.fs
@@ -0,0 +1,94 @@
+module ARCtrl.Spreadsheet.DataMapTable
+
+open ARCtrl
+open ArcTable
+open FsSpreadsheet
+
+[]
+let datamapTablePrefix = "datamapTable"
+
+let helperColumnStrings =
+ [
+ "Term Source REF"
+ "Term Accession Number"
+ "Data Format"
+ "Data Selector Format"
+ ]
+
+let groupColumnsByHeader (columns : list) =
+ columns
+ |> Aux.List.groupWhen (fun c ->
+ let v = c.[1].ValueAsString()
+ helperColumnStrings
+ |> List.exists (fun s -> v.StartsWith s)
+ |> not
+ )
+
+/// Returns the annotation table of the worksheet if it exists, else returns None
+let tryDataMapTable (sheet : FsWorksheet) =
+ sheet.Tables
+ |> Seq.tryFind (fun t -> t.Name.StartsWith datamapTablePrefix)
+
+/// Groups and parses a collection of single columns into the according ISA composite columns
+let composeColumns (columns : seq) : CompositeColumn [] =
+ columns
+ |> Seq.toList
+ |> groupColumnsByHeader
+ |> List.map DataMapColumn.fromFsColumns
+ |> List.toArray
+
+
+/// Returns the protocol described by the headers and a function for parsing the values of the matrix to the processes of this protocol
+let tryFromFsWorksheet (sheet : FsWorksheet) =
+ try
+ match tryDataMapTable sheet with
+ | Some (t: FsTable) ->
+ let compositeColumns =
+ t.GetColumns(sheet.CellCollection)
+ |> composeColumns
+ DataMap.init()
+ |> DataMap.addColumns(compositeColumns,skipFillMissing = true)
+ |> Some
+ | None ->
+ None
+ with
+ | err -> failwithf "Could not parse datamap table with name \"%s\":\n%s" sheet.Name err.Message
+
+let toFsWorksheet (table : DataMap) =
+ /// This dictionary is used to add spaces at the end of duplicate headers.
+ let stringCount = System.Collections.Generic.Dictionary()
+ let ws = FsWorksheet("isa_datamap")
+
+ // Cancel if there are no columns
+ if table.Table.Columns.Length = 0 then ws
+ else
+
+ let columns =
+ table.Table.Columns
+ |> List.ofArray
+ |> List.sortBy classifyColumnOrder
+ |> List.collect DataMapColumn.toFsColumns
+ let maxRow = columns.Head.Length
+ let maxCol = columns.Length
+ let fsTable = ws.Table("datamapTable",FsRangeAddress(FsAddress(1,1),FsAddress(maxRow,maxCol)))
+ columns
+ |> List.iteri (fun colI col ->
+ col
+ |> List.iteri (fun rowI cell ->
+ let value =
+ let v = cell.ValueAsString()
+ if rowI = 0 then
+
+ match Dictionary.tryGet v stringCount with
+ | Some spaces ->
+ stringCount.[v] <- spaces + " "
+ v + " " + spaces
+ | None ->
+ stringCount.Add(cell.ValueAsString(),"")
+ v
+ else v
+ let address = FsAddress(rowI+1,colI+1)
+ fsTable.Cell(address, ws.CellCollection).SetValueAs value
+ )
+ )
+ ws
\ No newline at end of file
diff --git a/src/Spreadsheet/Metadata/Assays.fs b/src/Spreadsheet/Metadata/Assays.fs
index f3c2efe3..5f0cf1bb 100644
--- a/src/Spreadsheet/Metadata/Assays.fs
+++ b/src/Spreadsheet/Metadata/Assays.fs
@@ -35,6 +35,7 @@ module Assays =
(Option.fromValueWithDefault (OntologyAnnotation()) technologyType)
(technologyPlatform |> Option.map JsonTypes.decomposeTechnologyPlatform)
(ResizeArray())
+ None
(ResizeArray())
(comments)
diff --git a/src/Spreadsheet/Metadata/Study.fs b/src/Spreadsheet/Metadata/Study.fs
index 23c51e1e..19e546f5 100644
--- a/src/Spreadsheet/Metadata/Study.fs
+++ b/src/Spreadsheet/Metadata/Study.fs
@@ -121,6 +121,7 @@ module Studies =
(ResizeArray contacts)
(ResizeArray designDescriptors)
(ResizeArray())
+ None
(ResizeArray(assayIdentifiers))
(ResizeArray studyInfo.Comments)
|> fun arcstudy ->
diff --git a/tests/ARCtrl/ARCtrl.Contracts.Tests.fs b/tests/ARCtrl/ARCtrl.Contracts.Tests.fs
index 36f96f6d..71b63cbe 100644
--- a/tests/ARCtrl/ARCtrl.Contracts.Tests.fs
+++ b/tests/ARCtrl/ARCtrl.Contracts.Tests.fs
@@ -20,6 +20,58 @@ let tests_tryFromContract = testList "tryFromContract" [
|]
let investigation = contracts |> Array.choose ArcInvestigation.tryFromReadContract
Expect.hasLength investigation 1 ""
+ testCase "DataMap" <| fun _ ->
+ let fswb = TestObjects.Contract.ISA.SimpleISA.Assay.proteomeDatamapWB
+ let assayName = "myAssay"
+ let contracts = [|
+ Contract.create(
+ READ,
+ $"assays/{assayName}/isa.datamap.xlsx",
+ DTOType.ISA_Datamap,
+ DTO.Spreadsheet fswb
+ )
+ |]
+ let datamap = ARCAux.getAssayDataMapFromContracts assayName contracts
+ Expect.isSome datamap "Datamap should have been parsed"
+ testCase "DataMap_WrongIdentifier" <| fun _ ->
+ let fswb = TestObjects.Contract.ISA.SimpleISA.Assay.proteomeDatamapWB
+ let assayName = "myAssay"
+ let contracts = [|
+ Contract.create(
+ READ,
+ $"assays/{assayName}/isa.datamap.xlsx",
+ DTOType.ISA_Datamap,
+ DTO.Spreadsheet fswb
+ )
+ |]
+ let datamap = ARCAux.getAssayDataMapFromContracts "wrongAssay" contracts
+ Expect.isNone datamap "Datamap should not have been parsed"
+ testCase "DataMap_WrongType" <| fun _ ->
+ let fswb = TestObjects.Contract.ISA.SimpleISA.Assay.proteomeDatamapWB
+ let assayName = "myAssay"
+ let contracts = [|
+ Contract.create(
+ READ,
+ $"assays/{assayName}/isa.datamap.xlsx",
+ DTOType.ISA_Assay,
+ DTO.Spreadsheet fswb
+ )
+ |]
+ let datamap = ARCAux.getAssayDataMapFromContracts assayName contracts
+ Expect.isNone datamap "Datamap should not have been parsed"
+ testCase "DataMap_WrongPath" <| fun _ ->
+ let fswb = TestObjects.Contract.ISA.SimpleISA.Assay.proteomeDatamapWB
+ let assayName = "myAssay"
+ let contracts = [|
+ Contract.create(
+ READ,
+ $"studies/{assayName}/isa.datamap.xlsx",
+ DTOType.ISA_Datamap,
+ DTO.Spreadsheet fswb
+ )
+ |]
+ let datamap = ARCAux.getAssayDataMapFromContracts assayName contracts
+ Expect.isNone datamap "Datamap should not have been parsed"
]
let tests_gitContracts = testList "gitContracts" [
diff --git a/tests/ARCtrl/ARCtrl.Tests.fs b/tests/ARCtrl/ARCtrl.Tests.fs
index 95237d31..9c4afe55 100644
--- a/tests/ARCtrl/ARCtrl.Tests.fs
+++ b/tests/ARCtrl/ARCtrl.Tests.fs
@@ -60,7 +60,7 @@ let private simpleISAContracts =
|]
let private tests_read_contracts = testList "read_contracts" [
- ptestCase "simpleISA" (fun () -> // set to pending, until performance issues in Study.fromFsWorkbook is resolved.
+ testCase "simpleISA" (fun () ->
let arc = ARC()
arc.SetISAFromContracts simpleISAContracts
Expect.isSome arc.ISA "isa should be filled out"
@@ -70,7 +70,9 @@ let private tests_read_contracts = testList "read_contracts" [
Expect.equal inv.Studies.Count 2 "should have read two studies"
let study1 = inv.Studies.[0]
Expect.equal study1.Identifier Study.BII_S_1.studyIdentifier "study 1 identifier should have been read from study contract"
- Expect.equal study1.TableCount 8 "study 1 should have the 7 tables from investigation plus one extra. One table should be overwritten."
+
+ Expect.equal study1.TableCount 2 "study 1 should have the 2 tables. Top level Metadata tables are ignored."
+ //Expect.equal study1.TableCount 8 "study 1 should have the 7 tables from investigation plus one extra. One table should be overwritten."
Expect.equal study1.RegisteredAssays.Count 3 "study 1 should have read three assays"
let assay1 = study1.RegisteredAssays.[0]
@@ -78,7 +80,7 @@ let private tests_read_contracts = testList "read_contracts" [
Expect.equal assay1.TableCount 1 "assay 1 should have read one table"
)
- ptestCase "StudyAssayOnlyRegistered" (fun () -> // set to pending, until performance issues in Study.fromFsWorkbook is resolved.
+ testCase "StudyAssayOnlyRegistered" (fun () -> // set to pending, until performance issues in Study.fromFsWorkbook is resolved.
let arc = ARC()
arc.SetISAFromContracts([|
SimpleISA.Investigation.investigationReadContract
@@ -94,7 +96,8 @@ let private tests_read_contracts = testList "read_contracts" [
Expect.equal inv.VacantStudyIdentifiers.Count 1 "should have one vacant study identifier"
let study1 = inv.Studies.[0]
Expect.equal study1.Identifier Study.BII_S_1.studyIdentifier "study 1 identifier should have been read from study contract"
- Expect.equal study1.TableCount 8 "study 1 should have the 7 tables from investigation plus one extra. One table should be overwritten."
+ Expect.equal study1.TableCount 2 "study 1 should have the 2 tables. Top level Metadata tables are ignored."
+ //Expect.equal study1.TableCount 8 "study 1 should have the 7 tables from investigation plus one extra. One table should be overwritten."
Expect.equal study1.RegisteredAssays.Count 1 "study 1 should have read one assay"
Expect.equal study1.RegisteredAssayIdentifierCount 3 "study 1 should have read three registered assay identifiers"
@@ -148,6 +151,23 @@ let private tests_read_contracts = testList "read_contracts" [
(Array.create 2 (CompositeCell.createFreeText UpdateAssayWithStudyProtocol.description))
"Description value was not taken correctly"
)
+ testCase "SimpleISA_WithDataset" (fun _ ->
+ let contracts = Array.append simpleISAContracts [|SimpleISA.Assay.proteomeDatamapContract|]
+
+ let arc = ARC()
+ arc.SetISAFromContracts contracts
+
+ let inv = Expect.wantSome arc.ISA "Arc should have investigation"
+ let a1 = inv.GetAssay(SimpleISA.Assay.proteomeIdentifer)
+ let datamap = Expect.wantSome a1.DataMap "Proteome Assay was supposed to have datamap"
+
+ Expect.equal 2 datamap.Table.RowCount "Datamap was not read correctly"
+
+ let a2 = inv.GetAssay(SimpleISA.Assay.metabolomeIdentifer)
+ Expect.isNone a2.DataMap "Metabolome Assay was not supposed to have datamap"
+
+ )
+
]
let private tests_writeContracts = testList "write_contracts" [
@@ -194,6 +214,33 @@ let private tests_writeContracts = testList "write_contracts" [
Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/isa.assay.xlsx" && c.DTOType.IsSome && c.DTOType.Value = Contract.DTOType.ISA_Assay) "assay file exisiting but has wrong DTO type"
)
+ testCase "assayWithDatamap" (fun _ ->
+ let inv = ArcInvestigation("MyInvestigation", "BestTitle")
+ let a = inv.InitAssay("MyAssay")
+ let dm = DataMap.init()
+ a.DataMap <- Some dm
+ let arc = ARC(isa = inv)
+ let contracts = arc.GetWriteContracts()
+ let contractPathsString = contracts |> Array.map (fun c -> c.Path) |> String.concat ", "
+ Expect.equal contracts.Length 10 $"Should contain more contracts as base folders but contained: {contractPathsString}"
+
+ // Base
+ Expect.exists contracts (fun c -> c.Path = "workflows/.gitkeep") "Contract for workflows folder missing"
+ Expect.exists contracts (fun c -> c.Path = "runs/.gitkeep") "Contract for runs folder missing"
+ Expect.exists contracts (fun c -> c.Path = "assays/.gitkeep") "Contract for assays folder missing"
+ Expect.exists contracts (fun c -> c.Path = "studies/.gitkeep") "Contract for studies folder missing"
+ Expect.exists contracts (fun c -> c.Path = "isa.investigation.xlsx") "Contract for investigation folder missing"
+ Expect.exists contracts (fun c -> c.Path = "isa.investigation.xlsx" && c.DTOType.IsSome && c.DTOType.Value = Contract.DTOType.ISA_Investigation) "Contract for investigation existing but has wrong DTO type"
+
+ // Assay folder
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/README.md") "assay readme missing"
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/protocols/.gitkeep") "assay protocols folder missing"
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/dataset/.gitkeep") "assay dataset folder missing"
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/isa.assay.xlsx") "assay file missing"
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/isa.assay.xlsx" && c.DTOType.IsSome && c.DTOType.Value = Contract.DTOType.ISA_Assay) "assay file existing but has wrong DTO type"
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/isa.datamap.xlsx") "assay datamap file missing"
+ Expect.exists contracts (fun c -> c.Path = "assays/MyAssay/isa.datamap.xlsx" && c.DTOType.IsSome && c.DTOType.Value = Contract.DTOType.ISA_Datamap) "assay datamap file existing but has wrong DTO type"
+ )
testCase "sameAssayAndStudyName" (fun _ ->
let inv = ArcInvestigation("MyInvestigation", "BestTitle")
inv.InitStudy("MyAssay").InitRegisteredAssay("MyAssay") |> ignore
@@ -315,6 +362,29 @@ let private tests_updateContracts = testList "update_contracts" [
let nextContracts = arc.GetUpdateContracts()
Expect.equal nextContracts.Length 0 "Should contain no contracts as there are no changes"
)
+ testCase "simpleISA_Datamap_NoChanges" (fun _ ->
+ let arc = ARC()
+ let readContracts = Array.append simpleISAContracts [|SimpleISA.Assay.proteomeDatamapContract|]
+ arc.SetISAFromContracts readContracts
+ let contracts = arc.GetUpdateContracts()
+ Expect.equal contracts.Length 0 "Should contain no contracts as there are no changes"
+ )
+ testCase "simpleISA_Datamap_Changed" (fun _ ->
+ let arc = ARC()
+ let readContracts = Array.append simpleISAContracts [|SimpleISA.Assay.proteomeDatamapContract|]
+ arc.SetISAFromContracts readContracts
+ let isa = arc.ISA.Value
+
+ let dm = Expect.wantSome (isa.GetAssay(SimpleISA.Assay.proteomeIdentifer).DataMap) "Assay should have datamap"
+ dm.Values.[(0,1)] <- CompositeCell.createDataFromString("Hello")
+
+ let contracts = arc.GetUpdateContracts()
+ Expect.equal contracts.Length 1 $"Should contain only assay datamap change contract"
+ let expectedPath = Identifier.Assay.datamapFileNameFromIdentifier SimpleISA.Assay.proteomeIdentifer
+ Expect.equal contracts.[0].Path expectedPath "Should be the assay datamap file"
+ let nextContracts = arc.GetUpdateContracts()
+ Expect.equal nextContracts.Length 0 "Should contain no contracts as there are no changes"
+ )
testCase "simpleISA_StudyChange" (fun _ ->
let arc = ARC()
arc.SetISAFromContracts simpleISAContracts
@@ -427,9 +497,9 @@ let private ``payload_file_filters`` =
let assay = ArcAssay("registered_assay")
let assayTable = assay.InitTable("MyAssayTable")
- assayTable.AppendColumn(CompositeHeader.Input (IOType.RawDataFile), [|CompositeCell.createFreeText "registered_assay_input.txt"|])
+ assayTable.AppendColumn(CompositeHeader.Input (IOType.Data), [|CompositeCell.createFreeText "registered_assay_input.txt"|])
assayTable.AppendColumn(CompositeHeader.ProtocolREF, [|CompositeCell.createFreeText "assay_protocol.rtf"|])
- assayTable.AppendColumn(CompositeHeader.Output (IOType.DerivedDataFile), [|CompositeCell.createFreeText "registered_assay_output.txt"|])
+ assayTable.AppendColumn(CompositeHeader.Output (IOType.Data), [|CompositeCell.createFreeText "registered_assay_output.txt"|])
let study = ArcStudy("registered_study")
inv.AddRegisteredStudy(study)
@@ -437,7 +507,7 @@ let private ``payload_file_filters`` =
studyTable.AppendColumn(CompositeHeader.Input (IOType.Sample), [|CompositeCell.createFreeText "some_study_input_material"|])
studyTable.AppendColumn(CompositeHeader.FreeText "Some File", [|CompositeCell.createFreeText "xd/some_file_that_lies_in_slashxd.txt"|])
studyTable.AppendColumn(CompositeHeader.ProtocolREF, [|CompositeCell.createFreeText "study_protocol.pdf"|])
- studyTable.AppendColumn(CompositeHeader.Output (IOType.RawDataFile), [|CompositeCell.createFreeText "registered_study_output.txt"|])
+ studyTable.AppendColumn(CompositeHeader.Output (IOType.Data), [|CompositeCell.createFreeText "registered_study_output.txt"|])
study.AddRegisteredAssay(assay)
diff --git a/tests/ARCtrl/ARCtrl.Tests.fsproj b/tests/ARCtrl/ARCtrl.Tests.fsproj
index d3737d30..f03693c4 100644
--- a/tests/ARCtrl/ARCtrl.Tests.fsproj
+++ b/tests/ARCtrl/ARCtrl.Tests.fsproj
@@ -18,6 +18,6 @@
-
+
\ No newline at end of file
diff --git a/tests/Core/ARCtrl.Core.Tests.fsproj b/tests/Core/ARCtrl.Core.Tests.fsproj
index 5eab9fe3..9a9eca43 100644
--- a/tests/Core/ARCtrl.Core.Tests.fsproj
+++ b/tests/Core/ARCtrl.Core.Tests.fsproj
@@ -9,6 +9,7 @@
+
@@ -25,10 +26,6 @@
-
-
-
-
diff --git a/tests/Core/ArcAssay.Tests.fs b/tests/Core/ArcAssay.Tests.fs
index 3a70045e..47ddb06f 100644
--- a/tests/Core/ArcAssay.Tests.fs
+++ b/tests/Core/ArcAssay.Tests.fs
@@ -76,7 +76,7 @@ let private test_create =
let tables = ResizeArray([ArcTable.init("MyTable1")])
let performers = ResizeArray [|Person(firstName = "Kevin", lastName = "Frey")|]
let comments = ResizeArray [|Comment.create("Comment Name")|]
- let actual = ArcAssay(identifier, oa_mt, oa_tt, technologyPlatform, tables, performers, comments)
+ let actual = ArcAssay(identifier, oa_mt, oa_tt, technologyPlatform, tables, performers = performers, comments = comments)
Expect.equal actual.Identifier identifier "identifier"
Expect.equal actual.MeasurementType (Some oa_mt) "MeasurementType"
Expect.equal actual.TechnologyType (Some oa_tt) "TechnologyType"
@@ -92,7 +92,7 @@ let private test_create =
let tables = ResizeArray([ArcTable.init("MyTable1")])
let performers = ResizeArray [|Person.create(firstName = "Kevin", lastName = "Frey")|]
let comments = ResizeArray [|Comment.create("Comment Name")|]
- let actual = ArcAssay(identifier, oa_mt, oa_tt, technologyPlatform, tables, performers, comments)
+ let actual = ArcAssay(identifier, oa_mt, oa_tt, technologyPlatform, tables, performers = performers, comments = comments)
Expect.equal actual.Identifier identifier "identifier"
Expect.equal actual.MeasurementType (Some oa_mt) "MeasurementType"
Expect.equal actual.TechnologyType (Some oa_tt) "TechnologyType"
@@ -108,7 +108,7 @@ let private test_create =
let tables = ResizeArray([ArcTable.init("MyTable1")])
let performers = ResizeArray[|Person.create(firstName = "Kevin", lastName = "Frey")|]
let comments = ResizeArray[|Comment.create("Comment Name")|]
- let actual = ArcAssay.create(identifier, oa_mt, oa_tt, technologyPlatform, tables, performers, comments)
+ let actual = ArcAssay.create(identifier, oa_mt, oa_tt, technologyPlatform, tables, performers = performers, comments = comments)
Expect.equal actual.Identifier identifier "identifier"
Expect.equal actual.MeasurementType (Some oa_mt) "MeasurementType"
Expect.equal actual.TechnologyType (Some oa_tt) "TechnologyType"
@@ -142,6 +142,7 @@ let private test_create =
technologyType
technologyPlatform
tables
+ None
performers
comments
@@ -507,8 +508,8 @@ let private tests_UpdateBy = testList "UpdateBy" [
OntologyAnnotation("MyTechnologyType"),
OntologyAnnotation("MyTechnologyPlatform"),
ResizeArray([ArcTable.init("MyTable")]),
- ResizeArray [|Person(firstName="Kevin", lastName="Frey")|],
- ResizeArray [|Comment(name="CommentName", value="CommentValue")|]
+ performers = ResizeArray [|Person(firstName="Kevin", lastName="Frey")|],
+ comments = ResizeArray [|Comment(name="CommentName", value="CommentValue")|]
)
testCase "UpdateBy, full replace" <| fun _ ->
let actual = create_testAssay()
@@ -611,6 +612,7 @@ let private tests_GetHashCode = testList "GetHashCode" [
(OntologyAnnotation "tt" |> Some)
(OntologyAnnotation "tp" |> Some)
(ResizeArray([ArcTable.init("My Table"); ArcTable.Tests.create_testTable()]))
+ None
(ResizeArray [|Person(firstName="John",lastName="Doe"); Person(firstName="Jane",lastName="Doe")|])
(ResizeArray [|Comment("Hello", "World"); Comment("ByeBye", "World") |])
testCase "passing" <| fun _ ->
diff --git a/tests/Core/ArcInvestigation.Tests.fs b/tests/Core/ArcInvestigation.Tests.fs
index 10bdb096..b8521763 100644
--- a/tests/Core/ArcInvestigation.Tests.fs
+++ b/tests/Core/ArcInvestigation.Tests.fs
@@ -627,7 +627,7 @@ let tests_UpdateIOTypeByEntityIDTypes = testList "UpdateIOTypeByEntityIDType" [
CompositeColumn.create (CompositeHeader.Output IOType.Sample, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample %i" i)))
|]
t2.AddColumns [|
- CompositeColumn.create (CompositeHeader.Input IOType.DerivedDataFile, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample %i" i)))
+ CompositeColumn.create (CompositeHeader.Input IOType.Data, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample %i" i)))
CompositeColumn.create (CompositeHeader.Output IOType.Sample, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample_Alt %i" i)))
|]
Expect.throws (fun () -> i.UpdateIOTypeByEntityID()) "Update should fail as sample and data can not be updated against each other."
@@ -680,7 +680,7 @@ let tests_UpdateIOTypeByEntityIDTypes = testList "UpdateIOTypeByEntityIDType" [
CompositeColumn.create (CompositeHeader.Output IOType.Sample, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample %i" i)))
|]
t2.AddColumns [|
- CompositeColumn.create (CompositeHeader.Input IOType.DerivedDataFile, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample %i" i)))
+ CompositeColumn.create (CompositeHeader.Input IOType.Data, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample %i" i)))
CompositeColumn.create (CompositeHeader.Output IOType.Sample, Array.init 3 (fun i -> CompositeCell.createFreeText (sprintf "Sample_Alt %i" i)))
|]
Expect.throws (fun () -> i.UpdateIOTypeByEntityID()) "Update should fail as sample and data can not be updated against each other."
diff --git a/tests/Core/ArcJsonConversion.Tests.fs b/tests/Core/ArcJsonConversion.Tests.fs
index dced8450..4a731a36 100644
--- a/tests/Core/ArcJsonConversion.Tests.fs
+++ b/tests/Core/ArcJsonConversion.Tests.fs
@@ -60,9 +60,9 @@ module Helper =
let singleRowDataInputWithCharacteristic =
let columns =
[|
- CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "RData" 1)
+ CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "RData" 1)
CompositeColumn.create(CompositeHeader.Characteristic oa_species, createCells_chlamy 1)
- CompositeColumn.create(CompositeHeader.Output IOType.DerivedDataFile, createCells_FreeText "DData" 1)
+ CompositeColumn.create(CompositeHeader.Output IOType.Data, createCells_FreeText "DData" 1)
|]
let t = ArcTable.init(tableName1)
t.AddColumns(columns)
@@ -71,9 +71,9 @@ module Helper =
let singleRowDataOutputWithFactor =
let columns =
[|
- CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "RData" 1)
+ CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "RData" 1)
CompositeColumn.create(CompositeHeader.Factor oa_temperature, createCells_DegreeCelsius 1)
- CompositeColumn.create(CompositeHeader.Output IOType.DerivedDataFile, createCells_FreeText "DData" 1)
+ CompositeColumn.create(CompositeHeader.Output IOType.Data, createCells_FreeText "DData" 1)
|]
let t = ArcTable.init(tableName1)
t.AddColumns(columns)
diff --git a/tests/Core/ArcStudy.Tests.fs b/tests/Core/ArcStudy.Tests.fs
index ebd55a51..cb97399e 100644
--- a/tests/Core/ArcStudy.Tests.fs
+++ b/tests/Core/ArcStudy.Tests.fs
@@ -130,6 +130,7 @@ let private test_create =
contacts
studyDesignDescriptors
tables
+ None
assay_identifiers
comments
@@ -452,6 +453,7 @@ let private tests_GetHashCode = testList "GetHashCode" [
(ResizeArray [|Person(firstName="John",lastName="Doe"); Person(firstName="Jane",lastName="Doe")|])
(ResizeArray [|OntologyAnnotation(); OntologyAnnotation(); OntologyAnnotation("Name", "tsr", "Tan")|])
(ResizeArray([ArcTable.init("My Table"); ArcTable.Tests.create_testTable()]))
+ None
(ResizeArray(["Registered Assay1"; "Registered Assay2"]))
(ResizeArray [|Comment("Hello", "World"); Comment("ByeBye", "World") |])
testCase "passing" <| fun _ ->
diff --git a/tests/Core/ArcTable.Tests.fs b/tests/Core/ArcTable.Tests.fs
index 012ec438..0da8c4a2 100644
--- a/tests/Core/ArcTable.Tests.fs
+++ b/tests/Core/ArcTable.Tests.fs
@@ -87,7 +87,7 @@ let private tests_GetHashCode = testList "GetHashCode" [
Expect.equal hash1 hash2 "HashCode"
testCase "equal, table-order does not matter" <| fun _ ->
let column_inputHeader, column_inputValues = CompositeHeader.Input IOType.Source, [|for i in 0 .. 20 do yield (0,i), sprintf "Source_%i" i |> CompositeCell.createFreeText|]
- let column_outputHeader, column_outputValues = CompositeHeader.Output IOType.RawDataFile, [|for i in 0 .. 20 do yield (1,i), sprintf "File_%i" i |> CompositeCell.createFreeText|]
+ let column_outputHeader, column_outputValues = CompositeHeader.Output IOType.Data, [|for i in 0 .. 20 do yield (1,i), sprintf "File_%i" i |> CompositeCell.createFreeText|]
let createTable(reverse:bool) =
let t = ArcTable.init("MyTable")
let shuffled = if reverse then [|yield! column_outputValues; yield! column_inputValues|] else [|yield! column_inputValues; yield! column_outputValues|]
@@ -142,7 +142,7 @@ let private tests_SanityChecks = testList "SanityChecks" [
CompositeHeader.Component (OntologyAnnotation())
CompositeHeader.ProtocolREF
CompositeHeader.ProtocolType
- CompositeHeader.Output IOType.DerivedDataFile
+ CompositeHeader.Output IOType.Data
]
testCase "valid headers" (fun () ->
let columns = headers_valid |> Seq.map (fun x -> CompositeColumn.create(x))
@@ -237,7 +237,7 @@ let private tests_ArcTableAux =
CompositeHeader.Component (OntologyAnnotation())
CompositeHeader.ProtocolREF
CompositeHeader.ProtocolType
- CompositeHeader.Output IOType.DerivedDataFile
+ CompositeHeader.Output IOType.Data
]
testCase "No duplicate, component" (fun () ->
let header = CompositeHeader.Component (OntologyAnnotation())
@@ -329,12 +329,12 @@ let private tests_UpdateHeader =
)
testCase "set unique at different index" (fun () ->
let testTable = create_testTable()
- let table() = testTable.UpdateHeader(2, CompositeHeader.Input IOType.DerivedDataFile)
+ let table() = testTable.UpdateHeader(2, CompositeHeader.Input IOType.Data)
Expect.throws (table >> ignore) ""
)
testCase "set unique at same index" (fun () ->
let table = create_testTable()
- let newHeader = CompositeHeader.Input IOType.DerivedDataFile
+ let newHeader = CompositeHeader.Input IOType.Data
table.UpdateHeader(0, newHeader)
Expect.equal table.RowCount 5 "RowCount"
Expect.equal table.ColumnCount 5 "ColumnCount"
@@ -518,7 +518,7 @@ let private tests_UpdateColumn =
)
testCase "set unique duplicate, different index" (fun () ->
let table = create_testTable()
- let h = CompositeHeader.Input IOType.RawDataFile
+ let h = CompositeHeader.Input IOType.Data
let cells = createCells_FreeText "NEWSOURCE" 5
let column = CompositeColumn.create(h, cells)
let eval() = table.UpdateColumn(1, h, cells)
@@ -526,7 +526,7 @@ let private tests_UpdateColumn =
)
testCase "set unique duplicate, same index" (fun () ->
let table = create_testTable()
- let h = CompositeHeader.Input IOType.RawDataFile
+ let h = CompositeHeader.Input IOType.Data
let cells = createCells_FreeText "NEWSOURCE" 5
table.UpdateColumn(0, h, cells)
Expect.equal table.RowCount 5 "RowCount"
@@ -1429,7 +1429,7 @@ let private tests_AddColumns =
)
testCase "multiple columns, same rowCount, duplicate replace" (fun () ->
let testTable = create_testTable()
- let newInputCol = CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "NEW" 5)
+ let newInputCol = CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "NEW" 5)
let columns = [|
column_param
newInputCol
@@ -1455,7 +1455,7 @@ let private tests_AddColumns =
)
testCase "multiple columns, same rowCount, duplicate replace, insert at" (fun () ->
let testTable = create_testTable()
- let newInputCol = CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "NEW" 5)
+ let newInputCol = CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "NEW" 5)
let columns = [|
column_param
newInputCol
@@ -1481,7 +1481,7 @@ let private tests_AddColumns =
)
testCase "multiple columns, same rowCount, duplicate replace, insert at2" (fun () ->
let testTable = create_testTable()
- let newInputCol = CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "NEW" 5)
+ let newInputCol = CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "NEW" 5)
let columns = [|
column_param
newInputCol
@@ -1563,7 +1563,7 @@ let private tests_AddColumns =
)
testCase "multiple columns, more rowCount, duplicate replace" (fun () ->
let testTable = create_testTable()
- let newInput = CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "NEW" 8)
+ let newInput = CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "NEW" 8)
let newColumn = CompositeColumn.create(CompositeHeader.Characteristic oa_species, createCells_Term 8)
let columns = [|
newColumn
@@ -1592,7 +1592,7 @@ let private tests_AddColumns =
)
testCase "multiple columns, different rowCount, duplicate replace" (fun () ->
let testTable = create_testTable()
- let newInput = CompositeColumn.create(CompositeHeader.Input IOType.RawDataFile, createCells_FreeText "NEW" 2)
+ let newInput = CompositeColumn.create(CompositeHeader.Input IOType.Data, createCells_FreeText "NEW" 2)
let newColumn = CompositeColumn.create(CompositeHeader.Characteristic oa_species, createCells_Term 8)
let columns = [|
newColumn
@@ -2152,13 +2152,13 @@ let private tests_Join = testList "Join" [
let table = create_testTable()
let joinTable = ArcTable.create(
"jointable",
- ResizeArray([CompositeHeader.Input IOType.ImageFile]),
+ ResizeArray([CompositeHeader.Input IOType.Data]),
System.Collections.Generic.Dictionary()
)
table.Join(joinTable,-1,TableJoinOptions.Headers,true)
Expect.equal table.ColumnCount 5 "columnCount"
// test headers
- Expect.equal table.Headers.[0] (CompositeHeader.Input IOType.ImageFile) "Here should be new image input"
+ Expect.equal table.Headers.[0] (CompositeHeader.Input IOType.Data) "Here should be new image input"
Expect.equal table.Headers.[1] (CompositeHeader.Output IOType.Sample) "Header output"
Expect.equal table.Headers.[2] (CompositeHeader.Parameter (OntologyAnnotation())) "Header parameter [empty]"
Expect.equal table.Headers.[3] (CompositeHeader.Component oa_instrumentModel) "Header component [instrument model]"
@@ -2221,7 +2221,7 @@ let private tests_Join = testList "Join" [
let private tests_IterColumns = testList "IterColumns" [
testCase "Replace input column header" <| fun _ ->
let table = create_testTable()
- let expected = CompositeHeader.Input IOType.RawDataFile
+ let expected = CompositeHeader.Input IOType.Data
table.IteriColumns (fun i c ->
if c.Header.isInput then
table.UpdateHeader(i,expected)
diff --git a/tests/Core/CompositeCell.Tests.fs b/tests/Core/CompositeCell.Tests.fs
index 9dd48808..740c26e2 100644
--- a/tests/Core/CompositeCell.Tests.fs
+++ b/tests/Core/CompositeCell.Tests.fs
@@ -107,7 +107,18 @@ let private tests_create =
let expected = CompositeCell.Unitized("42", oa)
Expect.equal newCell expected ""
)
- ]
+ testCase "createData" (fun () ->
+ let d = Data(name = "MyData#row=1", format = "text/csv", selectorFormat = "MySelector")
+ let newCell : CompositeCell = CompositeCell.createData(d)
+ let expected = CompositeCell.Data d
+ Expect.equal newCell expected ""
+ )
+ testCase "createDataFromString" (fun () ->
+ let newCell : CompositeCell = CompositeCell.createDataFromString("MyData#row=1", "text/csv", "MySelector")
+ let expected = CompositeCell.Data <| Data(name = "MyData#row=1", format = "text/csv", selectorFormat = "MySelector")
+ Expect.equal newCell expected ""
+ )
+ ]
let private tests_ToString = testList "ToString" [
testCase "FreeText" <| fun _ ->
@@ -125,6 +136,12 @@ let private tests_ToString = testList "ToString" [
let actual = cc.ToString()
let expected = "20 degree celcius"
Expect.equal actual expected ""
+ testCase "Data" <| fun _ ->
+ let d = Data(name = "MyData#row=1", format = "text/csv", selectorFormat = "MySelector")
+ let cc = CompositeCell.createData d
+ let actual = cc.ToString()
+ let expected = "MyData#row=1"
+ Expect.equal actual expected ""
]
let private tests_GetContent = testList "GetContent" [
@@ -140,6 +157,11 @@ let private tests_GetContent = testList "GetContent" [
let cell = CompositeCell.createUnitized ("12", OntologyAnnotation("My Unit Name"))
let actual = cell.GetContent()
Expect.equal actual [|"12"; "My Unit Name"; ""; ""|] ""
+ testCase "Data" <| fun _ ->
+ let d = Data(name = "MyData#row=1", format = "text/csv", selectorFormat = "MySelector")
+ let cell = CompositeCell.createData d
+ let actual = cell.GetContent()
+ Expect.equal actual [|"MyData#row=1"; "text/csv"; "MySelector"|] ""
testCase "Matching" <| fun _ ->
let matchContent (content: string []) =
match content with
@@ -189,6 +211,11 @@ let private tests_GetHashCode = testList "GetHashCode" [
let cc = CompositeCell.createFreeText("TestTerm")
cc.GetHashCode() |> ignore
Expect.isTrue true " "
+ testCase "Data" <| fun _ ->
+ let d = Data(name = "MyData#row=1", format = "text/csv", selectorFormat = "MySelector")
+ let cc = CompositeCell.createData d
+ cc.GetHashCode() |> ignore
+ Expect.isTrue true " "
]
]
diff --git a/tests/Core/CompositeColumn.Tests.fs b/tests/Core/CompositeColumn.Tests.fs
index 195ae1aa..3823dd52 100644
--- a/tests/Core/CompositeColumn.Tests.fs
+++ b/tests/Core/CompositeColumn.Tests.fs
@@ -53,7 +53,7 @@ let private tests_Validate =
Expect.throws eval ""
)
testCase "Invalid io column with term cells" (fun () ->
- let header : CompositeHeader = CompositeHeader.Input IOType.ImageFile
+ let header : CompositeHeader = CompositeHeader.Input IOType.Data
let cells : CompositeCell [] = Array.init 2 (fun _ -> CompositeCell.emptyTerm)
let column = CompositeColumn.create(header, cells).Validate()
let eval() = CompositeColumn.create(header, cells).Validate(true) |> ignore
@@ -61,7 +61,7 @@ let private tests_Validate =
Expect.throws eval ""
)
testCase "Invalid io column with unit cells" (fun () ->
- let header : CompositeHeader = CompositeHeader.Input IOType.ImageFile
+ let header : CompositeHeader = CompositeHeader.Input IOType.Data
let cells : CompositeCell [] = Array.init 2 (fun _ -> CompositeCell.emptyUnitized)
let column = CompositeColumn.create(header, cells).Validate()
let eval() = CompositeColumn.create(header, cells).Validate(true) |> ignore
diff --git a/tests/Core/CompositeHeader.Tests.fs b/tests/Core/CompositeHeader.Tests.fs
index 422f184e..25437a5b 100644
--- a/tests/Core/CompositeHeader.Tests.fs
+++ b/tests/Core/CompositeHeader.Tests.fs
@@ -10,18 +10,14 @@ let private tests_iotype =
testCase "asInput" (fun () ->
Expect.equal IOType.Source.asInput "Input [Source Name]" "Source"
Expect.equal IOType.Sample.asInput "Input [Sample Name]" "Sample"
- Expect.equal IOType.RawDataFile.asInput "Input [Raw Data File]" "Raw Data File"
- Expect.equal IOType.DerivedDataFile.asInput "Input [Derived Data File]" "Derived Data File"
- Expect.equal IOType.ImageFile.asInput "Input [Image File]" "Image File"
+ Expect.equal IOType.Data.asInput "Input [Data]" "Data"
Expect.equal IOType.Material.asInput "Input [Material]" "Material"
Expect.equal (IOType.FreeText "Test").asInput "Input [Test]" "FreeText Test"
)
testCase "asOutput" (fun () ->
Expect.equal IOType.Source.asOutput "Output [Source Name]" "Source"
Expect.equal IOType.Sample.asOutput "Output [Sample Name]" "Sample"
- Expect.equal IOType.RawDataFile.asOutput "Output [Raw Data File]" "Raw Data File"
- Expect.equal IOType.DerivedDataFile.asOutput "Output [Derived Data File]" "Derived Data File"
- Expect.equal IOType.ImageFile.asOutput "Output [Image File]" "Image File"
+ Expect.equal IOType.Data.asOutput "Output [Data]" "Data"
Expect.equal IOType.Material.asOutput "Output [Material]" "Material"
Expect.equal (IOType.FreeText "Test").asOutput "Output [Test]" "FreeText Test"
)
@@ -30,7 +26,7 @@ let private tests_iotype =
let caseInfos = IOType.Cases
Expect.hasLength IOType.All (caseInfos.Length-1) "Expect one less than all because we do not want to track `FreeText` case."
)
- testCase "getUIToolTip" <| fun _ ->
+ ptestCase "getUIToolTip" <| fun _ ->
let cases = IOType.Cases |> Array.map snd
for case in cases do
let actual = IOType.getUITooltip(U2.Case2 case)
@@ -102,10 +98,10 @@ let private tests_compositeHeader =
let expected = "Input [Source Name]"
Expect.equal actual expected ""
)
- testCase "Output ImageFile" (fun () ->
- let header = CompositeHeader.Input IOType.ImageFile
+ testCase "Output Data" (fun () ->
+ let header = CompositeHeader.Output IOType.Data
let actual = header.ToString()
- let expected = "Input [Image File]"
+ let expected = "Output [Data]"
Expect.equal actual expected ""
)
]
@@ -375,7 +371,7 @@ let tests_GetHashCode = testList "GetHashCode" [
)
testCase "InputDifferentType" (fun () ->
let i1 = CompositeHeader.Input(IOType.Sample)
- let i2 = CompositeHeader.Input(IOType.RawDataFile)
+ let i2 = CompositeHeader.Input(IOType.Data)
let h1 = i1.GetHashCode()
let h2 = i2.GetHashCode()
Expect.notEqual h1 h2 "Input Sample Header should be unequal to Input Data"
diff --git a/tests/Core/Data.Tests.fs b/tests/Core/Data.Tests.fs
new file mode 100644
index 00000000..4da482f6
--- /dev/null
+++ b/tests/Core/Data.Tests.fs
@@ -0,0 +1,28 @@
+module Data.Tests
+
+open ARCtrl
+
+open TestingUtils
+
+let private tests_GetHashCode = testList "GetHashCode" [
+ testCase "equal" <| fun _ ->
+ let d1 = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let d2 = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let hash1 = d1.GetHashCode()
+ let hash2 = d2.GetHashCode()
+ Expect.equal d1 d2 "Should be equal"
+ Expect.equal hash1 hash2 "HashCode should be equal"
+ testCase "unequal, different name" <| fun _ ->
+ let d1 = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let d2 = Data("MyID","MyName2",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let hash1 = d1.GetHashCode()
+ let hash2 = d2.GetHashCode()
+ Expect.notEqual d1 d2 "Should not be equal"
+ Expect.notEqual hash1 hash2 "HashCode should not be equal"
+ ]
+
+
+let main =
+ testList "Data" [
+ tests_GetHashCode
+ ]
\ No newline at end of file
diff --git a/tests/Core/Main.fs b/tests/Core/Main.fs
index 56851605..ddc81d2c 100644
--- a/tests/Core/Main.fs
+++ b/tests/Core/Main.fs
@@ -8,6 +8,7 @@ let all = testSequenced <| testList "Core" [
Regex.Tests.main
Person.Tests.main
CompositeHeader.Tests.main
+ Data.Tests.main
CompositeCell.Tests.main
CompositeColumn.Tests.main
ArcTables.Tests.main
diff --git a/tests/Core/Template.Tests.fs b/tests/Core/Template.Tests.fs
index 4a5102eb..e59f449a 100644
--- a/tests/Core/Template.Tests.fs
+++ b/tests/Core/Template.Tests.fs
@@ -11,7 +11,7 @@ open TestingUtils
let create_TestTemplate() =
let table = ArcTable.init("My Table")
table.AddColumn(CompositeHeader.Input IOType.Source, [|for i in 0 .. 9 do yield CompositeCell.createFreeText($"Source {i}")|])
- table.AddColumn(CompositeHeader.Output IOType.RawDataFile, [|for i in 0 .. 9 do yield CompositeCell.createFreeText($"Output {i}")|])
+ table.AddColumn(CompositeHeader.Output IOType.Data, [|for i in 0 .. 9 do yield CompositeCell.createFreeText($"Output {i}")|])
let guid = System.Guid(String.init 32 (fun _ -> "d"))
Template.make
guid
diff --git a/tests/JavaScript/CompositeHeader.js b/tests/JavaScript/CompositeHeader.js
index 956771ee..ce530680 100644
--- a/tests/JavaScript/CompositeHeader.js
+++ b/tests/JavaScript/CompositeHeader.js
@@ -8,7 +8,7 @@ function tests_IOType() {
it('cases', function () {
let cases = IOType.Cases
//console.log(cases)
- equal(cases.length, 7);
+ equal(cases.length, 5);
});
it('Create non Freetext', function () {
for (let mycase of IOType.Cases) {
@@ -22,25 +22,19 @@ function tests_IOType() {
equal(iotype.asInput, "Input [Sample Name]");
break;
case 2:
- equal(iotype.asInput, "Input [Raw Data File]");
+ equal(iotype.asInput, "Input [Data]");
break;
case 3:
- equal(iotype.asInput, "Input [Derived Data File]");
- break;
- case 4:
- equal(iotype.asInput, "Input [Image File]");
- break;
- case 5:
equal(iotype.asInput, "Input [Material]");
break;
- case 6:
+ case 4:
equal(iotype.asInput, "Input [undefined]");
break;
}
}
});
it('Create FreeText', function () {
- let freetext = new IOType(6, ["My FreeTextValue"])
+ let freetext = new IOType(4, ["My FreeTextValue"])
let asinput = freetext.asInput
equal(asinput, "Input [My FreeTextValue]")
});
@@ -53,26 +47,17 @@ function tests_IOType() {
let sa2 = new IOType(1, [])
assertEqual(sa1, sa2);
- let ra1 = IOType.rawDataFile()
+ let ra1 = IOType.data()
let ra2 = new IOType(2, [])
assertEqual(ra1, ra2);
- let da1 = IOType.derivedDataFile()
- let da2 = new IOType(3, [])
- assertEqual(da1, da2);
-
- let im1 = IOType.imageFile()
- let im2 = new IOType(4, [])
- //let imb = equals(im1, im2);
- assertEqual(im1, im2);
-
let ma1 = IOType.material()
- let ma2 = new IOType(5, [])
+ let ma2 = new IOType(3, [])
assertEqual(ma1, ma2);
let ft = "My FreeTextValue"
let ft1 = IOType.freeText(ft)
- let ft2 = new IOType(6, [ft])
+ let ft2 = new IOType(4, [ft])
assertEqual(ft1, ft2);
});
@@ -82,7 +67,7 @@ function tests_IOType() {
describe('CompositeHeader', function () {
tests_IOType();
it("Input", function () {
- let iotype = new IOType(6, ["My FreeTextValue"])
+ let iotype = new IOType(4, ["My FreeTextValue"])
let header = new CompositeHeader(11, [iotype])
let actual = header.toString()
equal(actual, "Input [My FreeTextValue]")
diff --git a/tests/Json/ARCtrl.Json.Tests.fsproj b/tests/Json/ARCtrl.Json.Tests.fsproj
index d0ac62b9..9835cf5f 100644
--- a/tests/Json/ARCtrl.Json.Tests.fsproj
+++ b/tests/Json/ARCtrl.Json.Tests.fsproj
@@ -17,6 +17,7 @@
+
diff --git a/tests/Json/ArcTable.Tests.fs b/tests/Json/ArcTable.Tests.fs
index e83a4d61..a7486342 100644
--- a/tests/Json/ArcTable.Tests.fs
+++ b/tests/Json/ArcTable.Tests.fs
@@ -91,10 +91,24 @@ let private tests = testList "extended" [
]
]
+let private tests_dataColumns =
+ testList "dataColumns" [
+ testCase "dataColumns" <| fun _ ->
+ let testTable = ArcTable.init("Test")
+ testTable.AddColumn (CompositeHeader.Input IOType.Data, [|CompositeCell.Data (Data(name="MyInputDataFile.csv"))|])
+ testTable.AddColumn (CompositeHeader.Output IOType.Data, [|CompositeCell.Data (Data(name="MyData.csv#row=1",format="text/csv",selectorFormat = "MySelector"))|])
+
+ let encoded = testTable.ToJsonString()
+ let decoded = ArcTable.fromJsonString encoded
+ Expect.arcTableEqual decoded testTable "decompressed table should be equal to original table"
+ ]
+
+
let main = testList "ArcTable" [
tests
tests_core
tests_coreEmpty
tests_compressedEmpty
tests_compressedFilled
+ tests_dataColumns
]
\ No newline at end of file
diff --git a/tests/Json/Assay.Tests.fs b/tests/Json/Assay.Tests.fs
index 47dcc2ce..d4fbff9c 100644
--- a/tests/Json/Assay.Tests.fs
+++ b/tests/Json/Assay.Tests.fs
@@ -13,8 +13,8 @@ module Helper =
OntologyAnnotation("TT", "MS", "MS:696969"),
OntologyAnnotation("TP", "MS", "MS:123456", ResizeArray [Comment.create("Hello","Space")]),
ResizeArray([Tests.ArcTable.Helper.create_filled(); ArcTable.init("My Second Table")]),
- ResizeArray [|Person.create(firstName="Kevin", lastName="Frey")|],
- ResizeArray [|Comment.create("Hello", "World")|]
+ performers = ResizeArray [|Person.create(firstName="Kevin", lastName="Frey")|],
+ comments = ResizeArray [|Comment.create("Hello", "World")|]
)
let compare =
@@ -65,7 +65,7 @@ let private test_roCrateEmpty =
createBaseJsonTests
"ROCrate-empty"
create_empty
- (fun () -> ArcAssay.toROCrateJsonString None)
+ (fun () -> ArcAssay.toROCrateJsonString())
ArcAssay.fromROCrateJsonString
None
compare
@@ -111,12 +111,12 @@ let private test_roCrate = testList "ROCrate" [
// Mainly: #12, #9, #10, #13
ptestCase "Write" <| fun _ ->
let a = create_filled()
- let json = ArcAssay.toROCrateJsonString None a
+ let json = ArcAssay.toROCrateJsonString() a
printfn "%s" json
createBaseJsonTests
""
create_filled
- (fun () -> ArcAssay.toROCrateJsonString None)
+ (fun () -> ArcAssay.toROCrateJsonString())
ArcAssay.fromROCrateJsonString
None
compare
diff --git a/tests/Json/CompositeCell.Tests.fs b/tests/Json/CompositeCell.Tests.fs
index 63222dcf..464631bb 100644
--- a/tests/Json/CompositeCell.Tests.fs
+++ b/tests/Json/CompositeCell.Tests.fs
@@ -15,6 +15,9 @@ let tests_extended = testList "extended" [
let cell_term_empty_jsonString = sprintf """{"%s":"Term","values":[{}]}""" CompositeCell.CellType
let cell_unitized_jsonString = sprintf """{"%s":"Unitized","values":["42",{"annotationValue":"My Name","termSource":"MY","termAccession":"MY:1"}]}""" CompositeCell.CellType
let cell_unitized_empty_jsonString = sprintf """{"%s":"Unitized","values":["",{}]}""" CompositeCell.CellType
+ let cell_data_empty_jsonString = sprintf """{"%s":"Data","values":[{}]}""" CompositeCell.CellType
+ let cell_data_jsonString = sprintf """{"%s":"Data","values":[{"@id":"MyID","name":"MyName","dataType":"Raw Data File","format":"text/csv","selectorFormat":"MySelector","comments":[{"name":"MyKey","value":"MyValue"}]}]}""" CompositeCell.CellType
+
testList "encoder (toJsonString)" [
testCase "FreeText" <| fun _ ->
let actual = CompositeCell.encoder cell_freetext |> Encode.toJsonString 0
@@ -36,6 +39,14 @@ let tests_extended = testList "extended" [
let actual = CompositeCell.encoder cell_unitized_empty |> Encode.toJsonString 0
let expected = cell_unitized_empty_jsonString
Expect.equal actual expected ""
+ testCase "Data" <| fun _ ->
+ let actual = CompositeCell.encoder (CompositeCell.Data(Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])) ) |> Encode.toJsonString 0
+ let expected = cell_data_jsonString
+ Expect.equal actual expected ""
+ testCase "Data empty" <| fun _ ->
+ let actual = CompositeCell.encoder (CompositeCell.Data(Data())) |> Encode.toJsonString 0
+ let expected = cell_data_empty_jsonString
+ Expect.equal actual expected ""
]
testList "decoder (fromJsonString)" [
testCase "FreeText" <| fun _ ->
@@ -58,6 +69,14 @@ let tests_extended = testList "extended" [
let actual = Decode.fromJsonString CompositeCell.decoder cell_unitized_empty_jsonString
let expected = cell_unitized_empty
Expect.equal actual expected ""
+ testCase "Data" <| fun _ ->
+ let actual = Decode.fromJsonString CompositeCell.decoder cell_data_jsonString
+ let expected = CompositeCell.Data(Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")]))
+ Expect.equal actual expected ""
+ testCase "Data empty" <| fun _ ->
+ let actual = Decode.fromJsonString CompositeCell.decoder cell_data_empty_jsonString
+ let expected = CompositeCell.Data(Data())
+ Expect.equal actual expected ""
]
]
diff --git a/tests/Json/Data.Tests.fs b/tests/Json/Data.Tests.fs
new file mode 100644
index 00000000..78d5ece0
--- /dev/null
+++ b/tests/Json/Data.Tests.fs
@@ -0,0 +1,59 @@
+module Tests.Data
+
+open TestingUtils
+open ARCtrl
+open ARCtrl.Json
+
+let basic_tests = testList "BasicJson" [
+ testCase "AllFields" <| fun _ ->
+ let d = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let json = Data.encoder d |> Encode.toJsonString 2
+ let d2 = Decode.fromJsonString Data.decoder json
+ Expect.equal d2 d "Different after write and read"
+ ]
+
+let isa_tests = testList "ISAJson" [
+ testCase "NativeISAFieldsIO" <| fun _ ->
+ let d = Data("MyID","MyName",DataFile.RawDataFile,comments = ResizeArray [Comment.create("MyKey","MyValue")])
+ let json = Data.ISAJson.encoder d |> Encode.toJsonString 2
+ let d2 = Decode.fromJsonString Data.ISAJson.decoder json
+ Expect.equal d2 d "Different after write and read"
+ ptestCase "AllFieldsLossless" <| fun _ ->
+ let d = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let json = Data.ISAJson.encoder d |> Encode.toJsonString 2
+ let d2 = Decode.fromJsonString Data.ISAJson.decoder json
+ Expect.equal d2 d "Different after write and read"
+ #if !FABLE_COMPILER_PYTHON
+ testAsync "WriterSchemaCorrectness" {
+ let d = Data("MyID","MyName",DataFile.RawDataFile, "text/csv", "MySelector", ResizeArray [Comment.create("MyKey","MyValue")])
+ let json = Data.ISAJson.encoder d |> Encode.toJsonString 2
+ let! validation = Validation.validateData json
+ Expect.isTrue validation.Success $"Data did not match schema: {validation.GetErrors()}"
+ }
+ #endif
+]
+
+let rocrate_tests = testList "RO-CrateJson" [
+ testCase "AllFields" <| fun _ ->
+ let d = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let json = Data.ROCrate.encoder d |> Encode.toJsonString 2
+ let d2 = Decode.fromJsonString Data.ROCrate.decoder json
+ Expect.equal d2 d "Different after write and read"
+ ]
+
+let compressed_tests =
+ testList "CompressedJson" [
+ testCase "AllFields" <| fun _ ->
+ let d = Data("MyID","MyName",DataFile.RawDataFile,"text/csv","MySelector",ResizeArray [Comment.create("MyKey","MyValue")])
+ let stringTable = StringTable.StringTableMap()
+ let json = Data.compressedEncoder stringTable d |> Encode.toJsonString 2
+ let d2 = Decode.fromJsonString (Data.compressedDecoder (StringTable.arrayFromMap stringTable)) json
+ Expect.equal d2 d "Different after write and read"
+ ]
+
+let main = testList "Data" [
+ basic_tests
+ isa_tests
+ rocrate_tests
+ compressed_tests
+]
\ No newline at end of file
diff --git a/tests/Json/Main.fs b/tests/Json/Main.fs
index 9b4043a1..ca032176 100644
--- a/tests/Json/Main.fs
+++ b/tests/Json/Main.fs
@@ -6,6 +6,7 @@ let all = testSequenced <| testList "Json" [
Tests.Decoder.main
Tests.Comment.main
Tests.OntologyAnnotation.main
+ Tests.Data.main
Tests.CompositeCell.main
Tests.IOType.main
Tests.CompositeHeader.main
diff --git a/tests/Json/Study.Tests.fs b/tests/Json/Study.Tests.fs
index 2bbbf52d..e029bc10 100644
--- a/tests/Json/Study.Tests.fs
+++ b/tests/Json/Study.Tests.fs
@@ -22,8 +22,8 @@ module Helper =
ResizeArray [|Person.create(firstName="Kevin", lastName="Frey", phone="023382093810")|],
ResizeArray [|OntologyAnnotation(); OntologyAnnotation()|],
ResizeArray [ArcTable.Helper.create_filled(); ArcTable.init("Table 2")],
- ResizeArray ["Assay 1"; "Assay 2"],
- ResizeArray [|Comment.create("Hello", "World")|]
+ registeredAssayIdentifiers = ResizeArray ["Assay 1"; "Assay 2"],
+ comments = ResizeArray [|Comment.create("Hello", "World")|]
)
let compareFields =
diff --git a/tests/Json/Template.Tests.fs b/tests/Json/Template.Tests.fs
index baf2bb4a..f5c00dd4 100644
--- a/tests/Json/Template.Tests.fs
+++ b/tests/Json/Template.Tests.fs
@@ -55,7 +55,7 @@ let tests_Template =
testCase "complete" <| fun _ ->
let table = ArcTable.init("My Table")
table.AddColumn(CompositeHeader.Input IOType.Source, [|for i in 0 .. 9 do yield CompositeCell.createFreeText($"Source {i}")|])
- table.AddColumn(CompositeHeader.Output IOType.RawDataFile, [|for i in 0 .. 9 do yield CompositeCell.createFreeText($"Output {i}")|])
+ table.AddColumn(CompositeHeader.Output IOType.Data, [|for i in 0 .. 9 do yield CompositeCell.createFreeText($"Output {i}")|])
let o = Template.init("MyTemplate")
o.Table <- table
o.Authors <- ResizeArray [|ARCtrl.Person.create(firstName="John", lastName="Doe"); ARCtrl.Person.create(firstName="Jane", lastName="Doe");|]
diff --git a/tests/Spreadsheet/ARCtrl.Spreadsheet.Tests.fsproj b/tests/Spreadsheet/ARCtrl.Spreadsheet.Tests.fsproj
index 339ff304..7cbc904b 100644
--- a/tests/Spreadsheet/ARCtrl.Spreadsheet.Tests.fsproj
+++ b/tests/Spreadsheet/ARCtrl.Spreadsheet.Tests.fsproj
@@ -13,6 +13,7 @@
+
diff --git a/tests/Spreadsheet/ArcTableTests.fs b/tests/Spreadsheet/ArcTableTests.fs
index 84bd2a80..915d3f12 100644
--- a/tests/Spreadsheet/ArcTableTests.fs
+++ b/tests/Spreadsheet/ArcTableTests.fs
@@ -236,7 +236,7 @@ let private ioTable =
Parameter.appendTemperatureColumn 1
Characteristic.appendOrganismColumn 1
Factor.appendTimeColumn 1
- Output.appendRawDataColumn 1
+ Output.appendSimpleDataColumn 1
]
testCase "Read" (fun () ->
@@ -256,7 +256,7 @@ let private ioTable =
Parameter.temperatureHeader
Characteristic.organismHeader
Factor.timeHeader
- Output.rawDataHeader
+ Output.simpleDataHeader
]
Expect.sequenceEqual table.Headers expectedHeaders "Headers did not match"
let expectedCells =
@@ -266,7 +266,7 @@ let private ioTable =
Parameter.temperatureValue
Characteristic.organismValue
Factor.timeValue
- Output.rawDataValue
+ Output.simpleDataValue
]
Expect.sequenceEqual (table.GetRow(0)) expectedCells "Cells did not match"
)
@@ -280,7 +280,54 @@ let private ioTable =
)
]
+let private fullDataTable =
+ testList "fullDataTable" [
+ let wsName = "MyWorksheet"
+ let ws =
+ initWorksheet wsName
+ [
+ Input.appenddataColumn 1
+ Protocol.REF.appendLolColumn 1
+ Parameter.appendTemperatureColumn 1
+ Output.appendFullDataColumn 1
+ ]
+ testCase "Read" (fun () ->
+
+ let table = ArcTable.tryFromFsWorksheet ws
+
+ Expect.isSome table "Table was not created"
+ let table = table.Value
+
+ Expect.equal table.Name wsName "Name did not match"
+ Expect.equal table.ColumnCount 4 "Wrong number of columns"
+ Expect.equal table.RowCount 1 "Wrong number of rows"
+ let expectedHeaders =
+ [
+ Input.dataHeader
+ Protocol.REF.lolHeader
+ Parameter.temperatureHeader
+ Output.fullDataHeader
+ ]
+ Expect.sequenceEqual table.Headers expectedHeaders "Headers did not match"
+ let expectedCells =
+ [
+ Input.dataValue
+ Protocol.REF.lolValue
+ Parameter.temperatureValue
+ Output.fullDataValue
+ ]
+ Expect.sequenceEqual (table.GetRow(0)) expectedCells "Cells did not match"
+ )
+ testCase "Write" (fun () ->
+
+ let table = ArcTable.tryFromFsWorksheet ws
+ Expect.isSome table "Table was not created"
+ let out = ArcTable.toFsWorksheet table.Value
+ Expect.workSheetEqual out ws "Worksheet was not correctly written"
+
+ )
+ ]
let private deprecatedColumnTable =
testList "deprecatedIOColumnTable" [
@@ -317,11 +364,11 @@ let private deprecatedColumnTable =
let expectedCells =
[
- Input.sampleValue
+ Input.sourceValue
Protocol.REF.lolValue
Protocol.Type.collectionValue
Parameter.temperatureValue
- Output.rawDataValue
+ Output.sampleValue
]
Expect.sequenceEqual (table.GetRow(0)) expectedCells "Cells did not match"
)
@@ -338,7 +385,7 @@ let private writeOrder =
[
Parameter.appendTemperatureColumn 1
Characteristic.appendOrganismColumn 1
- Output.appendRawDataColumn 1
+ Output.appendSimpleDataColumn 1
Protocol.REF.appendLolColumn 1
Input.appendSampleColumn 1
Factor.appendTimeColumn 1
@@ -355,7 +402,7 @@ let private writeOrder =
Parameter.appendTemperatureColumn 1
Characteristic.appendOrganismColumn 1
Factor.appendTimeColumn 1
- Output.appendRawDataColumn 1
+ Output.appendSimpleDataColumn 1
]
Expect.workSheetEqual mixedOut orderedWs "Columns were not ordered correctly"
@@ -386,6 +433,7 @@ let main =
mixedTable
ioTable
valuelessTable
+ fullDataTable
deprecatedColumnTable
writeOrder
emptyTable
diff --git a/tests/Spreadsheet/CompositeHeaderTests.fs b/tests/Spreadsheet/CompositeHeaderTests.fs
index 21cc62ad..cb09be00 100644
--- a/tests/Spreadsheet/CompositeHeaderTests.fs
+++ b/tests/Spreadsheet/CompositeHeaderTests.fs
@@ -2,6 +2,28 @@
open TestingUtils
+open ARCtrl
+open ARCtrl.Spreadsheet
+open FsSpreadsheet
+
+let deprecatedDataHeaders =
+ testList "DeprecatedIOHeaders" [
+ testCase "Raw Data File" <| fun _ ->
+ let cells = FsCell.create 1 1 "Input [Raw Data File]"
+ let header,_ = CompositeHeader.fromFsCells [cells]
+ Expect.equal header (CompositeHeader.Input IOType.Data) "Should be Input [Data]"
+ testCase "Derived Data File" <| fun _ ->
+ let cells = FsCell.create 1 1 "Output [Derived Data File]"
+ let header,_ = CompositeHeader.fromFsCells [cells]
+ Expect.equal header (CompositeHeader.Output IOType.Data) "Should be Output [Data]"
+ testCase "Image File" <| fun _ ->
+ let cells = FsCell.create 1 1 "Output [Image File]"
+ let header,_ = CompositeHeader.fromFsCells [cells]
+ Expect.equal header (CompositeHeader.Output IOType.Data) "Should be Output [Image]"
+ ]
+
+
let main =
testList "CompositeHeader" [
+ deprecatedDataHeaders
]
\ No newline at end of file
diff --git a/tests/Spreadsheet/DataMapTests.fs b/tests/Spreadsheet/DataMapTests.fs
new file mode 100644
index 00000000..6d43065f
--- /dev/null
+++ b/tests/Spreadsheet/DataMapTests.fs
@@ -0,0 +1,192 @@
+module DataMapTests
+
+
+open ARCtrl
+open ARCtrl.Spreadsheet
+open FsSpreadsheet
+
+open TestingUtils
+open TestObjects.Spreadsheet.DataMap
+
+let private simpleTable =
+ testList "simpleTable" [
+ let wsName = "isa_datamap"
+ let ws =
+ initWorksheet wsName
+ [
+ Data.appendDataColumn 1
+ Explication.appendMeanColumn 1
+ Unit.appendPPMColumn 1
+ ObjectType.appendFloatColumn 1
+ Description.appendDescriptionColumn 1
+ GeneratedBy.appendGeneratedByColumn 1
+
+ ]
+ testCase "Read" (fun () ->
+
+ let table = DataMapTable.tryFromFsWorksheet ws
+
+ Expect.isSome table "Table was not created"
+ let table = table.Value
+
+ Expect.equal table.Table.ColumnCount 6 "Wrong number of columns"
+ Expect.equal table.Table.RowCount 1 "Wrong number of rows"
+
+ let expectedHeaders =
+ [
+ DataMapAux.dataHeader
+ DataMapAux.explicationHeader
+ DataMapAux.unitHeader
+ DataMapAux.objectTypeHeader
+ DataMapAux.descriptionHeader
+ DataMapAux.generatedByHeader
+ ]
+ Expect.sequenceEqual table.Headers expectedHeaders "Headers did not match"
+
+ let expectedCells =
+ [
+ Data.dataValue
+ Explication.meanValue
+ Unit.ppmValue
+ ObjectType.floatValue
+ Description.descriptionValue
+ GeneratedBy.generatedByValue
+ ]
+ Expect.sequenceEqual (table.GetRow(0)) expectedCells "Cells did not match"
+ )
+ testCase "Write" (fun () ->
+
+ let table = DataMapTable.tryFromFsWorksheet ws
+ Expect.isSome table "Table was not created"
+ let out = DataMapTable.toFsWorksheet table.Value
+ Expect.workSheetEqual out ws "Worksheet was not correctly written"
+
+ )
+ ]
+
+let private valuelessTable =
+ testList "valuelessTable" [
+ let wsName = "isa_datamap"
+ let ws =
+ initWorksheet wsName
+ [
+ Data.appendDataColumn 0
+ Explication.appendMeanColumn 0
+ Unit.appendPPMColumn 0
+ ObjectType.appendFloatColumn 0
+ Description.appendDescriptionColumn 0
+ GeneratedBy.appendGeneratedByColumn 0
+ ]
+ testCase "Read" (fun () ->
+
+ let table = DataMapTable.tryFromFsWorksheet ws
+
+ Expect.isSome table "Table was not created"
+ let table = table.Value
+
+ Expect.equal table.Table.ColumnCount 6 "Wrong number of columns"
+ Expect.equal table.Table.RowCount 0 "Wrong number of rows"
+
+ let expectedHeaders =
+ [
+ DataMapAux.dataHeader
+ DataMapAux.explicationHeader
+ DataMapAux.unitHeader
+ DataMapAux.objectTypeHeader
+ DataMapAux.descriptionHeader
+ DataMapAux.generatedByHeader
+ ]
+ Expect.sequenceEqual table.Headers expectedHeaders "Headers did not match"
+ )
+ // TODO: What should we do with units of empty columns?
+ //testCase "Write" (fun () ->
+
+ // let table = ArcTable.tryFromFsWorksheet ws
+ // Expect.isSome table "Table was not created"
+ // let out = ArcTable.toFsWorksheet table.Value
+ // Expect.workSheetEqual out ws "Worksheet was not correctly written"
+
+ //)
+ ]
+
+let private emptyTable =
+ testList "emptyTable" [
+ let t = DataMap.init()
+ testCase "Write" (fun () ->
+ let sheet = DataMapTable.toFsWorksheet t
+ Expect.equal "isa_datamap" sheet.Name "Worksheet name did not match"
+ Expect.equal 0 sheet.Rows.Count "Row count should be 0"
+ )
+ testCase "Read" (fun () ->
+ let sheet = DataMapTable.toFsWorksheet t
+ Expect.isNone (DataMapTable.tryFromFsWorksheet sheet) "Table was not created"
+ )
+ ]
+
+let private simpleFile =
+ testList "simpleFile" [
+ let wb = new FsWorkbook()
+ let wsName = "isa_datamap"
+ let ws =
+ initWorksheet wsName
+ [
+ Data.appendDataColumn 1
+ Explication.appendMeanColumn 1
+ Unit.appendPPMColumn 1
+ ObjectType.appendFloatColumn 1
+ Description.appendDescriptionColumn 1
+ GeneratedBy.appendGeneratedByColumn 1
+
+ ]
+ wb.AddWorksheet ws
+ testCase "Read" (fun () ->
+
+ let table = DataMap.fromFsWorkbook wb
+
+ Expect.equal table.Table.ColumnCount 6 "Wrong number of columns"
+ Expect.equal table.Table.RowCount 1 "Wrong number of rows"
+
+ let expectedHeaders =
+ [
+ DataMapAux.dataHeader
+ DataMapAux.explicationHeader
+ DataMapAux.unitHeader
+ DataMapAux.objectTypeHeader
+ DataMapAux.descriptionHeader
+ DataMapAux.generatedByHeader
+ ]
+ Expect.sequenceEqual table.Headers expectedHeaders "Headers did not match"
+
+ let expectedCells =
+ [
+ Data.dataValue
+ Explication.meanValue
+ Unit.ppmValue
+ ObjectType.floatValue
+ Description.descriptionValue
+ GeneratedBy.generatedByValue
+ ]
+ Expect.sequenceEqual (table.GetRow(0)) expectedCells "Cells did not match"
+ )
+ testCase "Write" (fun () ->
+
+ let table = DataMap.fromFsWorkbook wb
+
+ let out = DataMap.toFsWorkbook table
+
+ Expect.equal (out.GetWorksheets().Count) 1 "Wrong number of worksheets"
+
+ let wsOut = out.GetWorksheets().[0]
+
+ Expect.workSheetEqual wsOut ws "Worksheet was not correctly written"
+
+ )
+ ]
+
+let main =
+ testList "DataMapTableTests" [
+ simpleTable
+ valuelessTable
+ emptyTable
+ simpleFile
+ ]
\ No newline at end of file
diff --git a/tests/Spreadsheet/Main.fs b/tests/Spreadsheet/Main.fs
index 400135c6..076a55d5 100644
--- a/tests/Spreadsheet/Main.fs
+++ b/tests/Spreadsheet/Main.fs
@@ -7,7 +7,9 @@ let all = testSequenced <| testList "ISA.Spreadsheet" [
RegexTests.main
ArcInvestigationTests.main
CompositeColumnTests.main
+ CompositeHeaderTests.main
ArcTableTests.main
+ DataMapTests.main
ArcAssayTests.main
ArcStudyTests.main
SparseTableTests.main
diff --git a/tests/TestingUtils/TestObjects.Contract/ISA.fs b/tests/TestingUtils/TestObjects.Contract/ISA.fs
index ab87e2c3..d6bc59b6 100644
--- a/tests/TestingUtils/TestObjects.Contract/ISA.fs
+++ b/tests/TestingUtils/TestObjects.Contract/ISA.fs
@@ -13,6 +13,7 @@ module SimpleISA =
module Assay =
+ let proteomeIdentifer = Assay.Proteome.assayIdentifier
let proteomeMetadataWorksheet = Assay.Proteome.assayMetadata
let proteomeWsName = "Measurement"
let proteomeTable =
@@ -37,6 +38,31 @@ module SimpleISA =
dtoType = DTOType.ISA_Assay,
dto = DTO.Spreadsheet proteomeWB)
+ let proteomeDatamapTable =
+ DataMap.initWorksheet "Proteome"
+ [
+ DataMap.Data.appendDataColumn 2
+ DataMap.Explication.appendMeanColumn 2
+ DataMap.Unit.appendPPMColumn 2
+ DataMap.ObjectType.appendFloatColumn 2
+ DataMap.Description.appendDescriptionColumn 2
+ DataMap.GeneratedBy.appendGeneratedByColumn 2
+ ]
+
+ let proteomeDatamapWB =
+ let wb = new FsWorkbook()
+ wb.AddWorksheet(proteomeDatamapTable)
+ wb
+
+ let proteomeDatamapContract =
+ Contract.create(
+ Operation.READ,
+ path = Identifier.Assay.datamapFileNameFromIdentifier Assay.Proteome.assayIdentifier,
+ dtoType = DTOType.ISA_Datamap,
+ dto = DTO.Spreadsheet proteomeDatamapWB)
+
+
+ let metabolomeIdentifer = Assay.Metabolome.assayIdentifier
let metabolomeMetadataWorksheet = Assay.Metabolome.assayMetadata
let metabolomeWB =
@@ -125,7 +151,6 @@ module SimpleISA =
dtoType = DTOType.ISA_Investigation,
dto = DTO.Spreadsheet Investigation.BII_I_1.fullInvestigation)
-
module UpdateAssayWithStudyProtocol =
let assayIdentifier = "MyAssay"
diff --git a/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.ArcTable.fs b/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.ArcTable.fs
index d3c940be..e399c1d6 100644
--- a/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.ArcTable.fs
+++ b/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.ArcTable.fs
@@ -158,6 +158,18 @@ module Factor =
t.Cell(FsAddress(i, colCount + 4),c).SetValueAs timeValueV4
module Input =
+
+ let sourceValue =
+ CompositeCell.FreeText "MySource"
+
+ let sourceValueV1 = "MySource"
+
+ let dataHeader =
+ CompositeHeader.Input IOType.Data
+
+ let dataValue =
+ CompositeCell.Data (Data.create(Name = "MyInputData", Format = "text/csv", SelectorFormat = "https://datatracker.ietf.org/doc/html/rfc7111"))
+
let sampleHeader =
CompositeHeader.Input IOType.Sample
@@ -174,6 +186,28 @@ module Input =
for i = 2 to l + 1 do
t.Cell(FsAddress(i, colCount + 1),c).SetValueAs sampleValueV1
+ let dataHeaderV1 = "Input [Data]"
+
+ let dataValueV1 = "MyInputData"
+
+ let dataHeaderV2 = "Data Format"
+
+ let dataValueV2 = "text/csv"
+
+ let dataHeaderV3 = "Data Selector Format"
+
+ let dataValueV3 = "https://datatracker.ietf.org/doc/html/rfc7111"
+
+ let appenddataColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs dataHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs dataHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs dataHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs dataValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs dataValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs dataValueV3
+
let deprecatedSourceHeader = CompositeHeader.Input IOType.Source
let deprecatedSourceHeaderV1 = "Source Name"
@@ -182,20 +216,61 @@ module Input =
let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
t.Cell(FsAddress(1, colCount + 1),c).SetValueAs deprecatedSourceHeaderV1
for i = 2 to l + 1 do
- t.Cell(FsAddress(i, colCount + 1),c).SetValueAs sampleValueV1
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs sourceValueV1
module Output =
- let rawDataHeader =
- CompositeHeader.Output IOType.RawDataFile
+ let simpleDataHeader =
+ CompositeHeader.Output IOType.Data
+
+ let simpleDataValue =
+ CompositeCell.Data (Data.create (Name = "MyData"))
+
+ let fullDataHeader =
+ CompositeHeader.Output IOType.Data
+
+ let fullDataValue =
+ CompositeCell.Data (Data.create(Name = "MyData", Format = "text/csv", SelectorFormat = "https://datatracker.ietf.org/doc/html/rfc7111"))
- let rawDataValue =
- CompositeCell.FreeText "MyRawData"
let rawDataHeaderV1 = "Output [Raw Data File]"
let rawDataValueV1 = "MyRawData"
+ let dataHeaderV1 = "Output [Data]"
+
+ let dataValueV1 = "MyData"
+
+ let dataHeaderV2 = "Data Format"
+
+ let dataValueV2 = "text/csv"
+
+ let dataHeaderV3 = "Data Selector Format"
+
+ let dataValueV3 = "https://datatracker.ietf.org/doc/html/rfc7111"
+
+
+ let sampleValue =
+ CompositeCell.FreeText "MySample"
+
+ let sampleValueV1 = "MySample"
+
+ let appendSimpleDataColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs dataHeaderV1
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs dataValueV1
+
+ let appendFullDataColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs dataHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs dataHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs dataHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs dataValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs dataValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs dataValueV3
+
let appendRawDataColumn l (c : FsCellsCollection) (t : FsTable) =
let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
t.Cell(FsAddress(1, colCount + 1),c).SetValueAs rawDataHeaderV1
@@ -210,7 +285,7 @@ module Output =
let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
t.Cell(FsAddress(1, colCount + 1),c).SetValueAs deprecatedSampleHeaderV1
for i = 2 to l + 1 do
- t.Cell(FsAddress(i, colCount + 1),c).SetValueAs rawDataValueV1
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs sampleValueV1
module Protocol =
module REF =
diff --git a/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.DataMap.fs b/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.DataMap.fs
new file mode 100644
index 00000000..adc5777c
--- /dev/null
+++ b/tests/TestingUtils/TestObjects.Spreadsheet/Spreadsheet.DataMap.fs
@@ -0,0 +1,165 @@
+module TestObjects.Spreadsheet.DataMap
+
+open ARCtrl
+open FsSpreadsheet
+open ARCtrl.Spreadsheet
+
+type FsTable with
+ member this.IsEmpty(c : FsCellsCollection) =
+ this.RangeAddress.Range = "A1:A1"
+ &&
+ (this.Cell(FsAddress("A1"),c).Value = null)
+ ||
+ (this.Cell(FsAddress("A1"),c).Value = "")
+
+module Data =
+
+ let dataValue =
+ Data.create(Name = "MyDataFile.csv#col=1",Format = "text/csv", SelectorFormat = "https://datatracker.ietf.org/doc/html/rfc7111")
+ |> CompositeCell.Data
+
+ let dataHeaderV1 = "Data"
+ let dataHeaderV2 = "Data Format"
+ let dataHeaderV3 = "Data Selector Format"
+
+ let dataValueV1 = "MyDataFile.csv#col=1"
+ let dataValueV2 = "text/csv"
+ let dataValueV3 = "https://datatracker.ietf.org/doc/html/rfc7111"
+
+ let appendDataColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs dataHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs dataHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs dataHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs dataValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs dataValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs dataValueV3
+
+module Explication =
+
+ let pValueValue =
+ OntologyAnnotation("p-value","NCIT","http://purl.obolibrary.org/obo/NCIT_C44185")
+ |> CompositeCell.Term
+
+ let explicationHeaderV1 = "Explication"
+ let explicationHeaderV2 = "Term Source REF"
+ let explicationHeaderV3 = "Term Accession Number"
+
+ let pValueValueV1 = "p-value"
+ let pValueValueV2 = "NCIT"
+ let pValueValueV3 = "http://purl.obolibrary.org/obo/NCIT_C44185"
+
+ let appendPValueColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs explicationHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs explicationHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs explicationHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs pValueValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs pValueValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs pValueValueV3
+
+ // Arithmetic Mean, http://purl.obolibrary.org/obo/NCIT_C53319
+ let meanValue =
+ OntologyAnnotation("Arithmetic Mean","NCIT","http://purl.obolibrary.org/obo/NCIT_C53319")
+ |> CompositeCell.Term
+
+ let meanValueV1 = "Arithmetic Mean"
+ let meanValueV2 = "NCIT"
+ let meanValueV3 = "http://purl.obolibrary.org/obo/NCIT_C53319"
+
+ let appendMeanColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs explicationHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs explicationHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs explicationHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs meanValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs meanValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs meanValueV3
+
+module Unit =
+
+ let ppmValue =
+ OntologyAnnotation("parts per million","UO","http://purl.obolibrary.org/obo/UO_0000169")
+ |> CompositeCell.Term
+
+ let unitHeaderV1 = "Unit"
+ let unitHeaderV2 = "Term Source REF"
+ let unitHeaderV3 = "Term Accession Number"
+
+ let ppmValueV1 = "parts per million"
+ let ppmValueV2 = "UO"
+ let ppmValueV3 = "http://purl.obolibrary.org/obo/UO_0000169"
+
+ let appendPPMColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs unitHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs unitHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs unitHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs ppmValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs ppmValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs ppmValueV3
+
+module ObjectType =
+
+ let floatValue =
+ OntologyAnnotation("float","NCIT","http://purl.obolibrary.org/obo/NCIT_C42645")
+ |> CompositeCell.Term
+
+ let objectTypeHeaderV1 = "Object Type"
+ let objectTypeHeaderV2 = "Term Source REF"
+ let objectTypeHeaderV3 = "Term Accession Number"
+
+ let floatValueV1 = "float"
+ let floatValueV2 = "NCIT"
+ let floatValueV3 = "http://purl.obolibrary.org/obo/NCIT_C42645"
+
+ let appendFloatColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs objectTypeHeaderV1
+ t.Cell(FsAddress(1, colCount + 2),c).SetValueAs objectTypeHeaderV2
+ t.Cell(FsAddress(1, colCount + 3),c).SetValueAs objectTypeHeaderV3
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs floatValueV1
+ t.Cell(FsAddress(i, colCount + 2),c).SetValueAs floatValueV2
+ t.Cell(FsAddress(i, colCount + 3),c).SetValueAs floatValueV3
+
+module Description =
+
+ let descriptionValue = CompositeCell.FreeText "This is a description"
+
+ let descriptionHeaderV1 = "Description"
+
+ let descriptionValueV1 = "This is a description"
+
+ let appendDescriptionColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs descriptionHeaderV1
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs descriptionValueV1
+
+module GeneratedBy =
+
+ let generatedByValue = CompositeCell.FreeText "MyTool.exe"
+
+ let generatedByHeaderV1 = "Generated By"
+
+ let generatedByValueV1 = "MyTool.exe"
+
+ let appendGeneratedByColumn l (c : FsCellsCollection) (t : FsTable) =
+ let colCount = if t.IsEmpty(c) then 0 else t.ColumnCount()
+ t.Cell(FsAddress(1, colCount + 1),c).SetValueAs generatedByHeaderV1
+ for i = 2 to l + 1 do
+ t.Cell(FsAddress(i, colCount + 1),c).SetValueAs generatedByValueV1
+
+let initWorksheet (name : string) (appendOperations : (FsCellsCollection -> FsTable -> unit) list) =
+ let w = FsWorksheet(name)
+ let t = w.Table(DataMapTable.datamapTablePrefix, FsRangeAddress("A1:A1"))
+ appendOperations
+ |> List.iter (fun o -> o w.CellCollection t)
+ ArcTable.addSpacesToEnd w.CellCollection t
+ t.RescanFieldNames(w.CellCollection)
+ w
\ No newline at end of file
diff --git a/tests/TestingUtils/TestingUtils.fsproj b/tests/TestingUtils/TestingUtils.fsproj
index 31589ba3..eb22605e 100644
--- a/tests/TestingUtils/TestingUtils.fsproj
+++ b/tests/TestingUtils/TestingUtils.fsproj
@@ -17,6 +17,7 @@
+
@@ -26,7 +27,7 @@
-
+