sparql 3.1.8 → 3.2.3

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -60
  3. data/VERSION +1 -1
  4. data/bin/sparql +15 -35
  5. data/lib/rack/sparql/conneg.rb +22 -1
  6. data/lib/sinatra/sparql/extensions.rb +1 -1
  7. data/lib/sinatra/sparql.rb +57 -12
  8. data/lib/sparql/algebra/expression.rb +63 -10
  9. data/lib/sparql/algebra/extensions.rb +110 -46
  10. data/lib/sparql/algebra/operator/abs.rb +22 -2
  11. data/lib/sparql/algebra/operator/add.rb +21 -2
  12. data/lib/sparql/algebra/operator/adjust.rb +69 -0
  13. data/lib/sparql/algebra/operator/alt.rb +26 -2
  14. data/lib/sparql/algebra/operator/and.rb +25 -3
  15. data/lib/sparql/algebra/operator/asc.rb +20 -1
  16. data/lib/sparql/algebra/operator/ask.rb +17 -1
  17. data/lib/sparql/algebra/operator/avg.rb +19 -1
  18. data/lib/sparql/algebra/operator/base.rb +18 -1
  19. data/lib/sparql/algebra/operator/bgp.rb +13 -1
  20. data/lib/sparql/algebra/operator/bnode.rb +33 -10
  21. data/lib/sparql/algebra/operator/bound.rb +22 -1
  22. data/lib/sparql/algebra/operator/ceil.rb +25 -2
  23. data/lib/sparql/algebra/operator/clear.rb +26 -2
  24. data/lib/sparql/algebra/operator/coalesce.rb +33 -11
  25. data/lib/sparql/algebra/operator/compare.rb +9 -0
  26. data/lib/sparql/algebra/operator/concat.rb +26 -2
  27. data/lib/sparql/algebra/operator/construct.rb +29 -6
  28. data/lib/sparql/algebra/operator/contains.rb +24 -2
  29. data/lib/sparql/algebra/operator/copy.rb +19 -2
  30. data/lib/sparql/algebra/operator/count.rb +52 -6
  31. data/lib/sparql/algebra/operator/create.rb +20 -2
  32. data/lib/sparql/algebra/operator/dataset.rb +37 -2
  33. data/lib/sparql/algebra/operator/datatype.rb +25 -6
  34. data/lib/sparql/algebra/operator/day.rb +25 -7
  35. data/lib/sparql/algebra/operator/delete.rb +29 -2
  36. data/lib/sparql/algebra/operator/delete_data.rb +23 -2
  37. data/lib/sparql/algebra/operator/delete_where.rb +24 -2
  38. data/lib/sparql/algebra/operator/desc.rb +20 -1
  39. data/lib/sparql/algebra/operator/describe.rb +27 -4
  40. data/lib/sparql/algebra/operator/distinct.rb +20 -3
  41. data/lib/sparql/algebra/operator/divide.rb +26 -2
  42. data/lib/sparql/algebra/operator/drop.rb +27 -3
  43. data/lib/sparql/algebra/operator/encode_for_uri.rb +22 -2
  44. data/lib/sparql/algebra/operator/equal.rb +12 -2
  45. data/lib/sparql/algebra/operator/exists.rb +28 -4
  46. data/lib/sparql/algebra/operator/exprlist.rb +15 -2
  47. data/lib/sparql/algebra/operator/extend.rb +95 -7
  48. data/lib/sparql/algebra/operator/filter.rb +27 -5
  49. data/lib/sparql/algebra/operator/floor.rb +25 -2
  50. data/lib/sparql/algebra/operator/function_call.rb +64 -0
  51. data/lib/sparql/algebra/operator/graph.rb +69 -6
  52. data/lib/sparql/algebra/operator/greater_than.rb +12 -3
  53. data/lib/sparql/algebra/operator/greater_than_or_equal.rb +12 -2
  54. data/lib/sparql/algebra/operator/group.rb +133 -8
  55. data/lib/sparql/algebra/operator/group_concat.rb +43 -7
  56. data/lib/sparql/algebra/operator/hours.rb +25 -7
  57. data/lib/sparql/algebra/operator/if.rb +20 -3
  58. data/lib/sparql/algebra/operator/in.rb +18 -1
  59. data/lib/sparql/algebra/operator/insert.rb +24 -2
  60. data/lib/sparql/algebra/operator/insert_data.rb +23 -2
  61. data/lib/sparql/algebra/operator/iri.rb +21 -4
  62. data/lib/sparql/algebra/operator/is_blank.rb +20 -3
  63. data/lib/sparql/algebra/operator/is_iri.rb +20 -3
  64. data/lib/sparql/algebra/operator/is_literal.rb +20 -3
  65. data/lib/sparql/algebra/operator/is_numeric.rb +22 -5
  66. data/lib/sparql/algebra/operator/is_triple.rb +32 -0
  67. data/lib/sparql/algebra/operator/join.rb +58 -3
  68. data/lib/sparql/algebra/operator/lang.rb +25 -0
  69. data/lib/sparql/algebra/operator/lang_matches.rb +22 -1
  70. data/lib/sparql/algebra/operator/lcase.rb +22 -2
  71. data/lib/sparql/algebra/operator/left_join.rb +44 -3
  72. data/lib/sparql/algebra/operator/less_than.rb +12 -3
  73. data/lib/sparql/algebra/operator/less_than_or_equal.rb +12 -2
  74. data/lib/sparql/algebra/operator/load.rb +25 -2
  75. data/lib/sparql/algebra/operator/max.rb +19 -1
  76. data/lib/sparql/algebra/operator/md5.rb +22 -5
  77. data/lib/sparql/algebra/operator/min.rb +21 -3
  78. data/lib/sparql/algebra/operator/minus.rb +65 -7
  79. data/lib/sparql/algebra/operator/minutes.rb +25 -7
  80. data/lib/sparql/algebra/operator/modify.rb +62 -5
  81. data/lib/sparql/algebra/operator/month.rb +25 -7
  82. data/lib/sparql/algebra/operator/move.rb +20 -2
  83. data/lib/sparql/algebra/operator/multiply.rb +26 -3
  84. data/lib/sparql/algebra/operator/negate.rb +23 -3
  85. data/lib/sparql/algebra/operator/not.rb +24 -3
  86. data/lib/sparql/algebra/operator/not_equal.rb +13 -0
  87. data/lib/sparql/algebra/operator/notexists.rb +30 -6
  88. data/lib/sparql/algebra/operator/notin.rb +20 -3
  89. data/lib/sparql/algebra/operator/notoneof.rb +21 -2
  90. data/lib/sparql/algebra/operator/now.rb +24 -5
  91. data/lib/sparql/algebra/operator/object.rb +32 -0
  92. data/lib/sparql/algebra/operator/or.rb +26 -3
  93. data/lib/sparql/algebra/operator/order.rb +64 -1
  94. data/lib/sparql/algebra/operator/path.rb +29 -2
  95. data/lib/sparql/algebra/operator/path_opt.rb +28 -65
  96. data/lib/sparql/algebra/operator/path_plus.rb +37 -10
  97. data/lib/sparql/algebra/operator/path_range.rb +178 -0
  98. data/lib/sparql/algebra/operator/path_star.rb +25 -4
  99. data/lib/sparql/algebra/operator/path_zero.rb +110 -0
  100. data/lib/sparql/algebra/operator/plus.rb +49 -8
  101. data/lib/sparql/algebra/operator/predicate.rb +32 -0
  102. data/lib/sparql/algebra/operator/prefix.rb +24 -3
  103. data/lib/sparql/algebra/operator/project.rb +111 -6
  104. data/lib/sparql/algebra/operator/rand.rb +30 -2
  105. data/lib/sparql/algebra/operator/reduced.rb +20 -3
  106. data/lib/sparql/algebra/operator/regex.rb +26 -18
  107. data/lib/sparql/algebra/operator/replace.rb +26 -6
  108. data/lib/sparql/algebra/operator/reverse.rb +31 -2
  109. data/lib/sparql/algebra/operator/round.rb +25 -2
  110. data/lib/sparql/algebra/operator/same_term.rb +24 -6
  111. data/lib/sparql/algebra/operator/sample.rb +32 -8
  112. data/lib/sparql/algebra/operator/seconds.rb +25 -7
  113. data/lib/sparql/algebra/operator/seq.rb +23 -5
  114. data/lib/sparql/algebra/operator/sequence.rb +14 -11
  115. data/lib/sparql/algebra/operator/sha1.rb +18 -1
  116. data/lib/sparql/algebra/operator/sha256.rb +18 -1
  117. data/lib/sparql/algebra/operator/sha384.rb +18 -1
  118. data/lib/sparql/algebra/operator/sha512.rb +18 -1
  119. data/lib/sparql/algebra/operator/slice.rb +27 -5
  120. data/lib/sparql/algebra/operator/str.rb +21 -1
  121. data/lib/sparql/algebra/operator/strafter.rb +25 -2
  122. data/lib/sparql/algebra/operator/strbefore.rb +25 -2
  123. data/lib/sparql/algebra/operator/strdt.rb +22 -1
  124. data/lib/sparql/algebra/operator/strends.rb +25 -3
  125. data/lib/sparql/algebra/operator/strlang.rb +24 -6
  126. data/lib/sparql/algebra/operator/strlen.rb +23 -2
  127. data/lib/sparql/algebra/operator/strstarts.rb +25 -2
  128. data/lib/sparql/algebra/operator/struuid.rb +29 -9
  129. data/lib/sparql/algebra/operator/subject.rb +32 -0
  130. data/lib/sparql/algebra/operator/substr.rb +23 -2
  131. data/lib/sparql/algebra/operator/subtract.rb +37 -7
  132. data/lib/sparql/algebra/operator/sum.rb +24 -6
  133. data/lib/sparql/algebra/operator/table.rb +85 -4
  134. data/lib/sparql/algebra/operator/timezone.rb +25 -7
  135. data/lib/sparql/algebra/operator/triple.rb +24 -0
  136. data/lib/sparql/algebra/operator/tz.rb +24 -7
  137. data/lib/sparql/algebra/operator/ucase.rb +23 -2
  138. data/lib/sparql/algebra/operator/union.rb +29 -6
  139. data/lib/sparql/algebra/operator/update.rb +46 -4
  140. data/lib/sparql/algebra/operator/using.rb +49 -2
  141. data/lib/sparql/algebra/operator/uuid.rb +27 -8
  142. data/lib/sparql/algebra/operator/with.rb +38 -4
  143. data/lib/sparql/algebra/operator/year.rb +25 -7
  144. data/lib/sparql/algebra/operator.rb +150 -12
  145. data/lib/sparql/algebra/query.rb +5 -3
  146. data/lib/sparql/algebra/sxp_extensions.rb +3 -3
  147. data/lib/sparql/algebra.rb +42 -6
  148. data/lib/sparql/grammar/meta.rb +1367 -267
  149. data/lib/sparql/grammar/parser11.rb +829 -331
  150. data/lib/sparql/grammar/terminals11.rb +2 -2
  151. data/lib/sparql/grammar.rb +6 -4
  152. data/lib/sparql/results.rb +3 -2
  153. data/lib/sparql/server.rb +93 -0
  154. data/lib/sparql.rb +8 -5
  155. metadata +57 -35
@@ -5,12 +5,23 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # There is a filter operator EXISTS that takes a graph pattern. EXISTS returns `true`/`false` depending on whether the pattern matches the dataset given the bindings in the current group graph pattern, the dataset and the active graph at this point in the query evaluation. No additional binding of variables occurs. The `NOT EXISTS` form translates into `fn:not(EXISTS{...})`.
7
7
  #
8
- # @example
9
- # (prefix ((ex: <http://www.example.org/>))
10
- # (filter (exists
11
- # (filter (notexists (bgp (triple ?s ?p ex:o2)))
12
- # (bgp (triple ?s ?p ex:o1))))
13
- # (bgp (triple ?s ?p ex:o))))
8
+ # [126] NotExistsFunc ::= 'NOT' 'EXISTS' GroupGraphPattern
9
+ #
10
+ # @example SPARQL Grammar
11
+ # PREFIX ex: <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/negation#>
12
+ # SELECT ?animal {
13
+ # ?animal a ex:Animal
14
+ # FILTER NOT EXISTS { ?animal a ex:Insect }
15
+ # }
16
+ #
17
+ # @example SSE
18
+ # (prefix
19
+ # ((ex: <http://www.w3.org/2009/sparql/docs/tests/data-sparql11/negation#>))
20
+ # (project (?animal)
21
+ # (filter
22
+ # (notexists
23
+ # (bgp (triple ?animal a ex:Insect)))
24
+ # (bgp (triple ?animal a ex:Animal)))) )
14
25
  #
15
26
  # @see https://www.w3.org/TR/sparql11-query/#func-abs
16
27
  # @see https://www.w3.org/TR/xpath-functions/#func-abs
@@ -34,6 +45,19 @@ module SPARQL; module Algebra
34
45
  queryable = options[:queryable]
35
46
  operand(0).execute(queryable, solutions: solutions, **options).empty?
36
47
  end
48
+
49
+ ##
50
+ #
51
+ # Returns a partial SPARQL grammar for this operator.
52
+ #
53
+ # @param [Boolean] top_level (true)
54
+ # Treat this as a top-level, generating SELECT ... WHERE {}
55
+ # @return [String]
56
+ def to_sparql(top_level: true, **options)
57
+ "NOT EXISTS {\n" +
58
+ operands.last.to_sparql(top_level: false, **options) +
59
+ "\n}"
60
+ end
37
61
  end # NotExists
38
62
  end # Operator
39
63
  end; end # SPARQL::Algebra
@@ -5,8 +5,13 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # Used for filters with more than one expression.
7
7
  #
8
- # @example
9
- # (ask (filter (notin ?o 1 2) (bgp)))
8
+ # [114] RelationalExpression ::= NumericExpression ('NOT' 'IN' ExpressionList)?
9
+ #
10
+ # @example SPARQL Grammar
11
+ # ASK { FILTER(2 NOT IN ()) }
12
+ #
13
+ # @example SSE
14
+ # (ask (filter (notin 2) (bgp)))
10
15
  #
11
16
  # @see https://www.w3.org/TR/sparql11-query/#func-notin
12
17
  class NotIn < Operator
@@ -58,6 +63,18 @@ module SPARQL; module Algebra
58
63
  else RDF::Literal::TRUE
59
64
  end
60
65
  end
61
- end # Exprlist
66
+
67
+ ##
68
+ #
69
+ # Returns a partial SPARQL grammar for this operator.
70
+ #
71
+ # @return [String]
72
+ def to_sparql(**options)
73
+ "(" + operands.first.to_sparql(**options) +
74
+ " NOT IN (" +
75
+ operands[1..-1].map {|e| e.to_sparql(**options)}.join(", ") +
76
+ "))"
77
+ end
78
+ end # NotIn
62
79
  end # Operator
63
80
  end; end # SPARQL::Algebra
@@ -3,8 +3,18 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL Property Path `notoneof` (NegatedPropertySet) operator.
5
5
  #
6
- # @example
7
- # (notoneof ex:p1 ex:p2)
6
+ # [96] PathOneInPropertySet ::= iri | 'a' | '^' ( iri | 'a' )
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX ex: <http://www.example.org/schema#>
10
+ # PREFIX in: <http://www.example.org/instance#>
11
+ # ASK { in:a !(ex:p1|ex:p2) ?x }
12
+ #
13
+ # @example SSE
14
+ # (prefix ((ex: <http://www.example.org/schema#>)
15
+ # (in: <http://www.example.org/instance#>))
16
+ # (ask
17
+ # (path in:a (notoneof ex:p1 ex:p2) ?x)))
8
18
  #
9
19
  # @see https://www.w3.org/TR/sparql11-query/#eval_negatedPropertySet
10
20
  class NotOneOf < Operator
@@ -46,6 +56,15 @@ module SPARQL; module Algebra
46
56
  block.call(solution)
47
57
  end
48
58
  end
59
+
60
+ ##
61
+ #
62
+ # Returns a partial SPARQL grammar for this operator.
63
+ #
64
+ # @return [String]
65
+ def to_sparql(**options)
66
+ "!(" + operands.to_sparql(delimiter: ' | ', **options) + ')'
67
+ end
49
68
  end # NotOneOf
50
69
  end # Operator
51
70
  end; end # SPARQL::Algebra
@@ -7,11 +7,21 @@ module SPARQL; module Algebra
7
7
  #
8
8
  # Returns an XSD dateTime value for the current query execution. All calls to this function in any one query execution must return the same value. The exact moment returned is not specified.
9
9
  #
10
- # @example
11
- # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>))
12
- # (ask (filter (= (datatype ?n) xsd:dateTime)
13
- # (extend ((?n (now)))
14
- # (bgp)))))
10
+ # [121] BuiltInCall ::= ... | 'NOW' NIL
11
+ #
12
+ # @example SPARQL Grammar
13
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
14
+ # ASK {
15
+ # BIND(NOW() AS ?n)
16
+ # FILTER(DATATYPE(?n) = xsd:dateTime)
17
+ # }
18
+ #
19
+ # @example SSE
20
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>))
21
+ # (ask
22
+ # (filter (= (datatype ?n) xsd:dateTime)
23
+ # (extend ((?n (now)))
24
+ # (bgp)))))
15
25
  #
16
26
  # @see https://www.w3.org/TR/sparql11-query/#func-now
17
27
  class Now < Operator::Nullary
@@ -26,6 +36,15 @@ module SPARQL; module Algebra
26
36
  def apply(**options)
27
37
  RDF::Literal(DateTime.now)
28
38
  end
39
+
40
+ ##
41
+ #
42
+ # Returns a partial SPARQL grammar for this operator.
43
+ #
44
+ # @return [String]
45
+ def to_sparql(**options)
46
+ "NOW()"
47
+ end
29
48
  end # Now
30
49
  end # Operator
31
50
  end; end # SPARQL::Algebra
@@ -5,6 +5,29 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # If triple is an RDF-star triple, the function returns the object of this triple. Passing anything other than an RDF-star triple is an error.
7
7
  #
8
+ # [121] BuiltInCall ::= ... | 'OBJECT' '(' Expression ')'
9
+ #
10
+ # @example SPARQL Grammar
11
+ # PREFIX : <http://example.com/ns#>
12
+ # SELECT * {
13
+ # ?t :source :g
14
+ # FILTER(isTriple(?t))
15
+ # FILTER(SUBJECT(?t) = :s)
16
+ # FILTER(PREDICATE(?t) = :p)
17
+ # FILTER(OBJECT(?t) = :o)
18
+ # }
19
+ #
20
+ # @example SSE
21
+ # (prefix
22
+ # ((: <http://example.com/ns#>))
23
+ # (filter
24
+ # (exprlist
25
+ # (isTRIPLE ?t)
26
+ # (= (subject ?t) :s)
27
+ # (= (predicate ?t) :p)
28
+ # (= (object ?t) :o))
29
+ # (bgp (triple ?t :source :g))) )
30
+ #
8
31
  # @see https://w3c.github.io/rdf-star/rdf-star-cg-spec.html#object
9
32
  class Object < Operator::Unary
10
33
  include Evaluatable
@@ -22,6 +45,15 @@ module SPARQL; module Algebra
22
45
  raise TypeError, "expected an RDF::Statement, but got #{operand.inspect}" unless operand.is_a?(RDF::Statement)
23
46
  operand.object
24
47
  end
48
+
49
+ ##
50
+ #
51
+ # Returns a partial SPARQL grammar for this operator.
52
+ #
53
+ # @return [String]
54
+ def to_sparql(**options)
55
+ "OBJECT(" + operands.last.to_sparql(**options) + ")"
56
+ end
25
57
  end # Object
26
58
  end # Operator
27
59
  end; end # SPARQL::Algebra
@@ -3,9 +3,23 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL logical `or` operator.
5
5
  #
6
- # @example
7
- # (|| ?x ?y)
8
- # (or ?x ?y)
6
+ # [111] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )*
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
10
+ # PREFIX : <http://example.org/ns#>
11
+ # SELECT ?a
12
+ # WHERE {
13
+ # ?a :p ?v .
14
+ # FILTER ("false"^^xsd:boolean || ?v) .
15
+ # }
16
+ #
17
+ # @example SSE
18
+ # (prefix ((xsd: <http://www.w3.org/2001/XMLSchema#>)
19
+ # (: <http://example.org/ns#>))
20
+ # (project (?a)
21
+ # (filter (|| false ?v)
22
+ # (bgp (triple ?a :p ?v)))))
9
23
  #
10
24
  # @see https://www.w3.org/TR/sparql11-query/#func-logical-or
11
25
  # @see https://www.w3.org/TR/sparql11-query/#evaluation
@@ -63,6 +77,15 @@ module SPARQL; module Algebra
63
77
  else RDF::Literal(left || right)
64
78
  end
65
79
  end
80
+
81
+ ##
82
+ #
83
+ # Returns a partial SPARQL grammar for this operator.
84
+ #
85
+ # @return [String]
86
+ def to_sparql(**options)
87
+ "(#{operands.first.to_sparql(**options)} || #{operands.last.to_sparql(**options)})"
88
+ end
66
89
  end # Or
67
90
  end # Operator
68
91
  end; end # SPARQL::Algebra
@@ -3,12 +3,64 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL GraphPattern `order` operator.
5
5
  #
6
- # @example
6
+ # [23] OrderClause ::= 'ORDER' 'BY' OrderCondition+
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX foaf: <http://xmlns.com/foaf/0.1/>
10
+ # SELECT ?name
11
+ # WHERE { ?x foaf:name ?name }
12
+ # ORDER BY ASC(?name)
13
+ #
14
+ # @example SSE
7
15
  # (prefix ((foaf: <http://xmlns.com/foaf/0.1/>))
8
16
  # (project (?name)
9
17
  # (order ((asc ?name))
10
18
  # (bgp (triple ?x foaf:name ?name)))))
11
19
  #
20
+ # @example SPARQL Grammar (with builtin)
21
+ # PREFIX : <http://example.org/>
22
+ # SELECT ?s WHERE {
23
+ # ?s :p ?o .
24
+ # }
25
+ # ORDER BY str(?o)
26
+ #
27
+ # @example SSE (with builtin)
28
+ # (prefix ((: <http://example.org/>))
29
+ # (project (?s)
30
+ # (order ((str ?o))
31
+ # (bgp (triple ?s :p ?o)))))
32
+ #
33
+ # @example SPARQL Grammar (with bracketed expression)
34
+ # PREFIX : <http://example.org/>
35
+ # SELECT ?s WHERE {
36
+ # ?s :p ?o1 ; :q ?o2 .
37
+ # } ORDER BY (?o1 + ?o2)
38
+ #
39
+ # @example SSE (with bracketed expression)
40
+ # (prefix
41
+ # ((: <http://example.org/>))
42
+ # (project (?s)
43
+ # (order ((+ ?o1 ?o2))
44
+ # (bgp
45
+ # (triple ?s :p ?o1)
46
+ # (triple ?s :q ?o2)))))
47
+ #
48
+ # @example SPARQL Grammar (with function call)
49
+ # PREFIX : <http://example.org/ns#>
50
+ # PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
51
+ # SELECT *
52
+ # { ?s ?p ?o }
53
+ # ORDER BY
54
+ # DESC(?o+57) xsd:string(?o) ASC(?s)
55
+ #
56
+ # @example SSE (with function call)
57
+ # (prefix ((: <http://example.org/ns#>)
58
+ # (xsd: <http://www.w3.org/2001/XMLSchema#>))
59
+ # (order ((desc (+ ?o 57))
60
+ # (xsd:string ?o)
61
+ # (asc ?s))
62
+ # (bgp (triple ?s ?p ?o))))
63
+ #
12
64
  # @see https://www.w3.org/TR/sparql11-query/#modOrderBy
13
65
  class Order < Operator::Binary
14
66
  include Query
@@ -56,6 +108,17 @@ module SPARQL; module Algebra
56
108
  @solutions.each(&block) if block_given?
57
109
  @solutions
58
110
  end
111
+
112
+ ##
113
+ #
114
+ # Returns a partial SPARQL grammar for this operator.
115
+ #
116
+ # Provides order to descendant query.
117
+ #
118
+ # @return [String]
119
+ def to_sparql(**options)
120
+ operands.last.to_sparql(order_ops: operands.first, **options)
121
+ end
59
122
  end # Order
60
123
  end # Operator
61
124
  end; end # SPARQL::Algebra
@@ -3,8 +3,23 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL Property Path `path` operator.
5
5
  #
6
- # @example
7
- # (path :a (path+ :p) ?z)
6
+ # [88] Path ::= PathAlternative
7
+ #
8
+ # @example SPARQL Grammar
9
+ # PREFIX : <http://www.example.org/>
10
+ # SELECT ?t
11
+ # WHERE {
12
+ # :a :p1|:p2/:p3|:p4 ?t
13
+ # }
14
+ #
15
+ # @example SSE
16
+ # (prefix ((: <http://www.example.org/>))
17
+ # (project (?t)
18
+ # (path :a
19
+ # (alt
20
+ # (alt :p1 (seq :p2 :p3))
21
+ # :p4)
22
+ # ?t)))
8
23
  #
9
24
  # @see https://www.w3.org/TR/sparql11-query/#sparqlTranslatePathExpressions
10
25
  class Path < Operator::Ternary
@@ -45,6 +60,18 @@ module SPARQL; module Algebra
45
60
  @solutions.each(&block) if block_given?
46
61
  @solutions
47
62
  end
63
+
64
+ ##
65
+ #
66
+ # Returns a partial SPARQL grammar for this operator.
67
+ #
68
+ # @param [Boolean] top_level (true)
69
+ # Treat this as a top-level, generating SELECT ... WHERE {}
70
+ # @return [String]
71
+ def to_sparql(top_level: true, **options)
72
+ str = operands.to_sparql(top_level: false, **options) + " ."
73
+ top_level ? Operator.to_sparql(str, **options) : str
74
+ end
48
75
  end # Path
49
76
  end # Operator
50
77
  end; end # SPARQL::Algebra
@@ -3,8 +3,18 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL Property Path `path?` (ZeroOrOnePath) operator.
5
5
  #
6
- # @example
7
- # (path? :p)
6
+ # [91] PathElt ::= PathPrimary PathMod?
7
+ # [93] PathMod ::= '*' | '?' | '+' | '{' INTEGER? (',' INTEGER?)? '}'
8
+
9
+ # @example SPARQL Grammar
10
+ # PREFIX : <http://example/>
11
+ # SELECT * WHERE {
12
+ # :a (:p/:p)? ?t
13
+ # }
14
+ #
15
+ # @example SSE
16
+ # (prefix ((: <http://example/>))
17
+ # (path :a (path? (seq :p :p)) ?t))
8
18
  #
9
19
  # @see https://www.w3.org/TR/sparql11-query/#defn_evalPP_ZeroOrOnePath
10
20
  class PathOpt < Operator::Unary
@@ -13,11 +23,10 @@ module SPARQL; module Algebra
13
23
  NAME = :path?
14
24
 
15
25
  ##
16
- # Equivalent to:
26
+ # Optional path:
17
27
  #
18
28
  # (path x (path? :p) y)
19
- # => (union (bgp ((x :p y))) (filter (x = x) (solution x y)))
20
- #
29
+ # => (union (bgp ((x :p y))) (filter (x = y) (solution x y)))
21
30
  #
22
31
  # @param [RDF::Queryable] queryable
23
32
  # the graph or repository to query
@@ -34,79 +43,33 @@ module SPARQL; module Algebra
34
43
  subject, object = options[:subject], options[:object]
35
44
  debug(options) {"Path? #{[subject, operands, object].to_sse}"}
36
45
 
37
- solutions = RDF::Query::Solutions.new
38
- # Solutions where subject == object with no predicate
39
- case
40
- when subject.variable? && object.variable?
41
- # Nodes is the set of all subjects and objects in queryable
42
- # FIXME: should this be Queryable#enum_nodes?
43
- # All subjects which are `object`
44
- query = RDF::Query.new {|q| q.pattern({subject: subject})}
45
- queryable.query(query, **options) do |solution|
46
- solution.merge!(object.to_sym => solution[subject])
47
- debug(options) {"(solution-s0)-> #{solution.to_h.to_sse}"}
48
- solutions << solution
49
- end if query.valid?
50
-
51
- # All objects which are `object`
52
- query = RDF::Query.new {|q| q.pattern({object: object})}
53
- queryable.query(query, **options) do |solution|
54
- solution.merge!(subject.to_sym => solution[object])
55
- debug(options) {"(solution-o0)-> #{solution.to_h.to_sse}"}
56
- solutions << solution
57
- end if query.valid?
58
- when subject.variable?
59
- # All subjects which are `object`
60
- query = RDF::Query.new {|q| q.pattern({subject: object})}
61
- queryable.query(query, **options) do |solution|
62
- solution.merge!(subject.to_sym => object)
63
- debug(options) {"(solution-s0)-> #{solution.to_h.to_sse}"}
64
- solutions << solution
65
- end if query.valid?
66
-
67
- # All objects which are `object`
68
- query = RDF::Query.new {|q| q.pattern({object: object})}
69
- queryable.query(query, **options) do |solution|
70
- solution.merge!(subject.to_sym => object)
71
- debug(options) {"(solution-o0)-> #{solution.to_h.to_sse}"}
72
- solutions << solution
73
- end if query.valid?
74
- when object.variable?
75
- # All subjects which are `subject`
76
- query = RDF::Query.new {|q| q.pattern({subject: subject})}
77
- queryable.query(query, **options) do |solution|
78
- solution.merge!(object.to_sym => subject)
79
- debug(options) {"(solution-s0)-> #{solution.to_h.to_sse}"}
80
- solutions << solution
81
- end if query.valid?
82
-
83
- # All objects which are `subject
84
- query = RDF::Query.new {|q| q.pattern({object: subject})}
85
- queryable.query(query, **options) do |solution|
86
- solution.merge!(object.to_sym => subject)
87
- debug(options) {"(solution-o0)-> #{solution.to_h.to_sse}"}
88
- solutions << solution
89
- end if query.valid?
90
- else
91
- # Otherwise, if subject == object, an empty solution
92
- solutions << RDF::Query::Solution.new if subject == object
93
- end
46
+ query = PathZero.new(operand)
47
+ solutions = query.execute(queryable, **options.merge(depth: options[:depth].to_i + 1))
94
48
 
95
49
  # Solutions where predicate exists
96
50
  query = if operand.is_a?(RDF::Term)
97
51
  RDF::Query.new do |q|
98
52
  q.pattern [subject, operand, object]
99
53
  end
100
- else
54
+ else # path
101
55
  operand
102
56
  end
103
57
 
104
58
  # Recurse into query
105
- solutions +=
106
- queryable.query(query, depth: options[:depth].to_i + 1, **options)
59
+ solutions += query.execute(queryable, **options.merge(depth: options[:depth].to_i + 1))
60
+ debug(options) {"(path?)=> #{solutions.to_sxp}"}
107
61
  solutions.each(&block) if block_given?
108
62
  solutions
109
63
  end
64
+
65
+ ##
66
+ #
67
+ # Returns a partial SPARQL grammar for this operator.
68
+ #
69
+ # @return [String]
70
+ def to_sparql(**options)
71
+ "(#{operands.first.to_sparql(**options)})?"
72
+ end
110
73
  end # PathOpt
111
74
  end # Operator
112
75
  end; end # SPARQL::Algebra
@@ -3,8 +3,18 @@ module SPARQL; module Algebra
3
3
  ##
4
4
  # The SPARQL Property Path `path+` (OneOrMorePath) operator.
5
5
  #
6
- # @example
7
- # (path+ :p)
6
+ # [91] PathElt ::= PathPrimary PathMod?
7
+ # [93] PathMod ::= '*' | '?' | '+' | '{' INTEGER? (',' INTEGER?)? '}'
8
+
9
+ # @example SPARQL Grammar
10
+ # PREFIX : <http://example/>
11
+ # SELECT * WHERE {
12
+ # :a :p+ ?z
13
+ # }
14
+ #
15
+ # @example SSE
16
+ # (prefix ((: <http://example/>))
17
+ # (path :a (path+ :p) ?z))
8
18
  #
9
19
  # @see https://www.w3.org/TR/sparql11-query/#defn_evalPP_OneOrMorePath
10
20
  class PathPlus < Operator::Unary
@@ -15,6 +25,16 @@ module SPARQL; module Algebra
15
25
  ##
16
26
  # Match on simple relation of subject to object, and then recurse on solutions
17
27
  #
28
+ # Path including at least one:
29
+ #
30
+ # (path :a (path+ :p) :b)
31
+ #
32
+ # into
33
+ #
34
+ # (union
35
+ # (bgp (triple :a :p :b))
36
+ # (path :a (path* :p) :b))
37
+ #
18
38
  # @param [RDF::Queryable] queryable
19
39
  # the graph or repository to query
20
40
  # @param [Hash{Symbol => Object}] options
@@ -52,10 +72,8 @@ module SPARQL; module Algebra
52
72
 
53
73
  # Keep track of solutions
54
74
  # Recurse into query
55
- immediate_solutions = []
56
- queryable.query(query, depth: options[:depth].to_i + 1, **options) do |solution|
57
- immediate_solutions << solution
58
- end
75
+ immediate_solutions =
76
+ query.execute(queryable, depth: options[:depth].to_i + 1, **options)
59
77
 
60
78
  # For all solutions, if they are not in the accumulator, add them and recurse, otherwise skip
61
79
  recursive_solutions = RDF::Query::Solutions.new
@@ -66,23 +84,23 @@ module SPARQL; module Algebra
66
84
  case
67
85
  when subject.variable? && object.variable?
68
86
  # Query starting with bound object as subject, but replace result with subject
69
- rs = queryable.query(self, **options.merge(
87
+ rs = self.execute(queryable, **options.merge(
70
88
  subject: solution[object],
71
89
  accumulator: (cumulative_solutions + immediate_solutions),
72
90
  depth: options[:depth].to_i + 1)).map {|s| s.merge(subject.to_sym => solution[subject])}
73
91
  # Query starting with bound subject as object, but replace result with subject
74
- ro = queryable.query(self, **options.merge(
92
+ ro = self.execute(queryable, **options.merge(
75
93
  object: solution[subject],
76
94
  accumulator: (cumulative_solutions + immediate_solutions),
77
95
  depth: options[:depth].to_i + 1)).map {|s| s.merge(object.to_sym => solution[object])}
78
96
  recursive_solutions += (rs + ro).uniq
79
97
  when subject.variable?
80
- recursive_solutions += queryable.query(self, **options.merge(
98
+ recursive_solutions += self.execute(queryable, **options.merge(
81
99
  object: solution[subject],
82
100
  accumulator: (cumulative_solutions + immediate_solutions),
83
101
  depth: options[:depth].to_i + 1)).uniq
84
102
  when object.variable?
85
- recursive_solutions += queryable.query(self, **options.merge(
103
+ recursive_solutions += self.execute(queryable, **options.merge(
86
104
  subject: solution[object],
87
105
  accumulator: (cumulative_solutions + immediate_solutions),
88
106
  depth: options[:depth].to_i + 1)).uniq
@@ -94,6 +112,15 @@ module SPARQL; module Algebra
94
112
  solutions.each(&block) if block_given? # Only at top-level
95
113
  solutions
96
114
  end
115
+
116
+ ##
117
+ #
118
+ # Returns a partial SPARQL grammar for this operator.
119
+ #
120
+ # @return [String]
121
+ def to_sparql(**options)
122
+ "(#{operands.first.to_sparql(**options)})+"
123
+ end
97
124
  end # PathPlus
98
125
  end # Operator
99
126
  end; end # SPARQL::Algebra