sparql 1.1.6 → 1.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 +4 -6
- data/VERSION +1 -1
- data/lib/sparql/algebra/expression.rb +28 -2
- data/lib/sparql/algebra/extensions.rb +73 -0
- data/lib/sparql/algebra/operator.rb +73 -9
- data/lib/sparql/algebra/operator/alt.rb +58 -0
- data/lib/sparql/algebra/operator/extend.rb +15 -3
- data/lib/sparql/algebra/operator/filter.rb +18 -1
- data/lib/sparql/algebra/operator/group.rb +22 -1
- data/lib/sparql/algebra/operator/join.rb +16 -5
- data/lib/sparql/algebra/operator/left_join.rb +12 -1
- data/lib/sparql/algebra/operator/notin.rb +1 -1
- data/lib/sparql/algebra/operator/notoneof.rb +52 -0
- data/lib/sparql/algebra/operator/path.rb +49 -0
- data/lib/sparql/algebra/operator/path_opt.rb +112 -0
- data/lib/sparql/algebra/operator/path_plus.rb +99 -0
- data/lib/sparql/algebra/operator/path_star.rb +42 -0
- data/lib/sparql/algebra/operator/reverse.rb +54 -0
- data/lib/sparql/algebra/operator/seq.rb +73 -0
- data/lib/sparql/algebra/operator/sequence.rb +63 -0
- data/lib/sparql/algebra/operator/union.rb +12 -1
- data/lib/sparql/algebra/query.rb +1 -0
- data/lib/sparql/grammar/meta.rb +4593 -4582
- data/lib/sparql/grammar/parser11.rb +301 -107
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8e188130c333370c626f037f5c2312a222b5f3d
|
4
|
+
data.tar.gz: 61c0398d56e8e2891dc97d4a8843411c5912e0d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9398d997c21707cfaeef51fb8fd5dd11008e0d23bcc81ee8f9027d98ee37297b19735b4c4a6202cbf241c7faf811510af0dbf588742bcaf2389cfdda1488027a
|
7
|
+
data.tar.gz: 03a7de12fa45056026eff0a2d93bfc92d375173c6afabfc462e223f10f5ea75f4ef943d22a9621aa84836b07703be4d4ee2206b917206edba70648af30f79723
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
|
9
9
|
## Features
|
10
10
|
|
11
11
|
* 100% free and unencumbered [public domain](http://unlicense.org/) software.
|
12
|
-
* [SPARQL 1.1 Query][] parsing and execution
|
12
|
+
* Complete [SPARQL 1.1 Query][] parsing and execution
|
13
13
|
* SPARQL results as [XML][SPARQL XML], [JSON][SPARQL JSON],
|
14
14
|
[CSV][SPARQL 1.1 Query Results CSV and TSV Formats],
|
15
15
|
[TSV][SPARQL 1.1 Query Results CSV and TSV Formats]
|
@@ -21,6 +21,7 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
|
21
21
|
* [Rack][] and [Sinatra][] middleware to perform [HTTP content negotiation][conneg] for result formats
|
22
22
|
* Compatible with any [Rack][] or [Sinatra][] application and any Rack-based framework.
|
23
23
|
* Helper method for describing [SPARQL Service Description][SSD]
|
24
|
+
* Implementation Report: {file:etc/earl.html EARL}
|
24
25
|
* Compatible with Ruby >= 1.9.3.
|
25
26
|
* Compatible with older Ruby versions with the help of the [Backports][] gem.
|
26
27
|
* Supports Unicode query strings both on all versions of Ruby.
|
@@ -30,8 +31,6 @@ This is a [Ruby][] implementation of [SPARQL][] for [RDF.rb][].
|
|
30
31
|
The {SPARQL} gem implements [SPARQL 1.1 Query][], and [SPARQL 1.1 Update][], and provides [Rack][] and [Sinatra][] middleware to provide results using [HTTP Content Negotiation][conneg].
|
31
32
|
|
32
33
|
* {SPARQL::Grammar} implements a [SPARQL 1.1 Query][] and [SPARQL 1.1 Update][] parser generating [SPARQL S-Expressions (SSE)][SSE].
|
33
|
-
* Support for [Property Paths][] is excluded.
|
34
|
-
See the section on [SPARQL 1.1 Query][] extensions and limitations for further detail.
|
35
34
|
* {SPARQL::Algebra} executes SSE against Any `RDF::Graph` or `RDF::Repository`, including compliant [RDF.rb][] repository adaptors such as [RDF::DO][] and [RDF::Mongo][].
|
36
35
|
* {Rack::SPARQL} and {Sinatra::SPARQL} provide middleware components to format results using an appropriate format based on [HTTP content negotiation][conneg].
|
37
36
|
|
@@ -53,13 +52,13 @@ The SPARQL gem now implements the following [SPARQL 1.1 Query][] operations:
|
|
53
52
|
* [Inline Data](http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#inline-data)
|
54
53
|
* [Exists](http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#func-filter-exists)
|
55
54
|
* [Negation](http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#negation)
|
55
|
+
* [Property Paths](http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#propertypaths)
|
56
56
|
|
57
57
|
The gem also includes the following [SPARQL 1.1 Update][] operations:
|
58
58
|
* [Graph Update](http://www.w3.org/TR/sparql11-update/#graphUpdate)
|
59
59
|
* [Graph Management](http://www.w3.org/TR/sparql11-update/#graphManagement)
|
60
60
|
|
61
|
-
|
62
|
-
[Property Paths][], which will be in later release along with:
|
61
|
+
Not supported:
|
63
62
|
|
64
63
|
* [Federated Query][SPARQL 1.1 Federated Query],
|
65
64
|
* [Entailment Regimes][SPARQL 1.1 Entailment Regimes],
|
@@ -337,7 +336,6 @@ A copy of the [SPARQL 1.0 tests][] and [SPARQL 1.1 tests][] are also included in
|
|
337
336
|
[SPARQL XML]: http://www.w3.org/TR/rdf-sparql-XMLres/
|
338
337
|
[SPARQL JSON]: http://www.w3.org/TR/rdf-sparql-json-res/
|
339
338
|
[SPARQL EBNF]: http://www.w3.org/TR/sparql11-query/#sparqlGrammar
|
340
|
-
[Property Paths]: http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#propertypaths
|
341
339
|
|
342
340
|
[SSD]: http://www.w3.org/TR/sparql11-service-description/
|
343
341
|
[Rack]: http://rack.rubyforge.org/
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.7
|
@@ -120,7 +120,7 @@ module SPARQL; module Algebra
|
|
120
120
|
end
|
121
121
|
|
122
122
|
debug(options) {"#{operator.inspect}(#{operands.map(&:inspect).join(',')})"}
|
123
|
-
options.delete_if {|k, v| [:debug, :depth, :prefixes, :base_uri, :update].include?(k) }
|
123
|
+
options.delete_if {|k, v| [:debug, :depth, :prefixes, :base_uri, :update, :validate].include?(k) }
|
124
124
|
operands << options unless options.empty?
|
125
125
|
operator.new(*operands)
|
126
126
|
end
|
@@ -317,7 +317,33 @@ module SPARQL; module Algebra
|
|
317
317
|
def to_sxp_bin
|
318
318
|
self
|
319
319
|
end
|
320
|
-
|
320
|
+
|
321
|
+
##
|
322
|
+
# Is this value valid, and composed only of valid components?
|
323
|
+
#
|
324
|
+
# @return [Boolean] `true` or `false`
|
325
|
+
def valid?
|
326
|
+
true
|
327
|
+
end
|
328
|
+
|
329
|
+
##
|
330
|
+
# Is this value invalid, or is it composed of any invalid components?
|
331
|
+
#
|
332
|
+
# @return [Boolean] `true` or `false`
|
333
|
+
def invalid?
|
334
|
+
!valid?
|
335
|
+
end
|
336
|
+
|
337
|
+
##
|
338
|
+
# Default validate! implementation, overridden in concrete classes
|
339
|
+
# @return [SPARQL::Algebra::Expression] `self`
|
340
|
+
# @raise [ArgumentError] if the value is invalid
|
341
|
+
def validate!
|
342
|
+
raise ArgumentError if invalid?
|
343
|
+
self
|
344
|
+
end
|
345
|
+
alias_method :validate, :validate!
|
346
|
+
|
321
347
|
private
|
322
348
|
# @overload: May be called with node, message and an option hash
|
323
349
|
# @param [String] node processing node
|
@@ -135,6 +135,37 @@ class Array
|
|
135
135
|
end
|
136
136
|
self
|
137
137
|
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Return the non-destinguished variables contained within this Array
|
141
|
+
# @return [Array<RDF::Query::Variable>]
|
142
|
+
def ndvars
|
143
|
+
vars.reject(&:distinguished?)
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Return the variables contained within this Array
|
148
|
+
# @return [Array<RDF::Query::Variable>]
|
149
|
+
def vars
|
150
|
+
select {|o| o.respond_to?(:vars)}.map(&:vars).flatten.compact
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Is this value composed only of valid components?
|
155
|
+
#
|
156
|
+
# @return [Boolean] `true` or `false`
|
157
|
+
def valid?
|
158
|
+
all? {|e| e.respond_to?(:valid?) ? e.valid? : true}
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Validate all components.
|
163
|
+
# @return [Array] `self`
|
164
|
+
# @raise [ArgumentError] if the value is invalid
|
165
|
+
def validate!
|
166
|
+
each {|e| e.validate! if e.respond_to?(:validate!)}
|
167
|
+
self
|
168
|
+
end
|
138
169
|
end
|
139
170
|
|
140
171
|
##
|
@@ -199,6 +230,20 @@ module RDF::Term
|
|
199
230
|
(language == other.language || dtr == RDF::XSD.string) :
|
200
231
|
dtr == RDF::XSD.string
|
201
232
|
end
|
233
|
+
|
234
|
+
##
|
235
|
+
# Return the non-destinguished variables contained within this operator
|
236
|
+
# @return [Array<RDF::Query::Variable>]
|
237
|
+
def ndvars
|
238
|
+
vars.reject(&:distinguished?)
|
239
|
+
end
|
240
|
+
|
241
|
+
##
|
242
|
+
# Return the variables contained within this operator
|
243
|
+
# @return [Array<RDF::Query::Variable>]
|
244
|
+
def vars
|
245
|
+
variable? ? [self] : []
|
246
|
+
end
|
202
247
|
end # RDF::Term
|
203
248
|
|
204
249
|
# Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
|
@@ -311,6 +356,20 @@ class RDF::Query
|
|
311
356
|
def query_yields_solutions?
|
312
357
|
true
|
313
358
|
end
|
359
|
+
|
360
|
+
##
|
361
|
+
# Return the non-destinguished variables contained within patterns
|
362
|
+
# @return [Array<RDF::Query::Variable>]
|
363
|
+
def ndvars
|
364
|
+
patterns.map(&:ndvars).flatten
|
365
|
+
end
|
366
|
+
|
367
|
+
##
|
368
|
+
# Return the variables contained within patterns
|
369
|
+
# @return [Array<RDF::Query::Variable>]
|
370
|
+
def vars
|
371
|
+
patterns.map(&:vars).flatten
|
372
|
+
end
|
314
373
|
end
|
315
374
|
|
316
375
|
class RDF::Query::Pattern
|
@@ -323,6 +382,20 @@ class RDF::Query::Pattern
|
|
323
382
|
[:triple, subject, predicate, object]
|
324
383
|
end
|
325
384
|
end
|
385
|
+
|
386
|
+
##
|
387
|
+
# Return the non-destinguished variables contained within this pattern
|
388
|
+
# @return [Array<RDF::Query::Variable>]
|
389
|
+
def ndvars
|
390
|
+
vars.reject(&:distinguished?)
|
391
|
+
end
|
392
|
+
|
393
|
+
##
|
394
|
+
# Return the variables contained within this pattern
|
395
|
+
# @return [Array<RDF::Query::Variable>]
|
396
|
+
def vars
|
397
|
+
variables.values
|
398
|
+
end
|
326
399
|
end
|
327
400
|
|
328
401
|
##
|
@@ -85,6 +85,17 @@ module SPARQL; module Algebra
|
|
85
85
|
autoload :Subtract, 'sparql/algebra/operator/subtract'
|
86
86
|
autoload :UCase, 'sparql/algebra/operator/ucase'
|
87
87
|
|
88
|
+
# Property Paths
|
89
|
+
autoload :Alt, 'sparql/algebra/operator/alt'
|
90
|
+
autoload :NotOneOf, 'sparql/algebra/operator/notoneof'
|
91
|
+
autoload :PathOpt, 'sparql/algebra/operator/path_opt'
|
92
|
+
autoload :PathPlus, 'sparql/algebra/operator/path_plus'
|
93
|
+
autoload :PathStar, 'sparql/algebra/operator/path_star'
|
94
|
+
autoload :Path, 'sparql/algebra/operator/path'
|
95
|
+
autoload :Reverse, 'sparql/algebra/operator/reverse'
|
96
|
+
autoload :Seq, 'sparql/algebra/operator/seq'
|
97
|
+
autoload :Sequence, 'sparql/algebra/operator/sequence'
|
98
|
+
|
88
99
|
# Miscellaneous
|
89
100
|
autoload :Asc, 'sparql/algebra/operator/asc'
|
90
101
|
autoload :Coalesce, 'sparql/algebra/operator/coalesce'
|
@@ -159,6 +170,7 @@ module SPARQL; module Algebra
|
|
159
170
|
when :>= then GreaterThanOrEqual
|
160
171
|
when :abs then Abs
|
161
172
|
when :add then Add
|
173
|
+
when :alt then Alt
|
162
174
|
when :and, :'&&' then And
|
163
175
|
when :avg then Avg
|
164
176
|
when :bnode then BNode
|
@@ -195,18 +207,26 @@ module SPARQL; module Algebra
|
|
195
207
|
when :month then Month
|
196
208
|
when :multiply then Multiply
|
197
209
|
when :not, :'!' then Not
|
198
|
-
when :notexists
|
210
|
+
when :notexists then NotExists
|
199
211
|
when :notin then NotIn
|
212
|
+
when :notoneof then NotOneOf
|
200
213
|
when :now then Now
|
201
214
|
when :or, :'||' then Or
|
215
|
+
when :path then Path
|
216
|
+
when :path? then PathOpt
|
217
|
+
when :"path*" then PathStar
|
218
|
+
when :"path+" then PathPlus
|
202
219
|
when :plus then Plus
|
203
220
|
when :rand then Rand
|
204
221
|
when :regex then Regex
|
205
222
|
when :replace then Replace
|
223
|
+
when :reverse then Reverse
|
206
224
|
when :round then Round
|
207
225
|
when :sameterm then SameTerm
|
208
226
|
when :sample then Sample
|
209
227
|
when :seconds then Seconds
|
228
|
+
when :seq then Seq
|
229
|
+
when :sequence then Sequence
|
210
230
|
when :sha1 then SHA1
|
211
231
|
when :sha256 then SHA256
|
212
232
|
when :sha512 then SHA512
|
@@ -322,7 +342,11 @@ module SPARQL; module Algebra
|
|
322
342
|
@options = operands.last.is_a?(Hash) ? operands.pop.dup : {}
|
323
343
|
@operands = operands.map! do |operand|
|
324
344
|
case operand
|
345
|
+
when Array
|
346
|
+
operand.each {|op| op.parent = self if operand.respond_to?(:parent=)}
|
347
|
+
operand
|
325
348
|
when Operator, Variable, RDF::Term, RDF::Query, RDF::Query::Pattern, Array, Symbol
|
349
|
+
operand.parent = self if operand.respond_to?(:parent=)
|
326
350
|
operand
|
327
351
|
when TrueClass, FalseClass, Numeric, String, DateTime, Date, Time
|
328
352
|
RDF::Literal(operand)
|
@@ -387,12 +411,6 @@ module SPARQL; module Algebra
|
|
387
411
|
@prefixes = hash
|
388
412
|
end
|
389
413
|
|
390
|
-
##
|
391
|
-
# Any additional options for this operator.
|
392
|
-
#
|
393
|
-
# @return [Hash]
|
394
|
-
attr_reader :options
|
395
|
-
|
396
414
|
##
|
397
415
|
# The operands to this operator.
|
398
416
|
#
|
@@ -540,7 +558,7 @@ module SPARQL; module Algebra
|
|
540
558
|
#
|
541
559
|
# @return [String]
|
542
560
|
def inspect
|
543
|
-
sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, operands.
|
561
|
+
sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, operands.to_sse.gsub(/\s+/m, ' '))
|
544
562
|
end
|
545
563
|
|
546
564
|
##
|
@@ -552,7 +570,21 @@ module SPARQL; module Algebra
|
|
552
570
|
alias_method :==, :eql?
|
553
571
|
|
554
572
|
##
|
555
|
-
#
|
573
|
+
# Return the non-destinguished variables contained within this operator
|
574
|
+
# @return [Array<RDF::Query::Variable>]
|
575
|
+
def ndvars
|
576
|
+
vars.reject(&:distinguished?)
|
577
|
+
end
|
578
|
+
|
579
|
+
##
|
580
|
+
# Return the variables contained within this operator
|
581
|
+
# @return [Array<RDF::Query::Variable>]
|
582
|
+
def vars
|
583
|
+
operands.select {|o| o.respond_to?(:vars)}.map(&:vars).flatten
|
584
|
+
end
|
585
|
+
|
586
|
+
##
|
587
|
+
# Iterate via depth-first recursive descent over operands, yielding each operator
|
556
588
|
# @yield operator
|
557
589
|
# @yieldparam [Object] operator
|
558
590
|
def descendants(&block)
|
@@ -569,6 +601,38 @@ module SPARQL; module Algebra
|
|
569
601
|
block.call(operand)
|
570
602
|
end
|
571
603
|
end
|
604
|
+
|
605
|
+
##
|
606
|
+
# Parent expression, if any
|
607
|
+
#
|
608
|
+
# @return [Operator]
|
609
|
+
def parent; @options[:parent]; end
|
610
|
+
|
611
|
+
##
|
612
|
+
# Parent operator, if any
|
613
|
+
#
|
614
|
+
# @return [Operator]
|
615
|
+
def parent=(operator)
|
616
|
+
@options[:parent]= operator
|
617
|
+
end
|
618
|
+
|
619
|
+
##
|
620
|
+
# First ancestor operator of type `klass`
|
621
|
+
#
|
622
|
+
# @param [Class] klass
|
623
|
+
# @return [Operator]
|
624
|
+
def first_ancestor(klass)
|
625
|
+
parent.is_a?(klass) ? parent : parent.first_ancestor(klass) if parent
|
626
|
+
end
|
627
|
+
|
628
|
+
##
|
629
|
+
# Validate all operands, operator specific classes should override for operator-specific validation
|
630
|
+
# @return [SPARQL::Algebra::Expression] `self`
|
631
|
+
# @raise [ArgumentError] if the value is invalid
|
632
|
+
def validate!
|
633
|
+
operands.each {|op| op.validate! if op.respond_to?(:validate!)}
|
634
|
+
self
|
635
|
+
end
|
572
636
|
protected
|
573
637
|
|
574
638
|
##
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module SPARQL; module Algebra
|
2
|
+
class Operator
|
3
|
+
##
|
4
|
+
# The SPARQL Property Path `alt` (Alternative Property Path) operator.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# (alt a b)
|
8
|
+
#
|
9
|
+
# @see http://www.w3.org/TR/sparql11-query/#defn_evalPP_alternative
|
10
|
+
class Alt < Operator::Binary
|
11
|
+
include Query
|
12
|
+
|
13
|
+
NAME = :alt
|
14
|
+
|
15
|
+
##
|
16
|
+
# Equivalent to:
|
17
|
+
#
|
18
|
+
# (path x (alt :p :q) y)
|
19
|
+
# => (union (bgp (x :p y)) (bgp (x :q y)))
|
20
|
+
#
|
21
|
+
# @param [RDF::Queryable] queryable
|
22
|
+
# the graph or repository to query
|
23
|
+
# @param [Hash{Symbol => Object}] options
|
24
|
+
# any additional keyword options
|
25
|
+
# @option options [RDF::Term, RDF::Variable] :subject
|
26
|
+
# @option options [RDF::Term, RDF::Variable] :object
|
27
|
+
# @yield [solution]
|
28
|
+
# each matching solution
|
29
|
+
# @yieldparam [RDF::Query::Solution] solution
|
30
|
+
# @yieldreturn [void] ignored
|
31
|
+
# @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
|
32
|
+
def execute(queryable, options = {}, &block)
|
33
|
+
subject, object = options[:subject], options[:object]
|
34
|
+
debug(options) {"Alt #{[subject, operands, object].to_sse}"}
|
35
|
+
|
36
|
+
# Solutions where predicate exists
|
37
|
+
qa = if operand(0).is_a?(RDF::Term)
|
38
|
+
RDF::Query.new do |q|
|
39
|
+
q.pattern [subject, operand(0), object]
|
40
|
+
end
|
41
|
+
else
|
42
|
+
operand(0)
|
43
|
+
end
|
44
|
+
|
45
|
+
qb = if operand(1).is_a?(RDF::Term)
|
46
|
+
RDF::Query.new do |q|
|
47
|
+
q.pattern [subject, operand(1), object]
|
48
|
+
end
|
49
|
+
else
|
50
|
+
operand(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
query = Union.new(qa, qb)
|
54
|
+
queryable.query(query, options.merge(depth: options[:depth].to_i + 1), &block)
|
55
|
+
end
|
56
|
+
end # Alt
|
57
|
+
end # Operator
|
58
|
+
end; end # SPARQL::Algebra
|
@@ -41,10 +41,10 @@ module SPARQL; module Algebra
|
|
41
41
|
# @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
|
42
42
|
def execute(queryable, options = {}, &block)
|
43
43
|
debug(options) {"Extend"}
|
44
|
-
@solutions =
|
44
|
+
@solutions = operand(1).execute(queryable, options.merge(depth: options[:depth].to_i + 1))
|
45
45
|
@solutions.each do |solution|
|
46
46
|
debug(options) {"===> soln #{solution.to_hash.inspect}"}
|
47
|
-
|
47
|
+
operand(0).each do |(var, expr)|
|
48
48
|
begin
|
49
49
|
val = expr.evaluate(solution, options.merge(
|
50
50
|
queryable: queryable,
|
@@ -60,7 +60,19 @@ module SPARQL; module Algebra
|
|
60
60
|
@solutions.each(&block) if block_given?
|
61
61
|
@solutions
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
|
+
# The variable introduced by the BIND clause must not have been used in the group graph pattern up to the point of use in BIND
|
65
|
+
def validate!
|
66
|
+
bind_vars = operand(0).map(&:first)
|
67
|
+
query_vars = operand(1).vars
|
68
|
+
|
69
|
+
unless (bind_vars.compact & query_vars.compact).empty?
|
70
|
+
raise ArgumentError,
|
71
|
+
"bound variable used in query: #{(bind_vars.compact & query_vars.compact).to_sse}"
|
72
|
+
end
|
73
|
+
super
|
74
|
+
end
|
75
|
+
|
64
76
|
##
|
65
77
|
# Returns an optimized version of this query.
|
66
78
|
#
|
@@ -52,7 +52,24 @@ module SPARQL; module Algebra
|
|
52
52
|
@solutions.each(&block) if block_given?
|
53
53
|
@solutions
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
|
+
# If filtering a join of two BGPs (having the same graph name), don't worry about validating, for shared ndvars, anyway,
|
57
|
+
#
|
58
|
+
# (filter (regex ?homepage "^http://example.org/" "")
|
59
|
+
# (join
|
60
|
+
# (bgp (triple ??who :homepage ?homepage))
|
61
|
+
# (bgp (triple ??who :schoolHomepage ?schoolPage))))))
|
62
|
+
#
|
63
|
+
# is legitimate
|
64
|
+
def validate!
|
65
|
+
unless (join = operands.last).is_a?(Join) &&
|
66
|
+
join.operands.all? {|op| op.is_a?(RDF::Query)} &&
|
67
|
+
join.operands.map(&:context).uniq.length == 1
|
68
|
+
operands.last.validate!
|
69
|
+
end
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
56
73
|
##
|
57
74
|
# Returns an optimized version of this query.
|
58
75
|
#
|