sparql 3.1.2 → 3.1.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/sparql.png)](https://badge.fury.io/rb/sparql)
|
6
|
-
|
7
|
-
[![
|
8
|
-
|
9
|
-
[![Coverage Status](https://coveralls.io/repos/ruby-rdf/sparql/badge.svg)](https://coveralls.io/r/ruby-rdf/sparql)
|
6
|
+
[![Build Status](https://github.com/ruby-rdf/sparql/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/sparql/actions?query=workflow%3ACI)
|
7
|
+
[![Coverage Status](https://coveralls.io/repos/ruby-rdf/sparql/badge.svg?branch=develop)](https://coveralls.io/r/ruby-rdf/sparql?branch=develop)
|
8
|
+
[![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](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
|
##
|