Class: RDF::Query::Pattern
- Defined in:
- lib/rdf/query/pattern.rb
Overview
An RDF query pattern.
Instance Attribute Summary collapse
-
#cost ⇒ Numeric
The estimated cost of this pattern (for query optimization).
-
#options ⇒ Hash
readonly
Any additional options for this pattern.
Attributes inherited from Statement
#graph_name, #id, #object, #predicate, #subject
Class Method Summary collapse
Instance Method Summary collapse
-
#bind(solution) ⇒ self
Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables.
-
#binding_count ⇒ Integer
Returns the number of bindings in this pattern.
-
#bindings ⇒ Hash{Symbol => RDF::Term}
Returns all bindings in this pattern.
-
#bindings? ⇒ Boolean
Returns ‘true` if this pattern contains bindings.
-
#blank? ⇒ Boolean
Returns ‘true` if this is a blank pattern, with all terms being `nil`.
-
#bound? ⇒ Boolean
Returns ‘true` if all variables in this pattern are bound.
-
#bound_variables ⇒ Hash{Symbol => Variable}
Returns all bound variables in this pattern.
-
#dup ⇒ Object
Create a new pattern from the quads, recursivly dupping sub-patterns.
-
#eql?(other) ⇒ Boolean
Checks pattern equality against a statement, considering nesting.
-
#execute(queryable, bindings = {}) {|statement| ... } ⇒ Enumerable<RDF::Query::Pattern>
Executes this query pattern on the given ‘queryable` object.
-
#initialize(subject = nil, predicate = nil, object = nil, options = {}) ⇒ Pattern
constructor
A new instance of Pattern.
- #initialize! ⇒ Object
-
#optional? ⇒ Boolean
Returns ‘true` if this is an optional pattern.
-
#solution(statement) ⇒ RDF::Query::Solution
Returns a query solution constructed by binding any variables in this pattern with the corresponding terms in the given ‘statement`.
-
#to_s ⇒ String
Returns a string representation of this pattern.
-
#unbound? ⇒ Boolean
Returns ‘true` if all variables in this pattern are unbound.
-
#unbound_variables ⇒ Hash{Symbol => Variable}
Returns all unbound variables in this pattern.
-
#valid? ⇒ Boolean
Is this pattern composed only of valid components?.
-
#var_values(var, statement) ⇒ Array<RDF::Term>
Returns all values the statement in the same pattern position.
-
#variable_count ⇒ Integer
(also: #cardinality, #arity)
Returns the number of variables in this pattern.
-
#variable_terms(name = nil) ⇒ Array<Symbol>
deprecated
Deprecated.
use #var_values instead
-
#variables ⇒ Hash{Symbol => Variable}
Returns all variables in this pattern.
-
#variables? ⇒ Boolean
(also: #has_variables?)
Returns ‘true` if this pattern contains any variables.
Methods inherited from Statement
#==, #===, #[], #[]=, #asserted?, #canonicalize, #canonicalize!, #complete?, #embedded?, #graph?, #hash, #incomplete?, #inferred?, #invalid?, #node?, #object?, #predicate?, #quoted?, #reified, #statement?, #subject?, #terms, #to_h, #to_quad, #to_triple, #tripleTerm?, #variable?
Methods included from Resource
Methods included from Term
#<=>, #==, #compatible?, #term?, #terms, #to_base, #to_term
Methods included from Value
#anonymous?, #canonicalize, #canonicalize!, #constant?, #graph?, #inspect, #inspect!, #invalid?, #iri?, #list?, #literal?, #node?, #resource?, #start_with?, #statement?, #term?, #to_nquads, #to_ntriples, #to_rdf, #to_term, #type_error, #uri?, #validate!, #variable?
Constructor Details
#initialize(options = {}) ⇒ Pattern #initialize(subject, predicate, object, options = {}) ⇒ Pattern
Statement treats symbols as interned Node instances, in a RDF::Query::Pattern, they are treated as Variable.
Returns a new instance of Pattern.
39 40 41 |
# File 'lib/rdf/query/pattern.rb', line 39 def initialize(subject = nil, predicate = nil, object = nil, = {}) super end |
Instance Attribute Details
#cost ⇒ Numeric
The estimated cost of this pattern (for query optimization).
78 79 80 |
# File 'lib/rdf/query/pattern.rb', line 78 def cost @cost end |
#options ⇒ Hash (readonly)
Any additional options for this pattern.
72 73 74 |
# File 'lib/rdf/query/pattern.rb', line 72 def @options end |
Class Method Details
.from(pattern, graph_name: nil, **options) ⇒ Object
8 9 10 11 12 13 14 15 16 17 |
# File 'lib/rdf/query/pattern.rb', line 8 def self.from(pattern, graph_name: nil, **) case pattern when Pattern then pattern when Array, Statement graph_name ||= pattern[3] self.new(pattern[0], pattern[1], pattern[2], graph_name: graph_name, **) when Hash then self.new(.merge(pattern)) else raise ArgumentError, "expected RDF::Query::Pattern, RDF::Statement, Hash, or Array, but got #{pattern.inspect}" end end |
Instance Method Details
#bind(solution) ⇒ self
Binds the pattern to a solution, making it no longer variable if all variables are resolved to bound variables
298 299 300 301 302 303 304 305 306 307 |
# File 'lib/rdf/query/pattern.rb', line 298 def bind(solution) self.to_quad.each_with_index do |term, index| if term.is_a?(Variable) && solution[term] self[index] = solution[term] elsif term.is_a?(Pattern) term.bind(solution) end end self end |
#binding_count ⇒ Integer
Returns the number of bindings in this pattern.
321 322 323 |
# File 'lib/rdf/query/pattern.rb', line 321 def binding_count bindings.size end |
#bindings ⇒ Hash{Symbol => RDF::Term}
Returns all bindings in this pattern.
329 330 331 332 333 334 335 336 |
# File 'lib/rdf/query/pattern.rb', line 329 def bindings bindings = {} bindings.merge!(subject.bindings) if subject && subject.variable? bindings.merge!(predicate.bindings) if predicate && predicate.variable? bindings.merge!(object.bindings) if object && object.variable? bindings.merge!(graph_name.bindings) if graph_name && graph_name.variable? bindings end |
#bindings? ⇒ Boolean
Returns ‘true` if this pattern contains bindings.
313 314 315 |
# File 'lib/rdf/query/pattern.rb', line 313 def bindings? !bindings.empty? end |
#blank? ⇒ Boolean
Returns ‘true` if this is a blank pattern, with all terms being `nil`.
85 86 87 |
# File 'lib/rdf/query/pattern.rb', line 85 def blank? subject.nil? && predicate.nil? && object.nil? && graph_name.nil? end |
#bound? ⇒ Boolean
Returns ‘true` if all variables in this pattern are bound.
342 343 344 |
# File 'lib/rdf/query/pattern.rb', line 342 def bound? !variables.empty? && variables.values.all?(&:bound?) end |
#bound_variables ⇒ Hash{Symbol => Variable}
Returns all bound variables in this pattern.
350 351 352 |
# File 'lib/rdf/query/pattern.rb', line 350 def bound_variables variables.reject { |name, variable| variable.unbound? } end |
#dup ⇒ Object
Create a new pattern from the quads, recursivly dupping sub-patterns.
64 65 66 |
# File 'lib/rdf/query/pattern.rb', line 64 def dup self.class.from(self.to_quad.map {|t| t.is_a?(RDF::Query::Pattern) ? t.dup : t}) end |
#eql?(other) ⇒ Boolean
Checks pattern equality against a statement, considering nesting.
-
A pattern which has a pattern as a subject or an object, matches a statement having a statement as a subject or an object using #eql?.
141 142 143 144 145 146 147 |
# File 'lib/rdf/query/pattern.rb', line 141 def eql?(other) return false unless other.is_a?(Statement) && (self.graph_name || false) == (other.graph_name || false) predicate == other.predicate && (subject.is_a?(Pattern) ? subject.eql?(other.subject) : subject == other.subject) && (object.is_a?(Pattern) ? object.eql?(other.object) : object == other.object) end |
#execute(queryable, bindings = {}) {|statement| ... } ⇒ Enumerable<RDF::Query::Pattern>
Executes this query pattern on the given ‘queryable` object.
Values are matched using using Queryable#query_pattern.
If the optional ‘bindings` are given, variables will be substituted with their values when executing the query.
To match triples only in the default graph, set graph_name to ‘false`.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/rdf/query/pattern.rb', line 173 def execute(queryable, bindings = {}, &block) bindings = bindings.to_h if bindings.is_a?(Solution) query = { subject: subject.is_a?(Variable) && bindings[subject.to_sym] ? bindings[subject.to_sym] : subject, predicate: predicate.is_a?(Variable) && bindings[predicate.to_sym] ? bindings[predicate.to_sym] : predicate, object: object.is_a?(Variable) && bindings[object.to_sym] ? bindings[object.to_sym] : object, graph_name: graph_name.is_a?(Variable) && bindings[graph_name.to_sym] ? bindings[graph_name.to_sym] : graph_name, }.delete_if{|k,v| v.nil?} # Do all the variable terms refer to distinct variables? variables = self.variables if variable_count == variables.size # If so, we can just let the repository implementation handle # everything and yield matching statements directly: queryable.query(query, &block) # No, some terms actually refer to the same variable... else # Considering embedding, figure out if variables that may appear more than once resolve to the same value. vars = variables.keys queryable.query(query).select do |statement| if vars.all? {|var| self.var_values(var, statement).uniq.size == 1} yield statement if block_given? true end end end end |
#initialize! ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/rdf/query/pattern.rb', line 45 def initialize! @graph_name = Variable.new(@graph_name) if @graph_name.is_a?(Symbol) @subject = Variable.new(@subject) if @subject.is_a?(Symbol) @predicate = Variable.new(@predicate) if @predicate.is_a?(Symbol) @object = Variable.new(@object) if @object.is_a?(Symbol) # Estmate cost positionally, with variables being least expensive as objects, then predicates, then subjects, then graph_names. # XXX does not consider bound variables, which would need to be dynamically calculated. @cost = (@object.nil? || @object.is_a?(Variable) ? 8 : 0) + (@predicate.nil? || @predicate.is_a?(Variable) ? 4 : 0) + (@subject.nil? || @subject.is_a?(Variable) ? 2 : 0) + (@graph_name.is_a?(Variable) ? 1 : 0) + (@object.is_a?(Pattern) ? (@object.cost * 4) : 0) + (@subject.is_a?(Pattern) ? (@subject.cost * 2) : 0) super end |
#optional? ⇒ Boolean
Returns ‘true` if this is an optional pattern.
111 112 113 |
# File 'lib/rdf/query/pattern.rb', line 111 def optional? !![:optional] end |
#solution(statement) ⇒ RDF::Query::Solution
Returns a query solution constructed by binding any variables in this pattern with the corresponding terms in the given ‘statement`.
218 219 220 221 222 223 224 225 226 227 |
# File 'lib/rdf/query/pattern.rb', line 218 def solution(statement) RDF::Query::Solution.new do |solution| solution[subject.to_sym] = statement.subject if subject.is_a?(Variable) solution[predicate.to_sym] = statement.predicate if predicate.is_a?(Variable) solution[object.to_sym] = statement.object if object.is_a?(Variable) solution[graph_name.to_sym] = statement.graph_name if graph_name.is_a?(Variable) solution.merge!(subject.solution(statement.subject)) if subject.respond_to?(:solution) solution.merge!(object.solution(statement.object)) if object.respond_to?(:solution) end end |
#to_s ⇒ String
Returns a string representation of this pattern.
374 375 376 |
# File 'lib/rdf/query/pattern.rb', line 374 def to_s (optional? ? 'OPTIONAL ' : '') + super end |
#unbound? ⇒ Boolean
Returns ‘true` if all variables in this pattern are unbound.
358 359 360 |
# File 'lib/rdf/query/pattern.rb', line 358 def unbound? !variables.empty? && variables.values.all?(&:unbound?) end |
#unbound_variables ⇒ Hash{Symbol => Variable}
Returns all unbound variables in this pattern.
366 367 368 |
# File 'lib/rdf/query/pattern.rb', line 366 def unbound_variables variables.reject { |name, variable| variable.bound? } end |
#valid? ⇒ Boolean
Is this pattern composed only of valid components?
119 120 121 122 123 124 125 126 |
# File 'lib/rdf/query/pattern.rb', line 119 def valid? (subject? ? (subject.resource? || subject.variable?) && subject.valid? : true) && (predicate? ? (predicate.uri? || predicate.variable?) && predicate.valid? : true) && (object? ? (object.term? || object.variable?) && object.valid? : true) && (graph? ? (graph_name.resource? || graph_name.variable?) && graph_name.valid? : true) rescue NoMethodError false end |
#var_values(var, statement) ⇒ Array<RDF::Term>
Returns all values the statement in the same pattern position
257 258 259 260 261 262 263 |
# File 'lib/rdf/query/pattern.rb', line 257 def var_values(var, statement) %i(subject predicate object graph_name).map do |position| po = self.send(position) so = statement.send(position) po.var_values(var, so) if po.respond_to?(:var_values) end.flatten.compact end |
#variable_count ⇒ Integer Also known as: cardinality, arity
Returns the number of variables in this pattern.
Note: this does not count distinct variables, and will therefore e.g. return 3 even if two terms are actually the same variable.
272 273 274 275 276 277 |
# File 'lib/rdf/query/pattern.rb', line 272 def variable_count [subject, predicate, object, graph_name].inject(0) do |memo, term| memo += (term.is_a?(Variable) ? 1 : (term.respond_to?(:variable_count) ? term.variable_count : 0)) end end |
#variable_terms(name = nil) ⇒ Array<Symbol>
use #var_values instead
Returns the variable terms in this pattern.
240 241 242 243 244 245 246 247 248 249 |
# File 'lib/rdf/query/pattern.rb', line 240 def variable_terms(name = nil) warn "[DEPRECATION] RDF::Query::Pattern#variable_terms is deprecated and will be removed in a future version.\n" + "Called from #{Gem.location_of_caller.join(':')}" terms = [] terms << :subject if subject.is_a?(Variable) && (!name || name.eql?(subject.name)) terms << :predicate if predicate.is_a?(Variable) && (!name || name.eql?(predicate.name)) terms << :object if object.is_a?(Variable) && (!name || name.eql?(object.name)) terms << :graph_name if graph_name.is_a?(Variable) && (!name || name.eql?(graph_name.name)) terms end |
#variables ⇒ Hash{Symbol => Variable}
Returns all variables in this pattern.
Note: this returns a hash containing distinct variables only.
287 288 289 290 291 |
# File 'lib/rdf/query/pattern.rb', line 287 def variables [subject, predicate, object, graph_name].inject({}) do |memo, term| term && term.variable? ? memo.merge(term.variables) : memo end end |
#variables? ⇒ Boolean Also known as: has_variables?
Returns ‘true` if this pattern contains any variables.
94 95 96 97 98 99 |
# File 'lib/rdf/query/pattern.rb', line 94 def variables? subject && subject.variable? || predicate && predicate.variable? || object && object.variable? || graph_name && graph_name.variable? end |