sparql 3.1.5 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -28
  3. data/VERSION +1 -1
  4. data/bin/sparql +14 -4
  5. data/lib/sparql/algebra/aggregate.rb +1 -1
  6. data/lib/sparql/algebra/evaluatable.rb +4 -4
  7. data/lib/sparql/algebra/expression.rb +4 -1
  8. data/lib/sparql/algebra/extensions.rb +96 -29
  9. data/lib/sparql/algebra/operator/abs.rb +23 -3
  10. data/lib/sparql/algebra/operator/add.rb +21 -2
  11. data/lib/sparql/algebra/operator/alt.rb +26 -2
  12. data/lib/sparql/algebra/operator/and.rb +25 -3
  13. data/lib/sparql/algebra/operator/asc.rb +20 -1
  14. data/lib/sparql/algebra/operator/ask.rb +17 -1
  15. data/lib/sparql/algebra/operator/avg.rb +18 -2
  16. data/lib/sparql/algebra/operator/base.rb +18 -1
  17. data/lib/sparql/algebra/operator/bgp.rb +5 -1
  18. data/lib/sparql/algebra/operator/bnode.rb +34 -11
  19. data/lib/sparql/algebra/operator/bound.rb +22 -1
  20. data/lib/sparql/algebra/operator/ceil.rb +26 -3
  21. data/lib/sparql/algebra/operator/clear.rb +16 -2
  22. data/lib/sparql/algebra/operator/coalesce.rb +33 -11
  23. data/lib/sparql/algebra/operator/compare.rb +48 -33
  24. data/lib/sparql/algebra/operator/concat.rb +26 -2
  25. data/lib/sparql/algebra/operator/construct.rb +31 -7
  26. data/lib/sparql/algebra/operator/contains.rb +25 -3
  27. data/lib/sparql/algebra/operator/copy.rb +19 -2
  28. data/lib/sparql/algebra/operator/count.rb +18 -2
  29. data/lib/sparql/algebra/operator/create.rb +19 -2
  30. data/lib/sparql/algebra/operator/dataset.rb +17 -0
  31. data/lib/sparql/algebra/operator/datatype.rb +26 -7
  32. data/lib/sparql/algebra/operator/day.rb +24 -6
  33. data/lib/sparql/algebra/operator/delete.rb +27 -2
  34. data/lib/sparql/algebra/operator/delete_data.rb +23 -2
  35. data/lib/sparql/algebra/operator/delete_where.rb +24 -2
  36. data/lib/sparql/algebra/operator/desc.rb +20 -1
  37. data/lib/sparql/algebra/operator/describe.rb +27 -4
  38. data/lib/sparql/algebra/operator/distinct.rb +18 -1
  39. data/lib/sparql/algebra/operator/divide.rb +27 -3
  40. data/lib/sparql/algebra/operator/drop.rb +17 -2
  41. data/lib/sparql/algebra/operator/encode_for_uri.rb +25 -3
  42. data/lib/sparql/algebra/operator/equal.rb +13 -3
  43. data/lib/sparql/algebra/operator/exists.rb +28 -4
  44. data/lib/sparql/algebra/operator/exprlist.rb +12 -1
  45. data/lib/sparql/algebra/operator/extend.rb +33 -18
  46. data/lib/sparql/algebra/operator/filter.rb +27 -5
  47. data/lib/sparql/algebra/operator/floor.rb +26 -3
  48. data/lib/sparql/algebra/operator/graph.rb +13 -0
  49. data/lib/sparql/algebra/operator/greater_than.rb +14 -4
  50. data/lib/sparql/algebra/operator/greater_than_or_equal.rb +14 -4
  51. data/lib/sparql/algebra/operator/group.rb +34 -8
  52. data/lib/sparql/algebra/operator/group_concat.rb +20 -8
  53. data/lib/sparql/algebra/operator/hours.rb +24 -6
  54. data/lib/sparql/algebra/operator/if.rb +21 -4
  55. data/lib/sparql/algebra/operator/in.rb +18 -1
  56. data/lib/sparql/algebra/operator/insert.rb +22 -2
  57. data/lib/sparql/algebra/operator/insert_data.rb +23 -2
  58. data/lib/sparql/algebra/operator/iri.rb +22 -5
  59. data/lib/sparql/algebra/operator/is_blank.rb +20 -2
  60. data/lib/sparql/algebra/operator/is_iri.rb +20 -2
  61. data/lib/sparql/algebra/operator/is_literal.rb +20 -2
  62. data/lib/sparql/algebra/operator/is_numeric.rb +22 -4
  63. data/lib/sparql/algebra/operator/is_triple.rb +62 -0
  64. data/lib/sparql/algebra/operator/join.rb +22 -1
  65. data/lib/sparql/algebra/operator/lang.rb +26 -1
  66. data/lib/sparql/algebra/operator/lang_matches.rb +23 -2
  67. data/lib/sparql/algebra/operator/lcase.rb +24 -3
  68. data/lib/sparql/algebra/operator/left_join.rb +29 -1
  69. data/lib/sparql/algebra/operator/less_than.rb +14 -4
  70. data/lib/sparql/algebra/operator/less_than_or_equal.rb +14 -4
  71. data/lib/sparql/algebra/operator/load.rb +25 -2
  72. data/lib/sparql/algebra/operator/max.rb +18 -2
  73. data/lib/sparql/algebra/operator/md5.rb +23 -6
  74. data/lib/sparql/algebra/operator/min.rb +19 -3
  75. data/lib/sparql/algebra/operator/minus.rb +25 -7
  76. data/lib/sparql/algebra/operator/minutes.rb +24 -6
  77. data/lib/sparql/algebra/operator/modify.rb +41 -5
  78. data/lib/sparql/algebra/operator/month.rb +24 -6
  79. data/lib/sparql/algebra/operator/move.rb +20 -2
  80. data/lib/sparql/algebra/operator/multiply.rb +27 -4
  81. data/lib/sparql/algebra/operator/negate.rb +24 -4
  82. data/lib/sparql/algebra/operator/not.rb +25 -4
  83. data/lib/sparql/algebra/operator/not_equal.rb +16 -1
  84. data/lib/sparql/algebra/operator/notexists.rb +30 -6
  85. data/lib/sparql/algebra/operator/notin.rb +20 -3
  86. data/lib/sparql/algebra/operator/notoneof.rb +12 -2
  87. data/lib/sparql/algebra/operator/now.rb +25 -6
  88. data/lib/sparql/algebra/operator/object.rb +59 -0
  89. data/lib/sparql/algebra/operator/or.rb +26 -3
  90. data/lib/sparql/algebra/operator/order.rb +27 -2
  91. data/lib/sparql/algebra/operator/path.rb +29 -2
  92. data/lib/sparql/algebra/operator/path_opt.rb +21 -2
  93. data/lib/sparql/algebra/operator/path_plus.rb +21 -2
  94. data/lib/sparql/algebra/operator/path_star.rb +20 -2
  95. data/lib/sparql/algebra/operator/plus.rb +43 -4
  96. data/lib/sparql/algebra/operator/predicate.rb +59 -0
  97. data/lib/sparql/algebra/operator/prefix.rb +24 -3
  98. data/lib/sparql/algebra/operator/project.rb +51 -5
  99. data/lib/sparql/algebra/operator/rand.rb +31 -3
  100. data/lib/sparql/algebra/operator/reduced.rb +18 -1
  101. data/lib/sparql/algebra/operator/regex.rb +27 -19
  102. data/lib/sparql/algebra/operator/replace.rb +27 -7
  103. data/lib/sparql/algebra/operator/reverse.rb +20 -2
  104. data/lib/sparql/algebra/operator/round.rb +26 -3
  105. data/lib/sparql/algebra/operator/same_term.rb +25 -7
  106. data/lib/sparql/algebra/operator/sample.rb +31 -9
  107. data/lib/sparql/algebra/operator/seconds.rb +24 -6
  108. data/lib/sparql/algebra/operator/seq.rb +20 -2
  109. data/lib/sparql/algebra/operator/sequence.rb +0 -10
  110. data/lib/sparql/algebra/operator/sha1.rb +19 -2
  111. data/lib/sparql/algebra/operator/sha256.rb +19 -2
  112. data/lib/sparql/algebra/operator/sha384.rb +19 -2
  113. data/lib/sparql/algebra/operator/sha512.rb +19 -2
  114. data/lib/sparql/algebra/operator/slice.rb +27 -5
  115. data/lib/sparql/algebra/operator/str.rb +22 -2
  116. data/lib/sparql/algebra/operator/strafter.rb +26 -3
  117. data/lib/sparql/algebra/operator/strbefore.rb +26 -3
  118. data/lib/sparql/algebra/operator/strdt.rb +23 -2
  119. data/lib/sparql/algebra/operator/strends.rb +26 -4
  120. data/lib/sparql/algebra/operator/strlang.rb +26 -7
  121. data/lib/sparql/algebra/operator/strlen.rb +24 -3
  122. data/lib/sparql/algebra/operator/strstarts.rb +26 -3
  123. data/lib/sparql/algebra/operator/struuid.rb +30 -10
  124. data/lib/sparql/algebra/operator/subject.rb +61 -0
  125. data/lib/sparql/algebra/operator/substr.rb +24 -3
  126. data/lib/sparql/algebra/operator/subtract.rb +29 -3
  127. data/lib/sparql/algebra/operator/sum.rb +18 -2
  128. data/lib/sparql/algebra/operator/table.rb +42 -4
  129. data/lib/sparql/algebra/operator/timezone.rb +24 -6
  130. data/lib/sparql/algebra/operator/tz.rb +23 -6
  131. data/lib/sparql/algebra/operator/ucase.rb +24 -3
  132. data/lib/sparql/algebra/operator/union.rb +29 -6
  133. data/lib/sparql/algebra/operator/update.rb +25 -4
  134. data/lib/sparql/algebra/operator/using.rb +32 -2
  135. data/lib/sparql/algebra/operator/uuid.rb +28 -9
  136. data/lib/sparql/algebra/operator/with.rb +38 -4
  137. data/lib/sparql/algebra/operator/year.rb +24 -6
  138. data/lib/sparql/algebra/operator.rb +112 -7
  139. data/lib/sparql/algebra/sxp_extensions.rb +3 -3
  140. data/lib/sparql/grammar/meta.rb +5390 -2410
  141. data/lib/sparql/grammar/parser11.rb +119 -53
  142. data/lib/sparql/grammar/terminals11.rb +2 -0
  143. data/lib/sparql/grammar.rb +0 -25
  144. metadata +40 -34
@@ -5,7 +5,13 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # Applications can use the ASK form to test whether or not a query pattern has a solution. No information is returned about the possible query solutions, just whether or not a solution exists.
7
7
  #
8
- # @example
8
+ # [12] AskQuery ::= 'ASK' DatasetClause* WhereClause ValuesClause
9
+ #
10
+ # @example SPARQL Query
11
+ # PREFIX : <http://example/>
12
+ # ASK { :x :p ?x }
13
+ #
14
+ # @example SSE
9
15
  # (prefix ((: <http://example/>))
10
16
  # (ask
11
17
  # (bgp (triple :x :p ?x))))
@@ -41,6 +47,16 @@ module SPARQL; module Algebra
41
47
  def query_yields_boolean?
42
48
  true
43
49
  end
50
+
51
+ ##
52
+ #
53
+ # Returns a partial SPARQL grammar for this term.
54
+ #
55
+ # @return [String]
56
+ def to_sparql(**options)
57
+ "ASK\n" +
58
+ operands.first.to_sparql(top_level: true, project: nil, **options)
59
+ end
44
60
  end # Ask
45
61
  end # Operator
46
62
  end; end # SPARQL::Algebra
@@ -3,7 +3,14 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL `avg` set function.
5
5
  #
6
- # @example
6
+ # [127] Aggregate::= ... | 'AVG' '(' 'DISTINCT'? Expression ')'
7
+ #
8
+ # @example SPARQL Query
9
+ # PREFIX : <http://www.example.org/>
10
+ # SELECT (AVG(?o) AS ?avg)
11
+ # WHERE { ?s :dec ?o }
12
+ #
13
+ # @example SSE
7
14
  # (prefix ((: <http://www.example.org/>))
8
15
  # (project (?avg)
9
16
  # (extend ((?avg ??.0))
@@ -29,7 +36,7 @@ module SPARQL; module Algebra
29
36
  # @param [Enumerable<Array<RDF::Term>>] enum
30
37
  # enum of evaluated operand
31
38
  # @return [RDF::Literal::Numeric] The numeric average of the terms
32
- def apply(enum)
39
+ def apply(enum, **options)
33
40
  # FIXME: we don't actually do anything with distinct
34
41
  operands.shift if distinct = (operands.first == :distinct)
35
42
  if enum.empty?
@@ -40,6 +47,15 @@ module SPARQL; module Algebra
40
47
  raise TypeError, "Averaging non-numeric types: #{enum.flatten}"
41
48
  end
42
49
  end
50
+
51
+ ##
52
+ #
53
+ # Returns a partial SPARQL grammar for this operator.
54
+ #
55
+ # @return [String]
56
+ def to_sparql(**options)
57
+ "AVG(#{operands.to_sparql(**options)})"
58
+ end
43
59
  end # Avg
44
60
  end # Operator
45
61
  end; end # SPARQL::Algebra
@@ -3,7 +3,13 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL GraphPattern `base` operator.
5
5
  #
6
- # @example
6
+ # [5] BaseDecl ::= 'BASE' IRIREF
7
+ #
8
+ # @example SPARQL Grammar
9
+ # BASE <http://example.org/>
10
+ # SELECT * { <a> <b> 123.0 }
11
+ #
12
+ # @example SSE
7
13
  # (base <http://example.org/>
8
14
  # (bgp (triple <a> <b> 123.0)))
9
15
  #
@@ -56,6 +62,17 @@ module SPARQL; module Algebra
56
62
  def query_yields_statements?
57
63
  operands.last.query_yields_statements?
58
64
  end
65
+
66
+ ##
67
+ #
68
+ # Returns a partial SPARQL grammar for this term.
69
+ #
70
+ # @return [String]
71
+ def to_sparql(**options)
72
+ str = "BASE #{operands.first.to_sparql}\n"
73
+
74
+ str << operands.last.to_sparql(base_uri: operands.first, **options)
75
+ end
59
76
  end # Base
60
77
  end # Operator
61
78
  end; end # SPARQL::Algebra
@@ -5,7 +5,11 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # Query with `graph_name` set to false.
7
7
  #
8
- # @example
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://example/>
10
+ # SELECT * { :s :p :o }
11
+ #
12
+ # @example SSE
9
13
  # (prefix ((: <http://example/>))
10
14
  # (bgp (triple ?s ?p ?o)))
11
15
  #
@@ -5,16 +5,30 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # The BNODE function constructs a blank node that is distinct from all blank nodes in the dataset being queried and distinct from all blank nodes created by calls to this constructor for other query solutions. If the no argument form is used, every call results in a distinct blank node. If the form with a simple literal is used, every call results in distinct blank nodes for different simple literals, and the same blank node for calls with the same simple literal within expressions for one solution mapping.
7
7
  #
8
- # @example
9
- # (prefix ((: <http://example.org/>)
10
- # (xsd: <http://www.w3.org/2001/XMLSchema#>))
11
- # (project (?s1 ?s2 ?b1 ?b2)
12
- # (extend ((?b1 (bnode ?s1)) (?b2 (bnode ?s2)))
13
- # (filter (exprlist (|| (= ?a :s1) (= ?a :s3)) (|| (= ?b :s1) (= ?b :s3)))
14
- # (bgp
15
- # (triple ?a :str ?s1)
16
- # (triple ?b :str ?s2)
17
- # )))))
8
+ # [121] BuiltInCall ::= ... | 'BNODE' ( '(' Expression ')' | NIL )
9
+ #
10
+ # @example SPARQL Grammar
11
+ # PREFIX : <http://example.org/>
12
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
13
+ # SELECT ?s1 ?s2 (BNODE(?s1) AS ?b1) (BNODE(?s2) AS ?b2)
14
+ # WHERE {
15
+ # ?a :str ?s1 .
16
+ # ?b :str ?s2 .
17
+ # FILTER (?a = :s1 || ?a = :s3)
18
+ # FILTER (?b = :s1 || ?b = :s3)
19
+ # }
20
+ #
21
+ # @example SSE
22
+ # (prefix
23
+ # ((: <http://example.org/>) (xsd: <http://www.w3.org/2001/XMLSchema#>))
24
+ # (project (?s1 ?s2 ?b1 ?b2)
25
+ # (extend
26
+ # ((?b1 (bnode ?s1)) (?b2 (bnode ?s2)))
27
+ # (filter
28
+ # (exprlist
29
+ # (|| (= ?a :s1) (= ?a :s3))
30
+ # (|| (= ?b :s1) (= ?b :s3)))
31
+ # (bgp (triple ?a :str ?s1) (triple ?b :str ?s2))) )) )
18
32
  #
19
33
  # @see https://www.w3.org/TR/sparql11-query/#func-bnode
20
34
  class BNode < Operator::Unary
@@ -57,7 +71,7 @@ module SPARQL; module Algebra
57
71
  # a query solution containing zero or more variable bindings
58
72
  # @return [RDF::Node]
59
73
  # @raise [TypeError] if the operand is not a simple literal or nil
60
- def apply(literal, bindings)
74
+ def apply(literal, bindings, **options)
61
75
  @@bnode_base ||= "b0"
62
76
  @@bindings ||= bindings
63
77
  @@bnodes ||= {}
@@ -86,6 +100,15 @@ module SPARQL; module Algebra
86
100
  def to_sxp_bin
87
101
  [NAME] + operands.reject {|o| o == false}
88
102
  end
103
+
104
+ ##
105
+ #
106
+ # Returns a partial SPARQL grammar for this operator.
107
+ #
108
+ # @return [String]
109
+ def to_sparql(**options)
110
+ "BNODE(#{operands.last.to_sparql(**options)})"
111
+ end
89
112
  end # BNode
90
113
  end # Operator
91
114
  end; end # SPARQL::Algebra
@@ -3,7 +3,19 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL `bound` operator.
5
5
  #
6
- # @example
6
+ # [121] BuiltInCall ::= ... | 'BOUND' '(' Var ')'
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://example.org/ns#>
10
+ # SELECT ?a ?c
11
+ # WHERE
12
+ # { ?a :b ?c .
13
+ # OPTIONAL
14
+ # { ?c :d ?e } .
15
+ # FILTER (! bound(?e))
16
+ # }
17
+ #
18
+ # @example SSE
7
19
  # (prefix ((: <http://example.org/ns#>))
8
20
  # (project (?a ?c)
9
21
  # (filter (! (bound ?e))
@@ -46,6 +58,15 @@ module SPARQL; module Algebra
46
58
  else raise TypeError, "expected an RDF::Query::Variable, but got #{var.inspect}"
47
59
  end
48
60
  end
61
+
62
+ ##
63
+ #
64
+ # Returns a partial SPARQL grammar for this operator.
65
+ #
66
+ # @return [String]
67
+ def to_sparql(**options)
68
+ "bound(" + operands.first.to_sparql(**options) + ")"
69
+ end
49
70
  end # Bound
50
71
  end # Operator
51
72
  end; end # SPARQL::Algebra
@@ -3,8 +3,22 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL logical `ceil` operator.
5
5
  #
6
- # @example
7
- # (ceil ?x)
6
+ # [121] BuiltInCall ::= ... 'CEIL' '(' Expression ')'
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://example.org/>
10
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
11
+ # SELECT ?s ?num (CEIL(?num) AS ?ceil) WHERE {
12
+ # ?s :num ?num
13
+ # }
14
+ #
15
+ # @example SSE
16
+ # (prefix
17
+ # ((: <http://example.org/>)
18
+ # (xsd: <http://www.w3.org/2001/XMLSchema#>))
19
+ # (project (?s ?num ?ceil)
20
+ # (extend ((?ceil (ceil ?num)))
21
+ # (bgp (triple ?s :num ?num)))))
8
22
  #
9
23
  # @see https://www.w3.org/TR/sparql11-query/#func-ceil
10
24
  # @see https://www.w3.org/TR/xpath-functions/#func-ceil
@@ -20,12 +34,21 @@ module SPARQL; module Algebra
20
34
  # the operand
21
35
  # @return [RDF::Literal] literal of same type
22
36
  # @raise [TypeError] if the operand is not a numeric value
23
- def apply(operand)
37
+ def apply(operand, **options)
24
38
  case operand
25
39
  when RDF::Literal::Numeric then operand.ceil
26
40
  else raise TypeError, "expected an RDF::Literal::Numeric, but got #{operand.inspect}"
27
41
  end
28
42
  end
43
+
44
+ ##
45
+ #
46
+ # Returns a partial SPARQL grammar for this operator.
47
+ #
48
+ # @return [String]
49
+ def to_sparql(**options)
50
+ "CEIL(#{operands.to_sparql(**options)})"
51
+ end
29
52
  end # Ceil
30
53
  end # Operator
31
54
  end; end # SPARQL::Algebra
@@ -6,8 +6,13 @@ module SPARQL; module Algebra
6
6
  #
7
7
  # The CLEAR operation removes all the triples in the specified graph(s) in the Graph Store.
8
8
  #
9
- # @example
10
- # (clear silent default)
9
+ # [32] Clear ::= 'CLEAR' 'SILENT'? GraphRefAll
10
+ #
11
+ # @example SPARQL Grammar
12
+ # CLEAR SILENT DEFAULT
13
+ #
14
+ # @example SSE
15
+ # (update (clear silent default))
11
16
  #
12
17
  # @see https://www.w3.org/TR/sparql11-update/#clear
13
18
  class Clear < Operator
@@ -58,6 +63,15 @@ module SPARQL; module Algebra
58
63
 
59
64
  queryable
60
65
  end
66
+
67
+ ##
68
+ #
69
+ # Returns a partial SPARQL grammar for this operator.
70
+ #
71
+ # @return [String]
72
+ def to_sparql(**options)
73
+ "CLEAR " + operands.to_sparql(**options)
74
+ end
61
75
  end # Clear
62
76
  end # Operator
63
77
  end; end # SPARQL::Algebra
@@ -3,17 +3,30 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL `coalesce` function.
5
5
  #
6
- # @example
7
- # (prefix ((: <http://example.org/>)
8
- # (xsd: <http://www.w3.org/2001/XMLSchema#>))
9
- # (project (?cx ?div ?def ?err)
10
- # (extend ((?cx (coalesce ?x -1))
11
- # (?div (coalesce (/ ?o ?x) -2))
12
- # (?def (coalesce ?z -3))
13
- # (?err (coalesce ?z)))
14
- # (leftjoin
15
- # (bgp (triple ?s :p ?o))
16
- # (bgp (triple ?s :q ?x))))))
6
+ # [121] BuiltInCall ::= ... | 'COALESCE' ExpressionList
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://example/>
10
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
11
+ #
12
+ # SELECT ?X (SAMPLE(?v) AS ?S)
13
+ # {
14
+ # ?s :p ?v .
15
+ # OPTIONAL { ?s :q ?w }
16
+ # }
17
+ # GROUP BY (COALESCE(?w, "1605-11-05"^^xsd:date) AS ?X)
18
+ #
19
+ # @example SSE
20
+ # (prefix
21
+ # ((: <http://example/>) (xsd: <http://www.w3.org/2001/XMLSchema#>))
22
+ # (project (?X ?S)
23
+ # (extend ((?S ??.0))
24
+ # (group
25
+ # ((?X (coalesce ?w "1605-11-05"^^xsd:date)))
26
+ # ((??.0 (sample ?v)))
27
+ # (leftjoin
28
+ # (bgp (triple ?s :p ?v))
29
+ # (bgp (triple ?s :q ?w)))))))
17
30
  #
18
31
  # @see https://www.w3.org/TR/sparql11-query/#func-coalesce
19
32
  class Coalesce < Operator
@@ -50,6 +63,15 @@ module SPARQL; module Algebra
50
63
  end
51
64
  raise TypeError, "None of the operands evaluated"
52
65
  end
66
+
67
+ ##
68
+ #
69
+ # Returns a partial SPARQL grammar for this operator.
70
+ #
71
+ # @return [String]
72
+ def to_sparql(**options)
73
+ "COALESCE(#{operands.to_sparql(delimiter: ', ', **options)})"
74
+ end
53
75
  end # Coalesce
54
76
  end # Operator
55
77
  end; end # SPARQL::Algebra
@@ -30,62 +30,77 @@ module SPARQL; module Algebra
30
30
  # @param [RDF::Literal] right
31
31
  # a literal
32
32
  # @return [RDF::Literal::Integer] `-1`, `0`, or `1`
33
- # @raise [TypeError] if either operand is not a literal
34
- def apply(left, right)
33
+ # @raise [TypeError] if either operand is not a term
34
+ def apply(left, right, **options)
35
+ RDF::Literal(spaceship(left, right, **options))
36
+ end
37
+
38
+ ##
39
+ #
40
+ # Returns a partial SPARQL grammar for this operator.
41
+ #
42
+ # @return [String]
43
+ def to_sparql(**options)
44
+ "(#{operands.first.to_sparql(**options)} #{self.class.const_get(:NAME)} #{operands.last.to_sparql(**options)})"
45
+ end
46
+
47
+ private
48
+ # Define <=> as private for recursive statements
49
+ def spaceship(left, right, **options)
35
50
  case
36
51
  # @see https://www.w3.org/TR/sparql11-query/#OperatorMapping
37
52
  # @see https://www.w3.org/TR/sparql11-query/#modOrderBy
38
53
  when left.is_a?(RDF::Literal) && right.is_a?(RDF::Literal)
39
- case
40
54
  # @see https://www.w3.org/TR/xpath-functions/#string-compare
41
55
  # @see https://www.w3.org/TR/xpath-functions/#comp.numeric
42
56
  # @see https://www.w3.org/TR/xpath-functions/#op.boolean
43
57
  # @see https://www.w3.org/TR/xpath-functions/#comp.duration.datetime
44
- when (left.simple? && right.simple?) ||
45
- (left.is_a?(RDF::Literal::Numeric) && right.is_a?(RDF::Literal::Numeric)) ||
46
- (left.datatype == right.datatype && left.language == right.language)
47
- RDF::Literal(left.send(self.class.const_get(:NAME), right))
48
-
49
- # A plain literal is lower than an RDF literal with type xsd:string of the same lexical form.
50
- when left.simple? && right.datatype == RDF::XSD.string && left.value == right.value
51
- RDF::Literal(-1)
52
- when right.simple? && left.datatype == RDF::XSD.string && right.value == left.value
53
- RDF::Literal(-1)
54
-
55
- else
56
- left <=> right
57
- end
58
-
58
+ left <=> right
59
59
  when left.is_a?(RDF::URI) && right.is_a?(RDF::URI)
60
+ raise TypeError, "Comparing IRIs not supported" unless options[:order_by] || left == right
60
61
  # Pairs of IRIs are ordered by comparing them as simple literals.
61
- RDF::Literal(RDF::Literal(left.to_s).send(self.class.const_get(:NAME), RDF::Literal(right.to_s)))
62
+ left.to_s <=> right.to_s
62
63
  when left.is_a?(RDF::Node) && right.is_a?(RDF::Node)
64
+ raise TypeError, "Comparing Blank nodes not supported" unless options[:order_by] || left == right
63
65
  # BNode comparison is undefined.
64
- RDF::Literal(0)
66
+ left == right ? 0 : 1
65
67
  when left.nil? && right.nil?
66
- RDF::Literal(0)
67
-
68
+ 0
69
+
70
+ when left.is_a?(RDF::Statement) && right.is_a?(RDF::Statement)
71
+ v = spaceship(left.subject, right.subject, **options)
72
+ v = spaceship(left.predicate, right.predicate, **options) if v == 0
73
+ v = spaceship(left.object, right.object, **options) if v == 0
74
+ v
75
+ when left.is_a?(RDF::Statement) && right.is_a?(RDF::Term)
76
+ raise TypeError, "Comparing statement with #{right.inspect}" unless options[:order_by]
77
+ 1
78
+ when right.is_a?(RDF::Statement) && left.is_a?(RDF::Term)
79
+ raise TypeError, "Comparing statement with #{left.inspect}" unless options[:order_by]
80
+ -1
81
+
68
82
  # SPARQL also fixes an order between some kinds of RDF terms that would not otherwise be ordered:
69
83
 
70
84
  when left.nil? && !right.nil?
71
- RDF::Literal(-1)
85
+ -1
72
86
  when right.nil?
73
- RDF::Literal(1)
87
+ 1
74
88
 
75
89
  when left.is_a?(RDF::Node) && right.is_a?(RDF::Term)
76
- RDF::Literal(-1)
90
+ raise TypeError, "Comparing Blank nodes not supported" unless options[:order_by]
91
+ # Nodes lower than other terms
92
+ -1
77
93
  when right.is_a?(RDF::Node) && left.is_a?(RDF::Term)
78
- RDF::Literal(1)
79
-
80
- when left.is_a?(RDF::Node) && right.is_a?(RDF::URI)
81
- RDF::Literal(-1)
82
- when right.is_a?(RDF::Node) && left.is_a?(RDF::URI)
83
- RDF::Literal(1)
94
+ raise TypeError, "Comparing Blank nodes not supported" unless options[:order_by]
95
+ 1
84
96
 
85
97
  when left.is_a?(RDF::URI) && right.is_a?(RDF::Term)
86
- RDF::Literal(-1)
98
+ raise TypeError, "Comparing IRIs not supported" unless options[:order_by]
99
+ # IRIs lower than terms other than nodes
100
+ -1
87
101
  when right.is_a?(RDF::URI) && left.is_a?(RDF::Term)
88
- RDF::Literal(1)
102
+ raise TypeError, "Comparing IRIs not supported" unless options[:order_by]
103
+ 1
89
104
  else raise TypeError, "expected two RDF::Term operands, but got #{left.inspect} and #{right.inspect}"
90
105
  end
91
106
  end
@@ -5,8 +5,23 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # The CONCAT function corresponds to the XPath fn:concat function. The function accepts string literals as arguments.
7
7
  #
8
- # @example
9
- # (concat ?a ?b ...)
8
+ # [121] BuiltInCall ::= ... 'CONCAT' ExpressionList
9
+ #
10
+ # @example SPARQL Grammar
11
+ # PREFIX : <http://example.org/>
12
+ # SELECT (CONCAT(?str1,?str2) AS ?str) WHERE {
13
+ # :s6 :str ?str1 .
14
+ # :s7 :str ?str2 .
15
+ # }
16
+ #
17
+ # @example SSE
18
+ # (prefix
19
+ # ((: <http://example.org/>))
20
+ # (project (?str)
21
+ # (extend ((?str (concat ?str1 ?str2)))
22
+ # (bgp
23
+ # (triple :s6 :str ?str1)
24
+ # (triple :s7 :str ?str2)))))
10
25
  #
11
26
  # @see https://www.w3.org/TR/sparql11-query/#func-concat
12
27
  # @see https://www.w3.org/TR/xpath-functions/#func-concat
@@ -48,6 +63,15 @@ module SPARQL; module Algebra
48
63
  end
49
64
  end
50
65
  end
66
+
67
+ ##
68
+ #
69
+ # Returns a partial SPARQL grammar for this operator.
70
+ #
71
+ # @return [String]
72
+ def to_sparql(**options)
73
+ "CONCAT(#{operands.to_sparql(delimiter: ', ', **options)})"
74
+ end
51
75
  end # Concat
52
76
  end # Operator
53
77
  end; end # SPARQL::Algebra
@@ -5,12 +5,22 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # The CONSTRUCT query form returns a single RDF graph specified by a graph template. The result is an RDF graph formed by taking each query solution in the solution sequence, substituting for the variables in the graph template, and combining the triples into a single RDF graph by set union.
7
7
  #
8
- # @example
9
- # (prefix ((rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
10
- # (foaf: <http://xmlns.com/foaf/0.1/>))
11
- # (construct ((triple ?s ?p ?o))
12
- # (project (?s ?p ?o)
13
- # (bgp (triple ?s ?p ?o)))))
8
+ # [10] ConstructQuery ::= 'CONSTRUCT' ( ConstructTemplate DatasetClause* WhereClause SolutionModifier | DatasetClause* 'WHERE' '{' TriplesTemplate? '}' SolutionModifier ) ValuesClause
9
+ #
10
+ # @example SPARQL Grammar
11
+ # PREFIX : <http://example/>
12
+ # CONSTRUCT { ?x :p2 ?v }
13
+ # WHERE {
14
+ # ?x :p ?o .
15
+ # OPTIONAL {?o :q ?v }
16
+ # }
17
+ #
18
+ # @example SSE
19
+ # (prefix ((: <http://example/>))
20
+ # (construct ((triple ?x :p2 ?v))
21
+ # (leftjoin
22
+ # (bgp (triple ?x :p ?o))
23
+ # (bgp (triple ?o :q ?v)))))
14
24
  #
15
25
  # @see https://www.w3.org/TR/sparql11-query/#construct
16
26
  class Construct < Operator::Binary
@@ -52,10 +62,11 @@ module SPARQL; module Algebra
52
62
  terms[r] = case o = pattern.send(r)
53
63
  when RDF::Node then nodes[o] ||= RDF::Node.new
54
64
  when RDF::Query::Variable then solution[o]
65
+ when RDF::Query::Pattern then RDF::Statement.from(o.dup.bind(solution))
55
66
  else o
56
67
  end
57
68
  end
58
-
69
+
59
70
  statement = RDF::Statement.from(terms)
60
71
 
61
72
  # Sanity checking on statement
@@ -80,6 +91,19 @@ module SPARQL; module Algebra
80
91
  def query_yields_statements?
81
92
  true
82
93
  end
94
+
95
+ ##
96
+ #
97
+ # Returns a partial SPARQL grammar for this term.
98
+ #
99
+ # @return [String]
100
+ def to_sparql(**options)
101
+ str = "CONSTRUCT {\n" +
102
+ operands[0].map { |e| e.to_sparql(as_statement: true, top_level: false, **options) }.join("\n") +
103
+ "\n}\n"
104
+
105
+ str << operands[1].to_sparql(top_level: true, project: nil, **options)
106
+ end
83
107
  end # Construct
84
108
  end # Operator
85
109
  end; end # SPARQL::Algebra
@@ -3,8 +3,21 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # A SPARQL `contains` operator.
5
5
  #
6
- # @example
7
- # (contains ?x ?y)
6
+ # [121] BuiltInCall ::= ... | 'CONTAINS' '(' Expression ',' Expression ')'
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://example.org/>
10
+ # SELECT ?s ?str WHERE {
11
+ # ?s :str ?str
12
+ # FILTER CONTAINS(?str, "a")
13
+ # }
14
+ #
15
+ # @example SSE
16
+ # (prefix
17
+ # ((: <http://example.org/>))
18
+ # (project (?s ?str)
19
+ # (filter (contains ?str "a")
20
+ # (bgp (triple ?s :str ?str)))))
8
21
  #
9
22
  # @see https://www.w3.org/TR/sparql11-query/#func-contains
10
23
  # @see https://www.w3.org/TR/xpath-functions/#func-contains
@@ -31,7 +44,7 @@ module SPARQL; module Algebra
31
44
  # a literal
32
45
  # @return [RDF::Literal::Boolean]
33
46
  # @raise [TypeError] if operands are not compatible
34
- def apply(left, right)
47
+ def apply(left, right, **options)
35
48
  case
36
49
  when !left.compatible?(right)
37
50
  raise TypeError, "expected two RDF::Literal operands, but got #{left.inspect} and #{right.inspect}"
@@ -39,6 +52,15 @@ module SPARQL; module Algebra
39
52
  else RDF::Literal::FALSE
40
53
  end
41
54
  end
55
+
56
+ ##
57
+ #
58
+ # Returns a partial SPARQL grammar for this operator.
59
+ #
60
+ # @return [String]
61
+ def to_sparql(**options)
62
+ "contains(" + operands.to_sparql(delimiter: ', ', **options) + ")"
63
+ end
42
64
  end # Contains
43
65
  end # Operator
44
66
  end; end # SPARQL::Algebra
@@ -6,8 +6,13 @@ module SPARQL; module Algebra
6
6
  #
7
7
  # The COPY operation is a shortcut for inserting all data from an input graph into a destination graph. Data from the input graph is not affected, but data from the destination graph, if any, is removed before insertion.
8
8
  #
9
- # @example
10
- # (copy silent <iri> to default)
9
+ # [37] Copy ::= 'COPY' 'SILENT'? GraphOrDefault 'TO' GraphOrDefault
10
+ #
11
+ # @example SPARQL Grammar
12
+ # COPY SILENT GRAPH <http://www.example.com/g1> TO DEFAULT
13
+ #
14
+ # @example SSE
15
+ # (update (copy silent <http://www.example.com/g1> default))
11
16
  #
12
17
  # @see https://www.w3.org/TR/sparql11-update/#copy
13
18
  class Copy < Operator
@@ -59,6 +64,18 @@ module SPARQL; module Algebra
59
64
  end
60
65
  queryable
61
66
  end
67
+
68
+ ##
69
+ #
70
+ # Returns a partial SPARQL grammar for this operator.
71
+ #
72
+ # @return [String]
73
+ def to_sparql(**options)
74
+ *args, last = operands.dup
75
+ args += [:TO, last]
76
+
77
+ "COPY " + args.to_sparql(**options)
78
+ end
62
79
  end # Copy
63
80
  end # Operator
64
81
  end; end # SPARQL::Algebra