Module: ROM::Repository::RelationProxy::Combine

Included in:
ROM::Repository::RelationProxy
Defined in:
lib/rom/repository/relation_proxy/combine.rb

Overview

Provides convenient methods for composing relations

Instance Method Summary collapse

Instance Method Details

#combine(*associations) ⇒ RelationProxy #combine(options) ⇒ RelationProxy

Combine with other relations

Overloads:

  • #combine(*associations) ⇒ RelationProxy

    Composes relations using configured associations

    Examples:

    users.combine(:tasks, :posts)

    Parameters:

    • *associations (Array<Symbol>)

      A list of association names

  • #combine(options) ⇒ RelationProxy

    Composes relations based on options

    Examples:

    # users have-many tasks (name and join-keys inferred, which needs associations in schema)
    users.combine(many: tasks)
    
    # users have-many tasks with custom name (join-keys inferred, which needs associations in schema)
    users.combine(many: { priority_tasks: tasks.priority })
    
    # users have-many tasks with custom view and join keys
    users.combine(many: { tasks: [tasks.for_users, id: :task_id] })
    
    # users has-one task
    users.combine(one: { task: tasks })

    Parameters:

    • options (Hash)

      Options for combine @option :many [Hash] Sets options for “has-many” type of association @option :one [Hash] Sets options for “has-one/belongs-to” type of association

Returns:



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rom/repository/relation_proxy/combine.rb', line 54

def combine(*args)
  options = args[0].is_a?(Hash) ? args[0] : args

  combine_opts = Hash.new { |h, k| h[k] = {} }

  options.each do |key, value|
    if key == :one || key == :many
      if value.is_a?(Hash)
        value.each do |name, spec|
          if spec.is_a?(Array)
            combine_opts[key][name] = spec
          else
            _, (curried, keys) = combine_opts_from_relations(spec).to_a[0]
            combine_opts[key][name] = [curried, keys]
          end
        end
      else
        _, (curried, keys) = combine_opts_from_relations(value).to_a[0]
        combine_opts[key][curried.combine_tuple_key(key)] = [curried, keys]
      end
    else
      if value.is_a?(Array)
        curried = combine_from_assoc(key, registry[key]).combine(*value)
        result, _, keys = combine_opts_for_assoc(key)
        combine_opts[result][key] = [curried, keys]
      else
        result, curried, keys = combine_opts_for_assoc(key, value)
        combine_opts[result][key] = [curried, keys]
      end
    end
  end

  nodes = combine_opts.flat_map do |type, relations|
    relations.map { |name, (relation, keys)|
      relation.combined(name, keys, type)
    }
  end

  __new__(relation.combine(*nodes))
end

#combine_children(options) ⇒ RelationProxy

Shortcut for combining with children which infers the join keys

Examples:

# users have-many tasks
users.combine_children(many: tasks)

# users have-many tasks with custom mapping (requires associations)
users.combine_children(many: { priority_tasks: tasks.priority })

Parameters:

  • options (Hash)

Returns:



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rom/repository/relation_proxy/combine.rb', line 153

def combine_children(options)
  combine_opts = {}

  options.each do |type, children|
    combine_opts[type] =
      case children
      when Hash
        children.each_with_object({}) { |(name, child), r|
          keys = combine_keys(relation, child, :children)
          curried = combine_from_assoc_with_fallback(name, child, keys)
          r[name] = [curried, keys]
        }
      when Array
        children.each_with_object({}) { |child, r|
          keys = combine_keys(relation, child, :children)
          tuple_key = child.combine_tuple_key(type)
          curried = combine_from_assoc_with_fallback(child.name, child, keys)
          r[tuple_key] = [curried, keys]
        }
      else
        keys = combine_keys(relation, children, :children)
        curried = combine_from_assoc_with_fallback(children.name, children, keys)
        tuple_key = children.combine_tuple_key(type)
        { tuple_key => [curried, keys] }
      end
  end

  combine(combine_opts)
end

#combine_parents(options) ⇒ RelationProxy

Shortcut for combining with parents which infers the join keys

Examples:

# tasks belong-to users
tasks.combine_parents(one: users)

# tasks belong-to users with custom user view
tasks.combine_parents(one: users.task_owners)

Parameters:

  • options (Hash)

    Combine options hash

Returns:



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/rom/repository/relation_proxy/combine.rb', line 109

def combine_parents(options)
  combine_opts = {}

  options.each do |type, parents|
    combine_opts[type] =
      case parents
      when Hash
        parents.each_with_object({}) { |(name, parent), r|
          keys = combine_keys(parent, relation, :parent)
          curried = combine_from_assoc_with_fallback(name, parent, keys)
          r[name] = [curried, keys]
        }
      when Array
        parents.each_with_object({}) { |parent, r|
          keys = combine_keys(parent, relation, :parent)
          tuple_key = parent.combine_tuple_key(type)
          curried = combine_from_assoc_with_fallback(parent.name, parent, keys)
          r[tuple_key] = [curried, keys]
        }
      else
        keys = combine_keys(parents, relation, :parent)
        tuple_key = parents.combine_tuple_key(type)
        curried = combine_from_assoc_with_fallback(parents.name, parents, keys)
        { tuple_key => [curried, keys] }
      end
  end

  combine(combine_opts)
end

#combined(name, keys, type) ⇒ RelationProxy

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a combine representation of a loading-proxy relation

This will carry meta info used to produce a correct AST from a relation so that correct mapper can be generated

Returns:



18
19
20
21
# File 'lib/rom/repository/relation_proxy/combine.rb', line 18

def combined(name, keys, type)
  meta = { keys: keys, combine_type: type, combine_name: name }
  with(name: name, meta: self.meta.merge(meta))
end