lib/rom/sql/plugin/associates.rb in rom-sql-0.9.1 vs lib/rom/sql/plugin/associates.rb in rom-sql-1.0.0.beta1

- old
+ new

@@ -1,86 +1,103 @@ -require 'rom/support/deprecations' - module ROM module SQL module Plugin # Make a command that automaticaly sets FK attribute on input tuples # # @api private module Associates # @api private def self.included(klass) - klass.extend(ClassMethods) - super - end + klass.class_eval do + extend ClassMethods + include InstanceMethods + defines :associations - module InstanceMethods - attr_reader :assoc, :__registry__ + associations [] - # @api private - def initialize(*) - super - @__registry__ = relation.__registry__ - assoc_name, assoc_opts = self.class.associations[0] - @assoc = - if assoc_opts.any? - assoc_opts[:key] - else - relation.associations[assoc_name] - end + option :associations, reader: true, optional: true, default: -> cmd { cmd.class.associations } end + super + end + module InstanceMethods # Set fk on tuples from parent tuple # # @param [Array<Hash>, Hash] tuples The input tuple(s) # @param [Hash] parent The parent tuple with its pk already set # - # @return [Array<Hash>,Hash] + # @return [Array<Hash>] # - # @overload SQL::Commands::Create#execute - # # @api public - def execute(tuples, parent) + def associate(tuples, parent, assoc:, keys:) input_tuples = case assoc - when Array - fk, pk = assoc + when Symbol + fk, pk = keys - input_tuples = with_input_tuples(tuples).map { |tuple| + with_input_tuples(tuples).map { |tuple| tuple.merge(fk => parent.fetch(pk)) } - - super(input_tuples) when Association::ManyToMany - new_tuples = super(tuples) - - join_tuples = assoc.associate(__registry__, new_tuples, parent) + join_tuples = assoc.associate(__registry__, tuples, parent) join_relation = assoc.join_relation(__registry__) join_relation.multi_insert(join_tuples) pk, fk = __registry__[assoc.target] .associations[assoc.source] .combine_keys(__registry__).to_a.flatten pk_extend = { fk => parent[pk] } - new_tuples.map { |tuple| tuple.update(pk_extend) } + tuples.map { |tuple| tuple.update(pk_extend) } when Association - input_tuples = with_input_tuples(tuples).map { |tuple| + with_input_tuples(tuples).map { |tuple| assoc.associate(relation.__registry__, tuple, parent) } - super(input_tuples) end end + + # @api public + def with_association(name, opts = EMPTY_HASH) + self.class.build(relation, options.merge(associations: [[name, opts]])) + end + + # @api private + def __registry__ + relation.__registry__ + end end module ClassMethods - # @api private - def inherited(klass) - klass.defines :associations - klass.associations [] - super + # @see ROM::Command::ClassInterface.build + # + # @api public + def build(relation, options = EMPTY_HASH) + command = super + associations = command.associations + + before_hooks = associations.each_with_object([]) do |(name, opts), acc| + relation.associations.try(name) do |assoc| + unless assoc.is_a?(Association::ManyToMany) + acc << { associate: { assoc: assoc, keys: assoc.join_keys(relation.__registry__) } } + else + true + end + end or acc << { associate: { assoc: name, keys: opts[:key] } } + end + + after_hooks = associations.each_with_object([]) do |(name, opts), acc| + next unless relation.associations.key?(name) + + assoc = relation.associations[name] + + if assoc.is_a?(Association::ManyToMany) + acc << { associate: { assoc: assoc, keys: assoc.join_keys(relation.__registry__) } } + end + end + + command.before(*before_hooks).after(*after_hooks) end # Set command to associate tuples with a parent tuple using provided keys # # @example @@ -100,20 +117,16 @@ # @param [Symbol] name The name of associated table # @param [Hash] options The options # @option options [Array] :key The association keys # # @api public - def associates(name, options = {}) + def associates(name, options = EMPTY_HASH) if associations.map(&:first).include?(name) raise ArgumentError, - "#{name} association is already defined for #{self.class}" + "#{name} association is already defined for #{self.class}" end - option :association, reader: true, default: {} - - include InstanceMethods - - associations << [name, options] + associations(associations.dup << [name, options]) end end end end end