spargebra/
algebra.rs

1//! [SPARQL 1.1 Query Algebra](https://www.w3.org/TR/sparql11-query/#sparqlQuery) representation.
2
3use crate::term::*;
4use oxrdf::LiteralRef;
5use std::fmt;
6
7/// A [property path expression](https://www.w3.org/TR/sparql11-query/#defn_PropertyPathExpr).
8#[derive(Eq, PartialEq, Debug, Clone, Hash)]
9pub enum PropertyPathExpression {
10    NamedNode(NamedNode),
11    Reverse(Box<Self>),
12    Sequence(Box<Self>, Box<Self>),
13    Alternative(Box<Self>, Box<Self>),
14    ZeroOrMore(Box<Self>),
15    OneOrMore(Box<Self>),
16    ZeroOrOne(Box<Self>),
17    NegatedPropertySet(Vec<NamedNode>),
18}
19
20impl PropertyPathExpression {
21    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
22    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
23        match self {
24            Self::NamedNode(p) => write!(f, "{p}"),
25            Self::Reverse(p) => {
26                f.write_str("(reverse ")?;
27                p.fmt_sse(f)?;
28                f.write_str(")")
29            }
30            Self::Alternative(a, b) => {
31                f.write_str("(alt ")?;
32                a.fmt_sse(f)?;
33                f.write_str(" ")?;
34                b.fmt_sse(f)?;
35                f.write_str(")")
36            }
37            Self::Sequence(a, b) => {
38                f.write_str("(seq ")?;
39                a.fmt_sse(f)?;
40                f.write_str(" ")?;
41                b.fmt_sse(f)?;
42                f.write_str(")")
43            }
44            Self::ZeroOrMore(p) => {
45                f.write_str("(path* ")?;
46                p.fmt_sse(f)?;
47                f.write_str(")")
48            }
49            Self::OneOrMore(p) => {
50                f.write_str("(path+ ")?;
51                p.fmt_sse(f)?;
52                f.write_str(")")
53            }
54            Self::ZeroOrOne(p) => {
55                f.write_str("(path? ")?;
56                p.fmt_sse(f)?;
57                f.write_str(")")
58            }
59            Self::NegatedPropertySet(p) => {
60                f.write_str("(notoneof")?;
61                for p in p {
62                    write!(f, " {p}")?;
63                }
64                f.write_str(")")
65            }
66        }
67    }
68}
69
70impl fmt::Display for PropertyPathExpression {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        match self {
73            Self::NamedNode(p) => p.fmt(f),
74            Self::Reverse(p) => write!(f, "^({p})"),
75            Self::Sequence(a, b) => write!(f, "({a} / {b})"),
76            Self::Alternative(a, b) => write!(f, "({a} | {b})"),
77            Self::ZeroOrMore(p) => write!(f, "({p})*"),
78            Self::OneOrMore(p) => write!(f, "({p})+"),
79            Self::ZeroOrOne(p) => write!(f, "({p})?"),
80            Self::NegatedPropertySet(p) => {
81                f.write_str("!(")?;
82                for (i, c) in p.iter().enumerate() {
83                    if i > 0 {
84                        f.write_str(" | ")?;
85                    }
86                    write!(f, "{c}")?;
87                }
88                f.write_str(")")
89            }
90        }
91    }
92}
93
94impl From<NamedNode> for PropertyPathExpression {
95    fn from(p: NamedNode) -> Self {
96        Self::NamedNode(p)
97    }
98}
99
100/// An [expression](https://www.w3.org/TR/sparql11-query/#expressions).
101#[derive(Eq, PartialEq, Debug, Clone, Hash)]
102pub enum Expression {
103    NamedNode(NamedNode),
104    Literal(Literal),
105    Variable(Variable),
106    /// [Logical-or](https://www.w3.org/TR/sparql11-query/#func-logical-or).
107    Or(Box<Self>, Box<Self>),
108    /// [Logical-and](https://www.w3.org/TR/sparql11-query/#func-logical-and).
109    And(Box<Self>, Box<Self>),
110    /// [RDFterm-equal](https://www.w3.org/TR/sparql11-query/#func-RDFterm-equal) and all the XSD equalities.
111    Equal(Box<Self>, Box<Self>),
112    /// [sameTerm](https://www.w3.org/TR/sparql11-query/#func-sameTerm).
113    SameTerm(Box<Self>, Box<Self>),
114    /// [op:numeric-greater-than](https://www.w3.org/TR/xpath-functions-31/#func-numeric-greater-than) and other XSD greater than operators.
115    Greater(Box<Self>, Box<Self>),
116    GreaterOrEqual(Box<Self>, Box<Self>),
117    /// [op:numeric-less-than](https://www.w3.org/TR/xpath-functions-31/#func-numeric-less-than) and other XSD greater than operators.
118    Less(Box<Self>, Box<Self>),
119    LessOrEqual(Box<Self>, Box<Self>),
120    /// [IN](https://www.w3.org/TR/sparql11-query/#func-in)
121    In(Box<Self>, Vec<Self>),
122    /// [op:numeric-add](https://www.w3.org/TR/xpath-functions-31/#func-numeric-add) and other XSD additions.
123    Add(Box<Self>, Box<Self>),
124    /// [op:numeric-subtract](https://www.w3.org/TR/xpath-functions-31/#func-numeric-subtract) and other XSD subtractions.
125    Subtract(Box<Self>, Box<Self>),
126    /// [op:numeric-multiply](https://www.w3.org/TR/xpath-functions-31/#func-numeric-multiply) and other XSD multiplications.
127    Multiply(Box<Self>, Box<Self>),
128    /// [op:numeric-divide](https://www.w3.org/TR/xpath-functions-31/#func-numeric-divide) and other XSD divides.
129    Divide(Box<Self>, Box<Self>),
130    /// [op:numeric-unary-plus](https://www.w3.org/TR/xpath-functions-31/#func-numeric-unary-plus) and other XSD unary plus.
131    UnaryPlus(Box<Self>),
132    /// [op:numeric-unary-minus](https://www.w3.org/TR/xpath-functions-31/#func-numeric-unary-minus) and other XSD unary minus.
133    UnaryMinus(Box<Self>),
134    /// [fn:not](https://www.w3.org/TR/xpath-functions-31/#func-not).
135    Not(Box<Self>),
136    /// [EXISTS](https://www.w3.org/TR/sparql11-query/#func-filter-exists).
137    Exists(Box<GraphPattern>),
138    /// [BOUND](https://www.w3.org/TR/sparql11-query/#func-bound).
139    Bound(Variable),
140    /// [IF](https://www.w3.org/TR/sparql11-query/#func-if).
141    If(Box<Self>, Box<Self>, Box<Self>),
142    /// [COALESCE](https://www.w3.org/TR/sparql11-query/#func-coalesce).
143    Coalesce(Vec<Self>),
144    /// A regular function call.
145    FunctionCall(Function, Vec<Self>),
146}
147
148impl Expression {
149    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
150    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
151        match self {
152            Self::NamedNode(node) => write!(f, "{node}"),
153            Self::Literal(l) => write!(f, "{l}"),
154            Self::Variable(var) => write!(f, "{var}"),
155            Self::Or(a, b) => fmt_sse_binary_expression(f, "||", a, b),
156            Self::And(a, b) => fmt_sse_binary_expression(f, "&&", a, b),
157            Self::Equal(a, b) => fmt_sse_binary_expression(f, "=", a, b),
158            Self::SameTerm(a, b) => fmt_sse_binary_expression(f, "sameTerm", a, b),
159            Self::Greater(a, b) => fmt_sse_binary_expression(f, ">", a, b),
160            Self::GreaterOrEqual(a, b) => fmt_sse_binary_expression(f, ">=", a, b),
161            Self::Less(a, b) => fmt_sse_binary_expression(f, "<", a, b),
162            Self::LessOrEqual(a, b) => fmt_sse_binary_expression(f, "<=", a, b),
163            Self::In(a, b) => {
164                f.write_str("(in ")?;
165                a.fmt_sse(f)?;
166                for p in b {
167                    f.write_str(" ")?;
168                    p.fmt_sse(f)?;
169                }
170                f.write_str(")")
171            }
172            Self::Add(a, b) => fmt_sse_binary_expression(f, "+", a, b),
173            Self::Subtract(a, b) => fmt_sse_binary_expression(f, "-", a, b),
174            Self::Multiply(a, b) => fmt_sse_binary_expression(f, "*", a, b),
175            Self::Divide(a, b) => fmt_sse_binary_expression(f, "/", a, b),
176            Self::UnaryPlus(e) => fmt_sse_unary_expression(f, "+", e),
177            Self::UnaryMinus(e) => fmt_sse_unary_expression(f, "-", e),
178            Self::Not(e) => fmt_sse_unary_expression(f, "!", e),
179            Self::FunctionCall(function, parameters) => {
180                f.write_str("( ")?;
181                function.fmt_sse(f)?;
182                for p in parameters {
183                    f.write_str(" ")?;
184                    p.fmt_sse(f)?;
185                }
186                f.write_str(")")
187            }
188            Self::Exists(p) => {
189                f.write_str("(exists ")?;
190                p.fmt_sse(f)?;
191                f.write_str(")")
192            }
193            Self::Bound(v) => {
194                write!(f, "(bound {v})")
195            }
196            Self::If(a, b, c) => {
197                f.write_str("(if ")?;
198                a.fmt_sse(f)?;
199                f.write_str(" ")?;
200                b.fmt_sse(f)?;
201                f.write_str(" ")?;
202                c.fmt_sse(f)?;
203                f.write_str(")")
204            }
205            Self::Coalesce(parameters) => {
206                f.write_str("(coalesce")?;
207                for p in parameters {
208                    f.write_str(" ")?;
209                    p.fmt_sse(f)?;
210                }
211                f.write_str(")")
212            }
213        }
214    }
215}
216
217impl fmt::Display for Expression {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        match self {
220            Self::NamedNode(node) => node.fmt(f),
221            Self::Literal(l) => l.fmt(f),
222            Self::Variable(var) => var.fmt(f),
223            Self::Or(a, b) => write!(f, "({a} || {b})"),
224            Self::And(a, b) => write!(f, "({a} && {b})"),
225            Self::Equal(a, b) => {
226                write!(f, "({a} = {b})")
227            }
228            Self::SameTerm(a, b) => {
229                write!(f, "sameTerm({a}, {b})")
230            }
231            Self::Greater(a, b) => {
232                write!(f, "({a} > {b})")
233            }
234            Self::GreaterOrEqual(a, b) => write!(f, "({a} >= {b})"),
235            Self::Less(a, b) => {
236                write!(f, "({a} < {b})")
237            }
238            Self::LessOrEqual(a, b) => write!(f, "({a} <= {b})"),
239            Self::In(a, b) => {
240                write!(f, "({a} IN ")?;
241                write_arg_list(b, f)?;
242                f.write_str(")")
243            }
244            Self::Add(a, b) => {
245                write!(f, "{a} + {b}")
246            }
247            Self::Subtract(a, b) => {
248                write!(f, "{a} - {b}")
249            }
250            Self::Multiply(a, b) => {
251                write!(f, "{a} * {b}")
252            }
253            Self::Divide(a, b) => {
254                write!(f, "{a} / {b}")
255            }
256            Self::UnaryPlus(e) => write!(f, "+{e}"),
257            Self::UnaryMinus(e) => write!(f, "-{e}"),
258            Self::Not(e) => match e.as_ref() {
259                Self::Exists(p) => write!(f, "NOT EXISTS {{ {p} }}"),
260                e => write!(f, "!{e}"),
261            },
262            Self::FunctionCall(function, parameters) => {
263                write!(f, "{function}")?;
264                write_arg_list(parameters, f)
265            }
266            Self::Bound(v) => write!(f, "BOUND({v})"),
267            Self::Exists(p) => write!(f, "EXISTS {{ {p} }}"),
268            Self::If(a, b, c) => write!(f, "IF({a}, {b}, {c})"),
269            Self::Coalesce(parameters) => {
270                f.write_str("COALESCE")?;
271                write_arg_list(parameters, f)
272            }
273        }
274    }
275}
276
277impl From<NamedNode> for Expression {
278    fn from(p: NamedNode) -> Self {
279        Self::NamedNode(p)
280    }
281}
282
283impl From<Literal> for Expression {
284    fn from(p: Literal) -> Self {
285        Self::Literal(p)
286    }
287}
288
289impl From<Variable> for Expression {
290    fn from(v: Variable) -> Self {
291        Self::Variable(v)
292    }
293}
294
295impl From<NamedNodePattern> for Expression {
296    fn from(p: NamedNodePattern) -> Self {
297        match p {
298            NamedNodePattern::NamedNode(p) => p.into(),
299            NamedNodePattern::Variable(p) => p.into(),
300        }
301    }
302}
303
304fn write_arg_list(
305    params: impl IntoIterator<Item = impl fmt::Display>,
306    f: &mut fmt::Formatter<'_>,
307) -> fmt::Result {
308    f.write_str("(")?;
309    let mut cont = false;
310    for p in params {
311        if cont {
312            f.write_str(", ")?;
313        }
314        p.fmt(f)?;
315        cont = true;
316    }
317    f.write_str(")")
318}
319
320/// A function name.
321#[derive(Eq, PartialEq, Debug, Clone, Hash)]
322pub enum Function {
323    Str,
324    Lang,
325    LangMatches,
326    Datatype,
327    Iri,
328    BNode,
329    Rand,
330    Abs,
331    Ceil,
332    Floor,
333    Round,
334    Concat,
335    SubStr,
336    StrLen,
337    Replace,
338    UCase,
339    LCase,
340    EncodeForUri,
341    Contains,
342    StrStarts,
343    StrEnds,
344    StrBefore,
345    StrAfter,
346    Year,
347    Month,
348    Day,
349    Hours,
350    Minutes,
351    Seconds,
352    Timezone,
353    Tz,
354    Now,
355    Uuid,
356    StrUuid,
357    Md5,
358    Sha1,
359    Sha256,
360    Sha384,
361    Sha512,
362    StrLang,
363    StrDt,
364    IsIri,
365    IsBlank,
366    IsLiteral,
367    IsNumeric,
368    Regex,
369    #[cfg(feature = "rdf-star")]
370    Triple,
371    #[cfg(feature = "rdf-star")]
372    Subject,
373    #[cfg(feature = "rdf-star")]
374    Predicate,
375    #[cfg(feature = "rdf-star")]
376    Object,
377    #[cfg(feature = "rdf-star")]
378    IsTriple,
379    #[cfg(feature = "sep-0002")]
380    Adjust,
381    Custom(NamedNode),
382}
383
384impl Function {
385    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
386    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
387        match self {
388            Self::Str => f.write_str("str"),
389            Self::Lang => f.write_str("lang"),
390            Self::LangMatches => f.write_str("langmatches"),
391            Self::Datatype => f.write_str("datatype"),
392            Self::Iri => f.write_str("iri"),
393            Self::BNode => f.write_str("bnode"),
394            Self::Rand => f.write_str("rand"),
395            Self::Abs => f.write_str("abs"),
396            Self::Ceil => f.write_str("ceil"),
397            Self::Floor => f.write_str("floor"),
398            Self::Round => f.write_str("round"),
399            Self::Concat => f.write_str("concat"),
400            Self::SubStr => f.write_str("substr"),
401            Self::StrLen => f.write_str("strlen"),
402            Self::Replace => f.write_str("replace"),
403            Self::UCase => f.write_str("ucase"),
404            Self::LCase => f.write_str("lcase"),
405            Self::EncodeForUri => f.write_str("encode_for_uri"),
406            Self::Contains => f.write_str("contains"),
407            Self::StrStarts => f.write_str("strstarts"),
408            Self::StrEnds => f.write_str("strends"),
409            Self::StrBefore => f.write_str("strbefore"),
410            Self::StrAfter => f.write_str("strafter"),
411            Self::Year => f.write_str("year"),
412            Self::Month => f.write_str("month"),
413            Self::Day => f.write_str("day"),
414            Self::Hours => f.write_str("hours"),
415            Self::Minutes => f.write_str("minutes"),
416            Self::Seconds => f.write_str("seconds"),
417            Self::Timezone => f.write_str("timezone"),
418            Self::Tz => f.write_str("tz"),
419            Self::Now => f.write_str("now"),
420            Self::Uuid => f.write_str("uuid"),
421            Self::StrUuid => f.write_str("struuid"),
422            Self::Md5 => f.write_str("md5"),
423            Self::Sha1 => f.write_str("sha1"),
424            Self::Sha256 => f.write_str("sha256"),
425            Self::Sha384 => f.write_str("sha384"),
426            Self::Sha512 => f.write_str("sha512"),
427            Self::StrLang => f.write_str("strlang"),
428            Self::StrDt => f.write_str("strdt"),
429            Self::IsIri => f.write_str("isiri"),
430            Self::IsBlank => f.write_str("isblank"),
431            Self::IsLiteral => f.write_str("isliteral"),
432            Self::IsNumeric => f.write_str("isnumeric"),
433            Self::Regex => f.write_str("regex"),
434            #[cfg(feature = "rdf-star")]
435            Self::Triple => f.write_str("triple"),
436            #[cfg(feature = "rdf-star")]
437            Self::Subject => f.write_str("subject"),
438            #[cfg(feature = "rdf-star")]
439            Self::Predicate => f.write_str("predicate"),
440            #[cfg(feature = "rdf-star")]
441            Self::Object => f.write_str("object"),
442            #[cfg(feature = "rdf-star")]
443            Self::IsTriple => f.write_str("istriple"),
444            #[cfg(feature = "sep-0002")]
445            Self::Adjust => f.write_str("adjust"),
446            Self::Custom(iri) => write!(f, "{iri}"),
447        }
448    }
449}
450
451impl fmt::Display for Function {
452    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453        match self {
454            Self::Str => f.write_str("STR"),
455            Self::Lang => f.write_str("LANG"),
456            Self::LangMatches => f.write_str("LANGMATCHES"),
457            Self::Datatype => f.write_str("DATATYPE"),
458            Self::Iri => f.write_str("IRI"),
459            Self::BNode => f.write_str("BNODE"),
460            Self::Rand => f.write_str("RAND"),
461            Self::Abs => f.write_str("ABS"),
462            Self::Ceil => f.write_str("CEIL"),
463            Self::Floor => f.write_str("FLOOR"),
464            Self::Round => f.write_str("ROUND"),
465            Self::Concat => f.write_str("CONCAT"),
466            Self::SubStr => f.write_str("SUBSTR"),
467            Self::StrLen => f.write_str("STRLEN"),
468            Self::Replace => f.write_str("REPLACE"),
469            Self::UCase => f.write_str("UCASE"),
470            Self::LCase => f.write_str("LCASE"),
471            Self::EncodeForUri => f.write_str("ENCODE_FOR_URI"),
472            Self::Contains => f.write_str("CONTAINS"),
473            Self::StrStarts => f.write_str("STRSTARTS"),
474            Self::StrEnds => f.write_str("STRENDS"),
475            Self::StrBefore => f.write_str("STRBEFORE"),
476            Self::StrAfter => f.write_str("STRAFTER"),
477            Self::Year => f.write_str("YEAR"),
478            Self::Month => f.write_str("MONTH"),
479            Self::Day => f.write_str("DAY"),
480            Self::Hours => f.write_str("HOURS"),
481            Self::Minutes => f.write_str("MINUTES"),
482            Self::Seconds => f.write_str("SECONDS"),
483            Self::Timezone => f.write_str("TIMEZONE"),
484            Self::Tz => f.write_str("TZ"),
485            Self::Now => f.write_str("NOW"),
486            Self::Uuid => f.write_str("UUID"),
487            Self::StrUuid => f.write_str("STRUUID"),
488            Self::Md5 => f.write_str("MD5"),
489            Self::Sha1 => f.write_str("SHA1"),
490            Self::Sha256 => f.write_str("SHA256"),
491            Self::Sha384 => f.write_str("SHA384"),
492            Self::Sha512 => f.write_str("SHA512"),
493            Self::StrLang => f.write_str("STRLANG"),
494            Self::StrDt => f.write_str("STRDT"),
495            Self::IsIri => f.write_str("isIRI"),
496            Self::IsBlank => f.write_str("isBLANK"),
497            Self::IsLiteral => f.write_str("isLITERAL"),
498            Self::IsNumeric => f.write_str("isNUMERIC"),
499            Self::Regex => f.write_str("REGEX"),
500            #[cfg(feature = "rdf-star")]
501            Self::Triple => f.write_str("TRIPLE"),
502            #[cfg(feature = "rdf-star")]
503            Self::Subject => f.write_str("SUBJECT"),
504            #[cfg(feature = "rdf-star")]
505            Self::Predicate => f.write_str("PREDICATE"),
506            #[cfg(feature = "rdf-star")]
507            Self::Object => f.write_str("OBJECT"),
508            #[cfg(feature = "rdf-star")]
509            Self::IsTriple => f.write_str("isTRIPLE"),
510            #[cfg(feature = "sep-0002")]
511            Self::Adjust => f.write_str("ADJUST"),
512            Self::Custom(iri) => iri.fmt(f),
513        }
514    }
515}
516
517/// A SPARQL query [graph pattern](https://www.w3.org/TR/sparql11-query/#sparqlQuery).
518#[derive(Eq, PartialEq, Debug, Clone, Hash)]
519pub enum GraphPattern {
520    /// A [basic graph pattern](https://www.w3.org/TR/sparql11-query/#defn_BasicGraphPattern).
521    Bgp { patterns: Vec<TriplePattern> },
522    /// A [property path pattern](https://www.w3.org/TR/sparql11-query/#defn_evalPP_predicate).
523    Path {
524        subject: TermPattern,
525        path: PropertyPathExpression,
526        object: TermPattern,
527    },
528    /// [Join](https://www.w3.org/TR/sparql11-query/#defn_algJoin).
529    Join { left: Box<Self>, right: Box<Self> },
530    /// [LeftJoin](https://www.w3.org/TR/sparql11-query/#defn_algLeftJoin).
531    LeftJoin {
532        left: Box<Self>,
533        right: Box<Self>,
534        expression: Option<Expression>,
535    },
536    /// Lateral join i.e. evaluate right for all result row of left
537    #[cfg(feature = "sep-0006")]
538    Lateral { left: Box<Self>, right: Box<Self> },
539    /// [Filter](https://www.w3.org/TR/sparql11-query/#defn_algFilter).
540    Filter { expr: Expression, inner: Box<Self> },
541    /// [Union](https://www.w3.org/TR/sparql11-query/#defn_algUnion).
542    Union { left: Box<Self>, right: Box<Self> },
543    Graph {
544        name: NamedNodePattern,
545        inner: Box<Self>,
546    },
547    /// [Extend](https://www.w3.org/TR/sparql11-query/#defn_extend).
548    Extend {
549        inner: Box<Self>,
550        variable: Variable,
551        expression: Expression,
552    },
553    /// [Minus](https://www.w3.org/TR/sparql11-query/#defn_algMinus).
554    Minus { left: Box<Self>, right: Box<Self> },
555    /// A table used to provide inline values
556    Values {
557        variables: Vec<Variable>,
558        bindings: Vec<Vec<Option<GroundTerm>>>,
559    },
560    /// [OrderBy](https://www.w3.org/TR/sparql11-query/#defn_algOrdered).
561    OrderBy {
562        inner: Box<Self>,
563        expression: Vec<OrderExpression>,
564    },
565    /// [Project](https://www.w3.org/TR/sparql11-query/#defn_algProjection).
566    Project {
567        inner: Box<Self>,
568        variables: Vec<Variable>,
569    },
570    /// [Distinct](https://www.w3.org/TR/sparql11-query/#defn_algDistinct).
571    Distinct { inner: Box<Self> },
572    /// [Reduced](https://www.w3.org/TR/sparql11-query/#defn_algReduced).
573    Reduced { inner: Box<Self> },
574    /// [Slice](https://www.w3.org/TR/sparql11-query/#defn_algSlice).
575    Slice {
576        inner: Box<Self>,
577        start: usize,
578        length: Option<usize>,
579    },
580    /// [Group](https://www.w3.org/TR/sparql11-query/#aggregateAlgebra).
581    Group {
582        inner: Box<Self>,
583        variables: Vec<Variable>,
584        aggregates: Vec<(Variable, AggregateExpression)>,
585    },
586    /// [Service](https://www.w3.org/TR/sparql11-federated-query/#defn_evalService).
587    Service {
588        name: NamedNodePattern,
589        inner: Box<Self>,
590        silent: bool,
591    },
592}
593
594impl fmt::Display for GraphPattern {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        match self {
597            Self::Bgp { patterns } => {
598                for pattern in patterns {
599                    write!(f, "{pattern} .")?
600                }
601                Ok(())
602            }
603            Self::Path {
604                subject,
605                path,
606                object,
607            } => write!(f, "{subject} {path} {object} ."),
608            Self::Join { left, right } => {
609                #[allow(clippy::match_same_arms)]
610                match right.as_ref() {
611                    Self::LeftJoin { .. }
612                    | Self::Minus { .. }
613                    | Self::Extend { .. }
614                    | Self::Filter { .. } => {
615                        // The second block might be considered as a modification of the first one.
616                        write!(f, "{left} {{ {right} }}")
617                    }
618                    #[cfg(feature = "sep-0006")]
619                    Self::Lateral { .. } => {
620                        write!(f, "{left} {{ {right} }}")
621                    }
622                    _ => write!(f, "{left} {right}"),
623                }
624            }
625            Self::LeftJoin {
626                left,
627                right,
628                expression,
629            } => {
630                if let Some(expr) = expression {
631                    write!(f, "{left} OPTIONAL {{ {right} FILTER({expr}) }}")
632                } else {
633                    write!(f, "{left} OPTIONAL {{ {right} }}")
634                }
635            }
636            #[cfg(feature = "sep-0006")]
637            Self::Lateral { left, right } => {
638                write!(f, "{left} LATERAL {{ {right} }}")
639            }
640            Self::Filter { expr, inner } => {
641                write!(f, "{inner} FILTER({expr})")
642            }
643            Self::Union { left, right } => write!(f, "{{ {left} }} UNION {{ {right} }}"),
644            Self::Graph { name, inner } => {
645                write!(f, "GRAPH {name} {{ {inner} }}")
646            }
647            Self::Extend {
648                inner,
649                variable,
650                expression,
651            } => write!(f, "{inner} BIND({expression} AS {variable})"),
652            Self::Minus { left, right } => write!(f, "{left} MINUS {{ {right} }}"),
653            Self::Service {
654                name,
655                inner,
656                silent,
657            } => {
658                if *silent {
659                    write!(f, "SERVICE SILENT {name} {{ {inner} }}")
660                } else {
661                    write!(f, "SERVICE {name} {{ {inner} }}")
662                }
663            }
664            Self::Values {
665                variables,
666                bindings,
667            } => {
668                f.write_str("VALUES ( ")?;
669                for var in variables {
670                    write!(f, "{var} ")?;
671                }
672                f.write_str(") { ")?;
673                for row in bindings {
674                    f.write_str("( ")?;
675                    for val in row {
676                        match val {
677                            Some(val) => write!(f, "{val} "),
678                            None => f.write_str("UNDEF "),
679                        }?;
680                    }
681                    f.write_str(") ")?;
682                }
683                f.write_str(" }")
684            }
685            Self::Group {
686                inner,
687                variables,
688                aggregates,
689            } => {
690                f.write_str("{SELECT")?;
691                for (a, v) in aggregates {
692                    write!(f, " ({v} AS {a})")?;
693                }
694                for b in variables {
695                    write!(f, " {b}")?;
696                }
697                write!(f, " WHERE {{ {inner} }}")?;
698                if !variables.is_empty() {
699                    f.write_str(" GROUP BY")?;
700                    for v in variables {
701                        write!(f, " {v}")?;
702                    }
703                }
704                f.write_str("}")
705            }
706            p => write!(
707                f,
708                "{{ {} }}",
709                SparqlGraphRootPattern {
710                    pattern: p,
711                    dataset: None
712                }
713            ),
714        }
715    }
716}
717
718impl Default for GraphPattern {
719    fn default() -> Self {
720        Self::Bgp {
721            patterns: Vec::default(),
722        }
723    }
724}
725
726impl GraphPattern {
727    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
728    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
729        match self {
730            Self::Bgp { patterns } => {
731                f.write_str("(bgp")?;
732                for pattern in patterns {
733                    f.write_str(" ")?;
734                    pattern.fmt_sse(f)?;
735                }
736                f.write_str(")")
737            }
738            Self::Path {
739                subject,
740                path,
741                object,
742            } => {
743                f.write_str("(path ")?;
744                subject.fmt_sse(f)?;
745                f.write_str(" ")?;
746                path.fmt_sse(f)?;
747                f.write_str(" ")?;
748                object.fmt_sse(f)?;
749                f.write_str(")")
750            }
751            Self::Join { left, right } => {
752                f.write_str("(join ")?;
753                left.fmt_sse(f)?;
754                f.write_str(" ")?;
755                right.fmt_sse(f)?;
756                f.write_str(")")
757            }
758            Self::LeftJoin {
759                left,
760                right,
761                expression,
762            } => {
763                f.write_str("(leftjoin ")?;
764                left.fmt_sse(f)?;
765                f.write_str(" ")?;
766                right.fmt_sse(f)?;
767                if let Some(expr) = expression {
768                    f.write_str(" ")?;
769                    expr.fmt_sse(f)?;
770                }
771                f.write_str(")")
772            }
773            #[cfg(feature = "sep-0006")]
774            Self::Lateral { left, right } => {
775                f.write_str("(lateral ")?;
776                left.fmt_sse(f)?;
777                f.write_str(" ")?;
778                right.fmt_sse(f)?;
779                f.write_str(")")
780            }
781            Self::Filter { expr, inner } => {
782                f.write_str("(filter ")?;
783                expr.fmt_sse(f)?;
784                f.write_str(" ")?;
785                inner.fmt_sse(f)?;
786                f.write_str(")")
787            }
788            Self::Union { left, right } => {
789                f.write_str("(union ")?;
790                left.fmt_sse(f)?;
791                f.write_str(" ")?;
792                right.fmt_sse(f)?;
793                f.write_str(")")
794            }
795            Self::Graph { name, inner } => {
796                f.write_str("(graph ")?;
797                name.fmt_sse(f)?;
798                f.write_str(" ")?;
799                inner.fmt_sse(f)?;
800                f.write_str(")")
801            }
802            Self::Extend {
803                inner,
804                variable,
805                expression,
806            } => {
807                write!(f, "(extend (({variable} ")?;
808                expression.fmt_sse(f)?;
809                f.write_str(")) ")?;
810                inner.fmt_sse(f)?;
811                f.write_str(")")
812            }
813            Self::Minus { left, right } => {
814                f.write_str("(minus ")?;
815                left.fmt_sse(f)?;
816                f.write_str(" ")?;
817                right.fmt_sse(f)?;
818                f.write_str(")")
819            }
820            Self::Service {
821                name,
822                inner,
823                silent,
824            } => {
825                f.write_str("(service ")?;
826                if *silent {
827                    f.write_str("silent ")?;
828                }
829                name.fmt_sse(f)?;
830                f.write_str(" ")?;
831                inner.fmt_sse(f)?;
832                f.write_str(")")
833            }
834            Self::Group {
835                inner,
836                variables,
837                aggregates,
838            } => {
839                f.write_str("(group (")?;
840                for (i, v) in variables.iter().enumerate() {
841                    if i > 0 {
842                        f.write_str(" ")?;
843                    }
844                    write!(f, "{v}")?;
845                }
846                f.write_str(") (")?;
847                for (i, (v, a)) in aggregates.iter().enumerate() {
848                    if i > 0 {
849                        f.write_str(" ")?;
850                    }
851                    f.write_str("(")?;
852                    a.fmt_sse(f)?;
853                    write!(f, " {v})")?;
854                }
855                f.write_str(") ")?;
856                inner.fmt_sse(f)?;
857                f.write_str(")")
858            }
859            Self::Values {
860                variables,
861                bindings,
862            } => {
863                f.write_str("(table (vars")?;
864                for var in variables {
865                    write!(f, " {var}")?;
866                }
867                f.write_str(")")?;
868                for row in bindings {
869                    f.write_str(" (row")?;
870                    for (value, var) in row.iter().zip(variables) {
871                        if let Some(value) = value {
872                            write!(f, " ({var} {value})")?;
873                        }
874                    }
875                    f.write_str(")")?;
876                }
877                f.write_str(")")
878            }
879            Self::OrderBy { inner, expression } => {
880                f.write_str("(order (")?;
881                for (i, c) in expression.iter().enumerate() {
882                    if i > 0 {
883                        f.write_str(" ")?;
884                    }
885                    c.fmt_sse(f)?;
886                }
887                f.write_str(") ")?;
888                inner.fmt_sse(f)?;
889                f.write_str(")")
890            }
891            Self::Project { inner, variables } => {
892                f.write_str("(project (")?;
893                for (i, v) in variables.iter().enumerate() {
894                    if i > 0 {
895                        f.write_str(" ")?;
896                    }
897                    write!(f, "{v}")?;
898                }
899                f.write_str(") ")?;
900                inner.fmt_sse(f)?;
901                f.write_str(")")
902            }
903            Self::Distinct { inner } => {
904                f.write_str("(distinct ")?;
905                inner.fmt_sse(f)?;
906                f.write_str(")")
907            }
908            Self::Reduced { inner } => {
909                f.write_str("(reduced ")?;
910                inner.fmt_sse(f)?;
911                f.write_str(")")
912            }
913            Self::Slice {
914                inner,
915                start,
916                length,
917            } => {
918                if let Some(length) = length {
919                    write!(f, "(slice {start} {length} ")?;
920                } else {
921                    write!(f, "(slice {start} _ ")?;
922                }
923                inner.fmt_sse(f)?;
924                f.write_str(")")
925            }
926        }
927    }
928
929    /// Calls `callback` on each [in-scope variable](https://www.w3.org/TR/sparql11-query/#variableScope) occurrence.
930    pub fn on_in_scope_variable<'a>(&'a self, mut callback: impl FnMut(&'a Variable)) {
931        self.lookup_in_scope_variables(&mut callback)
932    }
933
934    fn lookup_in_scope_variables<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
935        #[allow(clippy::match_same_arms)]
936        match self {
937            Self::Bgp { patterns } => {
938                for pattern in patterns {
939                    lookup_triple_pattern_variables(pattern, callback)
940                }
941            }
942            Self::Path {
943                subject, object, ..
944            } => {
945                if let TermPattern::Variable(s) = subject {
946                    callback(s);
947                }
948                #[cfg(feature = "rdf-star")]
949                if let TermPattern::Triple(s) = subject {
950                    lookup_triple_pattern_variables(s, callback)
951                }
952                if let TermPattern::Variable(o) = object {
953                    callback(o);
954                }
955                #[cfg(feature = "rdf-star")]
956                if let TermPattern::Triple(o) = object {
957                    lookup_triple_pattern_variables(o, callback)
958                }
959            }
960            Self::Join { left, right }
961            | Self::LeftJoin { left, right, .. }
962            | Self::Union { left, right } => {
963                left.lookup_in_scope_variables(callback);
964                right.lookup_in_scope_variables(callback);
965            }
966            #[cfg(feature = "sep-0006")]
967            Self::Lateral { left, right } => {
968                left.lookup_in_scope_variables(callback);
969                right.lookup_in_scope_variables(callback);
970            }
971            Self::Graph { name, inner } => {
972                if let NamedNodePattern::Variable(g) = &name {
973                    callback(g);
974                }
975                inner.lookup_in_scope_variables(callback);
976            }
977            Self::Extend {
978                inner, variable, ..
979            } => {
980                callback(variable);
981                inner.lookup_in_scope_variables(callback);
982            }
983            Self::Minus { left, .. } => left.lookup_in_scope_variables(callback),
984            Self::Group {
985                variables,
986                aggregates,
987                ..
988            } => {
989                for v in variables {
990                    callback(v);
991                }
992                for (v, _) in aggregates {
993                    callback(v);
994                }
995            }
996            Self::Values { variables, .. } | Self::Project { variables, .. } => {
997                for v in variables {
998                    callback(v);
999                }
1000            }
1001            Self::Service { inner, .. }
1002            | Self::Filter { inner, .. }
1003            | Self::OrderBy { inner, .. }
1004            | Self::Distinct { inner }
1005            | Self::Reduced { inner }
1006            | Self::Slice { inner, .. } => inner.lookup_in_scope_variables(callback),
1007        }
1008    }
1009}
1010
1011fn lookup_triple_pattern_variables<'a>(
1012    pattern: &'a TriplePattern,
1013    callback: &mut impl FnMut(&'a Variable),
1014) {
1015    if let TermPattern::Variable(s) = &pattern.subject {
1016        callback(s);
1017    }
1018    #[cfg(feature = "rdf-star")]
1019    if let TermPattern::Triple(s) = &pattern.subject {
1020        lookup_triple_pattern_variables(s, callback)
1021    }
1022    if let NamedNodePattern::Variable(p) = &pattern.predicate {
1023        callback(p);
1024    }
1025    if let TermPattern::Variable(o) = &pattern.object {
1026        callback(o);
1027    }
1028    #[cfg(feature = "rdf-star")]
1029    if let TermPattern::Triple(o) = &pattern.object {
1030        lookup_triple_pattern_variables(o, callback)
1031    }
1032}
1033
1034pub(crate) struct SparqlGraphRootPattern<'a> {
1035    pattern: &'a GraphPattern,
1036    dataset: Option<&'a QueryDataset>,
1037}
1038
1039impl<'a> SparqlGraphRootPattern<'a> {
1040    pub fn new(pattern: &'a GraphPattern, dataset: Option<&'a QueryDataset>) -> Self {
1041        Self { pattern, dataset }
1042    }
1043}
1044
1045impl fmt::Display for SparqlGraphRootPattern<'_> {
1046    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1047        let mut distinct = false;
1048        let mut reduced = false;
1049        let mut order = None;
1050        let mut start = 0;
1051        let mut length = None;
1052        let mut project: &[Variable] = &[];
1053
1054        let mut child = self.pattern;
1055        loop {
1056            match child {
1057                GraphPattern::OrderBy { inner, expression } => {
1058                    order = Some(expression);
1059                    child = inner;
1060                }
1061                GraphPattern::Project { inner, variables } if project.is_empty() => {
1062                    project = variables;
1063                    child = inner;
1064                }
1065                GraphPattern::Distinct { inner } => {
1066                    distinct = true;
1067                    child = inner;
1068                }
1069                GraphPattern::Reduced { inner } => {
1070                    reduced = true;
1071                    child = inner;
1072                }
1073                GraphPattern::Slice {
1074                    inner,
1075                    start: s,
1076                    length: l,
1077                } => {
1078                    start = *s;
1079                    length = *l;
1080                    child = inner;
1081                }
1082                p => {
1083                    f.write_str("SELECT")?;
1084                    if distinct {
1085                        f.write_str(" DISTINCT")?;
1086                    }
1087                    if reduced {
1088                        f.write_str(" REDUCED")?;
1089                    }
1090                    if project.is_empty() {
1091                        f.write_str(" *")?;
1092                    } else {
1093                        for v in project {
1094                            write!(f, " {v}")?;
1095                        }
1096                    }
1097                    if let Some(dataset) = self.dataset {
1098                        write!(f, " {dataset}")?;
1099                    }
1100                    write!(f, " WHERE {{ {p} }}")?;
1101                    if let Some(order) = order {
1102                        f.write_str(" ORDER BY")?;
1103                        for c in order {
1104                            write!(f, " {c}")?;
1105                        }
1106                    }
1107                    if start > 0 {
1108                        write!(f, " OFFSET {start}")?;
1109                    }
1110                    if let Some(length) = length {
1111                        write!(f, " LIMIT {length}")?;
1112                    }
1113                    return Ok(());
1114                }
1115            }
1116        }
1117    }
1118}
1119
1120/// A set function used in aggregates (c.f. [`GraphPattern::Group`]).
1121#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1122pub enum AggregateExpression {
1123    /// [Count](https://www.w3.org/TR/sparql11-query/#defn_aggCount) with *.
1124    CountSolutions { distinct: bool },
1125    FunctionCall {
1126        name: AggregateFunction,
1127        expr: Expression,
1128        distinct: bool,
1129    },
1130}
1131
1132impl AggregateExpression {
1133    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1134    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1135        match self {
1136            Self::CountSolutions { distinct } => {
1137                f.write_str("(count")?;
1138                if *distinct {
1139                    f.write_str(" distinct")?;
1140                }
1141                f.write_str(")")
1142            }
1143            Self::FunctionCall {
1144                name:
1145                    AggregateFunction::GroupConcat {
1146                        separator: Some(separator),
1147                    },
1148                expr,
1149                distinct,
1150            } => {
1151                f.write_str("(group_concat ")?;
1152                if *distinct {
1153                    f.write_str("distinct ")?;
1154                }
1155                expr.fmt_sse(f)?;
1156                write!(f, " {})", LiteralRef::new_simple_literal(separator))
1157            }
1158            Self::FunctionCall {
1159                name,
1160                expr,
1161                distinct,
1162            } => {
1163                f.write_str("(")?;
1164                name.fmt_sse(f)?;
1165                f.write_str(" ")?;
1166                if *distinct {
1167                    f.write_str("distinct ")?;
1168                }
1169                expr.fmt_sse(f)?;
1170                f.write_str(")")
1171            }
1172        }
1173    }
1174}
1175
1176impl fmt::Display for AggregateExpression {
1177    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1178        match self {
1179            Self::CountSolutions { distinct } => {
1180                if *distinct {
1181                    f.write_str("COUNT(DISTINCT *)")
1182                } else {
1183                    f.write_str("COUNT(*)")
1184                }
1185            }
1186            Self::FunctionCall {
1187                name:
1188                    AggregateFunction::GroupConcat {
1189                        separator: Some(separator),
1190                    },
1191                expr,
1192                distinct,
1193            } => {
1194                if *distinct {
1195                    write!(
1196                        f,
1197                        "GROUP_CONCAT(DISTINCT {}; SEPARATOR = {})",
1198                        expr,
1199                        LiteralRef::new_simple_literal(separator)
1200                    )
1201                } else {
1202                    write!(
1203                        f,
1204                        "GROUP_CONCAT({}; SEPARATOR = {})",
1205                        expr,
1206                        LiteralRef::new_simple_literal(separator)
1207                    )
1208                }
1209            }
1210            Self::FunctionCall {
1211                name,
1212                expr,
1213                distinct,
1214            } => {
1215                if *distinct {
1216                    write!(f, "{name}(DISTINCT {expr})")
1217                } else {
1218                    write!(f, "{name}({expr})")
1219                }
1220            }
1221        }
1222    }
1223}
1224
1225/// An aggregate function name.
1226#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1227pub enum AggregateFunction {
1228    /// [Count](https://www.w3.org/TR/sparql11-query/#defn_aggCount) with *.
1229    Count,
1230    /// [Sum](https://www.w3.org/TR/sparql11-query/#defn_aggSum).
1231    Sum,
1232    /// [Avg](https://www.w3.org/TR/sparql11-query/#defn_aggAvg).
1233    Avg,
1234    /// [Min](https://www.w3.org/TR/sparql11-query/#defn_aggMin).
1235    Min,
1236    /// [Max](https://www.w3.org/TR/sparql11-query/#defn_aggMax).
1237    Max,
1238    /// [GroupConcat](https://www.w3.org/TR/sparql11-query/#defn_aggGroupConcat).
1239    GroupConcat {
1240        separator: Option<String>,
1241    },
1242    /// [Sample](https://www.w3.org/TR/sparql11-query/#defn_aggSample).
1243    Sample,
1244    Custom(NamedNode),
1245}
1246
1247impl AggregateFunction {
1248    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1249    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1250        match self {
1251            Self::Count => f.write_str("count"),
1252            Self::Sum => f.write_str("sum"),
1253            Self::Avg => f.write_str("avg"),
1254            Self::Min => f.write_str("min"),
1255            Self::Max => f.write_str("max"),
1256            Self::GroupConcat { .. } => f.write_str("group_concat"),
1257            Self::Sample => f.write_str("sample"),
1258            Self::Custom(iri) => write!(f, "{iri}"),
1259        }
1260    }
1261}
1262
1263impl fmt::Display for AggregateFunction {
1264    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1265        match self {
1266            Self::Count => f.write_str("COUNT"),
1267            Self::Sum => f.write_str("SUM"),
1268            Self::Avg => f.write_str("AVG"),
1269            Self::Min => f.write_str("MIN"),
1270            Self::Max => f.write_str("MAX"),
1271            Self::GroupConcat { .. } => f.write_str("GROUP_CONCAT"),
1272            Self::Sample => f.write_str("SAMPLE"),
1273            Self::Custom(iri) => iri.fmt(f),
1274        }
1275    }
1276}
1277
1278/// An ordering comparator used by [`GraphPattern::OrderBy`].
1279#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1280pub enum OrderExpression {
1281    /// Ascending order
1282    Asc(Expression),
1283    /// Descending order
1284    Desc(Expression),
1285}
1286
1287impl OrderExpression {
1288    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1289    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1290        match self {
1291            Self::Asc(e) => {
1292                f.write_str("(asc ")?;
1293                e.fmt_sse(f)?;
1294                f.write_str(")")
1295            }
1296            Self::Desc(e) => {
1297                f.write_str("(desc ")?;
1298                e.fmt_sse(f)?;
1299                f.write_str(")")
1300            }
1301        }
1302    }
1303}
1304
1305impl fmt::Display for OrderExpression {
1306    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1307        match self {
1308            Self::Asc(e) => write!(f, "ASC({e})"),
1309            Self::Desc(e) => write!(f, "DESC({e})"),
1310        }
1311    }
1312}
1313
1314/// A SPARQL query [dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset).
1315#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1316pub struct QueryDataset {
1317    pub default: Vec<NamedNode>,
1318    pub named: Option<Vec<NamedNode>>,
1319}
1320
1321impl QueryDataset {
1322    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1323    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1324        f.write_str("(")?;
1325        for (i, graph_name) in self.default.iter().enumerate() {
1326            if i > 0 {
1327                f.write_str(" ")?;
1328            }
1329            write!(f, "{graph_name}")?;
1330        }
1331        if let Some(named) = &self.named {
1332            for (i, graph_name) in named.iter().enumerate() {
1333                if !self.default.is_empty() || i > 0 {
1334                    f.write_str(" ")?;
1335                }
1336                write!(f, "(named {graph_name})")?;
1337            }
1338        }
1339        f.write_str(")")
1340    }
1341}
1342
1343impl fmt::Display for QueryDataset {
1344    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1345        for g in &self.default {
1346            write!(f, " FROM {g}")?;
1347        }
1348        if let Some(named) = &self.named {
1349            for g in named {
1350                write!(f, " FROM NAMED {g}")?;
1351            }
1352        }
1353        Ok(())
1354    }
1355}
1356
1357/// A target RDF graph for update operations.
1358///
1359/// Could be a specific graph, all named graphs or the complete dataset.
1360#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1361pub enum GraphTarget {
1362    NamedNode(NamedNode),
1363    DefaultGraph,
1364    NamedGraphs,
1365    AllGraphs,
1366}
1367
1368impl GraphTarget {
1369    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1370    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1371        match self {
1372            Self::NamedNode(node) => write!(f, "{node}"),
1373            Self::DefaultGraph => f.write_str("default"),
1374            Self::NamedGraphs => f.write_str("named"),
1375            Self::AllGraphs => f.write_str("all"),
1376        }
1377    }
1378}
1379
1380impl fmt::Display for GraphTarget {
1381    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1382        match self {
1383            Self::NamedNode(node) => write!(f, "GRAPH {node}"),
1384            Self::DefaultGraph => f.write_str("DEFAULT"),
1385            Self::NamedGraphs => f.write_str("NAMED"),
1386            Self::AllGraphs => f.write_str("ALL"),
1387        }
1388    }
1389}
1390
1391impl From<NamedNode> for GraphTarget {
1392    fn from(node: NamedNode) -> Self {
1393        Self::NamedNode(node)
1394    }
1395}
1396
1397impl From<GraphName> for GraphTarget {
1398    fn from(graph_name: GraphName) -> Self {
1399        match graph_name {
1400            GraphName::NamedNode(node) => Self::NamedNode(node),
1401            GraphName::DefaultGraph => Self::DefaultGraph,
1402        }
1403    }
1404}
1405
1406#[inline]
1407fn fmt_sse_unary_expression(f: &mut impl fmt::Write, name: &str, e: &Expression) -> fmt::Result {
1408    write!(f, "({name} ")?;
1409    e.fmt_sse(f)?;
1410    f.write_str(")")
1411}
1412
1413#[inline]
1414fn fmt_sse_binary_expression(
1415    f: &mut impl fmt::Write,
1416    name: &str,
1417    a: &Expression,
1418    b: &Expression,
1419) -> fmt::Result {
1420    write!(f, "({name} ")?;
1421    a.fmt_sse(f)?;
1422    f.write_str(" ")?;
1423    b.fmt_sse(f)?;
1424    f.write_str(")")
1425}