Skip to content

Commit

Permalink
Merge pull request #17 from nfdi4plants/querymodel
Browse files Browse the repository at this point in the history
Querymodel fixes
  • Loading branch information
HLWeil authored Feb 21, 2024
2 parents 2181cc7 + b40490c commit 2195d8a
Show file tree
Hide file tree
Showing 51 changed files with 539 additions and 235 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,5 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

**/TestResults/**
**/TestResults/**
tests/ARCtrl.Querymodel.Tests/playground_2.fsx
39 changes: 30 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
# ARCtrl.NET

> **ARCtrl.NET** is the .NET IO implementation of [ARCtrl](https://github.com/nfdi4plants/ARCtrl)
| Version | Downloads |
| :--------|-----------:|
|<a href="https://www.nuget.org/packages/ARCtrl.NET/"><img alt="Nuget" src="https://img.shields.io/nuget/vpre/ARCtrl.NET?logo=nuget&color=%234fb3d9"></a>|<a href="https://www.nuget.org/packages/ARCtrl/"><img alt="Nuget" src="https://img.shields.io/nuget/dt/ARCtrl?color=%234FB3D9"></a>|
This library functions as an IO wrapper for the [ARCtrl](https://github.com/nfdi4plants/ARCtrl) library in .NET.

The documentation for the actual functions for manipulating the ARC datamodel can be found [here](https://github.com/nfdi4plants/ARCtrl/tree/main/docs/scripts_fsharp).

## Usage

```fsharp
#r "nuget: ARCtrl.NET, 1.0.0-beta.2"
open ARCtrl.NET
open ARCtrl
let arc = ARC.load(myArcPath)
// work work work
let arcPath = ""
let arc = ARC.load(arcPath)
let isa = arc.ISA.Value
arc.Write(myArcPath)
isa.InitStudy("MyStudy")
arc.Write(arcPath)
```

For documentation on manipulationh of the datamodel, see https://github.com/nfdi4plants/ARCtrl/tree/main/docs
## Development

`./build.cmd runtests`

## ARCtrl.Querymodel

```fsharp
open ARCtrl
open ARCtrl.QueryModel
open ARCtrl.ISA
let i = ArcInvestigation("Dummy Investigation")
i.ArcTables.Values().WithName("Dummy Header").First.ValueText
i.GetAssay("Dummy Assay").LastSamples
```
296 changes: 143 additions & 153 deletions src/ARCtrl.QueryModel/ArcTables.fs

Large diffs are not rendered by default.

66 changes: 12 additions & 54 deletions src/ARCtrl.QueryModel/Investigation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,18 @@ open System.Collections
[<AutoOpen>]
module ArcInvestigationExtensions =

///// Queryable representation of an ISA Investigation. Implements the QProcessSequence interface
//type ArcInvestigation with

// /// Returns the QStudy with the given name
// member this.Study(studyName : string) =
// this.Studies
// |> List.find (fun s -> s.Identifier.Value = studyName)

// /// Returns the nth QStudy
// member this.Study(i : int) =
// this.Studies
// |> List.item i

// /// Returns the QAssay with the given name (registered in the study with the given study name)
// member this.Assay(assayName : string, ?StudyName : string) =
// match StudyName with
// | Some sn ->
// this.Study(sn).Assay(assayName)
// | None ->
// this.Studies
// |> List.collect (fun s -> s.Assays)
// |> List.find (fun a -> a.FileName.Value.Contains assayName)

// /// get the protocol or sheet (in ISATab logic) with the given name
// member this.Protocol (sheetName : string) =
// base.Protocol(sheetName, $"Assay \"{this.FileName}\"")

// /// get the nth protocol or sheet (in ISATab logic)
// member this.Protocol (index : int) =
// base.Protocol(index, $"Assay \"{this.FileName}\"")

// /// Returns the initial inputs final outputs of the assay, to which no processPoints
// static member getRootInputs (investigation : QInvestigation) = QProcessSequence.getRootInputs investigation

// /// Returns the final outputs of the investigation, which point to no further nodes
// static member getFinalOutputs (investigation : QInvestigation) = QProcessSequence.getFinalOutputs investigation

// /// Returns the initial inputs final outputs of the investigation, to which no processPoints
// static member getRootInputOf (investigation : QInvestigation) (sample : string) = QProcessSequence.getRootInputsOfBy (fun _ -> true) sample investigation

// /// Returns the final outputs of the investigation, which point to no further nodes
// static member getFinalOutputsOf (investigation : QInvestigation) (sample : string) = QProcessSequence.getFinalOutputsOfBy (fun _ -> true) sample investigation

// static member toString (rwa : QInvestigation) = JsonSerializer.Serialize<QInvestigation>(rwa,JsonExtensions.options)

// static member toFile (path : string) (rwa:QInvestigation) =
// File.WriteAllText(path,QInvestigation.toString rwa)

// static member fromString (s:string) =
// JsonSerializer.Deserialize<QInvestigation>(s,JsonExtensions.options)

// static member fromFile (path : string) =
// File.ReadAllText path
// |> QInvestigation.fromString
/// Queryable representation of an ISA Investigation. Implements the QProcessSequence interface
type ArcInvestigation with

/// Returns the QStudy with the given name
member this.ArcTables
with get() : ArcTables =
seq {
for s in this.Studies do yield! s.Tables
for a in this.Assays do yield! a.Tables
}
|> ResizeArray
|> ArcTables

module Investigation =

Expand Down
10 changes: 10 additions & 0 deletions src/ARCtrl.QueryModel/ResizeArray.fs
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,14 @@ module ResizeArray =
for i in a do
if not (b.Contains(i)) then
b.Add(i)
b

let distinctBy f (a : ResizeArray<_>) =
let b = ResizeArray<_>()
let c = ResizeArray<_>()
for i in a do
let k = f i
if not (c.Contains(k)) then
c.Add(k)
b.Add(i)
b
4 changes: 2 additions & 2 deletions src/ARCtrl.QueryModel/Value.fs
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,11 @@ module ISAValueExtensions =
this.TryUnit |> Option.map (fun u -> u.NameText)

/// Returns the value of the Value as string
member this.ValueText = this.Value.AsName()
member this.ValueText = this.Value.Text

/// Returns the value of the Value as string if it exists, else returns None
member this.TryValueText =
this.TryValue |> Option.map (fun v -> v.AsName())
this.TryValue |> Option.map (fun v -> v.Text)

/// Returns the value and unit of the Value as string
member this.ValueWithUnitText =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="ArcTable.fs" />
<Compile Include="TestARC.fs" />
<Compile Include="Main.fs" />
<Folder Include="TestObjects" />
</ItemGroup>
Expand Down
14 changes: 0 additions & 14 deletions tests/ARCtrl.Querymodel.Tests/ArcTable.fs

This file was deleted.

2 changes: 1 addition & 1 deletion tests/ARCtrl.Querymodel.Tests/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ open Expecto


let all = testSequenced <| testList "All" [
ArcTable.Tests.testStuff
TestARC.Tests.main
]

[<EntryPoint>]
Expand Down
165 changes: 165 additions & 0 deletions tests/ARCtrl.Querymodel.Tests/TestARC.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
module TestARC.Tests

open Expecto
open System.Text.Json
open ARCtrl
open ARCtrl.NET
open ARCtrl.QueryModel
open ARCtrl.ISA
let testArcPath = __SOURCE_DIRECTORY__ + @"\TestObjects\TestArc"
let testArc = ARC.load(testArcPath)


let ArcTables_getNodes =
let isa = testArc.ISA.Value
testList "ARCTables_GetNodes" [
testCase "LastData" (fun () ->
let nodes = isa.ArcTables.LastData
let nodeNames = nodes |> List.map (fun n -> n.Name)
let expected = ["sampleOutCold.txt"; "sampleOutHeat.txt"]
Expect.sequenceEqual nodeNames expected "LastData of full sequence"
)
testCase "LastSamples" (fun () ->
let nodes = isa.ArcTables.LastSamples
let nodeNames = nodes |> List.map (fun n -> n.Name)
let expected = ["CC1_prep"; "CC2_prep"; "CC3_prep"; "Co1_prep"; "Co2_prep"; "Co3_prep"; "C1_prep"; "C2_prep"; "C3_prep"; "H1_prep"; "H2_prep"; "H3_prep"]
Expect.sequenceEqual expected nodeNames "LastSamples of full sequence"
)
testCase "LastNodes" (fun () ->
let nodes = isa.ArcTables.LastNodes
let nodeNames = nodes |> Seq.map (fun n -> n.Name)
let expected = ["sampleOutCold.txt"; "sampleOutHeat.txt"]
Expect.sequenceEqual nodeNames expected "LastData of full sequence"
)
testCase "RawData" (fun () ->
let nodes = isa.ArcTables.RawData
let nodeNames = nodes |> Seq.map (fun n -> n.Name)
let expected = ["CC1_measured";"CC2_measured";"CC3_measured";"Co1_measured";"Co2_measured";"Co3_measured";"C1_measured";"C2_measured";"C3_measured";"H1_measured";"H2_measured";"H3_measured"]
Expect.sequenceEqual nodeNames expected "RawData of full sequence"
)
testCase "LastRawData" (fun () ->
let nodes = isa.ArcTables.LastRawData
let nodeNames = nodes |> Seq.map (fun n -> n.Name)
let expected = ["CC1_measured";"CC2_measured";"CC3_measured";"Co1_measured";"Co2_measured";"Co3_measured";"C1_measured";"C2_measured";"C3_measured";"H1_measured";"H2_measured";"H3_measured"]
Expect.sequenceEqual nodeNames expected "RawData of full sequence"
)
testCase "FirstRawData" (fun () ->
let nodes = isa.ArcTables.FirstRawData
let nodeNames = nodes |> Seq.map (fun n -> n.Name)
let expected = ["CC1_measured";"CC2_measured";"CC3_measured";"Co1_measured";"Co2_measured";"Co3_measured";"C1_measured";"C2_measured";"C3_measured";"H1_measured";"H2_measured";"H3_measured"]
Expect.sequenceEqual nodeNames expected "RawData of full sequence"
)
]

let Assay_getNodes =
let isa = testArc.ISA.Value
testList "Assay_GetNodes" [

testCase "LastNodes" (fun () ->
let nodes = isa.GetAssay("MSEval_Heat").LastNodes
let nodeNames = nodes |> Seq.map (fun n -> n.Name)
let expected = ["sampleOutHeat.txt"]
Expect.sequenceEqual nodeNames expected "LastData of full sequence"
)
]
let Assay_ValuesOf =
let isa = testArc.ISA.Value
testList "Assay_ValuesOf" [

testCase "ValuesOfOutput_PooledOutput" (fun () ->
let values = isa.GetAssay("MSEval_Heat").ValuesOf("sampleOutHeat.txt").WithName("Column")
let valueValues = values |> Seq.map (fun n -> n.ValueText)
let expected = ["C1 Intensity";"C2 Intensity";"C3 Intensity";"H1 Intensity";"H2 Intensity";"H3 Intensity"]
Expect.sequenceEqual valueValues expected "Did not return all values correctly"
)
testCase "SucceedingValuesOfInput_PooledOutput" (fun () ->
let values = isa.GetAssay("MSEval_Heat").SucceedingValuesOf("C2_measured").WithName("Column")
let valueValues = values |> Seq.map (fun n -> n.ValueText)
let expected = ["C2 Intensity"]
Expect.sequenceEqual valueValues expected "Did not return the single value correctly"
)
testCase "PreviousValuesOfInput_PooledOutput" (fun () ->
let values = isa.GetAssay("MSEval_Heat").PreviousValuesOf("C2_measured").WithName("Column")
let valueValues = values |> Seq.map (fun n -> n.ValueText)
let expected = []
Expect.sequenceEqual valueValues expected "Should return no values"
)
testCase "ValuesOfInput_PooledOutput" (fun () ->
let values = isa.GetAssay("MSEval_Heat").ValuesOf("C2_measured").WithName("Column")
let valueValues = values |> Seq.map (fun n -> n.ValueText)
let expected = ["C2 Intensity"]
Expect.sequenceEqual valueValues expected "Did not return the single value correctly"
)

]

let ArcTables_ValueOf =
let isa = testArc.ISA.Value
testList "ArcTable_Values" [
testCase "ValuesOf_SpecificTable" (fun () ->
let nodeName = "sampleOutHeat.txt"
let protocolName = "MS"
let values = isa.ArcTables.ValuesOf(nodeName,protocolName)
let expectedTechRep =
ISAValue.Parameter (
ProcessParameterValue.create(
ProtocolParameter.fromString("technical replicate","MS","MS:1001808"),
Value.Ontology (OntologyAnnotation.fromString("1"))
)
)
let expectedInjVol =
ISAValue.Parameter (
ProcessParameterValue.create(
ProtocolParameter.fromString("injection volume setting","AFR","AFR:0001577"),
Value.Int 20,
OntologyAnnotation.fromString("microliter","UO","http://purl.obolibrary.org/obo/UO_0000101")
)
)
let expected =
[
expectedTechRep;expectedInjVol
expectedTechRep;expectedInjVol
expectedTechRep;expectedInjVol
expectedTechRep;expectedInjVol
expectedTechRep;expectedInjVol
expectedTechRep;expectedInjVol
]
Expect.sequenceEqual values expected "Did not return correct values for specific table"
)
testCase "ValuesOf" (fun () ->
let nodeName = "sampleOutHeat.txt"

let valueHeaders =
isa.ArcTables.ValuesOf(nodeName).DistinctHeaderCategories()
|> Seq.map (fun x -> x.NameText)
let expected =
["biological replicate";"organism";"temperature day";"pH";"technical replicate"; "injection volume setting";"analysis software";"Column"]
Expect.sequenceEqual valueHeaders expected "Did not return correct values for all table"
)
testCase "GetSpecificValue" (fun () ->
let rep1 = isa.ArcTables.ValuesOf("C1_measured").WithName("biological replicate").First.ValueText
Expect.equal rep1 "1" "Did not return correct value for specific table"
let rep2 = isa.ArcTables.ValuesOf("C2_measured").WithName("biological replicate").First.ValueText
Expect.equal rep2 "2" "Did not return correct value for specific table"
)
testCase "ValuesOf_SpecificTable_PooledOutput" (fun () ->
let vals = isa.ArcTables.ValuesOf("sampleOutHeat.txt","Growth").WithName("biological replicate").Values |> List.map (fun v -> v.ValueText)
Expect.sequenceEqual vals ["1";"2";"3";"1";"2";"3"] "Did not return correct values"
)
testCase "SpecificValue_SpecificTable_PooledOutput" (fun () ->
let vals = isa.ArcTables.ValuesOf("C2_prep","Growth").WithName("biological replicate").First.ValueText
Expect.equal vals "2" "Did not return correct value"
)
]





[<Tests>]
let main = testList "TestArcTests" [
ArcTables_getNodes
Assay_getNodes
Assay_ValuesOf
ArcTables_ValueOf
]
Loading

0 comments on commit 2195d8a

Please sign in to comment.