Class: OmniService::FindMany

Inherits:
Object
  • Object
show all
Extended by:
Dry::Initializer
Includes:
Dry::Core::Constants
Defined in:
lib/omni_service/find_many.rb

Overview

Finds multiple entities by IDs via repository#get_many. Accepts array of IDs or nested structures with IDs. Returns deduplicated entities; reports not-found errors with array indices.

Options:

  • :with - param key for IDs array (default: :“#context_keycontext_key.singularize_ids”)

  • :by - column mapping with nested paths: { id: [:items, :product_id] }

  • :repository - single repo or Hash for polymorphic lookup

  • :type - path to type discriminator for polymorphic lookup

Flags:

  • :nullable - skip nil values in array instead of reporting errors

  • :omittable - allow missing param key, returns Success({})

Examples:

Basic bulk lookup

FindMany.new(:posts, repository: post_repo)
# params: { post_ids: [1, 2, 3] } => Success(posts: [<Post>, <Post>, <Post>])

Nested IDs in array of hashes

FindMany.new(:products, repository: repo, by: { id: [:items, :product_id] })
# params: { items: [{ product_id: 1 }, { product_id: [2, 3] }] }
# => Success(products: [<Product>, <Product>, <Product>])

Error reporting with indices

# params: { post_ids: [1, 999, 3] } where 999 doesn't exist
# => Failure([{ code: :not_found, path: [:post_ids, 1] }])

Polymorphic lookup

FindMany.new(:attachments, repository: { 'Image' => img_repo, 'Video' => vid_repo },
             by: { id: [:files, :id] }, type: [:files, :type])
# params: { files: [{ type: 'Image', id: 1 }, { type: 'Video', id: 2 }] }

Nullable for optional associations

FindMany.new(:tags, repository: repo, nullable: true)
# params: { tag_ids: [1, nil, 2] } => Success(tags: [<Tag>, <Tag>])

Constant Summary collapse

PRIMARY_KEY =
:id
Reference =
Class.new(Dry::Struct) do
  attribute :path, OmniService::Types::Array.of(OmniService::Types::Symbol | OmniService::Types::Integer)
  attribute :value, OmniService::Types::Any

  def undefined?
    Undefined.equal?(value)
  end

  def missing_id_path
    path if undefined?
  end

  def missing_type_path; end

  def normalized_value
    Array.wrap(value)
  end
end
PolymorphicReference =
Class.new(Dry::Struct) do
  attribute :type, Reference
  attribute :id, Reference

  delegate :path, :missing_id_path, to: :id

  def undefined?
    type.undefined? || id.undefined?
  end

  def missing_type_path
    type.missing_id_path unless id.value.nil?
  end
end

Instance Method Summary collapse

Instance Method Details

#call(params, **context) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/omni_service/find_many.rb', line 93

def call(params, **context)
  return Success({}) if already_found?(context)

  references, *missing_paths = references(params)
  no_errors = missing_paths.all?(&:empty?)

  if references.values.all?(&:empty?) && no_errors
    Success({})
  elsif !no_errors
    missing_keys_result(*missing_paths)
  else
    find(references)
  end
end