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
trueif this pattern contains bindings. -
#blank? ⇒ Boolean
Returns
trueif this is a blank pattern, with all terms beingnil. -
#bound? ⇒ Boolean
Returns
trueif all variables in this pattern are bound. -
#bound_variables ⇒ Hash{Symbol => Variable}
Returns all bound variables in this pattern.
-
#execute(queryable, bindings = {}) {|statement| ... } ⇒ Enumerable<RDF::Query::Pattern>
Executes this query pattern on the given
queryableobject. -
#has_variables? ⇒ Boolean
(also: #variables?)
Returns
trueif this pattern contains any variables. -
#initialize(subject = nil, predicate = nil, object = nil, options = {}) ⇒ Pattern
constructor
A new instance of Pattern.
- #initialize! ⇒ Object
-
#optional? ⇒ Boolean
Returns
trueif 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
trueif 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?.
-
#variable_count ⇒ Integer
(also: #cardinality, #arity)
Returns the number of variables in this pattern.
-
#variable_terms(name = nil) ⇒ Array<Symbol>
Returns the variable terms in this pattern.
-
#variables ⇒ Hash{Symbol => Variable}
Returns all variables in this pattern.
Methods inherited from Statement
#==, #===, #[], #[]=, #asserted?, #canonicalize, #canonicalize!, #complete?, #eql?, #has_graph?, #has_object?, #has_predicate?, #has_subject?, #hash, #incomplete?, #inferred?, #invalid?, #node?, #quoted?, #reified, #statement?, #to_h, #to_quad, #to_triple, #variable?
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).
70 71 72 |
# File 'lib/rdf/query/pattern.rb', line 70 def cost @cost end |
#options ⇒ Hash (readonly)
Any additional options for this pattern.
64 65 66 |
# File 'lib/rdf/query/pattern.rb', line 64 def 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
255 256 257 258 259 260 261 262 |
# File 'lib/rdf/query/pattern.rb', line 255 def bind(solution) self.to_quad.each_with_index do |term, index| if term && term.variable? && solution[term] self[index] = solution[term] end end self end |
#binding_count ⇒ Integer
Returns the number of bindings in this pattern.
276 277 278 |
# File 'lib/rdf/query/pattern.rb', line 276 def binding_count bindings.size end |
#bindings ⇒ Hash{Symbol => RDF::Term}
Returns all bindings in this pattern.
284 285 286 287 288 289 290 291 |
# File 'lib/rdf/query/pattern.rb', line 284 def bindings bindings = {} bindings.merge!(subject.bindings) if subject.is_a?(Variable) bindings.merge!(predicate.bindings) if predicate.is_a?(Variable) bindings.merge!(object.bindings) if object.is_a?(Variable) bindings.merge!(graph_name.bindings) if graph_name.is_a?(Variable) bindings end |
#bindings? ⇒ Boolean
Returns true if this pattern contains bindings.
268 269 270 |
# File 'lib/rdf/query/pattern.rb', line 268 def bindings? !bindings.empty? end |
#blank? ⇒ Boolean
Returns true if this is a blank pattern, with all terms being nil.
77 78 79 |
# File 'lib/rdf/query/pattern.rb', line 77 def blank? subject.nil? && predicate.nil? && object.nil? && graph_name.nil? end |
#bound? ⇒ Boolean
Returns true if all variables in this pattern are bound.
297 298 299 |
# File 'lib/rdf/query/pattern.rb', line 297 def bound? !variables.empty? && variables.values.all?(&:bound?) end |
#bound_variables ⇒ Hash{Symbol => Variable}
Returns all bound variables in this pattern.
305 306 307 |
# File 'lib/rdf/query/pattern.rb', line 305 def bound_variables variables.reject { |name, variable| variable.unbound? } 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.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/rdf/query/pattern.rb', line 145 def execute(queryable, bindings = {}, &block) 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 # Figure out which terms refer to the same variable: terms = variables.each_key.find do |name| terms = variable_terms(name) break terms if terms.size > 1 end queryable.query(query).select do |statement| # Only yield those matching statements where the variable # constraint is also satisfied: # FIXME: `Array#uniq` uses `#eql?` and `#hash`, not `#==` if terms.map { |term| statement.send(term) }.uniq.size.equal?(1) yield statement if block_given? true end end end end |
#has_variables? ⇒ Boolean Also known as: variables?
Returns true if this pattern contains any variables.
86 87 88 89 90 91 |
# File 'lib/rdf/query/pattern.rb', line 86 def has_variables? subject.is_a?(Variable) || predicate.is_a?(Variable) || object.is_a?(Variable) || graph_name.is_a?(Variable) end |
#initialize! ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# 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) ? 1 : 0) + (@predicate.nil? || @predicate.is_a?(Variable) ? 2 : 0) + (@subject.nil? || @subject.is_a?(Variable) ? 4 : 0) + (@graph_name.is_a?(Variable) ? 8 : 0) super end |
#optional? ⇒ Boolean
Returns true if this is an optional pattern.
103 104 105 |
# File 'lib/rdf/query/pattern.rb', line 103 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.
195 196 197 198 199 200 201 202 |
# File 'lib/rdf/query/pattern.rb', line 195 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) end end |
#to_s ⇒ String
Returns a string representation of this pattern.
329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
# File 'lib/rdf/query/pattern.rb', line 329 def to_s StringIO.open do |buffer| # FIXME in RDF::Statement buffer << 'OPTIONAL ' if optional? buffer << [subject, predicate, object].map do |r| r.is_a?(RDF::Query::Variable) ? r.to_s : RDF::NTriples.serialize(r) end.join(" ") buffer << case graph_name when nil, false then " ." when Variable then " #{graph_name.to_s} ." else " #{RDF::NTriples.serialize(graph_name)} ." end buffer.string end end |
#unbound? ⇒ Boolean
Returns true if all variables in this pattern are unbound.
313 314 315 |
# File 'lib/rdf/query/pattern.rb', line 313 def unbound? !variables.empty? && variables.values.all?(&:unbound?) end |
#unbound_variables ⇒ Hash{Symbol => Variable}
Returns all unbound variables in this pattern.
321 322 323 |
# File 'lib/rdf/query/pattern.rb', line 321 def unbound_variables variables.reject { |name, variable| variable.bound? } end |
#valid? ⇒ Boolean
Is this pattern composed only of valid components?
111 112 113 114 115 116 117 118 |
# File 'lib/rdf/query/pattern.rb', line 111 def valid? (has_subject? ? (subject.resource? || subject.variable?) && subject.valid? : true) && (has_predicate? ? (predicate.uri? || predicate.variable?) && predicate.valid? : true) && (has_object? ? (object.term? || object.variable?) && object.valid? : true) && (has_graph? ? (graph_name.resource? || graph_name.variable?) && graph_name.valid? : true) rescue NoMethodError false 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.
230 231 232 233 234 |
# File 'lib/rdf/query/pattern.rb', line 230 def variable_count [subject, predicate, object, graph_name].inject(0) do |memo, term| memo += (term.is_a?(Variable) ? 1 : 0) end end |
#variable_terms(name = nil) ⇒ Array<Symbol>
Returns the variable terms in this pattern.
214 215 216 217 218 219 220 221 |
# File 'lib/rdf/query/pattern.rb', line 214 def variable_terms(name = nil) 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.
244 245 246 247 248 |
# File 'lib/rdf/query/pattern.rb', line 244 def variables [subject, predicate, object, graph_name].inject({}) do |memo, term| term.is_a?(Variable) ? memo.merge(term.variables) : memo end end |