Skip to main content

oxirs_core/query/
sparql_algebra.rs

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