sparql 3.0.0 → 3.1.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.
- checksums.yaml +5 -5
- data/README.md +184 -70
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/bin/sparql +28 -17
- data/lib/rack/sparql.rb +1 -1
- data/lib/rack/sparql/conneg.rb +3 -3
- data/lib/sinatra/sparql.rb +5 -5
- data/lib/sparql.rb +14 -10
- data/lib/sparql/algebra.rb +15 -23
- data/lib/sparql/algebra/aggregate.rb +4 -4
- data/lib/sparql/algebra/evaluatable.rb +2 -2
- data/lib/sparql/algebra/expression.rb +28 -21
- data/lib/sparql/algebra/extensions.rb +142 -16
- data/lib/sparql/algebra/operator.rb +37 -16
- data/lib/sparql/algebra/operator/abs.rb +2 -2
- data/lib/sparql/algebra/operator/add.rb +3 -3
- data/lib/sparql/algebra/operator/alt.rb +4 -4
- data/lib/sparql/algebra/operator/and.rb +7 -7
- data/lib/sparql/algebra/operator/asc.rb +3 -3
- data/lib/sparql/algebra/operator/ask.rb +4 -14
- data/lib/sparql/algebra/operator/avg.rb +6 -4
- data/lib/sparql/algebra/operator/base.rb +10 -10
- data/lib/sparql/algebra/operator/bgp.rb +1 -1
- data/lib/sparql/algebra/operator/bnode.rb +5 -5
- data/lib/sparql/algebra/operator/bound.rb +3 -3
- data/lib/sparql/algebra/operator/ceil.rb +2 -2
- data/lib/sparql/algebra/operator/clear.rb +3 -3
- data/lib/sparql/algebra/operator/coalesce.rb +3 -13
- data/lib/sparql/algebra/operator/compare.rb +8 -8
- data/lib/sparql/algebra/operator/concat.rb +4 -4
- data/lib/sparql/algebra/operator/construct.rb +4 -14
- data/lib/sparql/algebra/operator/contains.rb +2 -2
- data/lib/sparql/algebra/operator/copy.rb +3 -3
- data/lib/sparql/algebra/operator/count.rb +3 -3
- data/lib/sparql/algebra/operator/create.rb +3 -3
- data/lib/sparql/algebra/operator/dataset.rb +5 -16
- 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 +7 -5
- data/lib/sparql/algebra/operator/delete_data.rb +3 -3
- data/lib/sparql/algebra/operator/delete_where.rb +5 -5
- data/lib/sparql/algebra/operator/desc.rb +1 -1
- data/lib/sparql/algebra/operator/describe.rb +3 -13
- data/lib/sparql/algebra/operator/distinct.rb +4 -14
- data/lib/sparql/algebra/operator/divide.rb +1 -1
- data/lib/sparql/algebra/operator/drop.rb +3 -3
- data/lib/sparql/algebra/operator/encode_for_uri.rb +3 -3
- data/lib/sparql/algebra/operator/equal.rb +3 -3
- data/lib/sparql/algebra/operator/exists.rb +5 -5
- data/lib/sparql/algebra/operator/exprlist.rb +3 -13
- data/lib/sparql/algebra/operator/extend.rb +21 -20
- data/lib/sparql/algebra/operator/filter.rb +6 -16
- data/lib/sparql/algebra/operator/floor.rb +2 -2
- data/lib/sparql/algebra/operator/graph.rb +5 -16
- 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 +25 -25
- data/lib/sparql/algebra/operator/group_concat.rb +6 -6
- data/lib/sparql/algebra/operator/hours.rb +1 -1
- data/lib/sparql/algebra/operator/if.rb +5 -15
- data/lib/sparql/algebra/operator/in.rb +4 -14
- data/lib/sparql/algebra/operator/insert.rb +6 -4
- data/lib/sparql/algebra/operator/insert_data.rb +3 -3
- 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 +12 -10
- 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 +15 -12
- 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 +3 -3
- data/lib/sparql/algebra/operator/max.rb +6 -4
- data/lib/sparql/algebra/operator/md5.rb +1 -1
- data/lib/sparql/algebra/operator/min.rb +6 -4
- data/lib/sparql/algebra/operator/minus.rb +12 -11
- data/lib/sparql/algebra/operator/minutes.rb +1 -1
- data/lib/sparql/algebra/operator/modify.rb +4 -4
- data/lib/sparql/algebra/operator/month.rb +1 -1
- data/lib/sparql/algebra/operator/move.rb +3 -3
- 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 +4 -4
- data/lib/sparql/algebra/operator/notin.rb +4 -14
- data/lib/sparql/algebra/operator/notoneof.rb +5 -6
- data/lib/sparql/algebra/operator/now.rb +1 -1
- data/lib/sparql/algebra/operator/or.rb +7 -7
- data/lib/sparql/algebra/operator/order.rb +6 -16
- data/lib/sparql/algebra/operator/path.rb +6 -5
- data/lib/sparql/algebra/operator/path_opt.rb +16 -16
- data/lib/sparql/algebra/operator/path_plus.rb +8 -8
- data/lib/sparql/algebra/operator/path_star.rb +4 -4
- data/lib/sparql/algebra/operator/plus.rb +3 -3
- data/lib/sparql/algebra/operator/prefix.rb +10 -10
- data/lib/sparql/algebra/operator/project.rb +4 -14
- data/lib/sparql/algebra/operator/rand.rb +1 -1
- data/lib/sparql/algebra/operator/reduced.rb +4 -14
- data/lib/sparql/algebra/operator/regex.rb +6 -6
- data/lib/sparql/algebra/operator/replace.rb +4 -4
- data/lib/sparql/algebra/operator/reverse.rb +4 -4
- 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 +3 -3
- data/lib/sparql/algebra/operator/seconds.rb +1 -1
- data/lib/sparql/algebra/operator/seq.rb +5 -6
- data/lib/sparql/algebra/operator/sequence.rb +4 -4
- 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 +4 -14
- 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 +4 -4
- data/lib/sparql/algebra/operator/subtract.rb +1 -1
- data/lib/sparql/algebra/operator/sum.rb +6 -4
- data/lib/sparql/algebra/operator/table.rb +6 -4
- 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 +10 -9
- data/lib/sparql/algebra/operator/update.rb +4 -4
- data/lib/sparql/algebra/operator/using.rb +4 -4
- data/lib/sparql/algebra/operator/uuid.rb +1 -1
- data/lib/sparql/algebra/operator/with.rb +6 -6
- data/lib/sparql/algebra/operator/year.rb +1 -1
- data/lib/sparql/algebra/query.rb +2 -2
- data/lib/sparql/algebra/update.rb +2 -2
- data/lib/sparql/algebra/version.rb +1 -1
- data/lib/sparql/extensions.rb +5 -5
- data/lib/sparql/grammar.rb +111 -11
- data/lib/sparql/grammar/meta.rb +1372 -333
- data/lib/sparql/grammar/parser11.rb +56 -42
- data/lib/sparql/grammar/terminals11.rb +1 -0
- data/lib/sparql/results.rb +63 -44
- data/lib/sparql/version.rb +1 -1
- metadata +40 -47
data/lib/rack/sparql.rb
CHANGED
@@ -18,7 +18,7 @@ module Rack
|
|
18
18
|
# @param [Hash{Symbol => Object}] options
|
19
19
|
# @option options [Boolean] :overwrite (false)
|
20
20
|
# @return [void]
|
21
|
-
def self.register_mime_types!(options
|
21
|
+
def self.register_mime_types!(**options)
|
22
22
|
if defined?(Rack::Mime::MIME_TYPES)
|
23
23
|
RDF::Format.each do |format|
|
24
24
|
if !Rack::Mime::MIME_TYPES.has_key?(file_ext = ".#{format.to_sym}") || options[:overwrite]
|
data/lib/rack/sparql/conneg.rb
CHANGED
@@ -43,7 +43,7 @@ module Rack; module SPARQL
|
|
43
43
|
#
|
44
44
|
# @param [Hash{String => String}] env
|
45
45
|
# @return [Array(Integer, Hash, #each)]
|
46
|
-
# @see
|
46
|
+
# @see https://www.rubydoc.info/github/rack/rack/Rack/Runtime#call-instance_method
|
47
47
|
def call(env)
|
48
48
|
env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
|
49
49
|
response = app.call(env)
|
@@ -71,7 +71,7 @@ module Rack; module SPARQL
|
|
71
71
|
serialize_options = {}
|
72
72
|
serialize_options[:content_types] = env['ORDERED_CONTENT_TYPES'] if env['ORDERED_CONTENT_TYPES']
|
73
73
|
serialize_options.merge!(@options)
|
74
|
-
results = ::SPARQL.serialize_results(body, serialize_options)
|
74
|
+
results = ::SPARQL.serialize_results(body, **serialize_options)
|
75
75
|
raise RDF::WriterError, "can't serialize results" unless results
|
76
76
|
headers = headers.merge(VARY).merge('Content-Type' => results.content_type) # FIXME: don't overwrite existing Vary headers
|
77
77
|
[status, headers, [results]]
|
@@ -89,7 +89,7 @@ module Rack; module SPARQL
|
|
89
89
|
#
|
90
90
|
# @param [String, #to_s] header
|
91
91
|
# @return [Array<String>]
|
92
|
-
# @see
|
92
|
+
# @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
93
93
|
def parse_accept_header(header)
|
94
94
|
entries = header.to_s.split(',')
|
95
95
|
entries.map { |e| accept_entry(e) }.sort_by(&:last).map(&:first)
|
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,9 +25,9 @@ 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
|
30
|
-
def service_description(options
|
28
|
+
# @see https://www.w3.org/TR/sparql11-service-description
|
29
|
+
# @see https://www.w3.org/TR/void/
|
30
|
+
def service_description(**options)
|
31
31
|
repository = options[:repository]
|
32
32
|
|
33
33
|
g = RDF::Graph.new
|
@@ -103,7 +103,7 @@ module Sinatra
|
|
103
103
|
app.helpers(Sinatra::SPARQL::Helpers)
|
104
104
|
app.send(:include, ::SPARQL)
|
105
105
|
app.send(:include, ::RDF)
|
106
|
-
app.send(:include, ::LinkedData)
|
106
|
+
app.send(:include, ::LinkedData) if defined?(::LinkedData)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
data/lib/sparql.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
require 'sxp'
|
1
2
|
require 'sparql/extensions'
|
3
|
+
require 'sparql/algebra/sxp_extensions'
|
2
4
|
|
3
5
|
##
|
4
6
|
# A SPARQL for RDF.rb.
|
5
7
|
#
|
6
|
-
# @see
|
8
|
+
# @see https://www.w3.org/TR/sparql11-query
|
7
9
|
module SPARQL
|
8
10
|
autoload :Algebra, 'sparql/algebra'
|
9
11
|
autoload :Grammar, 'sparql/grammar'
|
10
12
|
autoload :Results, 'sparql/results'
|
11
13
|
autoload :VERSION, 'sparql/version'
|
12
14
|
|
13
|
-
# @see
|
15
|
+
# @see https://rubygems-client
|
14
16
|
autoload :Client, 'sparql/client'
|
15
17
|
|
16
18
|
##
|
@@ -28,8 +30,8 @@ module SPARQL
|
|
28
30
|
# a `queryable` object such as an RDF::Graph
|
29
31
|
# or RDF::Repository.
|
30
32
|
# @raise [Parser::Error] on invalid input
|
31
|
-
def self.parse(query, options
|
32
|
-
query = Grammar::Parser.new(query, options).parse(options[:update] ? :UpdateUnit : :QueryUnit)
|
33
|
+
def self.parse(query, **options)
|
34
|
+
query = Grammar::Parser.new(query, **options).parse(options[:update] ? :UpdateUnit : :QueryUnit)
|
33
35
|
end
|
34
36
|
|
35
37
|
##
|
@@ -52,12 +54,13 @@ module SPARQL
|
|
52
54
|
# results = SPARQL.execute("SELECT * WHERE { ?s ?p ?o }", repository)
|
53
55
|
#
|
54
56
|
# @param [IO, StringIO, String, #to_s] query
|
57
|
+
# @param [RDF::Queryable] queryable
|
55
58
|
# @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.
|
59
|
+
# @option options [Boolean] :optimize
|
60
|
+
# Optimize query before execution.
|
59
61
|
# @option options [RDF::URI, String, Array<RDF::URI, String>] :default_graph_uri
|
60
|
-
#
|
62
|
+
# @option options [RDF::URI, String, Array<RDF::URI, String>] :load_datasets
|
63
|
+
# 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
64
|
# @option options [RDF::URI, String, Array<RDF::URI, String>] :named_graph_uri
|
62
65
|
# One or more URIs used to initialize the `queryable` as a named graph.
|
63
66
|
# @yield [solution]
|
@@ -67,8 +70,9 @@ module SPARQL
|
|
67
70
|
# @return [RDF::Graph, Boolean, RDF::Query::Solutions::Enumerator]
|
68
71
|
# Note, results may be used with {SPARQL.serialize_results} to obtain appropriate output encoding.
|
69
72
|
# @raise [SPARQL::MalformedQuery] on invalid input
|
70
|
-
def self.execute(query, queryable, options
|
71
|
-
query = self.parse(query, options)
|
73
|
+
def self.execute(query, queryable, **options, &block)
|
74
|
+
query = self.parse(query, **options)
|
75
|
+
query = query.optimize(**options) if options[:optimize]
|
72
76
|
queryable = queryable || RDF::Repository.new
|
73
77
|
|
74
78
|
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('
|
145
|
-
# Operator(:isLiteral).new(RDF::Literal(3.1415)).to_sxp #=> "(isLiteral 3.
|
146
|
-
# Operator(:str).new(Operator(:datatype).new(RDF::Literal(3.1415))).to_sxp #=> "(str (datatype 3.
|
144
|
+
# Operator(:isIRI).new(RDF::URI('https://rubygems.org/gems/rdf/')).to_sxp #=> "(isIRI <https://rubygems.org/gems/rdf/>)"
|
145
|
+
# Operator(:isLiteral).new(RDF::Literal(3.1415)).to_sxp #=> "(isLiteral 3.1415e0)"
|
146
|
+
# Operator(:str).new(Operator(:datatype).new(RDF::Literal(3.1415))).to_sxp #=> "(str (datatype 3.1415e0))"
|
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('
|
152
|
-
# SPARQL::Algebra::Expression[:isLiteral, RDF::Literal(3.1415)].to_sxp #=> "(isLiteral 3.
|
153
|
-
# SPARQL::Algebra::Expression[:str, [:datatype, RDF::Literal(3.1415)]].to_sxp #=> "(str (datatype 3.
|
151
|
+
# SPARQL::Algebra::Expression[:isIRI, RDF::URI('https://rubygems.org/gems/rdf/')].to_sxp #=> "(isIRI <https://rubygems.org/gems/rdf/>)"
|
152
|
+
# SPARQL::Algebra::Expression[:isLiteral, RDF::Literal(3.1415)].to_sxp #=> "(isLiteral 3.1415e0)"
|
153
|
+
# SPARQL::Algebra::Expression[:str, [:datatype, RDF::Literal(3.1415)]].to_sxp #=> "(str (datatype 3.1415e0))"
|
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:
|
@@ -372,8 +367,8 @@ module SPARQL
|
|
372
367
|
# @param [Hash{Symbol => Object}] options
|
373
368
|
# any additional options (see {Operator#initialize})
|
374
369
|
# @return [SPARQL::Algebra::Operator]
|
375
|
-
def parse(sse, options
|
376
|
-
Expression.parse(sse, options)
|
370
|
+
def parse(sse, **options)
|
371
|
+
Expression.parse(sse, **options)
|
377
372
|
end
|
378
373
|
module_function :parse
|
379
374
|
|
@@ -390,8 +385,8 @@ module SPARQL
|
|
390
385
|
# @yieldparam [SPARQL::Algebra::Expression] expression
|
391
386
|
# @yieldreturn [void] ignored
|
392
387
|
# @return [Expression]
|
393
|
-
def open(sse, options
|
394
|
-
Expression.open(sse, options)
|
388
|
+
def open(sse, **options)
|
389
|
+
Expression.open(sse, **options)
|
395
390
|
end
|
396
391
|
module_function :open
|
397
392
|
|
@@ -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
|
@@ -24,12 +24,12 @@ module SPARQL; module Algebra
|
|
24
24
|
# @return [RDF::Term]
|
25
25
|
# @raise [TypeError]
|
26
26
|
# @abstract
|
27
|
-
def aggregate(solutions = [], options
|
27
|
+
def aggregate(solutions = [], **options)
|
28
28
|
operands.shift if distinct = (operands.first == :distinct)
|
29
29
|
args_enum = solutions.map do |solution|
|
30
30
|
operands.map do |operand|
|
31
31
|
begin
|
32
|
-
operand.evaluate(solution,
|
32
|
+
operand.evaluate(solution, depth: options[:depth].to_i + 1, **options)
|
33
33
|
rescue TypeError
|
34
34
|
# Ignore errors
|
35
35
|
nil
|
@@ -13,8 +13,8 @@ module SPARQL; module Algebra
|
|
13
13
|
# options passed from query
|
14
14
|
# @return [RDF::Term]
|
15
15
|
# @abstract
|
16
|
-
def evaluate(bindings, options
|
17
|
-
args = operands.map { |operand| operand.evaluate(bindings,
|
16
|
+
def evaluate(bindings, **options)
|
17
|
+
args = operands.map { |operand| operand.evaluate(bindings, depth: options[:depth].to_i + 1, **options) }
|
18
18
|
options[:memoize] ? memoize(*args) : apply(*args)
|
19
19
|
end
|
20
20
|
|
@@ -19,14 +19,7 @@ module SPARQL; module Algebra
|
|
19
19
|
# @yieldparam [SPARQL::Algebra::Expression] expression
|
20
20
|
# @yieldreturn [void] ignored
|
21
21
|
# @return [Expression]
|
22
|
-
def self.parse(sse, options
|
23
|
-
begin
|
24
|
-
require 'sxp' # @see http://rubygems.org/gems/sxp
|
25
|
-
rescue LoadError
|
26
|
-
abort "SPARQL::Algebra::Expression.parse requires the SXP gem (hint: `gem install sxp')."
|
27
|
-
end
|
28
|
-
require 'sparql/algebra/sxp_extensions'
|
29
|
-
|
22
|
+
def self.parse(sse, **options, &block)
|
30
23
|
sse = sse.encode(Encoding::UTF_8)
|
31
24
|
sxp = SXP::Reader::SPARQL.new(sse) do |reader|
|
32
25
|
# Set base_uri if we have one
|
@@ -38,7 +31,7 @@ module SPARQL; module Algebra
|
|
38
31
|
Operator.base_uri = options.delete(:base_uri) if options.has_key?(:base_uri)
|
39
32
|
Operator.prefixes = sxp.prefixes || {}
|
40
33
|
|
41
|
-
expression = self.new(sxp_result, options)
|
34
|
+
expression = self.new(sxp_result, **options)
|
42
35
|
|
43
36
|
yield(expression) if block_given?
|
44
37
|
expression
|
@@ -57,8 +50,8 @@ module SPARQL; module Algebra
|
|
57
50
|
# @yieldparam [SPARQL::Algebra::Expression] expression
|
58
51
|
# @yieldreturn [void] ignored
|
59
52
|
# @return [Expression]
|
60
|
-
def self.open(filename, options
|
61
|
-
RDF::Util::File.open_file(filename, options) do |file|
|
53
|
+
def self.open(filename, **options, &block)
|
54
|
+
RDF::Util::File.open_file(filename, **options) do |file|
|
62
55
|
options[:base_uri] ||= filename
|
63
56
|
Expression.parse(file, options, &block)
|
64
57
|
end
|
@@ -87,7 +80,7 @@ module SPARQL; module Algebra
|
|
87
80
|
# any additional options (see {Operator#initialize})
|
88
81
|
# @return [Expression]
|
89
82
|
# @raise [TypeError] if any of the operands is invalid
|
90
|
-
def self.new(sse, options
|
83
|
+
def self.new(sse, **options)
|
91
84
|
raise ArgumentError, "invalid SPARQL::Algebra::Expression form: #{sse.inspect}" unless sse.is_a?(Array)
|
92
85
|
|
93
86
|
operator = Operator.for(sse.first, sse.length - 1)
|
@@ -95,7 +88,7 @@ module SPARQL; module Algebra
|
|
95
88
|
return case sse.first
|
96
89
|
when Array
|
97
90
|
debug(options) {"Map array elements #{sse}"}
|
98
|
-
sse.map {|s| self.new(s,
|
91
|
+
sse.map {|s| self.new(s, depth: options[:depth].to_i + 1, **options)}
|
99
92
|
else
|
100
93
|
debug(options) {"No operator found for #{sse.first}"}
|
101
94
|
sse.map do |s|
|
@@ -110,7 +103,7 @@ module SPARQL; module Algebra
|
|
110
103
|
debug(options) {"Operator=#{operator.inspect}, Operand=#{operand.inspect}"}
|
111
104
|
case operand
|
112
105
|
when Array
|
113
|
-
self.new(operand,
|
106
|
+
self.new(operand, depth: options[:depth].to_i + 1, **options)
|
114
107
|
when Operator, Variable, RDF::Term, RDF::Query, Symbol
|
115
108
|
operand
|
116
109
|
when TrueClass, FalseClass, Numeric, String, DateTime, Date, Time
|
@@ -175,8 +168,8 @@ module SPARQL; module Algebra
|
|
175
168
|
# @param [RDF::URI] function
|
176
169
|
# @param [Array<RDF::Term>] args splat of args to function
|
177
170
|
# @return [RDF::Term]
|
178
|
-
# @see
|
179
|
-
# @see
|
171
|
+
# @see https://www.w3.org/TR/sparql11-query/#extensionFunctions
|
172
|
+
# @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
|
180
173
|
def self.extension(function, *args)
|
181
174
|
if function.to_s.start_with?(RDF::XSD.to_s)
|
182
175
|
self.cast(function, args.first)
|
@@ -197,7 +190,7 @@ module SPARQL; module Algebra
|
|
197
190
|
# Value, which should be a typed literal, where the type must be that specified
|
198
191
|
# @raise [TypeError] if datatype is not a URI or value cannot be cast to datatype
|
199
192
|
# @return [RDF::Term]
|
200
|
-
# @see
|
193
|
+
# @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
|
201
194
|
def self.cast(datatype, value)
|
202
195
|
case datatype
|
203
196
|
when RDF::XSD.dateTime
|
@@ -280,12 +273,26 @@ module SPARQL; module Algebra
|
|
280
273
|
##
|
281
274
|
# Returns an optimized version of this expression.
|
282
275
|
#
|
283
|
-
# This is the default implementation, which simply returns `self`.
|
276
|
+
# This is the default implementation, which simply returns a copy of `self`.
|
284
277
|
# Subclasses can override this method in order to implement something
|
285
278
|
# more useful.
|
286
279
|
#
|
287
|
-
# @
|
288
|
-
|
280
|
+
# @param [Hash{Symbol => Object}] options
|
281
|
+
# any additional options for optimization
|
282
|
+
# @return [Expression] a copy of `self`
|
283
|
+
# @see RDF::Query#optimize
|
284
|
+
def optimize(**options)
|
285
|
+
self.deep_dup.optimize!(**options)
|
286
|
+
end
|
287
|
+
|
288
|
+
##
|
289
|
+
# Optimizes this query.
|
290
|
+
#
|
291
|
+
# @param [Hash{Symbol => Object}] options
|
292
|
+
# any additional options for optimization
|
293
|
+
# @return [self]
|
294
|
+
# @see RDF::Query#optimize!
|
295
|
+
def optimize!(**options)
|
289
296
|
self
|
290
297
|
end
|
291
298
|
|
@@ -313,7 +320,7 @@ module SPARQL; module Algebra
|
|
313
320
|
# more useful.
|
314
321
|
#
|
315
322
|
# @return [Array] `self`
|
316
|
-
# @see
|
323
|
+
# @see https://openjena.org/wiki/SSE
|
317
324
|
def to_sxp_bin
|
318
325
|
self
|
319
326
|
end
|
@@ -4,7 +4,7 @@ require 'json'
|
|
4
4
|
# Extensions for Ruby's `NilClass` class.
|
5
5
|
class NilClass
|
6
6
|
|
7
|
-
def evaluate(bindings, options
|
7
|
+
def evaluate(bindings, **options)
|
8
8
|
self
|
9
9
|
end
|
10
10
|
|
@@ -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
|
##
|
@@ -52,9 +68,9 @@ class Array
|
|
52
68
|
# @param [Hash{Symbol => Object}] options ({})
|
53
69
|
# options passed from query
|
54
70
|
# @return [RDF::Term]
|
55
|
-
# @see
|
56
|
-
def evaluate(bindings, options
|
57
|
-
SPARQL::Algebra::Expression.extension(*self.map {|o| o.evaluate(bindings, options)})
|
71
|
+
# @see SPARQL::Algebra::Expression.evaluate
|
72
|
+
def evaluate(bindings, **options)
|
73
|
+
SPARQL::Algebra::Expression.extension(*self.map {|o| o.evaluate(bindings, **options)})
|
58
74
|
end
|
59
75
|
|
60
76
|
##
|
@@ -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
|
70
|
-
def execute(queryable, options
|
85
|
+
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
|
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
|
##
|
@@ -191,7 +251,7 @@ module RDF::Term
|
|
191
251
|
# @param [Hash{Symbol => Object}] options ({})
|
192
252
|
# options passed from query
|
193
253
|
# @return [RDF::Term]
|
194
|
-
def evaluate(bindings, options
|
254
|
+
def evaluate(bindings, **options)
|
195
255
|
self
|
196
256
|
end
|
197
257
|
|
@@ -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
|
@@ -243,7 +314,7 @@ module RDF::Queryable
|
|
243
314
|
solutions = if method(:query_execute).arity == 1
|
244
315
|
query_execute(pattern, &block)
|
245
316
|
else
|
246
|
-
query_execute(pattern, options, &block)
|
317
|
+
query_execute(pattern, **options, &block)
|
247
318
|
end
|
248
319
|
after_query(pattern) if respond_to?(:after_query)
|
249
320
|
|
@@ -252,13 +323,12 @@ module RDF::Queryable
|
|
252
323
|
solutions
|
253
324
|
else
|
254
325
|
# Return an enumerator
|
255
|
-
enum_for(:query, pattern, options)
|
326
|
+
enum_for(:query, pattern, **options)
|
256
327
|
end
|
257
328
|
else
|
258
|
-
query_without_sparql(pattern, options, &block)
|
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,26 @@ class RDF::Query
|
|
338
427
|
variables.values
|
339
428
|
end
|
340
429
|
|
430
|
+
alias_method :optimize_without_expression!, :optimize!
|
431
|
+
##
|
432
|
+
# Optimize the query, removing lexical shortcuts in URIs
|
433
|
+
#
|
434
|
+
# @return [self]
|
435
|
+
# @see SPARQL::Algebra::Expression#optimize!
|
436
|
+
def optimize!(**options)
|
437
|
+
@patterns = @patterns.map do |pattern|
|
438
|
+
components = pattern.to_a.map do |term|
|
439
|
+
if term.respond_to?(:lexical=)
|
440
|
+
term.dup.instance_eval {@lexical = nil; self}
|
441
|
+
else
|
442
|
+
term
|
443
|
+
end
|
444
|
+
end
|
445
|
+
RDF::Query::Pattern.from(components, **pattern.options)
|
446
|
+
end
|
447
|
+
self.optimize_without_expression!(**options)
|
448
|
+
end
|
449
|
+
|
341
450
|
##
|
342
451
|
# Returns `true` if this is executable (i.e., contains a graph patterns), `false`
|
343
452
|
# otherwise.
|
@@ -386,14 +495,18 @@ class RDF::Query::Variable
|
|
386
495
|
# options passed from query
|
387
496
|
# @return [RDF::Term] the value of this variable
|
388
497
|
# @raise [TypeError] if the variable is not bound
|
389
|
-
def evaluate(bindings, options
|
498
|
+
def evaluate(bindings, **options)
|
390
499
|
raise TypeError if bindings.respond_to?(:bound?) && !bindings.bound?(self)
|
391
500
|
bindings[name.to_sym]
|
392
501
|
end
|
393
502
|
|
394
|
-
|
395
|
-
|
396
|
-
|
503
|
+
##
|
504
|
+
# Return self
|
505
|
+
#
|
506
|
+
# @return [RDF::Query::Variable] a copy of `self`
|
507
|
+
# @see SPARQL::Algebra::Expression#optimize
|
508
|
+
def optimize(**options)
|
509
|
+
self
|
397
510
|
end
|
398
511
|
end # RDF::Query::Variable
|
399
512
|
|
@@ -424,3 +537,16 @@ class RDF::Query::Solutions
|
|
424
537
|
end
|
425
538
|
alias_method :filter!, :filter
|
426
539
|
end # RDF::Query::Solutions
|
540
|
+
|
541
|
+
##
|
542
|
+
# Extensions for `RDF::Query::Solution`.
|
543
|
+
class RDF::Query::Solution
|
544
|
+
##
|
545
|
+
# Returns the SXP representation of this object, defaults to `self`.
|
546
|
+
#
|
547
|
+
# @return [String]
|
548
|
+
def to_sxp_bin
|
549
|
+
to_a.to_sxp_bin
|
550
|
+
end
|
551
|
+
def to_sxp; to_sxp_bin; end
|
552
|
+
end # RDF::Query::Solution
|