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

#==(other) ⇒ Object

Equals of solution

Since:

  • 0.3.0



315
316
317
# File 'lib/rdf/query/solutions.rb', line 315

def ==(other)
  super && (!other.respond_to?(:variable_names) || variable_names.eql?(other.variable_names))
end

#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



119
120
121
122
123
124
125
126
127
128
# File 'lib/rdf/query/solutions.rb', line 119

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



264
265
266
267
# File 'lib/rdf/query/solutions.rb', line 264

def distinct
  self.uniq!
  self
end

#dupRDF::Query::Solutions

Duplicates each solution.

Returns:

Since:

  • 0.3.0



133
134
135
# File 'lib/rdf/query/solutions.rb', line 133

def dup
  RDF::Query::Solutions.new(self.compact.map(&:dup))
end

#eql?(other) ⇒ Boolean

Equivalence of solution

Returns:

  • (Boolean)

Since:

  • 0.3.0



309
310
311
# File 'lib/rdf/query/solutions.rb', line 309

def eql?(other)
  super && (!other.respond_to?(:variable_names) || variable_names.eql?(other.variable_names))
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



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rdf/query/solutions.rb', line 160

def filter(criteria = {})
  @variable_names = nil
  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

#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



296
297
298
299
300
301
302
303
304
# File 'lib/rdf/query/solutions.rb', line 296

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

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

Merge solutions in other into a new solutions instance. Each solution in other is merged into those solutions in self that are compatible.

Parameters:

Returns:

Since:

  • 0.3.0



142
143
144
145
146
147
148
149
150
# File 'lib/rdf/query/solutions.rb', line 142

def merge(other)
  other ||= RDF::Query::Solutions()
  return other if self.empty?
  return self if other.empty?

  RDF::Query::Solutions(self.map do |s1|
    other.map { |s2| s2.merge(s1) if s2.compatible?(s1) }
  end.flatten.compact)
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



191
192
193
194
195
# File 'lib/rdf/query/solutions.rb', line 191

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



279
280
281
282
283
284
285
# File 'lib/rdf/query/solutions.rb', line 279

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



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/rdf/query/solutions.rb', line 213

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



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/rdf/query/solutions.rb', line 240

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

  # Make sure variable_names are ordered by projected variables
  projected_vars, vars = variables.map(&:to_sym), variable_names
  vars = variable_names

  # Maintain projected order, and add any non-projected variables
  @variable_names = (projected_vars & vars) + (vars - projected_vars)
  self
end

#variable?Boolean #variable?(variables) ⇒ Object Also known as: variables?, have_variables?

the given variables.

@param [Array] variables @return [Boolean]

Overloads:

  • #variable?Boolean

    Returns false.

    Returns:

    • (Boolean)
  • #variable?(variables) ⇒ Object

    Returns true if this solution sequence contains bindings for any of

See Also:

Since:

  • 0.3.0



102
103
104
105
106
107
108
109
# File 'lib/rdf/query/solutions.rb', line 102

def variable?(*args)
  case args.length
  when 0 then false
  when 1
    self.any? { |solution| solution.variables?(args.first) }
  else raise ArgumentError("wrong number of arguments (given #{args.length}, expected 0 or 1)")
  end
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
77
78
# File 'lib/rdf/query/solutions.rb', line 68

def variable_names
  @variable_names ||= begin
    variables = self.inject({}) do |result, solution|
      solution.each_name do |name|
        result[name] ||= true
      end
      result
    end
    variables.keys
  end
end

#variable_names=(vars) ⇒ Array<Symbol>

Sets variable names used in these solutions. If not set, the default is determined by the variables used in each solution.

Parameters:

Returns:

  • (Array<Symbol>)

Since:

  • 0.3.0



85
86
87
# File 'lib/rdf/query/solutions.rb', line 85

def variable_names=(vars)
  @variable_names = vars.map(&:to_sym)
end