diff --git a/src/Ontology.NET/OBO/OboOntology.fs b/src/Ontology.NET/OBO/OboOntology.fs
index 8381886..caab132 100644
--- a/src/Ontology.NET/OBO/OboOntology.fs
+++ b/src/Ontology.NET/OBO/OboOntology.fs
@@ -13,7 +13,7 @@ open System
open System.IO
-/// Ontology containing OBO Terms and OBO Type Defs (OBO 1.2).
+/// Ontology containing OBO Terms and OBO Typedefs (OBO 1.4).
type OboOntology =
{
@@ -91,6 +91,15 @@ type OboOntology =
RelaxUniqueLabelAssumptionForNamespaces = defaultArg RelaxUniqueLabelAssumptionForNamespaces []
}
+ ///
+ /// Creates an OboOntology out of the given header tags alongside the given terms and typedefs.
+ ///
+ /// The list of OboTerms the resulting OboOntology shall have.
+ /// The list of OboTypedefs the resulting OboOntology shall have.
+ /// The header tags the resulting OboOntology shall have.
+ static member Create(terms, typedefs, headerTags : OboOntologyHeaderTags) =
+ headerTags.ToOboOntology(terms, typedefs)
+
/// Reads an OBO Ontology containing document header tags, and term and type def stanzas from lines.
static member fromLines verbose (input : seq) =
@@ -565,6 +574,186 @@ type OboOntology =
onto1.ReturnAllEquivalentTerms(onto2)
+and OboOntologyHeaderTags =
+
+ {
+ FormatVersion : string
+ DataVersion : string option
+ Ontology : string option
+ Date : DateTime option
+ SavedBy : string option
+ AutoGeneratedBy : string option
+ Subsetdefs : string list
+ Imports : string list // needs its own type (Record?)
+ Synonymtypedefs : string list // rethink type, maybe create a mother type (Union? Maybe Record'd be better)
+ Idspaces : string list // rethink as own Record type
+ DefaultRelationshipIdPrefix : string option
+ IdMappings : string list // rethink: maybe a new record? or TermRelation?
+ Remarks : string list
+ TreatXrefsAsEquivalents : string list
+ TreatXrefsAsGenusDifferentias : string list // rethink: maybe a new record? or plain string option?
+ TreatXrefsAsRelationships : string list // maybe better as its own (Record/Union?) type
+ TreatXrefsAsIsAs : string list
+ RelaxUniqueIdentifierAssumptionForNamespaces : string list
+ RelaxUniqueLabelAssumptionForNamespaces : string list
+ }
+
+ // Param descriptions taken and adapted from the OBO flat file format 1.4: https://owlcollab.github.io/oboformat/doc/GO.format.obo-1_4.html
+ ///
+ /// Creates the header tags for an OboOntology.
+ ///
+ /// Gives the OBO specification version that this OboOntology uses. This is useful if tag semantics change from one OBO specification version to the next.
+ /// Gives the version of the current OboOntology. This gets translated to versionIRI in OWL.
+ /// The ID space of this OboOntology. This should correspond to to the ID prefix of the terms that belong to that ontology, translated to lowercase. For GO, the value of this field will be "go". For the cell ontology (i.e. the ontology that contains CL:0000001), the value will be "cl". If the obo document contains some alternative cut or extension of the ontology (for example, a GO slim, or an ontology merged with another), then the ontology should be of form "X/Y", where X is the basic ontology name, and Y identifies the cut. For example go/gosubset_prok. A URI is also permitted in here. In the translation to OWL, the usual default prefix rules will apply, with the ".owl" suffix. E.g. "go" will be treated as "http://purl.obo-library.org/obo/go.owl".
+ /// The current date in dd:MM:yyyy HH:mm format (note: for historic reasons, this is NOT a ISO 8601 date, as is the case for the creation-date field).
+ /// The username of the person to last save this OboOntology. The meaning of "username" is entirely up to the application that generated the file.
+ /// The program that generated the OboOntology.
+ /// A description of a term subset. The value for this tag should contain a subset name, a space, and a quote enclosed subset description.
+ /// A url or ontology ID referencing another OBO document.
+ /// A description of a user-defined synonym type. The value for this tag should contain a synonym type name, a space, a quote enclosed description, and an optional scope specifier.
+ /// A mapping between a "local" ID space and a "global" ID space. The value for this tag should be a local idspace, a space, a URI, optionally followed by a quote-enclosed description.
+ /// Any relationship lacking an ID space will be prefixed with the value of this tag.
+ /// Maps a Term or Typedef ID to another Term or Typedef ID. The main reason for this tag is to increase interoperability between different OBO ontologies.
+ /// General comments for this file. This tag is differentiated from a ! comment in that the contents of a remark tag are guaranteed to be preserved by a parser.
+ /// The value for this tag should contain an ID Space.
+ /// The value for this tag should contain an ID Space followed by a relation and then a class filler.
+ /// The value for this tag should contain an ID Space followed by a relation ID.
+ /// The value for this tag should contain an ID Space.
+ /// The value for this tag should be a namespace. By default, an OBO namespace (note: not ID-space) partitions all the entities such that no two entities belonging to the same namespace may be equivalent. This header tag relaxes this assumption.
+ ///
+ static member create formatVersion dataVersion ontology date savedBy autoGeneratedBy subsetdefs imports synonymtypedefs idspaces defaultRelationshipIdPrefix idMappings remarks treatXrefsAsEquivalents treatXrefsAsGenusDifferentias treatXrefsAsRelationships treatXrefsAsIsAs relaxUniqueIdentifierAssumptionForNamespaces relaxUniqueLabelAssumptionForNamespaces =
+ {
+ FormatVersion = formatVersion
+ DataVersion = dataVersion
+ Ontology = ontology
+ Date = date
+ SavedBy = savedBy
+ AutoGeneratedBy = autoGeneratedBy
+ Subsetdefs = subsetdefs
+ Imports = imports
+ Synonymtypedefs = synonymtypedefs
+ Idspaces = idspaces
+ DefaultRelationshipIdPrefix = defaultRelationshipIdPrefix
+ IdMappings = idMappings
+ Remarks = remarks
+ TreatXrefsAsEquivalents = treatXrefsAsEquivalents
+ TreatXrefsAsGenusDifferentias = treatXrefsAsGenusDifferentias
+ TreatXrefsAsRelationships = treatXrefsAsRelationships
+ TreatXrefsAsIsAs = treatXrefsAsIsAs
+ RelaxUniqueIdentifierAssumptionForNamespaces = relaxUniqueIdentifierAssumptionForNamespaces
+ RelaxUniqueLabelAssumptionForNamespaces = relaxUniqueLabelAssumptionForNamespaces
+ }
+
+ // Param descriptions taken and adapted from the OBO flat file format 1.4: https://owlcollab.github.io/oboformat/doc/GO.format.obo-1_4.html
+ ///
+ /// Creates the header tags for an OboOntology.
+ ///
+ /// Gives the OBO specification version that this OboOntology uses. This is useful if tag semantics change from one OBO specification version to the next.
+ /// Gives the version of the current OboOntology. This gets translated to versionIRI in OWL.
+ /// The ID space of this OboOntology. This should correspond to to the ID prefix of the terms that belong to that ontology, translated to lowercase. For GO, the value of this field will be "go". For the cell ontology (i.e. the ontology that contains CL:0000001), the value will be "cl". If the obo document contains some alternative cut or extension of the ontology (for example, a GO slim, or an ontology merged with another), then the ontology should be of form "X/Y", where X is the basic ontology name, and Y identifies the cut. For example go/gosubset_prok. A URI is also permitted in here. In the translation to OWL, the usual default prefix rules will apply, with the ".owl" suffix. E.g. "go" will be treated as "http://purl.obo-library.org/obo/go.owl".
+ /// The current date in dd:MM:yyyy HH:mm format (note: for historic reasons, this is NOT a ISO 8601 date, as is the case for the creation-date field).
+ /// The username of the person to last save this OboOntology. The meaning of "username" is entirely up to the application that generated the file.
+ /// The program that generated the OboOntology.
+ /// A description of a term subset. The value for this tag should contain a subset name, a space, and a quote enclosed subset description.
+ /// A url or ontology ID referencing another OBO document.
+ /// A description of a user-defined synonym type. The value for this tag should contain a synonym type name, a space, a quote enclosed description, and an optional scope specifier.
+ /// A mapping between a "local" ID space and a "global" ID space. The value for this tag should be a local idspace, a space, a URI, optionally followed by a quote-enclosed description.
+ /// Any relationship lacking an ID space will be prefixed with the value of this tag.
+ /// Maps a Term or Typedef ID to another Term or Typedef ID. The main reason for this tag is to increase interoperability between different OBO ontologies.
+ /// General comments for this file. This tag is differentiated from a ! comment in that the contents of a remark tag are guaranteed to be preserved by a parser.
+ /// The value for this tag should contain an ID Space.
+ /// The value for this tag should contain an ID Space followed by a relation and then a class filler.
+ /// The value for this tag should contain an ID Space followed by a relation ID.
+ /// The value for this tag should contain an ID Space.
+ /// The value for this tag should be a namespace. By default, an OBO namespace (note: not ID-space) partitions all the entities such that no two entities belonging to the same namespace may be equivalent. This header tag relaxes this assumption.
+ ///
+ static member Create(formatVersion, ?DataVersion, ?Ontology, ?Date, ?SavedBy, ?AutoGeneratedBy, ?Subsetdefs, ?Imports, ?Synonymtypedefs, ?Idspaces, ?DefaultRelationshipIdPrefix, ?IdMappings, ?Remarks, ?TreatXrefsAsEquivalents, ?TreatXrefsAsGenusDifferentias, ?TreatXrefsAsRelationships, ?TreatXrefsAsIsAs, ?RelaxUniqueIdentifierAssumptionForNamespaces, ?RelaxUniqueLabelAssumptionFornamespaces) =
+ OboOntologyHeaderTags.create
+ formatVersion
+ DataVersion
+ Ontology
+ Date
+ SavedBy
+ AutoGeneratedBy
+ (Option.defaultValue [] Subsetdefs)
+ (Option.defaultValue [] Imports)
+ (Option.defaultValue [] Synonymtypedefs)
+ (Option.defaultValue [] Idspaces)
+ DefaultRelationshipIdPrefix
+ (Option.defaultValue [] IdMappings)
+ (Option.defaultValue [] Remarks)
+ (Option.defaultValue [] TreatXrefsAsEquivalents)
+ (Option.defaultValue [] TreatXrefsAsGenusDifferentias)
+ (Option.defaultValue [] TreatXrefsAsRelationships)
+ (Option.defaultValue [] TreatXrefsAsIsAs)
+ (Option.defaultValue [] RelaxUniqueIdentifierAssumptionForNamespaces)
+ (Option.defaultValue [] RelaxUniqueLabelAssumptionFornamespaces)
+
+ ///
+ /// Creates an empty OboOntologyHeaderTag object.
+ ///
+ static member createDefault () =
+ {
+ FormatVersion = ""
+ DataVersion = None
+ Ontology = None
+ Date = None
+ SavedBy = None
+ AutoGeneratedBy = None
+ Subsetdefs = []
+ Imports = []
+ Synonymtypedefs = []
+ Idspaces = []
+ DefaultRelationshipIdPrefix = None
+ IdMappings = []
+ Remarks = []
+ TreatXrefsAsEquivalents = []
+ TreatXrefsAsGenusDifferentias = []
+ TreatXrefsAsRelationships = []
+ TreatXrefsAsIsAs = []
+ RelaxUniqueIdentifierAssumptionForNamespaces = []
+ RelaxUniqueLabelAssumptionForNamespaces = []
+ }
+
+ ///
+ /// Creates an OboOntology out of this header tags alongside the given terms and typedefs.
+ ///
+ /// The list of OboTerms the resulting OboOntology shall have.
+ /// The list of OboTypedefs the resulting OboOntology shall have.
+ member this.ToOboOntology(terms, typedefs) =
+ OboOntology.Create(
+ terms,
+ typedefs,
+ this.FormatVersion,
+ ?DataVersion = this.DataVersion,
+ ?Ontology = this.Ontology,
+ ?Date = this.Date,
+ ?SavedBy = this.SavedBy,
+ ?AutoGeneratedBy = this.AutoGeneratedBy,
+ Subsetdefs = this.Subsetdefs,
+ Imports = this.Imports,
+ Synonymtypedefs = this.Synonymtypedefs,
+ Idspaces = this.Idspaces,
+ ?DefaultRelationshipIdPrefix = this.DefaultRelationshipIdPrefix,
+ IdMappings = this.IdMappings,
+ Remarks = this.Remarks,
+ TreatXrefsAsEquivalents = this.TreatXrefsAsEquivalents,
+ TreatXrefsAsGenusDifferentias = this.TreatXrefsAsGenusDifferentias,
+ TreatXrefsAsRelationships = this.TreatXrefsAsRelationships,
+ TreatXrefsAsIsAs = this.TreatXrefsAsIsAs,
+ RelaxUniqueIdentifierAssumptionForNamespaces = this.RelaxUniqueIdentifierAssumptionForNamespaces,
+ RelaxUniqueLabelAssumptionForNamespaces = this.RelaxUniqueLabelAssumptionForNamespaces
+ )
+
+ ///
+ /// Creates an OboOntology out of the given header tags alongside the given terms and typedefs.
+ ///
+ /// The list of OboTerms the resulting OboOntology shall have.
+ /// The list of OboTypedefs the resulting OboOntology shall have.
+ static member toOboOntology terms typedefs (oboOntoloyHeaderTags : OboOntologyHeaderTags) =
+ oboOntoloyHeaderTags.ToOboOntology(terms, typedefs)
+
+
type OboTermDef =
{
Id : string
diff --git a/src/Ontology.NET/OBO/OboTerm.fs b/src/Ontology.NET/OBO/OboTerm.fs
index e814103..6748b28 100644
--- a/src/Ontology.NET/OBO/OboTerm.fs
+++ b/src/Ontology.NET/OBO/OboTerm.fs
@@ -1,11 +1,12 @@
namespace Ontology.NET.OBO
+open System
+open System.Text.RegularExpressions
+
open DBXref
open TermSynonym
-open System
-
open ControlledVocabulary
open FSharpAux
@@ -517,10 +518,21 @@ type OboTerm =
/// Takes a relationship and returns a tuple consisting of the name of the relationship and the ID of the OboTerm it matches.
static member deconstructRelationship relationship =
- let pattern = System.Text.RegularExpressions.Regex @"^(?.+?) (?[^ ]+:\d+)(?: .*)?$"
+ let pattern = Regex @"^(?.+?) (?[^ ]+:\d+)(?: .*)?$"
let regexMatch = pattern.Match relationship
regexMatch.Groups["relName"].Value, regexMatch.Groups["id"].Value
+ ///
+ /// Takes the ID of a target term and the name of a relationship and constructs the relationship from them.
+ ///
+ /// The ID of the term that the relationship targets.
+ /// The name of the relationship, e.g. "part_of".
+ static member constructRelationship targetTermId relationshipName =
+ let whiteSpacePattern = Regex(@"\s")
+ if whiteSpacePattern.Match(relationshipName).Success then
+ raise (System.ArgumentException($"relationshipName {relationshipName} must not contain white spaces.", relationshipName))
+ $"{targetTermId} {relationshipName}"
+
/// Returns the OboTerm's relationships as a triple consisting of the term's ID, the name of the relationship, and the related term's ID.
member this.GetRelatedTermIds() =
this.Relationships
diff --git a/src/Ontology.NET/Ontology.fs b/src/Ontology.NET/Ontology.fs
index 972142a..0746744 100644
--- a/src/Ontology.NET/Ontology.fs
+++ b/src/Ontology.NET/Ontology.fs
@@ -8,6 +8,7 @@ open Graphoscope
open GraphoscopeAux
open Ontology.NET.OBO
+open type RelationType
module internal OntologyGraphHelpers =
@@ -15,23 +16,36 @@ module internal OntologyGraphHelpers =
let setOrAddEdgeObo sourceTerm searchedTermKey (relationType : RelationType) oboOnto graph =
let cvtTarget = OboOntology.getOrCreateTerm searchedTermKey oboOnto |> OboTerm.toCvTerm
if FGraph.containsNode cvtTarget.Accession graph then
- match FGraph.tryFindEdge sourceTerm.Accession cvtTarget.Accession graph with
- | Some (nk1,nk2,alreadyExistingEdge) ->
+ if FGraph.containsEdge sourceTerm.Accession cvtTarget.Accession graph then
+ let _, _, alreadyExistingEdge = FGraph.findEdge sourceTerm.Accession cvtTarget.Accession graph
FGraph.setEdgeData sourceTerm.Accession cvtTarget.Accession (Set.add relationType alreadyExistingEdge) graph
- | None ->
+ else
FGraph.addEdge sourceTerm.Accession cvtTarget.Accession (Set (List.singleton relationType)) graph
|> ignore
+ // TO DO: Replace this with the code below as soon as the `FGraph.tryFindEdge` bug is fixed and a new version with the fix is released.
+ //match FGraph.tryFindEdge sourceTerm.Accession cvtTarget.Accession graph with
+ //| Some (nk1,nk2,alreadyExistingEdge) ->
+ // FGraph.setEdgeData sourceTerm.Accession cvtTarget.Accession (Set.add relationType alreadyExistingEdge) graph
+ //| None ->
+ // FGraph.addEdge sourceTerm.Accession cvtTarget.Accession (Set (List.singleton relationType)) graph
+ //|> ignore
else
let missingTargetTerm = CvTerm.create(searchedTermKey, "", "")
FGraph.addElement sourceTerm.Accession sourceTerm missingTargetTerm.Accession missingTargetTerm (Set (List.singleton relationType)) graph |> ignore
// CAUTION: fails if one of the terms doesn't exist in the given Ontology!
- let setOrAddEdge sourceTerm targetTerm (relation : RelationType) onto =
- match FGraph.tryFindEdge sourceTerm targetTerm onto with
- | Some (_, _, edgeData) ->
- FGraph.setEdgeData sourceTerm targetTerm (Set.add relation edgeData) onto
- | None ->
- FGraph.addEdge sourceTerm targetTerm (Set.singleton relation) onto
+ let setOrAddEdge sourceTermId targetTermId (relation : RelationType) onto =
+ if FGraph.containsEdge sourceTermId targetTermId onto then
+ let _, _, currRel = FGraph.findEdge sourceTermId targetTermId onto
+ FGraph.setEdgeData sourceTermId targetTermId (Set.add relation currRel) onto
+ else
+ FGraph.addEdge sourceTermId targetTermId (Set.singleton relation) onto
+ // TO DO: Replace this with the code below as soon as the `FGraph.tryFindEdge` bug is fixed and a new version with the fix is released.
+ //match FGraph.tryFindEdge sourceTerm targetTerm onto with
+ //| Some (_, _, edgeData) ->
+ // FGraph.setEdgeData sourceTerm targetTerm (Set.add relation edgeData) onto
+ //| None ->
+ // FGraph.addEdge sourceTerm targetTerm (Set.singleton relation) onto
open OntologyGraphHelpers
@@ -46,7 +60,7 @@ type Ontology() =
// parsing functionality:
///
- /// Takes a given OboOntology and transforms it into an Ontology, with the term IDs as node keys, the terms as CvTerms as node data and the relations as edges.
+ /// Takes a given OboOntology and returns the corresponding Ontology, with the term IDs as node keys, the terms as CvTerms as node data and the relations as edges.
///
/// If a relation points to a term that is not present in the given OboOntology, initializes them as new CvTerms but with name and ref = "<missing>".
static member fromOboOntology (oboOnto : OboOntology) =
@@ -117,9 +131,86 @@ type Ontology() =
|> Seq.map Ontology.fromOboOntology
|> Ontology.mergeAll
+ ///
+ /// Creates an OboOntology from the Ontology. Incorporates the given header tags if present.
+ ///
+ /// Optional. The header tags of the resulting OboOntology. Default is empty.
+ member this.ToOboOntology(?headerTags) =
+
+ let ht = Option.defaultValue (OboOntologyHeaderTags.createDefault ()) headerTags
+
+ let rec innerLoop (tt : string) (rts : RelationType list) rs ias xs =
+ match rts with
+ | h :: t ->
+ match h with
+ | IsA -> innerLoop tt t rs (tt :: ias) xs
+ | Xref -> innerLoop tt t rs ias (tt :: xs)
+ | Term cvt -> innerLoop tt t ((tt,cvt.Name) :: rs) ias xs
+ | Custom c -> innerLoop tt t ((tt, c) :: rs) ias xs
+ | [] -> rs, ias, xs
+
+ let rec outerLoop (input : (string * RelationType Set) list) rs ias xs =
+ match input with
+ | (tt,rts) :: t ->
+ let newRs, newIas, newXs = innerLoop tt (Seq.toList rts) rs ias xs
+ outerLoop t newRs newIas newXs
+ | [] -> rs, ias, xs
+
+ let terms =
+ this.GetTerms()
+ |> Seq.map snd
+ |> Seq.map (
+ fun cvt ->
+ let relations = this.GetTargetTermRelations(cvt.Accession)
+ let relationshipsRaw, isAs, xrefsRaw = outerLoop (List.ofSeq relations) [] [] []
+ let relationshipsProcessed = relationshipsRaw |> List.map (fun (tt,rsn) -> OboTerm.constructRelationship tt rsn)
+ let xrefsProcessed = xrefsRaw |> List.map DBXref.ofString
+ OboTerm.Create(
+ cvt.Accession,
+ Name = cvt.Name,
+ Relationships = relationshipsProcessed,
+ IsA = isAs,
+ Xrefs = xrefsProcessed
+ )
+ )
+
+ OboOntology.Create(Seq.toList terms, [], ht)
+
+ ///
+ /// Creates an OboOntology from the given Ontology. Incorporates the given header tags if present.
+ ///
+ /// Optional. The header tags of the resulting OboOntology. Default is empty.
+ /// The Ontology that shall be used as the basis of the resulting OboOntology.
+ static member toOboOntology headerTags (onto : Ontology) =
+ onto.ToOboOntology(headerTags)
+
+ ///
+ /// Takes a sequence of triplets and returns the corresponding Ontology.
+ ///
+ /// The triplets in the form of source term * relation * target term that serve as the informational basis for the ontology that gets created out of them.
+ static member fromTriplets (triplets : (CvTerm * RelationType * CvTerm) seq) =
+ let onto = Ontology()
+
+ triplets
+ |> Seq.iter (
+ fun (term1,rel,term2) ->
+ onto.AddTerm(term1) |> ignore
+ onto.AddTerm(term2) |> ignore
+ onto.AddRelation(term1.Accession, term2.Accession, rel) |> ignore
+ )
+
+ onto
+
// basic functionality:
+ ///
+ /// Checks if a term exists under the given ID.
+ ///
+ /// The ID of the term whose presence in the Ontology shall be checked.
+ member this.ContainsTerm(termId) =
+ FGraph.containsNode termId this
+
///
/// Adds a CvTerm to the Ontology.
///
@@ -166,72 +257,108 @@ type Ontology() =
///
/// Removes the given term from the Ontology. Also removes all of its relations.
///
- /// The ID of the term that gets removed.
- member this.RemoveTerm(term) =
- FGraph.removeNode term this :?> Ontology
+ /// The ID of the term that gets removed.
+ member this.RemoveTerm(termId) =
+ FGraph.removeNode termId this :?> Ontology
+
+ ///
+ /// Checks if at least 1 relation from source term to target term exists.
+ ///
+ /// The ID of the term from which the relation originates.
+ /// The ID of the term that is related to the source term.
+ /// Does not check if a relation exists from target to source term.
+ member this.HasRelations(sourceTermId, targetTermId) =
+ FGraph.containsEdge sourceTermId targetTermId this
+
+ ///
+ /// Checks if the given relation from source term to target term exists.
+ ///
+ /// The ID of the term from which the relation originates.
+ /// The ID of the term that is related to the source term.
+ /// The relation whose presence shall be checked.
+ /// Does not check if the relation exists from target to source term.
+ member this.HasRelation(sourceTermId, targetTermId, relation) =
+ match this.TryGetRelations(sourceTermId, targetTermId) with
+ | None ->
+ false
+ | Some r ->
+ Set.contains relation r
///
/// Adds a relation of source term to target term to the Ontology.
///
- /// The ID of the term from which the relation originates.
- /// The ID of the term that is related to the source term.
+ /// The ID of the term from which the relation originates.
+ /// The ID of the term that is related to the source term.
/// The relation between both terms.
/// Thrown when source term or target term are not presen in the Ontology.
- member this.AddRelation(sourceTerm, targetTerm, relation) =
- match FGraph.containsNode sourceTerm this, FGraph.containsNode targetTerm this with
+ member this.AddRelation(sourceTermId, targetTermId, relation) =
+ match FGraph.containsNode sourceTermId this, FGraph.containsNode targetTermId this with
| true, true ->
- setOrAddEdge sourceTerm targetTerm relation this :?> Ontology
+ setOrAddEdge sourceTermId targetTermId relation this :?> Ontology
| false, true ->
- raise (System.ArgumentException($"source term {sourceTerm} does not exist in the Ontology.", sourceTerm))
+ raise (System.ArgumentException($"source term {sourceTermId} does not exist in the Ontology.", sourceTermId))
| true, false ->
- raise (System.ArgumentException($"target term {targetTerm} does not exist in the Ontology.", targetTerm))
+ raise (System.ArgumentException($"target term {targetTermId} does not exist in the Ontology.", targetTermId))
| false, false ->
- raise (System.ArgumentException($"terms {sourceTerm} and {targetTerm} do not exist in the Ontology."))
+ raise (System.ArgumentException($"terms {sourceTermId} and {targetTermId} do not exist in the Ontology."))
///
/// Returns the set of Relations from source to target term.
///
- /// ID of the source term (where the relation originates).
- /// ID of the target term (where the relation points to).
+ /// ID of the source term (where the relation originates).
+ /// ID of the target term (where the relation points to).
/// Thrown when there is no relation from source to target term in the Ontology.
- member this.GetRelation(sourceTerm, targetTerm) =
- if FGraph.containsEdge sourceTerm targetTerm this then
- FGraph.findEdge sourceTerm targetTerm this
+ member this.GetRelations(sourceTermId, targetTermId) =
+ if FGraph.containsEdge sourceTermId targetTermId this then
+ FGraph.findEdge sourceTermId targetTermId this
|> fun (_,_,e) -> e
- else raise (System.ArgumentException($"There is no relation from source terms {sourceTerm} to target term {targetTerm} in the Ontology."))
+ else raise (System.ArgumentException($"There is no relation from source terms {sourceTermId} to target term {targetTermId} in the Ontology."))
// TO DO: Replace this with the code below as soon as the `FGraph.tryFindEdge` bug is fixed and a new version with the fix is released.
- //match FGraph.tryFindEdge sourceTerm targetTerm this with
+ //match FGraph.tryFindEdge sourceTermId targetTermId this with
//| Some (_,_,e) -> e
- //| None -> raise (System.ArgumentException($"There is no relation from source terms {sourceTerm} to target term {targetTerm} in the Ontology."))
+ //| None -> raise (System.ArgumentException($"There is no relation from source terms {sourceTermId} to target term {targetTermId} in the Ontology."))
+
+ ///
+ /// Returns the set of Relations from source to target term if they exist. Else returns None.
+ ///
+ /// ID of the source term (where the relation originates).
+ /// ID of the target term (where the relation points to).
+ member this.TryGetRelations(sourceTermId, targetTermId) =
+ if FGraph.containsEdge sourceTermId targetTermId this then
+ Some (FGraph.findEdge sourceTermId targetTermId this |> fun (_,_,e) -> e)
+ else None
+ // TO DO: Replace this with the code below as soon as the `FGraph.tryFindEdge` bug is fixed and a new version with the fix is released.
+ //FGraph.tryFindEdge sourceTermId targetTermId this
+ //|> Option.map (fun (_,_,e) -> e)
///
/// Returns all relations of the Ontology as a sequence of source term ID * target term ID * relations.
///
- member this.GetRelations() =
+ member this.GetAllRelations() =
FGraph.toEdgeSeq this
///
/// Removes all relations from given source to target term. Relations directed vice versa (from target to source term) are unaffected.
///
- /// ID of the source term (where the relation originates).
+ /// ID of the source term (where the relation originates).
/// ID of the target term (where the relation points to).
- member this.RemoveRelations(sourceTerm, targetTerm) =
- FGraph.removeEdge sourceTerm targetTerm this :?> Ontology
+ member this.RemoveRelations(sourceTermId, targetTermId) =
+ FGraph.removeEdge sourceTermId targetTermId this :?> Ontology
///
/// Removes the given relation from given source to target term. Relations directed vice versa (from target to source term) are unaffected.
///
- /// ID of the source term (where the relation originates).
+ /// ID of the source term (where the relation originates).
/// ID of the target term (where the relation points to).
/// The relation to be removed from the set of relations from source to target term.
/// Thrown when no relation from source term to target term exists.
- member this.RemoveRelation(sourceTerm, targetTerm, relation) =
+ member this.RemoveRelation(sourceTermId, targetTermId, relation) =
try
- FGraph.findEdge sourceTerm targetTerm this
+ FGraph.findEdge sourceTermId targetTermId this
|> fun (_,_,e) ->
- FGraph.setEdgeData sourceTerm targetTerm (Set.remove relation e) this :?> Ontology
+ FGraph.setEdgeData sourceTermId targetTermId (Set.remove relation e) this :?> Ontology
with _ ->
- raise (System.ArgumentException($"no relation from source term {sourceTerm} to target term {targetTerm}."))
+ raise (System.ArgumentException($"no relation from source term {sourceTermId} to target term {targetTermId}."))
// TO DO: Replace this with the code below as soon as the `FGraph.tryFindEdge` bug is fixed and a new version with the fix is released.
//match FGraph.tryFindEdge sourceTerm targetTerm this with
//| Some (_,_,e) ->
@@ -278,10 +405,10 @@ type Ontology() =
///
/// Returns the target relations of the given term as (target term ID * relations) sequence.
///
- /// The ID of the term whose target relations shall be returned.
+ /// The ID of the term whose target relations shall be returned.
/// Target relations to the given term look like this: "given term -> target term"
- member this.GetTargetTermRelations(termID) =
- this[termID]
+ member this.GetTargetTermRelations(termId) =
+ this[termId]
|> fun (_,_,s) ->
s
|> Seq.map (fun e -> e.Key, e.Value)
@@ -780,7 +907,7 @@ type Ontology() =
/// The Ontology that gets merged into this one.
member this.MergeWith(onto : Ontology) =
let newTerms = onto.GetTerms()
- let newRelations = onto.GetRelations()
+ let newRelations = onto.GetAllRelations()
newTerms
|> Seq.iter (
fun (termId,cvTerm) ->
@@ -827,6 +954,14 @@ type Ontology() =
// accompanying static methods (to existing instance methods):
+ ///
+ /// Checks if a term exists under the given ID.
+ ///
+ /// The ID of the term whose presence in the Ontology shall be checked.
+ /// The Ontology where the presence of the term shall be checked.
+ static member containsTerm termId (onto : Ontology) =
+ onto.ContainsTerm(termId)
+
///
/// Adds a CvTerm to the Ontology.
///
@@ -875,50 +1010,80 @@ type Ontology() =
static member removeTerm term (onto : Ontology) =
onto.RemoveTerm(term)
+ ///
+ /// Checks if at least 1 relation from source term to target term exists.
+ ///
+ /// The ID of the term from which the relation originates.
+ /// The ID of the term that is related to the source term.
+ /// The Ontology in which the relation shall be searched for.
+ /// Does not check if a relation exists from target to source term.
+ static member hasRelations sourceTermId targetTermId (onto : Ontology) =
+ onto.HasRelations(sourceTermId, targetTermId)
+
+ ///
+ /// Checks if the given relation from source term to target term exists.
+ ///
+ /// The ID of the term from which the relation originates.
+ /// The ID of the term that is related to the source term.
+ /// The relation whose presence shall be checked.
+ /// The Ontology in which the relation shall be searched for.
+ /// Does not check if the relation exists from target to source term.
+ static member hasRelation sourceTermId targetTermId relation (onto : Ontology) =
+ onto.HasRelation(sourceTermId, targetTermId, relation)
+
///
/// Adds a relation of source term to target term to the Ontology.
///
- /// The ID of the term from which the relation originates.
- /// The ID of the term that is related to the source term.
+ /// The ID of the term from which the relation originates.
+ /// The ID of the term that is related to the source term.
/// The relation between both terms.
/// The Ontology in which the relation shall be added.
- static member addRelation sourceTerm targetTerm relation (onto : Ontology) =
- onto.AddRelation(sourceTerm, targetTerm, relation)
+ static member addRelation sourceTermId targetTermId relation (onto : Ontology) =
+ onto.AddRelation(sourceTermId, targetTermId, relation)
///
/// Returns the set of Relations from source to target term.
///
- /// ID of the source term (where the relation originates).
- /// ID of the target term (where the relation points to).
+ /// ID of the source term (where the relation originates).
+ /// ID of the target term (where the relation points to).
/// The Ontology in which to look for the relation.
- static member getRelation sourceTerm targetTerm (onto : Ontology) =
- onto.GetRelation(sourceTerm, targetTerm)
+ static member getRelations sourceTermId targetTermId (onto : Ontology) =
+ onto.GetRelations(sourceTermId, targetTermId)
+
+ ///
+ /// Returns the set of Relations from source to target term if they exist. Else returns None.
+ ///
+ /// ID of the source term (where the relation originates).
+ /// ID of the target term (where the relation points to).
+ /// The Ontology in which to look for the relation.
+ static member tryGetRelations sourceTermId targetTermId (onto : Ontology) =
+ onto.TryGetRelations(sourceTermId, targetTermId)
///
/// Returns all relations of the Ontology as a sequence of source term ID * target term ID * relations.
///
/// The Ontology in which to look for the relation.
- static member getRelations (onto : Ontology) =
- onto.GetRelations()
+ static member getAllRelations (onto : Ontology) =
+ onto.GetAllRelations()
///
/// Removes all relations from given source to target term. Relations directed vice versa (from target to source term) are unaffected.
///
- /// ID of the source term (where the relation originates).
- /// ID of the target term (where the relation points to).
+ /// ID of the source term (where the relation originates).
+ /// ID of the target term (where the relation points to).
/// The Ontology from which the relations shall be removed.
- static member removeRelations sourceTerm targetTerm (onto : Ontology) =
- onto.RemoveRelations(sourceTerm, targetTerm)
+ static member removeRelations sourceTermId targetTermId (onto : Ontology) =
+ onto.RemoveRelations(sourceTermId, targetTermId)
///
/// Removes the given relation from given source to target term. Relations directed vice versa (from target to source term) are unaffected.
///
- /// ID of the source term (where the relation originates).
- /// ID of the target term (where the relation points to).
+ /// ID of the source term (where the relation originates).
+ /// ID of the target term (where the relation points to).
/// The relation to be removed from the set of relations from source to target term.
/// The Ontology from which the relation shall be removed.
- static member removeRelation sourceTerm targetTerm relation (onto : Ontology) =
- onto.RemoveRelation(sourceTerm, targetTerm, relation)
+ static member removeRelation sourceTermId targetTermId relation (onto : Ontology) =
+ onto.RemoveRelation(sourceTermId, targetTermId, relation)
///
/// Returns the term IDs of all terms that have an Xref relation to the given term with the given Ontology.
diff --git a/src/Ontology.NET/OntologyRelation.fs b/src/Ontology.NET/OntologyRelation.fs
index dd16cd6..3bde583 100644
--- a/src/Ontology.NET/OntologyRelation.fs
+++ b/src/Ontology.NET/OntologyRelation.fs
@@ -11,6 +11,37 @@ type RelationType =
| Term of CvTerm
| Custom of string
+ with
+ ///
+ /// Creates a RelationType from a given string.
+ ///
+ /// The string that is used to create a RelationType.
+ static member fromString (str : string) =
+ match str.ToLower() with
+ | "is_a"
+ | "is a"
+ | "isa" -> IsA
+ | "xref"
+ | "x_ref"
+ | "x ref" -> Xref
+ | _ -> Custom str
+
+ ///
+ /// Returns the RelationType as a string.
+ ///
+ override this.ToString() : string =
+ match this with
+ | IsA -> "is_a"
+ | Xref -> "xref"
+ | Custom r -> r
+ | Term cvt -> cvt.Name
+
+ ///
+ /// Returns a RelationType as a string.
+ ///
+ static member toString (rt : RelationType) =
+ rt.ToString()
+
/// Model for a generic ontological relation. Consists of fields RelationType that inhabits the type of the relation, and Target for the targeted CvTerm of the relation.
type OntologyRelation = {
diff --git a/tests/Ontology.NET.Tests/OBO/OboOntology.Tests.fs b/tests/Ontology.NET.Tests/OBO/OboOntology.Tests.fs
index a4ce412..c72d9a0 100644
--- a/tests/Ontology.NET.Tests/OBO/OboOntology.Tests.fs
+++ b/tests/Ontology.NET.Tests/OBO/OboOntology.Tests.fs
@@ -71,25 +71,25 @@ module OboOntologyTests =
Expect.isSome testFile2 $"Could not read testFile2: {testFile2Path}"
Expect.isSome testFile3 $"Could not read testFile3: {testFile3Path}"
testCase "reads correct headers correctly" <| fun _ ->
- let formatVersionActual = Option.map (fun o -> o.FormatVersion) testFile1
- let dataVersionActual = Option.map (fun o -> o.DataVersion) testFile1 |> Option.flatten
- let ontologyActual = Option.map (fun o -> o.Ontology) testFile1 |> Option.flatten
- let dateActual = Option.map (fun o -> o.Date) testFile1 |> Option.flatten
- let savedByActual = Option.map (fun o -> o.SavedBy) testFile1 |> Option.flatten
- let autoGeneratedByActual = Option.map (fun o -> o.AutoGeneratedBy) testFile1 |> Option.flatten
- let subsetdefsActual = Option.map (fun o -> o.Subsetdefs) testFile1
- let importsActual = Option.map (fun o -> o.Imports) testFile1
- let synonymtypedefsActual = Option.map (fun o -> o.Synonymtypedefs) testFile1
- let idSpacesActual = Option.map (fun o -> o.Idspaces) testFile1
- let defaultRelationshipIdPrefixActual = Option.map (fun o -> o.DefaultRelationshipIdPrefix) testFile1 |> Option.flatten
- let idMappingsActual = Option.map (fun o -> o.IdMappings) testFile1
- let remarksActual = Option.map (fun o -> o.Remarks) testFile1
- let treatXrefsAsEquivalentsActual = Option.map (fun o -> o.TreatXrefsAsEquivalents) testFile1
- let treatXrefsAsGenusDifferentiasActual = Option.map (fun o -> o.TreatXrefsAsGenusDifferentias) testFile1
- let treatXrefsAsRelationshipsActual = Option.map (fun o -> o.TreatXrefsAsRelationships) testFile1
- let treatXrefsAsIsAsActual = Option.map (fun o -> o.TreatXrefsAsIsAs) testFile1
- let relaxUniqueIdentifierAssumptionForNamespacesActual = Option.map (fun o -> o.RelaxUniqueIdentifierAssumptionForNamespaces) testFile1
- let relaxUniqueLabelAssumptionForNamespacesActual = Option.map (fun o -> o.RelaxUniqueLabelAssumptionForNamespaces) testFile1
+ let formatVersionActual = testFile1 |> Option.map (fun o -> o.FormatVersion)
+ let dataVersionActual = testFile1 |> Option.map (fun o -> o.DataVersion) |> Option.flatten
+ let ontologyActual = testFile1 |> Option.map (fun o -> o.Ontology) |> Option.flatten
+ let dateActual = testFile1 |> Option.map (fun o -> o.Date) |> Option.flatten
+ let savedByActual = testFile1 |> Option.map (fun o -> o.SavedBy) |> Option.flatten
+ let autoGeneratedByActual = testFile1 |> Option.map (fun o -> o.AutoGeneratedBy) |> Option.flatten
+ let subsetdefsActual = testFile1 |> Option.map (fun o -> o.Subsetdefs)
+ let importsActual = testFile1 |> Option.map (fun o -> o.Imports)
+ let synonymtypedefsActual = testFile1 |> Option.map (fun o -> o.Synonymtypedefs)
+ let idSpacesActual = testFile1 |> Option.map (fun o -> o.Idspaces)
+ let defaultRelationshipIdPrefixActual = testFile1 |> Option.map (fun o -> o.DefaultRelationshipIdPrefix) |> Option.flatten
+ let idMappingsActual = testFile1 |> Option.map (fun o -> o.IdMappings)
+ let remarksActual = testFile1 |> Option.map (fun o -> o.Remarks)
+ let treatXrefsAsEquivalentsActual = testFile1 |> Option.map (fun o -> o.TreatXrefsAsEquivalents)
+ let treatXrefsAsGenusDifferentiasActual = testFile1 |> Option.map (fun o -> o.TreatXrefsAsGenusDifferentias)
+ let treatXrefsAsRelationshipsActual = testFile1 |> Option.map (fun o -> o.TreatXrefsAsRelationships)
+ let treatXrefsAsIsAsActual = testFile1 |> Option.map (fun o -> o.TreatXrefsAsIsAs)
+ let relaxUniqueIdentifierAssumptionForNamespacesActual = testFile1 |> Option.map (fun o -> o.RelaxUniqueIdentifierAssumptionForNamespaces)
+ let relaxUniqueLabelAssumptionForNamespacesActual = testFile1 |> Option.map (fun o -> o.RelaxUniqueLabelAssumptionForNamespaces)
let formatVersionExpected = "0.0.1" |> Some
let dataVersionExpected = "0.0.1" |> Some
let ontologyExpected = "CL" |> Some
@@ -129,7 +129,7 @@ module OboOntologyTests =
Expect.equal relaxUniqueIdentifierAssumptionForNamespacesActual relaxUniqueIdentifierAssumptionForNamespaceExpected "relax-unique-identifier-assumption-for-namespaces are not identical"
Expect.equal relaxUniqueLabelAssumptionForNamespacesActual relaxUniqueLabelAssumptionForNamespaceExpected "relax-unique-label-assumption-for-namespaces are not identical"
testCase "reads incorrect headers correctly" <| fun _ ->
- Expect.isNone (Option.map (fun o -> o.Date) testFile2 |> Option.flatten) "Date should be missing but was still parsed"
+ Expect.isNone (testFile2 |> Option.map (fun o -> o.Date) |> Option.flatten) "Date should be missing but was still parsed"
testCase "reads Terms correctly" <| fun _ ->
let termsExpected = List.init 2 (fun i -> OboTerm.Create $"Test:000{i + 1}") |> Some
Expect.equal (Option.map (fun o -> o.Terms) testFile1) termsExpected "Terms did not match"
diff --git a/tests/Ontology.NET.Tests/OBO/OboTerm.Tests.fs b/tests/Ontology.NET.Tests/OBO/OboTerm.Tests.fs
index 122631b..08cae25 100644
--- a/tests/Ontology.NET.Tests/OBO/OboTerm.Tests.fs
+++ b/tests/Ontology.NET.Tests/OBO/OboTerm.Tests.fs
@@ -56,4 +56,14 @@ module OboTermTests =
Expect.equal actual.Name expected.Name "Names are different"
Expect.equal actual.Accession expected.Accession "TANs are different"
]
+
+ testList "constructRelationship" [
+ testCase "returns correct relationship string" <| fun _ ->
+ let actual = OboTerm.constructRelationship "part_of" "TGMA:0000002"
+ let expected = "part_of TGMA:0000002"
+ Expect.equal actual expected "relationship strings differ"
+
+ testCase "throws when expected" <| fun _ ->
+ Expect.throws (fun _ -> OboTerm.constructRelationship "TGMA:0000002" "part of" |> ignore) "Did not throw though expected"
+ ]
]
\ No newline at end of file
diff --git a/tests/Ontology.NET.Tests/Ontology.NET.Tests.fsproj b/tests/Ontology.NET.Tests/Ontology.NET.Tests.fsproj
index e16ac71..2b966db 100644
--- a/tests/Ontology.NET.Tests/Ontology.NET.Tests.fsproj
+++ b/tests/Ontology.NET.Tests/Ontology.NET.Tests.fsproj
@@ -34,10 +34,9 @@
+
-
-
diff --git a/tests/Ontology.NET.Tests/Ontology.Tests.fs b/tests/Ontology.NET.Tests/Ontology.Tests.fs
index dba9ba7..5e7fa0a 100644
--- a/tests/Ontology.NET.Tests/Ontology.Tests.fs
+++ b/tests/Ontology.NET.Tests/Ontology.Tests.fs
@@ -7,6 +7,10 @@ open FSharpAux
open ControlledVocabulary
open Ontology.NET
+open Ontology.NET.OBO
+
+
+open type Ontology.NET.RelationType
module OntologyTests =
@@ -55,9 +59,9 @@ module OntologyTests =
Expect.equal actual expected "CvTerms differ"
]
- testList "GetRelation" [
- testCase "gets relation correctly" <| fun _ ->
- let actual = ReferenceObjects.testOnto1.GetRelation("test:01", "test:02")
+ testList "GetRelations" [
+ testCase "gets relations correctly" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.GetRelations("test:01", "test:02")
let expected = set [Xref]
Expect.equal actual expected "Relations are not equal"
]
@@ -124,25 +128,25 @@ module OntologyTests =
]
testList "GetTargetTermsWithXrefsBy" [
- testCase "returns all target terms and their Xrefs correctly, Case: Hund is_a ..." <| fun _ ->
- let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Hund", fun _ _ relations -> Set.contains IsA relations) |> Seq.toList
- let expected = ["Räuber"; "Höhere Säugetiere"; "Höhere Säuger"; "Eutheria"; "Raubtiere"; "Carnivora"; "Laurasiatheria"]
- Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
-
- testCase "returns all target terms and their Xrefs correctly, Case: Carnivora Sprache ..." <| fun _ ->
- let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Carnivora", fun _ _ relations -> Set.contains (Custom "Sprache") relations) |> Seq.toList
- let expected = ["Latein"; "Lateinisch"]
- Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
-
- testCase "returns all target terms and their Xrefs correctly, Case: Lateinisch ist nicht ..." <| fun _ ->
- let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Lateinisch", fun _ _ relations -> Set.contains (Custom "ist nicht") relations) |> Seq.toList
- let expected = ["Deutsch"]
- Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
-
- testCase "returns all target terms and their Xrefs correctly, Case: term ID has space(s)" <| fun _ ->
- let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Eutheria", fun termID _ _ -> String.contains " " termID) |> Seq.toList
- let expected = ["Höhere Säugetiere"; "Höhere Säuger"]
- Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
+ testCase "returns all target terms and their Xrefs correctly, Case: Hund is_a ..." <| fun _ ->
+ let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Hund", fun _ _ relations -> Set.contains IsA relations) |> Seq.toList
+ let expected = ["Räuber"; "Höhere Säugetiere"; "Höhere Säuger"; "Eutheria"; "Raubtiere"; "Carnivora"; "Laurasiatheria"]
+ Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
+
+ testCase "returns all target terms and their Xrefs correctly, Case: Carnivora Sprache ..." <| fun _ ->
+ let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Carnivora", fun _ _ relations -> Set.contains (Custom "Sprache") relations) |> Seq.toList
+ let expected = ["Latein"; "Lateinisch"]
+ Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
+
+ testCase "returns all target terms and their Xrefs correctly, Case: Lateinisch ist nicht ..." <| fun _ ->
+ let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Lateinisch", fun _ _ relations -> Set.contains (Custom "ist nicht") relations) |> Seq.toList
+ let expected = ["Deutsch"]
+ Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
+
+ testCase "returns all target terms and their Xrefs correctly, Case: term ID has space(s)" <| fun _ ->
+ let actual = ReferenceObjects.testOnto2.GetTargetTermsWithXrefsBy("Eutheria", fun termID _ _ -> String.contains " " termID) |> Seq.toList
+ let expected = ["Höhere Säugetiere"; "Höhere Säuger"]
+ Expect.sequenceEqual actual expected "Target terms and/or their Xrefs differ"
]
testList "GetTargetTermsWithDepth" [
@@ -242,7 +246,7 @@ module OntologyTests =
o
let res = testOnto1.MergeWith(testOnto2)
let actual1 = res.GetTerms() |> Seq.toList
- let actual2 = res.GetRelations() |> Seq.toList
+ let actual2 = res.GetAllRelations() |> Seq.toList
let expected1 = [
"TO1:1", CvTerm.create("TO1:1", "test1", "TO1"); "TO1:2", CvTerm.create("TO1:2", "test2", "TO1"); "TO3:1", CvTerm.create("TO3:1", "", ""); "TO2:1", CvTerm.create("TO2:1", "test1", "TO2"); "TO2:2", CvTerm.create("TO2:2", "test2", "TO2")
]
@@ -253,4 +257,105 @@ module OntologyTests =
Expect.sequenceEqual actual2 expected2 "Relations differ"
]
+ testList "ContainsTerm" [
+ let testOnto = Ontology().AddTerm(CvTerm.create("TO:0", "test", "TO"))
+
+ testCase "gives correct check: true" <| fun _ ->
+ let actual = testOnto.ContainsTerm("TO:0")
+ Expect.isTrue actual "Returns false but should be true"
+
+ testCase "gives correct check: false" <| fun _ ->
+ let actual = testOnto.ContainsTerm("TO:1")
+ Expect.isFalse actual "Returns true but should be false"
+ ]
+
+ testList "GetAllRelations" [
+ testCase "returns all relations correctly" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.GetAllRelations()
+ let expected = [
+ "test:01", "test:02", Set.singleton Xref
+ "test:01", "test:04", Set.singleton IsA
+ "test:02", "test:04", Set.singleton IsA
+ "test:03", "test:02", Set.singleton Xref
+ "test:03", "test:04", Set.singleton IsA
+ ]
+ Expect.sequenceEqual actual expected "Relations differ"
+ ]
+
+ testList "TryGetRelations" [
+ testCase "gets Some relations" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.TryGetRelations("test:01", "test:02")
+ Expect.isSome actual "Relations are not there though they should"
+
+ testCase "gets relations correctly" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.TryGetRelations("test:01", "test:02")
+ let expected = Some <| set [Xref]
+ Expect.equal actual expected "Relations are not equal"
+
+ testCase "gets None when relations are not existing" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.TryGetRelations("test:02", "test:01")
+ Expect.isNone actual "Relations are there though they shouldn't"
+ ]
+
+ testList "HasRelations" [
+ testCase "gives correct check: true" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.HasRelations("test:01", "test:02")
+ Expect.isTrue actual "Returns false but should be true"
+
+ testCase "gives correct check: false" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.HasRelations("test:02", "test:01")
+ Expect.isFalse actual "Returns true but should be false"
+ ]
+
+ testList "HasRelation" [
+ testCase "gives correct check: true" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.HasRelation("test:01", "test:02", Xref)
+ Expect.isTrue actual "Returns false but should be true"
+
+ testCase "gives correct check: false" <| fun _ ->
+ let actual = ReferenceObjects.testOnto1.HasRelation("test:01", "test:02", IsA)
+ Expect.isFalse actual "Returns true but should be false"
+ ]
+
+ testList "fromTriplets" [
+ testCase "returns correct Ontology" <| fun _ ->
+ let trips = [
+ CvTerm.create("TR:1", "tripletTerm1", "TR"), IsA, CvTerm.create("TR:2", "tripletTerm2", "TR")
+ CvTerm.create("TR:1", "tripletTerm1", "TR"), Xref, CvTerm.create("TR:3", "tripletTerm3", "TR")
+ CvTerm.create("TR:2", "tripletTerm2", "TR"), Custom "has_a", CvTerm.create("TR:3", "tripletTerm3", "TR")
+ CvTerm.create("TR:1", "tripletTerm1", "TR"), Term (CvTerm.create("RO:9999999", "uses", "RO")), CvTerm.create("TR:4", "tripletTerm4", "TR")
+ CvTerm.create("TR:1", "tripletTerm1", "TR"), Custom "optional use", CvTerm.create("TR:4", "tripletTerm4", "TR")
+ ]
+ let actual = Ontology.fromTriplets trips |> FGraph.toSeq
+ let expected = [
+ "TR:1", CvTerm.create("TR:1", "tripletTerm1", "TR"), "TR:2", CvTerm.create("TR:2", "tripletTerm2", "TR"), Set.singleton IsA
+ "TR:1", CvTerm.create("TR:1", "tripletTerm1", "TR"), "TR:3", CvTerm.create("TR:3", "tripletTerm3", "TR"), Set.singleton Xref
+ "TR:1", CvTerm.create("TR:1", "tripletTerm1", "TR"), "TR:4", CvTerm.create("TR:4", "tripletTerm4", "TR"), Set [Term (CvTerm.create("RO:9999999", "uses", "RO")); Custom "optional use"]
+ "TR:2", CvTerm.create("TR:2", "tripletTerm2", "TR"), "TR:3", CvTerm.create("TR:3", "tripletTerm3", "TR"), Set.singleton <| Custom "has_a"
+ ]
+ Expect.sequenceEqual actual expected "Ontologies differ but they shouldn't"
+ ]
+
+ testList "toOboOntology" [
+ testCase "returns correct OboOntology" <| fun _ ->
+
+ let oboOntoHeaderTags = OboOntologyHeaderTags.Create("1.4", Ontology = "test")
+ let terms = [
+ OboTerm.Create("test:01", "Frosch", Xrefs = [{Name = "test:02"; Description = ""; Modifiers = ""}], IsA = ["test:04"])
+ OboTerm.Create("test:02", "Kröte", IsA = ["test:04"])
+ OboTerm.Create("test:03", "Quakendes Geschöpf", IsA = ["test:04"], Xrefs = [{Name = "test:02"; Description = ""; Modifiers = ""}])
+ OboTerm.Create("test:04", "Tier")
+ ]
+
+ let prepare terms =
+ terms
+ |> List.map (fun ot -> ot.Id, ot.Name, ot.IsA, ot.Relationships)
+
+ let actual = ReferenceObjects.testOnto1.ToOboOntology(oboOntoHeaderTags)
+ let expected = OboOntology.Create(terms, [], oboOntoHeaderTags)
+ Expect.sequenceEqual (prepare actual.Terms) (prepare expected.Terms) "Terms differ"
+ Expect.equal actual.FormatVersion expected.FormatVersion "format-version differs"
+ Expect.equal actual.Ontology expected.Ontology "ontology (i.e., ontology name) differs"
+ ]
+
]
\ No newline at end of file
diff --git a/tests/Ontology.NET.Tests/RelationType.Tests.fs b/tests/Ontology.NET.Tests/RelationType.Tests.fs
new file mode 100644
index 0000000..f9de5b1
--- /dev/null
+++ b/tests/Ontology.NET.Tests/RelationType.Tests.fs
@@ -0,0 +1,88 @@
+namespace Ontology.NET.Tests
+
+
+open Expecto
+open Graphoscope
+open FSharpAux
+
+open ControlledVocabulary
+open Ontology.NET
+
+
+module RelationTypeTests =
+
+ []
+ let relationTypeTests =
+ testList "RelationType" [
+
+ let dummyTerm = CvTerm.create("DT:1", "dummyTerm", "DT")
+
+ testList "fromString" [
+ testCase "creates IsA from 'is_a'" <| fun _ ->
+ let actual = RelationType.fromString "is_a"
+ Expect.equal actual IsA "Expected RelationType.IsA"
+
+ testCase "creates IsA from 'is a'" <| fun _ ->
+ let actual = RelationType.fromString "is a"
+ Expect.equal actual IsA "Expected RelationType.IsA"
+
+ testCase "creates IsA from 'ISA'" <| fun _ ->
+ let actual = RelationType.fromString "ISA"
+ Expect.equal actual IsA "Expected RelationType.IsA"
+
+ testCase "creates Xref from 'xref'" <| fun _ ->
+ let actual = RelationType.fromString "xref"
+ Expect.equal actual Xref "Expected RelationType.Xref"
+
+ testCase "creates Xref from 'x_ref'" <| fun _ ->
+ let actual = RelationType.fromString "x_ref"
+ Expect.equal actual Xref "Expected RelationType.Xref"
+
+ testCase "creates Xref from 'x ref'" <| fun _ ->
+ let actual = RelationType.fromString "x ref"
+ Expect.equal actual Xref "Expected RelationType.Xref"
+
+ testCase "creates Custom from unknown string" <| fun _ ->
+ let input = "related_to"
+ let actual = RelationType.fromString input
+ let expected = Custom input
+ Expect.equal actual expected "Expected Custom relation type"
+ ]
+
+ testList "ToString instance method" [
+ testCase "returns 'is_a' for IsA" <| fun _ ->
+ let actual = IsA.ToString()
+ Expect.equal actual "is_a" "ToString failed for IsA"
+
+ testCase "returns 'xref' for Xref" <| fun _ ->
+ let actual = Xref.ToString()
+ Expect.equal actual "xref" "ToString failed for Xref"
+
+ testCase "returns original string for Custom" <| fun _ ->
+ let actual = (Custom "related_to").ToString()
+ Expect.equal actual "related_to" "ToString failed for Custom"
+
+ testCase "returns CvTerm name for Term" <| fun _ ->
+ let actual = (Term dummyTerm).ToString()
+ Expect.equal actual "dummyTerm" "ToString failed for Term"
+ ]
+
+ testList "toString static method" [
+ testCase "returns 'is_a' for IsA" <| fun _ ->
+ let actual = RelationType.toString IsA
+ Expect.equal actual "is_a" "toString failed for IsA"
+
+ testCase "returns 'xref' for Xref" <| fun _ ->
+ let actual = RelationType.toString Xref
+ Expect.equal actual "xref" "toString failed for Xref"
+
+ testCase "returns string for Custom" <| fun _ ->
+ let actual = RelationType.toString (Custom "foobar")
+ Expect.equal actual "foobar" "toString failed for Custom"
+
+ testCase "returns term name for Term" <| fun _ ->
+ let actual = RelationType.toString (Term dummyTerm)
+ Expect.equal actual "dummyTerm" "toString failed for Term"
+ ]
+
+ ]
\ No newline at end of file