Class: ROM::Relation::Combined

Inherits:
Graph
  • Object
show all
Includes:
Commands
Defined in:
lib/rom/relation/combined.rb

Overview

Represents a relation graphs which combines root relation with other relation nodes

Constant Summary

Constants included from Memoizable

Memoizable::MEMOIZED_HASH

Instance Attribute Summary

Attributes inherited from Graph

#nodes, #root

Attributes included from Memoizable

#__memoized__

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Graph

#graph?, #map_to, #map_with, #mapper, #with_nodes

Methods included from Initializer

extended

Methods included from Pipeline::Proxy

#respond_to_missing?

Methods included from Pipeline

#map_with

Methods included from Pipeline::Operator

#>>

Methods included from Materializable

#each, #first, #one, #one!, #to_a

Methods included from Memoizable

included

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class ROM::Pipeline::Proxy

Class Method Details

.new(root, nodes) ⇒ Combined

Create a new relation combined with others

Parameters:

Returns:



21
22
23
24
# File 'lib/rom/relation/combined.rb', line 21

def self.new(root, nodes)
  root_ns = root.options[:struct_namespace]
  super(root, nodes.map { |node| node.struct_namespace(root_ns) })
end

Instance Method Details

#call(*args) ⇒ Loaded

Materialize combined relation

Returns:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rom/relation/combined.rb', line 53

def call(*args)
  left = root.with(auto_map: false, auto_struct: false).call(*args)

  right =
    if left.empty?
      nodes.map { |node| Loaded.new(node, EMPTY_ARRAY) }
    else
      nodes.map { |node| node.call(left) }
    end

  if auto_map?
    Loaded.new(self, mapper.([left, right]))
  else
    Loaded.new(self, [left, right])
  end
end

#combine(*args) ⇒ Combined

Combine with other relations

Returns:

See Also:



44
45
46
# File 'lib/rom/relation/combined.rb', line 44

def combine(*args)
  self.class.new(root, nodes + root.combine(*args).nodes)
end

#combine_with(*others) ⇒ Graph

Combine this graph with more nodes

Parameters:

  • others (Array<Relation>)

    A list of relations

Returns:



33
34
35
# File 'lib/rom/relation/combined.rb', line 33

def combine_with(*others)
  self.class.new(root, nodes + others)
end

#command(type, *args) ⇒ Object

Return a ‘:create` command that can insert data from a nested hash.

This is limited to ‘:create` commands only, because automatic restriction for `:update` commands would be quite complex. It’s possible that in the future support for ‘:update` commands will be added though.

Another limitation is that it can only work when you’re composing parent and its child(ren), which follows canonical hierarchy from your database, so that parents are created first, then their PKs are set as FKs in child tuples. It should be possible to make it work with both directions (parent => child or child => parent), and it would require converting input tuples based on how they depend on each other, which we could do in the future.

Expanding functionality of this method is planned for rom 5.0.

Raises:

  • NotImplementedError when type is not ‘:create`

See Also:

  • Relation#command


131
132
133
134
135
136
137
# File 'lib/rom/relation/combined.rb', line 131

def command(type, *args)
  if type == :create
    super
  else
    raise NotImplementedError, "#{self.class}#command doesn't work with #{type.inspect} command type yet"
  end
end

#node(name) {|relation| ... } ⇒ Relation

Return a new combined relation with adjusted node returned from a block

Examples:

with a node identifier

combine(:tasks).node(:tasks) { |tasks| tasks.prioritized }

with a nested path

combine(tasks: :tags).node(tasks: :tags) { |tags| tags.where(name: 'red') }

Parameters:

  • name (Symbol)

    The node relation name

Yield Parameters:

  • relation (Relation)

    The relation node

Yield Returns:

Returns:



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rom/relation/combined.rb', line 86

def node(name, &block)
  if name.is_a?(Symbol) && !nodes.map { |n| n.name.key }.include?(name)
    raise ArgumentError, "#{name.inspect} is not a valid aggregate node name"
  end

  new_nodes = nodes.map { |node|
    case name
    when Symbol
      name == node.name.key ? yield(node) : node
    when Hash
      other, *rest = name.flatten(1)
      if other == node.name.key
        nodes.detect { |n| n.name.key == other }.node(*rest, &block)
      else
        node
      end
    else
      node
    end
  }

  with_nodes(new_nodes)
end