sparql 1.1.5 → 1.1.6

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +36 -32
  3. data/VERSION +1 -1
  4. data/bin/sparql +8 -6
  5. data/lib/sparql.rb +4 -2
  6. data/lib/sparql/algebra.rb +74 -4
  7. data/lib/sparql/algebra/aggregate.rb +1 -1
  8. data/lib/sparql/algebra/evaluatable.rb +1 -1
  9. data/lib/sparql/algebra/expression.rb +24 -16
  10. data/lib/sparql/algebra/extensions.rb +37 -9
  11. data/lib/sparql/algebra/operator.rb +75 -12
  12. data/lib/sparql/algebra/operator/add.rb +41 -19
  13. data/lib/sparql/algebra/operator/and.rb +2 -2
  14. data/lib/sparql/algebra/operator/asc.rb +1 -1
  15. data/lib/sparql/algebra/operator/ask.rb +1 -1
  16. data/lib/sparql/algebra/operator/base.rb +1 -1
  17. data/lib/sparql/algebra/operator/bgp.rb +1 -1
  18. data/lib/sparql/algebra/operator/bnode.rb +1 -1
  19. data/lib/sparql/algebra/operator/clear.rb +63 -0
  20. data/lib/sparql/algebra/operator/coalesce.rb +1 -1
  21. data/lib/sparql/algebra/operator/concat.rb +3 -3
  22. data/lib/sparql/algebra/operator/construct.rb +2 -2
  23. data/lib/sparql/algebra/operator/copy.rb +64 -0
  24. data/lib/sparql/algebra/operator/create.rb +49 -0
  25. data/lib/sparql/algebra/operator/dataset.rb +6 -31
  26. data/lib/sparql/algebra/operator/delete.rb +55 -0
  27. data/lib/sparql/algebra/operator/delete_data.rb +41 -0
  28. data/lib/sparql/algebra/operator/delete_where.rb +57 -0
  29. data/lib/sparql/algebra/operator/distinct.rb +1 -1
  30. data/lib/sparql/algebra/operator/drop.rb +66 -0
  31. data/lib/sparql/algebra/operator/exists.rb +2 -2
  32. data/lib/sparql/algebra/operator/exprlist.rb +1 -1
  33. data/lib/sparql/algebra/operator/extend.rb +3 -3
  34. data/lib/sparql/algebra/operator/filter.rb +2 -2
  35. data/lib/sparql/algebra/operator/graph.rb +39 -5
  36. data/lib/sparql/algebra/operator/group.rb +5 -5
  37. data/lib/sparql/algebra/operator/group_concat.rb +1 -1
  38. data/lib/sparql/algebra/operator/if.rb +3 -3
  39. data/lib/sparql/algebra/operator/in.rb +1 -1
  40. data/lib/sparql/algebra/operator/insert.rb +54 -0
  41. data/lib/sparql/algebra/operator/insert_data.rb +41 -0
  42. data/lib/sparql/algebra/operator/join.rb +2 -2
  43. data/lib/sparql/algebra/operator/lcase.rb +1 -1
  44. data/lib/sparql/algebra/operator/left_join.rb +2 -2
  45. data/lib/sparql/algebra/operator/load.rb +48 -0
  46. data/lib/sparql/algebra/operator/minus.rb +2 -2
  47. data/lib/sparql/algebra/operator/modify.rb +53 -0
  48. data/lib/sparql/algebra/operator/move.rb +67 -0
  49. data/lib/sparql/algebra/operator/notexists.rb +1 -1
  50. data/lib/sparql/algebra/operator/notin.rb +2 -2
  51. data/lib/sparql/algebra/operator/or.rb +2 -2
  52. data/lib/sparql/algebra/operator/order.rb +3 -3
  53. data/lib/sparql/algebra/operator/plus.rb +14 -8
  54. data/lib/sparql/algebra/operator/prefix.rb +1 -1
  55. data/lib/sparql/algebra/operator/project.rb +1 -1
  56. data/lib/sparql/algebra/operator/reduced.rb +1 -1
  57. data/lib/sparql/algebra/operator/replace.rb +1 -1
  58. data/lib/sparql/algebra/operator/slice.rb +1 -1
  59. data/lib/sparql/algebra/operator/strafter.rb +1 -1
  60. data/lib/sparql/algebra/operator/strbefore.rb +2 -2
  61. data/lib/sparql/algebra/operator/strdt.rb +1 -1
  62. data/lib/sparql/algebra/operator/strlang.rb +1 -1
  63. data/lib/sparql/algebra/operator/substr.rb +2 -2
  64. data/lib/sparql/algebra/operator/ucase.rb +1 -1
  65. data/lib/sparql/algebra/operator/union.rb +1 -1
  66. data/lib/sparql/algebra/operator/update.rb +44 -0
  67. data/lib/sparql/algebra/operator/using.rb +40 -0
  68. data/lib/sparql/algebra/operator/with.rb +72 -0
  69. data/lib/sparql/algebra/update.rb +56 -0
  70. data/lib/sparql/extensions.rb +8 -8
  71. data/lib/sparql/grammar.rb +31 -8
  72. data/lib/sparql/grammar/meta.rb +3758 -3273
  73. data/lib/sparql/grammar/parser11.rb +240 -46
  74. data/lib/sparql/grammar/terminals11.rb +5 -5
  75. data/lib/sparql/results.rb +26 -26
  76. metadata +38 -30
@@ -28,8 +28,8 @@ module SPARQL; module Algebra
28
28
  def evaluate(bindings, options = {})
29
29
  queryable = options[:queryable]
30
30
  !operand(0).execute(queryable, options.merge(
31
- :solutions => RDF::Query::Solutions(bindings),
32
- :depth => options[:depth].to_i + 1)).empty?
31
+ solutions: RDF::Query::Solutions(bindings),
32
+ depth: options[:depth].to_i + 1)).empty?
33
33
  end
34
34
  end # Exists
35
35
  end # Operator
@@ -37,7 +37,7 @@ module SPARQL; module Algebra
37
37
  # @return [RDF::Literal::Boolean] `true` or `false`
38
38
  # @raise [TypeError] if the operands could not be coerced to a boolean literal
39
39
  def evaluate(bindings, options = {})
40
- res = operands.all? {|op| boolean(op.evaluate(bindings, options.merge(:depth => options[:depth].to_i + 1))).true? }
40
+ res = operands.all? {|op| boolean(op.evaluate(bindings, options.merge(depth: options[:depth].to_i + 1))).true? }
41
41
  RDF::Literal(res) # FIXME: error handling
42
42
  end
43
43
 
@@ -41,14 +41,14 @@ 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 = operands.last.execute(queryable, options.merge(:depth => options[:depth].to_i + 1))
44
+ @solutions = operands.last.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
  operands.first.each do |(var, expr)|
48
48
  begin
49
49
  val = expr.evaluate(solution, options.merge(
50
- :queryable => queryable,
51
- :depth => options[:depth].to_i + 1))
50
+ queryable: queryable,
51
+ depth: options[:depth].to_i + 1))
52
52
  debug(options) {"===> + #{var} => #{val.inspect}"}
53
53
  solution.bindings[var.to_sym] = val
54
54
  rescue TypeError => e
@@ -38,9 +38,9 @@ module SPARQL; module Algebra
38
38
  # @see http://www.w3.org/TR/rdf-sparql-query/#ebv
39
39
  def execute(queryable, options = {}, &block)
40
40
  debug(options) {"Filter #{operands.first.to_sxp}"}
41
- opts = options.merge(:queryable => queryable, :depth => options[:depth].to_i + 1)
41
+ opts = options.merge(queryable: queryable, depth: options[:depth].to_i + 1)
42
42
  @solutions = RDF::Query::Solutions()
43
- queryable.query(operands.last, options.merge(:depth => options[:depth].to_i + 1)) do |solution|
43
+ queryable.query(operands.last, options.merge(depth: options[:depth].to_i + 1)) do |solution|
44
44
  begin
45
45
  pass = boolean(operands.first.evaluate(solution, opts)).true?
46
46
  debug(options) {"(filter) #{pass.inspect} #{solution.to_hash.inspect}"}
@@ -4,22 +4,55 @@ module SPARQL; module Algebra
4
4
  ##
5
5
  # The SPARQL GraphPattern `graph` operator.
6
6
  #
7
- # This is a wrapper to add a `context` to the query.
7
+ # This is a wrapper to add a `context` to the query, or an array of statements.
8
8
  #
9
- # @example
9
+ # @example of a query
10
10
  # (prefix ((: <http://example/>))
11
11
  # (graph ?g
12
12
  # (bgp (triple ?s ?p ?o))))
13
13
  #
14
+ # @example named set of statements
15
+ # (prefix ((: <http://example/>))
16
+ # (graph :g
17
+ # ((triple :s :p :o))))
18
+ #
14
19
  # @see http://www.w3.org/TR/rdf-sparql-query/#sparqlAlgebra
15
20
  class Graph < Operator::Binary
16
21
  include Query
17
22
 
18
23
  NAME = [:graph]
24
+ ##
25
+ # A `graph` is an RDF::Query with a context. It can also be used as a container of statements or patterns, or other queryable operators (see GraphGraphPattern)
26
+ #
27
+ # @overload self.new(name, bgp)
28
+ # @param [RDF::Resource] name
29
+ # @param [RDF::Query] patterns
30
+ # A sub-query (bgp)
31
+ # @overload self.new(name, bgp)
32
+ # @param [RDF::Resource] name
33
+ # @param [Operator] patterns
34
+ # A sub-query (GraphGraphPattern)
35
+ # @overload self.new(name, patterns)
36
+ # @param [RDF::Resource] name
37
+ # @param [Array<RDF::Query::Pattern>] patterns
38
+ # Quads
39
+ # @return [RDF::Query]
40
+ def self.new(name, patterns, &block)
41
+ case patterns
42
+ when RDF::Query
43
+ # Record that the argument as a (bgp) for re-serialization back to SSE
44
+ RDF::Query.new(*(patterns.patterns + [{context: name,}]), &block)
45
+ when Operator
46
+ super
47
+ else
48
+ RDF::Query.new(*(patterns + [{context: name, as_container: true}]), &block)
49
+ end
50
+ end
19
51
 
20
52
  ##
21
- # Executes this query on the given `queryable` graph or repository.
22
- # Applies the given `context` to the query, limiting the scope of the query to the specified `context`, which may be an `RDF::URI` or `RDF::Query::Variable`.
53
+ # If the second operand is a Query operator:
54
+ # Executes this query on the given `queryable` graph or repository.
55
+ # Applies the given `context` to the query, limiting the scope of the query to the specified `context`, which may be an `RDF::URI` or `RDF::Query::Variable`.
23
56
  #
24
57
  # @param [RDF::Queryable] queryable
25
58
  # the graph or repository to query
@@ -35,7 +68,7 @@ module SPARQL; module Algebra
35
68
  def execute(queryable, options = {}, &block)
36
69
  debug(options) {"Graph #{operands.first}"}
37
70
  context, query = operands.first, operands.last
38
- @solutions = queryable.query(query, options.merge(:context => context), &block)
71
+ @solutions = queryable.query(query, options.merge(context: context), &block)
39
72
  end
40
73
 
41
74
  ##
@@ -50,6 +83,7 @@ module SPARQL; module Algebra
50
83
 
51
84
  ##
52
85
  # Don't do any more rewriting
86
+ # FIXME: if ooperator is JOIN, and rewritten sub-operators are queries, can do simple merge of sub-graphs
53
87
  # @return [SPARQL::Algebra::Expression] `self`
54
88
  def rewrite(&block)
55
89
  self
@@ -43,7 +43,7 @@ module SPARQL; module Algebra
43
43
  exprlist = operands.first
44
44
  query = operands.last
45
45
  aggregates = operands.length == 3 ? operand(1) : []
46
- solutions = queryable.query(query, options.merge(:depth => options[:depth].to_i + 1))
46
+ solutions = queryable.query(query, options.merge(depth: options[:depth].to_i + 1))
47
47
 
48
48
  groups = solutions.group_by do |solution|
49
49
  # Evaluate each exprlist operand to get groups where each key is a new solution
@@ -55,13 +55,13 @@ module SPARQL; module Algebra
55
55
  # Form is [variable, expression]
56
56
  soln[operand.first] = operand.last.evaluate(solution,
57
57
  options.merge(
58
- :queryable => queryable,
59
- :depth => options[:depth].to_i + 1))
58
+ queryable: queryable,
59
+ depth: options[:depth].to_i + 1))
60
60
  else
61
61
  # Form is variable
62
62
  soln[operand] = operand.evaluate(solution, options.merge(
63
- :queryable => queryable,
64
- :depth => options[:depth].to_i + 1))
63
+ queryable: queryable,
64
+ depth: options[:depth].to_i + 1))
65
65
  end
66
66
  rescue TypeError
67
67
  # Ignore expression
@@ -30,7 +30,7 @@ module SPARQL; module Algebra
30
30
  sep = operands.length == 2 ? operand(0).last : RDF::Literal(' ')
31
31
  args_enum = solutions.map do |solution|
32
32
  begin
33
- operands.last.evaluate(solution, options.merge(:depth => options[:depth].to_i + 1))
33
+ operands.last.evaluate(solution, options.merge(depth: options[:depth].to_i + 1))
34
34
  rescue TypeError
35
35
  # Ignore errors
36
36
  nil
@@ -34,9 +34,9 @@ module SPARQL; module Algebra
34
34
  # @return [RDF::Term]
35
35
  # @raise [TypeError]
36
36
  def evaluate(bindings, options = {})
37
- operand(0).evaluate(bindings, options.merge(:depth => options[:depth].to_i + 1)) == RDF::Literal::TRUE ?
38
- operand(1).evaluate(bindings, options.merge(:depth => options[:depth].to_i + 1).merge(:depth => options[:depth].to_i + 1)) :
39
- operand(2).evaluate(bindings, options.merge(:depth => options[:depth].to_i + 1))
37
+ operand(0).evaluate(bindings, options.merge(depth: options[:depth].to_i + 1)) == RDF::Literal::TRUE ?
38
+ operand(1).evaluate(bindings, options.merge(depth: options[:depth].to_i + 1).merge(depth: options[:depth].to_i + 1)) :
39
+ operand(2).evaluate(bindings, options.merge(depth: options[:depth].to_i + 1))
40
40
  rescue
41
41
  raise TypeError
42
42
  end
@@ -45,7 +45,7 @@ module SPARQL; module Algebra
45
45
  error_found = false
46
46
  found = operands[1..-1].any? do |op|
47
47
  begin
48
- lhs == op.evaluate(bindings, options.merge(:depth => options[:depth].to_i + 1))
48
+ lhs == op.evaluate(bindings, options.merge(depth: options[:depth].to_i + 1))
49
49
  rescue TypeError
50
50
  error_found = true
51
51
  end
@@ -0,0 +1,54 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+
4
+ ##
5
+ # The SPARQL UPDATE `insertData` operator.
6
+ #
7
+ # The INSERT operation is a form of the DELETE/INSERT operation having no DELETE section
8
+ #
9
+ # @example
10
+ # (insert ((triple ?s ?p "q")))
11
+ #
12
+ # @see http://www.w3.org/TR/sparql11-update/#insert
13
+ class Insert < Operator::Unary
14
+ include SPARQL::Algebra::Update
15
+
16
+ NAME = [:insert]
17
+
18
+ ##
19
+ # Executes this upate on the given `writable` graph or repository.
20
+ #
21
+ # @param [RDF::Queryable] queryable
22
+ # the graph or repository to write
23
+ # @param [RDF::Query::Solution] solution
24
+ # Solution to map to patterns for this operation
25
+ # @param [Hash{Symbol => Object}] options
26
+ # any additional keyword options
27
+ # @option options [Boolean] debug
28
+ # Query execution debugging
29
+ # @return [RDF::Queryable]
30
+ # Returns queryable.
31
+ # @raise [IOError]
32
+ # If `from` does not exist, unless the `silent` operator is present
33
+ # @see http://www.w3.org/TR/sparql11-update/
34
+ def execute(queryable, solution, options = {})
35
+ debug(options) {"Insert"}
36
+ patterns = operand.inject([]) do |memo, op|
37
+ if op.respond_to?(:statements)
38
+ memo += op.statements.to_a
39
+ else
40
+ memo << op
41
+ end
42
+ memo
43
+ end
44
+ patterns.each do |pattern|
45
+ pattern = pattern.dup.bind(solution)
46
+ debug(options) {"Insert statement #{statement.to_sse}"}
47
+ # Only insert bound or constant patterns
48
+ queryable.insert(RDF::Statement.from(pattern)) if pattern.bound? || pattern.constant?
49
+ end
50
+ queryable
51
+ end
52
+ end # Insert
53
+ end # Operator
54
+ end; end # SPARQL::Algebra
@@ -0,0 +1,41 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+
4
+ ##
5
+ # The SPARQL UPDATE `insertData` operator.
6
+ #
7
+ # The INSERT DATA operation adds some triples, given inline in the request, into the Graph Store
8
+ #
9
+ # @example
10
+ # (insertData ((graph <http://example.org/g1> ((triple :s :p :o)))))
11
+ #
12
+ # @see http://www.w3.org/TR/sparql11-update/#insertData
13
+ class InsertData < Operator::Unary
14
+ include SPARQL::Algebra::Update
15
+
16
+ NAME = [:insertData]
17
+
18
+ ##
19
+ # Executes this upate on the given `writable` graph or repository.
20
+ #
21
+ # @param [RDF::Queryable] queryable
22
+ # the graph or repository to write
23
+ # @param [Hash{Symbol => Object}] options
24
+ # any additional keyword options
25
+ # @option options [Boolean] debug
26
+ # Query execution debugging
27
+ # @return [RDF::Queryable]
28
+ # Returns queryable.
29
+ # @raise [IOError]
30
+ # If `from` does not exist, unless the `silent` operator is present
31
+ # @see http://www.w3.org/TR/sparql11-update/
32
+ def execute(queryable, options = {})
33
+ operand.each do |op|
34
+ debug(options) {"InsertData #{op.to_sxp}"}
35
+ queryable.insert(op)
36
+ end
37
+ queryable
38
+ end
39
+ end # InsertData
40
+ end # Operator
41
+ end; end # SPARQL::Algebra
@@ -41,10 +41,10 @@ module SPARQL; module Algebra
41
41
  # Generate solutions independently, merge based on solution compatibility
42
42
  debug(options) {"Join"}
43
43
 
44
- left = queryable.query(operand(0), options.merge(:depth => options[:depth].to_i + 1))
44
+ left = queryable.query(operand(0), options.merge(depth: options[:depth].to_i + 1))
45
45
  debug(options) {"(join)=>(left) #{left.inspect}"}
46
46
 
47
- right = queryable.query(operand(1), options.merge(:depth => options[:depth].to_i + 1))
47
+ right = queryable.query(operand(1), options.merge(depth: options[:depth].to_i + 1))
48
48
  debug(options) {"(join)=>(right) #{right.inspect}"}
49
49
 
50
50
  @solutions = RDF::Query::Solutions(left.map do |s1|
@@ -22,7 +22,7 @@ module SPARQL; module Algebra
22
22
  # @raise [TypeError] if the operand is not a literal value
23
23
  def apply(operand)
24
24
  case operand
25
- when RDF::Literal then RDF::Literal(operand.to_s.downcase, :datatype => operand.datatype, :language => operand.language)
25
+ when RDF::Literal then RDF::Literal(operand.to_s.downcase, datatype: operand.datatype, language: operand.language)
26
26
  else raise TypeError, "expected an RDF::Literal::Numeric, but got #{operand.inspect}"
27
27
  end
28
28
  end
@@ -38,10 +38,10 @@ module SPARQL; module Algebra
38
38
  filter = operand(2)
39
39
 
40
40
  debug(options) {"LeftJoin"}
41
- left = queryable.query(operand(0), options.merge(:depth => options[:depth].to_i + 1))
41
+ left = queryable.query(operand(0), options.merge(depth: options[:depth].to_i + 1))
42
42
  debug(options) {"=>(leftjoin left) #{left.inspect}"}
43
43
 
44
- right = queryable.query(operand(1), options.merge(:depth => options[:depth].to_i + 1))
44
+ right = queryable.query(operand(1), options.merge(depth: options[:depth].to_i + 1))
45
45
  debug(options) {"=>(leftjoin right) #{right.inspect}"}
46
46
 
47
47
  # LeftJoin(Ω1, Ω2, expr) =
@@ -0,0 +1,48 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+
4
+ ##
5
+ # The SPARQL UPDATE `load` operator.
6
+ #
7
+ # The LOAD operation reads an RDF document from a IRI and inserts its triples into the specified graph in the Graph Store. The specified destination graph should be created if required; again, implementations providing an update service over a fixed set of graphs must return with failure for a request that would create a disallowed graph. If the destination graph already exists, then no data in that graph will be removed.
8
+ #
9
+ # @example
10
+ # (load <remote> <g>)
11
+ #
12
+ # @see http://www.w3.org/TR/sparql11-update/#load
13
+ class Load < Operator
14
+ include SPARQL::Algebra::Update
15
+
16
+ NAME = [:load]
17
+
18
+ ##
19
+ # Executes this upate on the given `writable` graph or repository.
20
+ #
21
+ # @param [RDF::Queryable] queryable
22
+ # the graph or repository to write
23
+ # @param [Hash{Symbol => Object}] options
24
+ # any additional keyword options
25
+ # @option options [Boolean] debug
26
+ # Query execution debugging
27
+ # @return [RDF::Queryable]
28
+ # Returns queryable.
29
+ # @raise [IOError]
30
+ # If `from` does not exist, unless the `silent` operator is present
31
+ # @see http://www.w3.org/TR/sparql11-update/
32
+ def execute(queryable, options = {})
33
+ debug(options) {"Load"}
34
+ silent = operands.first == :silent
35
+ operands.shift if silent
36
+
37
+ raise ArgumentError, "load expected one or two operands, got #{operands.length}" unless [1,2].include?(operands.length)
38
+
39
+ location, name = operands
40
+ queryable.load(location, context: name)
41
+ rescue IOError, Errno::ENOENT
42
+ raise unless silent
43
+ ensure
44
+ queryable
45
+ end
46
+ end # Load
47
+ end # Operator
48
+ end; end # SPARQL::Algebra
@@ -42,9 +42,9 @@ module SPARQL; module Algebra
42
42
  #
43
43
  # card[Minus(Ω1, Ω2)](μ) = card[Ω1](μ)
44
44
  debug(options) {"Minus"}
45
- left = queryable.query(operand(0), options.merge(:depth => options[:depth].to_i + 1))
45
+ left = queryable.query(operand(0), options.merge(depth: options[:depth].to_i + 1))
46
46
  debug(options) {"(minus left) #{left.inspect}"}
47
- right = queryable.query(operand(1), options.merge(:depth => options[:depth].to_i + 1))
47
+ right = queryable.query(operand(1), options.merge(depth: options[:depth].to_i + 1))
48
48
  debug(options) {"(minus right) #{right.inspect}"}
49
49
  @solutions = left.minus(right)
50
50
  @solutions.each(&block) if block_given?
@@ -0,0 +1,53 @@
1
+ module SPARQL; module Algebra
2
+ class Operator
3
+
4
+ ##
5
+ # The SPARQL UPDATE `modify` operator.
6
+ #
7
+ # Wraps delete/insert
8
+ #
9
+ # @example
10
+ # (modify
11
+ # (bgp (triple ?a foaf:knows ?b))
12
+ # (delete ((triple ?a foaf:knows ?b)))
13
+ # (insert ((triple ?b foaf:knows ?a)))
14
+ #
15
+ # @see XXX
16
+ class Modify < Operator
17
+ include SPARQL::Algebra::Update
18
+
19
+ NAME = [:modify]
20
+
21
+ ##
22
+ # Executes this upate on the given `writable` graph or repository.
23
+ #
24
+ # Execute the first operand to get solutions, and apply those solutions to the subsequent operators.
25
+ #
26
+ # @param [RDF::Queryable] queryable
27
+ # the graph or repository to write
28
+ # @param [Hash{Symbol => Object}] options
29
+ # any additional keyword options
30
+ # @option options [Boolean] debug
31
+ # Query execution debugging
32
+ # @return [RDF::Queryable]
33
+ # Returns queryable.
34
+ # @raise [IOError]
35
+ # If `from` does not exist, unless the `silent` operator is present
36
+ # @see http://www.w3.org/TR/sparql11-update/
37
+ def execute(queryable, options = {})
38
+ debug(options) {"Modify"}
39
+ query = operands.shift
40
+
41
+ queryable.query(query, options.merge(depth: options[:depth].to_i + 1)) do |solution|
42
+ debug(options) {"(solution)=>#{solution.inspect}"}
43
+
44
+ # Execute each operand with queryable and solution
45
+ operands.each do |op|
46
+ op.execute(queryable, solution, options.merge(depth: options[:depth].to_i + 1))
47
+ end
48
+ end
49
+ queryable
50
+ end
51
+ end # Modify
52
+ end # Operator
53
+ end; end # SPARQL::Algebra