Skip to main content

fastobo_graphs/from_graph/
entity.rs

1use std::str::FromStr;
2use std::string::ToString;
3
4use fastobo::ast::ClassIdent;
5use fastobo::ast::CreationDate;
6use fastobo::ast::Definition;
7use fastobo::ast::EntityFrame;
8use fastobo::ast::Ident;
9use fastobo::ast::InstanceClause;
10use fastobo::ast::InstanceFrame;
11use fastobo::ast::InstanceIdent;
12use fastobo::ast::Line;
13use fastobo::ast::LiteralPropertyValue;
14use fastobo::ast::PrefixedIdent;
15use fastobo::ast::PropertyValue;
16use fastobo::ast::QuotedString;
17use fastobo::ast::RelationIdent;
18use fastobo::ast::ResourcePropertyValue;
19use fastobo::ast::SubsetIdent;
20use fastobo::ast::Synonym;
21use fastobo::ast::TermClause;
22use fastobo::ast::TermFrame;
23use fastobo::ast::TypedefClause;
24use fastobo::ast::TypedefFrame;
25use fastobo::ast::UnquotedString;
26use fastobo::ast::Xref;
27use fastobo::ast::XrefList;
28
29use crate::constants::property::dc;
30use crate::constants::property::iao;
31use crate::constants::property::obo_in_owl;
32use crate::constants::property::rdfs;
33use crate::error::Error;
34use crate::error::Result;
35
36use crate::model::BasicPropertyValue;
37use crate::model::DefinitionPropertyValue;
38use crate::model::Meta;
39use crate::model::Node;
40use crate::model::NodeType;
41
42use super::FromGraph;
43
44// ---------------------------------------------------------------------------
45
46macro_rules! impl_frame_inner {
47    ($node:expr, $id: expr, $ident: ident, $variant: ident) => {{
48        mashup! {
49            m[Variant] = $variant;
50            m[Frame] = $variant Frame;
51            m[Clause] = $variant Clause;
52        }
53        m! {
54            let mut frame = Frame::new(Line::from($ident::from($id)));
55            if let Some(label) = $node.label {
56                let name = Clause::Name(Box::new(UnquotedString::new(label)));
57                frame.push(Line::from(name));
58            }
59            if let Some(meta) = $node.meta {
60                let clauses: Vec<Clause> = FromGraph::from_graph(*meta)?;
61                frame.extend(clauses.into_iter().map(Line::from));
62            }
63            Ok(Some(EntityFrame::Variant(Box::new(frame))))
64        }
65    }};
66}
67
68impl FromGraph<Node> for Option<EntityFrame> {
69    fn from_graph(node: Node) -> Result<Self> {
70        let id = Ident::from_str(&node.id)?;
71        match node.ty {
72            None => Ok(None),
73            Some(NodeType::Class) => impl_frame_inner!(node, id, ClassIdent, Term),
74            Some(NodeType::Individual) => impl_frame_inner!(node, id, InstanceIdent, Instance),
75            Some(NodeType::Property) => {
76                // replace ID with `oboInOwl:shorthand` if possible.
77                match impl_frame_inner!(node, id, RelationIdent, Typedef) {
78                    Ok(Some(EntityFrame::Typedef(mut frame))) => {
79                        if let Some((idx, _)) = frame.iter().enumerate().find(|(_, c)| {
80                            if let TypedefClause::PropertyValue(pv) = c.as_inner() {
81                                if let PropertyValue::Literal(lpv) = pv.as_ref() {
82                                    match lpv.property().as_ref() {
83                                        Ident::Url(url) => url.as_str() == obo_in_owl::SHORTHAND,
84                                        _ => false,
85                                    }
86                                } else {
87                                    false
88                                }
89                            } else {
90                                false
91                            }
92                        }) {
93                            let new_id = match frame.remove(idx).into_inner() {
94                                TypedefClause::PropertyValue(pv) => match *pv {
95                                    PropertyValue::Resource(rpv) => {
96                                        RelationIdent::from(rpv.target().clone())
97                                    }
98                                    _ => unreachable!(),
99                                },
100                                _ => unreachable!(),
101                            };
102                            *frame.id_mut() = new_id.into();
103                        }
104                        Ok(Some(EntityFrame::Typedef(frame)))
105                    }
106                    other => other,
107                }
108            }
109        }
110    }
111}
112
113// ---------------------------------------------------------------------------
114
115macro_rules! impl_meta {
116    ($clause:ident) => {
117        impl FromGraph<Meta> for Vec<$clause> {
118            fn from_graph(meta: Meta) -> Result<Self> {
119                let mut clauses = Vec::new();
120                if let Some(desc) = meta.definition {
121                    clauses.push($clause::from_graph(*desc)?)
122                }
123                for comment in meta.comments {
124                    clauses.push($clause::Comment(Box::new(UnquotedString::new(comment))));
125                }
126                for subset in meta.subsets {
127                    let id = SubsetIdent::from_str(&subset)?;
128                    clauses.push($clause::Subset(Box::new(id)));
129                }
130                for xref in meta.xrefs {
131                    clauses.push($clause::Xref(Box::new(Xref::from_graph(xref)?)));
132                }
133                for synonym in meta.synonyms {
134                    clauses.push($clause::Synonym(Box::new(Synonym::from_graph(synonym)?)));
135                }
136                for pv in meta.basic_property_values {
137                    clauses.push($clause::from_graph(pv)?);
138                }
139                if meta.deprecated {
140                    clauses.push($clause::IsObsolete(true));
141                }
142                Ok(clauses)
143            }
144        }
145    };
146}
147
148impl_meta!(TermClause);
149impl_meta!(TypedefClause);
150impl_meta!(InstanceClause);
151
152// ---------------------------------------------------------------------------
153
154macro_rules! impl_definition_pv {
155    ($clause:ident) => {
156        impl FromGraph<DefinitionPropertyValue> for $clause {
157            fn from_graph(pv: DefinitionPropertyValue) -> Result<Self> {
158                let value = QuotedString::new(pv.val);
159                let xrefs = pv
160                    .xrefs
161                    .into_iter()
162                    .map(|id: String| Ident::from_str(&id).map(Xref::new).map_err(Error::from))
163                    .collect::<Result<XrefList>>()?;
164                Ok($clause::Def(Box::new(Definition::with_xrefs(value, xrefs))))
165            }
166        }
167    };
168}
169
170impl_definition_pv!(TermClause);
171impl_definition_pv!(TypedefClause);
172impl_definition_pv!(InstanceClause);
173
174// ---------------------------------------------------------------------------
175
176macro_rules! impl_basic_pv_common {
177    ($pv:ident, $clause:ident, $x:ident $(, $l:pat => $r:expr )* ) => {{
178        match $x {
179            rdfs::COMMENT => {
180                Ok($clause::Comment(Box::new(UnquotedString::new($pv.val))))
181            },
182            obo_in_owl::HAS_ALTERNATIVE_ID => {
183                let id = Ident::from_str(&$pv.val)?;
184                Ok($clause::AltId(Box::new(id.into())))
185            },
186            obo_in_owl::HAS_OBO_NAMESPACE => {
187                let id = Ident::from_str(&$pv.val)?;
188                Ok($clause::Namespace(Box::new(id.into())))
189            },
190            obo_in_owl::CREATED_BY | dc::CREATOR => {
191                Ok($clause::CreatedBy(Box::new(UnquotedString::new($pv.val))))
192            }
193            obo_in_owl::CREATION_DATE | dc::DATE => {
194                let date = CreationDate::from_str(&$pv.val)?;
195                Ok($clause::CreationDate(Box::new(date)))
196            }
197            iao::REPLACED_BY => {
198                let id = Ident::from_str(&$pv.val)?;
199                Ok($clause::ReplacedBy(Box::new(id.into())))
200            }
201            $( $l => $r ),*
202            other => {
203                let rel = RelationIdent::from_str(&other)?;
204                let pv = match Ident::from_str(&$pv.val) {
205                    Ok(id) => PropertyValue::from(ResourcePropertyValue::new(rel, id)),
206                    Err(_) => PropertyValue::from(LiteralPropertyValue::new(
207                        rel,
208                        QuotedString::new($pv.val),
209                        Ident::from(PrefixedIdent::new("xsd", "string"))
210                    ))
211                };
212                Ok($clause::PropertyValue(Box::new(pv)))
213            },
214        }
215    }};
216}
217
218impl FromGraph<BasicPropertyValue> for TermClause {
219    fn from_graph(pv: BasicPropertyValue) -> Result<Self> {
220        let s = pv.pred.as_str();
221        impl_basic_pv_common!(pv, TermClause, s)
222    }
223}
224
225impl FromGraph<BasicPropertyValue> for TypedefClause {
226    fn from_graph(pv: BasicPropertyValue) -> Result<Self> {
227        let s = pv.pred.as_str();
228        impl_basic_pv_common!(pv, TypedefClause, s,
229            obo_in_owl::IS_CYCLIC => {
230                match bool::from_str(&pv.val) {
231                    Ok(b) => Ok(TypedefClause::IsCyclic(b)),
232                    Err(e) => Err(Error::InvalidBoolean(e, pv.val.to_string())),
233                }
234            },
235            iao::ANTISYMMETRIC_PROPERTY => {
236                match bool::from_str(&pv.val) {
237                    Ok(b) => Ok(TypedefClause::IsAntiSymmetric(b)),
238                    Err(e) => Err(Error::InvalidBoolean(e, pv.val.to_string())),
239                }
240            },
241            obo_in_owl::IS_CLASS_LEVEL => {
242                match bool::from_str(&pv.val) {
243                    Ok(b) => Ok(TypedefClause::IsClassLevel(b)),
244                    Err(e) => Err(Error::InvalidBoolean(e, pv.val.to_string())),
245                }
246            },
247            obo_in_owl::IS_METADATA_TAG => {
248                match bool::from_str(&pv.val) {
249                    Ok(b) => Ok(TypedefClause::IsMetadataTag(b)),
250                    Err(e) => Err(Error::InvalidBoolean(e, pv.val.to_string())),
251                }
252            }
253        )
254    }
255}
256
257impl FromGraph<BasicPropertyValue> for InstanceClause {
258    fn from_graph(pv: BasicPropertyValue) -> Result<Self> {
259        let s = pv.pred.as_str();
260        impl_basic_pv_common!(pv, InstanceClause, s)
261    }
262}