1use crate::error::OxirsError;
4use crate::model::{Literal, Term};
5use crate::rdf_store::VariableBinding;
6use crate::sparql::aggregates::find_matching_paren;
7use crate::Result;
8
9#[derive(Debug, Clone)]
11pub enum Expression {
12 Variable(String),
13 Literal(String),
14 Integer(i64),
15 Float(f64),
16 ArithmeticOp {
17 left: Box<Expression>,
18 op: ArithmeticOperator,
19 right: Box<Expression>,
20 },
21 FunctionCall {
22 name: String,
23 args: Vec<Expression>,
24 },
25}
26
27#[derive(Debug, Clone)]
29pub enum ArithmeticOperator {
30 Add,
31 Subtract,
32 Multiply,
33 Divide,
34}
35
36#[derive(Debug, Clone)]
38pub struct BindExpression {
39 pub expression: Expression,
40 pub variable: String,
41}
42
43pub fn extract_bind_expressions(sparql: &str) -> Result<Vec<BindExpression>> {
45 let mut binds = Vec::new();
46
47 let sparql_upper = sparql.to_uppercase();
49 let mut search_pos = 0;
50
51 while let Some(bind_pos) = sparql_upper[search_pos..].find("BIND") {
52 let abs_pos = search_pos + bind_pos;
53 let after_bind = &sparql[abs_pos + 4..];
54
55 if let Some(paren_start) = after_bind.find('(') {
57 if let Some(paren_end) = find_matching_paren(&after_bind[paren_start..]) {
59 let bind_content = &after_bind[paren_start + 1..paren_start + paren_end];
60
61 if let Some(as_pos) = bind_content.to_uppercase().find(" AS ") {
63 let expr_text = bind_content[..as_pos].trim();
64 let var_text = bind_content[as_pos + 4..].trim();
65
66 if let Some(var_name) = var_text.strip_prefix('?') {
68 if let Ok(expression) = parse_expression(expr_text) {
70 binds.push(BindExpression {
71 expression,
72 variable: var_name.to_string(),
73 });
74 }
75 }
76 }
77
78 search_pos = abs_pos + 4 + paren_start + paren_end;
79 } else {
80 break;
81 }
82 } else {
83 break;
84 }
85 }
86
87 Ok(binds)
88}
89
90pub fn split_function_args(args_text: &str) -> Vec<String> {
92 let mut args = Vec::new();
93 let mut current_arg = String::new();
94 let mut in_string = false;
95 let mut string_delimiter = ' ';
96 let mut paren_depth = 0;
97
98 for ch in args_text.chars() {
99 match ch {
100 '"' | '\'' if !in_string => {
101 in_string = true;
102 string_delimiter = ch;
103 current_arg.push(ch);
104 }
105 '"' | '\'' if in_string && ch == string_delimiter => {
106 in_string = false;
107 current_arg.push(ch);
108 }
109 '(' if !in_string => {
110 paren_depth += 1;
111 current_arg.push(ch);
112 }
113 ')' if !in_string => {
114 paren_depth -= 1;
115 current_arg.push(ch);
116 }
117 ',' if !in_string && paren_depth == 0 => {
118 if !current_arg.trim().is_empty() {
119 args.push(current_arg.clone());
120 }
121 current_arg.clear();
122 }
123 _ => {
124 current_arg.push(ch);
125 }
126 }
127 }
128
129 if !current_arg.trim().is_empty() {
131 args.push(current_arg);
132 }
133
134 args
135}
136
137pub fn parse_expression(expr: &str) -> Result<Expression> {
139 let expr = expr.trim();
140
141 if let Some(op_pos) = expr.rfind(" + ") {
143 let left = parse_expression(&expr[..op_pos])?;
144 let right = parse_expression(&expr[op_pos + 3..])?;
145 return Ok(Expression::ArithmeticOp {
146 left: Box::new(left),
147 op: ArithmeticOperator::Add,
148 right: Box::new(right),
149 });
150 }
151
152 if let Some(op_pos) = expr.rfind(" - ") {
153 let left = parse_expression(&expr[..op_pos])?;
154 let right = parse_expression(&expr[op_pos + 3..])?;
155 return Ok(Expression::ArithmeticOp {
156 left: Box::new(left),
157 op: ArithmeticOperator::Subtract,
158 right: Box::new(right),
159 });
160 }
161
162 if let Some(op_pos) = expr.rfind(" * ") {
163 let left = parse_expression(&expr[..op_pos])?;
164 let right = parse_expression(&expr[op_pos + 3..])?;
165 return Ok(Expression::ArithmeticOp {
166 left: Box::new(left),
167 op: ArithmeticOperator::Multiply,
168 right: Box::new(right),
169 });
170 }
171
172 if let Some(op_pos) = expr.rfind(" / ") {
173 let left = parse_expression(&expr[..op_pos])?;
174 let right = parse_expression(&expr[op_pos + 3..])?;
175 return Ok(Expression::ArithmeticOp {
176 left: Box::new(left),
177 op: ArithmeticOperator::Divide,
178 right: Box::new(right),
179 });
180 }
181
182 if let Some(paren_pos) = expr.find('(') {
184 if let Some(paren_end) = find_matching_paren(&expr[paren_pos..]) {
185 let func_name = expr[..paren_pos].trim().to_uppercase();
186 let args_text = &expr[paren_pos + 1..paren_pos + paren_end];
187
188 let arg_strs = split_function_args(args_text);
190 let mut args = Vec::new();
191 for arg_str in arg_strs {
192 args.push(parse_expression(arg_str.trim())?);
193 }
194
195 return Ok(Expression::FunctionCall {
196 name: func_name,
197 args,
198 });
199 }
200 }
201
202 if expr.starts_with('?') {
204 return Ok(Expression::Variable(expr.to_string()));
205 }
206
207 if (expr.starts_with('"') && expr.ends_with('"'))
209 || (expr.starts_with('\'') && expr.ends_with('\''))
210 {
211 return Ok(Expression::Literal(expr[1..expr.len() - 1].to_string()));
212 }
213
214 if let Ok(int_val) = expr.parse::<i64>() {
216 return Ok(Expression::Integer(int_val));
217 }
218
219 if let Ok(float_val) = expr.parse::<f64>() {
220 return Ok(Expression::Float(float_val));
221 }
222
223 Ok(Expression::Literal(expr.to_string()))
225}
226
227pub fn evaluate_expression(expr: &Expression, binding: &VariableBinding) -> Result<Term> {
229 match expr {
230 Expression::Variable(var_name) => {
231 let var = var_name.strip_prefix('?').unwrap_or(var_name);
232 binding
233 .get(var)
234 .cloned()
235 .ok_or_else(|| OxirsError::Query(format!("Unbound variable: {}", var_name)))
236 }
237 Expression::Literal(val) => Ok(Term::from(Literal::new(val.clone()))),
238 Expression::Integer(val) => Ok(Term::from(Literal::new(val.to_string()))),
239 Expression::Float(val) => Ok(Term::from(Literal::new(val.to_string()))),
240 Expression::ArithmeticOp { left, op, right } => {
241 let left_val = evaluate_expression(left, binding)?;
242 let right_val = evaluate_expression(right, binding)?;
243
244 let left_num = term_to_number(&left_val)?;
245 let right_num = term_to_number(&right_val)?;
246
247 let result = match op {
248 ArithmeticOperator::Add => left_num + right_num,
249 ArithmeticOperator::Subtract => left_num - right_num,
250 ArithmeticOperator::Multiply => left_num * right_num,
251 ArithmeticOperator::Divide => {
252 if right_num.abs() < f64::EPSILON {
253 return Err(OxirsError::Query("Division by zero".to_string()));
254 }
255 left_num / right_num
256 }
257 };
258
259 Ok(Term::from(Literal::new(result.to_string())))
260 }
261 Expression::FunctionCall { name, args } => {
262 match name.as_str() {
263 "STR" => {
264 if args.len() != 1 {
265 return Err(OxirsError::Query(
266 "STR requires exactly one argument".to_string(),
267 ));
268 }
269 let val = evaluate_expression(&args[0], binding)?;
270 Ok(Term::from(Literal::new(term_to_string(&val))))
271 }
272 "CONCAT" => {
273 let mut result = String::new();
274 for arg in args {
275 let val = evaluate_expression(arg, binding)?;
276 result.push_str(&term_to_string(&val));
277 }
278 Ok(Term::from(Literal::new(result)))
279 }
280 "STRLEN" => {
281 if args.len() != 1 {
282 return Err(OxirsError::Query(
283 "STRLEN requires exactly one argument".to_string(),
284 ));
285 }
286 let val = evaluate_expression(&args[0], binding)?;
287 let s = term_to_string(&val);
288 Ok(Term::from(Literal::new(s.len().to_string())))
289 }
290 "UCASE" => {
291 if args.len() != 1 {
292 return Err(OxirsError::Query(
293 "UCASE requires exactly one argument".to_string(),
294 ));
295 }
296 let val = evaluate_expression(&args[0], binding)?;
297 let s = term_to_string(&val);
298 Ok(Term::from(Literal::new(s.to_uppercase())))
299 }
300 "LCASE" => {
301 if args.len() != 1 {
302 return Err(OxirsError::Query(
303 "LCASE requires exactly one argument".to_string(),
304 ));
305 }
306 let val = evaluate_expression(&args[0], binding)?;
307 let s = term_to_string(&val);
308 Ok(Term::from(Literal::new(s.to_lowercase())))
309 }
310 "CONTAINS" => {
311 if args.len() != 2 {
312 return Err(OxirsError::Query(
313 "CONTAINS requires exactly two arguments".to_string(),
314 ));
315 }
316 let haystack = evaluate_expression(&args[0], binding)?;
317 let needle = evaluate_expression(&args[1], binding)?;
318 let haystack_str = term_to_string(&haystack);
319 let needle_str = term_to_string(&needle);
320 let result = if haystack_str.contains(&needle_str) {
321 "true"
322 } else {
323 "false"
324 };
325 Ok(Term::from(Literal::new(result.to_string())))
326 }
327 "SUBSTR" | "SUBSTRING" => {
328 if args.len() < 2 || args.len() > 3 {
329 return Err(OxirsError::Query(
330 "SUBSTR requires 2 or 3 arguments".to_string(),
331 ));
332 }
333 let s = term_to_string(&evaluate_expression(&args[0], binding)?);
334 let start = term_to_number(&evaluate_expression(&args[1], binding)?)? as usize;
335
336 let start_idx = if start > 0 { start - 1 } else { 0 };
338
339 let result: String = if args.len() == 3 {
340 let length =
341 term_to_number(&evaluate_expression(&args[2], binding)?)? as usize;
342 s.chars().skip(start_idx).take(length).collect()
343 } else {
344 s.chars().skip(start_idx).collect()
345 };
346
347 Ok(Term::from(Literal::new(result)))
348 }
349 "REPLACE" => {
350 if args.len() < 3 || args.len() > 4 {
351 return Err(OxirsError::Query(
352 "REPLACE requires 3 or 4 arguments".to_string(),
353 ));
354 }
355 let s = term_to_string(&evaluate_expression(&args[0], binding)?);
356 let pattern = term_to_string(&evaluate_expression(&args[1], binding)?);
357 let replacement = term_to_string(&evaluate_expression(&args[2], binding)?);
358
359 let result = s.replace(&pattern, &replacement);
361 Ok(Term::from(Literal::new(result)))
362 }
363 "STRSTARTS" => {
364 if args.len() != 2 {
365 return Err(OxirsError::Query(
366 "STRSTARTS requires exactly two arguments".to_string(),
367 ));
368 }
369 let s = term_to_string(&evaluate_expression(&args[0], binding)?);
370 let prefix = term_to_string(&evaluate_expression(&args[1], binding)?);
371 let result = if s.starts_with(&prefix) {
372 "true"
373 } else {
374 "false"
375 };
376 Ok(Term::from(Literal::new(result.to_string())))
377 }
378 "STRENDS" => {
379 if args.len() != 2 {
380 return Err(OxirsError::Query(
381 "STRENDS requires exactly two arguments".to_string(),
382 ));
383 }
384 let s = term_to_string(&evaluate_expression(&args[0], binding)?);
385 let suffix = term_to_string(&evaluate_expression(&args[1], binding)?);
386 let result = if s.ends_with(&suffix) {
387 "true"
388 } else {
389 "false"
390 };
391 Ok(Term::from(Literal::new(result.to_string())))
392 }
393 "TRIPLE" => {
420 if args.len() != 3 {
421 return Err(OxirsError::Query(
422 "TRIPLE requires exactly three arguments (subject, predicate, object)"
423 .to_string(),
424 ));
425 }
426 let subject_term = evaluate_expression(&args[0], binding)?;
427 let predicate_term = evaluate_expression(&args[1], binding)?;
428 let object_term = evaluate_expression(&args[2], binding)?;
429
430 use crate::model::{Object, Predicate, QuotedTriple, Subject, Triple};
432 let subject: Subject = match subject_term {
433 Term::NamedNode(n) => Subject::NamedNode(n),
434 Term::BlankNode(b) => Subject::BlankNode(b),
435 Term::Variable(v) => Subject::Variable(v),
436 Term::QuotedTriple(qt) => Subject::QuotedTriple(qt),
437 _ => {
438 return Err(OxirsError::Query(
439 "TRIPLE subject must be NamedNode, BlankNode, Variable, or QuotedTriple".to_string(),
440 ))
441 }
442 };
443
444 let predicate: Predicate = match predicate_term {
445 Term::NamedNode(n) => Predicate::NamedNode(n),
446 Term::Variable(v) => Predicate::Variable(v),
447 _ => {
448 return Err(OxirsError::Query(
449 "TRIPLE predicate must be NamedNode or Variable".to_string(),
450 ))
451 }
452 };
453
454 let object: Object = match object_term {
455 Term::NamedNode(n) => Object::NamedNode(n),
456 Term::BlankNode(b) => Object::BlankNode(b),
457 Term::Literal(l) => Object::Literal(l),
458 Term::Variable(v) => Object::Variable(v),
459 Term::QuotedTriple(qt) => Object::QuotedTriple(qt),
460 };
461
462 let triple = Triple::new(subject, predicate, object);
464 let quoted = QuotedTriple::new(triple);
465 Ok(Term::QuotedTriple(Box::new(quoted)))
466 }
467 "SUBJECT" => {
477 if args.len() != 1 {
478 return Err(OxirsError::Query(
479 "SUBJECT requires exactly one argument (a quoted triple)".to_string(),
480 ));
481 }
482 let term = evaluate_expression(&args[0], binding)?;
483 match term {
484 Term::QuotedTriple(triple) => {
485 use crate::model::Subject;
487 let subject = triple.subject();
488 let term = match subject {
489 Subject::NamedNode(n) => Term::NamedNode(n.clone()),
490 Subject::BlankNode(b) => Term::BlankNode(b.clone()),
491 Subject::Variable(v) => Term::Variable(v.clone()),
492 Subject::QuotedTriple(qt) => Term::QuotedTriple(qt.clone()),
493 };
494 Ok(term)
495 }
496 _ => Err(OxirsError::Query(
497 "SUBJECT function requires a quoted triple argument".to_string(),
498 )),
499 }
500 }
501 "PREDICATE" => {
511 if args.len() != 1 {
512 return Err(OxirsError::Query(
513 "PREDICATE requires exactly one argument (a quoted triple)".to_string(),
514 ));
515 }
516 let term = evaluate_expression(&args[0], binding)?;
517 match term {
518 Term::QuotedTriple(triple) => {
519 use crate::model::Predicate;
521 let predicate = triple.predicate();
522 let term = match predicate {
523 Predicate::NamedNode(n) => Term::NamedNode(n.clone()),
524 Predicate::Variable(v) => Term::Variable(v.clone()),
525 };
526 Ok(term)
527 }
528 _ => Err(OxirsError::Query(
529 "PREDICATE function requires a quoted triple argument".to_string(),
530 )),
531 }
532 }
533 "OBJECT" => {
543 if args.len() != 1 {
544 return Err(OxirsError::Query(
545 "OBJECT requires exactly one argument (a quoted triple)".to_string(),
546 ));
547 }
548 let term = evaluate_expression(&args[0], binding)?;
549 match term {
550 Term::QuotedTriple(triple) => {
551 use crate::model::Object;
553 let object = triple.object();
554 let term = match object {
555 Object::NamedNode(n) => Term::NamedNode(n.clone()),
556 Object::BlankNode(b) => Term::BlankNode(b.clone()),
557 Object::Literal(l) => Term::Literal(l.clone()),
558 Object::Variable(v) => Term::Variable(v.clone()),
559 Object::QuotedTriple(qt) => Term::QuotedTriple(qt.clone()),
560 };
561 Ok(term)
562 }
563 _ => Err(OxirsError::Query(
564 "OBJECT function requires a quoted triple argument".to_string(),
565 )),
566 }
567 }
568 "ISTRIPLE" => {
578 if args.len() != 1 {
579 return Err(OxirsError::Query(
580 "isTRIPLE requires exactly one argument".to_string(),
581 ));
582 }
583 let term = evaluate_expression(&args[0], binding)?;
584 let result = if matches!(term, Term::QuotedTriple(_)) {
585 "true"
586 } else {
587 "false"
588 };
589 Ok(Term::from(Literal::new(result.to_string())))
590 }
591 _ => Err(OxirsError::Query(format!("Unsupported function: {}", name))),
592 }
593 }
594 }
595}
596
597pub fn term_to_number(term: &Term) -> Result<f64> {
599 if let Term::Literal(lit) = term {
600 lit.value()
601 .parse::<f64>()
602 .map_err(|_| OxirsError::Query(format!("Cannot convert to number: {}", lit.value())))
603 } else {
604 Err(OxirsError::Query("Expected numeric literal".to_string()))
605 }
606}
607
608pub fn term_to_string(term: &Term) -> String {
610 match term {
611 Term::NamedNode(node) => node.to_string(),
612 Term::BlankNode(node) => node.to_string(),
613 Term::Literal(lit) => lit.value().to_string(),
614 Term::Variable(var) => var.to_string(),
615 Term::QuotedTriple(triple) => format!("<< {} >>", triple),
616 }
617}
618
619pub fn apply_bind_expressions(
621 results: Vec<VariableBinding>,
622 binds: &[BindExpression],
623) -> Result<Vec<VariableBinding>> {
624 if binds.is_empty() {
625 return Ok(results);
626 }
627
628 let mut new_results = Vec::new();
629
630 for binding in results {
631 let mut new_binding = binding.clone();
632
633 for bind_expr in binds {
635 match evaluate_expression(&bind_expr.expression, &binding) {
636 Ok(value) => {
637 new_binding.bind(bind_expr.variable.clone(), value);
638 }
639 Err(_) => {
640 continue;
642 }
643 }
644 }
645
646 new_results.push(new_binding);
647 }
648
649 Ok(new_results)
650}
651
652#[cfg(test)]
653mod tests {
654 use super::*;
655 use crate::model::{Literal, NamedNode, Object, Predicate, Subject, Triple};
656
657 #[test]
658 fn test_sparql_12_triple_function() {
659 let mut binding = VariableBinding::new();
661
662 let alice = Term::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
664 let knows = Term::NamedNode(NamedNode::new("http://example.org/knows").expect("valid IRI"));
665 let bob = Term::NamedNode(NamedNode::new("http://example.org/bob").expect("valid IRI"));
666
667 binding.bind("s".to_string(), alice.clone());
668 binding.bind("p".to_string(), knows.clone());
669 binding.bind("o".to_string(), bob.clone());
670
671 let expr = Expression::FunctionCall {
673 name: "TRIPLE".to_string(),
674 args: vec![
675 Expression::Variable("?s".to_string()),
676 Expression::Variable("?p".to_string()),
677 Expression::Variable("?o".to_string()),
678 ],
679 };
680
681 let result = evaluate_expression(&expr, &binding);
682 assert!(result.is_ok());
683
684 if let Ok(Term::QuotedTriple(qt)) = result {
685 assert_eq!(
686 qt.subject(),
687 &Subject::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"))
688 );
689 assert_eq!(
690 qt.predicate(),
691 &Predicate::NamedNode(
692 NamedNode::new("http://example.org/knows").expect("valid IRI")
693 )
694 );
695 } else {
696 panic!("Expected QuotedTriple");
697 }
698 }
699
700 #[test]
701 fn test_sparql_12_subject_function() {
702 let mut binding = VariableBinding::new();
704
705 let subject =
707 Subject::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
708 let predicate =
709 Predicate::NamedNode(NamedNode::new("http://example.org/age").expect("valid IRI"));
710 let object = Object::Literal(Literal::new("30"));
711
712 let triple = Triple::new(subject, predicate, object);
713 let quoted = crate::model::QuotedTriple::new(triple);
714
715 binding.bind("qt".to_string(), Term::QuotedTriple(Box::new(quoted)));
716
717 let expr = Expression::FunctionCall {
719 name: "SUBJECT".to_string(),
720 args: vec![Expression::Variable("?qt".to_string())],
721 };
722
723 let result = evaluate_expression(&expr, &binding);
724 assert!(result.is_ok());
725
726 if let Ok(Term::NamedNode(n)) = result {
727 assert_eq!(n.as_str(), "http://example.org/alice");
728 } else {
729 panic!("Expected NamedNode");
730 }
731 }
732
733 #[test]
734 fn test_sparql_12_predicate_function() {
735 let mut binding = VariableBinding::new();
737
738 let subject =
740 Subject::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
741 let predicate =
742 Predicate::NamedNode(NamedNode::new("http://example.org/age").expect("valid IRI"));
743 let object = Object::Literal(Literal::new("30"));
744
745 let triple = Triple::new(subject, predicate, object);
746 let quoted = crate::model::QuotedTriple::new(triple);
747
748 binding.bind("qt".to_string(), Term::QuotedTriple(Box::new(quoted)));
749
750 let expr = Expression::FunctionCall {
752 name: "PREDICATE".to_string(),
753 args: vec![Expression::Variable("?qt".to_string())],
754 };
755
756 let result = evaluate_expression(&expr, &binding);
757 assert!(result.is_ok());
758
759 if let Ok(Term::NamedNode(n)) = result {
760 assert_eq!(n.as_str(), "http://example.org/age");
761 } else {
762 panic!("Expected NamedNode");
763 }
764 }
765
766 #[test]
767 fn test_sparql_12_object_function() {
768 let mut binding = VariableBinding::new();
770
771 let subject =
773 Subject::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
774 let predicate =
775 Predicate::NamedNode(NamedNode::new("http://example.org/age").expect("valid IRI"));
776 let object = Object::Literal(Literal::new("30"));
777
778 let triple = Triple::new(subject, predicate, object);
779 let quoted = crate::model::QuotedTriple::new(triple);
780
781 binding.bind("qt".to_string(), Term::QuotedTriple(Box::new(quoted)));
782
783 let expr = Expression::FunctionCall {
785 name: "OBJECT".to_string(),
786 args: vec![Expression::Variable("?qt".to_string())],
787 };
788
789 let result = evaluate_expression(&expr, &binding);
790 assert!(result.is_ok());
791
792 if let Ok(Term::Literal(lit)) = result {
793 assert_eq!(lit.value(), "30");
794 } else {
795 panic!("Expected Literal");
796 }
797 }
798
799 #[test]
800 fn test_sparql_12_istriple_function_true() {
801 let mut binding = VariableBinding::new();
803
804 let subject =
806 Subject::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
807 let predicate =
808 Predicate::NamedNode(NamedNode::new("http://example.org/age").expect("valid IRI"));
809 let object = Object::Literal(Literal::new("30"));
810
811 let triple = Triple::new(subject, predicate, object);
812 let quoted = crate::model::QuotedTriple::new(triple);
813
814 binding.bind("qt".to_string(), Term::QuotedTriple(Box::new(quoted)));
815
816 let expr = Expression::FunctionCall {
818 name: "ISTRIPLE".to_string(),
819 args: vec![Expression::Variable("?qt".to_string())],
820 };
821
822 let result = evaluate_expression(&expr, &binding);
823 assert!(result.is_ok());
824
825 if let Ok(Term::Literal(lit)) = result {
826 assert_eq!(lit.value(), "true");
827 } else {
828 panic!("Expected true Literal");
829 }
830 }
831
832 #[test]
833 fn test_sparql_12_istriple_function_false() {
834 let mut binding = VariableBinding::new();
836
837 let alice = Term::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
838 binding.bind("n".to_string(), alice);
839
840 let expr = Expression::FunctionCall {
842 name: "ISTRIPLE".to_string(),
843 args: vec![Expression::Variable("?n".to_string())],
844 };
845
846 let result = evaluate_expression(&expr, &binding);
847 assert!(result.is_ok());
848
849 if let Ok(Term::Literal(lit)) = result {
850 assert_eq!(lit.value(), "false");
851 } else {
852 panic!("Expected false Literal");
853 }
854 }
855
856 #[test]
857 fn test_sparql_12_nested_quoted_triples() {
858 let mut binding = VariableBinding::new();
860
861 let alice = Term::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
862 let age = Term::NamedNode(NamedNode::new("http://example.org/age").expect("valid IRI"));
863 let thirty = Term::Literal(Literal::new("30"));
864 let confidence =
865 Term::NamedNode(NamedNode::new("http://example.org/confidence").expect("valid IRI"));
866 let high = Term::Literal(Literal::new("high"));
867
868 binding.bind("s".to_string(), alice);
869 binding.bind("p".to_string(), age);
870 binding.bind("o".to_string(), thirty);
871 binding.bind("p2".to_string(), confidence);
872 binding.bind("o2".to_string(), high);
873
874 let inner_expr = Expression::FunctionCall {
876 name: "TRIPLE".to_string(),
877 args: vec![
878 Expression::Variable("?s".to_string()),
879 Expression::Variable("?p".to_string()),
880 Expression::Variable("?o".to_string()),
881 ],
882 };
883
884 let outer_expr = Expression::FunctionCall {
886 name: "TRIPLE".to_string(),
887 args: vec![
888 inner_expr,
889 Expression::Variable("?p2".to_string()),
890 Expression::Variable("?o2".to_string()),
891 ],
892 };
893
894 let result = evaluate_expression(&outer_expr, &binding);
895 assert!(result.is_ok());
896
897 if let Ok(Term::QuotedTriple(outer_qt)) = result {
899 assert!(matches!(outer_qt.subject(), Subject::QuotedTriple(_)));
900 } else {
901 panic!("Expected nested QuotedTriple");
902 }
903 }
904
905 #[test]
906 fn test_sparql_12_rdf_star_composition() {
907 let mut binding = VariableBinding::new();
909
910 let alice = Term::NamedNode(NamedNode::new("http://example.org/alice").expect("valid IRI"));
911 let knows = Term::NamedNode(NamedNode::new("http://example.org/knows").expect("valid IRI"));
912 let bob = Term::NamedNode(NamedNode::new("http://example.org/bob").expect("valid IRI"));
913
914 binding.bind("s".to_string(), alice.clone());
915 binding.bind("p".to_string(), knows.clone());
916 binding.bind("o".to_string(), bob.clone());
917
918 let triple_expr = Expression::FunctionCall {
920 name: "TRIPLE".to_string(),
921 args: vec![
922 Expression::Variable("?s".to_string()),
923 Expression::Variable("?p".to_string()),
924 Expression::Variable("?o".to_string()),
925 ],
926 };
927
928 let quoted_triple = evaluate_expression(&triple_expr, &binding)
929 .expect("expression evaluation should succeed");
930 binding.bind("qt".to_string(), quoted_triple);
931
932 let subject_expr = Expression::FunctionCall {
934 name: "SUBJECT".to_string(),
935 args: vec![Expression::Variable("?qt".to_string())],
936 };
937 let extracted_subject = evaluate_expression(&subject_expr, &binding)
938 .expect("expression evaluation should succeed");
939
940 assert_eq!(extracted_subject, alice);
942
943 let predicate_expr = Expression::FunctionCall {
945 name: "PREDICATE".to_string(),
946 args: vec![Expression::Variable("?qt".to_string())],
947 };
948 let extracted_predicate = evaluate_expression(&predicate_expr, &binding)
949 .expect("expression evaluation should succeed");
950
951 assert_eq!(extracted_predicate, knows);
953
954 let object_expr = Expression::FunctionCall {
956 name: "OBJECT".to_string(),
957 args: vec![Expression::Variable("?qt".to_string())],
958 };
959 let extracted_object = evaluate_expression(&object_expr, &binding)
960 .expect("expression evaluation should succeed");
961
962 assert_eq!(extracted_object, bob);
964 }
965}