sparql 3.1.2 → 3.1.7
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 +13 -12
- data/VERSION +1 -1
- data/bin/sparql +20 -11
- data/lib/sinatra/sparql.rb +1 -1
- data/lib/sparql.rb +5 -6
- data/lib/sparql/algebra.rb +4 -4
- data/lib/sparql/algebra/aggregate.rb +1 -1
- data/lib/sparql/algebra/evaluatable.rb +4 -4
- data/lib/sparql/algebra/expression.rb +46 -31
- data/lib/sparql/algebra/extensions.rb +52 -25
- data/lib/sparql/algebra/operator.rb +22 -17
- data/lib/sparql/algebra/operator/abs.rb +1 -1
- data/lib/sparql/algebra/operator/avg.rb +8 -1
- data/lib/sparql/algebra/operator/bgp.rb +1 -1
- data/lib/sparql/algebra/operator/bnode.rb +1 -1
- data/lib/sparql/algebra/operator/ceil.rb +1 -1
- data/lib/sparql/algebra/operator/compare.rb +39 -33
- data/lib/sparql/algebra/operator/construct.rb +2 -1
- data/lib/sparql/algebra/operator/contains.rb +1 -1
- data/lib/sparql/algebra/operator/count.rb +1 -1
- data/lib/sparql/algebra/operator/dataset.rb +1 -1
- 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 +2 -2
- data/lib/sparql/algebra/operator/delete_where.rb +1 -1
- data/lib/sparql/algebra/operator/divide.rb +1 -1
- data/lib/sparql/algebra/operator/encode_for_uri.rb +1 -1
- data/lib/sparql/algebra/operator/equal.rb +1 -1
- data/lib/sparql/algebra/operator/extend.rb +2 -12
- data/lib/sparql/algebra/operator/floor.rb +1 -1
- data/lib/sparql/algebra/operator/graph.rb +1 -1
- data/lib/sparql/algebra/operator/greater_than.rb +3 -2
- data/lib/sparql/algebra/operator/greater_than_or_equal.rb +2 -2
- data/lib/sparql/algebra/operator/group_concat.rb +1 -1
- data/lib/sparql/algebra/operator/hours.rb +1 -1
- data/lib/sparql/algebra/operator/insert.rb +1 -1
- 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/is_triple.rb +30 -0
- data/lib/sparql/algebra/operator/lang.rb +1 -1
- data/lib/sparql/algebra/operator/lang_matches.rb +1 -1
- data/lib/sparql/algebra/operator/lcase.rb +1 -1
- data/lib/sparql/algebra/operator/left_join.rb +4 -0
- data/lib/sparql/algebra/operator/less_than.rb +3 -2
- data/lib/sparql/algebra/operator/less_than_or_equal.rb +2 -2
- data/lib/sparql/algebra/operator/max.rb +8 -1
- data/lib/sparql/algebra/operator/md5.rb +1 -1
- data/lib/sparql/algebra/operator/min.rb +8 -1
- data/lib/sparql/algebra/operator/minutes.rb +1 -1
- data/lib/sparql/algebra/operator/month.rb +1 -1
- 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 +3 -1
- data/lib/sparql/algebra/operator/now.rb +1 -1
- data/lib/sparql/algebra/operator/object.rb +27 -0
- data/lib/sparql/algebra/operator/order.rb +7 -1
- data/lib/sparql/algebra/operator/plus.rb +1 -1
- data/lib/sparql/algebra/operator/predicate.rb +27 -0
- data/lib/sparql/algebra/operator/rand.rb +1 -1
- data/lib/sparql/algebra/operator/regex.rb +1 -1
- data/lib/sparql/algebra/operator/replace.rb +1 -1
- data/lib/sparql/algebra/operator/round.rb +1 -1
- data/lib/sparql/algebra/operator/same_term.rb +1 -1
- data/lib/sparql/algebra/operator/sample.rb +9 -2
- data/lib/sparql/algebra/operator/seconds.rb +1 -1
- data/lib/sparql/algebra/operator/sha1.rb +1 -1
- data/lib/sparql/algebra/operator/sha256.rb +1 -1
- data/lib/sparql/algebra/operator/sha384.rb +1 -1
- data/lib/sparql/algebra/operator/sha512.rb +1 -1
- data/lib/sparql/algebra/operator/str.rb +1 -1
- data/lib/sparql/algebra/operator/strafter.rb +1 -1
- data/lib/sparql/algebra/operator/strbefore.rb +1 -1
- data/lib/sparql/algebra/operator/strdt.rb +1 -1
- data/lib/sparql/algebra/operator/strends.rb +1 -1
- data/lib/sparql/algebra/operator/strlang.rb +1 -1
- data/lib/sparql/algebra/operator/strlen.rb +1 -1
- data/lib/sparql/algebra/operator/strstarts.rb +1 -1
- data/lib/sparql/algebra/operator/struuid.rb +1 -1
- data/lib/sparql/algebra/operator/subject.rb +29 -0
- data/lib/sparql/algebra/operator/substr.rb +1 -1
- data/lib/sparql/algebra/operator/subtract.rb +1 -1
- data/lib/sparql/algebra/operator/sum.rb +1 -1
- data/lib/sparql/algebra/operator/timezone.rb +1 -1
- data/lib/sparql/algebra/operator/triple.rb +27 -0
- data/lib/sparql/algebra/operator/tz.rb +1 -1
- data/lib/sparql/algebra/operator/ucase.rb +1 -1
- data/lib/sparql/algebra/operator/uuid.rb +1 -1
- data/lib/sparql/algebra/operator/with.rb +1 -1
- data/lib/sparql/algebra/operator/year.rb +1 -1
- data/lib/sparql/extensions.rb +6 -12
- data/lib/sparql/grammar.rb +2 -28
- data/lib/sparql/grammar/meta.rb +5739 -2365
- data/lib/sparql/grammar/parser11.rb +119 -59
- data/lib/sparql/grammar/terminals11.rb +3 -0
- data/lib/sparql/results.rb +17 -9
- metadata +31 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcc81f10a741a9060299f9b3f54e1a7a35442fb7b68b7a79b2d1b67e16c0108a
|
4
|
+
data.tar.gz: aa6dd52a91d86b9a981edb5f4d56bdd0da288932ece265578ba773bb289a5fe0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64669164cff7cdd9b1580bba3576247dafff7feef77ab63ba355afb51bded23a8f996ca952332abea8a4d06f8aca4ae5db25702a69748f8577aeedb720c5f788
|
7
|
+
data.tar.gz: d269e6c8edf25e5929876d292290257527f4bfe69def6fbe3e4500283a0ed2418ac4df5420a24fd35f826970ae63c3d679ba998d27184851cc8fe58648521df7
|
data/README.md
CHANGED
@@ -3,10 +3,9 @@
|
|
3
3
|
This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
4
4
|
|
5
5
|
[](https://badge.fury.io/rb/sparql)
|
6
|
-
|
7
|
-
[](https://coveralls.io/r/ruby-rdf/sparql)
|
6
|
+
[](https://github.com/ruby-rdf/sparql/actions?query=workflow%3ACI)
|
7
|
+
[](https://coveralls.io/r/ruby-rdf/sparql?branch=develop)
|
8
|
+
[](https://gitter.im/ruby-rdf/rdf)
|
10
9
|
|
11
10
|
## Features
|
12
11
|
|
@@ -27,7 +26,7 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
|
27
26
|
* Compatible with Ruby >= 2.2.2.
|
28
27
|
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
29
28
|
* Supports Unicode query strings both on all versions of Ruby.
|
30
|
-
* Provisional support for [SPARQL
|
29
|
+
* Provisional support for [SPARQL-star][].
|
31
30
|
|
32
31
|
## Description
|
33
32
|
|
@@ -97,9 +96,9 @@ Then, use the function in a query:
|
|
97
96
|
|
98
97
|
See {SPARQL::Algebra::Expression.register_extension} for details.
|
99
98
|
|
100
|
-
### SPARQLStar (SPARQL
|
99
|
+
### SPARQLStar (SPARQL-star)
|
101
100
|
|
102
|
-
The gem supports [SPARQL
|
101
|
+
The gem supports [SPARQL-star][] where patterns may include sub-patterns recursively, for a kind of Reification.
|
103
102
|
|
104
103
|
For example, the following Turtle* file uses a statement as the subject of another statement:
|
105
104
|
|
@@ -160,7 +159,7 @@ As well as a `CONSTRUCT`:
|
|
160
159
|
<<?bob foaf:age ?age>> ?b ?c .
|
161
160
|
}
|
162
161
|
|
163
|
-
Note that results can be serialized only when the format supports [RDF
|
162
|
+
Note that results can be serialized only when the format supports [RDF-star][].
|
164
163
|
|
165
164
|
#### SPARQL results
|
166
165
|
|
@@ -419,7 +418,9 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
|
|
419
418
|
list in the the `README`. Alphabetical order applies.
|
420
419
|
* Do note that in order for us to merge any non-trivial changes (as a rule
|
421
420
|
of thumb, additions larger than about 15 lines of code), we need an
|
422
|
-
explicit [public domain dedication][PDD] on record from you
|
421
|
+
explicit [public domain dedication][PDD] on record from you,
|
422
|
+
which you will be asked to agree to on the first commit to a repo within the organization.
|
423
|
+
Note that the agreement applies to all repos in the [Ruby RDF](https://github.com/ruby-rdf/) organization.
|
423
424
|
|
424
425
|
## License
|
425
426
|
|
@@ -437,7 +438,7 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
|
|
437
438
|
[Rack::LinkedData]: https://rubygems.org/gems/rack-linkeddata
|
438
439
|
[YARD]: https://yardoc.org/
|
439
440
|
[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
440
|
-
[PDD]: https://
|
441
|
+
[PDD]: https://unlicense.org/#unlicensing-contributions
|
441
442
|
[SPARQL]: https://en.wikipedia.org/wiki/SPARQL
|
442
443
|
[SPARQL 1.0]: https://www.w3.org/TR/sparql11-query/
|
443
444
|
[SPARQL 1.0 tests]:https://www.w3.org/2001/sw/DataAccess/tests/
|
@@ -447,8 +448,8 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
|
|
447
448
|
[grammar]: https://www.w3.org/TR/sparql11-query/#grammar
|
448
449
|
[RDF 1.1]: https://www.w3.org/TR/rdf11-concepts
|
449
450
|
[RDF.rb]: https://rubydoc.info/github/ruby-rdf/rdf
|
450
|
-
[RDF
|
451
|
-
[SPARQL
|
451
|
+
[RDF-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html
|
452
|
+
[SPARQL-star]: https://w3c.github.io/rdf-star/rdf-star-cg-spec.html#sparql-query-language
|
452
453
|
[Backports]: https://rubygems.org/gems/backports
|
453
454
|
[Linked Data]: https://rubygems.org/gems/linkeddata
|
454
455
|
[SPARQL doc]: https://rubydoc.info/github/ruby-rdf/sparql/frames
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.1.
|
1
|
+
3.1.7
|
data/bin/sparql
CHANGED
@@ -38,7 +38,7 @@ def run(input, **options)
|
|
38
38
|
end
|
39
39
|
|
40
40
|
query = if options[:sse]
|
41
|
-
SPARQL::Algebra.parse(input,
|
41
|
+
SPARQL::Algebra.parse(input, logger: options[:logger], update: options[:update])
|
42
42
|
else
|
43
43
|
# Only do grammar debugging if we're generating SSE
|
44
44
|
SPARQL::Grammar.parse(input, **options)
|
@@ -47,7 +47,7 @@ def run(input, **options)
|
|
47
47
|
puts ("\nSSE:\n" + query.to_sse) if options[:debug] || options[:to_sse]
|
48
48
|
|
49
49
|
unless options[:to_sse]
|
50
|
-
res = query.execute(options[:dataset],
|
50
|
+
res = query.execute(options[:dataset], logger: options[:logger])
|
51
51
|
display_results(res, **options)
|
52
52
|
end
|
53
53
|
end
|
@@ -60,6 +60,11 @@ def server(options)
|
|
60
60
|
register Sinatra::SPARQL
|
61
61
|
set :repository, repository
|
62
62
|
|
63
|
+
before do
|
64
|
+
options[:logger].info "#{request.request_method} [#{request.path_info}], " +
|
65
|
+
params.merge(Accept: request.accept.map(&:to_s)).map {|k,v| "#{k}=#{v}" unless k.to_s == "content"}.join(" ")
|
66
|
+
end
|
67
|
+
|
63
68
|
get '/' do
|
64
69
|
if params["query"]
|
65
70
|
query = params["query"].to_s.match(/^http:/) ? RDF::Util::File.open_file(params["query"]) : ::CGI.unescape(params["query"].to_s)
|
@@ -78,20 +83,19 @@ def server(options)
|
|
78
83
|
SPARQL.execute(params['query'], settings.repository)
|
79
84
|
end
|
80
85
|
end
|
81
|
-
Rack::Server.start(app: app)
|
86
|
+
Rack::Server.start(app: app, Port: options.fetch(:port, 9292))
|
82
87
|
rescue LoadError
|
83
88
|
$stderr.puts "Running SPARQL server requires Rack to be in environment: #{$!.message}"
|
84
89
|
end
|
85
90
|
|
86
91
|
def usage
|
87
|
-
puts "Usage: #{$0} execute [options] query-file Execute a query against the specified dataset"
|
88
|
-
puts " #{$0} parse [options] query-file Parse a query into SPARQL S-Expressions (SSE)"
|
89
|
-
puts " #{$0} query [options] end-point query-file Run the query against a remote end-point"
|
90
|
-
puts " #{$0} server [options] dataset-file Start a server initialized from the specified dataset"
|
92
|
+
puts "Usage: #{File.basename($0)} execute [options] query-file Execute a query against the specified dataset"
|
93
|
+
puts " #{File.basename($0)} parse [options] query-file Parse a query into SPARQL S-Expressions (SSE)"
|
94
|
+
puts " #{File.basename($0)} query [options] end-point query-file Run the query against a remote end-point"
|
95
|
+
puts " #{File.basename($0)} server [options] dataset-file Start a server initialized from the specified dataset"
|
91
96
|
puts "Options:"
|
92
97
|
puts " --dataset: File containing RDF graph or dataset"
|
93
98
|
puts " --debug: Display detailed debug output"
|
94
|
-
puts " --debug: Display detailed debug output"
|
95
99
|
puts " --execute,-e: Use option argument as the SPARQL input if no query-file given"
|
96
100
|
puts " --format: Output format for results"
|
97
101
|
puts " --port,-p Port on which to run server; defaults to 9292"
|
@@ -116,20 +120,25 @@ opts = GetoptLong.new(
|
|
116
120
|
["--help", "-?", GetoptLong::NO_ARGUMENT]
|
117
121
|
)
|
118
122
|
|
123
|
+
logger = Logger.new(STDERR)
|
124
|
+
logger.level = Logger::WARN
|
125
|
+
logger.formatter = lambda {|severity, datetime, progname, msg| "%5s %s\n" % [severity, msg]}
|
126
|
+
|
119
127
|
options = {
|
120
128
|
dataset: RDF::Repository.new,
|
129
|
+
logger: logger,
|
121
130
|
}
|
122
131
|
|
123
132
|
opts.each do |opt, arg|
|
124
133
|
case opt
|
125
|
-
when '--dataset' then options[:dataset].load(arg, rdfstar:
|
126
|
-
when '--debug' then options[:debug] = true
|
134
|
+
when '--dataset' then options[:dataset].load(arg, rdfstar: true)
|
135
|
+
when '--debug' then options[:debug] = true ; logger.level = Logger::DEBUG
|
127
136
|
when '--execute' then input = arg
|
128
137
|
when '--format' then options[:format] = arg.to_sym
|
129
138
|
when '--port' then options[:port] = arg.to_i
|
130
139
|
when '--sse' then options[:sse] = true
|
131
140
|
when '--update' then options[:update] = true
|
132
|
-
when '--verbose' then options[:verbose] = true
|
141
|
+
when '--verbose' then options[:verbose] = true ; logger.level = Logger::INFO
|
133
142
|
when "--help" then usage
|
134
143
|
end
|
135
144
|
end
|
data/lib/sinatra/sparql.rb
CHANGED
data/lib/sparql.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
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.
|
@@ -72,12 +74,9 @@ module SPARQL
|
|
72
74
|
query = self.parse(query, **options)
|
73
75
|
query = query.optimize(**options) if options[:optimize]
|
74
76
|
queryable = queryable || RDF::Repository.new
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
puts query.to_sxp
|
79
|
-
when Array
|
80
|
-
options[:debug] << query.to_sxp
|
77
|
+
|
78
|
+
if options[:logger]
|
79
|
+
options[:logger].debug("SPARQL.execute") {SXP::Generator.string query.to_sxp_bin}
|
81
80
|
end
|
82
81
|
|
83
82
|
if options.has_key?(:load_datasets)
|
data/lib/sparql/algebra.rb
CHANGED
@@ -142,15 +142,15 @@ module SPARQL
|
|
142
142
|
#
|
143
143
|
# Operator(:isBlank).new(RDF::Node(:foobar)).to_sxp #=> "(isBlank _:foobar)"
|
144
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.
|
146
|
-
# Operator(:str).new(Operator(:datatype).new(RDF::Literal(3.1415))).to_sxp #=> "(str (datatype 3.
|
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
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.
|
153
|
-
# SPARQL::Algebra::Expression[:str, [:datatype, RDF::Literal(3.1415)]].to_sxp #=> "(str (datatype 3.
|
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
|
#
|
@@ -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
|
|
@@ -4,6 +4,8 @@ module SPARQL; module Algebra
|
|
4
4
|
#
|
5
5
|
# @abstract
|
6
6
|
module Expression
|
7
|
+
include RDF::Util::Logger
|
8
|
+
|
7
9
|
##
|
8
10
|
# @example
|
9
11
|
# Expression.parse('(isLiteral 3.1415)')
|
@@ -20,13 +22,6 @@ module SPARQL; module Algebra
|
|
20
22
|
# @yieldreturn [void] ignored
|
21
23
|
# @return [Expression]
|
22
24
|
def self.parse(sse, **options, &block)
|
23
|
-
begin
|
24
|
-
require 'sxp' # @see https://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
|
-
|
30
25
|
sse = sse.encode(Encoding::UTF_8)
|
31
26
|
sxp = SXP::Reader::SPARQL.new(sse) do |reader|
|
32
27
|
# Set base_uri if we have one
|
@@ -60,7 +55,7 @@ module SPARQL; module Algebra
|
|
60
55
|
def self.open(filename, **options, &block)
|
61
56
|
RDF::Util::File.open_file(filename, **options) do |file|
|
62
57
|
options[:base_uri] ||= filename
|
63
|
-
Expression.parse(file, options, &block)
|
58
|
+
Expression.parse(file, **options, &block)
|
64
59
|
end
|
65
60
|
end
|
66
61
|
|
@@ -120,9 +115,12 @@ module SPARQL; module Algebra
|
|
120
115
|
end
|
121
116
|
|
122
117
|
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
|
-
|
118
|
+
options.delete_if {|k, v| [:debug, :logger, :depth, :prefixes, :base_uri, :update, :validate].include?(k) }
|
119
|
+
begin
|
120
|
+
operator.new(*operands, **options)
|
121
|
+
rescue ArgumentError => e
|
122
|
+
error(options) {"Operator=#{operator.inspect}: #{e}"}
|
123
|
+
end
|
126
124
|
end
|
127
125
|
|
128
126
|
##
|
@@ -229,21 +227,45 @@ module SPARQL; module Algebra
|
|
229
227
|
when RDF::Literal::DateTime, RDF::Literal::Date, RDF::Literal::Time, RDF::URI, RDF::Node
|
230
228
|
raise TypeError, "Value #{value.inspect} cannot be cast as #{datatype}"
|
231
229
|
else
|
232
|
-
RDF::Literal.new(
|
230
|
+
RDF::Literal::Boolean.new(value.value, datatype: datatype, validate: true)
|
233
231
|
end
|
234
232
|
when RDF::XSD.decimal, RDF::XSD.integer
|
235
233
|
case value
|
236
234
|
when RDF::Literal::Boolean
|
237
235
|
RDF::Literal.new(value.object ? 1 : 0, datatype: datatype)
|
238
|
-
when RDF::Literal::
|
239
|
-
RDF::Literal.new(value, datatype: datatype)
|
236
|
+
when RDF::Literal::Numeric
|
237
|
+
RDF::Literal.new(value.object, datatype: datatype)
|
240
238
|
when RDF::Literal::DateTime, RDF::Literal::Date, RDF::Literal::Time, RDF::URI, RDF::Node
|
241
239
|
raise TypeError, "Value #{value.inspect} cannot be cast as #{datatype}"
|
242
240
|
else
|
243
241
|
RDF::Literal.new(value.value, datatype: datatype, validate: true)
|
244
242
|
end
|
245
243
|
when RDF::XSD.string
|
246
|
-
|
244
|
+
# Cast to string rules based on https://www.w3.org/TR/xpath-functions/#casting-to-string
|
245
|
+
case value
|
246
|
+
when RDF::Literal::Integer
|
247
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
248
|
+
when RDF::Literal::Decimal
|
249
|
+
if value == value.ceil
|
250
|
+
RDF::Literal.new(value.ceil, datatype: datatype)
|
251
|
+
else
|
252
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
253
|
+
end
|
254
|
+
when RDF::Literal::Float, RDF::Literal::Double
|
255
|
+
if value.abs >= 0.000001 && value.abs < 1000000
|
256
|
+
# 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.
|
257
|
+
cast(datatype, RDF::Literal::Decimal.new(value.object))
|
258
|
+
elsif value.object.zero?
|
259
|
+
# If SV has the value positive or negative zero, TV is "0" or "-0" respectively.
|
260
|
+
RDF::Literal.new(value.to_s.start_with?('-') ? '-0' : '0', datatype: datatype)
|
261
|
+
else
|
262
|
+
# If SV is positive or negative infinity, TV is the string "INF" or "-INF" respectively.
|
263
|
+
# 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.
|
264
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
265
|
+
end
|
266
|
+
else
|
267
|
+
RDF::Literal.new(value.canonicalize.to_s, datatype: datatype)
|
268
|
+
end
|
247
269
|
else
|
248
270
|
raise TypeError, "Expected datatype (#{datatype}) to be a recognized XPath function"
|
249
271
|
end
|
@@ -315,7 +337,7 @@ module SPARQL; module Algebra
|
|
315
337
|
# @param [Hash{Symbol => Object}] options ({})
|
316
338
|
# options passed from query
|
317
339
|
# @return [Expression] `self`
|
318
|
-
def evaluate(bindings, options
|
340
|
+
def evaluate(bindings, **options)
|
319
341
|
self
|
320
342
|
end
|
321
343
|
|
@@ -363,7 +385,7 @@ module SPARQL; module Algebra
|
|
363
385
|
# @param [String] node processing node
|
364
386
|
# @param [String] message
|
365
387
|
# @param [Hash{Symbol => Object}] options
|
366
|
-
# @option options [
|
388
|
+
# @option options [Logger] :logger for logging progress
|
367
389
|
# @option options [Integer] :depth (@productions.length)
|
368
390
|
# Processing depth for indenting message output.
|
369
391
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
@@ -371,7 +393,7 @@ module SPARQL; module Algebra
|
|
371
393
|
# @overload: May be called with node and an option hash
|
372
394
|
# @param [String] node processing node
|
373
395
|
# @param [Hash{Symbol => Object}] options
|
374
|
-
# @option options [
|
396
|
+
# @option options [Logger] :logger for logging progress
|
375
397
|
# @option options [Integer] :depth (@productions.length)
|
376
398
|
# Processing depth for indenting message output.
|
377
399
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
@@ -379,26 +401,19 @@ module SPARQL; module Algebra
|
|
379
401
|
# @overload: May be called with only options, in which case the block is used to return the output message
|
380
402
|
# @param [String] node processing node
|
381
403
|
# @param [Hash{Symbol => Object}] options
|
382
|
-
# @option options [
|
404
|
+
# @option options [Logger] :logger for logging progress
|
383
405
|
# @option options [Integer] :depth (@productions.length)
|
384
406
|
# Processing depth for indenting message output.
|
385
407
|
# @yieldreturn [String] appended to message, to allow for lazy-evaulation of message
|
386
|
-
def self.debug(*args)
|
408
|
+
def self.debug(*args, &block)
|
387
409
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
388
|
-
return unless options[:
|
389
|
-
|
390
|
-
message = message + yield if block_given?
|
391
|
-
depth = options[:depth] || 0
|
392
|
-
case options[:debug]
|
393
|
-
when Array
|
394
|
-
options[:debug] << "#{' ' * depth}#{message}"
|
395
|
-
else
|
396
|
-
$stderr.puts("#{' ' * depth}#{message}")
|
397
|
-
end
|
410
|
+
return unless options[:logger]
|
411
|
+
options[:logger].debug(*args, **options, &block)
|
398
412
|
end
|
399
413
|
|
400
414
|
def debug(*args, &block)
|
401
|
-
|
415
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
416
|
+
log_debug(*args, **options, &block)
|
402
417
|
end
|
403
418
|
end # Expression
|
404
419
|
end; end # SPARQL::Algebra
|
@@ -283,6 +283,20 @@ module RDF::Term
|
|
283
283
|
end
|
284
284
|
end # RDF::Term
|
285
285
|
|
286
|
+
class RDF::Literal::Double
|
287
|
+
##
|
288
|
+
# Returns the SXP representation of this object.
|
289
|
+
#
|
290
|
+
# @return [String]
|
291
|
+
def to_sxp
|
292
|
+
case
|
293
|
+
when nan? then 'nan.0'
|
294
|
+
when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0')
|
295
|
+
else canonicalize.to_s.downcase
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
286
300
|
# Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
|
287
301
|
module RDF::Queryable
|
288
302
|
alias_method :query_without_sparql, :query
|
@@ -294,7 +308,7 @@ module RDF::Queryable
|
|
294
308
|
#
|
295
309
|
# @example
|
296
310
|
# queryable.query([nil, RDF::DOAP.developer, nil])
|
297
|
-
# queryable.query(predicate: RDF::DOAP.developer)
|
311
|
+
# queryable.query({predicate: RDF::DOAP.developer})
|
298
312
|
#
|
299
313
|
# op = SPARQL::Algebra::Expression.parse(%q((bgp (triple ?a doap:developer ?b))))
|
300
314
|
# queryable.query(op)
|
@@ -306,7 +320,7 @@ module RDF::Queryable
|
|
306
320
|
# @yieldreturn [void] ignored
|
307
321
|
# @return [Enumerator]
|
308
322
|
# @see RDF::Queryable#query_pattern
|
309
|
-
def query(pattern, options
|
323
|
+
def query(pattern, **options, &block)
|
310
324
|
raise TypeError, "#{self} is not queryable" if respond_to?(:queryable?) && !queryable?
|
311
325
|
|
312
326
|
if pattern.is_a?(SPARQL::Algebra::Operator) && pattern.respond_to?(:execute)
|
@@ -335,11 +349,21 @@ class RDF::Statement
|
|
335
349
|
# Transform Statement Pattern into an SXP
|
336
350
|
# @return [Array]
|
337
351
|
def to_sxp_bin
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
352
|
+
[ (has_graph? ? :quad : :triple),
|
353
|
+
(:inferred if inferred?),
|
354
|
+
subject,
|
355
|
+
predicate,
|
356
|
+
object,
|
357
|
+
graph_name
|
358
|
+
].compact.map(&:to_sxp_bin)
|
359
|
+
end
|
360
|
+
|
361
|
+
##
|
362
|
+
# Returns an S-Expression (SXP) representation
|
363
|
+
#
|
364
|
+
# @return [String]
|
365
|
+
def to_sxp
|
366
|
+
to_sxp_bin.to_sxp
|
343
367
|
end
|
344
368
|
|
345
369
|
##
|
@@ -350,6 +374,8 @@ class RDF::Statement
|
|
350
374
|
def optimize(**options)
|
351
375
|
self.dup
|
352
376
|
end
|
377
|
+
|
378
|
+
def executable?; false; end
|
353
379
|
end
|
354
380
|
|
355
381
|
class RDF::Query
|
@@ -427,6 +453,7 @@ class RDF::Query
|
|
427
453
|
variables.values
|
428
454
|
end
|
429
455
|
|
456
|
+
alias_method :optimize_without_expression!, :optimize!
|
430
457
|
##
|
431
458
|
# Optimize the query, removing lexical shortcuts in URIs
|
432
459
|
#
|
@@ -434,39 +461,26 @@ class RDF::Query
|
|
434
461
|
# @see SPARQL::Algebra::Expression#optimize!
|
435
462
|
def optimize!(**options)
|
436
463
|
@patterns = @patterns.map do |pattern|
|
437
|
-
components = pattern.
|
464
|
+
components = pattern.to_quad.map do |term|
|
438
465
|
if term.respond_to?(:lexical=)
|
439
466
|
term.dup.instance_eval {@lexical = nil; self}
|
440
467
|
else
|
441
468
|
term
|
442
469
|
end
|
443
470
|
end
|
444
|
-
RDF::Query::Pattern.from(components)
|
445
|
-
end.sort! do |a, b|
|
446
|
-
(a.cost || 0) <=> (b.cost || 0)
|
471
|
+
RDF::Query::Pattern.from(components, **pattern.options)
|
447
472
|
end
|
448
|
-
self
|
473
|
+
self.optimize_without_expression!(**options)
|
449
474
|
end
|
450
475
|
|
451
476
|
##
|
452
|
-
# Returns `true`
|
453
|
-
# otherwise.
|
477
|
+
# Returns `true` as this is executable.
|
454
478
|
#
|
455
|
-
# @return [Boolean] `true`
|
479
|
+
# @return [Boolean] `true`
|
456
480
|
def executable?; true; end
|
457
481
|
end
|
458
482
|
|
459
483
|
class RDF::Query::Pattern
|
460
|
-
# Transform Query Pattern into an SXP
|
461
|
-
# @return [Array]
|
462
|
-
def to_sxp_bin
|
463
|
-
if has_graph?
|
464
|
-
[:quad, subject, predicate, object, graph_name]
|
465
|
-
else
|
466
|
-
[:triple, subject, predicate, object]
|
467
|
-
end
|
468
|
-
end
|
469
|
-
|
470
484
|
##
|
471
485
|
# Return the non-destinguished variables contained within this pattern
|
472
486
|
# @return [Array<RDF::Query::Variable>]
|
@@ -480,6 +494,12 @@ class RDF::Query::Pattern
|
|
480
494
|
def vars
|
481
495
|
variables.values
|
482
496
|
end
|
497
|
+
|
498
|
+
##
|
499
|
+
# Returns `true` as this is executable.
|
500
|
+
#
|
501
|
+
# @return [Boolean] `true`
|
502
|
+
def executable?; true; end
|
483
503
|
end
|
484
504
|
|
485
505
|
##
|
@@ -509,6 +529,13 @@ class RDF::Query::Variable
|
|
509
529
|
def optimize(**options)
|
510
530
|
self
|
511
531
|
end
|
532
|
+
|
533
|
+
# Display variable as SXP
|
534
|
+
# @return [Array]
|
535
|
+
def to_sxp
|
536
|
+
prefix = distinguished? ? (existential? ? '$' : '?') : (existential? ? '$$' : '??')
|
537
|
+
unbound? ? "#{prefix}#{name}".to_sym.to_sxp : ["#{prefix}#{name}".to_sym, value].to_sxp
|
538
|
+
end
|
512
539
|
end # RDF::Query::Variable
|
513
540
|
|
514
541
|
##
|