Skip to content

Commit

Permalink
Merge pull request #52 from sleepingkingstudios/chore/refactor-associ…
Browse files Browse the repository at this point in the history
…ation-command

Chore/Refactor Commands::Associations::FindMany.
  • Loading branch information
sleepingkingstudios authored Sep 29, 2023
2 parents 13d94e0 + 514cc18 commit 0d4bb06
Show file tree
Hide file tree
Showing 4 changed files with 566 additions and 1,049 deletions.
111 changes: 101 additions & 10 deletions lib/cuprum/collections/commands/associations/find_many.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,48 @@
module Cuprum::Collections::Commands::Associations
# Command for querying entities by association.
class FindMany < Cuprum::Command
PERMITTED_KEYWORDS = Set.new(%i[entities entity key keys]).freeze
private_constant :PERMITTED_KEYWORDS

# @!method call(**params)
# @overload call(key:)
# Finds the association values for the given key.
#
# @param key [Object] the primary or foreign key for querying the
# association.
#
# @return [Object, nil] the association value or nil, if the association
# is singular.
# @return [Array<Object>] the association values, if the association is
# plural.
#
# @overload call(keys:)
# Finds the association values for the given Array of keys.
# @return [Array<Object>] the association values.
#
# @param keys [Array<Object>] the primary or foreign keys for querying
# the association.
#
# @return [Array<Object>] the association values.
#
# @overload call(entity:)
# Finds the association values for the given entity.
#
# @param entity [Object] the base entity for querying the association.
#
# @return [Object, nil] the association value or nil, if the association
# is singular.
# @return [Array<Object>] the association values, if the association is
# plural.
#
# @overload call(entities:)
# Finds the association values for the given Array of entities.
#
# @param entity [Array<Object>] the base entities for querying the
# association.
#
# @return [Array<Object>] the association values.

# @param association [Cuprum::Collections::Association] the association to
# query.
# @param repository [Cuprum::Collections::Repository] the repository to
Expand Down Expand Up @@ -38,29 +80,78 @@ def collection
)
end

def perform_query(association:, expected_keys:)
def extract_keys(association, hsh)
return hsh[:key] if hsh.key?(:key)
return hsh[:keys] if hsh.key?(:keys)

values = hsh.fetch(:entity) { hsh[:entities] }

if values.is_a?(Array)
association.map_entities_to_keys(*values)
else
association.map_entities_to_keys(values).first
end
end

def handle_ambiguous_keys(hsh)
return if hsh.keys.size == 1

raise ArgumentError,
"ambiguous keywords #{hsh.each_key.map(&:inspect).join(', ')} " \
'- must provide exactly one parameter'
end

def handle_extra_keys(hsh)
return if hsh.keys.all? { |key| PERMITTED_KEYWORDS.include?(key) }

extra_keys = hsh.keys - PERMITTED_KEYWORDS.to_a

raise ArgumentError,
"invalid keywords #{extra_keys.map(&:inspect).join(', ')}"
end

def handle_missing_keys(hsh)
return unless hsh.empty?

raise ArgumentError, 'missing keyword :entity, :entities, :key, or :keys'
end

def perform_query(association:, expected_keys:, **)
query = association.build_keys_query(*expected_keys)
find_command = collection.find_matching

find_command.call(&query)
end

def process(*entities_or_keys)
association = @association.with_inverse(resource)
expected_keys =
association.map_entities_to_keys(*entities_or_keys, strict: false)
def process(**params) # rubocop:disable Metrics/MethodLength
association = @association.with_inverse(resource)
expected_keys, plural = resolve_keys(association, **params)
plural ||= association.plural?

return singular? ? nil : [] if expected_keys.empty?
return plural ? [] : nil if expected_keys.empty?

values = step do
perform_query(association: association, expected_keys: expected_keys)
perform_query(
association: association,
expected_keys: expected_keys,
plural: plural
)
end

singular? ? values.first : values.to_a
plural ? values.to_a : values.first
end

def singular?
association.singular? && resource.singular?
def resolve_keys(association, **params)
handle_missing_keys(params)
handle_extra_keys(params)
handle_ambiguous_keys(params)

keys = extract_keys(association, params)
plural = keys.is_a?(Array)
keys = [keys] unless plural
keys = keys.compact.uniq

[keys, plural]
end

def tools
Expand Down
13 changes: 9 additions & 4 deletions lib/cuprum/collections/commands/associations/require_many.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@ def map_entity_keys(entities:)
entities.map { |entity| entity[association.query_key_name] }
end

def missing_keys_error(missing_keys:)
def missing_keys_error(missing_keys:, plural:)
attribute_value =
!plural && missing_keys.is_a?(Array) ? missing_keys.first : missing_keys

Cuprum::Collections::Errors::Associations::NotFound.new(
attribute_name: association.query_key_name,
attribute_value: singular? ? missing_keys.first : missing_keys,
attribute_value: attribute_value,
collection_name: association.name,
primary_key: association.primary_key_query?
)
end

def perform_query(association:, expected_keys:)
def perform_query(association:, expected_keys:, plural:, **)
entities = step { super }
missing_keys = find_missing_keys(
entities: entities,
Expand All @@ -35,7 +38,9 @@ def perform_query(association:, expected_keys:)

return success(entities) if missing_keys.empty?

error = missing_keys_error(missing_keys: missing_keys)
missing_keys = missing_keys.first unless plural
error =
missing_keys_error(missing_keys: missing_keys, plural: plural)

failure(error)
end
Expand Down
Loading

0 comments on commit 0d4bb06

Please sign in to comment.