class RDF::Query::Solutions
An RDF basic graph pattern (BGP) query solution sequence.
@example Filtering solutions using a hash
solutions.filter(author: RDF::URI("http://ar.to/#self")) solutions.filter(author: "Gregg Kellogg") solutions.filter(author: [RDF::URI("http://ar.to/#self"), "Gregg Kellogg"]) solutions.filter(updated: RDF::Literal(Date.today))
@example Filtering solutions using a block
solutions.filter { |solution| solution.author.literal? } solutions.filter { |solution| solution.title.to_s =~ /^SPARQL/ } solutions.filter { |solution| solution.price < 30.5 } solutions.filter { |solution| solution.bound?(:date) } solutions.filter { |solution| solution.age.datatype == RDF::XSD.integer } solutions.filter { |solution| solution.name.language == :es }
@example Reordering solutions based on a variable or proc
solutions.order_by(:updated) solutions.order_by(:updated, :created) solutions.order_by(:updated, lambda {|a, b| b <=> a})
@example Selecting/Projecting particular variables only
solutions.select(:title) solutions.select(:title, :description) solutions.project(:title)
@example Eliminating duplicate solutions
solutions.distinct
@example Limiting the number of solutions
solutions.offset(20).limit(10)
@example Counting the number of matching solutions
solutions.count solutions.count { |solution| solution.price < 30.5 }
@example Iterating over all found solutions
solutions.each { |solution| puts solution.inspect }
@since 0.3.0
Public Instance Methods
Returns hash of bindings from each solution. Each bound variable will have an array of bound values representing those from each solution, where a given solution will have just a single value for each bound variable @return [Hash{Symbol => Array<RDF::Term>}]
# File lib/rdf/query/solutions.rb, line 97 def bindings bindings = {} each do |solution| solution.each do |key, value| bindings[key] ||= [] bindings[key] << value end end bindings end
Returns the number of matching query solutions.
@overload count
@return [Integer]
@overload count { |solution| … }
@yield [solution] @yieldparam [RDF::Query::Solution] solution @yieldreturn [Boolean] @return [Integer]
@return [Integer]
# File lib/rdf/query/solutions.rb, line 59 def count(&block) super end
Ensures that the solutions in this solution sequence are unique.
@return [self]
# File lib/rdf/query/solutions.rb, line 212 def distinct self.uniq! self end
Filters this solution sequence by the given `criteria`.
@param [Hash{Symbol => Object}] criteria @yield [solution] @yieldparam [RDF::Query::Solution] solution @yieldreturn [Boolean] @return [self]
# File lib/rdf/query/solutions.rb, line 116 def filter(criteria = {}) if block_given? self.reject! do |solution| !yield(solution.is_a?(Solution) ? solution : Solution.new(solution)) end else self.reject! do |solution| solution = solution.is_a?(Solution) ? solution : Solution.new(solution) results = criteria.map do |name, value| case value when Array then value.any? {|v| solution[name] == v} when Regexp then solution[name].to_s.match(value) else solution[name] == value end end !results.all? end end self end
Returns `true` if this solution sequence contains bindings for any of the given `variables`.
@param [Array<Symbol, to_sym>] variables
an array of variables to check
@return [Boolean] `true` or `false` @see RDF::Query::Solution#has_variables? @see RDF::Query#execute
# File lib/rdf/query/solutions.rb, line 87 def have_variables?(variables) self.any? { |solution| solution.has_variables?(variables) } end
Limits the number of solutions in this solution sequence to a maximum of `length`.
@param [Integer, to_i] length
zero or a positive integer
@return [self] @raise [ArgumentError] if `length` is negative
# File lib/rdf/query/solutions.rb, line 244 def limit(length) length = length.to_i raise ArgumentError, "expected zero or a positive integer, got #{length}" if length < 0 case length when 0 then self.clear else self.slice!(length..-1) if length < self.size end self end
Difference between solution sets, from SPARQL 1.1.
The `minus` operation on solutions returns those solutions which either have no compatible solution in `other`, or the solution domains are disjoint.
@param [RDF::Query::Solutions] other @return [RDF::Query::Solutions] a new solution set @see www.w3.org/TR/2013/REC-sparql11-query-20130321/#defn_algMinus
# File lib/rdf/query/solutions.rb, line 146 def minus(other) self.dup.filter! do |soln| !other.any? {|soln2| soln.compatible?(soln2) && !soln.disjoint?(soln2)} end end
Limits this solution sequence to bindings starting from the `start` offset in the overall solution sequence.
@param [Integer, to_i] start
zero or a positive or negative integer
@return [self]
# File lib/rdf/query/solutions.rb, line 227 def offset(start) case start = start.to_i when 0 then nil else self.slice!(0...start) end self end
Reorders this solution sequence by the given `variables`.
Variables may be symbols or {Query::Variable} instances. A variable may also be a Procedure/Lambda, compatible with `::Enumerable#sort`. This takes two arguments (solutions) and returns -1, 0, or 1 equivalently to <=>.
If called with a block, variables are ignored, and the block is invoked with pairs of solutions. The block is expected to return -1, 0, or 1 equivalently to <=>.
@param [Array<Proc, Query::Variable, Symbol, to_sym>] variables @yield [solution] @yieldparam [RDF::Query::Solution] q @yieldparam [RDF::Query::Solution] b @yieldreturn [Integer] -1, 0, or 1 depending on value of comparator @return [self]
# File lib/rdf/query/solutions.rb, line 168 def order(*variables) if variables.empty? && !block_given? raise ArgumentError, "wrong number of arguments (0 for 1)" else self.sort! do |a, b| if block_given? yield((a.is_a?(Solution) ? a : Solution.new(a)), (b.is_a?(Solution) ? b : Solution.new(b))) else # Try each variable until a difference is found. variables.inject(nil) do |memo, v| memo || begin comp = v.is_a?(Proc) ? v.call(a, b) : (v = v.to_sym; a[v] <=> b[v]) comp == 0 ? false : comp end end || 0 end end end self end
Restricts this solution sequence to the given `variables` only.
@param [Array<Symbol, to_sym>] variables @return [self]
# File lib/rdf/query/solutions.rb, line 195 def project(*variables) if variables.empty? raise ArgumentError, "wrong number of arguments (0 for 1)" else variables.map!(&:to_sym) self.each do |solution| solution.bindings.delete_if { |k, v| !variables.include?(k.to_sym) } end end self end
Returns an array of the distinct variable names used in this solution sequence.
@return [Array<Symbol>]
# File lib/rdf/query/solutions.rb, line 68 def variable_names variables = self.inject({}) do |result, solution| solution.each_name do |name| result[name] ||= true end result end variables.keys end