1#[cfg(feature = "sparql-12")]
2use oxrdf::BaseDirection;
3use oxrdf::{
4 BlankNode, Dataset, GraphNameRef, Literal, NamedNode, NamedOrBlankNodeRef, QuadRef, Term,
5 TermRef,
6};
7#[cfg(feature = "sparql-12")]
8use oxrdf::{NamedOrBlankNode, Triple};
9use oxsdatatypes::{Boolean, DateTime, Decimal, Double, Float, Integer};
10#[cfg(feature = "sep-0002")]
11use oxsdatatypes::{Date, DayTimeDuration, Duration, Time, YearMonthDuration};
12#[cfg(feature = "calendar-ext")]
13use oxsdatatypes::{GDay, GMonth, GMonthDay, GYear, GYearMonth};
14use rustc_hash::FxHashSet;
15use std::convert::Infallible;
16use std::error::Error;
17use std::hash::{Hash, Hasher};
18use std::iter::empty;
19use std::mem::discriminant;
20
21pub trait QueryableDataset<'a>: Sized + 'a {
23 type InternalTerm: Clone + Eq + Hash + 'a;
29
30 type Error: Error + Send + Sync + 'static;
32
33 fn internal_quads_for_pattern(
37 &self,
38 subject: Option<&Self::InternalTerm>,
39 predicate: Option<&Self::InternalTerm>,
40 object: Option<&Self::InternalTerm>,
41 graph_name: Option<Option<&Self::InternalTerm>>,
42 ) -> impl Iterator<Item = Result<InternalQuad<Self::InternalTerm>, Self::Error>> + use<'a, Self>;
43
44 fn internal_named_graphs(
46 &self,
47 ) -> impl Iterator<Item = Result<Self::InternalTerm, Self::Error>> + use<'a, Self> {
48 let mut error = None;
49 let graph_names = self
50 .internal_quads_for_pattern(None, None, None, None)
51 .filter_map(|r| match r {
52 Ok(r) => Some(r.graph_name?),
53 Err(e) => {
54 error = Some(e);
55 None
56 }
57 })
58 .collect::<FxHashSet<_>>();
59
60 Box::new(
61 error
62 .map(Err)
63 .into_iter()
64 .chain(graph_names.into_iter().map(Ok)),
65 )
66 }
67
68 fn contains_internal_graph_name(
70 &self,
71 graph_name: &Self::InternalTerm,
72 ) -> Result<bool, Self::Error> {
73 Ok(self
74 .internal_quads_for_pattern(None, None, None, Some(Some(graph_name)))
75 .next()
76 .transpose()?
77 .is_some())
78 }
79
80 fn internalize_term(&self, term: Term) -> Result<Self::InternalTerm, Self::Error>;
82
83 fn externalize_term(&self, term: Self::InternalTerm) -> Result<Term, Self::Error>;
85
86 fn externalize_expression_term(
90 &self,
91 term: Self::InternalTerm,
92 ) -> Result<ExpressionTerm, Self::Error> {
93 Ok(self.externalize_term(term)?.into())
94 }
95
96 fn internalize_expression_term(
98 &self,
99 term: ExpressionTerm,
100 ) -> Result<Self::InternalTerm, Self::Error> {
101 self.internalize_term(term.into())
102 }
103
104 fn internal_term_effective_boolean_value(
106 &self,
107 term: Self::InternalTerm,
108 ) -> Result<Option<bool>, Self::Error> {
109 Ok(self
110 .externalize_expression_term(term)?
111 .effective_boolean_value())
112 }
113}
114
115impl<'a> QueryableDataset<'a> for &'a Dataset {
116 type InternalTerm = TermCow<'a>;
117 type Error = Infallible;
118
119 fn internal_quads_for_pattern(
120 &self,
121 subject: Option<&TermCow<'a>>,
122 predicate: Option<&TermCow<'a>>,
123 object: Option<&TermCow<'a>>,
124 graph_name: Option<Option<&TermCow<'a>>>,
125 ) -> impl Iterator<Item = Result<InternalQuad<TermCow<'a>>, Infallible>> + use<'a> {
126 #[expect(clippy::unnecessary_wraps)]
127 fn quad_to_result(quad: QuadRef<'_>) -> Result<InternalQuad<TermCow<'_>>, Infallible> {
128 Ok(InternalQuad {
129 subject: TermRef::from(quad.subject).into(),
130 predicate: TermRef::from(quad.predicate).into(),
131 object: quad.object.into(),
132 graph_name: match quad.graph_name {
133 GraphNameRef::NamedNode(g) => Some(TermRef::from(g).into()),
134 GraphNameRef::BlankNode(g) => Some(TermRef::from(g).into()),
135 GraphNameRef::DefaultGraph => None,
136 },
137 })
138 }
139
140 let graph_name = if let Some(graph_name) = graph_name {
141 Some(if let Some(graph_name) = graph_name {
142 match graph_name.into() {
143 TermRef::NamedNode(s) => s.into(),
144 TermRef::BlankNode(s) => s.into(),
145 TermRef::Literal(_) => {
146 let empty: Box<dyn Iterator<Item = Result<_, _>>> = Box::new(empty());
147 return empty;
148 }
149 #[cfg(feature = "sparql-12")]
150 TermRef::Triple(_) => return Box::new(empty()),
151 }
152 } else {
153 GraphNameRef::DefaultGraph
154 })
155 } else {
156 None
157 };
158 if let Some(subject) = subject {
159 let subject = match subject.into() {
160 TermRef::NamedNode(s) => NamedOrBlankNodeRef::from(s),
161 TermRef::BlankNode(s) => s.into(),
162 TermRef::Literal(_) => {
163 return Box::new(empty());
164 }
165 #[cfg(feature = "sparql-12")]
166 TermRef::Triple(_) => return Box::new(empty()),
167 };
168 let predicate = predicate.cloned();
169 let object = object.cloned();
170 let graph_name = graph_name.map(GraphNameRef::into_owned);
171 Box::new(
172 self.quads_for_subject(subject)
173 .filter(move |q| {
174 predicate
175 .as_ref()
176 .is_none_or(|t| TermRef::from(t) == q.predicate.into())
177 && object.as_ref().is_none_or(|t| TermRef::from(t) == q.object)
178 && graph_name.as_ref().map_or_else(
179 || !q.graph_name.is_default_graph(),
180 |t| t.as_ref() == q.graph_name,
181 )
182 })
183 .map(quad_to_result),
184 )
185 } else if let Some(object) = object {
186 let predicate = predicate.cloned();
187 let graph_name = graph_name.map(GraphNameRef::into_owned);
188 Box::new(
189 self.quads_for_object(object)
190 .filter(move |q| {
191 predicate
192 .as_ref()
193 .is_none_or(|t| TermRef::from(t) == q.predicate.into())
194 && graph_name.as_ref().map_or_else(
195 || !q.graph_name.is_default_graph(),
196 |t| t.as_ref() == q.graph_name,
197 )
198 })
199 .map(quad_to_result),
200 )
201 } else if let Some(predicate) = predicate {
202 let TermRef::NamedNode(predicate) = predicate.into() else {
203 return Box::new(empty());
204 };
205 let graph_name = graph_name.map(GraphNameRef::into_owned);
206 Box::new(
207 self.quads_for_predicate(predicate)
208 .filter(move |q| {
209 graph_name.as_ref().map_or_else(
210 || !q.graph_name.is_default_graph(),
211 |t| t.as_ref() == q.graph_name,
212 )
213 })
214 .map(quad_to_result),
215 )
216 } else if let Some(graph_name) = graph_name {
217 Box::new(self.quads_for_graph_name(graph_name).map(quad_to_result))
218 } else {
219 Box::new(
220 self.iter()
221 .filter(|q| !q.graph_name.is_default_graph())
222 .map(quad_to_result),
223 )
224 }
225 }
226
227 fn internalize_term(&self, term: Term) -> Result<TermCow<'a>, Infallible> {
228 Ok(term.into())
229 }
230
231 fn externalize_term(&self, term: TermCow<'a>) -> Result<Term, Infallible> {
232 Ok(term.into())
233 }
234}
235
236pub struct InternalQuad<T> {
237 pub subject: T,
238 pub predicate: T,
239 pub object: T,
240 pub graph_name: Option<T>,
242}
243
244#[derive(Clone)]
246pub enum ExpressionTerm {
247 NamedNode(NamedNode),
248 BlankNode(BlankNode),
249 StringLiteral(String),
250 LangStringLiteral {
251 value: String,
252 language: String,
253 },
254 #[cfg(feature = "sparql-12")]
255 DirLangStringLiteral {
256 value: String,
257 language: String,
258 direction: BaseDirection,
259 },
260 BooleanLiteral(Boolean),
261 IntegerLiteral(Integer),
262 DecimalLiteral(Decimal),
263 FloatLiteral(Float),
264 DoubleLiteral(Double),
265 DateTimeLiteral(DateTime),
266 #[cfg(feature = "sep-0002")]
267 DateLiteral(Date),
268 #[cfg(feature = "sep-0002")]
269 TimeLiteral(Time),
270 #[cfg(feature = "calendar-ext")]
271 GYearLiteral(GYear),
272 #[cfg(feature = "calendar-ext")]
273 GYearMonthLiteral(GYearMonth),
274 #[cfg(feature = "calendar-ext")]
275 GMonthLiteral(GMonth),
276 #[cfg(feature = "calendar-ext")]
277 GMonthDayLiteral(GMonthDay),
278 #[cfg(feature = "calendar-ext")]
279 GDayLiteral(GDay),
280 #[cfg(feature = "sep-0002")]
281 DurationLiteral(Duration),
282 #[cfg(feature = "sep-0002")]
283 YearMonthDurationLiteral(YearMonthDuration),
284 #[cfg(feature = "sep-0002")]
285 DayTimeDurationLiteral(DayTimeDuration),
286 OtherTypedLiteral {
287 value: String,
288 datatype: NamedNode,
289 },
290 #[cfg(feature = "sparql-12")]
291 Triple(Box<ExpressionTriple>),
292}
293
294impl PartialEq for ExpressionTerm {
295 #[inline]
296 fn eq(&self, other: &Self) -> bool {
297 discriminant(self) == discriminant(other)
298 && match (self, other) {
299 (Self::NamedNode(l), Self::NamedNode(r)) => l == r,
300 (Self::BlankNode(l), Self::BlankNode(r)) => l == r,
301 (Self::StringLiteral(l), Self::StringLiteral(r)) => l == r,
302 (
303 Self::LangStringLiteral {
304 value: lv,
305 language: ll,
306 },
307 Self::LangStringLiteral {
308 value: rv,
309 language: rl,
310 },
311 ) => lv == rv && ll == rl,
312 (Self::BooleanLiteral(l), Self::BooleanLiteral(r)) => l == r,
313 (Self::IntegerLiteral(l), Self::IntegerLiteral(r)) => l == r,
314 (Self::DecimalLiteral(l), Self::DecimalLiteral(r)) => l == r,
315 (Self::FloatLiteral(l), Self::FloatLiteral(r)) => l.is_identical_with(*r),
316 (Self::DoubleLiteral(l), Self::DoubleLiteral(r)) => l.is_identical_with(*r),
317 (Self::DateTimeLiteral(l), Self::DateTimeLiteral(r)) => l == r,
318 #[cfg(feature = "sep-0002")]
319 (Self::DateLiteral(l), Self::DateLiteral(r)) => l == r,
320 #[cfg(feature = "sep-0002")]
321 (Self::TimeLiteral(l), Self::TimeLiteral(r)) => l == r,
322 #[cfg(feature = "calendar-ext")]
323 (Self::GYearMonthLiteral(l), Self::GYearMonthLiteral(r)) => l == r,
324 #[cfg(feature = "calendar-ext")]
325 (Self::GYearLiteral(l), Self::GYearLiteral(r)) => l == r,
326 #[cfg(feature = "calendar-ext")]
327 (Self::GMonthLiteral(l), Self::GMonthLiteral(r)) => l == r,
328 #[cfg(feature = "calendar-ext")]
329 (Self::GMonthDayLiteral(l), Self::GMonthDayLiteral(r)) => l == r,
330 #[cfg(feature = "calendar-ext")]
331 (Self::GDayLiteral(l), Self::GDayLiteral(r)) => l == r,
332 #[cfg(feature = "sep-0002")]
333 (Self::DurationLiteral(l), Self::DurationLiteral(r)) => l == r,
334 #[cfg(feature = "sep-0002")]
335 (Self::YearMonthDurationLiteral(l), Self::YearMonthDurationLiteral(r)) => l == r,
336 #[cfg(feature = "sep-0002")]
337 (Self::DayTimeDurationLiteral(l), Self::DayTimeDurationLiteral(r)) => l == r,
338 (
339 Self::OtherTypedLiteral {
340 value: lv,
341 datatype: ld,
342 },
343 Self::OtherTypedLiteral {
344 value: rv,
345 datatype: rd,
346 },
347 ) => lv == rv && ld == rd,
348 #[cfg(feature = "sparql-12")]
349 (Self::Triple(l), Self::Triple(r)) => l == r,
350 (_, _) => unreachable!(),
351 }
352 }
353}
354
355impl Eq for ExpressionTerm {}
356
357impl Hash for ExpressionTerm {
358 #[inline]
359 fn hash<H: Hasher>(&self, state: &mut H) {
360 discriminant(self).hash(state);
361 match self {
362 ExpressionTerm::NamedNode(v) => v.hash(state),
363 ExpressionTerm::BlankNode(v) => v.hash(state),
364 ExpressionTerm::StringLiteral(v) => v.hash(state),
365 ExpressionTerm::LangStringLiteral { value, language } => (value, language).hash(state),
366 #[cfg(feature = "sparql-12")]
367 ExpressionTerm::DirLangStringLiteral {
368 value,
369 language,
370 direction,
371 } => (value, language, direction).hash(state),
372 ExpressionTerm::BooleanLiteral(v) => v.hash(state),
373 ExpressionTerm::IntegerLiteral(v) => v.hash(state),
374 ExpressionTerm::DecimalLiteral(v) => v.hash(state),
375 ExpressionTerm::FloatLiteral(v) => v.to_be_bytes().hash(state),
376 ExpressionTerm::DoubleLiteral(v) => v.to_be_bytes().hash(state),
377 ExpressionTerm::DateTimeLiteral(v) => v.hash(state),
378 #[cfg(feature = "sep-0002")]
379 ExpressionTerm::DateLiteral(v) => v.hash(state),
380 #[cfg(feature = "sep-0002")]
381 ExpressionTerm::TimeLiteral(v) => v.hash(state),
382 #[cfg(feature = "calendar-ext")]
383 ExpressionTerm::GYearLiteral(v) => v.hash(state),
384 #[cfg(feature = "calendar-ext")]
385 ExpressionTerm::GYearMonthLiteral(v) => v.hash(state),
386 #[cfg(feature = "calendar-ext")]
387 ExpressionTerm::GMonthLiteral(v) => v.hash(state),
388 #[cfg(feature = "calendar-ext")]
389 ExpressionTerm::GMonthDayLiteral(v) => v.hash(state),
390 #[cfg(feature = "calendar-ext")]
391 ExpressionTerm::GDayLiteral(v) => v.hash(state),
392 #[cfg(feature = "sep-0002")]
393 ExpressionTerm::DurationLiteral(v) => v.hash(state),
394 #[cfg(feature = "sep-0002")]
395 ExpressionTerm::YearMonthDurationLiteral(v) => v.hash(state),
396 #[cfg(feature = "sep-0002")]
397 ExpressionTerm::DayTimeDurationLiteral(v) => v.hash(state),
398 ExpressionTerm::OtherTypedLiteral { value, datatype } => (value, datatype).hash(state),
399 #[cfg(feature = "sparql-12")]
400 ExpressionTerm::Triple(v) => v.hash(state),
401 }
402 }
403}
404
405impl From<Term> for ExpressionTerm {
406 #[inline]
407 fn from(term: Term) -> Self {
408 match term {
409 Term::NamedNode(t) => Self::NamedNode(t),
410 Term::BlankNode(t) => Self::BlankNode(t),
411 Term::Literal(t) => {
412 #[cfg(feature = "sparql-12")]
413 {
414 let (value, datatype, language, direction) = t.destruct();
415 if let Some(language) = language {
416 if let Some(direction) = direction {
417 Self::DirLangStringLiteral {
418 value,
419 language,
420 direction,
421 }
422 } else {
423 Self::LangStringLiteral { value, language }
424 }
425 } else if let Some(datatype) = datatype {
426 parse_typed_literal(&value, datatype.as_str())
427 .unwrap_or(Self::OtherTypedLiteral { value, datatype })
428 } else {
429 Self::StringLiteral(value)
430 }
431 }
432 #[cfg(not(feature = "sparql-12"))]
433 {
434 let (value, datatype, language) = t.destruct();
435 if let Some(language) = language {
436 Self::LangStringLiteral { value, language }
437 } else if let Some(datatype) = datatype {
438 parse_typed_literal(&value, datatype.as_str())
439 .unwrap_or(Self::OtherTypedLiteral { value, datatype })
440 } else {
441 Self::StringLiteral(value)
442 }
443 }
444 }
445 #[cfg(feature = "sparql-12")]
446 Term::Triple(t) => Self::Triple(Box::new((*t).into())),
447 }
448 }
449}
450
451impl From<ExpressionTerm> for Term {
452 #[inline]
453 fn from(term: ExpressionTerm) -> Self {
454 match term {
455 ExpressionTerm::NamedNode(t) => t.into(),
456 ExpressionTerm::BlankNode(t) => t.into(),
457 ExpressionTerm::StringLiteral(value) => Literal::from(value).into(),
458 ExpressionTerm::LangStringLiteral { value, language } => {
459 Literal::new_language_tagged_literal_unchecked(value, language).into()
460 }
461 #[cfg(feature = "sparql-12")]
462 ExpressionTerm::DirLangStringLiteral {
463 value,
464 language,
465 direction,
466 } => Literal::new_directional_language_tagged_literal_unchecked(
467 value, language, direction,
468 )
469 .into(),
470 ExpressionTerm::BooleanLiteral(value) => Literal::from(value).into(),
471 ExpressionTerm::IntegerLiteral(value) => Literal::from(value).into(),
472 ExpressionTerm::DecimalLiteral(value) => Literal::from(value).into(),
473 ExpressionTerm::FloatLiteral(value) => Literal::from(value).into(),
474 ExpressionTerm::DoubleLiteral(value) => Literal::from(value).into(),
475 ExpressionTerm::DateTimeLiteral(value) => Literal::from(value).into(),
476 #[cfg(feature = "sep-0002")]
477 ExpressionTerm::DateLiteral(value) => Literal::from(value).into(),
478 #[cfg(feature = "sep-0002")]
479 ExpressionTerm::TimeLiteral(value) => Literal::from(value).into(),
480 #[cfg(feature = "calendar-ext")]
481 ExpressionTerm::GYearLiteral(value) => Literal::from(value).into(),
482 #[cfg(feature = "calendar-ext")]
483 ExpressionTerm::GYearMonthLiteral(value) => Literal::from(value).into(),
484 #[cfg(feature = "calendar-ext")]
485 ExpressionTerm::GMonthLiteral(value) => Literal::from(value).into(),
486 #[cfg(feature = "calendar-ext")]
487 ExpressionTerm::GMonthDayLiteral(value) => Literal::from(value).into(),
488 #[cfg(feature = "calendar-ext")]
489 ExpressionTerm::GDayLiteral(value) => Literal::from(value).into(),
490 #[cfg(feature = "sep-0002")]
491 ExpressionTerm::DurationLiteral(value) => Literal::from(value).into(),
492 #[cfg(feature = "sep-0002")]
493 ExpressionTerm::YearMonthDurationLiteral(value) => Literal::from(value).into(),
494 #[cfg(feature = "sep-0002")]
495 ExpressionTerm::DayTimeDurationLiteral(value) => Literal::from(value).into(),
496 ExpressionTerm::OtherTypedLiteral { value, datatype } => {
497 Literal::new_typed_literal(value, datatype).into()
498 }
499 #[cfg(feature = "sparql-12")]
500 ExpressionTerm::Triple(t) => Triple::from(*t).into(),
501 }
502 }
503}
504
505impl From<NamedNode> for ExpressionTerm {
506 #[inline]
507 fn from(term: NamedNode) -> Self {
508 Self::NamedNode(term)
509 }
510}
511impl From<bool> for ExpressionTerm {
512 fn from(value: bool) -> Self {
513 Self::BooleanLiteral(value.into())
514 }
515}
516
517impl ExpressionTerm {
518 pub(crate) fn effective_boolean_value(&self) -> Option<bool> {
520 match self {
521 ExpressionTerm::BooleanLiteral(value) => Some((*value).into()),
522 ExpressionTerm::StringLiteral(value) => Some(!value.is_empty()),
523 ExpressionTerm::FloatLiteral(value) => Some(Boolean::from(*value).into()),
524 ExpressionTerm::DoubleLiteral(value) => Some(Boolean::from(*value).into()),
525 ExpressionTerm::IntegerLiteral(value) => Some(Boolean::from(*value).into()),
526 ExpressionTerm::DecimalLiteral(value) => Some(Boolean::from(*value).into()),
527 _ => None,
528 }
529 }
530}
531
532fn parse_typed_literal(value: &str, datatype: &str) -> Option<ExpressionTerm> {
533 Some(match datatype {
534 "http://www.w3.org/2001/XMLSchema#boolean" => {
535 ExpressionTerm::BooleanLiteral(value.parse().ok()?)
536 }
537 "http://www.w3.org/2001/XMLSchema#string" => ExpressionTerm::StringLiteral(value.into()),
538 "http://www.w3.org/2001/XMLSchema#float" => {
539 ExpressionTerm::FloatLiteral(value.parse().ok()?)
540 }
541 "http://www.w3.org/2001/XMLSchema#double" => {
542 ExpressionTerm::DoubleLiteral(value.parse().ok()?)
543 }
544 "http://www.w3.org/2001/XMLSchema#decimal" => {
545 ExpressionTerm::DecimalLiteral(value.parse().ok()?)
546 }
547 "http://www.w3.org/2001/XMLSchema#integer"
548 | "http://www.w3.org/2001/XMLSchema#byte"
549 | "http://www.w3.org/2001/XMLSchema#short"
550 | "http://www.w3.org/2001/XMLSchema#int"
551 | "http://www.w3.org/2001/XMLSchema#long"
552 | "http://www.w3.org/2001/XMLSchema#unsignedByte"
553 | "http://www.w3.org/2001/XMLSchema#unsignedShort"
554 | "http://www.w3.org/2001/XMLSchema#unsignedInt"
555 | "http://www.w3.org/2001/XMLSchema#unsignedLong"
556 | "http://www.w3.org/2001/XMLSchema#positiveInteger"
557 | "http://www.w3.org/2001/XMLSchema#negativeInteger"
558 | "http://www.w3.org/2001/XMLSchema#nonPositiveInteger"
559 | "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" => {
560 ExpressionTerm::IntegerLiteral(value.parse().ok()?)
561 }
562 "http://www.w3.org/2001/XMLSchema#dateTime"
563 | "http://www.w3.org/2001/XMLSchema#dateTimeStamp" => {
564 ExpressionTerm::DateTimeLiteral(value.parse().ok()?)
565 }
566 #[cfg(feature = "sep-0002")]
567 "http://www.w3.org/2001/XMLSchema#time" => ExpressionTerm::TimeLiteral(value.parse().ok()?),
568 #[cfg(feature = "sep-0002")]
569 "http://www.w3.org/2001/XMLSchema#date" => ExpressionTerm::DateLiteral(value.parse().ok()?),
570 #[cfg(feature = "calendar-ext")]
571 "http://www.w3.org/2001/XMLSchema#gYearMonth" => {
572 ExpressionTerm::GYearMonthLiteral(value.parse().ok()?)
573 }
574 #[cfg(feature = "calendar-ext")]
575 "http://www.w3.org/2001/XMLSchema#gYear" => {
576 ExpressionTerm::GYearLiteral(value.parse().ok()?)
577 }
578 #[cfg(feature = "calendar-ext")]
579 "http://www.w3.org/2001/XMLSchema#gMonthDay" => {
580 ExpressionTerm::GMonthDayLiteral(value.parse().ok()?)
581 }
582 #[cfg(feature = "calendar-ext")]
583 "http://www.w3.org/2001/XMLSchema#gDay" => ExpressionTerm::GDayLiteral(value.parse().ok()?),
584 #[cfg(feature = "calendar-ext")]
585 "http://www.w3.org/2001/XMLSchema#gMonth" => {
586 ExpressionTerm::GMonthLiteral(value.parse().ok()?)
587 }
588 #[cfg(feature = "sep-0002")]
589 "http://www.w3.org/2001/XMLSchema#duration" => {
590 ExpressionTerm::DurationLiteral(value.parse().ok()?)
591 }
592 #[cfg(feature = "sep-0002")]
593 "http://www.w3.org/2001/XMLSchema#yearMonthDuration" => {
594 ExpressionTerm::YearMonthDurationLiteral(value.parse().ok()?)
595 }
596 #[cfg(feature = "sep-0002")]
597 "http://www.w3.org/2001/XMLSchema#dayTimeDuration" => {
598 ExpressionTerm::DayTimeDurationLiteral(value.parse().ok()?)
599 }
600 _ => return None,
601 })
602}
603
604#[cfg(feature = "sparql-12")]
605#[derive(Clone, PartialEq, Eq, Hash)]
606pub struct ExpressionTriple {
607 pub subject: NamedOrBlankNode,
608 pub predicate: NamedNode,
609 pub object: ExpressionTerm,
610}
611
612#[cfg(feature = "sparql-12")]
613impl From<ExpressionTriple> for ExpressionTerm {
614 #[inline]
615 fn from(triple: ExpressionTriple) -> Self {
616 Self::Triple(Box::new(triple))
617 }
618}
619
620#[cfg(feature = "sparql-12")]
621impl From<Triple> for ExpressionTriple {
622 #[inline]
623 fn from(triple: Triple) -> Self {
624 ExpressionTriple {
625 subject: triple.subject,
626 predicate: triple.predicate,
627 object: triple.object.into(),
628 }
629 }
630}
631
632#[cfg(feature = "sparql-12")]
633impl From<ExpressionTriple> for Triple {
634 #[inline]
635 fn from(triple: ExpressionTriple) -> Self {
636 Triple {
637 subject: triple.subject,
638 predicate: triple.predicate,
639 object: triple.object.into(),
640 }
641 }
642}
643
644#[cfg(feature = "sparql-12")]
645impl ExpressionTriple {
646 pub fn new(
647 subject: ExpressionTerm,
648 predicate: ExpressionTerm,
649 object: ExpressionTerm,
650 ) -> Option<Self> {
651 if !matches!(
652 subject,
653 ExpressionTerm::NamedNode(_) | ExpressionTerm::BlankNode(_) | ExpressionTerm::Triple(_)
654 ) {
655 return None;
656 }
657 if !matches!(predicate, ExpressionTerm::NamedNode(_)) {
658 return None;
659 }
660 Some(Self {
661 subject: match subject {
662 ExpressionTerm::NamedNode(s) => NamedOrBlankNode::NamedNode(s),
663 ExpressionTerm::BlankNode(s) => NamedOrBlankNode::BlankNode(s),
664 _ => return None,
665 },
666 predicate: if let ExpressionTerm::NamedNode(p) = predicate {
667 p
668 } else {
669 return None;
670 },
671 object,
672 })
673 }
674}
675
676#[cfg(feature = "sparql-12")]
677impl From<NamedOrBlankNode> for ExpressionTerm {
678 #[inline]
679 fn from(subject: NamedOrBlankNode) -> Self {
680 match subject {
681 NamedOrBlankNode::NamedNode(s) => Self::NamedNode(s),
682 NamedOrBlankNode::BlankNode(s) => Self::BlankNode(s),
683 }
684 }
685}
686
687#[doc(hidden)]
688#[derive(Clone)]
689pub enum TermCow<'a> {
690 Owned(Term),
691 Borrowed(TermRef<'a>),
692}
693
694impl PartialEq for TermCow<'_> {
695 #[inline]
696 fn eq(&self, other: &Self) -> bool {
697 TermRef::from(self) == TermRef::from(other)
698 }
699}
700
701impl Eq for TermCow<'_> {}
702
703impl Hash for TermCow<'_> {
704 #[inline]
705 fn hash<H: Hasher>(&self, state: &mut H) {
706 TermRef::from(self).hash(state)
707 }
708}
709
710impl From<Term> for TermCow<'_> {
711 fn from(value: Term) -> Self {
712 Self::Owned(value)
713 }
714}
715
716impl<'a> From<TermRef<'a>> for TermCow<'a> {
717 fn from(value: TermRef<'a>) -> Self {
718 Self::Borrowed(value)
719 }
720}
721
722impl From<TermCow<'_>> for Term {
723 fn from(value: TermCow<'_>) -> Self {
724 match value {
725 TermCow::Owned(t) => t,
726 TermCow::Borrowed(t) => t.into_owned(),
727 }
728 }
729}
730
731impl<'a> From<&'a TermCow<'a>> for TermRef<'a> {
732 fn from(value: &'a TermCow<'a>) -> Self {
733 match value {
734 TermCow::Owned(t) => t.as_ref(),
735 TermCow::Borrowed(t) => *t,
736 }
737 }
738}