lib/rom/repository.rb in rom-repository-1.4.0 vs lib/rom/repository.rb in rom-repository-2.0.0.beta1
- old
+ new
@@ -1,14 +1,9 @@
require 'dry/core/deprecations'
require 'rom/initializer'
require 'rom/repository/class_interface'
-require 'rom/repository/mapper_builder'
-require 'rom/repository/relation_proxy'
-require 'rom/repository/command_compiler'
-
-require 'rom/repository/changeset'
require 'rom/repository/session'
module ROM
# Abstract repository class to inherit from
#
@@ -53,17 +48,10 @@
#
# @see Repository::Root
#
# @api public
class Repository
- # Mapping for supported changeset classes used in #changeset(type => relation) method
- CHANGESET_TYPES = {
- create: Changeset::Create,
- update: Changeset::Update,
- delete: Changeset::Delete
- }.freeze
-
extend ClassInterface
extend Initializer
extend Dry::Core::ClassAttributes
# @!method self.auto_struct
@@ -84,10 +72,15 @@
# @!method self.auto_struct
# Get or set struct namespace
defines :struct_namespace
+ # @!method self.relation_reader
+ # Get or set relation reader module
+ # @return [RelationReader]
+ defines :relation_reader
+
struct_namespace ROM::Struct
# @!attribute [r] container
# @return [ROM::Container] The container used to set up a repo
param :container, allow: ROM::Container
@@ -102,181 +95,21 @@
# @!attribute [r] relations
# @return [RelationRegistry] The relation proxy registry used by a repo
attr_reader :relations
- # @!attribute [r] mappers
- # @return [MapperBuilder] The auto-generated mappers for repo relations
- attr_reader :mappers
-
- # @!attribute [r] commmand_compiler
- # @return [Method] Function for compiling commands bound to a repo instance
- attr_reader :command_compiler
-
# Initializes a new repo by establishing configured relation proxies from
# the passed container
#
# @param container [ROM::Container] The rom container with relations and optional commands
#
- # @api public
- def initialize(container, opts = EMPTY_HASH)
+ # @api private
+ def initialize(container, options = EMPTY_HASH)
super
-
- @mappers = MapperBuilder.new(struct_namespace: struct_namespace)
-
- @relations = RelationRegistry.new do |registry, relations|
- self.class.relations.each do |name|
- relation = container.relations[name]
- relation = relation.with(mappers: container.mappers[name]) if container.mappers.key?(name)
-
- proxy = RelationProxy.new(
- relation, name: name, mappers: mappers, registry: registry, auto_struct: auto_struct
- )
-
- instance_variable_set("@#{name}", proxy)
-
- relations[name] = proxy
- end
- end
-
- @command_compiler = method(:command)
+ @relations = {}
end
- # Return a command for a relation
- #
- # @overload command(type, relation)
- # Returns a command for a relation
- #
- # @example
- # repo.command(:create, repo.users)
- #
- # @param type [Symbol] The command type (:create, :update or :delete)
- # @param relation [RelationProxy] The relation for which command should be built for
- #
- # @overload command(options)
- # Builds a command for a given relation identifier
- #
- # @example
- # repo.command(create: :users)
- #
- # @param options [Hash<Symbol=>Symbol>] A type => rel_name map
- #
- # @overload command(rel_name)
- # Returns command registry for a given relation identifier
- #
- # @example
- # repo.command(:users)[:my_custom_command]
- #
- # @param rel_name [Symbol] The relation identifier from the container
- #
- # @return [CommandRegistry]
- #
- # @overload command(rel_name, &block)
- # Yields a command graph composer for a given relation identifier
- #
- # @param rel_name [Symbol] The relation identifier from the container
- #
- # @return [ROM::Command]
- #
- # @api public
- def command(*args, **opts, &block)
- all_args = args + opts.to_a.flatten
-
- if all_args.size > 1
- commands.fetch_or_store(all_args.hash) do
- compile_command(*args, **opts)
- end
- else
- container.command(*args, &block)
- end
- end
-
- # Return a changeset for a relation
- #
- # @overload changeset(name, attributes)
- # Return a create changeset for a given relation identifier
- #
- # @example
- # repo.changeset(:users, name: "Jane")
- #
- # @param name [Symbol] The relation container identifier
- # @param attributes [Hash]
- #
- # @return [Changeset::Create]
- #
- # @overload changeset(name, primary_key, attributes)
- # Return an update changeset for a given relation identifier
- #
- # @example
- # repo.changeset(:users, 1, name: "Jane Doe")
- #
- # @param name [Symbol] The relation container identifier
- # @param restriction_arg [Object] The argument passed to restricted view
- #
- # @return [Changeset::Update]
- #
- # @overload changeset(changeset_class)
- # Return a changeset object using provided class
- #
- # @example
- # repo.changeset(NewUserChangeset).data(attributes)
- #
- # @param [Class] changeset_class Custom changeset class
- #
- # @return [Changeset]
- #
- # @overload changeset(opts)
- # Return a changeset object using provided changeset type and relation
- #
- # @example
- # repo.changeset(delete: repo.users.where { id > 10 })
- #
- # @param [Hash<Symbol=>Relation] opts Command type => Relation config
- #
- # @return [Changeset]
- #
- # @api public
- def changeset(*args)
- opts = { command_compiler: command_compiler }
-
- if args.size == 2
- name, data = args
- elsif args.size == 3
- name, pk, data = args
- elsif args.size == 1
- if args[0].is_a?(Class)
- klass = args[0]
-
- if klass < Changeset
- return klass.new(relations[klass.relation], opts)
- else
- raise ArgumentError, "+#{klass.name}+ is not a Changeset subclass"
- end
- else
- type, relation = args[0].to_a[0]
- end
- else
- raise ArgumentError, 'Repository#changeset accepts 1-3 arguments'
- end
-
- if type
- klass = CHANGESET_TYPES.fetch(type) {
- raise ArgumentError, "+#{type.inspect}+ is not a valid changeset type. Must be one of: #{CHANGESET_TYPES.keys.inspect}"
- }
-
- klass.new(relation, opts)
- else
- relation = relations[name]
-
- if pk
- Changeset::Update.new(relation.by_pk(pk), opts.update(__data__: data))
- else
- Changeset::Create.new(relation, opts.update(__data__: data))
- end
- end
- end
-
# Open a database transaction
#
# @example commited transaction
# user = transaction do |t|
# create(changeset(name: 'Jane'))
@@ -303,11 +136,11 @@
#
# @return [String]
#
# @api public
def inspect
- %(#<#{self.class} relations=[#{self.class.relations.map(&:inspect).join(' ')}]>)
+ %(#<#{self.class} struct_namespace=#{struct_namespace} auto_struct=#{auto_struct}>)
end
# Start a session for multiple changesets
#
# TODO: this is partly done, needs tweaks in changesets so that we can gather
@@ -318,49 +151,9 @@
# @api public
def session(&block)
session = Session.new(self)
yield(session)
transaction { session.commit! }
- end
-
- private
-
- # Local command cache
- #
- # @api private
- def commands
- @__commands__ ||= Concurrent::Map.new
- end
-
- # Build a new command or return existing one
- #
- # @api private
- def compile_command(*args, mapper: nil, use: nil, **opts)
- type, name = args + opts.to_a.flatten(1)
-
- relation = name.is_a?(Symbol) ? relations[name] : name
-
- ast = relation.to_ast
- adapter = relations[relation.name].adapter
-
- if mapper
- mapper_instance = container.mappers[relation.name.relation][mapper]
- elsif mapper.nil?
- mapper_instance = mappers[ast]
- end
-
- command = CommandCompiler[container, type, adapter, ast, use, opts]
-
- if mapper_instance
- command >> mapper_instance
- else
- command.new(relation)
- end
- end
-
- # @api private
- def map_tuple(relation, tuple)
- relations[relation.name].mapper.([tuple]).first
end
end
end
require 'rom/repository/root'