Skip to content

Commit

Permalink
Finish 3.2.5
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Jan 4, 2023
2 parents 4687fc5 + a773b0b commit 716a3f5
Show file tree
Hide file tree
Showing 51 changed files with 136 additions and 114 deletions.
10 changes: 2 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,10 @@ jobs:
strategy:
fail-fast: false
matrix:
ruby:
- 2.6
- 2.7
- "3.0"
- 3.1
- ruby-head
- jruby
ruby: [2.6, 2.7, '3.0', 3.1, 3.2, ruby-head, jruby]
steps:
- name: Clone repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/generate-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: Update gh-pages with docs
steps:
- name: Clone repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.4
3.2.5
2 changes: 1 addition & 1 deletion lib/sparql/algebra/aggregate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def aggregate(solutions = [], **options)
args_enum = solutions.map do |solution|
operands.map do |operand|
begin
operand.evaluate(solution, depth: options[:depth].to_i + 1, **options)
operand.evaluate(solution, **options.merge(depth: options[:depth].to_i + 1))
rescue TypeError
# Ignore errors
nil
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/evaluatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module Evaluatable
# @return [RDF::Term]
# @abstract
def evaluate(bindings, **options)
args = operands.map { |operand| operand.evaluate(bindings, depth: options[:depth].to_i + 1, **options) }
args = operands.map { |operand| operand.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1)) }
options[:memoize] ? memoize(*args, **options) : apply(*args, **options)
end

Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/expression.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def self.new(sse, parent_operator: nil, **options)
return case sse.first
when Array
debug(options) {"Map array elements #{sse}"}
sse.map {|s| self.new(s, parent_operator: parent_operator, depth: options[:depth].to_i + 1, **options)}
sse.map {|s| self.new(s, parent_operator: parent_operator, **options.merge(depth: options[:depth].to_i + 1))}
else
debug(options) {"No operator found for #{sse.first}"}
sse.map do |s|
Expand All @@ -127,7 +127,7 @@ def self.new(sse, parent_operator: nil, **options)
debug(options) {"Operator=#{operator.inspect}, Operand=#{operand.inspect}"}
case operand
when Array
self.new(operand, parent_operator: operator, depth: options[:depth].to_i + 1, **options)
self.new(operand, parent_operator: operator, **options.merge(depth: options[:depth].to_i + 1))
when Operator, Variable, RDF::Term, RDF::Query, Symbol
operand
when TrueClass, FalseClass, Numeric, String, DateTime, Date, Time
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/alt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def execute(queryable, **options, &block)
end

query = Union.new(qa, qb)
queryable.query(query, depth: options[:depth].to_i + 1, **options, &block)
queryable.query(query, **options.merge(depth: options[:depth].to_i + 1), &block)
end

##
Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/operator/and.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ def initialize(left, right, **options)
# @raise [TypeError] if the operands could not be coerced to boolean literals
def evaluate(bindings, **options)
begin
left = boolean(operand(0).evaluate(bindings, depth: options[:depth].to_i + 1, **options)).true?
left = boolean(operand(0).evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))).true?
rescue TypeError
left = nil
end

begin
right = boolean(operand(1).evaluate(bindings, depth: options[:depth].to_i + 1, **options)).true?
right = boolean(operand(1).evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))).true?
rescue TypeError
right = nil
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/asc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Asc < Operator::Unary
# options passed from query
# @return [RDF::Term]
def evaluate(bindings, **options)
operand(0).evaluate(bindings, depth: options[:depth].to_i + 1, **options)
operand(0).evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))
end

##
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/ask.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Ask < Operator::Unary
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
def execute(queryable, **options)
debug(options) {"Ask #{operands.first}"}
res = boolean(!queryable.query(operands.last, depth: options[:depth].to_i + 1, **options).empty?)
res = boolean(!queryable.query(operands.last, **options.merge(depth: options[:depth].to_i + 1)).empty?)
yield res if block_given?
res
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Base < Binary
def execute(queryable, **options, &block)
debug(options) {"Base #{operands.first}"}
Operator.base_uri = operands.first
queryable.query(operands.last, depth: options[:depth].to_i + 1, **options, &block)
queryable.query(operands.last, **options.merge(depth: options[:depth].to_i + 1), &block)
end

##
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/bnode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def initialize(literal = false, **options)
# options passed from query
# @return [RDF::Term]
def evaluate(bindings, **options)
args = operands.map { |operand| operand.evaluate(bindings, depth: options[:depth].to_i + 1, **options) }
args = operands.map { |operand| operand.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1)) }
apply(args.first, bindings)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/coalesce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Coalesce < Operator
def evaluate(bindings, **options)
operands.each do |op|
begin
return op.evaluate(bindings, depth: options[:depth].to_i + 1, **options)
return op.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))
rescue
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/concat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Concat < Operator
# @return [RDF::Term]
# @raise [TypeError] if any operand is not a literal
def evaluate(bindings, **options)
ops = operands.map {|op| op.evaluate(bindings, depth: options[:depth].to_i + 1, **options)}
ops = operands.map {|op| op.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))}

raise TypeError, "expected all plain literal operands" unless ops.all? {|op| op.literal? && op.plain?}

Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/construct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def execute(queryable, **options, &block)
patterns = operands.first
query = operands.last

queryable.query(query, depth: options[:depth].to_i + 1, **options).each do |solution|
queryable.query(query, **options.merge(depth: options[:depth].to_i + 1)).each do |solution|
debug(options) {"(construct apply) #{solution.inspect} to BGP"}

# Create a mapping from BNodes within the pattern list to newly constructed BNodes
Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/operator/dataset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def execute(queryable, **options, &base)
debug(options) {"Dataset"}
if %i(default-graph-uri named-graph-uri).any? {|k| options.key?(k)}
debug("=> Skip constructing merge repo due to options", options)
return queryable.query(operands.last, depth: options[:depth].to_i + 1, **options, &base)
return queryable.query(operands.last, **options.merge(depth: options[:depth].to_i + 1), &base)
end

default_datasets = []
Expand Down Expand Up @@ -180,7 +180,7 @@ def execute(queryable, **options, &base)
aggregate = RDF::AggregateRepo.new(queryable)
named_datasets.each {|name| aggregate.named(name) if queryable.has_graph?(name)}
aggregate.default(*default_datasets.select {|name| queryable.has_graph?(name)})
aggregate.query(operands.last, depth: options[:depth].to_i + 1, **options, &base)
aggregate.query(operands.last, **options.merge(depth: options[:depth].to_i + 1), &base)
end

##
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/delete_where.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def execute(queryable, **options)
end
query = RDF::Query.new(*patterns, **{}) # FIXME: added hash argument needed until Statement#to_hash removed.
debug(options) {"DeleteWhere query #{query.to_sse}"}
query.execute(queryable, depth: options[:depth].to_i + 1, **options) do |solution|
query.execute(queryable, **options.merge(depth: options[:depth].to_i + 1)) do |solution|
debug(options) {"DeleteWhere solution #{solution.to_sse}"}
query.each_statement do |pattern|
pattern = pattern.dup.bind(solution)
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/distinct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Distinct < Operator::Unary
# the resulting solution sequence
# @see https://www.w3.org/TR/sparql11-query/#sparqlAlgebra
def execute(queryable, **options, &block)
@solutions = queryable.query(operands.last, depth: options[:depth].to_i + 1, **options).distinct
@solutions = queryable.query(operands.last, **options.merge(depth: options[:depth].to_i + 1)).distinct
@solutions.each(&block) if block_given?
@solutions
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/exprlist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Exprlist < Operator
# @return [RDF::Literal::Boolean] `true` or `false`
# @raise [TypeError] if the operands could not be coerced to a boolean literal
def evaluate(bindings, **options)
res = operands.all? {|op| boolean(op.evaluate(bindings, depth: options[:depth].to_i + 1, **options)).true? }
res = operands.all? {|op| boolean(op.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))).true? }
RDF::Literal(res) # FIXME: error handling
end
end # Exprlist
Expand Down
5 changes: 2 additions & 3 deletions lib/sparql/algebra/operator/extend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Extend < Operator::Binary
# @see https://www.w3.org/TR/sparql11-query/#evaluation
def execute(queryable, **options, &block)
debug(options) {"Extend"}
@solutions = operand(1).execute(queryable, depth: options[:depth].to_i + 1, **options)
@solutions = operand(1).execute(queryable, **options.merge(depth: options[:depth].to_i + 1))
@solutions.each do |solution|
# Re-bind to bindings, if defined, as they might not be found in solution
options[:bindings].each_binding do |name, value|
Expand All @@ -93,8 +93,7 @@ def execute(queryable, **options, &block)
operand(0).each do |(var, expr)|
begin
val = expr.evaluate(solution, queryable: queryable,
depth: options[:depth].to_i + 1,
**options)
**options.merge(depth: options[:depth].to_i + 1))
debug(options) {"===> + #{var} => #{val.inspect}"}
val = val.dup.bind(solution) if val.is_a?(RDF::Query::Pattern)
solution.bindings[var.to_sym] = val
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def execute(queryable, **options, &block)
debug(options) {"Filter #{operands.first.to_sxp}"}
opts = options.merge(queryable: queryable, depth: options[:depth].to_i + 1)
@solutions = RDF::Query::Solutions()
queryable.query(operands.last, depth: options[:depth].to_i + 1, **options) do |solution|
queryable.query(operands.last, **options.merge(depth: options[:depth].to_i + 1)) do |solution|
# Re-bind to bindings, if defined, as they might not be found in solution
options[:bindings].each_binding do |name, value|
solution[name] ||= value if operands.first.variables.include?(name)
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def execute(queryable, **options, &block)
exprlist = operands.first
query = operands.last
aggregates = operands.length == 3 ? operand(1) : []
solutions = queryable.query(query, depth: options[:depth].to_i + 1, **options)
solutions = queryable.query(query, **options.merge(depth: options[:depth].to_i + 1))

groups = solutions.group_by do |solution|
# Evaluate each exprlist operand to get groups where each key is a new solution
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/group_concat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def aggregate(solutions = [], **options)
sep = operands.length == 2 ? operand(0).last : RDF::Literal(' ')
args_enum = solutions.map do |solution|
begin
operands.last.evaluate(solution, depth: options[:depth].to_i + 1, **options)
operands.last.evaluate(solution, **options.merge(depth: options[:depth].to_i + 1))
rescue TypeError
# Ignore errors
nil
Expand Down
6 changes: 3 additions & 3 deletions lib/sparql/algebra/operator/if.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ class If < Operator::Ternary
# @return [RDF::Term]
# @raise [TypeError]
def evaluate(bindings, **options)
operand(0).evaluate(bindings, depth: options[:depth].to_i + 1, **options) == RDF::Literal::TRUE ?
operand(1).evaluate(bindings, depth: options[:depth].to_i + 1, **options) :
operand(2).evaluate(bindings, depth: options[:depth].to_i + 1, **options)
operand(0).evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1)) == RDF::Literal::TRUE ?
operand(1).evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1)) :
operand(2).evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))
rescue
raise TypeError
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/in.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def evaluate(bindings, **options)
error_found = false
found = operands[1..-1].any? do |op|
begin
lhs == op.evaluate(bindings, depth: options[:depth].to_i + 1, **options)
lhs == op.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))
rescue TypeError
error_found = true
end
Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/operator/join.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ def execute(queryable, **options, &block)
# Generate solutions independently, merge based on solution compatibility
debug(options) {"Join #{operands.to_sse}"}

left = queryable.query(operand(0), depth: options[:depth].to_i + 1, **options)
left = queryable.query(operand(0), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"(join)=>(left) #{left.map(&:to_h).to_sse}"}

right = queryable.query(operand(1), depth: options[:depth].to_i + 1, **options)
right = queryable.query(operand(1), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"(join)=>(right) #{right.map(&:to_h).to_sse}"}

@solutions = RDF::Query::Solutions(left.map do |s1|
Expand Down
28 changes: 26 additions & 2 deletions lib/sparql/algebra/operator/left_join.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ def execute(queryable, **options, &block)
operands.length < 2 || operands.length > 3

debug(options) {"LeftJoin"}
left = queryable.query(operand(0), depth: options[:depth].to_i + 1, **options)
left = queryable.query(operand(0), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"=>(leftjoin left) #{left.inspect}"}

right = queryable.query(operand(1), depth: options[:depth].to_i + 1, **options)
right = queryable.query(operand(1), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"=>(leftjoin right) #{right.inspect}"}

# LeftJoin(Ω1, Ω2, expr) =
Expand All @@ -71,6 +71,30 @@ def execute(queryable, **options, &block)
s[name] = value if filter.variables.include?(name)
end if options[:bindings] && filter.respond_to?(:variables)

# See https://github.com/w3c/rdf-tests/pull/83#issuecomment-1324220844 for @afs's discussion of the simplified/not-simplified issue.
#
# The difference is when simplification is applied. It matters for OPTIONAL because OPTIONAL { ... FILTER(...) } puts the filter into the LeftJoin expressions. In LeftJoin, the FILTER can see the left-hand-side variables. (SQL: LEFT JOIN ... ON ...)
#
# For OPTIONAL { { ... FILTER(...) } }, the inner part is Join({}, {.... FILTER }).
#
# if simplify happens while coming back up the tree generating algebra operations, it removes the join i.e. the inner of {{ }}, and passes "... FILTER()" to the OPTIONAL. The effect of the extra nesting in {{ }} is lost and it exposes the filter to the OPTIONAL rule.
#
# if simplification happens as a step after the whole algebra is converted, this does not happen. Compiling the OPTIONAL see a join and the filter is not at the top level of the OPTIONAl block and so not handled in the LeftJoin.
#
# Use case:
#
# # Include name if person over 18
# SELECT *
# { ?person :age ?age
# OPTIONAL { ?person :name ?name. FILTER(?age > 18) }
# }
# Hindsight: a better syntax would be call out if the filter needed access to the LHS.
#
# OPTIONAL FILTER(....) { }
#
# But we are where we are.
#
# (a "no conditions on LeftJoin" approach would mean users having to duplicate parts of their query - possibly quite large parts.)
expr = filter ? boolean(filter.evaluate(s)).true? : true rescue false
debug(options) {"===>(evaluate) #{s.inspect}"} if filter

Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/operator/minus.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ def execute(queryable, **options, &block)
#
# card[Minus(Ω1, Ω2)](μ) = card[Ω1](μ)
debug(options) {"Minus"}
left = queryable.query(operand(0), depth: options[:depth].to_i + 1, **options)
left = queryable.query(operand(0), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"(minus left) #{left.inspect}"}
right = queryable.query(operand(1), depth: options[:depth].to_i + 1, **options)
right = queryable.query(operand(1), **options.merge(depth: options[:depth].to_i + 1))
debug(options) {"(minus right) #{right.inspect}"}
@solutions = left.minus(right)
@solutions.each(&block) if block_given?
Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/operator/modify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ def execute(queryable, **options)
query = Operator::Using.new((defaults + named), query, **options)
end

queryable.query(query, depth: options[:depth].to_i + 1, **options) do |solution|
queryable.query(query, **options.merge(depth: options[:depth].to_i + 1)) do |solution|
debug(options) {"(solution)=>#{solution.inspect}"}

# Execute each operand with queryable and solution
operands.each do |op|
op.execute(queryable, solutions: solution, depth: options[:depth].to_i + 1, **options)
op.execute(queryable, solutions: solution, **options.merge(depth: options[:depth].to_i + 1))
end
end
queryable
Expand Down
4 changes: 2 additions & 2 deletions lib/sparql/algebra/operator/notin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ class NotIn < Operator
# @return [RDF::Literal::Boolean] `true` or `false`
# @raise [TypeError] if term is not found and any operand raises an error
def evaluate(bindings, **options)
lhs = operands.first.evaluate(bindings, depth: options[:depth].to_i + 1, **options)
lhs = operands.first.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))
error_found = false
found = operands[1..-1].any? do |op|
begin
lhs == op.evaluate(bindings, depth: options[:depth].to_i + 1, **options)
lhs == op.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1))
rescue TypeError
error_found = true
end
Expand Down
2 changes: 1 addition & 1 deletion lib/sparql/algebra/operator/notoneof.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def execute(queryable, **options, &block)
q.pattern [subject, v, object]
end
query = Filter.new(NotIn.new(v, *operands), bgp)
queryable.query(query, depth: options[:depth].to_i + 1, **options) do |solution|
queryable.query(query, **options.merge(depth: options[:depth].to_i + 1)) do |solution|
solution.bindings.delete(v.to_sym)
debug(options) {"(solution)-> #{solution.to_h.to_sse}"}
block.call(solution)
Expand Down
Loading

0 comments on commit 716a3f5

Please sign in to comment.