sparql 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/VERSION +1 -1
  4. data/lib/rack/sparql/conneg.rb +5 -2
  5. data/lib/sinatra/sparql.rb +9 -16
  6. data/lib/sinatra/sparql/extensions.rb +0 -2
  7. data/lib/sparql.rb +8 -5
  8. data/lib/sparql/algebra/expression.rb +1 -1
  9. data/lib/sparql/algebra/extensions.rb +34 -6
  10. data/lib/sparql/algebra/operator/ask.rb +13 -5
  11. data/lib/sparql/algebra/operator/base.rb +19 -5
  12. data/lib/sparql/algebra/operator/bgp.rb +6 -2
  13. data/lib/sparql/algebra/operator/construct.rb +19 -8
  14. data/lib/sparql/algebra/operator/dataset.rb +8 -4
  15. data/lib/sparql/algebra/operator/datatype.rb +1 -7
  16. data/lib/sparql/algebra/operator/describe.rb +16 -6
  17. data/lib/sparql/algebra/operator/distinct.rb +7 -6
  18. data/lib/sparql/algebra/operator/exists.rb +3 -6
  19. data/lib/sparql/algebra/operator/extend.rb +11 -1
  20. data/lib/sparql/algebra/operator/filter.rb +12 -17
  21. data/lib/sparql/algebra/operator/graph.rb +6 -4
  22. data/lib/sparql/algebra/operator/group.rb +10 -5
  23. data/lib/sparql/algebra/operator/join.rb +16 -9
  24. data/lib/sparql/algebra/operator/left_join.rb +15 -11
  25. data/lib/sparql/algebra/operator/minus.rb +11 -7
  26. data/lib/sparql/algebra/operator/notexists.rb +1 -1
  27. data/lib/sparql/algebra/operator/order.rb +9 -3
  28. data/lib/sparql/algebra/operator/prefix.rb +19 -2
  29. data/lib/sparql/algebra/operator/project.rb +9 -4
  30. data/lib/sparql/algebra/operator/reduced.rb +8 -3
  31. data/lib/sparql/algebra/operator/slice.rb +8 -1
  32. data/lib/sparql/algebra/operator/table.rb +7 -2
  33. data/lib/sparql/algebra/operator/union.rb +7 -2
  34. data/lib/sparql/algebra/query.rb +26 -6
  35. data/lib/sparql/extensions.rb +0 -8
  36. data/lib/sparql/grammar/parser11.rb +1 -1
  37. data/lib/sparql/results.rb +6 -4
  38. metadata +25 -25
@@ -29,13 +29,7 @@ module SPARQL; module Algebra
29
29
  # @raise [TypeError] if the operand is not a typed or simple literal
30
30
  def apply(literal)
31
31
  case literal
32
- when RDF::Literal then case
33
- when RDF::VERSION.to_s >= "1.1" then literal.datatype
34
- when literal.simple? then RDF::XSD.string
35
- when literal.datatype == RDF::XSD.string then RDF::XSD.string
36
- when literal.plain? then RDF.langString
37
- else RDF::URI(literal.datatype)
38
- end
32
+ when RDF::Literal then literal.datatype
39
33
  else raise TypeError, "expected an RDF::Literal, but got #{literal.inspect}"
40
34
  end
41
35
  end
@@ -33,10 +33,14 @@ module SPARQL; module Algebra
33
33
  # the graph or repository to query
34
34
  # @param [Hash{Symbol => Object}] options
35
35
  # any additional keyword options
36
- # @return [RDF::Query::Solutions]
37
- # the resulting solution sequence
36
+ # @yield [statement]
37
+ # each matching statement
38
+ # @yieldparam [RDF::Statement] solution
39
+ # @yieldreturn [void] ignored
40
+ # @return [RDF::Graph]
41
+ # containing the constructed triples
38
42
  # @see http://www.w3.org/TR/rdf-sparql-query/#describe
39
- def execute(queryable, options = {})
43
+ def execute(queryable, options = {}, &block)
40
44
  debug(options) {"Describe #{operands.first}, #{options.inspect}"}
41
45
 
42
46
  # Describe any constand URIs
@@ -44,17 +48,17 @@ module SPARQL; module Algebra
44
48
 
45
49
  to_describe.each {|t| debug(options) {"=> describe #{t}"}}
46
50
 
47
- operands.last.execute(queryable).each do |solution|
51
+ queryable.query(operands.last) do |solution|
48
52
  solution.each_variable do |v|
49
53
  if operands.first.any? {|bound| v.eql?(bound)}
50
- debug(options) {"=> describe #{v}"}
54
+ debug(options) {"(describe)=> #{v}"}
51
55
  to_describe << v.value
52
56
  end
53
57
  end
54
58
  end
55
59
 
56
60
  # Return Concise Bounded Description
57
- queryable.concise_bounded_description(*to_describe)
61
+ queryable.concise_bounded_description(*to_describe.uniq, &block)
58
62
  end
59
63
 
60
64
  ##
@@ -66,6 +70,12 @@ module SPARQL; module Algebra
66
70
  def optimize
67
71
  operands = operands.map(&:optimize)
68
72
  end
73
+
74
+ # Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
75
+ # @return [Boolean]
76
+ def query_yields_statements?
77
+ true
78
+ end
69
79
  end # Construct
70
80
  end # Operator
71
81
  end; end # SPARQL::Algebra
@@ -24,15 +24,16 @@ module SPARQL; module Algebra
24
24
  # the graph or repository to query
25
25
  # @param [Hash{Symbol => Object}] options
26
26
  # any additional keyword options
27
+ # @yield [solution]
28
+ # each matching solution
29
+ # @yieldparam [RDF::Query::Solution] solution
30
+ # @yieldreturn [void] ignored
27
31
  # @return [RDF::Query::Solutions]
28
32
  # the resulting solution sequence
29
33
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
30
- def execute(queryable, options = {})
31
- debug(options) {"Distinct"}
32
- @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
33
- debug(options) {"=>(before) #{@solutions.inspect}"}
34
- @solutions = @solutions.distinct
35
- debug(options) {"=>(after) #{@solutions.inspect}"}
34
+ def execute(queryable, options = {}, &block)
35
+ @solutions = queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1)).distinct
36
+ @solutions.each(&block) if block_given?
36
37
  @solutions
37
38
  end
38
39
 
@@ -5,10 +5,8 @@ module SPARQL; module Algebra
5
5
  #
6
6
  # @example
7
7
  # (prefix ((ex: <http://www.example.org/>))
8
- # (filter (exists
9
- # (filter (notexists (bgp (triple ?s ?p ex:o2)))
10
- # (bgp (triple ?s ?p ex:o1))))
11
- # (bgp (triple ?s ?p ex:o))))
8
+ # (filter (exists (bgp (triple ?s ?p ex:o)))
9
+ # (bgp (triple ?s ?p ?o))))
12
10
  #
13
11
  # @see http://www.w3.org/TR/sparql11-query/#func-abs
14
12
  # @see http://www.w3.org/TR/xpath-functions/#func-abs
@@ -28,10 +26,9 @@ module SPARQL; module Algebra
28
26
  # queryable to execute, using bindings as an initial solution.
29
27
  # @return [RDF::Literal::Boolean] `true` or `false`
30
28
  def evaluate(bindings, options = {})
31
- solutions = RDF::Query::Solutions.new << bindings
32
29
  queryable = options[:queryable]
33
30
  !operand(0).execute(queryable, options.merge(
34
- :solutions => solutions,
31
+ :solutions => RDF::Query::Solutions(bindings),
35
32
  :depth => options[:depth].to_i + 1)).empty?
36
33
  end
37
34
  end # Exists
@@ -27,10 +27,19 @@ module SPARQL; module Algebra
27
27
  # Extend is undefined when var in dom(μ).
28
28
  #
29
29
  # Extend(Ω, var, expr) = { Extend(μ, var, expr) | μ in Ω }
30
+ #
31
+ # @param [RDF::Queryable] queryable
32
+ # the graph or repository to query
33
+ # @param [Hash{Symbol => Object}] options
34
+ # any additional keyword options
35
+ # @yield [solution]
36
+ # each matching solution
37
+ # @yieldparam [RDF::Query::Solution] solution
38
+ # @yieldreturn [void] ignored
30
39
  # @return [RDF::Query::Solutions]
31
40
  # the resulting solution sequence
32
41
  # @see http://www.w3.org/TR/rdf-sparql-query/#evaluation
33
- def execute(queryable, options = {})
42
+ def execute(queryable, options = {}, &block)
34
43
  debug(options) {"Extend"}
35
44
  @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
36
45
  @solutions.each do |solution|
@@ -48,6 +57,7 @@ module SPARQL; module Algebra
48
57
  end
49
58
  end
50
59
  end
60
+ @solutions.each(&block) if block_given?
51
61
  @solutions
52
62
  end
53
63
 
@@ -28,33 +28,28 @@ module SPARQL; module Algebra
28
28
  # the graph or repository to query
29
29
  # @param [Hash{Symbol => Object}] options
30
30
  # any additional keyword options
31
+ # @yield [solution]
32
+ # each matching solution
33
+ # @yieldparam [RDF::Query::Solution] solution
34
+ # @yieldreturn [void] ignored
31
35
  # @return [RDF::Query::Solutions]
32
36
  # the resulting solution sequence
33
37
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
34
38
  # @see http://www.w3.org/TR/rdf-sparql-query/#ebv
35
- def execute(queryable, options = {})
39
+ def execute(queryable, options = {}, &block)
36
40
  debug(options) {"Filter #{operands.first.to_sxp}"}
37
- @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
38
- debug(options) {"=>(before) #{@solutions.map(&:to_hash).inspect}"}
39
41
  opts = options.merge(:queryable => queryable, :depth => options[:depth].to_i + 1)
40
- @solutions = @solutions.filter do |solution|
41
- # Evaluate the solution, which will return true or false
42
- #debug(options) {"===>(evaluate) #{operands.first.inspect} against #{solution.to_hash.inspect}"}
43
-
44
- # From http://www.w3.org/TR/rdf-sparql-query/#tests
45
- # FILTERs eliminate any solutions that, when substituted into the expression, either
46
- # result in an effective boolean value of false or produce an error.
42
+ @solutions = RDF::Query::Solutions()
43
+ queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1)) do |solution|
47
44
  begin
48
- res = boolean(operands.first.evaluate(solution, opts)).true?
49
- debug(options) {"===>#{res} #{solution.to_hash.inspect}"}
50
- res
45
+ pass = boolean(operands.first.evaluate(solution, opts)).true?
46
+ debug(options) {"(filter) #{pass.inspect} #{solution.to_hash.inspect}"}
47
+ @solutions << solution if pass
51
48
  rescue
52
- debug(options) {"rescue(#{$!}): #{solution.to_hash.inspect}"}
53
- false
49
+ debug(options) {"(filter) rescue(#{$!}): #{solution.to_hash.inspect}"}
54
50
  end
55
51
  end
56
- @solutions = RDF::Query::Solutions.new(@solutions)
57
- debug(options) {"=>(after) #{@solutions.map(&:to_hash).inspect}"}
52
+ @solutions.each(&block) if block_given?
58
53
  @solutions
59
54
  end
60
55
 
@@ -25,15 +25,17 @@ module SPARQL; module Algebra
25
25
  # the graph or repository to query
26
26
  # @param [Hash{Symbol => Object}] options
27
27
  # any additional keyword options
28
+ # @yield [solution]
29
+ # each matching solution
30
+ # @yieldparam [RDF::Query::Solution] solution
31
+ # @yieldreturn [void] ignored
28
32
  # @return [RDF::Query::Solutions]
29
33
  # the resulting solution sequence
30
34
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
31
- def execute(queryable, options = {})
35
+ def execute(queryable, options = {}, &block)
32
36
  debug(options) {"Graph #{operands.first}"}
33
37
  context, query = operands.first, operands.last
34
- @solutions = query.execute(queryable, options.merge(:context => context))
35
- debug(options) {"=>(after) #{@solutions.map(&:to_hash).inspect}"}
36
- @solutions
38
+ @solutions = queryable.query(query, options.merge(:context => context), &block)
37
39
  end
38
40
 
39
41
  ##
@@ -31,15 +31,19 @@ module SPARQL; module Algebra
31
31
  # the graph or repository to query
32
32
  # @param [Hash{Symbol => Object}] options
33
33
  # any additional keyword options
34
+ # @yield [solution]
35
+ # each matching solution
36
+ # @yieldparam [RDF::Query::Solution] solution
37
+ # @yieldreturn [void] ignored
34
38
  # @return [RDF::Query::Solutions]
35
39
  # the resulting solution sequence
36
40
  # @see http://www.w3.org/TR/sparql11-query/#sparqlGroupAggregate
37
- def execute(queryable, options = {})
41
+ def execute(queryable, options = {}, &block)
38
42
  debug(options) {"Group"}
39
43
  exprlist = operands.first
40
44
  query = operands.last
41
45
  aggregates = operands.length == 3 ? operand(1) : []
42
- solutions = query.execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
46
+ solutions = queryable.query(query, options.merge(:depth => options[:depth].to_i + 1))
43
47
 
44
48
  groups = solutions.group_by do |solution|
45
49
  # Evaluate each exprlist operand to get groups where each key is a new solution
@@ -69,7 +73,7 @@ module SPARQL; module Algebra
69
73
  debug(options) {"=>(groups) #{groups.inspect}"}
70
74
 
71
75
  # Aggregate solutions in each group using aggregates to get solutions
72
- @solutions = groups.map do |group_soln, solns|
76
+ @solutions = RDF::Query::Solutions(groups.map do |group_soln, solns|
73
77
  aggregates.each do |(var, aggregate)|
74
78
  begin
75
79
  group_soln[var] = aggregate.aggregate(solns, options)
@@ -78,13 +82,14 @@ module SPARQL; module Algebra
78
82
  end
79
83
  end
80
84
  group_soln
81
- end
85
+ end)
82
86
 
83
87
  # Make sure that's at least an empty solution
84
88
  @solutions << RDF::Query::Solution.new if @solutions.empty?
85
89
 
86
90
  debug(options) {"=>(solutions) #{@solutions.inspect}"}
87
- @solutions = RDF::Query::Solutions.new(@solutions)
91
+ @solutions.each(&block) if block_given?
92
+ @solutions
88
93
  end
89
94
 
90
95
  ##
@@ -25,26 +25,33 @@ module SPARQL; module Algebra
25
25
  # the graph or repository to query
26
26
  # @param [Hash{Symbol => Object}] options
27
27
  # any additional keyword options
28
+ # @yield [solution]
29
+ # each matching solution
30
+ # @yieldparam [RDF::Query::Solution] solution
31
+ # @yieldreturn [void] ignored
28
32
  # @return [RDF::Query::Solutions]
29
33
  # the resulting solution sequence
30
34
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
31
35
  # @see http://rdf.rubyforge.org/RDF/Query/Solution.html#merge-instance_method
32
36
  # @see http://rdf.rubyforge.org/RDF/Query/Solution.html#compatible%3F-instance_method
33
- def execute(queryable, options = {})
37
+ def execute(queryable, options = {}, &block)
34
38
  # Join(Ω1, Ω2) = { merge(μ1, μ2) | μ1 in Ω1 and μ2 in Ω2, and μ1 and μ2 are compatible }
35
39
  # eval(D(G), Join(P1, P2)) = Join(eval(D(G), P1), eval(D(G), P2))
36
40
  #
37
41
  # Generate solutions independently, merge based on solution compatibility
38
42
  debug(options) {"Join"}
39
- solutions1 = operand(0).execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
40
- debug(options) {"=>(left) #{solutions1.inspect}"}
41
- solutions2 = operand(1).execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
42
- debug(options) {"=>(right) #{solutions2.inspect}"}
43
- @solutions = solutions1.map do |s1|
44
- solutions2.map { |s2| s2.merge(s1) if s2.compatible?(s1) }
45
- end.flatten.compact
46
- @solutions = RDF::Query::Solutions.new(@solutions)
43
+
44
+ left = queryable.query(operand(0), options.merge(:depth => options[:depth].to_i + 1))
45
+ debug(options) {"(join)=>(left) #{left.inspect}"}
46
+
47
+ right = queryable.query(operand(1), options.merge(:depth => options[:depth].to_i + 1))
48
+ debug(options) {"(join)=>(right) #{right.inspect}"}
49
+
50
+ @solutions = RDF::Query::Solutions(left.map do |s1|
51
+ right.map { |s2| s2.merge(s1) if s2.compatible?(s1) }
52
+ end.flatten.compact)
47
53
  debug(options) {"=> #{@solutions.inspect}"}
54
+ @solutions.each(&block) if block_given?
48
55
  @solutions
49
56
  end
50
57
 
@@ -25,23 +25,27 @@ module SPARQL; module Algebra
25
25
  # the graph or repository to query
26
26
  # @param [Hash{Symbol => Object}] options
27
27
  # any additional keyword options
28
+ # @yield [solution]
29
+ # each matching solution
30
+ # @yieldparam [RDF::Query::Solution] solution
31
+ # @yieldreturn [void] ignored
28
32
  # @return [RDF::Query::Solutions]
29
33
  # the resulting solution sequence
30
34
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
31
35
  # @see http://rdf.rubyforge.org/RDF/Query/Solution.html#merge-instance_method
32
36
  # @see http://rdf.rubyforge.org/RDF/Query/Solution.html#compatible%3F-instance_method
33
- def execute(queryable, options = {})
37
+ def execute(queryable, options = {}, &block)
34
38
  filter = operand(2)
35
39
 
36
-
37
40
  debug(options) {"LeftJoin"}
38
- left = operand(0).execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
39
- debug(options) {"=>(left) #{left.inspect}"}
40
- right = operand(1).execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
41
- debug(options) {"=>(right) #{right.inspect}"}
42
-
41
+ left = queryable.query(operand(0), options.merge(:depth => options[:depth].to_i + 1))
42
+ debug(options) {"=>(leftjoin left) #{left.inspect}"}
43
+
44
+ right = queryable.query(operand(1), options.merge(:depth => options[:depth].to_i + 1))
45
+ debug(options) {"=>(leftjoin right) #{right.inspect}"}
46
+
43
47
  # LeftJoin(Ω1, Ω2, expr) =
44
- solutions = []
48
+ @solutions = RDF::Query::Solutions()
45
49
  left.each do |s1|
46
50
  load_left = true
47
51
  right.each do |s2|
@@ -52,18 +56,18 @@ module SPARQL; module Algebra
52
56
  if expr && s1.compatible?(s2)
53
57
  # { merge(μ1, μ2) | μ1 in Ω1 and μ2 in Ω2, and μ1 and μ2 are compatible and expr(merge(μ1, μ2)) is true }
54
58
  debug(options) {"=>(merge s1 s2) #{s.inspect}"}
55
- solutions << s
59
+ @solutions << s
56
60
  load_left = false # Left solution added one or more times due to merge
57
61
  end
58
62
  end
59
63
  if load_left
60
64
  debug(options) {"=>(add) #{s1.inspect}"}
61
- solutions << s1
65
+ @solutions << s1
62
66
  end
63
67
  end
64
68
 
65
- @solutions = RDF::Query::Solutions.new(solutions)
66
69
  debug(options) {"=> #{@solutions.inspect}"}
70
+ @solutions.each(&block) if block_given?
67
71
  @solutions
68
72
  end
69
73
 
@@ -27,23 +27,27 @@ module SPARQL; module Algebra
27
27
  # the graph or repository to query
28
28
  # @param [Hash{Symbol => Object}] options
29
29
  # any additional keyword options
30
+ # @yield [solution]
31
+ # each matching solution
32
+ # @yieldparam [RDF::Query::Solution] solution
33
+ # @yieldreturn [void] ignored
30
34
  # @return [RDF::Query::Solutions]
31
35
  # the resulting solution sequence
32
36
  # @see http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#defn_algMinus
33
37
  # @see http://www.w3.org/TR/2013/REC-sparql11-query-20130321/#negation
34
- def execute(queryable, options = {})
38
+ def execute(queryable, options = {}, &block)
35
39
  # Let Ω1 and Ω2 be multisets of solution mappings. We define:
36
40
  #
37
41
  # Minus(Ω1, Ω2) = { μ | μ in Ω1 . ∀ μ' in Ω2, either μ and μ' are not compatible or dom(μ) and dom(μ') are disjoint }
38
42
  #
39
43
  # card[Minus(Ω1, Ω2)](μ) = card[Ω1](μ)
40
44
  debug(options) {"Minus"}
41
- solutions1 = operand(0).execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
42
- debug(options) {"=>(left) #{solutions1.inspect}"}
43
- solutions2 = operand(1).execute(queryable, options.merge(:depth => options[:depth].to_i + 1)) || {}
44
- debug(options) {"=>(right) #{solutions2.inspect}"}
45
- @solutions = solutions1.minus(solutions2)
46
- debug(options) {"=> #{@solutions.inspect}"}
45
+ left = queryable.query(operand(0), options.merge(:depth => options[:depth].to_i + 1))
46
+ debug(options) {"(minus left) #{left.inspect}"}
47
+ right = queryable.query(operand(1), options.merge(:depth => options[:depth].to_i + 1))
48
+ debug(options) {"(minus right) #{right.inspect}"}
49
+ @solutions = left.minus(right)
50
+ @solutions.each(&block) if block_given?
47
51
  @solutions
48
52
  end
49
53
 
@@ -28,7 +28,7 @@ module SPARQL; module Algebra
28
28
  # queryable to execute, using bindings as an initial solution.
29
29
  # @return [RDF::Literal::Boolean] `true` or `false`
30
30
  def evaluate(bindings, options = {})
31
- solutions = RDF::Query::Solutions.new << bindings
31
+ solutions = RDF::Query::Solutions(bindings)
32
32
  queryable = options[:queryable]
33
33
  operand(0).execute(queryable, options.merge(:solutions => solutions)).empty?
34
34
  end
@@ -24,14 +24,18 @@ module SPARQL; module Algebra
24
24
  # the graph or repository to query
25
25
  # @param [Hash{Symbol => Object}] options
26
26
  # any additional keyword options
27
+ # @yield [solution]
28
+ # each matching solution
29
+ # @yieldparam [RDF::Query::Solution] solution
30
+ # @yieldreturn [void] ignored
27
31
  # @return [RDF::Query::Solutions]
28
32
  # the resulting solution sequence
29
33
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
30
- def execute(queryable, options = {})
34
+ def execute(queryable, options = {}, &block)
31
35
  debug(options) {"Order"}
32
- @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1)).order do |a, b|
36
+ @solutions = queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1)).order do |a, b|
33
37
  operand(0).inject(false) do |memo, op|
34
- debug(options) {"=> #{op.inspect}"}
38
+ debug(options) {"(order) #{op.inspect}"}
35
39
  memo ||= begin
36
40
  a_eval = op.evaluate(a, options.merge(:queryable => queryable, :depth => options[:depth].to_i + 1)) rescue nil
37
41
  b_eval = op.evaluate(b, options.merge(:queryable => queryable, :depth => options[:depth].to_i + 1)) rescue nil
@@ -49,6 +53,8 @@ module SPARQL; module Algebra
49
53
  end
50
54
  end || 0 # They compare equivalently if there are no matches
51
55
  end
56
+ @solutions.each(&block) if block_given?
57
+ @solutions
52
58
  end
53
59
 
54
60
  ##
@@ -23,11 +23,16 @@ module SPARQL; module Algebra
23
23
  # the graph or repository to query
24
24
  # @param [Hash{Symbol => Object}] options
25
25
  # any additional keyword options
26
+ # @yield [solution]
27
+ # each matching solution, statement or boolean
28
+ # @yieldparam [RDF::Statement, RDF::Query::Solution, Boolean] solution
29
+ # @yieldreturn [void] ignored
26
30
  # @return [RDF::Query::Solutions]
27
31
  # the resulting solution sequence
28
32
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
29
- def execute(queryable, options = {})
30
- @solutions = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
33
+ def execute(queryable, options = {}, &block)
34
+ debug(options) {"Prefix"}
35
+ @solutions = queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1), &block)
31
36
  end
32
37
 
33
38
  ##
@@ -48,6 +53,18 @@ module SPARQL; module Algebra
48
53
  operands[0] += other.operands[0]
49
54
  self
50
55
  end
56
+
57
+ # Query results in a boolean result (e.g., ASK)
58
+ # @return [Boolean]
59
+ def query_yields_boolean?
60
+ operands.last.query_yields_boolean?
61
+ end
62
+
63
+ # Query results statements (e.g., CONSTRUCT, DESCRIBE, CREATE)
64
+ # @return [Boolean]
65
+ def query_yields_statements?
66
+ operands.last.query_yields_statements?
67
+ end
51
68
  end # Prefix
52
69
  end # Operator
53
70
  end; end # SPARQL::Algebra