Class: RDF::Query::Solutions

Inherits:
Array
  • Object
show all
Defined in:
lib/rdf/query/solutions.rb

Overview

An RDF basic graph pattern (BGP) query solution sequence.

Examples:

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))

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 }

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})

Selecting/Projecting particular variables only

solutions.select(:title)
solutions.select(:title, :description)
solutions.project(:title)

Eliminating duplicate solutions

solutions.distinct

Limiting the number of solutions

solutions.offset(20).limit(10)

Counting the number of matching solutions

solutions.count
solutions.count { |solution| solution.price < 30.5 }

Iterating over all found solutions

solutions.each { |solution| puts solution.inspect }

Since:

  • 0.3.0

Instance Method Summary collapse

Instance Method Details

#bindingsHash{Symbol => Array<RDF::Term>}

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

Returns:

Since:

  • 0.3.0



97
98
99
100
101
102
103
104
105
106
# 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

#countInteger #count({ |solution| ... }) {|solution| ... } ⇒ Integer

Returns the number of matching query solutions.

Overloads:

  • #countInteger

    Returns:

    • (Integer)
  • #count({ |solution| ... }) {|solution| ... } ⇒ Integer

    Yields:

    • (solution)

    Yield Parameters:

    Yield Returns:

    • (Boolean)

    Returns:

    • (Integer)

Returns:

  • (Integer)

Since:

  • 0.3.0



59
60
61
# File 'lib/rdf/query/solutions.rb', line 59

def count(&block)
  super
end

#distinctself Also known as: distinct!, reduced, reduced!

Ensures that the solutions in this solution sequence are unique.

Returns:

  • (self)

Since:

  • 0.3.0



212
213
214
215
# File 'lib/rdf/query/solutions.rb', line 212

def distinct
  self.uniq!
  self
end

#filter(criteria = {}) {|solution| ... } ⇒ self Also known as: filter!

Filters this solution sequence by the given ‘criteria`.

Parameters:

  • criteria (Hash{Symbol => Object}) (defaults to: {})

Yields:

  • (solution)

Yield Parameters:

Yield Returns:

  • (Boolean)

Returns:

  • (self)

Since:

  • 0.3.0



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 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

#have_variables?(variables) ⇒ Boolean Also known as: has_variables?

Returns ‘true` if this solution sequence contains bindings for any of the given `variables`.

Parameters:

  • variables (Array<Symbol, #to_sym>)

    an array of variables to check

Returns:

  • (Boolean)

    ‘true` or `false`

See Also:

Since:

  • 0.3.0



87
88
89
# File 'lib/rdf/query/solutions.rb', line 87

def have_variables?(variables)
  self.any? { |solution| solution.has_variables?(variables) }
end

#limit(length) ⇒ self Also known as: limit!

Limits the number of solutions in this solution sequence to a maximum of ‘length`.

Parameters:

  • length (Integer, #to_i)

    zero or a positive integer

Returns:

  • (self)

Raises:

  • (ArgumentError)

    if ‘length` is negative

Since:

  • 0.3.0



244
245
246
247
248
249
250
251
252
# 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

#minus(other) ⇒ RDF::Query::Solutions

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.

Parameters:

Returns:

See Also:

Since:

  • 0.3.0



146
147
148
149
150
# 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

#offset(start) ⇒ self Also known as: offset!

Limits this solution sequence to bindings starting from the ‘start` offset in the overall solution sequence.

Parameters:

  • start (Integer, #to_i)

    zero or a positive or negative integer

Returns:

  • (self)

Since:

  • 0.3.0



227
228
229
230
231
232
233
# 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

#order(*variables) {|solution| ... } ⇒ self Also known as: order_by

Reorders this solution sequence by the given ‘variables`.

Variables may be symbols or 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 <=>.

Parameters:

Yields:

  • (solution)

Yield Parameters:

Yield Returns:

  • (Integer)

    -1, 0, or 1 depending on value of comparator

Returns:

  • (self)

Since:

  • 0.3.0



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# 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

#project(*variables) ⇒ self Also known as: select

Restricts this solution sequence to the given ‘variables` only.

Parameters:

  • variables (Array<Symbol, #to_sym>)

Returns:

  • (self)

Since:

  • 0.3.0



195
196
197
198
199
200
201
202
203
204
205
# 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

#variable_namesArray<Symbol>

Returns an array of the distinct variable names used in this solution sequence.

Returns:

  • (Array<Symbol>)

Since:

  • 0.3.0



68
69
70
71
72
73
74
75
76
# 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