srdf/srdf_graph/
srdfgraph.rs

1use crate::async_srdf::AsyncSRDF;
2use crate::{FocusRDF, Query, RDFFormat, Rdf, SRDFBuilder, RDF_TYPE_STR};
3use async_trait::async_trait;
4use colored::*;
5use iri_s::IriS;
6use oxrdfio::{RdfFormat, RdfSerializer};
7use oxrdfxml::RdfXmlParser;
8use std::collections::{HashMap, HashSet};
9use std::fs::File;
10use std::io::{self, BufReader, Write};
11use std::path::{Path, PathBuf};
12use std::str::FromStr;
13use tracing::debug;
14
15use crate::srdfgraph_error::SRDFGraphError;
16use oxrdf::{
17    BlankNode as OxBlankNode, Graph, GraphName, Literal as OxLiteral, NamedNode as OxNamedNode,
18    NamedNodeRef, Quad, Subject as OxSubject, SubjectRef, Term as OxTerm, TermRef,
19    Triple as OxTriple, TripleRef,
20};
21use oxttl::{NQuadsParser, NTriplesParser, TurtleParser};
22use prefixmap::{prefixmap::*, PrefixMapError};
23
24#[derive(Debug, Default, Clone)]
25pub struct SRDFGraph {
26    focus: Option<OxTerm>,
27    graph: Graph,
28    pm: PrefixMap,
29    base: Option<IriS>,
30    bnode_counter: usize,
31}
32
33impl SRDFGraph {
34    pub fn new() -> Self {
35        Self::default()
36    }
37
38    pub fn len(&self) -> usize {
39        self.graph.len()
40    }
41
42    pub fn quads(&self) -> impl Iterator<Item = Quad> + '_ {
43        let graph_name = GraphName::DefaultGraph;
44        self.graph
45            .iter()
46            .map(move |t| triple_to_quad(t, graph_name.clone()))
47    }
48
49    pub fn is_empty(&self) -> bool {
50        self.graph.is_empty()
51    }
52
53    pub fn merge_from_reader<R: io::Read>(
54        &mut self,
55        read: R,
56        format: &RDFFormat,
57        base: Option<&str>,
58        reader_mode: &ReaderMode,
59    ) -> Result<(), SRDFGraphError> {
60        match format {
61            RDFFormat::Turtle => {
62                let turtle_parser = match base {
63                    None => TurtleParser::new(),
64                    Some(iri) => TurtleParser::new().with_base_iri(iri)?,
65                };
66                // let mut graph = Graph::default();
67                let mut reader = turtle_parser.for_reader(read);
68                for triple_result in reader.by_ref() {
69                    self.graph.insert(triple_result?.as_ref());
70                }
71                let prefixes: HashMap<&str, &str> = reader.prefixes().collect();
72                self.base = match (&self.base, base) {
73                    (None, None) => None,
74                    (Some(b), None) => Some(b.clone()),
75                    (_, Some(b)) => Some(IriS::new_unchecked(b)),
76                };
77                let pm = PrefixMap::from_hashmap(&prefixes)?;
78                self.merge_prefixes(pm)?;
79            }
80            RDFFormat::NTriples => {
81                let parser = NTriplesParser::new();
82                let mut reader = parser.for_reader(read);
83                for triple_result in reader.by_ref() {
84                    match triple_result {
85                        Err(e) => {
86                            if reader_mode.is_strict() {
87                                return Err(SRDFGraphError::TurtleError {
88                                    data: "Reading n-quads".to_string(),
89                                    turtle_error: e,
90                                });
91                            } else {
92                                debug!("Error captured: {e:?}")
93                            }
94                        }
95                        Ok(t) => {
96                            self.graph.insert(t.as_ref());
97                        }
98                    }
99                }
100            }
101            RDFFormat::RDFXML => {
102                let parser = RdfXmlParser::new();
103                let mut reader = parser.for_reader(read);
104                for triple_result in reader.by_ref() {
105                    match triple_result {
106                        Err(e) => {
107                            debug!("Error captured: {e:?}")
108                        }
109                        Ok(t) => {
110                            self.graph.insert(t.as_ref());
111                        }
112                    }
113                }
114            }
115            RDFFormat::TriG => todo!(),
116            RDFFormat::N3 => todo!(),
117            RDFFormat::NQuads => {
118                let parser = NQuadsParser::new();
119                let mut reader = parser.for_reader(read);
120                for triple_result in reader.by_ref() {
121                    match triple_result {
122                        Err(e) => {
123                            debug!("Error captured: {e:?}")
124                        }
125                        Ok(t) => {
126                            self.graph.insert(t.as_ref());
127                        }
128                    }
129                }
130            }
131        }
132        Ok(())
133    }
134
135    pub fn merge_prefixes(&mut self, prefixmap: PrefixMap) -> Result<(), SRDFGraphError> {
136        self.pm.merge(prefixmap)?;
137        Ok(())
138    }
139
140    pub fn from_reader<R: io::Read>(
141        read: R,
142        format: &RDFFormat,
143        base: Option<&str>,
144        reader_mode: &ReaderMode,
145    ) -> Result<SRDFGraph, SRDFGraphError> {
146        let mut srdf_graph = SRDFGraph::new();
147
148        srdf_graph.merge_from_reader(read, format, base, reader_mode)?;
149        Ok(srdf_graph)
150    }
151
152    pub fn resolve(&self, str: &str) -> Result<OxNamedNode, SRDFGraphError> {
153        let r = self.pm.resolve(str)?;
154        Ok(Self::cnv_iri(r))
155    }
156
157    pub fn show_blanknode(&self, bn: &OxBlankNode) -> String {
158        let str: String = format!("{}", bn);
159        format!("{}", str.green())
160    }
161
162    pub fn show_literal(&self, lit: &OxLiteral) -> String {
163        let str: String = format!("{}", lit);
164        format!("{}", str.red())
165    }
166
167    pub fn from_str(
168        data: &str,
169        format: &RDFFormat,
170        base: Option<&str>,
171        reader_mode: &ReaderMode,
172    ) -> Result<SRDFGraph, SRDFGraphError> {
173        Self::from_reader(std::io::Cursor::new(&data), format, base, reader_mode)
174    }
175
176    fn cnv_iri(iri: IriS) -> OxNamedNode {
177        OxNamedNode::new_unchecked(iri.as_str())
178    }
179
180    pub fn add_triple_ref<'a, S, P, O>(
181        &mut self,
182        subj: S,
183        pred: P,
184        obj: O,
185    ) -> Result<(), SRDFGraphError>
186    where
187        S: Into<SubjectRef<'a>>,
188        P: Into<NamedNodeRef<'a>>,
189        O: Into<TermRef<'a>>,
190    {
191        let subj: SubjectRef<'a> = subj.into();
192        let pred: NamedNodeRef<'a> = pred.into();
193        let obj: TermRef<'a> = obj.into();
194        let triple = TripleRef::new(subj, pred, obj);
195        self.graph.insert(triple);
196        Ok(())
197    }
198
199    pub fn merge_from_path<P: AsRef<Path>>(
200        &mut self,
201        path: P,
202        format: &RDFFormat,
203        base: Option<&str>,
204        reader_mode: &ReaderMode,
205    ) -> Result<(), SRDFGraphError> {
206        let path_name = path.as_ref().display();
207        let file = File::open(path.as_ref()).map_err(|e| SRDFGraphError::ReadingPathError {
208            path_name: path_name.to_string(),
209            error: e,
210        })?;
211        let reader = BufReader::new(file);
212        Self::merge_from_reader(self, reader, format, base, reader_mode)?;
213        Ok(())
214    }
215
216    pub fn from_path<P: AsRef<Path>>(
217        path: P,
218        format: &RDFFormat,
219        base: Option<&str>,
220        reader_mode: &ReaderMode,
221    ) -> Result<SRDFGraph, SRDFGraphError> {
222        let path_name = path.as_ref().display();
223        let file = File::open(path.as_ref()).map_err(|e| SRDFGraphError::ReadingPathError {
224            path_name: path_name.to_string(),
225            error: e,
226        })?;
227        let reader = BufReader::new(file);
228        Self::from_reader(reader, format, base, reader_mode)
229    }
230
231    pub fn parse_data(
232        data: &String,
233        format: &RDFFormat,
234        base: &Path,
235        reader_mode: &ReaderMode,
236    ) -> Result<SRDFGraph, SRDFGraphError> {
237        let mut attempt = PathBuf::from(base);
238        attempt.push(data);
239        let base = Some("base:://");
240        let data_path = &attempt;
241        let graph = Self::from_path(data_path, format, base, reader_mode)?;
242        Ok(graph)
243    }
244
245    pub fn prefixmap(&self) -> PrefixMap {
246        self.pm.clone()
247    }
248}
249
250impl Rdf for SRDFGraph {
251    type IRI = OxNamedNode;
252    type BNode = OxBlankNode;
253    type Literal = OxLiteral;
254    type Subject = OxSubject;
255    type Term = OxTerm;
256    type Triple = OxTriple;
257    type Err = SRDFGraphError;
258
259    fn resolve_prefix_local(&self, prefix: &str, local: &str) -> Result<IriS, PrefixMapError> {
260        let iri = self.pm.resolve_prefix_local(prefix, local)?;
261        Ok(iri.clone())
262    }
263
264    fn qualify_iri(&self, node: &Self::IRI) -> String {
265        let iri = IriS::from_str(node.as_str()).unwrap();
266        self.pm.qualify(&iri)
267    }
268
269    fn qualify_subject(&self, subj: &OxSubject) -> String {
270        match subj {
271            OxSubject::BlankNode(bn) => self.show_blanknode(bn),
272            OxSubject::NamedNode(n) => self.qualify_iri(n),
273            #[cfg(feature = "rdf-star")]
274            OxSubject::Triple(_) => unimplemented!(),
275        }
276    }
277
278    fn qualify_term(&self, term: &OxTerm) -> String {
279        match term {
280            OxTerm::BlankNode(bn) => self.show_blanknode(bn),
281            OxTerm::Literal(lit) => self.show_literal(lit),
282            OxTerm::NamedNode(n) => self.qualify_iri(n),
283            #[cfg(feature = "rdf-star")]
284            OxTerm::Triple(_) => unimplemented!(),
285        }
286    }
287
288    fn prefixmap(&self) -> Option<prefixmap::PrefixMap> {
289        Some(self.pm.clone())
290    }
291}
292
293impl Query for SRDFGraph {
294    fn triples(&self) -> Result<impl Iterator<Item = Self::Triple>, Self::Err> {
295        Ok(self.graph.iter().map(TripleRef::into_owned))
296    }
297}
298
299#[async_trait]
300impl AsyncSRDF for SRDFGraph {
301    type IRI = OxNamedNode;
302    type BNode = OxBlankNode;
303    type Literal = OxLiteral;
304    type Subject = OxSubject;
305    type Term = OxTerm;
306    type Err = SRDFGraphError;
307
308    async fn get_predicates_subject(
309        &self,
310        subject: &OxSubject,
311    ) -> Result<HashSet<OxNamedNode>, SRDFGraphError> {
312        let mut results = HashSet::new();
313        for triple in self.graph.triples_for_subject(subject) {
314            let predicate: OxNamedNode = triple.predicate.to_owned().into();
315            results.insert(predicate);
316        }
317        Ok(results)
318    }
319
320    async fn get_objects_for_subject_predicate(
321        &self,
322        subject: &OxSubject,
323        pred: &OxNamedNode,
324    ) -> Result<HashSet<OxTerm>, SRDFGraphError> {
325        let mut results = HashSet::new();
326        for triple in self.graph.triples_for_subject(subject) {
327            let predicate: OxNamedNode = triple.predicate.to_owned().into();
328            if predicate.eq(pred) {
329                let object: OxTerm = triple.object.to_owned().into();
330                results.insert(object);
331            }
332        }
333        Ok(results)
334    }
335
336    async fn get_subjects_for_object_predicate(
337        &self,
338        object: &OxTerm,
339        pred: &OxNamedNode,
340    ) -> Result<HashSet<OxSubject>, SRDFGraphError> {
341        let mut results = HashSet::new();
342        for triple in self.graph.triples_for_object(object) {
343            let predicate: OxNamedNode = triple.predicate.to_owned().into();
344            if predicate.eq(pred) {
345                let subject: OxSubject = triple.subject.to_owned().into();
346                results.insert(subject);
347            }
348        }
349        Ok(results)
350    }
351}
352
353impl FocusRDF for SRDFGraph {
354    fn set_focus(&mut self, focus: &Self::Term) {
355        self.focus = Some(focus.clone())
356    }
357
358    fn get_focus(&self) -> &Option<Self::Term> {
359        &self.focus
360    }
361}
362
363impl SRDFBuilder for SRDFGraph {
364    fn add_base(&mut self, base: &Option<IriS>) -> Result<(), Self::Err> {
365        self.base.clone_from(base);
366        Ok(())
367    }
368
369    fn add_prefix(&mut self, alias: &str, iri: &IriS) -> Result<(), Self::Err> {
370        self.pm.insert(alias, iri)?;
371        Ok(())
372    }
373
374    fn add_prefix_map(&mut self, prefix_map: PrefixMap) -> Result<(), Self::Err> {
375        self.pm = prefix_map.clone();
376        Ok(())
377    }
378
379    fn add_bnode(&mut self) -> Result<Self::BNode, Self::Err> {
380        self.bnode_counter += 1;
381        match self.bnode_counter.try_into() {
382            Ok(bn) => Ok(OxBlankNode::new_from_unique_id(bn)),
383            Err(_) => Err(SRDFGraphError::BlankNodeId {
384                msg: format!("Error converting {} to usize", self.bnode_counter),
385            }),
386        }
387    }
388
389    fn add_triple<S, P, O>(&mut self, subj: S, pred: P, obj: O) -> Result<(), Self::Err>
390    where
391        S: Into<Self::Subject>,
392        P: Into<Self::IRI>,
393        O: Into<Self::Term>,
394    {
395        let triple = OxTriple::new(subj.into(), pred.into(), obj.into());
396        self.graph.insert(&triple);
397        Ok(())
398    }
399
400    fn remove_triple<S, P, O>(&mut self, subj: S, pred: P, obj: O) -> Result<(), Self::Err>
401    where
402        S: Into<Self::Subject>,
403        P: Into<Self::IRI>,
404        O: Into<Self::Term>,
405    {
406        let triple = OxTriple::new(subj.into(), pred.into(), obj.into());
407        self.graph.remove(&triple);
408        Ok(())
409    }
410
411    fn add_type<S, T>(&mut self, node: S, type_: T) -> Result<(), Self::Err>
412    where
413        S: Into<Self::Subject>,
414        T: Into<Self::Term>,
415    {
416        let subject: Self::Subject = node.into();
417        let type_: Self::Term = type_.into();
418        let triple = OxTriple::new(subject, rdf_type(), type_.clone());
419        self.graph.insert(&triple);
420        Ok(())
421    }
422
423    fn empty() -> Self {
424        SRDFGraph {
425            focus: None,
426            graph: Graph::new(),
427            pm: PrefixMap::new(),
428            base: None,
429            bnode_counter: 0,
430        }
431    }
432
433    fn serialize<W: Write>(&self, format: &RDFFormat, write: &mut W) -> Result<(), Self::Err> {
434        let mut serializer = RdfSerializer::from_format(cnv_rdf_format(format));
435
436        for (prefix, iri) in &self.pm.map {
437            serializer = serializer.with_prefix(prefix, iri.as_str()).unwrap();
438        }
439
440        let mut writer = serializer.for_writer(write);
441        for triple in self.graph.iter() {
442            writer.serialize_triple(triple)?;
443        }
444        writer.finish()?;
445        Ok(())
446    }
447}
448
449fn cnv_rdf_format(rdf_format: &RDFFormat) -> RdfFormat {
450    match rdf_format {
451        RDFFormat::NTriples => RdfFormat::NTriples,
452        RDFFormat::Turtle => RdfFormat::Turtle,
453        RDFFormat::RDFXML => RdfFormat::RdfXml,
454        RDFFormat::TriG => RdfFormat::TriG,
455        RDFFormat::N3 => RdfFormat::N3,
456        RDFFormat::NQuads => RdfFormat::NQuads,
457    }
458}
459
460fn rdf_type() -> OxNamedNode {
461    OxNamedNode::new_unchecked(RDF_TYPE_STR)
462}
463
464fn triple_to_quad(t: TripleRef, graph_name: GraphName) -> Quad {
465    let subj: oxrdf::Subject = t.subject.into();
466    let pred: oxrdf::NamedNode = t.predicate.into();
467    let obj: oxrdf::Term = t.object.into();
468    Quad::new(subj, pred, obj, graph_name)
469}
470
471/// Reader mode when parsing RDF data files
472#[derive(Debug, PartialEq, Clone, Default)]
473pub enum ReaderMode {
474    /// Stops when there is an error
475    #[default]
476    Strict,
477
478    /// Emits a warning and continues processing
479    Lax,
480}
481
482impl ReaderMode {
483    pub fn is_strict(&self) -> bool {
484        matches!(self, ReaderMode::Strict)
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use std::collections::HashSet;
491
492    use iri_s::IriS;
493    use oxrdf::Literal as OxLiteral;
494    use oxrdf::NamedNode as OxNamedNode;
495    use oxrdf::Subject as OxSubject;
496    use oxrdf::Term as OxTerm;
497
498    use crate::iri;
499    use crate::matcher::Any;
500    use crate::not;
501    use crate::ok;
502    use crate::property_bool;
503    use crate::property_integer;
504    use crate::property_integers;
505    use crate::property_string;
506    use crate::property_value;
507    use crate::rdf_list;
508    use crate::rdf_parser;
509    use crate::satisfy;
510    use crate::set_focus;
511    use crate::PResult;
512    use crate::Query as _;
513    use crate::RDFFormat;
514    use crate::RDFNodeParse as _;
515    use crate::RDFParseError;
516    use crate::SRDFBuilder;
517    use crate::Triple;
518
519    use super::ReaderMode;
520    use super::SRDFGraph;
521
522    const DUMMY_GRAPH: &str = r#"
523        prefix : <http://example.org/>
524        :x :p 1 .
525        :y :p "String" .
526        :y :q 2 .
527        :z :r 3 .
528        :x :s 4 .
529    "#;
530
531    const DUMMY_GRAPH_1: &str = r#"
532        prefix : <http://example.org/>
533        prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
534        :x :p [ :p 1 ] .
535    "#;
536
537    const DUMMY_GRAPH_2: &str = r#"
538        prefix : <http://example.org/>
539        :x :p (1 2) .
540    "#;
541
542    const DUMMY_GRAPH_3: &str = r#"
543        prefix : <http://example.org/>
544        :x :p 1, 2, 3, 2 .
545    "#;
546
547    const DUMMY_GRAPH_4: &str = r#"
548        prefix : <http://example.org/>
549        :x :p 1, 2, 3 .
550    "#;
551
552    const DUMMY_GRAPH_5: &str = r#"
553        prefix : <http://example.org/>
554        :x :p 1, 2 ;
555        :q true .
556    "#;
557
558    const DUMMY_GRAPH_6: &str = r#"
559        prefix : <http://example.org/>
560        :x :p 1 .
561    "#;
562
563    const DUMMY_GRAPH_7: &str = r#"
564        prefix : <http://example.org/>
565        :x :p true .
566    "#;
567
568    const DUMMY_GRAPH_8: &str = r#"
569        prefix : <http://example.org/>
570        :x :p true ;
571        :q 1    .
572    "#;
573
574    const DUMMY_GRAPH_9: &str = r#"
575        prefix : <http://example.org/>
576        :x :p 1 .
577    "#;
578
579    const DUMMY_GRAPH_10: &str = r#"
580        prefix : <http://example.org/>
581        :x :p "1" .
582    "#;
583
584    #[derive(Debug, PartialEq)]
585    enum A {
586        Int(isize),
587        Bool(bool),
588    }
589
590    fn graph_from_str(s: &str) -> SRDFGraph {
591        SRDFGraph::from_str(s, &RDFFormat::Turtle, None, &ReaderMode::Strict).unwrap()
592    }
593
594    #[test]
595    fn test_triples_matching_subject_predicate_and_object() {
596        let graph = graph_from_str(DUMMY_GRAPH);
597        let x: OxSubject = OxNamedNode::new_unchecked("http://example.org/x").into();
598        let p = OxNamedNode::new_unchecked("http://example.org/p");
599        let one: OxTerm = OxLiteral::from(1).into();
600        let triples = graph.triples_matching(x, p, one).unwrap();
601        assert_eq!(triples.count(), 1)
602    }
603
604    #[test]
605    fn test_triples_matching_subject_and_predicate() {
606        let graph = graph_from_str(DUMMY_GRAPH);
607        let x: OxSubject = OxNamedNode::new_unchecked("http://example.org/x").into();
608        let p = OxNamedNode::new_unchecked("http://example.org/p");
609        let triples = graph.triples_matching(x, p, Any).unwrap();
610        assert_eq!(triples.count(), 1)
611    }
612
613    #[test]
614    fn test_triples_matching_subject_and_object() {
615        let graph = graph_from_str(DUMMY_GRAPH);
616        let x: OxSubject = OxNamedNode::new_unchecked("http://example.org/x").into();
617        let one: OxTerm = OxLiteral::from(1).into();
618        let triples = graph.triples_matching(x, Any, one).unwrap();
619        assert_eq!(triples.count(), 1)
620    }
621
622    #[test]
623    fn test_triples_matching_predicate_and_object() {
624        let graph = graph_from_str(DUMMY_GRAPH);
625        let p = OxNamedNode::new_unchecked("http://example.org/p");
626        let one: OxTerm = OxLiteral::from(1).into();
627        let triples = graph.triples_matching(Any, p, one).unwrap();
628        assert_eq!(triples.count(), 1)
629    }
630
631    #[test]
632    fn test_triples_matching_subject() {
633        let graph = graph_from_str(DUMMY_GRAPH);
634        let x: OxSubject = OxNamedNode::new_unchecked("http://example.org/x").into();
635        let triples = graph.triples_matching(x, Any, Any).unwrap();
636        assert_eq!(triples.count(), 2)
637    }
638
639    #[test]
640    fn test_triples_matching_predicate() {
641        let graph = graph_from_str(DUMMY_GRAPH);
642        let p = OxNamedNode::new_unchecked("http://example.org/p");
643        let triples = graph.triples_matching(Any, p, Any).unwrap();
644        assert_eq!(triples.count(), 2)
645    }
646
647    #[test]
648    fn test_triples_matching_object() {
649        let graph = graph_from_str(DUMMY_GRAPH);
650        let one: OxTerm = OxLiteral::from(1).into();
651        let triples = graph.triples_matching(Any, Any, one).unwrap();
652        assert_eq!(triples.count(), 1)
653    }
654
655    #[test]
656    fn test_incoming_arcs() {
657        let graph = graph_from_str(DUMMY_GRAPH);
658        let x = OxSubject::NamedNode(OxNamedNode::new_unchecked("http://example.org/x"));
659        let p = OxNamedNode::new_unchecked("http://example.org/p");
660        let one: OxTerm = OxLiteral::from(1).into();
661        let actual = graph.incoming_arcs(one).unwrap();
662        let expected = HashSet::from([x]);
663        assert_eq!(actual.get(&p), Some(&expected))
664    }
665
666    #[test]
667    fn test_outgoing_arcs() {
668        let graph = graph_from_str(DUMMY_GRAPH_1);
669
670        let x = OxSubject::NamedNode(OxNamedNode::new_unchecked("http://example.org/x"));
671        let p = OxNamedNode::new_unchecked("http://example.org/p");
672        let one: OxTerm = OxLiteral::from(1).into();
673
674        let subject = graph
675            .triples_matching(x, p.clone(), Any)
676            .unwrap()
677            .map(Triple::into_object)
678            .next()
679            .unwrap()
680            .try_into()
681            .unwrap();
682
683        let actual = graph.outgoing_arcs(subject).unwrap();
684        let expected = HashSet::from([one]);
685
686        assert_eq!(actual.get(&p), Some(&expected))
687    }
688
689    #[test]
690    fn test_add_triple() {
691        let mut graph = SRDFGraph::default();
692
693        let alice = OxSubject::NamedNode(OxNamedNode::new_unchecked("http://example.org/alice"));
694        let knows = OxNamedNode::new_unchecked("http://example.org/knows");
695        let bob = OxTerm::NamedNode(OxNamedNode::new_unchecked("http://example.org/bob"));
696
697        graph.add_triple(alice, knows, bob).unwrap();
698
699        assert_eq!(graph.len(), 1);
700    }
701
702    #[test]
703    fn test_rdf_list() {
704        let graph = graph_from_str(DUMMY_GRAPH_2);
705
706        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
707        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
708
709        let mut parser = property_value(&p).then(move |obj| set_focus(&obj).with(rdf_list()));
710        let result: Vec<OxTerm> = parser.parse(&x, graph).unwrap();
711
712        assert_eq!(
713            result,
714            vec![
715                OxTerm::from(OxLiteral::from(1)),
716                OxTerm::from(OxLiteral::from(2))
717            ]
718        )
719    }
720
721    #[test]
722    fn test_parser() {
723        rdf_parser! {
724            fn my_ok['a, A, RDF](value: &'a A)(RDF) -> A
725            where [
726                A: Clone
727            ] { ok(&value.clone()) }
728        }
729        let graph = graph_from_str("prefix : <http://example.org/>");
730        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
731        assert_eq!(my_ok(&3).parse(&x, graph).unwrap(), 3)
732    }
733
734    #[test]
735    fn test_parser_property_integers() {
736        let graph = graph_from_str(DUMMY_GRAPH_3);
737        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
738        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
739        let mut parser = property_integers(&p);
740        assert_eq!(parser.parse(&x, graph).unwrap(), HashSet::from([1, 2, 3]))
741    }
742
743    #[test]
744    fn test_parser_then_mut() {
745        let graph = graph_from_str(DUMMY_GRAPH_4);
746        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
747        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
748
749        let mut parser = property_integers(&p).then_mut(move |ns| {
750            ns.extend(vec![4, 5]);
751            ok(ns)
752        });
753
754        assert_eq!(
755            parser.parse(&x, graph).unwrap(),
756            HashSet::from([1, 2, 3, 4, 5])
757        )
758    }
759
760    #[test]
761    fn test_parser_or() {
762        let graph = graph_from_str(DUMMY_GRAPH_5);
763        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
764        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
765        let q = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/q"));
766        let mut parser = property_bool(&p).or(property_bool(&q));
767        assert!(parser.parse(&x, graph).unwrap())
768    }
769
770    #[test]
771    fn test_parser_or_enum_1() {
772        let graph = graph_from_str(DUMMY_GRAPH_6);
773        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
774        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
775        let parser_a_bool = property_bool(&p).map(A::Bool);
776        let parser_a_int = property_integer(&p).map(A::Int);
777        let mut parser = parser_a_int.or(parser_a_bool);
778        assert_eq!(parser.parse(&x, graph).unwrap(), A::Int(1))
779    }
780
781    #[test]
782    fn test_parser_or_enum_2() {
783        let graph = graph_from_str(DUMMY_GRAPH_7);
784        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
785        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
786        let parser_a_bool = property_bool(&p).map(A::Bool);
787        let parser_a_int = property_integer(&p).map(A::Int);
788        let mut parser = parser_a_int.or(parser_a_bool);
789        assert_eq!(parser.parse(&x, graph).unwrap(), A::Bool(true))
790    }
791
792    #[test]
793    fn test_parser_and() {
794        let graph = graph_from_str(DUMMY_GRAPH_8);
795        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
796        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
797        let q = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/q"));
798        let mut parser = property_bool(&p).and(property_integer(&q));
799        assert_eq!(parser.parse(&x, graph).unwrap(), (true, 1))
800    }
801
802    #[test]
803    fn test_parser_map() {
804        let graph = graph_from_str(DUMMY_GRAPH_9);
805        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
806        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
807        let mut parser = property_integer(&p).map(|n| n + 1);
808        assert_eq!(parser.parse(&x, graph).unwrap(), 2)
809    }
810
811    #[test]
812    fn test_parser_and_then() {
813        let graph = graph_from_str(DUMMY_GRAPH_10);
814        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
815        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
816
817        struct IntConversionError(String);
818
819        fn cnv_int(s: String) -> Result<isize, IntConversionError> {
820            s.parse().map_err(|_| IntConversionError(s))
821        }
822
823        impl From<IntConversionError> for RDFParseError {
824            fn from(error: IntConversionError) -> RDFParseError {
825                RDFParseError::Custom {
826                    msg: format!("Int conversion error: {}", error.0),
827                }
828            }
829        }
830
831        let mut parser = property_string(&p).and_then(cnv_int);
832        assert_eq!(parser.parse(&x, graph).unwrap(), 1)
833    }
834
835    #[test]
836    fn test_parser_flat_map() {
837        let graph = graph_from_str(DUMMY_GRAPH_10);
838        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
839        let p = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/p"));
840
841        fn cnv_int(s: String) -> PResult<isize> {
842            s.parse().map_err(|_| RDFParseError::Custom {
843                msg: format!("Error converting {s}"),
844            })
845        }
846
847        let mut parser = property_string(&p).flat_map(cnv_int);
848        assert_eq!(parser.parse(&x, graph).unwrap(), 1)
849    }
850
851    #[test]
852    fn test_rdf_parser_macro() {
853        rdf_parser! {
854              fn is_term['a, RDF](term: &'a RDF::Term)(RDF) -> ()
855              where [
856              ] {
857                let name = format!("is_{term}");
858                satisfy(|t| { t == *term }, name.as_str())
859              }
860        }
861
862        let graph = graph_from_str(DUMMY_GRAPH_9);
863        let x = OxNamedNode::new_unchecked("http://example.org/x");
864        let iri_s = IriS::from_named_node(&x);
865        let term = x.clone().into();
866        let mut parser = is_term(&term);
867        let result = parser.parse(&iri_s, graph);
868        assert!(result.is_ok())
869    }
870
871    #[test]
872    fn test_not() {
873        let graph = graph_from_str(DUMMY_GRAPH_9);
874        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
875        let q = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/q"));
876        assert!(not(property_value(&q)).parse(&x, graph).is_ok())
877    }
878
879    #[test]
880    fn test_iri() {
881        let graph = SRDFGraph::default();
882        let x = IriS::from_named_node(&OxNamedNode::new_unchecked("http://example.org/x"));
883        assert_eq!(iri().parse(&x, graph).unwrap(), x)
884    }
885
886    #[test]
887    fn test_add_triple_ref() {
888        let mut graph = SRDFGraph::default();
889        let s = OxNamedNode::new_unchecked("http://example.org/x");
890        let p = OxNamedNode::new_unchecked("http://example.org/p");
891        let o = OxNamedNode::new_unchecked("http://example.org/y");
892        graph.add_triple_ref(&s, &p, &o).unwrap();
893        assert_eq!(graph.len(), 1);
894    }
895}