Class: SPARQL::Algebra::Operator::Extend

Inherits:
Binary show all
Includes:
Query
Defined in:
lib/sparql/algebra/operator/extend.rb

Overview

The SPARQL Extend operator.

Extends a solution

[60] Bind ::= 'BIND' '(' Expression 'AS' Var ')'

Examples:

SPARQL Grammar

SELECT ?z
{ 
  ?x <http://example.org/p> ?o
  BIND(?o+10 AS ?z)
}

SSE

(project (?z)
  (extend ((?z (+ ?o 10)))
    (bgp (triple ?x <http://example.org/p> ?o))))

SPARQL Grammar (cast as boolean)

PREFIX : <http://example.org/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?a ?v (xsd:boolean(?v) AS ?boolean)
WHERE { ?a :p ?v . }

SSE (cast as boolean)

(prefix ((: <http://example.org/>)
         (rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>)
         (xsd: <http://www.w3.org/2001/XMLSchema#>))
 (project (?a ?v ?boolean)
  (extend ((?boolean (xsd:boolean ?v)))
   (bgp (triple ?a :p ?v)))))

SPARQL Grammar (inner bind)

PREFIX : <http://example.org/> 

SELECT ?z ?s1
{
  ?s ?p ?o .
  BIND(?o+1 AS ?z)
  ?s1 ?p1 ?z
}

SSE (inner bind)

(prefix ((: <http://example.org/>))
 (project (?z ?s1)
  (join
   (extend ((?z (+ ?o 1)))
    (bgp (triple ?s ?p ?o)))
  (bgp (triple ?s1 ?p1 ?z)))))

See Also:

Constant Summary collapse

NAME =
[:extend]

Constants inherited from Binary

Binary::ARITY

Constants inherited from SPARQL::Algebra::Operator

ARITY, IsURI, URI

Constants included from Expression

Expression::PATTERN_PARENTS

Instance Attribute Summary

Attributes included from Query

#solutions

Attributes inherited from SPARQL::Algebra::Operator

#operands

Instance Method Summary collapse

Methods included from Query

#each_solution, #empty?, #failed?, #graph_name=, #matched?, #query_yields_boolean?, #query_yields_solutions?, #query_yields_statements?, #unshift

Methods inherited from Binary

#initialize

Methods inherited from SPARQL::Algebra::Operator

#aggregate?, arity, #base_uri, base_uri, base_uri=, #bind, #boolean, #constant?, #deep_dup, #each_descendant, #eql?, #evaluatable?, evaluate, #executable?, #first_ancestor, for, #initialize, #inspect, #ndvars, #node?, #operand, #optimize, #optimize!, #parent, #parent=, #prefixes, prefixes, prefixes=, #rewrite, #to_binary, to_sparql, #to_sxp, #to_sxp_bin, #variable?, #vars

Methods included from Expression

cast, #constant?, #evaluate, extension, extension?, extensions, for, #invalid?, new, #node?, open, #optimize, #optimize!, parse, register_extension, #to_sxp_bin, #valid?, #variable?

Constructor Details

This class inherits a constructor from SPARQL::Algebra::Operator::Binary

Instance Method Details

#execute(queryable, **options) {|solution| ... } ⇒ RDF::Query::Solutions

Let μ be a solution mapping, Ω a multiset of solution mappings, var a variable and expr be an expression, then we define:

Extend(μ, var, expr) = μ ∪ { (var,value) | var not in dom(μ) and value = expr(μ) }

Extend(μ, var, expr) = μ if var not in dom(μ) and expr(μ) is an error

Extend is undefined when var in dom(μ).

Extend(Ω, var, expr) = { Extend(μ, var, expr) | μ in Ω }

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to query

  • options (Hash{Symbol => Object})

    any additional keyword options

Yields:

  • (solution)

    each matching solution

Yield Parameters:

Yield Returns:

  • (void)

    ignored

Returns:

See Also:



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/sparql/algebra/operator/extend.rb', line 83

def execute(queryable, **options, &block)
  debug(options) {"Extend"}
  @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|
      solution[name] = value if operands.first.variables.include?(name)
    end if options[:bindings] && operands.first.respond_to?(:variables)

    debug(options) {"===> soln #{solution.to_h.inspect}"}
    operand(0).each do |(var, expr)|
      begin
        val = expr.evaluate(solution, queryable: queryable,
                                      **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
      rescue TypeError => e
        # Evaluates to error, ignore
        debug(options) {"===> #{var} error: #{e.message}"}
      end
    end
  end
  @solutions.each(&block) if block_given?
  @solutions
end

#to_sparql(**options) ⇒ String

Returns a partial SPARQL grammar for this operator.

Extracts bindings.

Returns:

  • (String)


158
159
160
161
162
163
164
165
166
167
# File 'lib/sparql/algebra/operator/extend.rb', line 158

def to_sparql(**options)
  extensions = operands.first.inject({}) do |memo, (as, expression)|
    # Use string/name of variable "as" to aid in later matching
    memo.merge(as.to_s => expression)
  end

  # Merge any inherited extensions from options
  extensions = options.delete(:extensions).merge(extensions) if options.key?(:extensions)
  operands.last.to_sparql(extensions: extensions, **options)
end

#validate!Object

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

Also, variables used in a binding expression must be projected by the query.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/sparql/algebra/operator/extend.rb', line 113

def validate!
  bind_vars = operand(0).map(&:first).map(&:name)
  query_vars = operand(1).variables.keys
  
  unless (bind_vars.compact & query_vars.compact).empty?
    raise ArgumentError,
         "bound variable used in query: #{(bind_vars.compact & query_vars.compact).to_sse}"
  end

  # Special case for group variables
  if operands.last.is_a?(Group)
    bind_expr_vars = operand(0).map(&:last).variables.keys
    group_vars = operands.last.variables.keys
    group_internal_vars = operands.last.internal_variables.keys

    bind_expr_vars.each do |v|
      raise ArgumentError,
           "extension expression uses variable not in scope: #{v}" if
           group_internal_vars.include?(v) &&
           !group_vars.include?(v)
    end
  end

  super
end

#variablesHash{Symbol => RDF::Query::Variable}

The variables used in the extension. Includes extended variables.

Returns:



144
145
146
147
148
149
# File 'lib/sparql/algebra/operator/extend.rb', line 144

def variables
  operands.first.
    map(&:first).
    map(&:variables).
    inject(operands.last.variables) {|memo, h| memo.merge(h)}
end