sparql 3.2.0 → 3.2.1
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.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/VERSION +1 -1
- data/lib/sparql/algebra/expression.rb +28 -3
- data/lib/sparql/algebra/extensions.rb +36 -32
- data/lib/sparql/algebra/operator/abs.rb +1 -1
- data/lib/sparql/algebra/operator/alt.rb +1 -1
- data/lib/sparql/algebra/operator/avg.rb +3 -1
- data/lib/sparql/algebra/operator/bgp.rb +9 -1
- data/lib/sparql/algebra/operator/clear.rb +13 -3
- data/lib/sparql/algebra/operator/construct.rb +1 -1
- data/lib/sparql/algebra/operator/count.rb +36 -6
- data/lib/sparql/algebra/operator/create.rb +5 -4
- data/lib/sparql/algebra/operator/dataset.rb +19 -11
- data/lib/sparql/algebra/operator/delete.rb +3 -1
- data/lib/sparql/algebra/operator/delete_data.rb +1 -1
- data/lib/sparql/algebra/operator/delete_where.rb +1 -1
- data/lib/sparql/algebra/operator/distinct.rb +2 -2
- data/lib/sparql/algebra/operator/divide.rb +1 -1
- data/lib/sparql/algebra/operator/drop.rb +15 -6
- data/lib/sparql/algebra/operator/encode_for_uri.rb +2 -4
- data/lib/sparql/algebra/operator/exprlist.rb +3 -1
- data/lib/sparql/algebra/operator/extend.rb +36 -3
- data/lib/sparql/algebra/operator/filter.rb +1 -1
- data/lib/sparql/algebra/operator/function_call.rb +64 -0
- data/lib/sparql/algebra/operator/graph.rb +57 -7
- data/lib/sparql/algebra/operator/group.rb +76 -5
- data/lib/sparql/algebra/operator/group_concat.rb +25 -1
- data/lib/sparql/algebra/operator/if.rb +10 -10
- data/lib/sparql/algebra/operator/insert.rb +3 -1
- data/lib/sparql/algebra/operator/insert_data.rb +1 -1
- data/lib/sparql/algebra/operator/is_blank.rb +1 -2
- data/lib/sparql/algebra/operator/is_iri.rb +1 -2
- data/lib/sparql/algebra/operator/is_literal.rb +1 -2
- data/lib/sparql/algebra/operator/is_numeric.rb +1 -2
- data/lib/sparql/algebra/operator/join.rb +37 -3
- data/lib/sparql/algebra/operator/lcase.rb +2 -3
- data/lib/sparql/algebra/operator/left_join.rb +20 -7
- data/lib/sparql/algebra/operator/max.rb +3 -1
- data/lib/sparql/algebra/operator/min.rb +4 -2
- data/lib/sparql/algebra/operator/minus.rb +46 -6
- data/lib/sparql/algebra/operator/multiply.rb +1 -1
- data/lib/sparql/algebra/operator/notoneof.rb +12 -3
- data/lib/sparql/algebra/operator/order.rb +44 -0
- data/lib/sparql/algebra/operator/plus.rb +1 -1
- data/lib/sparql/algebra/operator/project.rb +22 -4
- data/lib/sparql/algebra/operator/reduced.rb +3 -3
- data/lib/sparql/algebra/operator/regex.rb +1 -1
- data/lib/sparql/algebra/operator/reverse.rb +12 -1
- data/lib/sparql/algebra/operator/sample.rb +3 -1
- data/lib/sparql/algebra/operator/seq.rb +1 -1
- data/lib/sparql/algebra/operator/sequence.rb +4 -1
- data/lib/sparql/algebra/operator/strlang.rb +1 -2
- data/lib/sparql/algebra/operator/subtract.rb +1 -1
- data/lib/sparql/algebra/operator/sum.rb +9 -7
- data/lib/sparql/algebra/operator/table.rb +41 -7
- data/lib/sparql/algebra/operator/ucase.rb +1 -1
- data/lib/sparql/algebra/operator/update.rb +22 -1
- data/lib/sparql/algebra/operator/using.rb +18 -1
- data/lib/sparql/algebra/operator/with.rb +1 -1
- data/lib/sparql/algebra/operator.rb +46 -18
- data/lib/sparql/algebra.rb +20 -3
- data/lib/sparql/grammar/parser11.rb +3 -3
- metadata +15 -2
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module SPARQL; module Algebra
|
3
|
+
class Operator
|
4
|
+
##
|
5
|
+
# The SPARQL `function_call` operator.
|
6
|
+
#
|
7
|
+
# [70] FunctionCall ::= iri ArgList
|
8
|
+
#
|
9
|
+
# @example SPARQL Grammar
|
10
|
+
# PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
11
|
+
# SELECT *
|
12
|
+
# WHERE { ?s ?p ?o . FILTER xsd:integer(?o) }
|
13
|
+
#
|
14
|
+
# @example SSE
|
15
|
+
# (prefix
|
16
|
+
# ((xsd: <http://www.w3.org/2001/XMLSchema#>))
|
17
|
+
# (filter (xsd:integer ?o)
|
18
|
+
# (bgp (triple ?s ?p ?o))))
|
19
|
+
#
|
20
|
+
# @see https://www.w3.org/TR/sparql11-query/#funcex-regex
|
21
|
+
# @see https://www.w3.org/TR/xpath-functions/#func-matches
|
22
|
+
class FunctionCall < Operator
|
23
|
+
include Evaluatable
|
24
|
+
|
25
|
+
NAME = :function_call
|
26
|
+
|
27
|
+
##
|
28
|
+
# Invokes the function with the passed arguments.
|
29
|
+
#
|
30
|
+
# @param [RDF::IRI] iri
|
31
|
+
# Identifies the function
|
32
|
+
# @param [Array<RDF::Term>] args
|
33
|
+
# @return [RDF::Term]
|
34
|
+
def apply(iri, *args, **options)
|
35
|
+
args = RDF.nil == args.last ? args[0..-2] : args
|
36
|
+
SPARQL::Algebra::Expression.extension(iri, *args, **options)
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# Returns the SPARQL S-Expression (SSE) representation of this expression.
|
41
|
+
#
|
42
|
+
# Remove the optional argument.
|
43
|
+
#
|
44
|
+
# @return [Array] `self`
|
45
|
+
# @see https://openjena.org/wiki/SSE
|
46
|
+
def to_sxp_bin
|
47
|
+
@operands.map(&:to_sxp_bin)
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
#
|
52
|
+
# Returns a partial SPARQL grammar for this operator.
|
53
|
+
#
|
54
|
+
# @return [String]
|
55
|
+
def to_sparql(**options)
|
56
|
+
iri, args = operands
|
57
|
+
iri.to_sparql(**options) +
|
58
|
+
'(' +
|
59
|
+
args.to_sparql(delimiter: ', ', **options) +
|
60
|
+
')'
|
61
|
+
end
|
62
|
+
end # FunctionCall
|
63
|
+
end # Operator
|
64
|
+
end; end # SPARQL::Algebra
|
@@ -7,7 +7,7 @@ module SPARQL; module Algebra
|
|
7
7
|
#
|
8
8
|
# [58] GraphGraphPattern ::= 'GRAPH' VarOrIri GroupGraphPattern
|
9
9
|
#
|
10
|
-
# @example SPARQL Grammar
|
10
|
+
# @example SPARQL Grammar (query)
|
11
11
|
# PREFIX : <http://example/>
|
12
12
|
# SELECT * {
|
13
13
|
# GRAPH ?g { ?s ?p ?o }
|
@@ -18,15 +18,50 @@ module SPARQL; module Algebra
|
|
18
18
|
# (graph ?g
|
19
19
|
# (bgp (triple ?s ?p ?o))))
|
20
20
|
#
|
21
|
-
# @example of
|
21
|
+
# @example SPARQL Grammar (named set of statements)
|
22
|
+
# PREFIX : <http://example/>
|
23
|
+
# SELECT * {
|
24
|
+
# GRAPH :g { :s :p :o }
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# @example SSE (named set of statements)
|
22
28
|
# (prefix ((: <http://example/>))
|
29
|
+
# (graph :g
|
30
|
+
# (bgp (triple :s :p :o))))
|
31
|
+
#
|
32
|
+
# @example SPARQL Grammar (syntax-graph-05.rq)
|
33
|
+
# PREFIX : <http://example.org/>
|
34
|
+
# SELECT *
|
35
|
+
# WHERE
|
36
|
+
# {
|
37
|
+
# :x :p :z
|
38
|
+
# GRAPH ?g { :x :b ?a . GRAPH ?g2 { :x :p ?x } }
|
39
|
+
# }
|
40
|
+
#
|
41
|
+
# @example SSE (syntax-graph-05.rq)
|
42
|
+
# (prefix ((: <http://example.org/>))
|
43
|
+
# (join
|
44
|
+
# (bgp (triple :x :p :z))
|
23
45
|
# (graph ?g
|
24
|
-
#
|
46
|
+
# (join
|
47
|
+
# (bgp (triple :x :b ?a))
|
48
|
+
# (graph ?g2
|
49
|
+
# (bgp (triple :x :p ?x)))))))
|
25
50
|
#
|
26
|
-
# @example
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
51
|
+
# @example SPARQL Grammar (pp06.rq)
|
52
|
+
# prefix ex: <http://www.example.org/schema#>
|
53
|
+
# prefix in: <http://www.example.org/instance#>
|
54
|
+
#
|
55
|
+
# select ?x where {
|
56
|
+
# graph ?g {in:a ex:p1/ex:p2 ?x}
|
57
|
+
# }
|
58
|
+
#
|
59
|
+
# @example SSE (syntax-graph-05.rq)
|
60
|
+
# (prefix ((ex: <http://www.example.org/schema#>)
|
61
|
+
# (in: <http://www.example.org/instance#>))
|
62
|
+
# (project (?x)
|
63
|
+
# (graph ?g
|
64
|
+
# (path in:a (seq ex:p1 ex:p2) ?x))))
|
30
65
|
#
|
31
66
|
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
|
32
67
|
class Graph < Operator::Binary
|
@@ -89,6 +124,21 @@ module SPARQL; module Algebra
|
|
89
124
|
def rewrite(&block)
|
90
125
|
self
|
91
126
|
end
|
127
|
+
|
128
|
+
##
|
129
|
+
#
|
130
|
+
# Returns a partial SPARQL grammar for this operator.
|
131
|
+
#
|
132
|
+
# @param [Boolean] top_level (true)
|
133
|
+
# Treat this as a top-level, generating SELECT ... WHERE {}
|
134
|
+
# @return [String]
|
135
|
+
def to_sparql(top_level: true, **options)
|
136
|
+
query = operands.last.to_sparql(top_level: false, **options)
|
137
|
+
# Paths don't automatically get braces.
|
138
|
+
query = "{\n#{query}\n}" unless query.start_with?('{')
|
139
|
+
str = "GRAPH #{operands.first.to_sparql(**options)} " + query
|
140
|
+
top_level ? Operator.to_sparql(str, **options) : str
|
141
|
+
end
|
92
142
|
end # Graph
|
93
143
|
end # Operator
|
94
144
|
end; end # SPARQL::Algebra
|
@@ -25,6 +25,37 @@ module SPARQL; module Algebra
|
|
25
25
|
# (group (?P) ((??.0 (count ?O)))
|
26
26
|
# (bgp (triple ?S ?P ?O))))))
|
27
27
|
#
|
28
|
+
# @example SPARQL Grammar (HAVING aggregate)
|
29
|
+
# PREFIX : <http://www.example.org/>
|
30
|
+
# SELECT ?s (AVG(?o) AS ?avg)
|
31
|
+
# WHERE { ?s ?p ?o }
|
32
|
+
# GROUP BY ?s
|
33
|
+
# HAVING (AVG(?o) <= 2.0)
|
34
|
+
#
|
35
|
+
# @example SSE (HAVING aggregate)
|
36
|
+
# (prefix ((: <http://www.example.org/>))
|
37
|
+
# (project (?s ?avg)
|
38
|
+
# (filter (<= ??.0 2.0)
|
39
|
+
# (extend ((?avg ??.0))
|
40
|
+
# (group (?s) ((??.0 (avg ?o)))
|
41
|
+
# (bgp (triple ?s ?p ?o)))))) )
|
42
|
+
#
|
43
|
+
# @example SPARQL Grammar (non-triveal filters)
|
44
|
+
# PREFIX : <http://example.com/data/#>
|
45
|
+
# SELECT ?g (AVG(?p) AS ?avg) ((MIN(?p) + MAX(?p)) / 2 AS ?c)
|
46
|
+
# WHERE { ?g :p ?p . }
|
47
|
+
# GROUP BY ?g
|
48
|
+
#
|
49
|
+
# @example SSE (non-triveal filters)
|
50
|
+
# (prefix ((: <http://example.com/data/#>))
|
51
|
+
# (project (?g ?avg ?c)
|
52
|
+
# (extend ((?avg ??.0) (?c (/ (+ ??.1 ??.2) 2)))
|
53
|
+
# (group (?g)
|
54
|
+
# ((??.0 (avg ?p))
|
55
|
+
# (??.1 (min ?p))
|
56
|
+
# (??.2 (max ?p)))
|
57
|
+
# (bgp (triple ?g :p ?p)))) ))
|
58
|
+
#
|
28
59
|
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
|
29
60
|
class Group < Operator
|
30
61
|
include Query
|
@@ -137,16 +168,56 @@ module SPARQL; module Algebra
|
|
137
168
|
#
|
138
169
|
# @param [Hash{Symbol => Operator}] extensions
|
139
170
|
# Variable bindings
|
171
|
+
# @param [Array<Operator>] filter_ops ([])
|
172
|
+
# Filter Operations
|
140
173
|
# @return [String]
|
141
|
-
def to_sparql(extensions: {}, **options)
|
174
|
+
def to_sparql(extensions: {}, filter_ops: [], **options)
|
175
|
+
having_ops = []
|
142
176
|
if operands.length > 2
|
177
|
+
temp_bindings = operands[1].inject({}) {|memo, (var, op)| memo.merge(var => op)}
|
143
178
|
# Replace extensions from temporary bindings
|
144
|
-
|
145
|
-
|
146
|
-
extensions
|
179
|
+
temp_bindings.each do |var, op|
|
180
|
+
# Update extensions using a temporarily bound variable with its binding
|
181
|
+
extensions = extensions.inject({}) do |memo, (ext_var, ext_op)|
|
182
|
+
if ext_op.is_a?(Operator)
|
183
|
+
# Try to recursivley replace variable within operator
|
184
|
+
new_op = ext_op.deep_dup.rewrite do |operand|
|
185
|
+
if operand.is_a?(Variable) && operand.to_sym == var.to_sym
|
186
|
+
op.dup
|
187
|
+
else
|
188
|
+
operand
|
189
|
+
end
|
190
|
+
end
|
191
|
+
memo.merge(ext_var => new_op)
|
192
|
+
elsif ext_op.is_a?(Variable) && ext_op.to_sym == var.to_sym
|
193
|
+
memo.merge(ext_var => op)
|
194
|
+
else
|
195
|
+
# Doesn't match this variable, so don't change
|
196
|
+
memo.merge(ext_var => ext_op)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Filter ops using temporary bindinds are used for HAVING clauses
|
201
|
+
filter_ops.each do |fop|
|
202
|
+
having_ops << fop if fop.descendants.include?(var) && !having_ops.include?(fop)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# If used in a HAVING clause, it's not also a filter
|
207
|
+
filter_ops -= having_ops
|
208
|
+
|
209
|
+
# Replace each operand in having using var with it's corresponding operation
|
210
|
+
having_ops = having_ops.map do |op|
|
211
|
+
op.dup.rewrite do |operand|
|
212
|
+
# Rewrite based on temporary bindings
|
213
|
+
temp_bindings.fetch(operand, operand)
|
214
|
+
end
|
147
215
|
end
|
148
216
|
end
|
149
|
-
operands.last.to_sparql(extensions: extensions,
|
217
|
+
operands.last.to_sparql(extensions: extensions,
|
218
|
+
group_ops: operands.first,
|
219
|
+
having_ops: having_ops,
|
220
|
+
**options)
|
150
221
|
end
|
151
222
|
end # Group
|
152
223
|
end # Operator
|
@@ -16,6 +16,24 @@ module SPARQL; module Algebra
|
|
16
16
|
# (group () ((??.0 (group_concat ?x)))
|
17
17
|
# (bgp))))
|
18
18
|
#
|
19
|
+
# @example SPARQL Grammar (DISTINCT)
|
20
|
+
# SELECT (GROUP_CONCAT(DISTINCT ?x) AS ?y) {}
|
21
|
+
#
|
22
|
+
# @example SSE (DISTINCT)
|
23
|
+
# (project (?y)
|
24
|
+
# (extend ((?y ??.0))
|
25
|
+
# (group () ((??.0 (group_concat distinct ?x)))
|
26
|
+
# (bgp))))
|
27
|
+
#
|
28
|
+
# @example SPARQL Grammar (SEPARATOR)
|
29
|
+
# SELECT (GROUP_CONCAT(?x; SEPARATOR=';') AS ?y) {}
|
30
|
+
#
|
31
|
+
# @example SSE (SEPARATOR)
|
32
|
+
# (project (?y)
|
33
|
+
# (extend ((?y ??.0))
|
34
|
+
# (group () ((??.0 (group_concat (separator ";") ?x)))
|
35
|
+
# (bgp))))
|
36
|
+
#
|
19
37
|
# @see https://www.w3.org/TR/sparql11-query/#defn_aggGroupConcat
|
20
38
|
class GroupConcat < Operator
|
21
39
|
include Aggregate
|
@@ -63,7 +81,13 @@ module SPARQL; module Algebra
|
|
63
81
|
#
|
64
82
|
# @return [String]
|
65
83
|
def to_sparql(**options)
|
66
|
-
|
84
|
+
distinct = operands.first == :distinct
|
85
|
+
args = distinct ? operands[1..-1] : operands
|
86
|
+
separator = args.first.last if args.first.is_a?(Array) && args.first.first == :separator
|
87
|
+
args = args[1..-1] if separator
|
88
|
+
str = "GROUP_CONCAT(#{'DISTINCT ' if distinct}#{args.to_sparql(delimiter: ', ', **options)}"
|
89
|
+
str << "; SEPARATOR=#{separator.to_sparql}" if separator
|
90
|
+
str << ")"
|
67
91
|
end
|
68
92
|
end # GroupConcat
|
69
93
|
end # Operator
|
@@ -48,15 +48,15 @@ module SPARQL; module Algebra
|
|
48
48
|
rescue
|
49
49
|
raise TypeError
|
50
50
|
end
|
51
|
-
end # If
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
52
|
+
##
|
53
|
+
#
|
54
|
+
# Returns a partial SPARQL grammar for this operator.
|
55
|
+
#
|
56
|
+
# @return [String]
|
57
|
+
def to_sparql(**options)
|
58
|
+
"IF(" + operands.to_sparql(delimiter: ', ', **options) + ")"
|
59
|
+
end
|
60
|
+
end # If
|
61
|
+
end # Operator
|
62
62
|
end; end # SPARQL::Algebra
|
@@ -69,7 +69,9 @@ module SPARQL; module Algebra
|
|
69
69
|
#
|
70
70
|
# @return [String]
|
71
71
|
def to_sparql(**options)
|
72
|
-
"INSERT {\n" +
|
72
|
+
"INSERT {\n" +
|
73
|
+
operands.first.to_sparql(as_statement: true, delimiter: " .\n", **options) +
|
74
|
+
"\n}"
|
73
75
|
end
|
74
76
|
end # Insert
|
75
77
|
end # Operator
|
@@ -54,7 +54,7 @@ module SPARQL; module Algebra
|
|
54
54
|
# @return [String]
|
55
55
|
def to_sparql(**options)
|
56
56
|
"INSERT DATA {\n" +
|
57
|
-
operands.first.to_sparql(as_statement: true, top_level: false, delimiter: "\n", **options) +
|
57
|
+
operands.first.to_sparql(as_statement: true, top_level: false, delimiter: ". \n", **options) +
|
58
58
|
"\n}"
|
59
59
|
end
|
60
60
|
end # InsertData
|
@@ -13,8 +13,7 @@ module SPARQL; module Algebra
|
|
13
13
|
# }
|
14
14
|
#
|
15
15
|
# @example SSE
|
16
|
-
# (prefix ((
|
17
|
-
# (: <http://example.org/things#>))
|
16
|
+
# (prefix ((: <http://example.org/things#>))
|
18
17
|
# (project (?x ?v)
|
19
18
|
# (filter (isBlank ?v)
|
20
19
|
# (bgp (triple ?x :p ?v)))))
|
@@ -13,8 +13,7 @@ module SPARQL; module Algebra
|
|
13
13
|
# }
|
14
14
|
#
|
15
15
|
# @example SSE
|
16
|
-
# (prefix ((
|
17
|
-
# (: <http://example.org/things#>))
|
16
|
+
# (prefix ((: <http://example.org/things#>))
|
18
17
|
# (project (?x ?v)
|
19
18
|
# (filter (isIRI ?v)
|
20
19
|
# (bgp (triple ?x :p ?v)))))
|
@@ -13,8 +13,7 @@ module SPARQL; module Algebra
|
|
13
13
|
# }
|
14
14
|
#
|
15
15
|
# @example SSE
|
16
|
-
# (prefix ((
|
17
|
-
# (: <http://example.org/things#>))
|
16
|
+
# (prefix ((: <http://example.org/things#>))
|
18
17
|
# (project (?x ?v)
|
19
18
|
# (filter (isLiteral ?v)
|
20
19
|
# (bgp (triple ?x :p ?v)))))
|
@@ -15,8 +15,7 @@ module SPARQL; module Algebra
|
|
15
15
|
# }
|
16
16
|
#
|
17
17
|
# @example SSE
|
18
|
-
# (prefix ((
|
19
|
-
# (: <http://example.org/things#>))
|
18
|
+
# (prefix ((: <http://example.org/things#>))
|
20
19
|
# (project (?x ?v)
|
21
20
|
# (filter (isNumeric ?v)
|
22
21
|
# (bgp (triple ?x :p ?v)))))
|
@@ -19,6 +19,22 @@ module SPARQL; module Algebra
|
|
19
19
|
# (graph ?g
|
20
20
|
# (bgp (triple ?s ?q ?v)))))
|
21
21
|
#
|
22
|
+
# @example SPARQL Grammar (inline filter)
|
23
|
+
# PREFIX : <http://xmlns.com/foaf/0.1/>
|
24
|
+
# ASK {
|
25
|
+
# :who :homepage ?homepage
|
26
|
+
# FILTER REGEX(?homepage, "^http://example.org/")
|
27
|
+
# :who :schoolHomepage ?schoolPage
|
28
|
+
# }
|
29
|
+
#
|
30
|
+
# @example SSE (inline filter)
|
31
|
+
# (prefix ((: <http://xmlns.com/foaf/0.1/>))
|
32
|
+
# (ask
|
33
|
+
# (filter (regex ?homepage "^http://example.org/")
|
34
|
+
# (join
|
35
|
+
# (bgp (triple :who :homepage ?homepage))
|
36
|
+
# (bgp (triple :who :schoolHomepage ?schoolPage))))))
|
37
|
+
#
|
22
38
|
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
|
23
39
|
class Join < Operator::Binary
|
24
40
|
include Query
|
@@ -98,10 +114,28 @@ module SPARQL; module Algebra
|
|
98
114
|
#
|
99
115
|
# @param [Boolean] top_level (true)
|
100
116
|
# Treat this as a top-level, generating SELECT ... WHERE {}
|
117
|
+
# @param [Hash{Symbol => Operator}] extensions
|
118
|
+
# Variable bindings
|
119
|
+
# @param [Array<Operator>] filter_ops ([])
|
120
|
+
# Filter Operations
|
101
121
|
# @return [String]
|
102
|
-
def to_sparql(top_level: true, **options)
|
103
|
-
|
104
|
-
|
122
|
+
def to_sparql(top_level: true, filter_ops: [], extensions: {}, **options)
|
123
|
+
# If this is top-level, and the last operand is a Table (values), put the values at the outer-level
|
124
|
+
str = "{\n" + operands.first.to_sparql(top_level: false, extensions: {}, **options)
|
125
|
+
|
126
|
+
# Any accrued filters go here.
|
127
|
+
filter_ops.each do |op|
|
128
|
+
str << "\nFILTER (#{op.to_sparql(**options)}) ."
|
129
|
+
end
|
130
|
+
|
131
|
+
if top_level && operands.last.is_a?(Table)
|
132
|
+
str << "\n}"
|
133
|
+
options = options.merge(values_clause: operands.last)
|
134
|
+
else
|
135
|
+
str << "\n{\n" + operands.last.to_sparql(top_level: false, extensions: {}, **options) + "\n}\n}"
|
136
|
+
end
|
137
|
+
|
138
|
+
top_level ? Operator.to_sparql(str, extensions: extensions, **options) : str
|
105
139
|
end
|
106
140
|
end # Join
|
107
141
|
end # Operator
|
@@ -12,9 +12,8 @@ module SPARQL; module Algebra
|
|
12
12
|
# }
|
13
13
|
#
|
14
14
|
# @example SSE
|
15
|
-
# (prefix
|
16
|
-
# ((
|
17
|
-
# (project (?str ?lstr)
|
15
|
+
# (prefix ((: <http://example.org/>))
|
16
|
+
# (project (?s ?lstr)
|
18
17
|
# (extend ((?lstr (lcase ?str)))
|
19
18
|
# (bgp (triple ?s :str ?str)))))
|
20
19
|
#
|
@@ -131,14 +131,27 @@ module SPARQL; module Algebra
|
|
131
131
|
#
|
132
132
|
# @param [Boolean] top_level (true)
|
133
133
|
# Treat this as a top-level, generating SELECT ... WHERE {}
|
134
|
+
# @param [Hash{Symbol => Operator}] extensions
|
135
|
+
# Variable bindings
|
136
|
+
# @param [Array<Operator>] filter_ops ([])
|
137
|
+
# Filter Operations
|
134
138
|
# @return [String]
|
135
|
-
def to_sparql(top_level: true, **options)
|
136
|
-
str = operands[0].to_sparql(top_level: false, **options)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
def to_sparql(top_level: true, filter_ops: [], extensions: {}, **options)
|
140
|
+
str = "{\n" + operands[0].to_sparql(top_level: false, extensions: {}, **options)
|
141
|
+
str <<
|
142
|
+
"\nOPTIONAL {\n" +
|
143
|
+
operands[1].to_sparql(top_level: false, extensions: {}, **options)
|
144
|
+
case operands[2]
|
145
|
+
when SPARQL::Algebra::Operator::Exprlist
|
146
|
+
operands[2].operands.each do |op|
|
147
|
+
str << "\nFILTER (" + op.to_sparql(**options) + ")"
|
148
|
+
end
|
149
|
+
when nil
|
150
|
+
else
|
151
|
+
str << "\nFILTER (" + operands[2].to_sparql(**options) + ")"
|
152
|
+
end
|
153
|
+
str << "\n}}"
|
154
|
+
top_level ? Operator.to_sparql(str, filter_ops: filter_ops, extensions: extensions, **options) : str
|
142
155
|
end
|
143
156
|
end # LeftJoin
|
144
157
|
end # Operator
|
@@ -56,7 +56,9 @@ module SPARQL; module Algebra
|
|
56
56
|
#
|
57
57
|
# @return [String]
|
58
58
|
def to_sparql(**options)
|
59
|
-
|
59
|
+
distinct = operands.first == :distinct
|
60
|
+
args = distinct ? operands[1..-1] : operands
|
61
|
+
"MAX(#{'DISTINCT ' if distinct}#{args.to_sparql(**options)})"
|
60
62
|
end
|
61
63
|
end # Max
|
62
64
|
end # Operator
|
@@ -15,7 +15,7 @@ module SPARQL; module Algebra
|
|
15
15
|
# (project (?min)
|
16
16
|
# (extend ((?min ??.0))
|
17
17
|
# (group () ((??.0 (min ?o)))
|
18
|
-
# (bgp (triple ?s
|
18
|
+
# (bgp (triple ?s :dec ?o))))))
|
19
19
|
#
|
20
20
|
# @see https://www.w3.org/TR/sparql11-query/#defn_aggMin
|
21
21
|
class Min < Operator
|
@@ -56,7 +56,9 @@ module SPARQL; module Algebra
|
|
56
56
|
#
|
57
57
|
# @return [String]
|
58
58
|
def to_sparql(**options)
|
59
|
-
|
59
|
+
distinct = operands.first == :distinct
|
60
|
+
args = distinct ? operands[1..-1] : operands
|
61
|
+
"MIN(#{'DISTINCT ' if distinct}#{args.to_sparql(**options)})"
|
60
62
|
end
|
61
63
|
end # Min
|
62
64
|
end # Operator
|
@@ -14,6 +14,32 @@ module SPARQL; module Algebra
|
|
14
14
|
# (triple ?s ?p ?o))
|
15
15
|
# (bgp (triple ?s ?q ?v)))
|
16
16
|
#
|
17
|
+
# @example SPARQL Grammar (inline filter)
|
18
|
+
# PREFIX : <http://example/>
|
19
|
+
# SELECT (?s1 AS ?subset) (?s2 AS ?superset)
|
20
|
+
# WHERE {
|
21
|
+
# ?s2 a :Set .
|
22
|
+
# ?s1 a :Set .
|
23
|
+
# FILTER(?s1 != ?s2)
|
24
|
+
# MINUS {
|
25
|
+
# ?s1 a :Set .
|
26
|
+
# ?s2 a :Set .
|
27
|
+
# FILTER(?s1 != ?s2)
|
28
|
+
# }
|
29
|
+
# }
|
30
|
+
#
|
31
|
+
# @example SSE (inline filter)
|
32
|
+
# (prefix ((: <http://example/>))
|
33
|
+
# (project (?subset ?superset)
|
34
|
+
# (extend ((?subset ?s1) (?superset ?s2))
|
35
|
+
# (filter (!= ?s1 ?s2)
|
36
|
+
# (minus
|
37
|
+
# (bgp (triple ?s2 a :Set) (triple ?s1 a :Set))
|
38
|
+
# (filter (!= ?s1 ?s2)
|
39
|
+
# (bgp
|
40
|
+
# (triple ?s1 a :Set)
|
41
|
+
# (triple ?s2 a :Set))))))))
|
42
|
+
#
|
17
43
|
# @see https://www.w3.org/TR/xpath-functions/#func-numeric-unary-minus
|
18
44
|
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
|
19
45
|
class Minus < Operator::Binary
|
@@ -74,15 +100,29 @@ module SPARQL; module Algebra
|
|
74
100
|
#
|
75
101
|
# Returns a partial SPARQL grammar for this operator.
|
76
102
|
#
|
103
|
+
# @param [Hash{Symbol => Operator}] extensions
|
104
|
+
# Variable bindings
|
105
|
+
# @param [Array<Operator>] filter_ops ([])
|
106
|
+
# Filter Operations
|
77
107
|
# @param [Boolean] top_level (true)
|
78
108
|
# Treat this as a top-level, generating SELECT ... WHERE {}
|
79
109
|
# @return [String]
|
80
|
-
def to_sparql(top_level: true, **options)
|
81
|
-
|
82
|
-
str
|
83
|
-
|
84
|
-
|
85
|
-
|
110
|
+
def to_sparql(top_level: true, filter_ops: [], extensions: {}, **options)
|
111
|
+
lhs, *rhs = operands
|
112
|
+
str = "{\n" + lhs.to_sparql(top_level: false, extensions: {}, **options)
|
113
|
+
|
114
|
+
# Any accrued filters go here.
|
115
|
+
filter_ops.each do |op|
|
116
|
+
str << "\nFILTER (#{op.to_sparql(**options)}) ."
|
117
|
+
end
|
118
|
+
|
119
|
+
rhs.each do |minus|
|
120
|
+
str << "\nMINUS {\n"
|
121
|
+
str << minus.to_sparql(top_level: false, extensions: {}, **options)
|
122
|
+
str << "\n}"
|
123
|
+
end
|
124
|
+
str << "}"
|
125
|
+
top_level ? Operator.to_sparql(str, extensions: extensions, **options) : str
|
86
126
|
end
|
87
127
|
end # Minus
|
88
128
|
end # Operator
|
@@ -50,7 +50,7 @@ module SPARQL; module Algebra
|
|
50
50
|
#
|
51
51
|
# @return [String]
|
52
52
|
def to_sparql(**options)
|
53
|
-
"#{operands.first.to_sparql(**options)} * #{operands.last.to_sparql(**options)}"
|
53
|
+
"(#{operands.first.to_sparql(**options)} * #{operands.last.to_sparql(**options)})"
|
54
54
|
end
|
55
55
|
end # Multiply
|
56
56
|
end # Operator
|
@@ -8,13 +8,13 @@ module SPARQL; module Algebra
|
|
8
8
|
# @example SPARQL Grammar
|
9
9
|
# PREFIX ex: <http://www.example.org/schema#>
|
10
10
|
# PREFIX in: <http://www.example.org/instance#>
|
11
|
-
# ASK { in:
|
11
|
+
# ASK { in:a !(ex:p1|ex:p2) ?x }
|
12
12
|
#
|
13
13
|
# @example SSE
|
14
14
|
# (prefix ((ex: <http://www.example.org/schema#>)
|
15
|
-
#
|
15
|
+
# (in: <http://www.example.org/instance#>))
|
16
16
|
# (ask
|
17
|
-
# (path in:
|
17
|
+
# (path in:a (notoneof ex:p1 ex:p2) ?x)))
|
18
18
|
#
|
19
19
|
# @see https://www.w3.org/TR/sparql11-query/#eval_negatedPropertySet
|
20
20
|
class NotOneOf < Operator
|
@@ -56,6 +56,15 @@ module SPARQL; module Algebra
|
|
56
56
|
block.call(solution)
|
57
57
|
end
|
58
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
|
59
68
|
end # NotOneOf
|
60
69
|
end # Operator
|
61
70
|
end; end # SPARQL::Algebra
|