projects/command/src/concerns/domain_mappers.rb in foobara-0.0.37 vs projects/command/src/concerns/domain_mappers.rb in foobara-0.0.38

- old
+ new

@@ -1,36 +1,126 @@ module Foobara class Command module Concerns module DomainMappers + class ForgotToDependOnDomainMapperError < Foobara::RuntimeError + context { mapper_name :string, :required } + + attr_accessor :mapper + + def initialize(mapper) + self.mapper = mapper + super() + end + + def context + { mapper_name: mapper.name } + end + + def message + "Did you maybe forget to add depends_on #{mapper.name}?" + end + end + + class NoDomainMapperFoundError < Foobara::RuntimeError + context do + subcommand_name :string, :required + to :duck + end + + attr_accessor :subcommand, :to + + def initialize(subcommand, to) + self.subcommand = subcommand + self.to = to + + super() + end + + def context + { subcommand_name: subcommand.name, to: } + end + + def message + "No DomainMapper found that maps to #{subcommand.name} or from its result" + end + end + include Concern - def run_mapped_subcommand!(subcommand_class, *args) - unmapped_inputs, has_result_type, result_type = - case args.size - when 1 - [args.first] - when 2 - [args[1], true, args[0]] - else - # :nocov: - raise ArgumentError, - "Wrong number of arguments: (#{args.size}. Expected 2 or 3 argument." - # :nocov: - end + def run_mapped_subcommand!(subcommand_class, unmapped_inputs = {}, to = nil) + mapped_something = false + no_mapper_found = nil - inputs = domain_map!(unmapped_inputs, to: subcommand_class, strict: true) + criteria = ->(mapper) { self.class.depends_on?(mapper) } - result = run_subcommand!(subcommand_class, inputs) + inputs_mapper = self.class.domain.lookup_matching_domain_mapper( + from: unmapped_inputs, + to: subcommand_class, + criteria:, + strict: true + ) - if has_result_type - result_mapper = self.class.domain.lookup_matching_domain_mapper!( + inputs = if inputs_mapper + mapped_something = true + run_subcommand!(inputs_mapper, from: unmapped_inputs) + else + unmapped_inputs + end + + result_mapper = if subcommand_class.result_type + mapper = self.class.domain.lookup_matching_domain_mapper( + from: subcommand_class.result_type, + to:, + criteria:, + strict: true + ) + + no_mapper_found = mapper.nil? && inputs_mapper.nil? + + mapper + end + + result = unless no_mapper_found + run_subcommand!(subcommand_class, inputs) + end + + unless subcommand_class.result_type + result_mapper = self.class.domain.lookup_matching_domain_mapper( from: result, - to: result_type, + to:, + criteria: ->(domain_mapper) { self.class.depends_on?(domain_mapper) }, strict: true ) + end - result = result_mapper.map!(result) + if result_mapper + mapped_something = true + result = run_subcommand!(result_mapper, from: result) + end + + unless mapped_something + mapper = self.class.domain.lookup_matching_domain_mapper( + from: unmapped_inputs, + to: subcommand_class, + strict: true + ) + + if mapper + raise ForgotToDependOnDomainMapperError, mapper + end + + mapper = self.class.domain.lookup_matching_domain_mapper( + from: subcommand_class.result_type, + to:, + strict: true + ) + + if mapper + raise ForgotToDependOnDomainMapperError, mapper + end + + raise NoDomainMapperFoundError.new(subcommand_class, to) end result end