Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Querymodel fixes #17

Merged
merged 15 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading