sparql 3.1.6 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +31 -22
- data/VERSION +1 -1
- data/bin/sparql +14 -4
- data/lib/sparql/algebra/aggregate.rb +1 -1
- data/lib/sparql/algebra/evaluatable.rb +4 -4
- data/lib/sparql/algebra/expression.rb +28 -3
- data/lib/sparql/algebra/extensions.rb +109 -45
- data/lib/sparql/algebra/operator/abs.rb +23 -3
- data/lib/sparql/algebra/operator/add.rb +21 -2
- data/lib/sparql/algebra/operator/alt.rb +26 -2
- data/lib/sparql/algebra/operator/and.rb +25 -3
- data/lib/sparql/algebra/operator/asc.rb +20 -1
- data/lib/sparql/algebra/operator/ask.rb +17 -1
- data/lib/sparql/algebra/operator/avg.rb +20 -2
- data/lib/sparql/algebra/operator/base.rb +18 -1
- data/lib/sparql/algebra/operator/bgp.rb +13 -1
- data/lib/sparql/algebra/operator/bnode.rb +34 -11
- data/lib/sparql/algebra/operator/bound.rb +22 -1
- data/lib/sparql/algebra/operator/ceil.rb +26 -3
- data/lib/sparql/algebra/operator/clear.rb +26 -2
- data/lib/sparql/algebra/operator/coalesce.rb +33 -11
- data/lib/sparql/algebra/operator/compare.rb +48 -40
- data/lib/sparql/algebra/operator/concat.rb +26 -2
- data/lib/sparql/algebra/operator/construct.rb +29 -6
- data/lib/sparql/algebra/operator/contains.rb +25 -3
- data/lib/sparql/algebra/operator/copy.rb +19 -2
- data/lib/sparql/algebra/operator/count.rb +53 -7
- data/lib/sparql/algebra/operator/create.rb +20 -2
- data/lib/sparql/algebra/operator/dataset.rb +27 -2
- data/lib/sparql/algebra/operator/datatype.rb +26 -7
- data/lib/sparql/algebra/operator/day.rb +24 -6
- data/lib/sparql/algebra/operator/delete.rb +29 -2
- data/lib/sparql/algebra/operator/delete_data.rb +23 -2
- data/lib/sparql/algebra/operator/delete_where.rb +24 -2
- data/lib/sparql/algebra/operator/desc.rb +20 -1
- data/lib/sparql/algebra/operator/describe.rb +27 -4
- data/lib/sparql/algebra/operator/distinct.rb +20 -3
- data/lib/sparql/algebra/operator/divide.rb +27 -3
- data/lib/sparql/algebra/operator/drop.rb +27 -3
- data/lib/sparql/algebra/operator/encode_for_uri.rb +23 -3
- data/lib/sparql/algebra/operator/equal.rb +13 -3
- data/lib/sparql/algebra/operator/exists.rb +28 -4
- data/lib/sparql/algebra/operator/exprlist.rb +15 -2
- data/lib/sparql/algebra/operator/extend.rb +64 -6
- data/lib/sparql/algebra/operator/filter.rb +27 -5
- data/lib/sparql/algebra/operator/floor.rb +26 -3
- data/lib/sparql/algebra/operator/function_call.rb +64 -0
- data/lib/sparql/algebra/operator/graph.rb +69 -6
- data/lib/sparql/algebra/operator/greater_than.rb +14 -4
- data/lib/sparql/algebra/operator/greater_than_or_equal.rb +14 -4
- data/lib/sparql/algebra/operator/group.rb +105 -8
- data/lib/sparql/algebra/operator/group_concat.rb +44 -8
- data/lib/sparql/algebra/operator/hours.rb +24 -6
- data/lib/sparql/algebra/operator/if.rb +20 -3
- data/lib/sparql/algebra/operator/in.rb +18 -1
- data/lib/sparql/algebra/operator/insert.rb +24 -2
- data/lib/sparql/algebra/operator/insert_data.rb +23 -2
- data/lib/sparql/algebra/operator/iri.rb +22 -5
- data/lib/sparql/algebra/operator/is_blank.rb +21 -4
- data/lib/sparql/algebra/operator/is_iri.rb +21 -4
- data/lib/sparql/algebra/operator/is_literal.rb +21 -4
- data/lib/sparql/algebra/operator/is_numeric.rb +23 -6
- data/lib/sparql/algebra/operator/is_triple.rb +33 -1
- data/lib/sparql/algebra/operator/join.rb +56 -1
- data/lib/sparql/algebra/operator/lang.rb +26 -1
- data/lib/sparql/algebra/operator/lang_matches.rb +23 -2
- data/lib/sparql/algebra/operator/lcase.rb +23 -3
- data/lib/sparql/algebra/operator/left_join.rb +42 -1
- data/lib/sparql/algebra/operator/less_than.rb +14 -4
- data/lib/sparql/algebra/operator/less_than_or_equal.rb +14 -4
- data/lib/sparql/algebra/operator/load.rb +25 -2
- data/lib/sparql/algebra/operator/max.rb +20 -2
- data/lib/sparql/algebra/operator/md5.rb +23 -6
- data/lib/sparql/algebra/operator/min.rb +22 -4
- data/lib/sparql/algebra/operator/minus.rb +65 -7
- data/lib/sparql/algebra/operator/minutes.rb +24 -6
- data/lib/sparql/algebra/operator/modify.rb +41 -5
- data/lib/sparql/algebra/operator/month.rb +24 -6
- data/lib/sparql/algebra/operator/move.rb +20 -2
- data/lib/sparql/algebra/operator/multiply.rb +27 -4
- data/lib/sparql/algebra/operator/negate.rb +24 -4
- data/lib/sparql/algebra/operator/not.rb +25 -4
- data/lib/sparql/algebra/operator/not_equal.rb +16 -1
- data/lib/sparql/algebra/operator/notexists.rb +30 -6
- data/lib/sparql/algebra/operator/notin.rb +20 -3
- data/lib/sparql/algebra/operator/notoneof.rb +21 -2
- data/lib/sparql/algebra/operator/now.rb +25 -6
- data/lib/sparql/algebra/operator/object.rb +33 -1
- data/lib/sparql/algebra/operator/or.rb +26 -3
- data/lib/sparql/algebra/operator/order.rb +71 -2
- data/lib/sparql/algebra/operator/path.rb +29 -2
- data/lib/sparql/algebra/operator/path_opt.rb +21 -2
- data/lib/sparql/algebra/operator/path_plus.rb +21 -2
- data/lib/sparql/algebra/operator/path_star.rb +20 -2
- data/lib/sparql/algebra/operator/plus.rb +43 -4
- data/lib/sparql/algebra/operator/predicate.rb +33 -1
- data/lib/sparql/algebra/operator/prefix.rb +24 -3
- data/lib/sparql/algebra/operator/project.rb +69 -5
- data/lib/sparql/algebra/operator/rand.rb +31 -3
- data/lib/sparql/algebra/operator/reduced.rb +20 -3
- data/lib/sparql/algebra/operator/regex.rb +27 -19
- data/lib/sparql/algebra/operator/replace.rb +27 -7
- data/lib/sparql/algebra/operator/reverse.rb +31 -2
- data/lib/sparql/algebra/operator/round.rb +26 -3
- data/lib/sparql/algebra/operator/same_term.rb +25 -7
- data/lib/sparql/algebra/operator/sample.rb +33 -9
- data/lib/sparql/algebra/operator/seconds.rb +24 -6
- data/lib/sparql/algebra/operator/seq.rb +20 -2
- data/lib/sparql/algebra/operator/sequence.rb +4 -11
- data/lib/sparql/algebra/operator/sha1.rb +19 -2
- data/lib/sparql/algebra/operator/sha256.rb +19 -2
- data/lib/sparql/algebra/operator/sha384.rb +19 -2
- data/lib/sparql/algebra/operator/sha512.rb +19 -2
- data/lib/sparql/algebra/operator/slice.rb +27 -5
- data/lib/sparql/algebra/operator/str.rb +22 -2
- data/lib/sparql/algebra/operator/strafter.rb +26 -3
- data/lib/sparql/algebra/operator/strbefore.rb +26 -3
- data/lib/sparql/algebra/operator/strdt.rb +23 -2
- data/lib/sparql/algebra/operator/strends.rb +26 -4
- data/lib/sparql/algebra/operator/strlang.rb +25 -7
- data/lib/sparql/algebra/operator/strlen.rb +24 -3
- data/lib/sparql/algebra/operator/strstarts.rb +26 -3
- data/lib/sparql/algebra/operator/struuid.rb +30 -10
- data/lib/sparql/algebra/operator/subject.rb +33 -1
- data/lib/sparql/algebra/operator/substr.rb +24 -3
- data/lib/sparql/algebra/operator/subtract.rb +29 -3
- data/lib/sparql/algebra/operator/sum.rb +25 -7
- data/lib/sparql/algebra/operator/table.rb +76 -4
- data/lib/sparql/algebra/operator/timezone.rb +24 -6
- data/lib/sparql/algebra/operator/tz.rb +23 -6
- data/lib/sparql/algebra/operator/ucase.rb +24 -3
- data/lib/sparql/algebra/operator/union.rb +29 -6
- data/lib/sparql/algebra/operator/update.rb +46 -4
- data/lib/sparql/algebra/operator/using.rb +49 -2
- data/lib/sparql/algebra/operator/uuid.rb +28 -9
- data/lib/sparql/algebra/operator/with.rb +38 -4
- data/lib/sparql/algebra/operator/year.rb +24 -6
- data/lib/sparql/algebra/operator.rb +135 -14
- data/lib/sparql/algebra/sxp_extensions.rb +3 -3
- data/lib/sparql/algebra.rb +20 -3
- data/lib/sparql/grammar/meta.rb +1103 -907
- data/lib/sparql/grammar/parser11.rb +63 -56
- metadata +43 -29
- data/lib/sparql/algebra/operator/triple.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9bcab10eb6706316b68b44a0fd917d7b735b18a8353b51e49ef124fc966176d
|
4
|
+
data.tar.gz: 6da59b4e90fd1b7a7d80c42d941f7c27f6bf95892d17302caf16a13809b03afa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2f99aee7d5b9482bbd653333eeefd215da872291993a2ba138ed9bcfc3f92812672cd1508dfbd11a729d527c9724f0a80ec816c5c84fd2df9933b4b91b5a296
|
7
|
+
data.tar.gz: 41a11caf8e85ca4bd01213bb0c0c236314560338dbd2825bd2437afbf4fd9855b994150737dbcad00838dc5ac50e368d72e5bfe2e516566a6319f824bdcacc56
|
data/README.md
CHANGED
@@ -23,8 +23,7 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
|
23
23
|
* Compatible with any [Rack][] or [Sinatra][] application and any Rack-based framework.
|
24
24
|
* Helper method for describing [SPARQL Service Description][SSD]
|
25
25
|
* Implementation Report: {file:etc/earl.html EARL}
|
26
|
-
* Compatible with Ruby >= 2.
|
27
|
-
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
26
|
+
* Compatible with Ruby >= 2.6.
|
28
27
|
* Supports Unicode query strings both on all versions of Ruby.
|
29
28
|
* Provisional support for [SPARQL-star][].
|
30
29
|
|
@@ -248,27 +247,27 @@ a full set of RDF formats.
|
|
248
247
|
### Querying a repository with a SPARQL query
|
249
248
|
|
250
249
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
251
|
-
|
252
|
-
queryable.query(
|
250
|
+
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
251
|
+
queryable.query(query) do |result|
|
253
252
|
result.inspect
|
254
253
|
end
|
255
254
|
|
256
255
|
### Executing a SPARQL query against a repository
|
257
256
|
|
258
257
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
259
|
-
|
260
|
-
|
258
|
+
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
259
|
+
query.execute(queryable) do |result|
|
261
260
|
result.inspect
|
262
261
|
end
|
263
262
|
|
264
263
|
### Updating a repository
|
265
264
|
|
266
265
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
267
|
-
|
266
|
+
update = SPARQL.parse(%(
|
268
267
|
PREFIX doap: <http://usefulinc.com/ns/doap#>
|
269
268
|
INSERT DATA { <https://rubygems> doap:implements <http://www.w3.org/TR/sparql11-update/>}
|
270
269
|
), update: true)
|
271
|
-
|
270
|
+
update.execute(queryable)
|
272
271
|
|
273
272
|
### Rendering solutions as JSON, XML, CSV, TSV or HTML
|
274
273
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
@@ -277,8 +276,15 @@ a full set of RDF formats.
|
|
277
276
|
|
278
277
|
### Parsing a SPARQL query string to SSE
|
279
278
|
|
280
|
-
|
281
|
-
|
279
|
+
query = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
280
|
+
query.to_sxp #=> (bgp (triple ?s ?p ?o))
|
281
|
+
|
282
|
+
### Parsing a SSE to SPARQL query or update string to SPARQL
|
283
|
+
|
284
|
+
# Note: if the SSE uses extension functions, they either must be XSD casting functions, or custom functions which are registered extensions. (See [SPARQL Extension Functions](#sparql-extension-functions))
|
285
|
+
|
286
|
+
query = SPARQL::Algebra.parse(%{(bgp (triple ?s ?p ?o))})
|
287
|
+
sparql = query.to_sparql #=> "SELECT * WHERE { ?s ?p ?o }"
|
282
288
|
|
283
289
|
### Command line processing
|
284
290
|
|
@@ -289,6 +295,10 @@ a full set of RDF formats.
|
|
289
295
|
sparql parse etc/input.rq
|
290
296
|
sparql parse -e "SELECT * WHERE { ?s ?p ?o }"
|
291
297
|
|
298
|
+
# Generate SPARQL Query from SSE
|
299
|
+
sparql parse --sse etc/input.sse --format sparql
|
300
|
+
sparql parse --sse --format sparql -e "(dataset (<http://usefulinc.com/ns/doap>) (bgp (triple ?s ?p ?o))))"
|
301
|
+
|
292
302
|
# Run query using SSE input
|
293
303
|
sparql execute --dataset etc/doap.ttl --sse etc/input.sse
|
294
304
|
sparql execute --sse -e "(dataset (<etc/doap.ttl>) (bgp (triple ?s ?p ?o))))"
|
@@ -368,19 +378,19 @@ Full documentation available on [Rubydoc.info][SPARQL doc]
|
|
368
378
|
|
369
379
|
## Dependencies
|
370
380
|
|
371
|
-
* [Ruby](https://ruby-lang.org/) (>= 2.
|
372
|
-
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.
|
373
|
-
* [SPARQL::Client](https://rubygems.org/gems/sparql-client) (~> 3.
|
374
|
-
* [SXP](https://rubygems.org/gems/sxp) (~> 1.
|
375
|
-
* [Builder](https://rubygems.org/gems/builder) (
|
376
|
-
* [JSON](https://rubygems.org/gems/json) (
|
377
|
-
* Soft dependency on [Linked Data][] (>= 3.
|
378
|
-
* Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (
|
381
|
+
* [Ruby](https://ruby-lang.org/) (>= 2.6)
|
382
|
+
* [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
|
383
|
+
* [SPARQL::Client](https://rubygems.org/gems/sparql-client) (~> 3.1)
|
384
|
+
* [SXP](https://rubygems.org/gems/sxp) (~> 1.2)
|
385
|
+
* [Builder](https://rubygems.org/gems/builder) (~> 3.2)
|
386
|
+
* [JSON](https://rubygems.org/gems/json) (~> 2.6)
|
387
|
+
* Soft dependency on [Linked Data][] (>= 3.1)
|
388
|
+
* Soft dependency on [Nokogiri](https://rubygems.org/gems/nokogiri) (~> 1.12)
|
379
389
|
Falls back to REXML for XML parsing Builder for XML serializing. Nokogiri is much more efficient
|
380
|
-
* Soft dependency on [Equivalent XML](https://rubygems.org/gems/equivalent-xml) (>= 0.
|
390
|
+
* Soft dependency on [Equivalent XML](https://rubygems.org/gems/equivalent-xml) (>= 0.6)
|
381
391
|
Equivalent XML performs more efficient comparisons of XML Literals when Nokogiri is included
|
382
|
-
* Soft dependency on [Rack][] (
|
383
|
-
* Soft dependency on [Sinatra][] (
|
392
|
+
* Soft dependency on [Rack][] (~> 2.2)
|
393
|
+
* Soft dependency on [Sinatra][] (~> 2.1)
|
384
394
|
|
385
395
|
## Installation
|
386
396
|
|
@@ -450,7 +460,6 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
|
|
450
460
|
[RDF.rb]: https://rubydoc.info/github/ruby-rdf/rdf
|
451
461
|
[RDF-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
|
452
462
|
[SPARQL-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html#sparql-query-language
|
453
|
-
[Backports]: https://rubygems.org/gems/backports
|
454
463
|
[Linked Data]: https://rubygems.org/gems/linkeddata
|
455
464
|
[SPARQL doc]: https://rubydoc.info/github/ruby-rdf/sparql/frames
|
456
465
|
[SPARQL XML]: https://www.w3.org/TR/rdf-sparql-XMLres/
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1
|
1
|
+
3.2.1
|
data/bin/sparql
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
3
|
$:.unshift("../../lib", __FILE__)
|
4
|
+
require 'logger'
|
4
5
|
require 'sparql'
|
5
6
|
begin
|
6
7
|
require 'linkeddata'
|
@@ -44,9 +45,18 @@ def run(input, **options)
|
|
44
45
|
SPARQL::Grammar.parse(input, **options)
|
45
46
|
end
|
46
47
|
|
47
|
-
puts ("\nSSE:\n" + query.to_sse) if options[:debug]
|
48
|
+
puts ("\nSSE:\n" + query.to_sse) if options[:debug]
|
48
49
|
|
49
|
-
|
50
|
+
if options[:parse_only]
|
51
|
+
case options[:format]
|
52
|
+
when :sparql
|
53
|
+
puts ("\nSPARQL:\n" + query.to_sparql)
|
54
|
+
when nil, :sse
|
55
|
+
puts ("\nSSE:\n" + query.to_sse)
|
56
|
+
else
|
57
|
+
$stderr.puts "Unknown output format for parsing: #{options[:format]}. Use 'sse' or 'sparql'"
|
58
|
+
end
|
59
|
+
else
|
50
60
|
res = query.execute(options[:dataset], logger: options[:logger])
|
51
61
|
display_results(res, **options)
|
52
62
|
end
|
@@ -97,7 +107,7 @@ def usage
|
|
97
107
|
puts " --dataset: File containing RDF graph or dataset"
|
98
108
|
puts " --debug: Display detailed debug output"
|
99
109
|
puts " --execute,-e: Use option argument as the SPARQL input if no query-file given"
|
100
|
-
puts " --format: Output format for results"
|
110
|
+
puts " --format: Output format for results (json, xml, csv, tsv, html, sparql, sse, or another RDF format)"
|
101
111
|
puts " --port,-p Port on which to run server; defaults to 9292"
|
102
112
|
puts " --sse: Query input is in SSE format"
|
103
113
|
puts " --update: Process query as a SPARQL Update"
|
@@ -150,7 +160,7 @@ end
|
|
150
160
|
|
151
161
|
case cmd
|
152
162
|
when 'execute', 'parse'
|
153
|
-
options[:
|
163
|
+
options[:parse_only] = true if cmd == 'parse'
|
154
164
|
input ||= ARGV.empty? ? $stdin.read : RDF::Util::File.open_file(ARGV.first).read
|
155
165
|
run(input, **options)
|
156
166
|
when 'query'
|
@@ -44,7 +44,7 @@ module SPARQL; module Algebra
|
|
44
44
|
# Enumerable yielding evaluated operands
|
45
45
|
# @return [RDF::Term]
|
46
46
|
# @abstract
|
47
|
-
def apply(enum)
|
47
|
+
def apply(enum, **options)
|
48
48
|
raise NotImplementedError, "#{self.class}#apply(#{operands.map(&:class).join(', ')})"
|
49
49
|
end
|
50
50
|
|
@@ -15,16 +15,16 @@ module SPARQL; module Algebra
|
|
15
15
|
# @abstract
|
16
16
|
def evaluate(bindings, **options)
|
17
17
|
args = operands.map { |operand| operand.evaluate(bindings, depth: options[:depth].to_i + 1, **options) }
|
18
|
-
options[:memoize] ? memoize(*args) : apply(*args)
|
18
|
+
options[:memoize] ? memoize(*args, **options) : apply(*args, **options)
|
19
19
|
end
|
20
20
|
|
21
21
|
##
|
22
22
|
# @param [Array<RDF::Term>] operands
|
23
23
|
# evaluated operands
|
24
24
|
# @return [RDF::Term] the memoized result
|
25
|
-
def memoize(*operands)
|
25
|
+
def memoize(*operands, **options)
|
26
26
|
@cache ||= RDF::Util::Cache.new(options[:memoize].is_a?(Integer) ? options[:memoize] : -1)
|
27
|
-
@cache[operands] ||= apply(*operands)
|
27
|
+
@cache[operands] ||= apply(*operands, **options)
|
28
28
|
end
|
29
29
|
|
30
30
|
##
|
@@ -32,7 +32,7 @@ module SPARQL; module Algebra
|
|
32
32
|
# evaluated operands
|
33
33
|
# @return [RDF::Term]
|
34
34
|
# @abstract
|
35
|
-
def apply(*operands)
|
35
|
+
def apply(*operands, **options)
|
36
36
|
raise NotImplementedError, "#{self.class}#apply(#{operands.map(&:class).join(', ')})"
|
37
37
|
end
|
38
38
|
|
@@ -66,9 +66,11 @@ module SPARQL; module Algebra
|
|
66
66
|
#
|
67
67
|
# @param [Array] sse
|
68
68
|
# a SPARQL S-Expression (SSE) form
|
69
|
+
# @param [Hash{Symbol => Object}] options
|
70
|
+
# any additional options (see {Operator#initialize})
|
69
71
|
# @return [Expression]
|
70
|
-
def self.for(*sse)
|
71
|
-
self.new(sse)
|
72
|
+
def self.for(*sse, **options)
|
73
|
+
self.new(sse, **options)
|
72
74
|
end
|
73
75
|
class << self; alias_method :[], :for; end
|
74
76
|
|
@@ -86,6 +88,13 @@ module SPARQL; module Algebra
|
|
86
88
|
raise ArgumentError, "invalid SPARQL::Algebra::Expression form: #{sse.inspect}" unless sse.is_a?(Array)
|
87
89
|
|
88
90
|
operator = Operator.for(sse.first, sse.length - 1)
|
91
|
+
|
92
|
+
# If we don't find an operator, and sse.first is an extension IRI, use a function call
|
93
|
+
if !operator && sse.first.is_a?(RDF::URI) && self.extension?(sse.first)
|
94
|
+
operator = Operator.for(:function_call, sse.length)
|
95
|
+
sse.unshift(:function_call)
|
96
|
+
end
|
97
|
+
|
89
98
|
unless operator
|
90
99
|
return case sse.first
|
91
100
|
when Array
|
@@ -115,11 +124,16 @@ module SPARQL; module Algebra
|
|
115
124
|
end
|
116
125
|
|
117
126
|
debug(options) {"#{operator.inspect}(#{operands.map(&:inspect).join(',')})"}
|
127
|
+
logger = options[:logger]
|
118
128
|
options.delete_if {|k, v| [:debug, :logger, :depth, :prefixes, :base_uri, :update, :validate].include?(k) }
|
119
129
|
begin
|
120
130
|
operator.new(*operands, **options)
|
121
131
|
rescue ArgumentError => e
|
122
|
-
|
132
|
+
if logger
|
133
|
+
logger.error("Operator=#{operator.inspect}: #{e}")
|
134
|
+
else
|
135
|
+
raise "Operator=#{operator.inspect}: #{e}"
|
136
|
+
end
|
123
137
|
end
|
124
138
|
end
|
125
139
|
|
@@ -163,6 +177,17 @@ module SPARQL; module Algebra
|
|
163
177
|
@extensions ||= {}
|
164
178
|
end
|
165
179
|
|
180
|
+
##
|
181
|
+
# Is an extension function available?
|
182
|
+
#
|
183
|
+
# It's either a registered extension, or an XSD casting function
|
184
|
+
#
|
185
|
+
# @param [RDF::URI] function
|
186
|
+
# @return [Boolean]
|
187
|
+
def self.extension?(function)
|
188
|
+
function.to_s.start_with?(RDF::XSD.to_s) || self.extensions[function]
|
189
|
+
end
|
190
|
+
|
166
191
|
##
|
167
192
|
# Invoke an extension function.
|
168
193
|
#
|
@@ -43,6 +43,15 @@ class Object
|
|
43
43
|
def deep_dup
|
44
44
|
dup
|
45
45
|
end
|
46
|
+
|
47
|
+
##
|
48
|
+
#
|
49
|
+
# Returns a partial SPARQL grammar for this term.
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def to_sparql(**options)
|
53
|
+
to_sxp(**options)
|
54
|
+
end
|
46
55
|
end
|
47
56
|
|
48
57
|
##
|
@@ -57,20 +66,14 @@ class Array
|
|
57
66
|
end
|
58
67
|
|
59
68
|
##
|
60
|
-
# Evaluates the array using the given variable `bindings`.
|
61
69
|
#
|
62
|
-
#
|
63
|
-
# an XSD datatype, and the second is the expression to be evaluated.
|
64
|
-
# The result is cast as a literal of the appropriate type
|
70
|
+
# Returns a partial SPARQL grammar for this array.
|
65
71
|
#
|
66
|
-
# @param
|
67
|
-
#
|
68
|
-
# @
|
69
|
-
|
70
|
-
|
71
|
-
# @see SPARQL::Algebra::Expression.evaluate
|
72
|
-
def evaluate(bindings, **options)
|
73
|
-
SPARQL::Algebra::Expression.extension(*self.map {|o| o.evaluate(bindings, **options)})
|
72
|
+
# @param [String] delimiter (" ")
|
73
|
+
# If the first element is an IRI, treat it as an extension function
|
74
|
+
# @return [String]
|
75
|
+
def to_sparql(delimiter: " ", **options)
|
76
|
+
map {|e| e.to_sparql(**options)}.join(delimiter)
|
74
77
|
end
|
75
78
|
|
76
79
|
##
|
@@ -216,15 +219,6 @@ end
|
|
216
219
|
##
|
217
220
|
# Extensions for Ruby's `Hash` class.
|
218
221
|
class Hash
|
219
|
-
##
|
220
|
-
# Returns the SXP representation of this object, defaults to `self`.
|
221
|
-
#
|
222
|
-
# @return [String]
|
223
|
-
def to_sxp_bin
|
224
|
-
to_a.to_sxp_bin
|
225
|
-
end
|
226
|
-
def to_sxp; to_sxp_bin; end
|
227
|
-
|
228
222
|
##
|
229
223
|
# A duplicate of this hash.
|
230
224
|
#
|
@@ -278,24 +272,19 @@ module RDF::Term
|
|
278
272
|
# @see SPARQL::Algebra::Expression#optimize
|
279
273
|
def optimize(**options)
|
280
274
|
optimized = self.deep_dup
|
281
|
-
optimized.lexical = nil if optimized.respond_to?(:lexical=)
|
282
|
-
optimized
|
275
|
+
#optimized.lexical = nil if optimized.respond_to?(:lexical=)
|
276
|
+
#optimized
|
283
277
|
end
|
284
|
-
end # RDF::Term
|
285
278
|
|
286
|
-
class RDF::Literal::Double
|
287
279
|
##
|
288
|
-
#
|
280
|
+
#
|
281
|
+
# Returns a partial SPARQL grammar for this term.
|
289
282
|
#
|
290
283
|
# @return [String]
|
291
|
-
def
|
292
|
-
|
293
|
-
when nan? then 'nan.0'
|
294
|
-
when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0')
|
295
|
-
else canonicalize.to_s.downcase
|
296
|
-
end
|
284
|
+
def to_sparql(**options)
|
285
|
+
to_sxp(**options)
|
297
286
|
end
|
298
|
-
end
|
287
|
+
end # RDF::Term
|
299
288
|
|
300
289
|
# Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
|
301
290
|
module RDF::Queryable
|
@@ -343,6 +332,15 @@ module RDF::Queryable
|
|
343
332
|
query_without_sparql(pattern, **options, &block)
|
344
333
|
end
|
345
334
|
end
|
335
|
+
|
336
|
+
##
|
337
|
+
#
|
338
|
+
# Returns a partial SPARQL grammar for this term.
|
339
|
+
#
|
340
|
+
# @return [String]
|
341
|
+
def to_sparql(**options)
|
342
|
+
raise NotImplementedError, "SPARQL::Algebra '#{first}' operator not implemented"
|
343
|
+
end
|
346
344
|
end
|
347
345
|
|
348
346
|
class RDF::Statement
|
@@ -361,9 +359,31 @@ class RDF::Statement
|
|
361
359
|
##
|
362
360
|
# Returns an S-Expression (SXP) representation
|
363
361
|
#
|
362
|
+
# @param [Hash{Symbol => RDF::URI}] prefixes (nil)
|
363
|
+
# @param [RDF::URI] base_uri (nil)
|
364
364
|
# @return [String]
|
365
|
-
def to_sxp
|
366
|
-
to_sxp_bin.to_sxp
|
365
|
+
def to_sxp(prefixes: nil, base_uri: nil)
|
366
|
+
to_sxp_bin.to_sxp(prefixes: prefixes, base_uri: base_uri)
|
367
|
+
end
|
368
|
+
|
369
|
+
##
|
370
|
+
#
|
371
|
+
# Returns a partial SPARQL grammar for this term.
|
372
|
+
#
|
373
|
+
# @param [Boolean] as_statement (false) serialize as < ... >, otherwise TRIPLE(...)
|
374
|
+
# @return [String]
|
375
|
+
def to_sparql(as_statement: false, **options)
|
376
|
+
if as_statement
|
377
|
+
to_triple.map do |term|
|
378
|
+
if term.is_a?(::RDF::Statement)
|
379
|
+
"<<" + term.to_sparql(as_statement: true, **options) + ">>"
|
380
|
+
else
|
381
|
+
term.to_sparql(**options)
|
382
|
+
end
|
383
|
+
end.join(" ")
|
384
|
+
else
|
385
|
+
"TRIPLE(#{to_triple.to_sparql(as_statement: true, **options)})"
|
386
|
+
end
|
367
387
|
end
|
368
388
|
|
369
389
|
##
|
@@ -411,6 +431,38 @@ class RDF::Query
|
|
411
431
|
end
|
412
432
|
end
|
413
433
|
|
434
|
+
##
|
435
|
+
#
|
436
|
+
# Returns a partial SPARQL grammar for this query.
|
437
|
+
#
|
438
|
+
# @param [Boolean] top_level (true)
|
439
|
+
# Treat this as a top-level, generating SELECT ... WHERE {}
|
440
|
+
# @param [Array<Operator>] filter_ops ([])
|
441
|
+
# Filter Operations
|
442
|
+
# @return [String]
|
443
|
+
def to_sparql(top_level: true, filter_ops: [], **options)
|
444
|
+
str = @patterns.map { |e| e.to_sparql(as_statement: true, top_level: false, **options) }.join(". \n")
|
445
|
+
str = "GRAPH #{graph_name.to_sparql(**options)} {\n#{str}\n}\n" if graph_name
|
446
|
+
if top_level
|
447
|
+
SPARQL::Algebra::Operator.to_sparql(str, filter_ops: filter_ops, **options)
|
448
|
+
else
|
449
|
+
# Filters
|
450
|
+
filter_ops.each do |op|
|
451
|
+
str << "\nFILTER (#{op.to_sparql(**options)}) ."
|
452
|
+
end
|
453
|
+
|
454
|
+
# Extensons
|
455
|
+
extensions = options.fetch(:extensions, [])
|
456
|
+
extensions.each do |as, expression|
|
457
|
+
v = expression.to_sparql(as_statement: true, **options)
|
458
|
+
v = "<< #{v} >>" if expression.is_a?(RDF::Statement)
|
459
|
+
str << "\nBIND (" << v << " AS " << as.to_sparql(**options) << ") ."
|
460
|
+
end
|
461
|
+
str = "{#{str}}" unless filter_ops.empty? && extensions.empty?
|
462
|
+
str
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
414
466
|
##
|
415
467
|
# Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
|
416
468
|
#
|
@@ -462,11 +514,11 @@ class RDF::Query
|
|
462
514
|
def optimize!(**options)
|
463
515
|
@patterns = @patterns.map do |pattern|
|
464
516
|
components = pattern.to_quad.map do |term|
|
465
|
-
if term.respond_to?(:lexical=)
|
466
|
-
|
467
|
-
else
|
517
|
+
#if term.respond_to?(:lexical=)
|
518
|
+
# term.dup.instance_eval {@lexical = nil; self}
|
519
|
+
#else
|
468
520
|
term
|
469
|
-
end
|
521
|
+
#end
|
470
522
|
end
|
471
523
|
RDF::Query::Pattern.from(components, **pattern.options)
|
472
524
|
end
|
@@ -530,11 +582,15 @@ class RDF::Query::Variable
|
|
530
582
|
self
|
531
583
|
end
|
532
584
|
|
533
|
-
|
534
|
-
#
|
535
|
-
|
536
|
-
|
537
|
-
|
585
|
+
##
|
586
|
+
#
|
587
|
+
# Returns a partial SPARQL grammar for this term.
|
588
|
+
#
|
589
|
+
# The Non-distinguished form (`??xxx`) is not part of the grammar, so replace with a blank-node
|
590
|
+
#
|
591
|
+
# @return [String]
|
592
|
+
def to_sparql(**options)
|
593
|
+
self.distinguished? ? super : "_:_nd#{self.name}"
|
538
594
|
end
|
539
595
|
end # RDF::Query::Variable
|
540
596
|
|
@@ -576,5 +632,13 @@ class RDF::Query::Solution
|
|
576
632
|
def to_sxp_bin
|
577
633
|
to_a.to_sxp_bin
|
578
634
|
end
|
579
|
-
|
635
|
+
|
636
|
+
# Transform Solution into an SXP
|
637
|
+
#
|
638
|
+
# @param [Hash{Symbol => RDF::URI}] prefixes (nil)
|
639
|
+
# @param [RDF::URI] base_uri (nil)
|
640
|
+
# @return [String]
|
641
|
+
def to_sxp(prefixes: nil, base_uri: nil)
|
642
|
+
to_sxp_bin.to_sxp(prefixes: prefixes, base_uri: base_uri)
|
643
|
+
end
|
580
644
|
end # RDF::Query::Solution
|
@@ -3,8 +3,19 @@ module SPARQL; module Algebra
|
|
3
3
|
##
|
4
4
|
# The SPARQL logical `abs` operator.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# [121] BuiltInCall ::= ... | 'ABS' '(' Expression ')'
|
7
|
+
#
|
8
|
+
# @example SPARQL Grammar
|
9
|
+
# PREFIX : <http://example.org/>
|
10
|
+
# SELECT * WHERE {
|
11
|
+
# ?s :num ?num
|
12
|
+
# FILTER(ABS(?num) >= 2)
|
13
|
+
# }
|
14
|
+
#
|
15
|
+
# @example SSE
|
16
|
+
# (prefix ((: <http://example.org/>))
|
17
|
+
# (filter (>= (abs ?num) 2)
|
18
|
+
# (bgp (triple ?s :num ?num))))
|
8
19
|
#
|
9
20
|
# @see https://www.w3.org/TR/sparql11-query/#func-abs
|
10
21
|
# @see https://www.w3.org/TR/xpath-functions/#func-abs
|
@@ -20,12 +31,21 @@ module SPARQL; module Algebra
|
|
20
31
|
# the operand
|
21
32
|
# @return [RDF::Literal] literal of same type
|
22
33
|
# @raise [TypeError] if the operand is not a numeric value
|
23
|
-
def apply(operand)
|
34
|
+
def apply(operand, **options)
|
24
35
|
case operand
|
25
36
|
when RDF::Literal::Numeric then operand.abs
|
26
37
|
else raise TypeError, "expected an RDF::Literal::Numeric, but got #{operand.inspect}"
|
27
38
|
end
|
28
39
|
end
|
40
|
+
|
41
|
+
##
|
42
|
+
#
|
43
|
+
# Returns a partial SPARQL grammar for this operator.
|
44
|
+
#
|
45
|
+
# @return [String]
|
46
|
+
def to_sparql(**options)
|
47
|
+
"ABS(#{operands.first.to_sparql(**options)})"
|
48
|
+
end
|
29
49
|
end # Abs
|
30
50
|
end # Operator
|
31
51
|
end; end # SPARQL::Algebra
|
@@ -6,8 +6,15 @@ module SPARQL; module Algebra
|
|
6
6
|
#
|
7
7
|
# The ADD operation is a shortcut for inserting all data from an input graph into a destination graph. Data from the input graph is not affected, and initial data from the destination graph, if any, is kept intact.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
9
|
+
# [35] Add ::= "ADD" "SILENT"? GraphOrDefault "TO" GraphOrDefault
|
10
|
+
#
|
11
|
+
# @example SPARQL Update
|
12
|
+
# PREFIX : <http://example.org/>
|
13
|
+
# ADD DEFAULT TO :g1
|
14
|
+
#
|
15
|
+
# @example SSE
|
16
|
+
# (prefix ((: <http://example.org/>))
|
17
|
+
# (update (add default :g1)))
|
11
18
|
#
|
12
19
|
# @see https://www.w3.org/TR/sparql11-update/#add
|
13
20
|
class Add < Operator
|
@@ -51,6 +58,18 @@ module SPARQL; module Algebra
|
|
51
58
|
end
|
52
59
|
queryable
|
53
60
|
end
|
61
|
+
|
62
|
+
##
|
63
|
+
#
|
64
|
+
# Returns a partial SPARQL grammar for this operator.
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
def to_sparql(**options)
|
68
|
+
*args, last = operands.dup
|
69
|
+
args += [:TO, last]
|
70
|
+
|
71
|
+
"ADD " + args.to_sparql(**options)
|
72
|
+
end
|
54
73
|
end # Add
|
55
74
|
end # Operator
|
56
75
|
end; end # SPARQL::Algebra
|
@@ -7,8 +7,23 @@ module SPARQL; module Algebra
|
|
7
7
|
#
|
8
8
|
# eval(Path(X, alt(P,Q), Y)) = Union(eval(Path(X, P, Y)), eval(Path(X, Q, Y)))
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# [89] PathAlternative ::= PathSequence ( '|' PathSequence )*
|
11
|
+
#
|
12
|
+
# @example SPARQL Query
|
13
|
+
# PREFIX : <http://www.example.org/>
|
14
|
+
# SELECT ?t
|
15
|
+
# WHERE {
|
16
|
+
# :a :p1|:p2/:p3|:p4 ?t
|
17
|
+
# }
|
18
|
+
#
|
19
|
+
# @example SSE
|
20
|
+
# (prefix ((: <http://www.example.org/>))
|
21
|
+
# (project (?t)
|
22
|
+
# (path :a
|
23
|
+
# (alt
|
24
|
+
# (alt :p1 (seq :p2 :p3))
|
25
|
+
# :p4)
|
26
|
+
# ?t)))
|
12
27
|
#
|
13
28
|
# @see https://www.w3.org/TR/sparql11-query/#defn_evalPP_alternative
|
14
29
|
class Alt < Operator::Binary
|
@@ -57,6 +72,15 @@ module SPARQL; module Algebra
|
|
57
72
|
query = Union.new(qa, qb)
|
58
73
|
queryable.query(query, depth: options[:depth].to_i + 1, **options, &block)
|
59
74
|
end
|
75
|
+
|
76
|
+
##
|
77
|
+
#
|
78
|
+
# Returns a partial SPARQL grammar for this operator.
|
79
|
+
#
|
80
|
+
# @return [String]
|
81
|
+
def to_sparql(**options)
|
82
|
+
"(#{operands.first.to_sparql(**options)}|#{operands.last.to_sparql(**options)})"
|
83
|
+
end
|
60
84
|
end # Alt
|
61
85
|
end # Operator
|
62
86
|
end; end # SPARQL::Algebra
|
@@ -3,9 +3,22 @@ module SPARQL; module Algebra
|
|
3
3
|
##
|
4
4
|
# The SPARQL logical `and` operator.
|
5
5
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# [112] ConditionalAndExpression::= ValueLogical ( '&&' ValueLogical )*
|
7
|
+
#
|
8
|
+
# @example SPARQL Grammar
|
9
|
+
# PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
10
|
+
# PREFIX : <http://example.org/ns#>
|
11
|
+
# SELECT ?a
|
12
|
+
# WHERE { ?a :p ?v .
|
13
|
+
# FILTER ("true"^^xsd:boolean && ?v) .
|
14
|
+
# }
|
15
|
+
#
|
16
|
+
# @example SSE
|
17
|
+
# (prefix
|
18
|
+
# ((xsd: <http://www.w3.org/2001/XMLSchema#>) (: <http://example.org/ns#>))
|
19
|
+
# (project (?a)
|
20
|
+
# (filter (&& true ?v)
|
21
|
+
# (bgp (triple ?a :p ?v)))))
|
9
22
|
#
|
10
23
|
# @see https://www.w3.org/TR/sparql11-query/#func-logical-and
|
11
24
|
# @see https://www.w3.org/TR/sparql11-query/#evaluation
|
@@ -60,6 +73,15 @@ module SPARQL; module Algebra
|
|
60
73
|
else RDF::Literal(left && right)
|
61
74
|
end
|
62
75
|
end
|
76
|
+
|
77
|
+
##
|
78
|
+
#
|
79
|
+
# Returns a partial SPARQL grammar for this operator.
|
80
|
+
#
|
81
|
+
# @return [String]
|
82
|
+
def to_sparql(**options)
|
83
|
+
"(#{operands.first.to_sparql(**options)} && #{operands.last.to_sparql(**options)})"
|
84
|
+
end
|
63
85
|
end # And
|
64
86
|
end # Operator
|
65
87
|
end; end # SPARQL::Algebra
|