sparql 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +23 -4
- data/VERSION +1 -1
- data/lib/rack/sparql/conneg.rb +5 -2
- data/lib/sinatra/sparql.rb +9 -16
- data/lib/sinatra/sparql/extensions.rb +0 -2
- data/lib/sparql.rb +8 -5
- data/lib/sparql/algebra/expression.rb +1 -1
- data/lib/sparql/algebra/extensions.rb +34 -6
- data/lib/sparql/algebra/operator/ask.rb +13 -5
- data/lib/sparql/algebra/operator/base.rb +19 -5
- data/lib/sparql/algebra/operator/bgp.rb +6 -2
- data/lib/sparql/algebra/operator/construct.rb +19 -8
- data/lib/sparql/algebra/operator/dataset.rb +8 -4
- data/lib/sparql/algebra/operator/datatype.rb +1 -7
- data/lib/sparql/algebra/operator/describe.rb +16 -6
- data/lib/sparql/algebra/operator/distinct.rb +7 -6
- data/lib/sparql/algebra/operator/exists.rb +3 -6
- data/lib/sparql/algebra/operator/extend.rb +11 -1
- data/lib/sparql/algebra/operator/filter.rb +12 -17
- data/lib/sparql/algebra/operator/graph.rb +6 -4
- data/lib/sparql/algebra/operator/group.rb +10 -5
- data/lib/sparql/algebra/operator/join.rb +16 -9
- data/lib/sparql/algebra/operator/left_join.rb +15 -11
- data/lib/sparql/algebra/operator/minus.rb +11 -7
- data/lib/sparql/algebra/operator/notexists.rb +1 -1
- data/lib/sparql/algebra/operator/order.rb +9 -3
- data/lib/sparql/algebra/operator/prefix.rb +19 -2
- data/lib/sparql/algebra/operator/project.rb +9 -4
- data/lib/sparql/algebra/operator/reduced.rb +8 -3
- data/lib/sparql/algebra/operator/slice.rb +8 -1
- data/lib/sparql/algebra/operator/table.rb +7 -2
- data/lib/sparql/algebra/operator/union.rb +7 -2
- data/lib/sparql/algebra/query.rb +26 -6
- data/lib/sparql/extensions.rb +0 -8
- data/lib/sparql/grammar/parser11.rb +1 -1
- data/lib/sparql/results.rb +6 -4
- metadata +25 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec306ea47d79b90b84acd927ef5169c6a745875b
|
4
|
+
data.tar.gz: 6e5860abfd989c5751c778c4212fdc3eb47368aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5f110a1767a95d2e2c194b2b903fd4f4db9cf470ad14529525a3ae64cc3b2b785bf25d9c95e760475a519a53c01a33ef2b0de3cfb06bee5a39e6c0c72a6337d
|
7
|
+
data.tar.gz: bf1dd65ca43bfe141f152de212ca6d9c7b2b1e11487fc8bbcaac03dabd241da86f58320926225fc784b398a5b0af4c6142636d909375e92426727fe91452b5ef
|
data/README.md
CHANGED
@@ -69,6 +69,11 @@ will be in later release along with:
|
|
69
69
|
|
70
70
|
either in this, or related gems.
|
71
71
|
|
72
|
+
### Updates for RDF 1.1
|
73
|
+
Starting with version 1.1.2, the SPARQL gem uses the 1.1 version of the [RDF.rb][], which adheres to [RDF 1.1 Concepts](http://www.w3.org/TR/rdf11-concepts/) rather than [RDF 1.0](http://www.w3.org/TR/rdf-concepts/). The main difference is that there is now no difference between a _Simple Literal_ (a literal with no datatype or language) and a Literal with datatype _xsd:string_; this causes some minor differences in the way in which queries are understood, and when expecting different results.
|
74
|
+
|
75
|
+
Additionally, queries now take a block, or return an `Enumerator`; this is in keeping with much of the behavior of [RDF.rb][] methods, including `Queryable#query`, and with version 1.1 or [RDF.rb][], Query#execute. As a consequence, all queries which used to be of the form `query.execute(repository)` may equally be called as `repository.query(query)`. Previously, results were returned as a concrete class implementing `RDF::Queryable` or `RDF::Query::Solutions`, these are now `Enumerators`.
|
76
|
+
|
72
77
|
### SPARQL Extension Functions
|
73
78
|
Extension functions may be defined, which will be invoked during query evaluation. For example:
|
74
79
|
|
@@ -94,8 +99,8 @@ See {SPARQL::Algebra::Expression.register_extension} for details.
|
|
94
99
|
### Middleware
|
95
100
|
|
96
101
|
{Rack::SPARQL} is a superset of [Rack::LinkedData][] to allow content negotiated results
|
97
|
-
to be returned any `RDF::Enumerable` or `RDF::Query::Solutions` compatible results.
|
98
|
-
You would typically return an instance of `RDF::Graph`, `RDF::Repository` or `RDF::Query::Solutions`
|
102
|
+
to be returned any `RDF::Enumerable` or an enumerator extended with `RDF::Query::Solutions` compatible results.
|
103
|
+
You would typically return an instance of `RDF::Graph`, `RDF::Repository` or an enumerator extended with `RDF::Query::Solutions`
|
99
104
|
from your Rack application, and let the `Rack::SPARQL::ContentNegotiation` middleware
|
100
105
|
take care of serializing your response into whatever format the HTTP
|
101
106
|
client requested and understands.
|
@@ -133,11 +138,21 @@ a full set of RDF formats.
|
|
133
138
|
require 'rubygems'
|
134
139
|
require 'sparql'
|
135
140
|
|
141
|
+
### Querying a repository with a SPARQL query
|
142
|
+
|
143
|
+
queryable = RDF::Repository.load("etc/doap.ttl")
|
144
|
+
sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
145
|
+
queryable.query(sse) do |result|
|
146
|
+
result.inspect
|
147
|
+
end
|
148
|
+
|
136
149
|
### Executing a SPARQL query against a repository
|
137
150
|
|
138
151
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
139
152
|
sse = SPARQL.parse("SELECT * WHERE { ?s ?p ?o }")
|
140
|
-
sse.execute(queryable)
|
153
|
+
sse.execute(queryable) do |result|
|
154
|
+
result.inspect
|
155
|
+
end
|
141
156
|
|
142
157
|
### Rendering solutions as JSON, XML, CSV, TSV or HTML
|
143
158
|
queryable = RDF::Repository.load("etc/doap.ttl")
|
@@ -272,6 +287,7 @@ To get a local working copy of the development repository, do:
|
|
272
287
|
* [Pius Uzamere](http://github.com/pius) - <http://pius.me/>
|
273
288
|
|
274
289
|
## Contributing
|
290
|
+
This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange development and release activity. All submissions _must_ be on a feature branch based on the _develop_ branch to ease staging and integration.
|
275
291
|
|
276
292
|
* Do your best to adhere to the existing coding conventions and idioms.
|
277
293
|
* Don't use hard tabs, and don't leave trailing whitespace on any line.
|
@@ -290,7 +306,9 @@ To get a local working copy of the development repository, do:
|
|
290
306
|
This is free and unencumbered public domain software. For more information,
|
291
307
|
see <http://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
292
308
|
|
293
|
-
A copy of the [SPARQL
|
309
|
+
A copy of the [SPARQL EBNF][] and derived parser files are included in the repository, which are not covered under the UNLICENSE. These files are covered via the [W3C Document License](http://www.w3.org/Consortium/Legal/2002/copyright-documents-20021231).
|
310
|
+
|
311
|
+
A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in the repository, which are not covered under the UNLICENSE; see the references for test copyright information.
|
294
312
|
|
295
313
|
[Ruby]: http://ruby-lang.org/
|
296
314
|
[RDF]: http://www.w3.org/RDF/
|
@@ -314,6 +332,7 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are included in the
|
|
314
332
|
[SPARQL doc]: http://rubydoc.info/github/ruby-rdf/sparql/frames
|
315
333
|
[SPARQL XML]: http://www.w3.org/TR/rdf-sparql-XMLres/
|
316
334
|
[SPARQL JSON]: http://www.w3.org/TR/rdf-sparql-json-res/
|
335
|
+
[SPARQL EBNF]: http://www.w3.org/TR/sparql11-query/#sparqlGrammar
|
317
336
|
[Property Paths]: http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#propertypaths
|
318
337
|
|
319
338
|
[SSD]: http://www.w3.org/TR/sparql11-service-description/
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.2
|
data/lib/rack/sparql/conneg.rb
CHANGED
@@ -34,15 +34,18 @@ module Rack; module SPARQL
|
|
34
34
|
end
|
35
35
|
|
36
36
|
##
|
37
|
-
# Handles a Rack protocol request.
|
37
|
+
# Handles a Rack protocol request. Parses Accept header to find appropriate mime-type and sets content_type accordingly.
|
38
38
|
#
|
39
39
|
# If result is `RDF::Literal::Boolean`, `RDF::Query::Results`, or `RDF::Enumerable`
|
40
40
|
# The result is serialized using {SPARQL::Results}
|
41
41
|
#
|
42
|
+
# Inserts ordered content types into the environment as `ORDERED_CONTENT_TYPES` if an Accept header is present
|
43
|
+
#
|
42
44
|
# @param [Hash{String => String}] env
|
43
45
|
# @return [Array(Integer, Hash, #each)]
|
44
46
|
# @see http://rack.rubyforge.org/doc/SPEC.html
|
45
47
|
def call(env)
|
48
|
+
env['ORDERED_CONTENT_TYPES'] = parse_accept_header(env['HTTP_ACCEPT']) if env.has_key?('HTTP_ACCEPT')
|
46
49
|
response = app.call(env)
|
47
50
|
body = response[2].respond_to?(:body) ? response[2].body : response[2]
|
48
51
|
case body
|
@@ -66,7 +69,7 @@ module Rack; module SPARQL
|
|
66
69
|
def serialize(env, status, headers, body)
|
67
70
|
begin
|
68
71
|
serialize_options = {}
|
69
|
-
serialize_options[:content_types] =
|
72
|
+
serialize_options[:content_types] = env['ORDERED_CONTENT_TYPES'] if env['ORDERED_CONTENT_TYPES']
|
70
73
|
serialize_options.merge!(@options)
|
71
74
|
results = ::SPARQL.serialize_results(body, serialize_options)
|
72
75
|
raise RDF::WriterError, "can't serialize results" unless results
|
data/lib/sinatra/sparql.rb
CHANGED
@@ -4,28 +4,23 @@ require 'rack/sparql'
|
|
4
4
|
|
5
5
|
module Sinatra
|
6
6
|
##
|
7
|
-
# The Sinatra::SPARQL module adds Rack::SPARQL} middleware support for responding to
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# to format the results appropriately.
|
7
|
+
# The Sinatra::SPARQL module adds {Rack::SPARQL} middleware support for responding to SPARQL requests. It is the responsibility of the application to manage the SPARQL endpoint and perform the query. The query results are then sent as the response body. {Rack::SPARQL} middleware uses content negotiation to format the results appropriately.
|
8
|
+
#
|
9
|
+
# To override negotiation on Content-Type, set :format in `sparql_options` to a RDF Format class, or symbol identifying a format.
|
10
|
+
#
|
12
11
|
# @see http://www.sinatrarb.com/extensions.html
|
13
12
|
module SPARQL
|
14
13
|
##
|
15
14
|
# Helper methods.
|
16
15
|
module Helpers
|
17
16
|
##
|
18
|
-
# This is useful when a GET request is performed against a SPARQL endpoint and
|
19
|
-
# no query is performed. Provide a set of datasets, including a default dataset
|
20
|
-
# along with optional triple count, dump location, and description of the dataset.
|
17
|
+
# This is useful when a GET request is performed against a SPARQL endpoint and no query is performed. Provide a set of datasets, including a default dataset along with optional triple count, dump location, and description of the dataset.
|
21
18
|
#
|
22
|
-
# The results are serialized using content negotiation. For text/html, authors
|
23
|
-
# should generate RDFa for the serivce description directly.
|
19
|
+
# The results are serialized using content negotiation. For text/html, authors should generate RDFa for the serivce description directly.
|
24
20
|
#
|
25
21
|
# @param [Hash{Symbol => Object}] options
|
26
22
|
# @option options [RDF::Enumerable] :repository
|
27
|
-
# An enumerable, typically a type of `RDF::Repository` containing the dataset used for
|
28
|
-
# queries against the service.
|
23
|
+
# An enumerable, typically a type of `RDF::Repository` containing the dataset used for queries against the service.
|
29
24
|
# @option options [RDF::URI, #to_s] :endpoint
|
30
25
|
# URI of the service endpoint, defaults to "/sparql" in the current realm.
|
31
26
|
# @return [RDF::Graph]
|
@@ -94,12 +89,10 @@ module Sinatra
|
|
94
89
|
end
|
95
90
|
|
96
91
|
##
|
97
|
-
# * Registers Rack::SPARQL::ContentNegotiation
|
92
|
+
# * Registers {Rack::SPARQL::ContentNegotiation}
|
98
93
|
# * adds helpers
|
99
94
|
# * includes SPARQL, RDF and LinkedData
|
100
|
-
# * defines `sparql_options`, which are passed to the Rack middleware
|
101
|
-
# available as `settings.sparql_options` and as options within
|
102
|
-
# the {Rack::SPARQL} middleware.
|
95
|
+
# * defines `sparql_options`, which are passed to the Rack middleware available as `settings.sparql_options` and as options within the {Rack::SPARQL} middleware.
|
103
96
|
#
|
104
97
|
# @param [Sinatra::Base] app
|
105
98
|
# @return [void]
|
@@ -7,8 +7,6 @@ class Sinatra::Response
|
|
7
7
|
headers.delete "Content-Type"
|
8
8
|
elsif RDF::Query::Solutions === body
|
9
9
|
# Don't calculate content-length here
|
10
|
-
elsif Array === body and not [204, 304].include?(status.to_i)
|
11
|
-
headers["Content-Length"] = body.inject(0) { |l, p| l + Rack::Utils.bytesize(p) }.to_s
|
12
10
|
end
|
13
11
|
|
14
12
|
# Rack::Response#finish sometimes returns self as response body. We don't want that.
|
data/lib/sparql.rb
CHANGED
@@ -58,11 +58,14 @@ module SPARQL
|
|
58
58
|
# One or more URIs used to initialize a new instance of `queryable` in the default context.
|
59
59
|
# @option options [RDF::URI, String, Array<RDF::URI, String>] :named_graph_uri
|
60
60
|
# One or more URIs used to initialize the `queryable` as a named context.
|
61
|
-
# @
|
62
|
-
#
|
63
|
-
#
|
61
|
+
# @yield [solution]
|
62
|
+
# each matching solution, statement or boolean
|
63
|
+
# @yieldparam [RDF::Statement, RDF::Query::Solution, Boolean] solution
|
64
|
+
# @yieldreturn [void] ignored
|
65
|
+
# @return [RDF::Graph, Boolean, RDF::Query::Solutions::Enumerator]
|
66
|
+
# Note, results may be used with {SPARQL.serialize_results} to obtain appropriate output encoding.
|
64
67
|
# @raise [SPARQL::MalformedQuery] on invalid input
|
65
|
-
def self.execute(query, queryable, options = {})
|
68
|
+
def self.execute(query, queryable, options = {}, &block)
|
66
69
|
query = self.parse(query, options)
|
67
70
|
queryable = queryable || RDF::Repository.new
|
68
71
|
|
@@ -82,7 +85,7 @@ module SPARQL
|
|
82
85
|
queryable.load(uri, :context => uri)
|
83
86
|
end
|
84
87
|
end
|
85
|
-
|
88
|
+
query.execute(queryable, &block)
|
86
89
|
rescue SPARQL::Grammar::Parser::Error => e
|
87
90
|
raise MalformedQuery, e.message
|
88
91
|
rescue TypeError => e
|
@@ -27,7 +27,7 @@ module SPARQL; module Algebra
|
|
27
27
|
end
|
28
28
|
require 'sparql/algebra/sxp_extensions'
|
29
29
|
|
30
|
-
sse = sse.
|
30
|
+
sse = sse.encode(Encoding::UTF_8)
|
31
31
|
sxp = SXP::Reader::SPARQL.new(sse) do |reader|
|
32
32
|
# Set base_uri if we have one
|
33
33
|
reader.base_uri = options[:base_uri] if options[:base_uri]
|
@@ -175,7 +175,7 @@ module RDF::Term
|
|
175
175
|
def compatible?(other)
|
176
176
|
return false unless literal? && other.literal? && plain? && other.plain?
|
177
177
|
|
178
|
-
dtr =
|
178
|
+
dtr = other.datatype
|
179
179
|
|
180
180
|
# * The arguments are simple literals or literals typed as xsd:string
|
181
181
|
# * The arguments are plain literals with identical language tags
|
@@ -209,16 +209,27 @@ module RDF::Queryable
|
|
209
209
|
# @yieldreturn [void] ignored
|
210
210
|
# @return [Enumerator]
|
211
211
|
# @see RDF::Queryable#query_pattern
|
212
|
-
def query(pattern, &block)
|
213
|
-
raise TypeError, "#{self} is not
|
212
|
+
def query(pattern, options = {}, &block)
|
213
|
+
raise TypeError, "#{self} is not queryable" if respond_to?(:queryable?) && !queryable?
|
214
214
|
|
215
215
|
if pattern.is_a?(SPARQL::Algebra::Operator) && pattern.respond_to?(:execute)
|
216
216
|
before_query(pattern) if respond_to?(:before_query)
|
217
|
-
query_execute
|
217
|
+
solutions = if method(:query_execute).arity == 1
|
218
|
+
query_execute(pattern, &block)
|
219
|
+
else
|
220
|
+
query_execute(pattern, options, &block)
|
221
|
+
end
|
218
222
|
after_query(pattern) if respond_to?(:after_query)
|
219
|
-
|
223
|
+
|
224
|
+
if !pattern.respond_to?(:query_yeilds_solutions?) || pattern.query_yields_solutions?
|
225
|
+
# Just return solutions
|
226
|
+
solutions
|
227
|
+
else
|
228
|
+
# Return an enumerator
|
229
|
+
enum_for(:query, pattern, options)
|
230
|
+
end
|
220
231
|
else
|
221
|
-
query_without_sparql(pattern, &block)
|
232
|
+
query_without_sparql(pattern, options, &block)
|
222
233
|
end
|
223
234
|
end
|
224
235
|
|
@@ -249,6 +260,23 @@ class RDF::Query
|
|
249
260
|
res = [:bgp] + patterns.map(&:to_sxp_bin)
|
250
261
|
(context ? [:graph, context, res] : res)
|
251
262
|
end
|
263
|
+
# Query results in a boolean result (e.g., ASK)
|
264
|
+
# @return [Boolean]
|
265
|
+
def query_yields_boolean?
|
266
|
+
false
|
267
|
+
end
|
268
|
+
|
269
|
+
# Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
|
270
|
+
# @return [Boolean]
|
271
|
+
def query_yields_statements?
|
272
|
+
false
|
273
|
+
end
|
274
|
+
|
275
|
+
# Query results solutions (e.g., SELECT)
|
276
|
+
# @return [Boolean]
|
277
|
+
def query_yields_solutions?
|
278
|
+
true
|
279
|
+
end
|
252
280
|
end
|
253
281
|
|
254
282
|
class RDF::Query::Pattern
|
@@ -22,14 +22,16 @@ module SPARQL; module Algebra
|
|
22
22
|
# the graph or repository to query
|
23
23
|
# @param [Hash{Symbol => Object}] options
|
24
24
|
# any additional keyword options
|
25
|
-
# @
|
26
|
-
#
|
25
|
+
# @yield [RDF::Literal::Boolean]
|
26
|
+
# @yieldparam [RDF::Query::Solution] solution
|
27
|
+
# @yieldreturn [void] ignored
|
28
|
+
# @return [RDF::Literal::Boolean]\
|
27
29
|
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
28
30
|
def execute(queryable, options = {})
|
29
31
|
debug(options) {"Ask #{operands.first}"}
|
30
|
-
boolean(!operands.last.
|
31
|
-
|
32
|
-
|
32
|
+
res = boolean(!queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1)).empty?)
|
33
|
+
yield res if block_given?
|
34
|
+
res
|
33
35
|
end
|
34
36
|
|
35
37
|
##
|
@@ -41,6 +43,12 @@ module SPARQL; module Algebra
|
|
41
43
|
def optimize
|
42
44
|
operands = operands.map(&:optimize)
|
43
45
|
end
|
46
|
+
|
47
|
+
# Query results in a boolean result (e.g., ASK)
|
48
|
+
# @return [Boolean]
|
49
|
+
def query_yields_boolean?
|
50
|
+
true
|
51
|
+
end
|
44
52
|
end # Ask
|
45
53
|
end # Operator
|
46
54
|
end; end # SPARQL::Algebra
|
@@ -22,15 +22,17 @@ module SPARQL; module Algebra
|
|
22
22
|
# the graph or repository to query
|
23
23
|
# @param [Hash{Symbol => Object}] options
|
24
24
|
# any additional keyword options
|
25
|
-
# @
|
25
|
+
# @yield [solution]
|
26
|
+
# each matching solution, statement or boolean
|
27
|
+
# @yieldparam [RDF::Statement, RDF::Query::Solution, Boolean] solution
|
28
|
+
# @yieldreturn [void] ignored
|
29
|
+
# @return [RDF::Queryable, RDF::Query::Solutions]
|
26
30
|
# the resulting solution sequence
|
27
31
|
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
28
|
-
def execute(queryable, options = {})
|
32
|
+
def execute(queryable, options = {}, &block)
|
29
33
|
debug(options) {"Base #{operands.first}"}
|
30
34
|
Operator.base_uri = operands.first
|
31
|
-
|
32
|
-
debug(options) {"=> #{@solutions.inspect}"}
|
33
|
-
@solutions
|
35
|
+
queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1), &block)
|
34
36
|
end
|
35
37
|
|
36
38
|
##
|
@@ -42,6 +44,18 @@ module SPARQL; module Algebra
|
|
42
44
|
def optimize
|
43
45
|
operands.last.optimize
|
44
46
|
end
|
47
|
+
|
48
|
+
# Query results in a boolean result (e.g., ASK)
|
49
|
+
# @return [Boolean]
|
50
|
+
def query_yields_boolean?
|
51
|
+
operands.last.query_yields_boolean?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
|
55
|
+
# @return [Boolean]
|
56
|
+
def query_yields_statements?
|
57
|
+
operands.last.query_yields_statements?
|
58
|
+
end
|
45
59
|
end # Base
|
46
60
|
end # Operator
|
47
61
|
end; end # SPARQL::Algebra
|
@@ -17,9 +17,13 @@ module SPARQL; module Algebra
|
|
17
17
|
#
|
18
18
|
# @overload self.new(*patterns)
|
19
19
|
# @param [Array<RDF::Query::Pattern>] patterns
|
20
|
+
# @yield [solution]
|
21
|
+
# each matching solution
|
22
|
+
# @yieldparam [RDF::Query::Solution] solution
|
23
|
+
# @yieldreturn [void] ignored
|
20
24
|
# @return [RDF::Query]
|
21
|
-
def self.new(*patterns)
|
22
|
-
RDF::Query.new(*(patterns + [{:context => false}]))
|
25
|
+
def self.new(*patterns, &block)
|
26
|
+
RDF::Query.new(*(patterns + [{:context => false}]), &block)
|
23
27
|
end
|
24
28
|
end # BGP
|
25
29
|
end # Operator
|
@@ -29,17 +29,21 @@ module SPARQL; module Algebra
|
|
29
29
|
# the graph or repository to query
|
30
30
|
# @param [Hash{Symbol => Object}] options
|
31
31
|
# any additional keyword options
|
32
|
-
# @
|
33
|
-
#
|
32
|
+
# @yield [statement]
|
33
|
+
# each matching statement
|
34
|
+
# @yieldparam [RDF::Statement] solution
|
35
|
+
# @yieldreturn [void] ignored
|
36
|
+
# @return [RDF::Queryable]
|
37
|
+
# A Queryable with constructed triples
|
34
38
|
# @see http://www.w3.org/TR/rdf-sparql-query/#construct
|
35
|
-
def execute(queryable, options = {})
|
39
|
+
def execute(queryable, options = {}, &block)
|
36
40
|
debug(options) {"Construct #{operands.first}, #{options.inspect}"}
|
37
41
|
graph = RDF::Graph.new
|
38
42
|
patterns = operands.first
|
39
43
|
query = operands.last
|
40
44
|
|
41
|
-
query
|
42
|
-
debug(options) {"
|
45
|
+
queryable.query(query, options.merge(:depth => options[:depth].to_i + 1)).each do |solution|
|
46
|
+
debug(options) {"(construct apply) #{solution.inspect} to BGP"}
|
43
47
|
|
44
48
|
# Create a mapping from BNodes within the pattern list to newly constructed BNodes
|
45
49
|
nodes = {}
|
@@ -58,16 +62,17 @@ module SPARQL; module Algebra
|
|
58
62
|
# Sanity checking on statement
|
59
63
|
if statement.subject.nil? || statement.predicate.nil? || statement.object.nil? ||
|
60
64
|
statement.subject.literal? || statement.predicate.literal?
|
61
|
-
debug(options) {"
|
65
|
+
debug(options) {"(construct skip) #{statement.inspect}"}
|
62
66
|
next
|
63
67
|
end
|
64
68
|
|
65
|
-
debug(options) {"
|
69
|
+
debug(options) {"(construct add) #{statement.inspect}"}
|
66
70
|
graph << statement
|
67
71
|
end
|
68
72
|
end
|
69
|
-
|
73
|
+
|
70
74
|
debug(options) {"=>\n#{graph.dump(:ttl, :standard_prefixes => true)}"}
|
75
|
+
graph.each(&block) if block_given?
|
71
76
|
graph
|
72
77
|
end
|
73
78
|
|
@@ -80,6 +85,12 @@ module SPARQL; module Algebra
|
|
80
85
|
def optimize
|
81
86
|
operands = operands.map(&:optimize)
|
82
87
|
end
|
88
|
+
|
89
|
+
# Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
|
90
|
+
# @return [Boolean]
|
91
|
+
def query_yields_statements?
|
92
|
+
true
|
93
|
+
end
|
83
94
|
end # Construct
|
84
95
|
end # Operator
|
85
96
|
end; end # SPARQL::Algebra
|
@@ -109,7 +109,8 @@ module SPARQL; module Algebra
|
|
109
109
|
NAME = [:dataset]
|
110
110
|
# Selected accept headers, from those available
|
111
111
|
ACCEPTS = (%w(
|
112
|
-
|
112
|
+
application/turtle
|
113
|
+
text/turtle;q=0.9
|
113
114
|
application/rdf+xml;q=0.8
|
114
115
|
application/n-triples;q=0.4
|
115
116
|
text/plain;q=0.1
|
@@ -130,10 +131,14 @@ module SPARQL; module Algebra
|
|
130
131
|
# the graph or repository to query
|
131
132
|
# @param [Hash{Symbol => Object}] options
|
132
133
|
# any additional keyword options
|
134
|
+
# @yield [solution]
|
135
|
+
# each matching solution
|
136
|
+
# @yieldparam [RDF::Query::Solution] solution
|
137
|
+
# @yieldreturn [void] ignored
|
133
138
|
# @return [RDF::Query::Solutions]
|
134
139
|
# the resulting solution sequence
|
135
140
|
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
136
|
-
def execute(queryable, options = {})
|
141
|
+
def execute(queryable, options = {}, &base)
|
137
142
|
debug(options) {"Dataset"}
|
138
143
|
default_datasets = []
|
139
144
|
named_datasets = []
|
@@ -176,8 +181,7 @@ module SPARQL; module Algebra
|
|
176
181
|
aggregate = RDF::AggregateRepo.new(queryable)
|
177
182
|
named_datasets.each {|name| aggregate.named(name) if queryable.has_context?(name)}
|
178
183
|
aggregate.default(*default_datasets.select {|name| queryable.has_context?(name)})
|
179
|
-
|
180
|
-
@solutions = executable.execute(aggregate, options.merge(:depth => options[:depth].to_i + 1))
|
184
|
+
aggregate.query(operands.last, options.merge(:depth => options[:depth].to_i + 1), &base)
|
181
185
|
end
|
182
186
|
|
183
187
|
##
|