Class: ROM::Repository::RelationProxy

Inherits:
Object
  • Object
show all
Extended by:
Initializer
Includes:
Combine, Wrap, Relation::Materializable
Defined in:
lib/rom/repository/relation_proxy.rb,
lib/rom/repository/relation_proxy/wrap.rb,
lib/rom/repository/relation_proxy/combine.rb

Overview

RelationProxy decorates a relation and automatically generates mappers that will map raw tuples into rom structs

Relation proxies are being registered within repositories so typically there’s no need to instantiate them manually.

Defined Under Namespace

Modules: Combine, Wrap

Constant Summary collapse

RelationRegistryType =
Types.Definition(RelationRegistry).constrained(type: RelationRegistry)

Instance Attribute Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object (private)

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.

Forward to relation and wrap it with proxy if response was a relation too

TODO: this will be simplified once ROM::Relation has lazy-features built-in

and ROM::Lazy is gone


220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/rom/repository/relation_proxy.rb', line 220

def method_missing(meth, *args, &block)
  if relation.respond_to?(meth)
    result = relation.__send__(meth, *args, &block)

    if result.kind_of?(Relation::Materializable) && !result.is_a?(Relation::Loaded)
      __new__(result)
    else
      result
    end
  else
    raise NoMethodError, "undefined method `#{meth}' for #{relation.class.name}"
  end
end

Instance Attribute Details

#relationRelation, ... (readonly)

Returns The decorated relation object.

Returns:

  • (Relation, Relation::Composite, Relation::Graph, Relation::Curried)

    The decorated relation object



27
# File 'lib/rom/repository/relation_proxy.rb', line 27

param :relation

Instance Method Details

#adapterSymbol

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 The wrapped relation’s adapter identifier ie :sql or :http.

Returns:

  • (Symbol)

    The wrapped relation’s adapter identifier ie :sql or :http



135
136
137
# File 'lib/rom/repository/relation_proxy.rb', line 135

def adapter
  relation.class.adapter
end

#call(*args) ⇒ Object

Materializes wrapped relation and sends it through a mapper

For performance reasons a combined relation will skip mapping since we only care about extracting key values for combining



49
50
51
# File 'lib/rom/repository/relation_proxy.rb', line 49

def call(*args)
  ((combine? || composite?) ? relation : (relation >> mapper)).call(*args)
end

#combine(*associations) ⇒ RelationProxy #combine(options) ⇒ RelationProxy Originally defined in module Combine

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:

#combine?Boolean

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 if this relation is combined aka a relation graph

Returns:

  • (Boolean)


119
120
121
# File 'lib/rom/repository/relation_proxy.rb', line 119

def combine?
  meta[:combine_type]
end

#combine_children(options) ⇒ RelationProxy Originally defined in module Combine

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:

#combine_parents(options) ⇒ RelationProxy Originally defined in module Combine

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:

#combined(name, keys, type) ⇒ RelationProxy Originally defined in module Combine

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:

#composite?Boolean

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.

Return if this relation is a composite

Returns:

  • (Boolean)


128
129
130
# File 'lib/rom/repository/relation_proxy.rb', line 128

def composite?
  relation.is_a?(Relation::Composite)
end

#inspectString

Return a string representation of this relation proxy

Returns:

  • (String)


90
91
92
# File 'lib/rom/repository/relation_proxy.rb', line 90

def inspect
  %(#<#{relation.class} name=#{name} dataset=#{dataset.inspect}>)
end

#map_with(model) ⇒ RelationProxy #map_with(*mappers) ⇒ RelationProxy Also known as: as

Maps the wrapped relation with other mappers available in the registry

Overloads:

  • #map_with(model) ⇒ RelationProxy

    Map tuples to the provided custom model class

    Examples:

    users.as(MyUserModel)

    Parameters:

    • ] (Class)

      model Your custom model class

  • #map_with(*mappers) ⇒ RelationProxy

    Map tuples using registered mappers

    Examples:

    users.map_with(:my_mapper, :my_other_mapper)

    Parameters:

    • mappers (Array<Symbol>)

      A list of mapper identifiers

Returns:

  • (RelationProxy)

    A new relation proxy with pipelined relation



74
75
76
77
78
79
80
81
82
# File 'lib/rom/repository/relation_proxy.rb', line 74

def map_with(*names)
  if names.size == 1 && names[0].is_a?(Class)
    with(meta: meta.merge(model: names[0]))
  elsif names.size > 1 && names.any? { |name| name.is_a?(Class) }
    raise ArgumentError, 'using custom mappers and a model is not supported'
  else
    names.reduce(self) { |a, e| a >> relation.mappers[e] }
  end
end

#mapperROM::Mapper

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.

Infers a mapper for the wrapped relation

Returns:

  • (ROM::Mapper)


99
100
101
# File 'lib/rom/repository/relation_proxy.rb', line 99

def mapper
  mappers[to_ast]
end

#nameROM::Relation::Name

Relation name

Returns:

  • (ROM::Relation::Name)


39
40
41
# File 'lib/rom/repository/relation_proxy.rb', line 39

def name
  @name == Dry::Initializer::UNDEFINED ? relation.name : relation.name.with(@name)
end

#respond_to_missing?(meth, _include_private = false) ⇒ Boolean

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:

  • (Boolean)


159
160
161
# File 'lib/rom/repository/relation_proxy.rb', line 159

def respond_to_missing?(meth, _include_private = false)
  relation.respond_to?(meth) || super
end

#to_astArray

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 AST for the wrapped relation

Returns:

  • (Array)


144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/rom/repository/relation_proxy.rb', line 144

def to_ast
  @to_ast ||=
    begin
      attr_ast = schema.map { |attr| [:attribute, attr] }

      meta = self.meta.merge(dataset: base_name.dataset)
      meta.delete(:wraps)

      header = attr_ast + nodes_ast + wraps_ast

      [:relation, [base_name.relation, meta, [:header, header]]]
    end
end

#with(new_options) ⇒ 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 new instance with new options

Parameters:

  • new_options (Hash)

Returns:



110
111
112
# File 'lib/rom/repository/relation_proxy.rb', line 110

def with(new_options)
  __new__(relation, options.merge(new_options))
end

#wrap(options) ⇒ RelationProxy Originally defined in module Wrap

Wrap other relations

Examples:

tasks.wrap(owner: [users, user_id: :id])

Parameters:

  • options (Hash)

Returns:

#wrap_parent(options) ⇒ RelationProxy Originally defined in module Wrap

Shortcut to wrap parents

Examples:

tasks.wrap_parent(owner: users)

Returns:

#wrapped(name, keys) ⇒ RelationProxy Originally defined in module Wrap

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.

Return a wrapped 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: