-
Notifications
You must be signed in to change notification settings - Fork 8
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
[WIP] Developer docs #228
Merged
Merged
[WIP] Developer docs #228
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0c03382
Start with docs in f# and js :books:
Freymaurer 4aaf772
:constrcution: #223
Freymaurer 2606865
Remove unused logging flag #231
Freymaurer f40d538
Remove reference to developer branch from gh-action #233
Freymaurer 0ca715a
improve error msgs in Template.Spreadsheet #234
Freymaurer bde87f5
inherit ArcTables in assay and study #232 :white_check_mark:
Freymaurer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
# ARC | ||
|
||
🔗 The script files for this documentation can be found here: | ||
- [JavaScript](/scripts_js/ARC.js) | ||
- [F#](/scripts_fsharp/ARC.fsx) | ||
|
||
Table of Content | ||
- [Create ARC](#create) | ||
- [Write ARC](#write) | ||
- [Read ARC](#read) | ||
|
||
## Create | ||
|
||
ARCtrl aims to provide an easy solution to create and manipulate ARCs in memory. | ||
|
||
```fsharp | ||
// F# | ||
#r "nuget: FsSpreadsheet.ExcelIO, 4.1.0" | ||
#r "nuget: ARCtrl, 1.0.0-alpha9" | ||
|
||
open ARCtrl | ||
|
||
/// Init a new empty ARC | ||
let arc = ARC() | ||
``` | ||
|
||
```js | ||
// JavaScript | ||
import {ARC} from "@nfdi4plants/arctrl"; | ||
|
||
let arc = new ARC() | ||
``` | ||
|
||
This will initialize an ARC without metadata but with the basic ARC folder structure in `arc.FileSystem` | ||
|
||
- 📁 ARC root | ||
- 📄 isa.investigation.xlsx | ||
- 📁 workflows | ||
- 📁 runs | ||
- 📁 assays | ||
- 📁 studies | ||
|
||
## Write | ||
|
||
In .NET you can use [ARCtrl.NET][1] to handle any contract based read/write operations. For this documentation we will extract the relevant ARCtrl.NET functions. | ||
|
||
```fsharp | ||
// F# | ||
open ARCtrl.Contract | ||
open FsSpreadsheet | ||
open FsSpreadsheet.ExcelIO | ||
|
||
let arcRootPath = @"path/where/you/want/the/NewTestARC" | ||
|
||
// From ARCtrl.NET | ||
let fulfillWriteContract basePath (c : Contract) = | ||
let ensureDirectory (filePath : string) = | ||
let file = new System.IO.FileInfo(filePath); | ||
file.Directory.Create() | ||
match c.DTO with | ||
| Some (DTO.Spreadsheet wb) -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
ensureDirectory path | ||
FsWorkbook.toFile path (wb :?> FsWorkbook) | ||
| Some (DTO.Text t) -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
ensureDirectory path | ||
System.IO.File.WriteAllText(path,t) | ||
| None -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
ensureDirectory path | ||
System.IO.File.Create(path).Close() | ||
| _ -> | ||
printfn "Contract %s is not an ISA contract" c.Path | ||
|
||
// From ARCtrl.NET | ||
let write (arcPath: string) (arc:ARC) = | ||
arc.GetWriteContracts() | ||
|> Array.iter (fulfillWriteContract arcPath) | ||
|
||
write arcRootPath arc | ||
``` | ||
|
||
```js | ||
// JavaScript | ||
import {ARC} from "@nfdi4plants/arctrl"; | ||
import {Xlsx} from "fsspreadsheet"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
|
||
const arcRootPath = "C:/Users/Kevin/Desktop/NewTestARCJS" | ||
|
||
async function fulfillWriteContract (basePath, contract) { | ||
function ensureDirectory (filePath) { | ||
let dirPath = path.dirname(filePath) | ||
if (!fs.existsSync(dirPath)){ | ||
fs.mkdirSync(dirPath, { recursive: true }); | ||
} | ||
} | ||
const p = path.join(basePath,contract.Path) | ||
if (contract.Operation = "CREATE") { | ||
if (contract.DTO == undefined) { | ||
ensureDirectory(p) | ||
fs.writeFileSync(p, "") | ||
} else if (contract.DTOType == "ISA_Assay" || contract.DTOType == "ISA_Assay" || contract.DTOType == "ISA_Investigation") { | ||
ensureDirectory(p) | ||
await Xlsx.toFile(p, contract.DTO) | ||
console.log("ISA", p) | ||
} else if (contract.DTOType == "PlainText") { | ||
ensureDirectory(p) | ||
fs.writeFileSync(p, contract.DTO) | ||
} else { | ||
console.log("Warning: The given contract is not a correct ARC write contract: ", contract) | ||
} | ||
} | ||
} | ||
|
||
async function write(arcPath, arc) { | ||
let contracts = arc.GetWriteContracts() | ||
contracts.forEach(async contract => { | ||
await fulfillWriteContract(arcPath,contract) | ||
}); | ||
} | ||
|
||
await write(arcRootPath,arc) | ||
``` | ||
|
||
## Read | ||
|
||
Read may look intimidating at first, until you notice that most of this is just setup which can be reused for any read you do. | ||
|
||
Setup will be placed on top, with the actual read below. | ||
|
||
```fsharp | ||
// F# | ||
open System.IO | ||
|
||
// Setup | ||
|
||
let normalizePathSeparators (str:string) = str.Replace("\\","/") | ||
|
||
let getAllFilePaths (basePath: string) = | ||
let options = EnumerationOptions() | ||
options.RecurseSubdirectories <- true | ||
Directory.EnumerateFiles(basePath, "*", options) | ||
|> Seq.map (fun fp -> | ||
Path.GetRelativePath(basePath, fp) | ||
|> normalizePathSeparators | ||
) | ||
|> Array.ofSeq | ||
|
||
// from ARCtrl.NET | ||
// https://github.com/nfdi4plants/ARCtrl.NET/blob/ba3d2fabe007d9ca2c8e07b62d02ddc5264306d0/src/ARCtrl.NET/Contract.fs#L7 | ||
let fulfillReadContract basePath (c : Contract) = | ||
match c.DTOType with | ||
| Some DTOType.ISA_Assay | ||
| Some DTOType.ISA_Investigation | ||
| Some DTOType.ISA_Study -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
let wb = FsWorkbook.fromXlsxFile path |> box |> DTO.Spreadsheet | ||
{c with DTO = Some wb} | ||
| Some DTOType.PlainText -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
let text = System.IO.File.ReadAllText(path) |> DTO.Text | ||
{c with DTO = Some text} | ||
| _ -> | ||
printfn "Contract %s is not an ISA contract" c.Path | ||
c | ||
|
||
// put it all together | ||
let readARC(basePath: string) = | ||
let allFilePaths = getAllFilePaths basePath | ||
// Initiates an ARC from FileSystem but no ISA info. | ||
let arcRead = ARC.fromFilePaths allFilePaths | ||
// Read contracts will tell us what we need to read from disc. | ||
let readContracts = arcRead.GetReadContracts() | ||
let fulfilledContracts = | ||
readContracts | ||
|> Array.map (fulfillReadContract basePath) | ||
arcRead.SetISAFromContracts(fulfilledContracts) | ||
arcRead | ||
|
||
// execution | ||
|
||
readARC arcRootPath | ||
``` | ||
|
||
```js | ||
|
||
``` | ||
|
||
[1]: <https://www.nuget.org/packages/ARCtrl.NET> "ARCtrl.NET Nuget" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Contracts - from a code perspective | ||
|
||
**Table of contents** | ||
- [WRITE](#write-contracts) | ||
- [READ](#read-contracts) | ||
|
||
**Code can be found here** | ||
- [F#](/docs/scripts_fsharp/Contracts.fsx) | ||
- [JavaScript](/docs/scripts_js/Contracts.js) | ||
|
||
|
||
Contracts in ARCtrl are used to delegate *IO operations* to the api consumer to allow interoperability with any environment (.NET, Node, Browser..). Contracts use *Data Transfer Object"s* (DTOs) instead of the ARCtrl types to provide a higher interoperability. | ||
|
||
A Contract object consists of the following fields: | ||
|
||
```fsharp | ||
// F# | ||
// Using F# discriminate union types it is very easy to match for differen cases. | ||
type Contract = | ||
{ | ||
/// Determines what io operation should be done: CREATE, READ, DELETE, ... | ||
Operation : Operation | ||
/// The path where the io operation should be executed. The path is relative to ARC root. | ||
Path: string | ||
/// The type of DTO that is expected: JSON, PlainText, ISA_Assay, ISA_Study, ISA_Investigation,.. | ||
DTOType : DTOType option | ||
/// The actual DTO, as discriminate union. | ||
DTO: DTO option | ||
} | ||
``` | ||
|
||
```js | ||
// JavaScript | ||
export class Contract extends Record { | ||
constructor(Operation, Path, DTOType, DTO) { | ||
super(); | ||
// Can be any of: "CREATE", "UPDATE", "DELETE", "READ", "EXECUTE" | ||
this.Operation = Operation; | ||
// string, the path where the io operation should be executed. The path is relative to ARC root | ||
this.Path = Path; | ||
// Can be undefined or any of: "ISA_Assay", "ISA_Study", "ISA_Investigation", "JSON", "Markdown", "CWL", "PlainText", "Cli". | ||
this.DTOType = DTOType; | ||
// Can be undefined or any of: `FsWorkbook` (from fsspreadsheet), string (e.g. json,..), or a `CLITool`. | ||
this.DTO = DTO; | ||
} | ||
``` | ||
|
||
Handling contracts can be generalized in a few functions. | ||
|
||
## WRITE contracts | ||
|
||
```fsharp | ||
#r "nuget: FsSpreadsheet.ExcelIO, 4.1.0" | ||
#r "nuget: ARCtrl, 1.0.0-alpha9" | ||
|
||
open ARCtrl | ||
open ARCtrl.Contract | ||
open FsSpreadsheet | ||
open FsSpreadsheet.ExcelIO | ||
|
||
/// From ARCtrl.NET | ||
let fulfillWriteContract basePath (c : Contract) = | ||
let ensureDirectory (filePath : string) = | ||
let file = new System.IO.FileInfo(filePath); | ||
file.Directory.Create() | ||
match c.DTO with | ||
| Some (DTO.Spreadsheet wb) -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
ensureDirectory path | ||
FsWorkbook.toFile path (wb :?> FsWorkbook) | ||
| Some (DTO.Text t) -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
ensureDirectory path | ||
System.IO.File.WriteAllText(path,t) | ||
| None -> | ||
let path = System.IO.Path.Combine(basePath, c.Path) | ||
ensureDirectory path | ||
System.IO.File.Create(path).Close() | ||
| _ -> | ||
printfn "Contract %s is not an ISA contract" c.Path | ||
``` | ||
|
||
```js | ||
import {Xlsx} from "fsspreadsheet"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
|
||
export async function fulfillWriteContract (basePath, contract) { | ||
function ensureDirectory (filePath) { | ||
let dirPath = path.dirname(filePath) | ||
if (!fs.existsSync(dirPath)){ | ||
fs.mkdirSync(dirPath, { recursive: true }); | ||
} | ||
} | ||
const p = path.join(basePath,contract.Path) | ||
if (contract.Operation = "CREATE") { | ||
if (contract.DTO == undefined) { | ||
ensureDirectory(p) | ||
fs.writeFileSync(p, "") | ||
} else if (contract.DTOType == "ISA_Assay" || contract.DTOType == "ISA_Assay" || contract.DTOType == "ISA_Investigation") { | ||
ensureDirectory(p) | ||
await Xlsx.toFile(p, contract.DTO) | ||
console.log("ISA", p) | ||
} else if (contract.DTOType == "PlainText") { | ||
ensureDirectory(p) | ||
fs.writeFileSync(p, contract.DTO) | ||
} else { | ||
console.log("Warning: The given contract is not a correct ARC write contract: ", contract) | ||
} | ||
} | ||
} | ||
``` | ||
|
||
|
||
## READ contracts |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we actually also add documentation for ARCtrl.Net here?