1use crate::model::*;
8use std::fmt;
9
10#[derive(Eq, PartialEq, Debug, Clone, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub enum PropertyPathExpression {
14 NamedNode(NamedNode),
16 Reverse(Box<Self>),
18 Sequence(Box<Self>, Box<Self>),
20 Alternative(Box<Self>, Box<Self>),
22 ZeroOrMore(Box<Self>),
24 OneOrMore(Box<Self>),
26 ZeroOrOne(Box<Self>),
28 NegatedPropertySet(Vec<NamedNode>),
30}
31
32impl PropertyPathExpression {
33 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#[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 Or(Box<Self>, Box<Self>),
121 And(Box<Self>, Box<Self>),
123 Equal(Box<Self>, Box<Self>),
125 SameTerm(Box<Self>, Box<Self>),
127 Greater(Box<Self>, Box<Self>),
129 GreaterOrEqual(Box<Self>, Box<Self>),
130 Less(Box<Self>, Box<Self>),
132 LessOrEqual(Box<Self>, Box<Self>),
133 In(Box<Self>, Vec<Self>),
135 Add(Box<Self>, Box<Self>),
137 Subtract(Box<Self>, Box<Self>),
139 Multiply(Box<Self>, Box<Self>),
141 Divide(Box<Self>, Box<Self>),
143 UnaryPlus(Box<Self>),
145 UnaryMinus(Box<Self>),
147 Not(Box<Self>),
149 Exists(Box<GraphPattern>),
151 Bound(Variable),
153 If(Box<Self>, Box<Self>, Box<Self>),
155 Coalesce(Vec<Self>),
157 FunctionCall(FunctionExpression, Vec<Self>),
159}
160
161impl Expression {
162 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#[derive(Eq, PartialEq, Debug, Clone, Hash)]
292#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
293pub enum FunctionExpression {
294 BuiltIn(BuiltInFunction),
296 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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
321pub enum BuiltInFunction {
322 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 Abs,
348 Round,
349 Ceil,
350 Floor,
351 Rand,
352
353 Now,
355 Year,
356 Month,
357 Day,
358 Hours,
359 Minutes,
360 Seconds,
361 Timezone,
362 Tz,
363
364 Md5,
366 Sha1,
367 Sha256,
368 Sha384,
369 Sha512,
370
371 IsIri,
373 IsUri,
374 IsBlank,
375 IsLiteral,
376 IsNumeric,
377
378 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#[derive(Eq, PartialEq, Debug, Clone, Hash)]
495#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
496pub enum GraphPattern {
497 Bgp { patterns: Vec<TriplePattern> },
499 Path {
501 subject: TermPattern,
502 path: PropertyPathExpression,
503 object: TermPattern,
504 },
505 Join { left: Box<Self>, right: Box<Self> },
507 LeftJoin {
509 left: Box<Self>,
510 right: Box<Self>,
511 expression: Option<Expression>,
512 },
513 Filter { expr: Expression, inner: Box<Self> },
515 Union { left: Box<Self>, right: Box<Self> },
517 Graph {
519 name: NamedNodePattern,
520 inner: Box<Self>,
521 },
522 Extend {
524 inner: Box<Self>,
525 variable: Variable,
526 expression: Expression,
527 },
528 Minus { left: Box<Self>, right: Box<Self> },
530 Values {
532 variables: Vec<Variable>,
533 bindings: Vec<Vec<Option<GroundTerm>>>,
534 },
535 OrderBy {
537 inner: Box<Self>,
538 expression: Vec<OrderExpression>,
539 },
540 Project {
542 inner: Box<Self>,
543 variables: Vec<Variable>,
544 },
545 Distinct { inner: Box<Self> },
547 Reduced { inner: Box<Self> },
549 Slice {
551 inner: Box<Self>,
552 start: usize,
553 length: Option<usize>,
554 },
555 Group {
557 inner: Box<Self>,
558 variables: Vec<Variable>,
559 aggregates: Vec<(Variable, AggregateExpression)>,
560 },
561 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 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#[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(()), Term::Literal(t) => Ok(t.into()),
1010 Term::Variable(_) => Err(()), Term::QuotedTriple(_) => Err(()), }
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 use crate::model::star::QuotedTriple;
1027 use crate::model::Triple as ModelTriple;
1028
1029 let subject: crate::model::Subject = match t.subject {
1031 GroundSubject::NamedNode(n) => n.into(),
1032 GroundSubject::Triple(_) => {
1033 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 let object: crate::model::Object = match t.object {
1045 GroundTerm::NamedNode(n) => n.into(),
1046 GroundTerm::Literal(l) => l.into(),
1047 GroundTerm::Triple(_) => {
1048 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#[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#[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#[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#[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#[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#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1267#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1268pub enum OrderExpression {
1269 Asc(Expression),
1271 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#[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
1528fn 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}