spargebra/
term.rs

1//! Data structures for [RDF 1.1 Concepts](https://www.w3.org/TR/rdf11-concepts/) like IRI, literal or triples.
2
3pub use oxrdf::{BlankNode, Literal, NamedNode, Subject, Term, Triple, Variable};
4use std::fmt;
5use std::fmt::Write;
6
7/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [triples](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple).
8///
9/// The default string formatter is returning an N-Triples, Turtle, and SPARQL compatible representation.
10#[derive(Eq, PartialEq, Debug, Clone, Hash)]
11pub enum GroundSubject {
12    NamedNode(NamedNode),
13    #[cfg(feature = "rdf-star")]
14    Triple(Box<GroundTriple>),
15}
16
17impl fmt::Display for GroundSubject {
18    #[inline]
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Self::NamedNode(node) => node.fmt(f),
22            #[cfg(feature = "rdf-star")]
23            Self::Triple(triple) => write!(
24                f,
25                "<<{} {} {}>>",
26                triple.subject, triple.predicate, triple.object
27            ),
28        }
29    }
30}
31
32impl From<NamedNode> for GroundSubject {
33    #[inline]
34    fn from(node: NamedNode) -> Self {
35        Self::NamedNode(node)
36    }
37}
38
39#[cfg(feature = "rdf-star")]
40impl From<GroundTriple> for GroundSubject {
41    #[inline]
42    fn from(triple: GroundTriple) -> Self {
43        Self::Triple(Box::new(triple))
44    }
45}
46
47impl TryFrom<Subject> for GroundSubject {
48    type Error = ();
49
50    #[inline]
51    fn try_from(subject: Subject) -> Result<Self, Self::Error> {
52        match subject {
53            Subject::NamedNode(t) => Ok(t.into()),
54            Subject::BlankNode(_) => Err(()),
55            #[cfg(feature = "rdf-star")]
56            Subject::Triple(t) => Ok(GroundTriple::try_from(*t)?.into()),
57        }
58    }
59}
60impl From<GroundSubject> for Subject {
61    #[inline]
62    fn from(subject: GroundSubject) -> Self {
63        match subject {
64            GroundSubject::NamedNode(t) => t.into(),
65            #[cfg(feature = "rdf-star")]
66            GroundSubject::Triple(t) => Triple::from(*t).into(),
67        }
68    }
69}
70
71impl TryFrom<GroundTerm> for GroundSubject {
72    type Error = ();
73
74    #[inline]
75    fn try_from(term: GroundTerm) -> Result<Self, Self::Error> {
76        match term {
77            GroundTerm::NamedNode(t) => Ok(t.into()),
78            GroundTerm::Literal(_) => Err(()),
79            #[cfg(feature = "rdf-star")]
80            GroundTerm::Triple(t) => Ok((*t).into()),
81        }
82    }
83}
84
85/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [literals](https://www.w3.org/TR/rdf11-concepts/#dfn-literal) and [triples](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple).
86///
87/// The default string formatter is returning an N-Triples, Turtle, and SPARQL compatible representation.
88#[derive(Eq, PartialEq, Debug, Clone, Hash)]
89pub enum GroundTerm {
90    NamedNode(NamedNode),
91    Literal(Literal),
92    #[cfg(feature = "rdf-star")]
93    Triple(Box<GroundTriple>),
94}
95
96impl fmt::Display for GroundTerm {
97    #[inline]
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        match self {
100            Self::NamedNode(node) => node.fmt(f),
101            Self::Literal(literal) => literal.fmt(f),
102            #[cfg(feature = "rdf-star")]
103            Self::Triple(triple) => write!(
104                f,
105                "<<{} {} {}>>",
106                triple.subject, triple.predicate, triple.object
107            ),
108        }
109    }
110}
111
112impl From<NamedNode> for GroundTerm {
113    #[inline]
114    fn from(node: NamedNode) -> Self {
115        Self::NamedNode(node)
116    }
117}
118
119impl From<Literal> for GroundTerm {
120    #[inline]
121    fn from(literal: Literal) -> Self {
122        Self::Literal(literal)
123    }
124}
125
126#[cfg(feature = "rdf-star")]
127impl From<GroundTriple> for GroundTerm {
128    #[inline]
129    fn from(triple: GroundTriple) -> Self {
130        Self::Triple(Box::new(triple))
131    }
132}
133
134impl TryFrom<Term> for GroundTerm {
135    type Error = ();
136
137    #[inline]
138    fn try_from(term: Term) -> Result<Self, Self::Error> {
139        match term {
140            Term::NamedNode(t) => Ok(t.into()),
141            Term::BlankNode(_) => Err(()),
142            Term::Literal(t) => Ok(t.into()),
143            #[cfg(feature = "rdf-star")]
144            Term::Triple(t) => Ok(GroundTriple::try_from(*t)?.into()),
145        }
146    }
147}
148
149impl From<GroundTerm> for Term {
150    #[inline]
151    fn from(term: GroundTerm) -> Self {
152        match term {
153            GroundTerm::NamedNode(t) => t.into(),
154            GroundTerm::Literal(l) => l.into(),
155            #[cfg(feature = "rdf-star")]
156            GroundTerm::Triple(t) => Triple::from(*t).into(),
157        }
158    }
159}
160
161/// A [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) without blank nodes.
162///
163/// The default string formatter is returning a N-Quads representation.
164///
165/// ```
166/// use spargebra::term::{GroundTriple, NamedNode};
167///
168/// assert_eq!(
169///     "<http://example.com/s> <http://example.com/p> <http://example.com/o>",
170///     GroundTriple {
171///         subject: NamedNode::new("http://example.com/s")?.into(),
172///         predicate: NamedNode::new("http://example.com/p")?,
173///         object: NamedNode::new("http://example.com/o")?.into(),
174///     }
175///     .to_string()
176/// );
177/// # Result::<_,oxrdf::IriParseError>::Ok(())
178/// ```
179#[derive(Eq, PartialEq, Debug, Clone, Hash)]
180pub struct GroundTriple {
181    pub subject: GroundSubject,
182    pub predicate: NamedNode,
183    pub object: GroundTerm,
184}
185
186impl fmt::Display for GroundTriple {
187    #[inline]
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        write!(f, "{} {} {}", self.subject, self.predicate, self.object)
190    }
191}
192
193impl TryFrom<Triple> for GroundTriple {
194    type Error = ();
195
196    #[inline]
197    fn try_from(triple: Triple) -> Result<Self, Self::Error> {
198        Ok(Self {
199            subject: triple.subject.try_into()?,
200            predicate: triple.predicate,
201            object: triple.object.try_into()?,
202        })
203    }
204}
205
206impl From<GroundTriple> for Triple {
207    #[inline]
208    fn from(triple: GroundTriple) -> Self {
209        Self {
210            subject: triple.subject.into(),
211            predicate: triple.predicate,
212            object: triple.object.into(),
213        }
214    }
215}
216
217/// A possible graph name.
218///
219/// It is the union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and the [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph).
220#[derive(Eq, PartialEq, Debug, Clone, Hash, Default)]
221pub enum GraphName {
222    NamedNode(NamedNode),
223    #[default]
224    DefaultGraph,
225}
226
227impl GraphName {
228    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
229    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
230        match self {
231            Self::NamedNode(node) => write!(f, "{node}"),
232            Self::DefaultGraph => f.write_str("default"),
233        }
234    }
235}
236
237impl fmt::Display for GraphName {
238    #[inline]
239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        match self {
241            Self::NamedNode(node) => node.fmt(f),
242            Self::DefaultGraph => f.write_str("DEFAULT"),
243        }
244    }
245}
246
247impl From<NamedNode> for GraphName {
248    #[inline]
249    fn from(node: NamedNode) -> Self {
250        Self::NamedNode(node)
251    }
252}
253
254impl TryFrom<GraphNamePattern> for GraphName {
255    type Error = ();
256
257    #[inline]
258    fn try_from(pattern: GraphNamePattern) -> Result<Self, Self::Error> {
259        match pattern {
260            GraphNamePattern::NamedNode(t) => Ok(t.into()),
261            GraphNamePattern::DefaultGraph => Ok(Self::DefaultGraph),
262            GraphNamePattern::Variable(_) => Err(()),
263        }
264    }
265}
266
267/// A [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset).
268///
269/// The default string formatter is returning a N-Quads representation.
270///
271/// ```
272/// use spargebra::term::{NamedNode, Quad};
273///
274/// assert_eq!(
275///     "<http://example.com/s> <http://example.com/p> <http://example.com/o> <http://example.com/g>",
276///     Quad {
277///         subject: NamedNode::new("http://example.com/s")?.into(),
278///         predicate: NamedNode::new("http://example.com/p")?,
279///         object: NamedNode::new("http://example.com/o")?.into(),
280///         graph_name: NamedNode::new("http://example.com/g")?.into(),
281///     }.to_string()
282/// );
283/// # Result::<_,oxrdf::IriParseError>::Ok(())
284/// ```
285#[derive(Eq, PartialEq, Debug, Clone, Hash)]
286pub struct Quad {
287    pub subject: Subject,
288    pub predicate: NamedNode,
289    pub object: Term,
290    pub graph_name: GraphName,
291}
292
293impl Quad {
294    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
295    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
296        if self.graph_name != GraphName::DefaultGraph {
297            f.write_str("(graph ")?;
298            self.graph_name.fmt_sse(f)?;
299            f.write_str(" (")?;
300        }
301        write!(
302            f,
303            "(triple {} {} {})",
304            self.subject, self.predicate, self.object
305        )?;
306        if self.graph_name != GraphName::DefaultGraph {
307            f.write_str("))")?;
308        }
309        Ok(())
310    }
311}
312
313impl fmt::Display for Quad {
314    #[inline]
315    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316        if self.graph_name == GraphName::DefaultGraph {
317            write!(f, "{} {} {}", self.subject, self.predicate, self.object)
318        } else {
319            write!(
320                f,
321                "{} {} {} {}",
322                self.subject, self.predicate, self.object, self.graph_name
323            )
324        }
325    }
326}
327
328impl TryFrom<QuadPattern> for Quad {
329    type Error = ();
330
331    #[inline]
332    fn try_from(quad: QuadPattern) -> Result<Self, Self::Error> {
333        Ok(Self {
334            subject: quad.subject.try_into()?,
335            predicate: quad.predicate.try_into()?,
336            object: quad.object.try_into()?,
337            graph_name: quad.graph_name.try_into()?,
338        })
339    }
340}
341
342/// A [RDF triple](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-triple) in an [RDF dataset](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-dataset) without blank nodes.
343///
344/// The default string formatter is returning a N-Quads representation.
345///
346/// ```
347/// use spargebra::term::{NamedNode, GroundQuad};
348///
349/// assert_eq!(
350///     "<http://example.com/s> <http://example.com/p> <http://example.com/o> <http://example.com/g>",
351///     GroundQuad {
352///         subject: NamedNode::new("http://example.com/s")?.into(),
353///         predicate: NamedNode::new("http://example.com/p")?,
354///         object: NamedNode::new("http://example.com/o")?.into(),
355///         graph_name: NamedNode::new("http://example.com/g")?.into(),
356///     }.to_string()
357/// );
358/// # Result::<_,oxrdf::IriParseError>::Ok(())
359/// ```
360#[derive(Eq, PartialEq, Debug, Clone, Hash)]
361pub struct GroundQuad {
362    pub subject: GroundSubject,
363    pub predicate: NamedNode,
364    pub object: GroundTerm,
365    pub graph_name: GraphName,
366}
367
368impl GroundQuad {
369    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
370    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
371        if self.graph_name != GraphName::DefaultGraph {
372            f.write_str("(graph ")?;
373            self.graph_name.fmt_sse(f)?;
374            f.write_str(" (")?;
375        }
376        write!(
377            f,
378            "(triple {} {} {})",
379            self.subject, self.predicate, self.object
380        )?;
381        if self.graph_name != GraphName::DefaultGraph {
382            f.write_str("))")?;
383        }
384        Ok(())
385    }
386}
387
388impl fmt::Display for GroundQuad {
389    #[inline]
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        if self.graph_name == GraphName::DefaultGraph {
392            write!(f, "{} {} {}", self.subject, self.predicate, self.object)
393        } else {
394            write!(
395                f,
396                "{} {} {} {}",
397                self.subject, self.predicate, self.object, self.graph_name
398            )
399        }
400    }
401}
402
403impl TryFrom<Quad> for GroundQuad {
404    type Error = ();
405
406    #[inline]
407    fn try_from(quad: Quad) -> Result<Self, Self::Error> {
408        Ok(Self {
409            subject: quad.subject.try_into()?,
410            predicate: quad.predicate,
411            object: quad.object.try_into()?,
412            graph_name: quad.graph_name,
413        })
414    }
415}
416
417/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
418#[derive(Eq, PartialEq, Debug, Clone, Hash)]
419pub enum NamedNodePattern {
420    NamedNode(NamedNode),
421    Variable(Variable),
422}
423
424impl NamedNodePattern {
425    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
426    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
427        match self {
428            Self::NamedNode(node) => write!(f, "{node}"),
429            Self::Variable(var) => write!(f, "{var}"),
430        }
431    }
432}
433
434impl fmt::Display for NamedNodePattern {
435    #[inline]
436    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437        match self {
438            Self::NamedNode(node) => node.fmt(f),
439            Self::Variable(var) => var.fmt(f),
440        }
441    }
442}
443
444impl From<NamedNode> for NamedNodePattern {
445    #[inline]
446    fn from(node: NamedNode) -> Self {
447        Self::NamedNode(node)
448    }
449}
450
451impl From<Variable> for NamedNodePattern {
452    #[inline]
453    fn from(var: Variable) -> Self {
454        Self::Variable(var)
455    }
456}
457
458impl TryFrom<NamedNodePattern> for NamedNode {
459    type Error = ();
460
461    #[inline]
462    fn try_from(pattern: NamedNodePattern) -> Result<Self, Self::Error> {
463        match pattern {
464            NamedNodePattern::NamedNode(t) => Ok(t),
465            NamedNodePattern::Variable(_) => Err(()),
466        }
467    }
468}
469
470/// The union of [terms](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
471#[derive(Eq, PartialEq, Debug, Clone, Hash)]
472pub enum TermPattern {
473    NamedNode(NamedNode),
474    BlankNode(BlankNode),
475    Literal(Literal),
476    #[cfg(feature = "rdf-star")]
477    Triple(Box<TriplePattern>),
478    Variable(Variable),
479}
480
481impl TermPattern {
482    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
483    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
484        match self {
485            Self::NamedNode(term) => write!(f, "{term}"),
486            Self::BlankNode(term) => write!(f, "{term}"),
487            Self::Literal(term) => write!(f, "{term}"),
488            #[cfg(feature = "rdf-star")]
489            Self::Triple(triple) => triple.fmt_sse(f),
490            Self::Variable(var) => write!(f, "{var}"),
491        }
492    }
493}
494
495impl fmt::Display for TermPattern {
496    #[inline]
497    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498        match self {
499            Self::NamedNode(term) => term.fmt(f),
500            Self::BlankNode(term) => term.fmt(f),
501            Self::Literal(term) => term.fmt(f),
502            #[cfg(feature = "rdf-star")]
503            Self::Triple(triple) => write!(f, "<<{triple}>>"),
504            Self::Variable(var) => var.fmt(f),
505        }
506    }
507}
508
509impl From<NamedNode> for TermPattern {
510    #[inline]
511    fn from(node: NamedNode) -> Self {
512        Self::NamedNode(node)
513    }
514}
515
516impl From<BlankNode> for TermPattern {
517    #[inline]
518    fn from(node: BlankNode) -> Self {
519        Self::BlankNode(node)
520    }
521}
522
523impl From<Literal> for TermPattern {
524    #[inline]
525    fn from(literal: Literal) -> Self {
526        Self::Literal(literal)
527    }
528}
529
530#[cfg(feature = "rdf-star")]
531impl From<TriplePattern> for TermPattern {
532    #[inline]
533    fn from(triple: TriplePattern) -> Self {
534        Self::Triple(Box::new(triple))
535    }
536}
537
538impl From<Variable> for TermPattern {
539    fn from(var: Variable) -> Self {
540        Self::Variable(var)
541    }
542}
543
544impl From<Subject> for TermPattern {
545    #[inline]
546    fn from(subject: Subject) -> Self {
547        match subject {
548            Subject::NamedNode(node) => node.into(),
549            Subject::BlankNode(node) => node.into(),
550            #[cfg(feature = "rdf-star")]
551            Subject::Triple(t) => TriplePattern::from(*t).into(),
552        }
553    }
554}
555
556impl From<Term> for TermPattern {
557    #[inline]
558    fn from(term: Term) -> Self {
559        match term {
560            Term::NamedNode(node) => node.into(),
561            Term::BlankNode(node) => node.into(),
562            Term::Literal(literal) => literal.into(),
563            #[cfg(feature = "rdf-star")]
564            Term::Triple(t) => TriplePattern::from(*t).into(),
565        }
566    }
567}
568
569impl From<NamedNodePattern> for TermPattern {
570    #[inline]
571    fn from(element: NamedNodePattern) -> Self {
572        match element {
573            NamedNodePattern::NamedNode(node) => node.into(),
574            NamedNodePattern::Variable(var) => var.into(),
575        }
576    }
577}
578
579impl From<GroundTermPattern> for TermPattern {
580    #[inline]
581    fn from(element: GroundTermPattern) -> Self {
582        match element {
583            GroundTermPattern::NamedNode(node) => node.into(),
584            GroundTermPattern::Literal(literal) => literal.into(),
585            #[cfg(feature = "rdf-star")]
586            GroundTermPattern::Triple(t) => TriplePattern::from(*t).into(),
587            GroundTermPattern::Variable(variable) => variable.into(),
588        }
589    }
590}
591
592impl TryFrom<TermPattern> for Subject {
593    type Error = ();
594
595    #[inline]
596    fn try_from(term: TermPattern) -> Result<Self, Self::Error> {
597        match term {
598            TermPattern::NamedNode(t) => Ok(t.into()),
599            TermPattern::BlankNode(t) => Ok(t.into()),
600            #[cfg(feature = "rdf-star")]
601            TermPattern::Triple(t) => Ok(Triple::try_from(*t)?.into()),
602            TermPattern::Literal(_) | TermPattern::Variable(_) => Err(()),
603        }
604    }
605}
606
607impl TryFrom<TermPattern> for Term {
608    type Error = ();
609
610    #[inline]
611    fn try_from(pattern: TermPattern) -> Result<Self, Self::Error> {
612        match pattern {
613            TermPattern::NamedNode(t) => Ok(t.into()),
614            TermPattern::BlankNode(t) => Ok(t.into()),
615            TermPattern::Literal(t) => Ok(t.into()),
616            #[cfg(feature = "rdf-star")]
617            TermPattern::Triple(t) => Ok(Triple::try_from(*t)?.into()),
618            TermPattern::Variable(_) => Err(()),
619        }
620    }
621}
622/// The union of [terms](https://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables) without blank nodes.
623#[derive(Eq, PartialEq, Debug, Clone, Hash)]
624pub enum GroundTermPattern {
625    NamedNode(NamedNode),
626    Literal(Literal),
627    Variable(Variable),
628    #[cfg(feature = "rdf-star")]
629    Triple(Box<GroundTriplePattern>),
630}
631
632impl GroundTermPattern {
633    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
634    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
635        match self {
636            Self::NamedNode(term) => write!(f, "{term}"),
637            Self::Literal(term) => write!(f, "{term}"),
638            Self::Variable(var) => write!(f, "{var}"),
639            #[cfg(feature = "rdf-star")]
640            Self::Triple(triple) => triple.fmt_sse(f),
641        }
642    }
643}
644
645impl fmt::Display for GroundTermPattern {
646    #[inline]
647    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
648        match self {
649            Self::NamedNode(term) => term.fmt(f),
650            Self::Literal(term) => term.fmt(f),
651            Self::Variable(var) => var.fmt(f),
652            #[cfg(feature = "rdf-star")]
653            Self::Triple(triple) => write!(f, "<<{triple}>>"),
654        }
655    }
656}
657
658impl From<NamedNode> for GroundTermPattern {
659    #[inline]
660    fn from(node: NamedNode) -> Self {
661        Self::NamedNode(node)
662    }
663}
664
665impl From<Literal> for GroundTermPattern {
666    #[inline]
667    fn from(literal: Literal) -> Self {
668        Self::Literal(literal)
669    }
670}
671
672#[cfg(feature = "rdf-star")]
673impl From<GroundTriplePattern> for GroundTermPattern {
674    #[inline]
675    fn from(triple: GroundTriplePattern) -> Self {
676        Self::Triple(Box::new(triple))
677    }
678}
679
680impl From<Variable> for GroundTermPattern {
681    #[inline]
682    fn from(var: Variable) -> Self {
683        Self::Variable(var)
684    }
685}
686
687impl From<GroundSubject> for GroundTermPattern {
688    #[inline]
689    fn from(term: GroundSubject) -> Self {
690        match term {
691            GroundSubject::NamedNode(node) => node.into(),
692            #[cfg(feature = "rdf-star")]
693            GroundSubject::Triple(triple) => GroundTriplePattern::from(*triple).into(),
694        }
695    }
696}
697impl From<GroundTerm> for GroundTermPattern {
698    #[inline]
699    fn from(term: GroundTerm) -> Self {
700        match term {
701            GroundTerm::NamedNode(node) => node.into(),
702            GroundTerm::Literal(literal) => literal.into(),
703            #[cfg(feature = "rdf-star")]
704            GroundTerm::Triple(triple) => GroundTriplePattern::from(*triple).into(),
705        }
706    }
707}
708
709impl From<NamedNodePattern> for GroundTermPattern {
710    #[inline]
711    fn from(element: NamedNodePattern) -> Self {
712        match element {
713            NamedNodePattern::NamedNode(node) => node.into(),
714            NamedNodePattern::Variable(var) => var.into(),
715        }
716    }
717}
718
719impl TryFrom<TermPattern> for GroundTermPattern {
720    type Error = ();
721
722    #[inline]
723    fn try_from(pattern: TermPattern) -> Result<Self, Self::Error> {
724        Ok(match pattern {
725            TermPattern::NamedNode(named_node) => named_node.into(),
726            TermPattern::BlankNode(_) => return Err(()),
727            TermPattern::Literal(literal) => literal.into(),
728            #[cfg(feature = "rdf-star")]
729            TermPattern::Triple(triple) => GroundTriplePattern::try_from(*triple)?.into(),
730            TermPattern::Variable(variable) => variable.into(),
731        })
732    }
733}
734
735/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri), [default graph name](https://www.w3.org/TR/rdf11-concepts/#dfn-default-graph) and [variables](https://www.w3.org/TR/sparql11-query/#sparqlQueryVariables).
736#[derive(Eq, PartialEq, Debug, Clone, Hash)]
737pub enum GraphNamePattern {
738    NamedNode(NamedNode),
739    DefaultGraph,
740    Variable(Variable),
741}
742
743impl GraphNamePattern {
744    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
745    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
746        match self {
747            Self::NamedNode(node) => write!(f, "{node}"),
748            Self::DefaultGraph => f.write_str("default"),
749            Self::Variable(var) => write!(f, "{var}"),
750        }
751    }
752}
753
754impl fmt::Display for GraphNamePattern {
755    #[inline]
756    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757        match self {
758            Self::NamedNode(node) => node.fmt(f),
759            Self::DefaultGraph => f.write_str("DEFAULT"),
760            Self::Variable(var) => var.fmt(f),
761        }
762    }
763}
764
765impl From<NamedNode> for GraphNamePattern {
766    #[inline]
767    fn from(node: NamedNode) -> Self {
768        Self::NamedNode(node)
769    }
770}
771
772impl From<Variable> for GraphNamePattern {
773    #[inline]
774    fn from(var: Variable) -> Self {
775        Self::Variable(var)
776    }
777}
778
779impl From<GraphName> for GraphNamePattern {
780    #[inline]
781    fn from(graph_name: GraphName) -> Self {
782        match graph_name {
783            GraphName::NamedNode(node) => node.into(),
784            GraphName::DefaultGraph => Self::DefaultGraph,
785        }
786    }
787}
788
789impl From<NamedNodePattern> for GraphNamePattern {
790    #[inline]
791    fn from(graph_name: NamedNodePattern) -> Self {
792        match graph_name {
793            NamedNodePattern::NamedNode(node) => node.into(),
794            NamedNodePattern::Variable(var) => var.into(),
795        }
796    }
797}
798
799/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern)
800#[derive(Eq, PartialEq, Debug, Clone, Hash)]
801pub struct TriplePattern {
802    pub subject: TermPattern,
803    pub predicate: NamedNodePattern,
804    pub object: TermPattern,
805}
806
807impl TriplePattern {
808    pub(crate) fn new(
809        subject: impl Into<TermPattern>,
810        predicate: impl Into<NamedNodePattern>,
811        object: impl Into<TermPattern>,
812    ) -> Self {
813        Self {
814            subject: subject.into(),
815            predicate: predicate.into(),
816            object: object.into(),
817        }
818    }
819
820    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
821    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
822        f.write_str("(triple ")?;
823        self.subject.fmt_sse(f)?;
824        f.write_str(" ")?;
825        self.predicate.fmt_sse(f)?;
826        f.write_str(" ")?;
827        self.object.fmt_sse(f)?;
828        f.write_str(")")
829    }
830}
831
832impl fmt::Display for TriplePattern {
833    #[inline]
834    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
835        write!(f, "{} {} {}", self.subject, self.predicate, self.object)
836    }
837}
838
839impl From<Triple> for TriplePattern {
840    #[inline]
841    fn from(triple: Triple) -> Self {
842        Self {
843            subject: triple.subject.into(),
844            predicate: triple.predicate.into(),
845            object: triple.object.into(),
846        }
847    }
848}
849
850impl From<GroundTriplePattern> for TriplePattern {
851    #[inline]
852    fn from(triple: GroundTriplePattern) -> Self {
853        Self {
854            subject: triple.subject.into(),
855            predicate: triple.predicate,
856            object: triple.object.into(),
857        }
858    }
859}
860
861impl TryFrom<TriplePattern> for Triple {
862    type Error = ();
863
864    #[inline]
865    fn try_from(triple: TriplePattern) -> Result<Self, Self::Error> {
866        Ok(Self {
867            subject: triple.subject.try_into()?,
868            predicate: triple.predicate.try_into()?,
869            object: triple.object.try_into()?,
870        })
871    }
872}
873
874/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) without blank nodes.
875#[derive(Eq, PartialEq, Debug, Clone, Hash)]
876pub struct GroundTriplePattern {
877    pub subject: GroundTermPattern,
878    pub predicate: NamedNodePattern,
879    pub object: GroundTermPattern,
880}
881
882impl GroundTriplePattern {
883    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
884    #[allow(dead_code)]
885    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
886        f.write_str("(triple ")?;
887        self.subject.fmt_sse(f)?;
888        f.write_str(" ")?;
889        self.predicate.fmt_sse(f)?;
890        f.write_str(" ")?;
891        self.object.fmt_sse(f)?;
892        f.write_str(")")
893    }
894}
895
896impl fmt::Display for GroundTriplePattern {
897    #[inline]
898    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
899        write!(f, "{} {} {}", self.subject, self.predicate, self.object)
900    }
901}
902
903impl From<GroundTriple> for GroundTriplePattern {
904    #[inline]
905    fn from(triple: GroundTriple) -> Self {
906        Self {
907            subject: triple.subject.into(),
908            predicate: triple.predicate.into(),
909            object: triple.object.into(),
910        }
911    }
912}
913
914impl TryFrom<TriplePattern> for GroundTriplePattern {
915    type Error = ();
916
917    #[inline]
918    fn try_from(triple: TriplePattern) -> Result<Self, Self::Error> {
919        Ok(Self {
920            subject: triple.subject.try_into()?,
921            predicate: triple.predicate,
922            object: triple.object.try_into()?,
923        })
924    }
925}
926
927/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph
928#[derive(Eq, PartialEq, Debug, Clone, Hash)]
929pub struct QuadPattern {
930    pub subject: TermPattern,
931    pub predicate: NamedNodePattern,
932    pub object: TermPattern,
933    pub graph_name: GraphNamePattern,
934}
935
936impl QuadPattern {
937    pub(crate) fn new(
938        subject: impl Into<TermPattern>,
939        predicate: impl Into<NamedNodePattern>,
940        object: impl Into<TermPattern>,
941        graph_name: impl Into<GraphNamePattern>,
942    ) -> Self {
943        Self {
944            subject: subject.into(),
945            predicate: predicate.into(),
946            object: object.into(),
947            graph_name: graph_name.into(),
948        }
949    }
950
951    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
952    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
953        if self.graph_name != GraphNamePattern::DefaultGraph {
954            f.write_str("(graph ")?;
955            self.graph_name.fmt_sse(f)?;
956            f.write_str(" (")?;
957        }
958        f.write_str("(triple ")?;
959        self.subject.fmt_sse(f)?;
960        f.write_str(" ")?;
961        self.predicate.fmt_sse(f)?;
962        f.write_str(" ")?;
963        self.object.fmt_sse(f)?;
964        f.write_str(")")?;
965        if self.graph_name != GraphNamePattern::DefaultGraph {
966            f.write_str("))")?;
967        }
968        Ok(())
969    }
970}
971
972impl fmt::Display for QuadPattern {
973    #[inline]
974    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
975        if self.graph_name == GraphNamePattern::DefaultGraph {
976            write!(f, "{} {} {}", self.subject, self.predicate, self.object)
977        } else {
978            write!(
979                f,
980                "GRAPH {} {{ {} {} {} }}",
981                self.graph_name, self.subject, self.predicate, self.object
982            )
983        }
984    }
985}
986
987/// A [triple pattern](https://www.w3.org/TR/sparql11-query/#defn_TriplePattern) in a specific graph without blank nodes.
988#[derive(Eq, PartialEq, Debug, Clone, Hash)]
989pub struct GroundQuadPattern {
990    pub subject: GroundTermPattern,
991    pub predicate: NamedNodePattern,
992    pub object: GroundTermPattern,
993    pub graph_name: GraphNamePattern,
994}
995
996impl GroundQuadPattern {
997    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
998    pub(crate) fn fmt_sse(&self, f: &mut impl Write) -> fmt::Result {
999        if self.graph_name != GraphNamePattern::DefaultGraph {
1000            f.write_str("(graph ")?;
1001            self.graph_name.fmt_sse(f)?;
1002            f.write_str(" (")?;
1003        }
1004        f.write_str("(triple ")?;
1005        self.subject.fmt_sse(f)?;
1006        f.write_str(" ")?;
1007        self.predicate.fmt_sse(f)?;
1008        f.write_str(" ")?;
1009        self.object.fmt_sse(f)?;
1010        f.write_str(")")?;
1011        if self.graph_name != GraphNamePattern::DefaultGraph {
1012            f.write_str("))")?;
1013        }
1014        Ok(())
1015    }
1016}
1017
1018impl fmt::Display for GroundQuadPattern {
1019    #[inline]
1020    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1021        if self.graph_name == GraphNamePattern::DefaultGraph {
1022            write!(f, "{} {} {}", self.subject, self.predicate, self.object)
1023        } else {
1024            write!(
1025                f,
1026                "GRAPH {} {{ {} {} {} }}",
1027                self.graph_name, self.subject, self.predicate, self.object
1028            )
1029        }
1030    }
1031}
1032
1033impl TryFrom<QuadPattern> for GroundQuadPattern {
1034    type Error = ();
1035
1036    #[inline]
1037    fn try_from(pattern: QuadPattern) -> Result<Self, Self::Error> {
1038        Ok(Self {
1039            subject: pattern.subject.try_into()?,
1040            predicate: pattern.predicate,
1041            object: pattern.object.try_into()?,
1042            graph_name: pattern.graph_name,
1043        })
1044    }
1045}