1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
//! The OBO Graphs data model and serde implementation.
//!
//! # See Also
//! The [OBO Graphs JSON schema](https://github.com/geneontology/obographs/tree/master/schema)
//! developed in the Gene Ontology project.

use std::iter::FromIterator;

use serde::Deserialize;
use serde::Serialize;

use crate::utils::serde::nullable_vector;
use crate::utils::serde::optional_vector;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct GraphDocument {
    #[serde(default, deserialize_with = "optional_vector")]
    pub graphs: Vec<Graph>,
    pub meta: Option<Box<Meta>>,
}

impl From<Graph> for GraphDocument {
    fn from(graph: Graph) -> Self {
        Self {
            graphs: vec![graph],
            meta: None,
        }
    }
}

impl FromIterator<Graph> for GraphDocument {
    fn from_iter<T>(iter: T) -> Self
    where
        T: IntoIterator<Item = Graph>,
    {
        Self {
            graphs: iter.into_iter().collect(),
            meta: None,
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Graph {
    #[serde(default, deserialize_with = "optional_vector")]
    pub nodes: Vec<Node>,
    #[serde(default, deserialize_with = "optional_vector")]
    pub edges: Vec<Edge>,
    pub id: String,
    #[serde(rename = "lbl")]
    pub label: Option<String>,
    pub meta: Box<Meta>,
    #[serde(rename = "equivalentNodesSets")]
    pub equivalent_nodes_sets: Vec<EquivalentNodesSet>,
    #[serde(rename = "logicalDefinitionAxioms")]
    pub logical_definition_axioms: Vec<LogicalDefinitionAxiom>,
    #[serde(rename = "domainRangeAxioms")]
    pub domain_range_axioms: Vec<DomainRangeAxiom>,
    #[serde(rename = "propertyChainAxioms")]
    pub property_chain_axioms: Vec<PropertyChainAxiom>,
}

impl Graph {
    pub fn extend(&mut self, other: Self) {
        self.nodes.extend(other.nodes);
        self.edges.extend(other.edges);
        self.equivalent_nodes_sets
            .extend(other.equivalent_nodes_sets);
        self.logical_definition_axioms
            .extend(other.logical_definition_axioms);
        self.domain_range_axioms.extend(other.domain_range_axioms);
        self.property_chain_axioms
            .extend(other.property_chain_axioms);
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Node {
    pub id: String,
    pub meta: Option<Box<Meta>>,
    #[serde(rename = "type")]
    pub ty: Option<NodeType>, // FIXME: Use `CLASS` as default instead?
    #[serde(rename = "lbl")]
    pub label: Option<String>,
}

#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
pub struct Meta {
    pub definition: Option<Box<DefinitionPropertyValue>>,
    #[serde(default, deserialize_with = "optional_vector")]
    pub comments: Vec<String>,
    #[serde(default, deserialize_with = "optional_vector")]
    pub subsets: Vec<String>,
    #[serde(default, deserialize_with = "optional_vector")]
    pub xrefs: Vec<XrefPropertyValue>,
    #[serde(default, deserialize_with = "optional_vector")]
    pub synonyms: Vec<SynonymPropertyValue>,
    #[serde(
        rename = "basicPropertyValues",
        default,
        deserialize_with = "optional_vector"
    )]
    pub basic_property_values: Vec<BasicPropertyValue>,
    pub version: Option<String>,
    #[serde(default)]
    pub deprecated: bool,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct DefinitionPropertyValue {
    pub pred: Option<String>,
    pub val: String,
    pub xrefs: Vec<String>,
    pub meta: Option<Box<Meta>>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum NodeType {
    Class,
    Individual,
    Property,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Edge {
    pub sub: String,
    pub pred: String,
    pub obj: String,
    pub meta: Option<Box<Meta>>,
}

#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
pub struct EquivalentNodesSet {
    pub meta: Option<Box<Meta>>,
    #[serde(rename = "representativeNodeId")]
    pub representative_node_id: Option<String>,
    #[serde(rename = "nodeIds", default, deserialize_with = "optional_vector")]
    pub node_ids: Vec<String>,
}

#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
pub struct LogicalDefinitionAxiom {
    pub meta: Option<Box<Meta>>,
    #[serde(rename = "definedClassId")]
    pub defined_class_id: String,
    #[serde(rename = "genusIds")]
    pub genus_ids: Vec<String>,
    #[serde(deserialize_with = "nullable_vector")]
    pub restrictions: Vec<ExistentialRestrictionExpression>,
}

#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq, Eq)]
pub struct ExistentialRestrictionExpression {
    #[serde(rename = "propertyId")]
    pub property_id: String,
    #[serde(rename = "fillerId")]
    pub filler_id: String,
}

impl ExistentialRestrictionExpression {
    pub fn new(property_id: String, filler_id: String) -> Self {
        Self {
            property_id,
            filler_id,
        }
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct DomainRangeAxiom {
    pub meta: Option<Box<Meta>>,
    #[serde(rename = "predicateId")]
    pub predicate_id: String,
    #[serde(
        rename = "domainClassIds",
        default,
        deserialize_with = "optional_vector"
    )]
    pub domain_class_ids: Vec<String>,
    #[serde(
        rename = "rangeClassIds",
        default,
        deserialize_with = "optional_vector"
    )]
    pub range_class_ids: Vec<String>,
    #[serde(
        rename = "allValuesFromEdges",
        default,
        deserialize_with = "optional_vector"
    )]
    pub all_values_from_edges: Vec<Edge>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct PropertyChainAxiom {
    pub meta: Option<Box<Meta>>,
    #[serde(rename = "predicateId")]
    pub predicate_id: String,
    #[serde(
        rename = "chainPredicateIds",
        default,
        deserialize_with = "optional_vector"
    )]
    pub chain_predicate_ids: Vec<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct XrefPropertyValue {
    pub pred: Option<String>,
    pub val: String,
    #[serde(default, deserialize_with = "optional_vector")]
    pub xrefs: Vec<String>,
    pub meta: Option<Box<Meta>>,
    #[serde(rename = "lbl")]
    pub label: Option<String>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct SynonymPropertyValue {
    pub pred: String,
    pub val: String,
    #[serde(default, deserialize_with = "optional_vector")]
    pub xrefs: Vec<String>,
    pub meta: Option<Box<Meta>>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct BasicPropertyValue {
    pub pred: String,
    pub val: String,
    #[serde(default, deserialize_with = "optional_vector")]
    pub xrefs: Vec<String>,
    pub meta: Option<Box<Meta>>,
}

impl BasicPropertyValue {
    pub fn new(predicate: String, value: String) -> Self {
        Self {
            pred: predicate,
            val: value,
            xrefs: Vec::new(),
            meta: None,
        }
    }
}