class ROM::Relation

Enhanced ROM relation wrapping axiom relation and using injected mapper to load/dump tuples/objects

@example

# set up an axiom relation
header = [[:id, Integer], [:name, String]]
data   = [[1, 'John'], [2, 'Jane']]
axiom  = Axiom::Relation.new(header, data)

# provide a simple mapper
class Mapper < Struct.new(:header)
  def load(tuple)
    data = header.map { |attribute|
      [attribute.name, tuple[attribute.name]]
    }
    Hash[data]
  end

  def dump(hash)
    header.each_with_object([]) { |attribute, tuple|
      tuple << hash[attribute.name]
    }
  end
end

# wrap axiom relation with ROM relation
mapper   = Mapper.new(axiom.header)
relation = ROM::Relation.new(axiom, mapper)

# relation is an enumerable and it uses mapper to load/dump tuples/objects
relation.to_a
# => [{:id=>1, :name=>'John'}, {:id=>2, :name=>'Jane'}]

# you can insert/update/delete objects
relation.insert(id: 3, name: 'Piotr').to_a
# => [{:id=>1, :name=>"John"}, {:id=>2, :name=>"Jane"}, {:id=>3, :name=>"Piotr"}]

relation.delete(id: 1, name: 'John').to_a
# => [{:id=>2, :name=>"Jane"}]

Constants

VERSION

Public Class Methods

build(relation, mapper) click to toggle source

Build a new relation

@param [Axiom::Relation] @param [Object] mapper

@return [Relation]

@api public

# File lib/rom/relation.rb, line 57
def self.build(relation, mapper)
  new(mapper.call(relation).optimize, mapper)
end

Public Instance Methods

<<(object)
Alias for: insert
delete(object) click to toggle source

Delete an object from the relation

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.delete(id: 1)
relation.to_a # => [[2]]

@param [Object]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 144
def delete(object)
  new(relation.delete([mapper.dump(object)]))
end
drop(offset) click to toggle source

Drop objects from the relation by the given offset

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.drop(1).to_a # => [[2]]

@param [Integer]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 249
def drop(offset)
  new(sorted.drop(offset))
end
each() { |load| ... } click to toggle source

Iterate over tuples yielded by the wrapped relation

@example

mapper = Class.new {
  def load(value)
    value.to_s
  end

  def dump(value)
    value.to_i
  end
}.new

relation = ROM::Relation.new([1, 2, 3], mapper)

relation.each do |value|
  puts value # => '1'
end

@yieldparam [Object]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 85
def each
  return to_enum unless block_given?
  relation.each { |tuple| yield(mapper.load(tuple)) }
  self
end
first(limit = 1) click to toggle source

Take first n-objects from the relation

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.first.to_a # => [[1]]
relation.first(2).to_a # => [[1], [2]]

@param [Integer]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 214
def first(limit = 1)
  new(sorted.first(limit))
end
inject_mapper(mapper) click to toggle source

Inject a new mapper into this relation

@example

relation = ROM::Relation.new([], mapper)
relation.inject_mapper(new_mapper)

@param [Object] a mapper object

@return [Relation]

@api public

# File lib/rom/relation.rb, line 313
def inject_mapper(mapper)
  new(relation, mapper)
end
insert(object) click to toggle source

Insert an object into relation

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.insert(id: 3)
relation.to_a # => [[1], [2], [3]]

@param [Object]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 105
def insert(object)
  new(relation.insert([mapper.dump(object)]))
end
Also aliased as: <<
last(limit = 1) click to toggle source

Take last n-objects from the relation

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.last.to_a # => [[2]]
relation.last(2).to_a # => [[1], [2]]

@param [Integer] limit

@return [Relation]

@api public

# File lib/rom/relation.rb, line 232
def last(limit = 1)
  new(sorted.last(limit))
end
one(&block) click to toggle source

Return exactly one object matching criteria or raise an error

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [1]])
relation = ROM::Relation.new(axiom, mapper)

relation.one.to_a # => {id: 1}

@param [Proc] block

optional block to call in case no tuple is returned

@return [Object]

@raise NoTuplesError

if no tuples were returned

@raise ManyTuplesError

if more than one tuple was returned

@api public

# File lib/rom/relation.rb, line 290
def one(&block)
  block  ||= ->() { raise NoTuplesError }
  tuples   = take(2).to_a

  if tuples.count > 1
    raise ManyTuplesError
  else
    tuples.first || block.call
  end
end
replace(objects) click to toggle source

Replace all objects in the relation with new ones

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.replace([{id: 3}, {id: 4}])
relation.to_a # => [[3], [4]]

@param [Array<Object>]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 162
def replace(objects)
  new(relation.replace(objects.map(&mapper.method(:dump))))
end
restrict(*args, &block) click to toggle source

Restrict the relation

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.restrict(id: 2).to_a # => [[2]]

@param [Hash] conditions

@return [Relation]

@api public

# File lib/rom/relation.rb, line 179
def restrict(*args, &block)
  new(relation.restrict(*args, &block))
end
sort_by(*args, &block) click to toggle source

Sort the relation by provided attributes

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[2], [1]])
relation = ROM::Relation.new(axiom, mapper)

relation.sort_by(:id).to_a # => [[1], [2]]

@param [Array<Symbol>]

@return [Relation]

@api public

# File lib/rom/relation.rb, line 266
def sort_by(*args, &block)
  new(relation.sort_by(*args, &block))
end
take(limit) click to toggle source

Take objects form the relation with provided limit

@example

axiom    = Axiom::Relation.new([[:id, Integer]], [[1], [2]])
relation = ROM::Relation.new(axiom, mapper)

relation.take(2).to_a # => [[2]]

@param [Integer] limit

@return [Relation]

@api public

# File lib/rom/relation.rb, line 196
def take(limit)
  new(sorted.take(limit))
end
update(object, original_tuple) click to toggle source

Update an object

@example

data     = [[1, 'John'], [2, 'Jane']]
axiom    = Axiom::Relation.new([[:id, Integer], [:name, String]], data)
relation = ROM::Relation.new(axiom, mapper)

relation.update({id: 2, name: 'Jane Doe'}, {id:2, name: 'Jane'})
relation.to_a # => [[1, 'John'], [2, 'Jane Doe']]

@param [Object] @param [Hash] original attributes

@return [Relation]

@api public

# File lib/rom/relation.rb, line 126
def update(object, original_tuple)
  new(relation.delete([original_tuple]).insert([mapper.dump(object)]))
end

Private Instance Methods

new(new_relation, new_mapper = mapper) click to toggle source

Return new relation instance

@return [Relation]

@api private

# File lib/rom/relation.rb, line 333
def new(new_relation, new_mapper = mapper)
  self.class.new(new_relation, new_mapper)
end
sorted() click to toggle source

Sort wrapped relation using all attributes in the header

@return [Axiom::Relation]

@api private

# File lib/rom/relation.rb, line 324
def sorted
  relation.sort
end