sparql 3.1.0 → 3.1.2
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 +183 -69
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/bin/sparql +20 -9
- data/lib/rack/sparql/conneg.rb +2 -2
- data/lib/sinatra/sparql.rb +3 -3
- data/lib/sparql.rb +8 -6
- data/lib/sparql/algebra.rb +7 -15
- data/lib/sparql/algebra/aggregate.rb +2 -2
- data/lib/sparql/algebra/expression.rb +22 -8
- data/lib/sparql/algebra/extensions.rb +135 -3
- data/lib/sparql/algebra/operator.rb +37 -9
- data/lib/sparql/algebra/operator/abs.rb +2 -2
- data/lib/sparql/algebra/operator/add.rb +2 -2
- data/lib/sparql/algebra/operator/alt.rb +2 -2
- data/lib/sparql/algebra/operator/and.rb +3 -3
- data/lib/sparql/algebra/operator/asc.rb +1 -1
- data/lib/sparql/algebra/operator/ask.rb +2 -12
- data/lib/sparql/algebra/operator/avg.rb +1 -1
- data/lib/sparql/algebra/operator/base.rb +8 -8
- data/lib/sparql/algebra/operator/bgp.rb +1 -1
- data/lib/sparql/algebra/operator/bnode.rb +2 -2
- data/lib/sparql/algebra/operator/bound.rb +1 -1
- data/lib/sparql/algebra/operator/ceil.rb +2 -2
- data/lib/sparql/algebra/operator/clear.rb +2 -2
- data/lib/sparql/algebra/operator/coalesce.rb +1 -11
- data/lib/sparql/algebra/operator/compare.rb +8 -8
- data/lib/sparql/algebra/operator/concat.rb +2 -2
- data/lib/sparql/algebra/operator/construct.rb +2 -12
- data/lib/sparql/algebra/operator/contains.rb +2 -2
- data/lib/sparql/algebra/operator/copy.rb +2 -2
- data/lib/sparql/algebra/operator/count.rb +1 -1
- data/lib/sparql/algebra/operator/create.rb +2 -2
- data/lib/sparql/algebra/operator/dataset.rb +2 -13
- data/lib/sparql/algebra/operator/datatype.rb +1 -1
- data/lib/sparql/algebra/operator/day.rb +1 -1
- data/lib/sparql/algebra/operator/delete.rb +4 -4
- data/lib/sparql/algebra/operator/delete_data.rb +2 -2
- data/lib/sparql/algebra/operator/delete_where.rb +2 -2
- data/lib/sparql/algebra/operator/desc.rb +1 -1
- data/lib/sparql/algebra/operator/describe.rb +2 -12
- data/lib/sparql/algebra/operator/distinct.rb +2 -12
- data/lib/sparql/algebra/operator/divide.rb +1 -1
- data/lib/sparql/algebra/operator/drop.rb +2 -2
- data/lib/sparql/algebra/operator/encode_for_uri.rb +2 -2
- data/lib/sparql/algebra/operator/equal.rb +2 -2
- data/lib/sparql/algebra/operator/exists.rb +1 -1
- data/lib/sparql/algebra/operator/exprlist.rb +1 -11
- data/lib/sparql/algebra/operator/extend.rb +14 -13
- data/lib/sparql/algebra/operator/filter.rb +3 -13
- data/lib/sparql/algebra/operator/floor.rb +2 -2
- data/lib/sparql/algebra/operator/graph.rb +3 -14
- data/lib/sparql/algebra/operator/greater_than.rb +5 -5
- data/lib/sparql/algebra/operator/greater_than_or_equal.rb +5 -5
- data/lib/sparql/algebra/operator/group.rb +14 -14
- data/lib/sparql/algebra/operator/group_concat.rb +1 -1
- data/lib/sparql/algebra/operator/hours.rb +1 -1
- data/lib/sparql/algebra/operator/if.rb +1 -11
- data/lib/sparql/algebra/operator/in.rb +1 -11
- data/lib/sparql/algebra/operator/insert.rb +3 -3
- data/lib/sparql/algebra/operator/insert_data.rb +2 -2
- data/lib/sparql/algebra/operator/iri.rb +1 -1
- data/lib/sparql/algebra/operator/is_blank.rb +1 -1
- data/lib/sparql/algebra/operator/is_iri.rb +1 -1
- data/lib/sparql/algebra/operator/is_literal.rb +1 -1
- data/lib/sparql/algebra/operator/is_numeric.rb +1 -1
- data/lib/sparql/algebra/operator/join.rb +9 -7
- data/lib/sparql/algebra/operator/lang.rb +1 -1
- data/lib/sparql/algebra/operator/lang_matches.rb +3 -3
- data/lib/sparql/algebra/operator/lcase.rb +2 -2
- data/lib/sparql/algebra/operator/left_join.rb +12 -9
- data/lib/sparql/algebra/operator/less_than.rb +5 -5
- data/lib/sparql/algebra/operator/less_than_or_equal.rb +5 -5
- data/lib/sparql/algebra/operator/load.rb +2 -2
- data/lib/sparql/algebra/operator/max.rb +1 -1
- data/lib/sparql/algebra/operator/md5.rb +1 -1
- data/lib/sparql/algebra/operator/min.rb +1 -1
- data/lib/sparql/algebra/operator/minus.rb +9 -8
- data/lib/sparql/algebra/operator/minutes.rb +1 -1
- data/lib/sparql/algebra/operator/modify.rb +1 -1
- data/lib/sparql/algebra/operator/month.rb +1 -1
- data/lib/sparql/algebra/operator/move.rb +2 -2
- data/lib/sparql/algebra/operator/multiply.rb +1 -1
- data/lib/sparql/algebra/operator/negate.rb +1 -1
- data/lib/sparql/algebra/operator/not.rb +1 -1
- data/lib/sparql/algebra/operator/not_equal.rb +2 -2
- data/lib/sparql/algebra/operator/notexists.rb +2 -2
- data/lib/sparql/algebra/operator/notin.rb +1 -11
- data/lib/sparql/algebra/operator/notoneof.rb +2 -2
- data/lib/sparql/algebra/operator/now.rb +1 -1
- data/lib/sparql/algebra/operator/or.rb +3 -3
- data/lib/sparql/algebra/operator/order.rb +2 -12
- data/lib/sparql/algebra/operator/path.rb +2 -2
- data/lib/sparql/algebra/operator/path_opt.rb +2 -2
- data/lib/sparql/algebra/operator/path_plus.rb +2 -2
- data/lib/sparql/algebra/operator/path_star.rb +2 -2
- data/lib/sparql/algebra/operator/plus.rb +2 -2
- data/lib/sparql/algebra/operator/prefix.rb +8 -8
- data/lib/sparql/algebra/operator/project.rb +2 -12
- data/lib/sparql/algebra/operator/rand.rb +1 -1
- data/lib/sparql/algebra/operator/reduced.rb +2 -12
- data/lib/sparql/algebra/operator/regex.rb +5 -5
- data/lib/sparql/algebra/operator/replace.rb +3 -3
- data/lib/sparql/algebra/operator/reverse.rb +2 -2
- data/lib/sparql/algebra/operator/round.rb +2 -2
- data/lib/sparql/algebra/operator/same_term.rb +8 -5
- data/lib/sparql/algebra/operator/sample.rb +1 -1
- data/lib/sparql/algebra/operator/seconds.rb +1 -1
- data/lib/sparql/algebra/operator/seq.rb +1 -1
- data/lib/sparql/algebra/operator/sequence.rb +1 -1
- data/lib/sparql/algebra/operator/sha1.rb +1 -1
- data/lib/sparql/algebra/operator/sha256.rb +1 -1
- data/lib/sparql/algebra/operator/sha384.rb +1 -1
- data/lib/sparql/algebra/operator/sha512.rb +1 -1
- data/lib/sparql/algebra/operator/slice.rb +2 -12
- data/lib/sparql/algebra/operator/str.rb +1 -1
- data/lib/sparql/algebra/operator/strafter.rb +2 -2
- data/lib/sparql/algebra/operator/strbefore.rb +2 -2
- data/lib/sparql/algebra/operator/strdt.rb +2 -2
- data/lib/sparql/algebra/operator/strends.rb +2 -2
- data/lib/sparql/algebra/operator/strlang.rb +2 -2
- data/lib/sparql/algebra/operator/strlen.rb +2 -2
- data/lib/sparql/algebra/operator/strstarts.rb +2 -2
- data/lib/sparql/algebra/operator/struuid.rb +1 -1
- data/lib/sparql/algebra/operator/substr.rb +3 -3
- data/lib/sparql/algebra/operator/subtract.rb +1 -1
- data/lib/sparql/algebra/operator/sum.rb +1 -1
- data/lib/sparql/algebra/operator/table.rb +2 -2
- data/lib/sparql/algebra/operator/timezone.rb +1 -1
- data/lib/sparql/algebra/operator/tz.rb +1 -1
- data/lib/sparql/algebra/operator/ucase.rb +2 -2
- data/lib/sparql/algebra/operator/union.rb +7 -6
- data/lib/sparql/algebra/operator/update.rb +2 -2
- data/lib/sparql/algebra/operator/using.rb +2 -2
- data/lib/sparql/algebra/operator/uuid.rb +1 -1
- data/lib/sparql/algebra/operator/with.rb +2 -2
- data/lib/sparql/algebra/operator/year.rb +1 -1
- data/lib/sparql/algebra/query.rb +1 -1
- data/lib/sparql/algebra/update.rb +1 -1
- data/lib/sparql/algebra/version.rb +1 -1
- data/lib/sparql/extensions.rb +1 -1
- data/lib/sparql/grammar.rb +104 -3
- data/lib/sparql/grammar/meta.rb +1372 -333
- data/lib/sparql/grammar/parser11.rb +27 -6
- data/lib/sparql/grammar/terminals11.rb +1 -0
- data/lib/sparql/results.rb +60 -41
- data/lib/sparql/version.rb +1 -1
- metadata +14 -8
data/lib/sinatra/sparql.rb
CHANGED
@@ -8,7 +8,7 @@ module Sinatra
|
|
8
8
|
#
|
9
9
|
# To override negotiation on Content-Type, set :format in `sparql_options` to a RDF Format class, or symbol identifying a format.
|
10
10
|
#
|
11
|
-
# @see
|
11
|
+
# @see https://www.sinatrarb.com/extensions.html
|
12
12
|
module SPARQL
|
13
13
|
##
|
14
14
|
# Helper methods.
|
@@ -25,8 +25,8 @@ module Sinatra
|
|
25
25
|
# URI of the service endpoint, defaults to "/sparql" in the current realm.
|
26
26
|
# @return [RDF::Graph]
|
27
27
|
#
|
28
|
-
# @see
|
29
|
-
# @see
|
28
|
+
# @see https://www.w3.org/TR/sparql11-service-description
|
29
|
+
# @see https://www.w3.org/TR/void/
|
30
30
|
def service_description(**options)
|
31
31
|
repository = options[:repository]
|
32
32
|
|
data/lib/sparql.rb
CHANGED
@@ -3,14 +3,14 @@ require 'sparql/extensions'
|
|
3
3
|
##
|
4
4
|
# A SPARQL for RDF.rb.
|
5
5
|
#
|
6
|
-
# @see
|
6
|
+
# @see https://www.w3.org/TR/sparql11-query
|
7
7
|
module SPARQL
|
8
8
|
autoload :Algebra, 'sparql/algebra'
|
9
9
|
autoload :Grammar, 'sparql/grammar'
|
10
10
|
autoload :Results, 'sparql/results'
|
11
11
|
autoload :VERSION, 'sparql/version'
|
12
12
|
|
13
|
-
# @see
|
13
|
+
# @see https://rubygems-client
|
14
14
|
autoload :Client, 'sparql/client'
|
15
15
|
|
16
16
|
##
|
@@ -52,12 +52,13 @@ module SPARQL
|
|
52
52
|
# results = SPARQL.execute("SELECT * WHERE { ?s ?p ?o }", repository)
|
53
53
|
#
|
54
54
|
# @param [IO, StringIO, String, #to_s] query
|
55
|
+
# @param [RDF::Queryable] queryable
|
55
56
|
# @param [Hash{Symbol => Object}] options
|
56
|
-
# @option options
|
57
|
-
#
|
58
|
-
# One or more URIs used to initialize a new instance of `queryable` in the default graph.
|
57
|
+
# @option options [Boolean] :optimize
|
58
|
+
# Optimize query before execution.
|
59
59
|
# @option options [RDF::URI, String, Array<RDF::URI, String>] :default_graph_uri
|
60
|
-
#
|
60
|
+
# @option options [RDF::URI, String, Array<RDF::URI, String>] :load_datasets
|
61
|
+
# One or more URIs used to initialize a new instance of `queryable` in the default graph. One or more URIs used to initialize a new instance of `queryable` in the default graph.
|
61
62
|
# @option options [RDF::URI, String, Array<RDF::URI, String>] :named_graph_uri
|
62
63
|
# One or more URIs used to initialize the `queryable` as a named graph.
|
63
64
|
# @yield [solution]
|
@@ -69,6 +70,7 @@ module SPARQL
|
|
69
70
|
# @raise [SPARQL::MalformedQuery] on invalid input
|
70
71
|
def self.execute(query, queryable, **options, &block)
|
71
72
|
query = self.parse(query, **options)
|
73
|
+
query = query.optimize(**options) if options[:optimize]
|
72
74
|
queryable = queryable || RDF::Repository.new
|
73
75
|
|
74
76
|
case options.fetch(:debug, nil)
|
data/lib/sparql/algebra.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'rdf' # @see
|
1
|
+
require 'rdf' # @see https://rubygems.org/gems/rdf
|
2
2
|
require 'rdf/xsd'
|
3
3
|
|
4
4
|
module SPARQL
|
@@ -141,21 +141,21 @@ module SPARQL
|
|
141
141
|
# ## Constructing operator expressions manually
|
142
142
|
#
|
143
143
|
# Operator(:isBlank).new(RDF::Node(:foobar)).to_sxp #=> "(isBlank _:foobar)"
|
144
|
-
# Operator(:isIRI).new(RDF::URI('
|
144
|
+
# Operator(:isIRI).new(RDF::URI('https://rubygems.org/gems/rdf/')).to_sxp #=> "(isIRI <https://rubygems.org/gems/rdf/>)"
|
145
145
|
# Operator(:isLiteral).new(RDF::Literal(3.1415)).to_sxp #=> "(isLiteral 3.1415)"
|
146
146
|
# Operator(:str).new(Operator(:datatype).new(RDF::Literal(3.1415))).to_sxp #=> "(str (datatype 3.1415))"
|
147
147
|
#
|
148
148
|
# ## Constructing operator expressions using SSE forms
|
149
149
|
#
|
150
150
|
# SPARQL::Algebra::Expression[:isBlank, RDF::Node(:foobar)].to_sxp #=> "(isBlank _:foobar)"
|
151
|
-
# SPARQL::Algebra::Expression[:isIRI, RDF::URI('
|
151
|
+
# SPARQL::Algebra::Expression[:isIRI, RDF::URI('https://rubygems.org/gems/rdf/')].to_sxp #=> "(isIRI <https://rubygems.org/gems/rdf/>)"
|
152
152
|
# SPARQL::Algebra::Expression[:isLiteral, RDF::Literal(3.1415)].to_sxp #=> "(isLiteral 3.1415)"
|
153
153
|
# SPARQL::Algebra::Expression[:str, [:datatype, RDF::Literal(3.1415)]].to_sxp #=> "(str (datatype 3.1415))"
|
154
154
|
#
|
155
155
|
# ## Constructing operator expressions using SSE strings
|
156
156
|
#
|
157
157
|
# SPARQL::Algebra::Expression.parse('(isBlank _:foobar)')
|
158
|
-
# SPARQL::Algebra::Expression.parse('(isIRI <
|
158
|
+
# SPARQL::Algebra::Expression.parse('(isIRI <https://rubygems.org/gems/rdf/>)')
|
159
159
|
# SPARQL::Algebra::Expression.parse('(isLiteral 3.1415)')
|
160
160
|
# SPARQL::Algebra::Expression.parse('(str (datatype 3.1415))')
|
161
161
|
#
|
@@ -165,11 +165,6 @@ module SPARQL
|
|
165
165
|
# Operator(:isIRI).evaluate(RDF::Vocab::DC.title) #=> RDF::Literal::TRUE
|
166
166
|
# Operator(:isLiteral).evaluate(RDF::Literal(3.1415)) #=> RDF::Literal::TRUE
|
167
167
|
#
|
168
|
-
# ## Optimizing expressions containing constant subexpressions
|
169
|
-
#
|
170
|
-
# SPARQL::Algebra::Expression.parse('(sameTerm ?var ?var)').optimize #=> RDF::Literal::TRUE
|
171
|
-
# SPARQL::Algebra::Expression.parse('(* -2 (- (* (+ 1 2) (+ 3 4))))').optimize #=> RDF::Literal(42)
|
172
|
-
#
|
173
168
|
# ## Evaluating expressions on a solution sequence
|
174
169
|
#
|
175
170
|
# # Find all people and their names & e-mail addresses:
|
@@ -405,8 +400,7 @@ module SPARQL
|
|
405
400
|
def Expression(*sse)
|
406
401
|
Expression.for(*sse)
|
407
402
|
end
|
408
|
-
|
409
|
-
module_function :Expr, :Expression
|
403
|
+
module_function :Expression
|
410
404
|
|
411
405
|
##
|
412
406
|
# @example
|
@@ -417,8 +411,7 @@ module SPARQL
|
|
417
411
|
def Operator(name, arity = nil)
|
418
412
|
Operator.for(name, arity)
|
419
413
|
end
|
420
|
-
|
421
|
-
module_function :Op, :Operator
|
414
|
+
module_function :Operator
|
422
415
|
|
423
416
|
##
|
424
417
|
# @example
|
@@ -430,8 +423,7 @@ module SPARQL
|
|
430
423
|
def Variable(name)
|
431
424
|
Variable.new(name)
|
432
425
|
end
|
433
|
-
|
434
|
-
module_function :Var, :Variable
|
426
|
+
module_function :Variable
|
435
427
|
|
436
428
|
Variable = RDF::Query::Variable
|
437
429
|
end # Algebra
|
@@ -6,8 +6,8 @@ module SPARQL; module Algebra
|
|
6
6
|
# or more operands which are `Enumerable` lists of `RDF::Term`
|
7
7
|
# and return a single `RDF::Term` or `TypeError`.
|
8
8
|
#
|
9
|
-
# @see
|
10
|
-
# @see
|
9
|
+
# @see https://www.w3.org/TR/sparql11-query/#setFunctions
|
10
|
+
# @see https://www.w3.org/TR/sparql11-query/#aggregates
|
11
11
|
#
|
12
12
|
# @abstract
|
13
13
|
module Aggregate
|
@@ -21,7 +21,7 @@ module SPARQL; module Algebra
|
|
21
21
|
# @return [Expression]
|
22
22
|
def self.parse(sse, **options, &block)
|
23
23
|
begin
|
24
|
-
require 'sxp' # @see
|
24
|
+
require 'sxp' # @see https://rubygems.org/gems/sxp
|
25
25
|
rescue LoadError
|
26
26
|
abort "SPARQL::Algebra::Expression.parse requires the SXP gem (hint: `gem install sxp')."
|
27
27
|
end
|
@@ -175,8 +175,8 @@ module SPARQL; module Algebra
|
|
175
175
|
# @param [RDF::URI] function
|
176
176
|
# @param [Array<RDF::Term>] args splat of args to function
|
177
177
|
# @return [RDF::Term]
|
178
|
-
# @see
|
179
|
-
# @see
|
178
|
+
# @see https://www.w3.org/TR/sparql11-query/#extensionFunctions
|
179
|
+
# @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
|
180
180
|
def self.extension(function, *args)
|
181
181
|
if function.to_s.start_with?(RDF::XSD.to_s)
|
182
182
|
self.cast(function, args.first)
|
@@ -197,7 +197,7 @@ module SPARQL; module Algebra
|
|
197
197
|
# Value, which should be a typed literal, where the type must be that specified
|
198
198
|
# @raise [TypeError] if datatype is not a URI or value cannot be cast to datatype
|
199
199
|
# @return [RDF::Term]
|
200
|
-
# @see
|
200
|
+
# @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
|
201
201
|
def self.cast(datatype, value)
|
202
202
|
case datatype
|
203
203
|
when RDF::XSD.dateTime
|
@@ -280,12 +280,26 @@ module SPARQL; module Algebra
|
|
280
280
|
##
|
281
281
|
# Returns an optimized version of this expression.
|
282
282
|
#
|
283
|
-
# This is the default implementation, which simply returns `self`.
|
283
|
+
# This is the default implementation, which simply returns a copy of `self`.
|
284
284
|
# Subclasses can override this method in order to implement something
|
285
285
|
# more useful.
|
286
286
|
#
|
287
|
-
# @
|
288
|
-
|
287
|
+
# @param [Hash{Symbol => Object}] options
|
288
|
+
# any additional options for optimization
|
289
|
+
# @return [Expression] a copy of `self`
|
290
|
+
# @see RDF::Query#optimize
|
291
|
+
def optimize(**options)
|
292
|
+
self.deep_dup.optimize!(**options)
|
293
|
+
end
|
294
|
+
|
295
|
+
##
|
296
|
+
# Optimizes this query.
|
297
|
+
#
|
298
|
+
# @param [Hash{Symbol => Object}] options
|
299
|
+
# any additional options for optimization
|
300
|
+
# @return [self]
|
301
|
+
# @see RDF::Query#optimize!
|
302
|
+
def optimize!(**options)
|
289
303
|
self
|
290
304
|
end
|
291
305
|
|
@@ -313,7 +327,7 @@ module SPARQL; module Algebra
|
|
313
327
|
# more useful.
|
314
328
|
#
|
315
329
|
# @return [Array] `self`
|
316
|
-
# @see
|
330
|
+
# @see https://openjena.org/wiki/SSE
|
317
331
|
def to_sxp_bin
|
318
332
|
self
|
319
333
|
end
|
@@ -27,6 +27,22 @@ class Object
|
|
27
27
|
def to_sse
|
28
28
|
SXP::Generator.string(self.to_sxp_bin)
|
29
29
|
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# A duplicate of this object.
|
33
|
+
#
|
34
|
+
# @return [Object] a copy of `self`
|
35
|
+
# @see SPARQL::Algebra::Expression#optimize
|
36
|
+
def optimize(**options)
|
37
|
+
self.deep_dup
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Default for deep_dup is shallow dup
|
42
|
+
# @return [Object]
|
43
|
+
def deep_dup
|
44
|
+
dup
|
45
|
+
end
|
30
46
|
end
|
31
47
|
|
32
48
|
##
|
@@ -66,11 +82,34 @@ class Array
|
|
66
82
|
# @param [Hash{Symbol => Object}] options
|
67
83
|
# @raise [NotImplementedError]
|
68
84
|
# If an attempt is made to perform an unsupported operation
|
69
|
-
# @see
|
85
|
+
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
|
70
86
|
def execute(queryable, **options)
|
71
87
|
raise NotImplementedError, "SPARQL::Algebra '#{first}' operator not implemented"
|
72
88
|
end
|
73
89
|
|
90
|
+
##
|
91
|
+
# Return an optimized version of this array.
|
92
|
+
#
|
93
|
+
# @return [Array] a copy of `self`
|
94
|
+
# @see SPARQL::Algebra::Expression#optimize
|
95
|
+
def optimize(**options)
|
96
|
+
self.map do |op|
|
97
|
+
op.optimize(**options) if op.respond_to?(:optimize)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
|
103
|
+
#
|
104
|
+
# @param [RDF::Query::Solution] solution
|
105
|
+
# @return [self]
|
106
|
+
def bind(solution)
|
107
|
+
map! do |op|
|
108
|
+
op.respond_to?(:bind) ? op.bind(solution) : op
|
109
|
+
end
|
110
|
+
self
|
111
|
+
end
|
112
|
+
|
74
113
|
##
|
75
114
|
# Returns `true` if any of the operands are variables, `false`
|
76
115
|
# otherwise.
|
@@ -78,7 +117,7 @@ class Array
|
|
78
117
|
# @return [Boolean] `true` or `false`
|
79
118
|
# @see #constant?
|
80
119
|
def variable?
|
81
|
-
any?(
|
120
|
+
any? {|op| op.respond_to?(:variable?) && op.variable?}
|
82
121
|
end
|
83
122
|
def constant?; !(variable?); end
|
84
123
|
|
@@ -166,6 +205,12 @@ class Array
|
|
166
205
|
each {|e| e.validate! if e.respond_to?(:validate!)}
|
167
206
|
self
|
168
207
|
end
|
208
|
+
|
209
|
+
##
|
210
|
+
# Deep duplicate
|
211
|
+
def deep_dup
|
212
|
+
map(&:deep_dup)
|
213
|
+
end
|
169
214
|
end
|
170
215
|
|
171
216
|
##
|
@@ -179,6 +224,21 @@ class Hash
|
|
179
224
|
to_a.to_sxp_bin
|
180
225
|
end
|
181
226
|
def to_sxp; to_sxp_bin; end
|
227
|
+
|
228
|
+
##
|
229
|
+
# A duplicate of this hash.
|
230
|
+
#
|
231
|
+
# @return [Hash] a copy of `self`
|
232
|
+
# @see SPARQL::Algebra::Expression#optimize
|
233
|
+
def optimize(**options)
|
234
|
+
self.deep_dup
|
235
|
+
end
|
236
|
+
|
237
|
+
##
|
238
|
+
# Deep duplicate
|
239
|
+
def deep_dup
|
240
|
+
inject({}) {|memo, (k, v)| memo.merge(k => v.deep_dup)}
|
241
|
+
end
|
182
242
|
end
|
183
243
|
|
184
244
|
##
|
@@ -210,6 +270,17 @@ module RDF::Term
|
|
210
270
|
def vars
|
211
271
|
variable? ? [self] : []
|
212
272
|
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# A duplicate of this term.
|
276
|
+
#
|
277
|
+
# @return [RDF::Term] a copy of `self`
|
278
|
+
# @see SPARQL::Algebra::Expression#optimize
|
279
|
+
def optimize(**options)
|
280
|
+
optimized = self.deep_dup
|
281
|
+
optimized.lexical = nil if optimized.respond_to?(:lexical=)
|
282
|
+
optimized
|
283
|
+
end
|
213
284
|
end # RDF::Term
|
214
285
|
|
215
286
|
# Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
|
@@ -258,7 +329,6 @@ module RDF::Queryable
|
|
258
329
|
query_without_sparql(pattern, **options, &block)
|
259
330
|
end
|
260
331
|
end
|
261
|
-
|
262
332
|
end
|
263
333
|
|
264
334
|
class RDF::Statement
|
@@ -271,6 +341,15 @@ class RDF::Statement
|
|
271
341
|
[:triple, subject, predicate, object]
|
272
342
|
end
|
273
343
|
end
|
344
|
+
|
345
|
+
##
|
346
|
+
# A duplicate of this Statement.
|
347
|
+
#
|
348
|
+
# @return [RDF::Statement] a copy of `self`
|
349
|
+
# @see SPARQL::Algebra::Expression#optimize
|
350
|
+
def optimize(**options)
|
351
|
+
self.dup
|
352
|
+
end
|
274
353
|
end
|
275
354
|
|
276
355
|
class RDF::Query
|
@@ -306,6 +385,16 @@ class RDF::Query
|
|
306
385
|
end
|
307
386
|
end
|
308
387
|
|
388
|
+
##
|
389
|
+
# Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
|
390
|
+
#
|
391
|
+
# @param [RDF::Query::Solution] solution
|
392
|
+
# @return [self]
|
393
|
+
def bind(solution)
|
394
|
+
patterns.each {|p| p.bind(solution)}
|
395
|
+
self
|
396
|
+
end
|
397
|
+
|
309
398
|
# Query results in a boolean result (e.g., ASK)
|
310
399
|
# @return [Boolean]
|
311
400
|
def query_yields_boolean?
|
@@ -338,6 +427,27 @@ class RDF::Query
|
|
338
427
|
variables.values
|
339
428
|
end
|
340
429
|
|
430
|
+
##
|
431
|
+
# Optimize the query, removing lexical shortcuts in URIs
|
432
|
+
#
|
433
|
+
# @return [self]
|
434
|
+
# @see SPARQL::Algebra::Expression#optimize!
|
435
|
+
def optimize!(**options)
|
436
|
+
@patterns = @patterns.map do |pattern|
|
437
|
+
components = pattern.to_a.map do |term|
|
438
|
+
if term.respond_to?(:lexical=)
|
439
|
+
term.dup.instance_eval {@lexical = nil; self}
|
440
|
+
else
|
441
|
+
term
|
442
|
+
end
|
443
|
+
end
|
444
|
+
RDF::Query::Pattern.from(components)
|
445
|
+
end.sort! do |a, b|
|
446
|
+
(a.cost || 0) <=> (b.cost || 0)
|
447
|
+
end
|
448
|
+
self
|
449
|
+
end
|
450
|
+
|
341
451
|
##
|
342
452
|
# Returns `true` if this is executable (i.e., contains a graph patterns), `false`
|
343
453
|
# otherwise.
|
@@ -390,6 +500,15 @@ class RDF::Query::Variable
|
|
390
500
|
raise TypeError if bindings.respond_to?(:bound?) && !bindings.bound?(self)
|
391
501
|
bindings[name.to_sym]
|
392
502
|
end
|
503
|
+
|
504
|
+
##
|
505
|
+
# Return self
|
506
|
+
#
|
507
|
+
# @return [RDF::Query::Variable] a copy of `self`
|
508
|
+
# @see SPARQL::Algebra::Expression#optimize
|
509
|
+
def optimize(**options)
|
510
|
+
self
|
511
|
+
end
|
393
512
|
end # RDF::Query::Variable
|
394
513
|
|
395
514
|
##
|
@@ -419,3 +538,16 @@ class RDF::Query::Solutions
|
|
419
538
|
end
|
420
539
|
alias_method :filter!, :filter
|
421
540
|
end # RDF::Query::Solutions
|
541
|
+
|
542
|
+
##
|
543
|
+
# Extensions for `RDF::Query::Solution`.
|
544
|
+
class RDF::Query::Solution
|
545
|
+
##
|
546
|
+
# Returns the SXP representation of this object, defaults to `self`.
|
547
|
+
#
|
548
|
+
# @return [String]
|
549
|
+
def to_sxp_bin
|
550
|
+
to_a.to_sxp_bin
|
551
|
+
end
|
552
|
+
def to_sxp; to_sxp_bin; end
|
553
|
+
end # RDF::Query::Solution
|
@@ -146,8 +146,6 @@ module SPARQL; module Algebra
|
|
146
146
|
autoload :Using, 'sparql/algebra/operator/using'
|
147
147
|
autoload :With, 'sparql/algebra/operator/with'
|
148
148
|
|
149
|
-
|
150
|
-
|
151
149
|
##
|
152
150
|
# Returns an operator class for the given operator `name`.
|
153
151
|
#
|
@@ -357,6 +355,22 @@ module SPARQL; module Algebra
|
|
357
355
|
end
|
358
356
|
end
|
359
357
|
|
358
|
+
##
|
359
|
+
# Deep duplicate operands
|
360
|
+
def deep_dup
|
361
|
+
self.class.new(*operands.map(&:deep_dup))
|
362
|
+
end
|
363
|
+
|
364
|
+
##
|
365
|
+
# Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
|
366
|
+
#
|
367
|
+
# @param [RDF::Query::Solution] solution
|
368
|
+
# @return [self]
|
369
|
+
def bind(solution)
|
370
|
+
@operands.each {|op| op.bind(solution)}
|
371
|
+
self
|
372
|
+
end
|
373
|
+
|
360
374
|
##
|
361
375
|
# Base URI used for reading data sources with relative URIs
|
362
376
|
#
|
@@ -434,7 +448,7 @@ module SPARQL; module Algebra
|
|
434
448
|
# @return [Boolean] `true` or `false`
|
435
449
|
# @see #constant?
|
436
450
|
def variable?
|
437
|
-
operands.any?(
|
451
|
+
operands.any? {|op| op.respond_to?(:variable?) && op.variable?}
|
438
452
|
end
|
439
453
|
|
440
454
|
##
|
@@ -491,21 +505,35 @@ module SPARQL; module Algebra
|
|
491
505
|
#
|
492
506
|
# For constant expressions containing no variables, returns the result
|
493
507
|
# of evaluating the expression with empty bindings; otherwise returns
|
494
|
-
# `self`.
|
508
|
+
# a copy of `self`.
|
495
509
|
#
|
496
510
|
# Optimization is not possible if the expression raises an exception,
|
497
511
|
# such as a `TypeError` or `ZeroDivisionError`, which must be conserved
|
498
512
|
# at runtime.
|
499
513
|
#
|
500
514
|
# @return [SPARQL::Algebra::Expression]
|
501
|
-
|
515
|
+
# @see RDF::Query#optimize
|
516
|
+
def optimize(**options)
|
502
517
|
if constant?
|
503
518
|
# Note that if evaluation results in a `TypeError` or other error,
|
504
519
|
# we must return `self` so that the error is conserved at runtime:
|
505
520
|
evaluate(RDF::Query::Solution.new) rescue self
|
506
521
|
else
|
507
|
-
super # returns `self`
|
522
|
+
super # returns a copy of `self`
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
##
|
527
|
+
# Optimizes this query by optimizing its constituent operands
|
528
|
+
# according to their cost estimates.
|
529
|
+
#
|
530
|
+
# @return [self]
|
531
|
+
# @see RDF::Query#optimize!
|
532
|
+
def optimize!(**options)
|
533
|
+
@operands.map! do |op|
|
534
|
+
op.optimize(**options) if op.respond_to?(:optimize)
|
508
535
|
end
|
536
|
+
self
|
509
537
|
end
|
510
538
|
|
511
539
|
##
|
@@ -532,7 +560,7 @@ module SPARQL; module Algebra
|
|
532
560
|
# Returns the SPARQL S-Expression (SSE) representation of this operator.
|
533
561
|
#
|
534
562
|
# @return [Array]
|
535
|
-
# @see
|
563
|
+
# @see https://openjena.org/wiki/SSE
|
536
564
|
def to_sxp_bin
|
537
565
|
operator = [self.class.const_get(:NAME)].flatten.first
|
538
566
|
[operator, *(operands || []).map(&:to_sxp_bin)]
|
@@ -544,7 +572,7 @@ module SPARQL; module Algebra
|
|
544
572
|
# @return [String]
|
545
573
|
def to_sxp
|
546
574
|
begin
|
547
|
-
require 'sxp' # @see
|
575
|
+
require 'sxp' # @see https://rubygems.org/gems/sxp
|
548
576
|
rescue LoadError
|
549
577
|
abort "SPARQL::Algebra::Operator#to_sxp requires the SXP gem (hint: `gem install sxp')."
|
550
578
|
end
|
@@ -647,7 +675,7 @@ module SPARQL; module Algebra
|
|
647
675
|
# @param [RDF::Literal] literal
|
648
676
|
# @return [RDF::Literal::Boolean] `true` or `false`
|
649
677
|
# @raise [TypeError] if the literal could not be coerced to an `RDF::Literal::Boolean`
|
650
|
-
# @see
|
678
|
+
# @see https://www.w3.org/TR/sparql11-query/#ebv
|
651
679
|
def boolean(literal)
|
652
680
|
case literal
|
653
681
|
when FalseClass then RDF::Literal::FALSE
|