sparql 3.0.2 → 3.1.5
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 +189 -74
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/bin/sparql +44 -24
- 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 +17 -16
- 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 +70 -44
- data/lib/sparql/algebra/extensions.rb +181 -34
- data/lib/sparql/algebra/operator.rb +44 -23
- 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 +13 -4
- data/lib/sparql/algebra/operator/base.rb +10 -10
- data/lib/sparql/algebra/operator/bgp.rb +2 -2
- 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 +6 -17
- 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 +9 -7
- data/lib/sparql/algebra/operator/delete_data.rb +3 -3
- data/lib/sparql/algebra/operator/delete_where.rb +6 -6
- 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 +2 -2
- 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 +19 -18
- 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 +6 -17
- 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 +7 -5
- 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 +19 -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 +13 -4
- data/lib/sparql/algebra/operator/md5.rb +1 -1
- data/lib/sparql/algebra/operator/min.rb +13 -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 +11 -4
- 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 +3 -3
- 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 +9 -8
- 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 +7 -7
- 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 +11 -17
- data/lib/sparql/grammar.rb +113 -13
- data/lib/sparql/grammar/meta.rb +2340 -907
- data/lib/sparql/grammar/parser11.rb +57 -52
- data/lib/sparql/grammar/terminals11.rb +2 -0
- data/lib/sparql/results.rb +73 -46
- data/lib/sparql/version.rb +1 -1
- metadata +46 -63
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,15 +70,13 @@ 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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
puts query.to_sxp
|
77
|
-
when Array
|
78
|
-
options[:debug] << query.to_sxp
|
77
|
+
|
78
|
+
if options[:logger]
|
79
|
+
options[:logger].debug("SPARQL.execute") {SXP::Generator.string query.to_sxp_bin}
|
79
80
|
end
|
80
81
|
|
81
82
|
if options.has_key?(:load_datasets)
|
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,10 +50,10 @@ 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
|
-
Expression.parse(file, options, &block)
|
56
|
+
Expression.parse(file, **options, &block)
|
64
57
|
end
|
65
58
|
end
|
66
59
|
|
@@ -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
|
@@ -120,9 +113,12 @@ module SPARQL; module Algebra
|
|
120
113
|
end
|
121
114
|
|
122
115
|
debug(options) {"#{operator.inspect}(#{operands.map(&:inspect).join(',')})"}
|
123
|
-
options.delete_if {|k, v| [:debug, :depth, :prefixes, :base_uri, :update, :validate].include?(k) }
|
124
|
-
|
125
|
-
|
116
|
+
options.delete_if {|k, v| [:debug, :logger, :depth, :prefixes, :base_uri, :update, :validate].include?(k) }
|
117
|
+
begin
|
118
|
+
operator.new(*operands, **options)
|
119
|
+
rescue ArgumentError => e
|
120
|
+
error(options) {"Operator=#{operator.inspect}: #{e}"}
|
121
|
+
end
|
126
122
|
end
|
127
123
|
|
128
124
|
##
|
@@ -175,8 +171,8 @@ module SPARQL; module Algebra
|
|
175
171
|
# @param [RDF::URI] function
|
176
172
|
# @param [Array<RDF::Term>] args splat of args to function
|
177
173
|
# @return [RDF::Term]
|
178
|
-
# @see
|
179
|
-
# @see
|
174
|
+
# @see https://www.w3.org/TR/sparql11-query/#extensionFunctions
|
175
|
+
# @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
|
180
176
|
def self.extension(function, *args)
|
181
177
|
if function.to_s.start_with?(RDF::XSD.to_s)
|
182
178
|
self.cast(function, args.first)
|
@@ -197,7 +193,7 @@ module SPARQL; module Algebra
|
|
197
193
|
# Value, which should be a typed literal, where the type must be that specified
|
198
194
|
# @raise [TypeError] if datatype is not a URI or value cannot be cast to datatype
|
199
195
|
# @return [RDF::Term]
|
200
|
-
# @see
|
196
|
+
# @see https://www.w3.org/TR/sparql11-query/#FunctionMapping
|
201
197
|
def self.cast(datatype, value)
|
202
198
|
case datatype
|
203
199
|
when RDF::XSD.dateTime
|
@@ -229,21 +225,45 @@ module SPARQL; module Algebra
|
|
229
225
|
when RDF::Literal::DateTime, RDF::Literal::Date, RDF::Literal::Time, RDF::URI, RDF::Node
|
230
226
|
raise TypeError, "Value #{value.inspect} cannot be cast as #{datatype}"
|
231
227
|
else
|
232
|
-
RDF::Literal.new(
|
228
|
+
RDF::Literal::Boolean.new(value.value, datatype: datatype, validate: true)
|
233
229
|
end
|
234
230
|
when RDF::XSD.decimal, RDF::XSD.integer
|
235
231
|
case value
|
236
232
|
when RDF::Literal::Boolean
|
237
233
|
RDF::Literal.new(value.object ? 1 : 0, datatype: datatype)
|
238
|
-
when RDF::Literal::
|
239
|
-
RDF::Literal.new(value, datatype: datatype)
|
234
|
+
when RDF::Literal::Numeric
|
235
|
+
RDF::Literal.new(value.object, datatype: datatype)
|
240
236
|
when RDF::Literal::DateTime, RDF::Literal::Date, RDF::Literal::Time, RDF::URI, RDF::Node
|
241
237
|
raise TypeError, "Value #{value.inspect} cannot be cast as #{datatype}"
|
242
238
|
else
|
243
239
|
RDF::Literal.new(value.value, datatype: datatype, validate: true)
|
244
240
|
end
|
245
241
|
when RDF::XSD.string
|
246
|
-
|
242
|
+
# Cast to string rules based on https://www.w3.org/TR/xpath-functions/#casting-to-string
|
243
|
+
case value
|
244
|
+
when RDF::Literal::Integer
|
245
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
246
|
+
when RDF::Literal::Decimal
|
247
|
+
if value == value.ceil
|
248
|
+
RDF::Literal.new(value.ceil, datatype: datatype)
|
249
|
+
else
|
250
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
251
|
+
end
|
252
|
+
when RDF::Literal::Float, RDF::Literal::Double
|
253
|
+
if value.abs >= 0.000001 && value.abs < 1000000
|
254
|
+
# If SV has an absolute value that is greater than or equal to 0.000001 (one millionth) and less than 1000000 (one million), then the value is converted to an xs:decimal and the resulting xs:decimal is converted to an xs:string according to the rules above, as though using an implementation of xs:decimal that imposes no limits on the totalDigits or fractionDigits facets.
|
255
|
+
cast(datatype, RDF::Literal::Decimal.new(value.object))
|
256
|
+
elsif value.object.zero?
|
257
|
+
# If SV has the value positive or negative zero, TV is "0" or "-0" respectively.
|
258
|
+
RDF::Literal.new(value.to_s.start_with?('-') ? '-0' : '0', datatype: datatype)
|
259
|
+
else
|
260
|
+
# If SV is positive or negative infinity, TV is the string "INF" or "-INF" respectively.
|
261
|
+
# In other cases, the result consists of a mantissa, which has the lexical form of an xs:decimal, followed by the letter "E", followed by an exponent which has the lexical form of an xs:integer. Leading zeroes and "+" signs are prohibited in the exponent. For the mantissa, there must be a decimal point, and there must be exactly one digit before the decimal point, which must be non-zero. The "+" sign is prohibited. There must be at least one digit after the decimal point. Apart from this mandatory digit, trailing zero digits are prohibited.
|
262
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
263
|
+
end
|
264
|
+
else
|
265
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
266
|
+
end
|
247
267
|
else
|
248
268
|
raise TypeError, "Expected datatype (#{datatype}) to be a recognized XPath function"
|
249
269
|
end
|
@@ -280,12 +300,26 @@ module SPARQL; module Algebra
|
|
280
300
|
##
|
281
301
|
# Returns an optimized version of this expression.
|
282
302
|
#
|
283
|
-
# This is the default implementation, which simply returns `self`.
|
303
|
+
# This is the default implementation, which simply returns a copy of `self`.
|
284
304
|
# Subclasses can override this method in order to implement something
|
285
305
|
# more useful.
|
286
306
|
#
|
287
|
-
# @
|
288
|
-
|
307
|
+
# @param [Hash{Symbol => Object}] options
|
308
|
+
# any additional options for optimization
|
309
|
+
# @return [Expression] a copy of `self`
|
310
|
+
# @see RDF::Query#optimize
|
311
|
+
def optimize(**options)
|
312
|
+
self.deep_dup.optimize!(**options)
|
313
|
+
end
|
314
|
+
|
315
|
+
##
|
316
|
+
# Optimizes this query.
|
317
|
+
#
|
318
|
+
# @param [Hash{Symbol => Object}] options
|
319
|
+
# any additional options for optimization
|
320
|
+
# @return [self]
|
321
|
+
# @see RDF::Query#optimize!
|
322
|
+
def optimize!(**options)
|
289
323
|
self
|
290
324
|
end
|
291
325
|
|
@@ -301,7 +335,7 @@ module SPARQL; module Algebra
|
|
301
335
|
# @param [Hash{Symbol => Object}] options ({})
|
302
336
|
# options passed from query
|
303
337
|
# @return [Expression] `self`
|
304
|
-
def evaluate(bindings, options
|
338
|
+
def evaluate(bindings, **options)
|
305
339
|
self
|
306
340
|
end
|
307
341
|
|
@@ -313,7 +347,7 @@ module SPARQL; module Algebra
|
|
313
347
|
# more useful.
|
314
348
|
#
|
315
349
|
# @return [Array] `self`
|
316
|
-
# @see
|
350
|
+
# @see https://openjena.org/wiki/SSE
|
317
351
|
def to_sxp_bin
|
318
352
|
self
|
319
353
|
end
|
@@ -349,7 +383,7 @@ module SPARQL; module Algebra
|
|
349
383
|
# @param [String] node processing node
|
350
384
|
# @param [String] message
|
351
385
|
# @param [Hash{Symbol => Object}] options
|
352
|
-
# @option options [
|
386
|
+
# @option options [Logger] :logger for logging progress
|
353
387
|
# @option options [Integer] :depth (@productions.length)
|
354
388
|
# Processing depth for indenting message output.
|
355
389
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
@@ -357,7 +391,7 @@ module SPARQL; module Algebra
|
|
357
391
|
# @overload: May be called with node and an option hash
|
358
392
|
# @param [String] node processing node
|
359
393
|
# @param [Hash{Symbol => Object}] options
|
360
|
-
# @option options [
|
394
|
+
# @option options [Logger] :logger for logging progress
|
361
395
|
# @option options [Integer] :depth (@productions.length)
|
362
396
|
# Processing depth for indenting message output.
|
363
397
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
@@ -365,22 +399,14 @@ module SPARQL; module Algebra
|
|
365
399
|
# @overload: May be called with only options, in which case the block is used to return the output message
|
366
400
|
# @param [String] node processing node
|
367
401
|
# @param [Hash{Symbol => Object}] options
|
368
|
-
# @option options [
|
402
|
+
# @option options [Logger] :logger for logging progress
|
369
403
|
# @option options [Integer] :depth (@productions.length)
|
370
404
|
# Processing depth for indenting message output.
|
371
405
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
372
|
-
def self.debug(*args)
|
406
|
+
def self.debug(*args, &block)
|
373
407
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
374
|
-
return unless options[:
|
375
|
-
|
376
|
-
message = message + yield if block_given?
|
377
|
-
depth = options[:depth] || 0
|
378
|
-
case options[:debug]
|
379
|
-
when Array
|
380
|
-
options[:debug] << "#{' ' * depth}#{message}"
|
381
|
-
else
|
382
|
-
$stderr.puts("#{' ' * depth}#{message}")
|
383
|
-
end
|
408
|
+
return unless options[:logger]
|
409
|
+
options[:logger].debug(*args, **options, &block)
|
384
410
|
end
|
385
411
|
|
386
412
|
def debug(*args, &block)
|