rom-rb/rom-repository

View on GitHub
lib/rom/repository/relation_proxy/wrap.rb

Summary

Maintainability
A
0 mins
Test Coverage
module ROM
  class Repository
    class RelationProxy
      # Provides convenient methods for producing wrapped relations
      #
      # @api public
      module Wrap
        # Wrap other relations
        #
        # @example
        #   tasks.wrap(owner: [users, user_id: :id])
        #
        # @param [Hash] options
        #
        # @return [RelationProxy]
        #
        # @api public
        def wrap(*names, **options)
          new_wraps = wraps_from_names(names) + wraps_from_options(options)

          relation = new_wraps.reduce(self) { |a, e|
            name = e.meta[:wrap_from_assoc] ? e.meta[:combine_name] : e.base_name.relation
            a.relation.for_wrap(e.meta.fetch(:keys), name)
          }

          __new__(relation, meta: { wraps: wraps + new_wraps })
        end

        # Shortcut to wrap parents
        #
        # @example
        #   tasks.wrap_parent(owner: users)
        #
        # @return [RelationProxy]
        #
        # @api public
        def wrap_parent(options)
          wrap(
            options.each_with_object({}) { |(name, parent), h|
              keys = combine_keys(parent, relation, :children)
              h[name] = [parent, keys]
            }
          )
        end

        # 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
        #
        # @return [RelationProxy]
        #
        # @api private
        def wrapped(name, keys, wrap_from_assoc = false)
          with(
            name: name,
            meta: {
              keys: keys, wrap_from_assoc: wrap_from_assoc, wrap: true, combine_name: name
            }
          )
        end

        # @api private
        def wraps_from_options(options)
          options.map { |(name, (relation, keys))| relation.wrapped(name, keys) }
        end

        # @api private
        def wraps_from_names(names)
          names.map { |name|
            assoc = associations[name]
            registry[assoc.target.relation].wrapped(name, assoc.combine_keys(__registry__), true)
          }
        end
      end
    end
  end
end