Skip to main content

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    fn walk<'a>(&'a self, callback: &mut impl FnMut(&'a Self)) {
217        callback(self);
218        match self {
219            Self::Variable(_)
220            | Self::Bound(_)
221            | Self::NamedNode(_)
222            | Self::Literal(_)
223            | Self::Exists(_) => (),
224            Self::UnaryPlus(i) | Self::UnaryMinus(i) | Self::Not(i) => i.walk(callback),
225            Self::Or(l, r)
226            | Self::And(l, r)
227            | Self::Equal(l, r)
228            | Self::SameTerm(l, r)
229            | Self::Greater(l, r)
230            | Self::GreaterOrEqual(l, r)
231            | Self::Less(l, r)
232            | Self::LessOrEqual(l, r)
233            | Self::Add(l, r)
234            | Self::Subtract(l, r)
235            | Self::Multiply(l, r)
236            | Self::Divide(l, r) => {
237                l.walk(callback);
238                r.walk(callback);
239            }
240            Self::If(c, l, r) => {
241                c.walk(callback);
242                l.walk(callback);
243                r.walk(callback);
244            }
245            Self::Coalesce(l) | Self::FunctionCall(_, l) => {
246                for e in l {
247                    e.walk(callback);
248                }
249            }
250            Self::In(l, r) => {
251                l.walk(callback);
252                for e in r {
253                    e.walk(callback);
254                }
255            }
256        }
257    }
258
259    fn lookup_used_variable<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
260        self.walk(&mut |e| {
261            if let Self::Variable(v) | Self::Bound(v) = e {
262                callback(v)
263            } else if let Self::Exists(p) = e {
264                p.lookup_used_variables(callback)
265            }
266        })
267    }
268}
269
270impl fmt::Display for Expression {
271    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272        match self {
273            Self::NamedNode(node) => node.fmt(f),
274            Self::Literal(l) => l.fmt(f),
275            Self::Variable(var) => var.fmt(f),
276            Self::Or(a, b) => write!(f, "({a} || {b})"),
277            Self::And(a, b) => write!(f, "({a} && {b})"),
278            Self::Equal(a, b) => {
279                write!(f, "({a} = {b})")
280            }
281            Self::SameTerm(a, b) => {
282                write!(f, "sameTerm({a}, {b})")
283            }
284            Self::Greater(a, b) => {
285                write!(f, "({a} > {b})")
286            }
287            Self::GreaterOrEqual(a, b) => write!(f, "({a} >= {b})"),
288            Self::Less(a, b) => {
289                write!(f, "({a} < {b})")
290            }
291            Self::LessOrEqual(a, b) => write!(f, "({a} <= {b})"),
292            Self::In(a, b) => {
293                write!(f, "({a} IN ")?;
294                write_arg_list(b, f)?;
295                f.write_str(")")
296            }
297            Self::Add(a, b) => {
298                write!(f, "{a} + {b}")
299            }
300            Self::Subtract(a, b) => {
301                write!(f, "{a} - {b}")
302            }
303            Self::Multiply(a, b) => {
304                write!(f, "{a} * {b}")
305            }
306            Self::Divide(a, b) => {
307                write!(f, "{a} / {b}")
308            }
309            Self::UnaryPlus(e) => write!(f, "+{e}"),
310            Self::UnaryMinus(e) => write!(f, "-{e}"),
311            Self::Not(e) => match e.as_ref() {
312                Self::Exists(p) => write!(f, "NOT EXISTS {{ {p} }}"),
313                e => write!(f, "!{e}"),
314            },
315            Self::FunctionCall(function, parameters) => {
316                write!(f, "{function}")?;
317                write_arg_list(parameters, f)
318            }
319            Self::Bound(v) => write!(f, "BOUND({v})"),
320            Self::Exists(p) => write!(f, "EXISTS {{ {p} }}"),
321            Self::If(a, b, c) => write!(f, "IF({a}, {b}, {c})"),
322            Self::Coalesce(parameters) => {
323                f.write_str("COALESCE")?;
324                write_arg_list(parameters, f)
325            }
326        }
327    }
328}
329
330impl From<NamedNode> for Expression {
331    fn from(p: NamedNode) -> Self {
332        Self::NamedNode(p)
333    }
334}
335
336impl From<Literal> for Expression {
337    fn from(p: Literal) -> Self {
338        Self::Literal(p)
339    }
340}
341
342impl From<Variable> for Expression {
343    fn from(v: Variable) -> Self {
344        Self::Variable(v)
345    }
346}
347
348impl From<NamedNodePattern> for Expression {
349    fn from(p: NamedNodePattern) -> Self {
350        match p {
351            NamedNodePattern::NamedNode(p) => p.into(),
352            NamedNodePattern::Variable(p) => p.into(),
353        }
354    }
355}
356
357fn write_arg_list(
358    params: impl IntoIterator<Item = impl fmt::Display>,
359    f: &mut fmt::Formatter<'_>,
360) -> fmt::Result {
361    f.write_str("(")?;
362    let mut cont = false;
363    for p in params {
364        if cont {
365            f.write_str(", ")?;
366        }
367        p.fmt(f)?;
368        cont = true;
369    }
370    f.write_str(")")
371}
372
373/// A function name.
374#[derive(Eq, PartialEq, Debug, Clone, Hash)]
375pub enum Function {
376    Str,
377    Lang,
378    LangMatches,
379    Datatype,
380    Iri,
381    BNode,
382    Rand,
383    Abs,
384    Ceil,
385    Floor,
386    Round,
387    Concat,
388    SubStr,
389    StrLen,
390    Replace,
391    UCase,
392    LCase,
393    EncodeForUri,
394    Contains,
395    StrStarts,
396    StrEnds,
397    StrBefore,
398    StrAfter,
399    Year,
400    Month,
401    Day,
402    Hours,
403    Minutes,
404    Seconds,
405    Timezone,
406    Tz,
407    Now,
408    Uuid,
409    StrUuid,
410    Md5,
411    Sha1,
412    Sha256,
413    Sha384,
414    Sha512,
415    StrLang,
416    StrDt,
417    IsIri,
418    IsBlank,
419    IsLiteral,
420    IsNumeric,
421    Regex,
422    #[cfg(feature = "sparql-12")]
423    Triple,
424    #[cfg(feature = "sparql-12")]
425    Subject,
426    #[cfg(feature = "sparql-12")]
427    Predicate,
428    #[cfg(feature = "sparql-12")]
429    Object,
430    #[cfg(feature = "sparql-12")]
431    IsTriple,
432    #[cfg(feature = "sparql-12")]
433    LangDir,
434    #[cfg(feature = "sparql-12")]
435    HasLang,
436    #[cfg(feature = "sparql-12")]
437    HasLangDir,
438    #[cfg(feature = "sparql-12")]
439    StrLangDir,
440    #[cfg(feature = "sep-0002")]
441    Adjust,
442    Custom(NamedNode),
443}
444
445impl Function {
446    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
447    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
448        match self {
449            Self::Str => f.write_str("str"),
450            Self::Lang => f.write_str("lang"),
451            Self::LangMatches => f.write_str("langmatches"),
452            Self::Datatype => f.write_str("datatype"),
453            Self::Iri => f.write_str("iri"),
454            Self::BNode => f.write_str("bnode"),
455            Self::Rand => f.write_str("rand"),
456            Self::Abs => f.write_str("abs"),
457            Self::Ceil => f.write_str("ceil"),
458            Self::Floor => f.write_str("floor"),
459            Self::Round => f.write_str("round"),
460            Self::Concat => f.write_str("concat"),
461            Self::SubStr => f.write_str("substr"),
462            Self::StrLen => f.write_str("strlen"),
463            Self::Replace => f.write_str("replace"),
464            Self::UCase => f.write_str("ucase"),
465            Self::LCase => f.write_str("lcase"),
466            Self::EncodeForUri => f.write_str("encode_for_uri"),
467            Self::Contains => f.write_str("contains"),
468            Self::StrStarts => f.write_str("strstarts"),
469            Self::StrEnds => f.write_str("strends"),
470            Self::StrBefore => f.write_str("strbefore"),
471            Self::StrAfter => f.write_str("strafter"),
472            Self::Year => f.write_str("year"),
473            Self::Month => f.write_str("month"),
474            Self::Day => f.write_str("day"),
475            Self::Hours => f.write_str("hours"),
476            Self::Minutes => f.write_str("minutes"),
477            Self::Seconds => f.write_str("seconds"),
478            Self::Timezone => f.write_str("timezone"),
479            Self::Tz => f.write_str("tz"),
480            Self::Now => f.write_str("now"),
481            Self::Uuid => f.write_str("uuid"),
482            Self::StrUuid => f.write_str("struuid"),
483            Self::Md5 => f.write_str("md5"),
484            Self::Sha1 => f.write_str("sha1"),
485            Self::Sha256 => f.write_str("sha256"),
486            Self::Sha384 => f.write_str("sha384"),
487            Self::Sha512 => f.write_str("sha512"),
488            Self::StrLang => f.write_str("strlang"),
489            Self::StrDt => f.write_str("strdt"),
490            Self::IsIri => f.write_str("isiri"),
491            Self::IsBlank => f.write_str("isblank"),
492            Self::IsLiteral => f.write_str("isliteral"),
493            Self::IsNumeric => f.write_str("isnumeric"),
494            Self::Regex => f.write_str("regex"),
495            #[cfg(feature = "sparql-12")]
496            Self::Triple => f.write_str("triple"),
497            #[cfg(feature = "sparql-12")]
498            Self::Subject => f.write_str("subject"),
499            #[cfg(feature = "sparql-12")]
500            Self::Predicate => f.write_str("predicate"),
501            #[cfg(feature = "sparql-12")]
502            Self::Object => f.write_str("object"),
503            #[cfg(feature = "sparql-12")]
504            Self::IsTriple => f.write_str("istriple"),
505            #[cfg(feature = "sparql-12")]
506            Function::LangDir => f.write_str("langdir"),
507            #[cfg(feature = "sparql-12")]
508            Function::HasLang => f.write_str("haslang"),
509            #[cfg(feature = "sparql-12")]
510            Function::HasLangDir => f.write_str("haslangdir"),
511            #[cfg(feature = "sparql-12")]
512            Function::StrLangDir => f.write_str("strlangdir"),
513            #[cfg(feature = "sep-0002")]
514            Self::Adjust => f.write_str("adjust"),
515            Self::Custom(iri) => write!(f, "{iri}"),
516        }
517    }
518}
519
520impl fmt::Display for Function {
521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522        match self {
523            Self::Str => f.write_str("STR"),
524            Self::Lang => f.write_str("LANG"),
525            Self::LangMatches => f.write_str("LANGMATCHES"),
526            Self::Datatype => f.write_str("DATATYPE"),
527            Self::Iri => f.write_str("IRI"),
528            Self::BNode => f.write_str("BNODE"),
529            Self::Rand => f.write_str("RAND"),
530            Self::Abs => f.write_str("ABS"),
531            Self::Ceil => f.write_str("CEIL"),
532            Self::Floor => f.write_str("FLOOR"),
533            Self::Round => f.write_str("ROUND"),
534            Self::Concat => f.write_str("CONCAT"),
535            Self::SubStr => f.write_str("SUBSTR"),
536            Self::StrLen => f.write_str("STRLEN"),
537            Self::Replace => f.write_str("REPLACE"),
538            Self::UCase => f.write_str("UCASE"),
539            Self::LCase => f.write_str("LCASE"),
540            Self::EncodeForUri => f.write_str("ENCODE_FOR_URI"),
541            Self::Contains => f.write_str("CONTAINS"),
542            Self::StrStarts => f.write_str("STRSTARTS"),
543            Self::StrEnds => f.write_str("STRENDS"),
544            Self::StrBefore => f.write_str("STRBEFORE"),
545            Self::StrAfter => f.write_str("STRAFTER"),
546            Self::Year => f.write_str("YEAR"),
547            Self::Month => f.write_str("MONTH"),
548            Self::Day => f.write_str("DAY"),
549            Self::Hours => f.write_str("HOURS"),
550            Self::Minutes => f.write_str("MINUTES"),
551            Self::Seconds => f.write_str("SECONDS"),
552            Self::Timezone => f.write_str("TIMEZONE"),
553            Self::Tz => f.write_str("TZ"),
554            Self::Now => f.write_str("NOW"),
555            Self::Uuid => f.write_str("UUID"),
556            Self::StrUuid => f.write_str("STRUUID"),
557            Self::Md5 => f.write_str("MD5"),
558            Self::Sha1 => f.write_str("SHA1"),
559            Self::Sha256 => f.write_str("SHA256"),
560            Self::Sha384 => f.write_str("SHA384"),
561            Self::Sha512 => f.write_str("SHA512"),
562            Self::StrLang => f.write_str("STRLANG"),
563            Self::StrDt => f.write_str("STRDT"),
564            Self::IsIri => f.write_str("isIRI"),
565            Self::IsBlank => f.write_str("isBLANK"),
566            Self::IsLiteral => f.write_str("isLITERAL"),
567            Self::IsNumeric => f.write_str("isNUMERIC"),
568            Self::Regex => f.write_str("REGEX"),
569            #[cfg(feature = "sparql-12")]
570            Self::Triple => f.write_str("TRIPLE"),
571            #[cfg(feature = "sparql-12")]
572            Self::Subject => f.write_str("SUBJECT"),
573            #[cfg(feature = "sparql-12")]
574            Self::Predicate => f.write_str("PREDICATE"),
575            #[cfg(feature = "sparql-12")]
576            Self::Object => f.write_str("OBJECT"),
577            #[cfg(feature = "sparql-12")]
578            Self::IsTriple => f.write_str("isTRIPLE"),
579            #[cfg(feature = "sparql-12")]
580            Function::LangDir => f.write_str("LANGDIR"),
581            #[cfg(feature = "sparql-12")]
582            Function::HasLang => f.write_str("hasLANG"),
583            #[cfg(feature = "sparql-12")]
584            Function::HasLangDir => f.write_str("hasLANGDIR"),
585            #[cfg(feature = "sparql-12")]
586            Function::StrLangDir => f.write_str("STRLANGDIR"),
587            #[cfg(feature = "sep-0002")]
588            Self::Adjust => f.write_str("ADJUST"),
589            Self::Custom(iri) => iri.fmt(f),
590        }
591    }
592}
593
594/// A SPARQL query [graph pattern](https://www.w3.org/TR/sparql11-query/#sparqlQuery).
595#[derive(Eq, PartialEq, Debug, Clone, Hash)]
596pub enum GraphPattern {
597    /// A [basic graph pattern](https://www.w3.org/TR/sparql11-query/#defn_BasicGraphPattern).
598    Bgp { patterns: Vec<TriplePattern> },
599    /// A [property path pattern](https://www.w3.org/TR/sparql11-query/#defn_evalPP_predicate).
600    Path {
601        subject: TermPattern,
602        path: PropertyPathExpression,
603        object: TermPattern,
604    },
605    /// [Join](https://www.w3.org/TR/sparql11-query/#defn_algJoin).
606    Join { left: Box<Self>, right: Box<Self> },
607    /// [LeftJoin](https://www.w3.org/TR/sparql11-query/#defn_algLeftJoin).
608    LeftJoin {
609        left: Box<Self>,
610        right: Box<Self>,
611        expression: Option<Expression>,
612    },
613    /// Lateral join i.e. evaluate right for all result row of left
614    #[cfg(feature = "sep-0006")]
615    Lateral { left: Box<Self>, right: Box<Self> },
616    /// [Filter](https://www.w3.org/TR/sparql11-query/#defn_algFilter).
617    Filter { expr: Expression, inner: Box<Self> },
618    /// [Union](https://www.w3.org/TR/sparql11-query/#defn_algUnion).
619    Union { left: Box<Self>, right: Box<Self> },
620    Graph {
621        name: NamedNodePattern,
622        inner: Box<Self>,
623    },
624    /// [Extend](https://www.w3.org/TR/sparql11-query/#defn_extend).
625    Extend {
626        inner: Box<Self>,
627        variable: Variable,
628        expression: Expression,
629    },
630    /// [Minus](https://www.w3.org/TR/sparql11-query/#defn_algMinus).
631    Minus { left: Box<Self>, right: Box<Self> },
632    /// A table used to provide inline values
633    Values {
634        variables: Vec<Variable>,
635        bindings: Vec<Vec<Option<GroundTerm>>>,
636    },
637    /// [OrderBy](https://www.w3.org/TR/sparql11-query/#defn_algOrdered).
638    OrderBy {
639        inner: Box<Self>,
640        expression: Vec<OrderExpression>,
641    },
642    /// [Project](https://www.w3.org/TR/sparql11-query/#defn_algProjection).
643    Project {
644        inner: Box<Self>,
645        variables: Vec<Variable>,
646    },
647    /// [Distinct](https://www.w3.org/TR/sparql11-query/#defn_algDistinct).
648    Distinct { inner: Box<Self> },
649    /// [Reduced](https://www.w3.org/TR/sparql11-query/#defn_algReduced).
650    Reduced { inner: Box<Self> },
651    /// [Slice](https://www.w3.org/TR/sparql11-query/#defn_algSlice).
652    Slice {
653        inner: Box<Self>,
654        start: usize,
655        length: Option<usize>,
656    },
657    /// [Group](https://www.w3.org/TR/sparql11-query/#aggregateAlgebra).
658    Group {
659        inner: Box<Self>,
660        variables: Vec<Variable>,
661        aggregates: Vec<(Variable, AggregateExpression)>,
662    },
663    /// [Service](https://www.w3.org/TR/sparql11-federated-query/#defn_evalService).
664    Service {
665        name: NamedNodePattern,
666        inner: Box<Self>,
667        silent: bool,
668    },
669}
670
671impl fmt::Display for GraphPattern {
672    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673        match self {
674            Self::Bgp { patterns } => {
675                for pattern in patterns {
676                    write!(f, "{pattern} .")?
677                }
678                Ok(())
679            }
680            Self::Path {
681                subject,
682                path,
683                object,
684            } => write!(f, "{subject} {path} {object} ."),
685            Self::Join { left, right } => {
686                match right.as_ref() {
687                    Self::LeftJoin { .. }
688                    | Self::Minus { .. }
689                    | Self::Extend { .. }
690                    | Self::Filter { .. } => {
691                        // The second block might be considered as a modification of the first one.
692                        write!(f, "{left} {{ {right} }}")
693                    }
694                    #[cfg(feature = "sep-0006")]
695                    Self::Lateral { .. } => {
696                        write!(f, "{left} {{ {right} }}")
697                    }
698                    _ => write!(f, "{left} {right}"),
699                }
700            }
701            Self::LeftJoin {
702                left,
703                right,
704                expression,
705            } => {
706                if let Some(expr) = expression {
707                    write!(f, "{left} OPTIONAL {{ {right} FILTER({expr}) }}")
708                } else {
709                    write!(f, "{left} OPTIONAL {{ {right} }}")
710                }
711            }
712            #[cfg(feature = "sep-0006")]
713            Self::Lateral { left, right } => {
714                write!(f, "{left} LATERAL {{ {right} }}")
715            }
716            Self::Filter { expr, inner } => {
717                write!(f, "{inner} FILTER({expr})")
718            }
719            Self::Union { left, right } => write!(f, "{{ {left} }} UNION {{ {right} }}"),
720            Self::Graph { name, inner } => {
721                write!(f, "GRAPH {name} {{ {inner} }}")
722            }
723            Self::Extend {
724                inner,
725                variable,
726                expression,
727            } => write!(f, "{inner} BIND({expression} AS {variable})"),
728            Self::Minus { left, right } => write!(f, "{left} MINUS {{ {right} }}"),
729            Self::Service {
730                name,
731                inner,
732                silent,
733            } => {
734                if *silent {
735                    write!(f, "SERVICE SILENT {name} {{ {inner} }}")
736                } else {
737                    write!(f, "SERVICE {name} {{ {inner} }}")
738                }
739            }
740            Self::Values {
741                variables,
742                bindings,
743            } => {
744                f.write_str("VALUES ( ")?;
745                for var in variables {
746                    write!(f, "{var} ")?;
747                }
748                f.write_str(") { ")?;
749                for row in bindings {
750                    f.write_str("( ")?;
751                    for val in row {
752                        match val {
753                            Some(val) => write!(f, "{val} "),
754                            None => f.write_str("UNDEF "),
755                        }?;
756                    }
757                    f.write_str(") ")?;
758                }
759                f.write_str(" }")
760            }
761            Self::Group {
762                inner,
763                variables,
764                aggregates,
765            } => {
766                f.write_str("{SELECT")?;
767                for (a, v) in aggregates {
768                    write!(f, " ({v} AS {a})")?;
769                }
770                for b in variables {
771                    write!(f, " {b}")?;
772                }
773                write!(f, " WHERE {{ {inner} }}")?;
774                if !variables.is_empty() {
775                    f.write_str(" GROUP BY")?;
776                    for v in variables {
777                        write!(f, " {v}")?;
778                    }
779                }
780                f.write_str("}")
781            }
782            p => write!(
783                f,
784                "{{ {} }}",
785                SparqlGraphRootPattern {
786                    pattern: p,
787                    dataset: None
788                }
789            ),
790        }
791    }
792}
793
794impl Default for GraphPattern {
795    fn default() -> Self {
796        Self::Bgp {
797            patterns: Vec::new(),
798        }
799    }
800}
801
802impl GraphPattern {
803    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
804    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
805        match self {
806            Self::Bgp { patterns } => {
807                f.write_str("(bgp")?;
808                for pattern in patterns {
809                    f.write_str(" ")?;
810                    pattern.fmt_sse(f)?;
811                }
812                f.write_str(")")
813            }
814            Self::Path {
815                subject,
816                path,
817                object,
818            } => {
819                f.write_str("(path ")?;
820                subject.fmt_sse(f)?;
821                f.write_str(" ")?;
822                path.fmt_sse(f)?;
823                f.write_str(" ")?;
824                object.fmt_sse(f)?;
825                f.write_str(")")
826            }
827            Self::Join { left, right } => {
828                f.write_str("(join ")?;
829                left.fmt_sse(f)?;
830                f.write_str(" ")?;
831                right.fmt_sse(f)?;
832                f.write_str(")")
833            }
834            Self::LeftJoin {
835                left,
836                right,
837                expression,
838            } => {
839                f.write_str("(leftjoin ")?;
840                left.fmt_sse(f)?;
841                f.write_str(" ")?;
842                right.fmt_sse(f)?;
843                if let Some(expr) = expression {
844                    f.write_str(" ")?;
845                    expr.fmt_sse(f)?;
846                }
847                f.write_str(")")
848            }
849            #[cfg(feature = "sep-0006")]
850            Self::Lateral { left, right } => {
851                f.write_str("(lateral ")?;
852                left.fmt_sse(f)?;
853                f.write_str(" ")?;
854                right.fmt_sse(f)?;
855                f.write_str(")")
856            }
857            Self::Filter { expr, inner } => {
858                f.write_str("(filter ")?;
859                expr.fmt_sse(f)?;
860                f.write_str(" ")?;
861                inner.fmt_sse(f)?;
862                f.write_str(")")
863            }
864            Self::Union { left, right } => {
865                f.write_str("(union ")?;
866                left.fmt_sse(f)?;
867                f.write_str(" ")?;
868                right.fmt_sse(f)?;
869                f.write_str(")")
870            }
871            Self::Graph { name, inner } => {
872                f.write_str("(graph ")?;
873                name.fmt_sse(f)?;
874                f.write_str(" ")?;
875                inner.fmt_sse(f)?;
876                f.write_str(")")
877            }
878            Self::Extend {
879                inner,
880                variable,
881                expression,
882            } => {
883                write!(f, "(extend (({variable} ")?;
884                expression.fmt_sse(f)?;
885                f.write_str(")) ")?;
886                inner.fmt_sse(f)?;
887                f.write_str(")")
888            }
889            Self::Minus { left, right } => {
890                f.write_str("(minus ")?;
891                left.fmt_sse(f)?;
892                f.write_str(" ")?;
893                right.fmt_sse(f)?;
894                f.write_str(")")
895            }
896            Self::Service {
897                name,
898                inner,
899                silent,
900            } => {
901                f.write_str("(service ")?;
902                if *silent {
903                    f.write_str("silent ")?;
904                }
905                name.fmt_sse(f)?;
906                f.write_str(" ")?;
907                inner.fmt_sse(f)?;
908                f.write_str(")")
909            }
910            Self::Group {
911                inner,
912                variables,
913                aggregates,
914            } => {
915                f.write_str("(group (")?;
916                for (i, v) in variables.iter().enumerate() {
917                    if i > 0 {
918                        f.write_str(" ")?;
919                    }
920                    write!(f, "{v}")?;
921                }
922                f.write_str(") (")?;
923                for (i, (v, a)) in aggregates.iter().enumerate() {
924                    if i > 0 {
925                        f.write_str(" ")?;
926                    }
927                    f.write_str("(")?;
928                    a.fmt_sse(f)?;
929                    write!(f, " {v})")?;
930                }
931                f.write_str(") ")?;
932                inner.fmt_sse(f)?;
933                f.write_str(")")
934            }
935            Self::Values {
936                variables,
937                bindings,
938            } => {
939                f.write_str("(table (vars")?;
940                for var in variables {
941                    write!(f, " {var}")?;
942                }
943                f.write_str(")")?;
944                for row in bindings {
945                    f.write_str(" (row")?;
946                    for (value, var) in row.iter().zip(variables) {
947                        if let Some(value) = value {
948                            write!(f, " ({var} {value})")?;
949                        }
950                    }
951                    f.write_str(")")?;
952                }
953                f.write_str(")")
954            }
955            Self::OrderBy { inner, expression } => {
956                f.write_str("(order (")?;
957                for (i, c) in expression.iter().enumerate() {
958                    if i > 0 {
959                        f.write_str(" ")?;
960                    }
961                    c.fmt_sse(f)?;
962                }
963                f.write_str(") ")?;
964                inner.fmt_sse(f)?;
965                f.write_str(")")
966            }
967            Self::Project { inner, variables } => {
968                f.write_str("(project (")?;
969                for (i, v) in variables.iter().enumerate() {
970                    if i > 0 {
971                        f.write_str(" ")?;
972                    }
973                    write!(f, "{v}")?;
974                }
975                f.write_str(") ")?;
976                inner.fmt_sse(f)?;
977                f.write_str(")")
978            }
979            Self::Distinct { inner } => {
980                f.write_str("(distinct ")?;
981                inner.fmt_sse(f)?;
982                f.write_str(")")
983            }
984            Self::Reduced { inner } => {
985                f.write_str("(reduced ")?;
986                inner.fmt_sse(f)?;
987                f.write_str(")")
988            }
989            Self::Slice {
990                inner,
991                start,
992                length,
993            } => {
994                if let Some(length) = length {
995                    write!(f, "(slice {start} {length} ")?;
996                } else {
997                    write!(f, "(slice {start} _ ")?;
998                }
999                inner.fmt_sse(f)?;
1000                f.write_str(")")
1001            }
1002        }
1003    }
1004
1005    /// Calls `callback` on each [in-scope variable](https://www.w3.org/TR/sparql11-query/#variableScope) occurrence.
1006    pub fn on_in_scope_variable<'a>(&'a self, mut callback: impl FnMut(&'a Variable)) {
1007        self.lookup_in_scope_variables(&mut callback)
1008    }
1009
1010    fn lookup_in_scope_variables<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
1011        match self {
1012            Self::Bgp { patterns } => {
1013                for pattern in patterns {
1014                    lookup_triple_pattern_variables(pattern, callback)
1015                }
1016            }
1017            Self::Path {
1018                subject, object, ..
1019            } => {
1020                if let TermPattern::Variable(s) = subject {
1021                    callback(s);
1022                }
1023                #[cfg(feature = "sparql-12")]
1024                if let TermPattern::Triple(s) = subject {
1025                    lookup_triple_pattern_variables(s, callback)
1026                }
1027                if let TermPattern::Variable(o) = object {
1028                    callback(o);
1029                }
1030                #[cfg(feature = "sparql-12")]
1031                if let TermPattern::Triple(o) = object {
1032                    lookup_triple_pattern_variables(o, callback)
1033                }
1034            }
1035            Self::Join { left, right }
1036            | Self::LeftJoin { left, right, .. }
1037            | Self::Union { left, right } => {
1038                left.lookup_in_scope_variables(callback);
1039                right.lookup_in_scope_variables(callback);
1040            }
1041            #[cfg(feature = "sep-0006")]
1042            Self::Lateral { left, right } => {
1043                left.lookup_in_scope_variables(callback);
1044                right.lookup_in_scope_variables(callback);
1045            }
1046            Self::Graph { name, inner } => {
1047                if let NamedNodePattern::Variable(g) = &name {
1048                    callback(g);
1049                }
1050                inner.lookup_in_scope_variables(callback);
1051            }
1052            Self::Extend {
1053                inner, variable, ..
1054            } => {
1055                callback(variable);
1056                inner.lookup_in_scope_variables(callback);
1057            }
1058            Self::Minus { left, .. } => left.lookup_in_scope_variables(callback),
1059            Self::Group {
1060                variables,
1061                aggregates,
1062                ..
1063            } => {
1064                for v in variables {
1065                    callback(v);
1066                }
1067                for (v, _) in aggregates {
1068                    callback(v);
1069                }
1070            }
1071            Self::Values { variables, .. } | Self::Project { variables, .. } => {
1072                for v in variables {
1073                    callback(v);
1074                }
1075            }
1076            Self::Service { inner, .. }
1077            | Self::Filter { inner, .. }
1078            | Self::OrderBy { inner, .. }
1079            | Self::Distinct { inner }
1080            | Self::Reduced { inner }
1081            | Self::Slice { inner, .. } => inner.lookup_in_scope_variables(callback),
1082        }
1083    }
1084
1085    fn lookup_used_variables<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
1086        match self {
1087            Self::Bgp { patterns } => {
1088                for pattern in patterns {
1089                    lookup_triple_pattern_variables(pattern, callback)
1090                }
1091            }
1092            Self::Path {
1093                subject, object, ..
1094            } => {
1095                if let TermPattern::Variable(s) = subject {
1096                    callback(s);
1097                }
1098                #[cfg(feature = "sparql-12")]
1099                if let TermPattern::Triple(s) = subject {
1100                    lookup_triple_pattern_variables(s, callback)
1101                }
1102                if let TermPattern::Variable(o) = object {
1103                    callback(o);
1104                }
1105                #[cfg(feature = "sparql-12")]
1106                if let TermPattern::Triple(o) = object {
1107                    lookup_triple_pattern_variables(o, callback)
1108                }
1109            }
1110            Self::Join { left, right }
1111            | Self::Minus { left, right }
1112            | Self::Union { left, right } => {
1113                left.lookup_used_variables(callback);
1114                right.lookup_used_variables(callback);
1115            }
1116            Self::LeftJoin {
1117                left,
1118                right,
1119                expression,
1120            } => {
1121                left.lookup_used_variables(callback);
1122                right.lookup_used_variables(callback);
1123                if let Some(expr) = expression {
1124                    expr.lookup_used_variable(callback);
1125                }
1126            }
1127            #[cfg(feature = "sep-0006")]
1128            Self::Lateral { left, right } => {
1129                left.lookup_used_variables(callback);
1130                right.lookup_used_variables(callback);
1131            }
1132            Self::Graph { name, inner } => {
1133                if let NamedNodePattern::Variable(g) = &name {
1134                    callback(g);
1135                }
1136                inner.lookup_used_variables(callback);
1137            }
1138            Self::Extend {
1139                inner,
1140                variable,
1141                expression,
1142            } => {
1143                callback(variable);
1144                expression.lookup_used_variable(callback);
1145                inner.lookup_used_variables(callback);
1146            }
1147            Self::Group {
1148                inner,
1149                variables,
1150                aggregates,
1151            } => {
1152                inner.lookup_used_variables(callback);
1153                for v in variables {
1154                    callback(v);
1155                }
1156                for (v, expr) in aggregates {
1157                    callback(v);
1158                    expr.lookup_used_variables(callback);
1159                }
1160            }
1161            Self::Values { variables, .. } | Self::Project { variables, .. } => {
1162                for v in variables {
1163                    callback(v);
1164                }
1165            }
1166            Self::Filter { inner, expr } => {
1167                expr.lookup_used_variable(callback);
1168                inner.lookup_used_variables(callback);
1169            }
1170            Self::Service { inner, name, .. } => {
1171                if let NamedNodePattern::Variable(s) = &name {
1172                    callback(s);
1173                }
1174                inner.lookup_used_variables(callback);
1175            }
1176            Self::OrderBy { inner, expression } => {
1177                for e in expression {
1178                    e.lookup_used_variables(callback);
1179                }
1180                inner.lookup_used_variables(callback);
1181            }
1182            Self::Distinct { inner } | Self::Reduced { inner } | Self::Slice { inner, .. } => {
1183                inner.lookup_used_variables(callback)
1184            }
1185        }
1186    }
1187}
1188
1189fn lookup_triple_pattern_variables<'a>(
1190    pattern: &'a TriplePattern,
1191    callback: &mut impl FnMut(&'a Variable),
1192) {
1193    if let TermPattern::Variable(s) = &pattern.subject {
1194        callback(s);
1195    }
1196    #[cfg(feature = "sparql-12")]
1197    if let TermPattern::Triple(s) = &pattern.subject {
1198        lookup_triple_pattern_variables(s, callback)
1199    }
1200    if let NamedNodePattern::Variable(p) = &pattern.predicate {
1201        callback(p);
1202    }
1203    if let TermPattern::Variable(o) = &pattern.object {
1204        callback(o);
1205    }
1206    #[cfg(feature = "sparql-12")]
1207    if let TermPattern::Triple(o) = &pattern.object {
1208        lookup_triple_pattern_variables(o, callback)
1209    }
1210}
1211
1212pub(crate) struct SparqlGraphRootPattern<'a> {
1213    pattern: &'a GraphPattern,
1214    dataset: Option<&'a QueryDataset>,
1215}
1216
1217impl<'a> SparqlGraphRootPattern<'a> {
1218    pub fn new(pattern: &'a GraphPattern, dataset: Option<&'a QueryDataset>) -> Self {
1219        Self { pattern, dataset }
1220    }
1221}
1222
1223impl fmt::Display for SparqlGraphRootPattern<'_> {
1224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1225        let mut distinct = false;
1226        let mut reduced = false;
1227        let mut order = None;
1228        let mut start = 0;
1229        let mut length = None;
1230        let mut project = Vec::new();
1231
1232        let mut child = self.pattern;
1233        loop {
1234            match child {
1235                GraphPattern::OrderBy { inner, expression } => {
1236                    order = Some(expression);
1237                    child = inner;
1238                }
1239                GraphPattern::Project { inner, variables } if project.is_empty() => {
1240                    project.extend(variables.iter().map(|v| (v, None)));
1241                    child = inner;
1242                }
1243                GraphPattern::Distinct { inner } => {
1244                    distinct = true;
1245                    child = inner;
1246                }
1247                GraphPattern::Reduced { inner } => {
1248                    reduced = true;
1249                    child = inner;
1250                }
1251                GraphPattern::Slice {
1252                    inner,
1253                    start: s,
1254                    length: l,
1255                } => {
1256                    start = *s;
1257                    length = *l;
1258                    child = inner;
1259                }
1260                GraphPattern::Extend {
1261                    inner,
1262                    expression,
1263                    variable,
1264                } if project.iter().any(|(v, _)| *v == variable)
1265                    && !project.iter().any(|(_, expr)| {
1266                        expr.is_some_and(|expr: &Expression| {
1267                            let mut found = false;
1268                            expr.lookup_used_variable(&mut |v| found |= v == variable);
1269                            found
1270                        })
1271                    }) =>
1272                {
1273                    // This simplification only works if the extended variable is in the projection and not used in another expression of the projection.
1274                    project
1275                        .iter_mut()
1276                        .find(|(v, _)| *v == variable)
1277                        .ok_or(fmt::Error)?
1278                        .1 = Some(expression);
1279                    child = inner
1280                }
1281                p => {
1282                    f.write_str("SELECT")?;
1283                    if distinct {
1284                        f.write_str(" DISTINCT")?;
1285                    }
1286                    if reduced {
1287                        f.write_str(" REDUCED")?;
1288                    }
1289                    if project.is_empty() {
1290                        f.write_str(" *")?;
1291                    } else {
1292                        for (variable, expr) in project {
1293                            if let Some(expr) = expr {
1294                                write!(f, " ({expr} AS {variable})")
1295                            } else {
1296                                write!(f, " {variable}")
1297                            }?;
1298                        }
1299                    }
1300                    if let Some(dataset) = self.dataset {
1301                        write!(f, " {dataset}")?;
1302                    }
1303                    write!(f, " WHERE {{ {p} }}")?;
1304                    if let Some(order) = order {
1305                        f.write_str(" ORDER BY")?;
1306                        for c in order {
1307                            write!(f, " {c}")?;
1308                        }
1309                    }
1310                    if start > 0 {
1311                        write!(f, " OFFSET {start}")?;
1312                    }
1313                    if let Some(length) = length {
1314                        write!(f, " LIMIT {length}")?;
1315                    }
1316                    return Ok(());
1317                }
1318            }
1319        }
1320    }
1321}
1322
1323/// A set function used in aggregates (c.f. [`GraphPattern::Group`]).
1324#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1325pub enum AggregateExpression {
1326    /// [Count](https://www.w3.org/TR/sparql11-query/#defn_aggCount) with *.
1327    CountSolutions { distinct: bool },
1328    FunctionCall {
1329        name: AggregateFunction,
1330        expr: Expression,
1331        distinct: bool,
1332    },
1333}
1334
1335impl AggregateExpression {
1336    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1337    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1338        match self {
1339            Self::CountSolutions { distinct } => {
1340                f.write_str("(count")?;
1341                if *distinct {
1342                    f.write_str(" distinct")?;
1343                }
1344                f.write_str(")")
1345            }
1346            Self::FunctionCall {
1347                name:
1348                    AggregateFunction::GroupConcat {
1349                        separator: Some(separator),
1350                    },
1351                expr,
1352                distinct,
1353            } => {
1354                f.write_str("(group_concat ")?;
1355                if *distinct {
1356                    f.write_str("distinct ")?;
1357                }
1358                expr.fmt_sse(f)?;
1359                write!(f, " {})", LiteralRef::new_simple_literal(separator))
1360            }
1361            Self::FunctionCall {
1362                name,
1363                expr,
1364                distinct,
1365            } => {
1366                f.write_str("(")?;
1367                name.fmt_sse(f)?;
1368                f.write_str(" ")?;
1369                if *distinct {
1370                    f.write_str("distinct ")?;
1371                }
1372                expr.fmt_sse(f)?;
1373                f.write_str(")")
1374            }
1375        }
1376    }
1377
1378    fn lookup_used_variables<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
1379        if let Self::FunctionCall { expr, .. } = self {
1380            expr.lookup_used_variable(callback);
1381        }
1382    }
1383}
1384
1385impl fmt::Display for AggregateExpression {
1386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1387        match self {
1388            Self::CountSolutions { distinct } => {
1389                if *distinct {
1390                    f.write_str("COUNT(DISTINCT *)")
1391                } else {
1392                    f.write_str("COUNT(*)")
1393                }
1394            }
1395            Self::FunctionCall {
1396                name:
1397                    AggregateFunction::GroupConcat {
1398                        separator: Some(separator),
1399                    },
1400                expr,
1401                distinct,
1402            } => {
1403                if *distinct {
1404                    write!(
1405                        f,
1406                        "GROUP_CONCAT(DISTINCT {}; SEPARATOR = {})",
1407                        expr,
1408                        LiteralRef::new_simple_literal(separator)
1409                    )
1410                } else {
1411                    write!(
1412                        f,
1413                        "GROUP_CONCAT({}; SEPARATOR = {})",
1414                        expr,
1415                        LiteralRef::new_simple_literal(separator)
1416                    )
1417                }
1418            }
1419            Self::FunctionCall {
1420                name,
1421                expr,
1422                distinct,
1423            } => {
1424                if *distinct {
1425                    write!(f, "{name}(DISTINCT {expr})")
1426                } else {
1427                    write!(f, "{name}({expr})")
1428                }
1429            }
1430        }
1431    }
1432}
1433
1434/// An aggregate function name.
1435#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1436pub enum AggregateFunction {
1437    /// [Count](https://www.w3.org/TR/sparql11-query/#defn_aggCount) with *.
1438    Count,
1439    /// [Sum](https://www.w3.org/TR/sparql11-query/#defn_aggSum).
1440    Sum,
1441    /// [Avg](https://www.w3.org/TR/sparql11-query/#defn_aggAvg).
1442    Avg,
1443    /// [Min](https://www.w3.org/TR/sparql11-query/#defn_aggMin).
1444    Min,
1445    /// [Max](https://www.w3.org/TR/sparql11-query/#defn_aggMax).
1446    Max,
1447    /// [GroupConcat](https://www.w3.org/TR/sparql11-query/#defn_aggGroupConcat).
1448    GroupConcat {
1449        separator: Option<String>,
1450    },
1451    /// [Sample](https://www.w3.org/TR/sparql11-query/#defn_aggSample).
1452    Sample,
1453    Custom(NamedNode),
1454}
1455
1456impl AggregateFunction {
1457    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1458    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1459        match self {
1460            Self::Count => f.write_str("count"),
1461            Self::Sum => f.write_str("sum"),
1462            Self::Avg => f.write_str("avg"),
1463            Self::Min => f.write_str("min"),
1464            Self::Max => f.write_str("max"),
1465            Self::GroupConcat { .. } => f.write_str("group_concat"),
1466            Self::Sample => f.write_str("sample"),
1467            Self::Custom(iri) => write!(f, "{iri}"),
1468        }
1469    }
1470}
1471
1472impl fmt::Display for AggregateFunction {
1473    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1474        match self {
1475            Self::Count => f.write_str("COUNT"),
1476            Self::Sum => f.write_str("SUM"),
1477            Self::Avg => f.write_str("AVG"),
1478            Self::Min => f.write_str("MIN"),
1479            Self::Max => f.write_str("MAX"),
1480            Self::GroupConcat { .. } => f.write_str("GROUP_CONCAT"),
1481            Self::Sample => f.write_str("SAMPLE"),
1482            Self::Custom(iri) => iri.fmt(f),
1483        }
1484    }
1485}
1486
1487/// An ordering comparator used by [`GraphPattern::OrderBy`].
1488#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1489pub enum OrderExpression {
1490    /// Ascending order
1491    Asc(Expression),
1492    /// Descending order
1493    Desc(Expression),
1494}
1495
1496impl OrderExpression {
1497    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1498    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1499        match self {
1500            Self::Asc(e) => {
1501                f.write_str("(asc ")?;
1502                e.fmt_sse(f)?;
1503                f.write_str(")")
1504            }
1505            Self::Desc(e) => {
1506                f.write_str("(desc ")?;
1507                e.fmt_sse(f)?;
1508                f.write_str(")")
1509            }
1510        }
1511    }
1512
1513    fn lookup_used_variables<'a>(&'a self, callback: &mut impl FnMut(&'a Variable)) {
1514        let (Self::Asc(e) | Self::Desc(e)) = self;
1515        e.lookup_used_variable(callback);
1516    }
1517}
1518
1519impl fmt::Display for OrderExpression {
1520    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1521        match self {
1522            Self::Asc(e) => write!(f, "ASC({e})"),
1523            Self::Desc(e) => write!(f, "DESC({e})"),
1524        }
1525    }
1526}
1527
1528/// A SPARQL query [dataset specification](https://www.w3.org/TR/sparql11-query/#specifyingDataset).
1529#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1530pub struct QueryDataset {
1531    pub default: Vec<NamedNode>,
1532    pub named: Option<Vec<NamedNode>>,
1533}
1534
1535impl QueryDataset {
1536    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1537    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1538        f.write_str("(")?;
1539        for (i, graph_name) in self.default.iter().enumerate() {
1540            if i > 0 {
1541                f.write_str(" ")?;
1542            }
1543            write!(f, "{graph_name}")?;
1544        }
1545        if let Some(named) = &self.named {
1546            for (i, graph_name) in named.iter().enumerate() {
1547                if !self.default.is_empty() || i > 0 {
1548                    f.write_str(" ")?;
1549                }
1550                write!(f, "(named {graph_name})")?;
1551            }
1552        }
1553        f.write_str(")")
1554    }
1555}
1556
1557impl fmt::Display for QueryDataset {
1558    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1559        for g in &self.default {
1560            write!(f, " FROM {g}")?;
1561        }
1562        if let Some(named) = &self.named {
1563            for g in named {
1564                write!(f, " FROM NAMED {g}")?;
1565            }
1566        }
1567        Ok(())
1568    }
1569}
1570
1571/// A target RDF graph for update operations.
1572///
1573/// Could be a specific graph, all named graphs or the complete dataset.
1574#[derive(Eq, PartialEq, Debug, Clone, Hash)]
1575pub enum GraphTarget {
1576    NamedNode(NamedNode),
1577    DefaultGraph,
1578    NamedGraphs,
1579    AllGraphs,
1580}
1581
1582impl GraphTarget {
1583    /// Formats using the [SPARQL S-Expression syntax](https://jena.apache.org/documentation/notes/sse.html).
1584    pub(crate) fn fmt_sse(&self, f: &mut impl fmt::Write) -> fmt::Result {
1585        match self {
1586            Self::NamedNode(node) => write!(f, "{node}"),
1587            Self::DefaultGraph => f.write_str("default"),
1588            Self::NamedGraphs => f.write_str("named"),
1589            Self::AllGraphs => f.write_str("all"),
1590        }
1591    }
1592}
1593
1594impl fmt::Display for GraphTarget {
1595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1596        match self {
1597            Self::NamedNode(node) => write!(f, "GRAPH {node}"),
1598            Self::DefaultGraph => f.write_str("DEFAULT"),
1599            Self::NamedGraphs => f.write_str("NAMED"),
1600            Self::AllGraphs => f.write_str("ALL"),
1601        }
1602    }
1603}
1604
1605impl From<NamedNode> for GraphTarget {
1606    fn from(node: NamedNode) -> Self {
1607        Self::NamedNode(node)
1608    }
1609}
1610
1611impl From<GraphName> for GraphTarget {
1612    fn from(graph_name: GraphName) -> Self {
1613        match graph_name {
1614            GraphName::NamedNode(node) => Self::NamedNode(node),
1615            GraphName::DefaultGraph => Self::DefaultGraph,
1616        }
1617    }
1618}
1619
1620#[inline]
1621fn fmt_sse_unary_expression(f: &mut impl fmt::Write, name: &str, e: &Expression) -> fmt::Result {
1622    write!(f, "({name} ")?;
1623    e.fmt_sse(f)?;
1624    f.write_str(")")
1625}
1626
1627#[inline]
1628fn fmt_sse_binary_expression(
1629    f: &mut impl fmt::Write,
1630    name: &str,
1631    a: &Expression,
1632    b: &Expression,
1633) -> fmt::Result {
1634    write!(f, "({name} ")?;
1635    a.fmt_sse(f)?;
1636    f.write_str(" ")?;
1637    b.fmt_sse(f)?;
1638    f.write_str(")")
1639}