Module: RDF::Queryable
- Includes:
- Enumerable
- Included in:
- Dataset, Enumerable::Enumerator, Graph, MergeGraph, Enumerator, Transaction
- Defined in:
- vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb,
vendor/bundler/ruby/3.3.0/bundler/gems/rdf-reasoner-e77a80426b61/lib/rdf/reasoner/extensions.rb,
vendor/bundler/ruby/3.3.0/bundler/gems/sparql-796d3be4aa08/lib/sparql/extensions.rb,
vendor/bundler/ruby/3.3.0/bundler/gems/sparql-796d3be4aa08/lib/sparql/algebra/extensions.rb
Overview
Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern
Defined Under Namespace
Classes: Enumerator
Instance Method Summary collapse
-
#concise_bounded_description(*terms, **options, &block) ⇒ RDF::Graph
Concise Bounded Description.
-
#first(pattern = nil) ⇒ RDF::Statement
Queries
self
for an RDF statement matching the givenpattern
and returns that statement if found. -
#first_literal(pattern = nil) ⇒ RDF::Literal
Queries
self
for RDF statements matching the givenpattern
and returns the first found object literal. -
#first_object(pattern = nil) ⇒ Object
Queries
self
for an RDF statement matching the givenpattern
and returns the statement's object term. -
#first_predicate(pattern = nil) ⇒ Object
Queries
self
for an RDF statement matching the givenpattern
and returns the statement's predicate term. -
#first_subject(pattern = nil) ⇒ Object
Queries
self
for an RDF statement matching the givenpattern
and returns the statement's subject term. -
#first_value(pattern = nil) ⇒ Object
Queries
self
for RDF statements matching the givenpattern
and returns the value of the first found object literal. -
#lint ⇒ Hash{Symbol => Hash{Symbol => Array<String>}}
Lint a queryable, presuming that it has already had RDFS entailment expansion.
-
#query(pattern, **options) {|statement| ... } ⇒ Enumerator
Queries
self
for RDF statements matching the givenpattern
. -
#query_execute(query, **options) {|solution| ... }
protected
Queries
self
using the given basic graph pattern (BGP) query, yielding each matched solution to the given block. -
#query_pattern(pattern, **options) {|statement| ... }
protected
Queries
self
for RDF statements matching the givenpattern
, yielding each matched statement to the given block. -
#query_without_sparql {|statement| ... } ⇒ Enumerator<RDF::Statement>, ...
Queries
self
for RDF statements matching the givenpattern
. -
#to_sparql(**options) ⇒ String
Returns a partial SPARQL grammar for this term.
Instance Method Details
#concise_bounded_description(*terms, **options, &block) ⇒ RDF::Graph
Concise Bounded Description
Given a particular node (the starting node) in a particular RDF graph (the source graph), a subgraph of that particular graph, taken to comprise a concise bounded description of the resource denoted by the starting node, can be identified as follows:
- Include in the subgraph all statements in the source graph where the subject of the statement is the starting node;
- Recursively, for all statements identified in the subgraph thus far having a blank node object, include in the subgraph all statements in the source graph where the subject of the statement is the blank node in question and which are not already included in the subgraph.
- Recursively, for all statements included in the subgraph thus far, for all reifications of each statement in the source graph, include the concise bounded description beginning from the rdf:Statement node of each reification. (we skip this step)
This results in a subgraph where the object nodes are either URI references, literals, or blank nodes not serving as the subject of any statement in the graph.
Used to implement the SPARQL DESCRIBE
operator.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/sparql-796d3be4aa08/lib/sparql/extensions.rb', line 43 def concise_bounded_description(*terms, **, &block) graph = [:graph] || RDF::Graph.new if [:non_subjects] query_terms = terms.dup # Find terms not in self as a subject and recurse with their subjects terms.reject {|term| self.first({subject: term})}.each do |term| self.query({predicate: term}) do |statement| query_terms << statement.subject end self.query({object: term}) do |statement| query_terms << statement.subject end end terms = query_terms.uniq end # Don't consider term if already in graph terms.reject {|term| graph.first({subject: term})}.each do |term| # Find statements from queryiable with term as a subject self.query({subject: term}) do |statement| yield(statement) if block_given? graph << statement # Include reifications of this statement RDF::Query.new({ s: { RDF.type => RDF["Statement"], RDF.subject => statement.subject, RDF.predicate => statement.predicate, RDF.object => statement.object, } }, **{}).execute(self).each do |solution| # Recurse to include this subject recurse_opts = .merge(non_subjects: false, graph: graph) self.concise_bounded_description(solution[:s], **recurse_opts, &block) end # Recurse if object is a BNode and it is not already in subjects if statement.object.node? recurse_opts = .merge(non_subjects: false, graph: graph) self.concise_bounded_description(statement.object, **recurse_opts, &block) end end end graph end |
#first ⇒ RDF::Statement #first(pattern) ⇒ RDF::Statement
Queries self
for an RDF statement matching the given pattern
and
returns that statement if found.
Returns nil
if no statements match pattern
.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 188 def first(pattern = nil) if pattern query(pattern) do |statement| return statement end elsif respond_to?(:each_statement) each_statement do |statement| return statement end else return super() end nil end |
#first_literal ⇒ RDF::Literal #first_literal(pattern) ⇒ RDF::Literal
Queries self
for RDF statements matching the given pattern
and
returns the first found object literal.
Returns nil
if no statements match pattern
or if none of the found
statements have a literal as their object term.
279 280 281 282 283 284 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 279 def first_literal(pattern = nil) __send__(*(pattern ? [:query, pattern] : [:each])) do |statement| return statement.object if statement.object.is_a?(RDF::Literal) end return nil end |
#first_object ⇒ RDF::Term #first_object(pattern) ⇒ RDF::Term
Queries self
for an RDF statement matching the given pattern
and
returns the statement's object term.
Returns nil
if no statements match pattern
.
256 257 258 259 260 261 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 256 def first_object(pattern = nil) __send__(*(pattern ? [:query, pattern] : [:each])) do |statement| return statement.object end return nil end |
#first_predicate ⇒ RDF::URI #first_predicate(pattern) ⇒ RDF::URI
Queries self
for an RDF statement matching the given pattern
and
returns the statement's predicate term.
Returns nil
if no statements match pattern
.
236 237 238 239 240 241 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 236 def first_predicate(pattern = nil) __send__(*(pattern ? [:query, pattern] : [:each])) do |statement| return statement.predicate end return nil end |
#first_subject ⇒ RDF::Resource #first_subject(pattern) ⇒ RDF::Resource
Queries self
for an RDF statement matching the given pattern
and
returns the statement's subject term.
Returns nil
if no statements match pattern
.
216 217 218 219 220 221 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 216 def first_subject(pattern = nil) __send__(*(pattern ? [:query, pattern] : [:each])) do |statement| return statement.subject end return nil end |
#first_value ⇒ Object #first_value(pattern) ⇒ Object
Queries self
for RDF statements matching the given pattern
and
returns the value of the first found object literal.
Returns nil
if no statements match pattern
or if none of the found
statements have a literal as their object term.
300 301 302 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 300 def first_value(pattern = nil) (literal = first_literal(pattern)) ? literal.value : nil end |
#lint ⇒ Hash{Symbol => Hash{Symbol => Array<String>}}
Lint a queryable, presuming that it has already had RDFS entailment expansion.
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-reasoner-e77a80426b61/lib/rdf/reasoner/extensions.rb', line 232 def lint = {} # Check for defined classes in known vocabularies self.query({predicate: RDF.type}) do |stmt| vocab = RDF::Vocabulary.find(stmt.object) term = (RDF::Vocabulary.find_term(stmt.object) rescue nil) if vocab pname = term ? term.pname : stmt.object.pname # Must be a defined term, not in RDF or RDFS vocabularies if term && term.class? # Warn against using a deprecated term superseded = term.properties[:'http://schema.org/supersededBy'] superseded = superseded.pname if superseded.respond_to?(:pname) ([:class] ||= {})[pname] = ["Term is superseded by #{superseded}"] if superseded else ([:class] ||= {})[pname] = ["No class definition found"] unless vocab.nil? || [RDF::RDFV, RDF::RDFS].include?(vocab) end end # Check for defined predicates in known vocabularies and domain/range resource_types = {} self.each_statement do |stmt| vocab = RDF::Vocabulary.find(stmt.predicate) term = (RDF::Vocabulary.find_term(stmt.predicate) rescue nil) if vocab pname = term ? term.pname : stmt.predicate.pname # Must be a valid statement begin stmt.validate! rescue (([:statement] ||= {})[pname] ||= []) << "Triple #{stmt.to_ntriples} is invalid" end # Must be a defined property if term.respond_to?(:property?) && term.property? # Warn against using a deprecated term superseded = term.properties[:'http://schema.org/supersededBy'] superseded = superseded.pname if superseded.respond_to?(:pname) ([:property] ||= {})[pname] = ["Term is superseded by #{superseded}"] if superseded else (([:property] ||= {})[pname] ||= []) << "No property definition found" unless vocab.nil? next end # See if type of the subject is in the domain of this predicate resource_types[stmt.subject] ||= self.query({subject: stmt.subject, predicate: RDF.type}). map {|s| (t = (RDF::Vocabulary.find_term(s.object) rescue nil)) && t.entail(:subClassOf)}. flatten. uniq. compact unless term.domain_compatible?(stmt.subject, self, types: resource_types[stmt.subject]) (([:property] ||= {})[pname] ||= []) << if !term.domain.empty? "Subject #{show_resource(stmt.subject)} not compatible with domain (#{Array(term.domain).map {|d| d.pname|| d}.join(',')})" else domains = Array(term.domainIncludes) + Array(term.properties[:'https://schema.org/domainIncludes']) "Subject #{show_resource(stmt.subject)} not compatible with domainIncludes (#{domains.map {|d| d.pname|| d}.join(',')})" end end # Make sure that if ranges are defined, the object has an appropriate type resource_types[stmt.object] ||= self.query({subject: stmt.object, predicate: RDF.type}). map {|s| (t = (RDF::Vocabulary.find_term(s.object) rescue nil)) && t.entail(:subClassOf)}. flatten. uniq. compact if stmt.object.resource? unless term.range_compatible?(stmt.object, self, types: resource_types[stmt.object]) (([:property] ||= {})[pname] ||= []) << if !term.range.empty? "Object #{show_resource(stmt.object)} not compatible with range (#{Array(term.range).map {|d| d.pname|| d}.join(',')})" else ranges = Array(term.rangeIncludes) + Array(term.properties[:'https://schema.org/rangeIncludes']) "Object #{show_resource(stmt.object)} not compatible with rangeIncludes (#{ranges.map {|d| d.pname|| d}.join(',')})" end end end [:class].each {|k, v| [:class][k] = v.uniq} if [:class] [:property].each {|k, v| [:property][k] = v.uniq} if [:property] end |
#query(pattern, **options) {|statement| ... } ⇒ Enumerator
Queries self
for RDF statements matching the given pattern
.
Monkey patch to RDF::Queryable#query to execute a SPARQL::Algebra::Operator in addition to an RDF::Query object.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 56 def query(pattern, **, &block) raise TypeError, "#{self} is not readable" if respond_to?(:readable?) && !readable? case pattern # A basic graph pattern (BGP) query: when Query solutions = RDF::Query::Solutions.new block = lambda {|solution| solutions << solution} unless block_given? before_query(pattern) if respond_to?(:before_query) query_execute(pattern, **, &block) after_query(pattern) if respond_to?(:after_query) # Returns the solutions, not an enumerator solutions # A simple triple/quad pattern query: else pattern = Query::Pattern.from(pattern) before_query(pattern) if respond_to?(:before_query) enum = case # Blank triple/quad patterns are equivalent to iterating over # every statement, so as a minor optimization we'll just do that # directly instead of bothering with `#query_pattern`: when pattern.blank? if block_given? each(&block) else to_a.extend(Queryable) end # Constant triple/quad patterns are equivalent to looking up a # particular statement, so as a minor optimization we'll just do # that directly instead of bothering with `#query_pattern`: when pattern.constant? statement = Statement.from(pattern) if include?(statement) if block_given? yield statement else [statement] end end # Otherwise, we delegate to `#query_pattern`: else # pattern.variable? query_pattern(pattern, **, &block) end after_query(pattern) if respond_to?(:after_query) enum end end |
#query_execute(query, **options) {|solution| ... } (protected)
This method returns an undefined value.
Queries self
using the given basic graph pattern (BGP) query,
yielding each matched solution to the given block.
Since RDF.rb 0.3.0, repository implementations can override this method in order to provide for storage-specific optimized graph pattern query execution.
126 127 128 129 130 131 132 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 126 def query_execute(query, **, &block) # By default, we let RDF.rb's built-in `RDF::Query#execute` handle BGP # query execution by breaking down the query into its constituent # triple patterns and invoking `RDF::Query::Pattern#execute` on each # pattern. query.execute(self, **, &block) end |
#query_pattern(pattern, **options) {|statement| ... } (protected)
This method returns an undefined value.
Queries self
for RDF statements matching the given pattern
,
yielding each matched statement to the given block.
Since RDF.rb 0.2.0, repository implementations should override this method in order to provide for storage-specific optimized triple pattern matching.
RDF-star
Statements may have embedded statements as either a subject or object, recursively.
Patterns may also have embedded patterns as either a subject or object, recursively.
Patterns with a variable graph_name
do not match the default graph.
When matching, match an embedded pattern against embedded statements, recursively. (see RDF::Query::Pattern#eql?)
164 165 166 167 168 169 170 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/rdf-884e3ef78084/lib/rdf/mixin/queryable.rb', line 164 def query_pattern(pattern, **, &block) # By default, we let Ruby's built-in `Enumerable#grep` handle the # matching of statements by iterating over all statements and calling # `RDF::Query::Pattern#===` on each statement. # @see http://ruby-doc.org/core/classes/Enumerable.html#M003121 grep(pattern, &block) end |
#query_without_sparql {|statement| ... } ⇒ Enumerator<RDF::Statement>, ...
Since 2.0, this may return an Enumerable or an Enumerator in addition to Solutions
Queries self
for RDF statements matching the given pattern
.
This method delegates to the protected #query_pattern method for the actual lower-level query pattern matching implementation.
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/sparql-796d3be4aa08/lib/sparql/algebra/extensions.rb', line 299 def query(pattern, **, &block) raise TypeError, "#{self} is not readable" if respond_to?(:readable?) && !readable? case pattern # A basic graph pattern (BGP) query: when Query solutions = RDF::Query::Solutions.new block = lambda {|solution| solutions << solution} unless block_given? before_query(pattern) if respond_to?(:before_query) query_execute(pattern, **, &block) after_query(pattern) if respond_to?(:after_query) # Returns the solutions, not an enumerator solutions # A simple triple/quad pattern query: else pattern = Query::Pattern.from(pattern) before_query(pattern) if respond_to?(:before_query) enum = case # Blank triple/quad patterns are equivalent to iterating over # every statement, so as a minor optimization we'll just do that # directly instead of bothering with `#query_pattern`: when pattern.blank? if block_given? each(&block) else to_a.extend(Queryable) end # Constant triple/quad patterns are equivalent to looking up a # particular statement, so as a minor optimization we'll just do # that directly instead of bothering with `#query_pattern`: when pattern.constant? statement = Statement.from(pattern) if include?(statement) if block_given? yield statement else [statement] end end # Otherwise, we delegate to `#query_pattern`: else # pattern.variable? query_pattern(pattern, **, &block) end after_query(pattern) if respond_to?(:after_query) enum end end |
#to_sparql(**options) ⇒ String
Returns a partial SPARQL grammar for this term.
349 350 351 |
# File 'vendor/bundler/ruby/3.3.0/bundler/gems/sparql-796d3be4aa08/lib/sparql/algebra/extensions.rb', line 349 def to_sparql(**) raise NotImplementedError, "SPARQL::Algebra '#{first}' operator not implemented" end |