cuprum-collections 0.5.1 → 0.6.0.rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -0
  3. data/lib/cuprum/collections/adaptable/collection.rb +18 -0
  4. data/lib/cuprum/collections/adaptable/command.rb +22 -0
  5. data/lib/cuprum/collections/adaptable/commands/abstract_assign_one.rb +27 -0
  6. data/lib/cuprum/collections/adaptable/commands/abstract_build_one.rb +25 -0
  7. data/lib/cuprum/collections/adaptable/commands/abstract_validate_one.rb +35 -0
  8. data/lib/cuprum/collections/adaptable/commands.rb +15 -0
  9. data/lib/cuprum/collections/adaptable/query.rb +64 -0
  10. data/lib/cuprum/collections/adaptable.rb +13 -0
  11. data/lib/cuprum/collections/adapter.rb +300 -0
  12. data/lib/cuprum/collections/adapters/data_adapter.rb +82 -0
  13. data/lib/cuprum/collections/adapters/entity_adapter.rb +76 -0
  14. data/lib/cuprum/collections/adapters/hash_adapter.rb +48 -0
  15. data/lib/cuprum/collections/adapters.rb +14 -0
  16. data/lib/cuprum/collections/basic/collection.rb +2 -20
  17. data/lib/cuprum/collections/basic/commands/destroy_one.rb +1 -1
  18. data/lib/cuprum/collections/basic/commands/find_many.rb +0 -31
  19. data/lib/cuprum/collections/basic/commands/find_matching.rb +0 -94
  20. data/lib/cuprum/collections/basic/commands/find_one.rb +0 -18
  21. data/lib/cuprum/collections/basic/commands/insert_one.rb +1 -1
  22. data/lib/cuprum/collections/basic/commands/update_one.rb +1 -1
  23. data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +36 -21
  24. data/lib/cuprum/collections/basic.rb +6 -5
  25. data/lib/cuprum/collections/collection.rb +6 -0
  26. data/lib/cuprum/collections/collection_command.rb +1 -1
  27. data/lib/cuprum/collections/commands/abstract_find_many.rb +40 -3
  28. data/lib/cuprum/collections/commands/abstract_find_matching.rb +102 -0
  29. data/lib/cuprum/collections/commands/abstract_find_one.rb +23 -1
  30. data/lib/cuprum/collections/commands/associations/find_many.rb +1 -3
  31. data/lib/cuprum/collections/commands/associations/require_many.rb +1 -1
  32. data/lib/cuprum/collections/commands/find_one_matching.rb +10 -10
  33. data/lib/cuprum/collections/commands/query_command.rb +6 -4
  34. data/lib/cuprum/collections/commands/upsert.rb +0 -2
  35. data/lib/cuprum/collections/constraints/order/attributes_array.rb +5 -4
  36. data/lib/cuprum/collections/constraints/order/attributes_hash.rb +5 -4
  37. data/lib/cuprum/collections/constraints/order/sort_direction.rb +2 -2
  38. data/lib/cuprum/collections/constraints/ordering.rb +11 -9
  39. data/lib/cuprum/collections/constraints/query_hash.rb +2 -2
  40. data/lib/cuprum/collections/errors/abstract_find_error.rb +101 -23
  41. data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
  42. data/lib/cuprum/collections/errors/failed_validation.rb +3 -3
  43. data/lib/cuprum/collections/errors/missing_default_contract.rb +12 -4
  44. data/lib/cuprum/collections/queries.rb +4 -0
  45. data/lib/cuprum/collections/relation.rb +0 -2
  46. data/lib/cuprum/collections/relations/parameters.rb +120 -68
  47. data/lib/cuprum/collections/repository.rb +71 -6
  48. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +23 -4
  49. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +18 -0
  50. data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +51 -0
  51. data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +10 -0
  52. data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +8 -0
  53. data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +18 -366
  54. data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +30 -0
  55. data/lib/cuprum/collections/rspec/contracts/scopes.rb +2 -0
  56. data/lib/cuprum/collections/rspec/contracts.rb +2 -10
  57. data/lib/cuprum/collections/rspec/deferred/adapter_examples.rb +1077 -0
  58. data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +27 -7
  59. data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +4 -4
  60. data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +2 -2
  61. data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +2 -2
  62. data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +5 -5
  63. data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +45 -12
  64. data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +2 -2
  65. data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +1 -1
  66. data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +1 -1
  67. data/lib/cuprum/collections/rspec/deferred/query_examples.rb +930 -0
  68. data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +48 -17
  69. data/lib/cuprum/collections/rspec/deferred/repository_examples.rb +961 -0
  70. data/lib/cuprum/collections/rspec/deferred/scope_examples.rb +598 -0
  71. data/lib/cuprum/collections/rspec/deferred/scopes/all_examples.rb +391 -0
  72. data/lib/cuprum/collections/rspec/deferred/scopes/builder_examples.rb +857 -0
  73. data/lib/cuprum/collections/rspec/deferred/scopes/composition_examples.rb +93 -0
  74. data/lib/cuprum/collections/rspec/deferred/scopes/conjunction_examples.rb +438 -0
  75. data/lib/cuprum/collections/rspec/deferred/scopes/criteria_examples.rb +1941 -0
  76. data/lib/cuprum/collections/rspec/deferred/scopes/disjunction_examples.rb +415 -0
  77. data/lib/cuprum/collections/rspec/deferred/scopes/none_examples.rb +385 -0
  78. data/lib/cuprum/collections/rspec/deferred/scopes/parser_examples.rb +740 -0
  79. data/lib/cuprum/collections/rspec/deferred/scopes.rb +8 -0
  80. data/lib/cuprum/collections/scope.rb +2 -2
  81. data/lib/cuprum/collections/scopes/container.rb +5 -4
  82. data/lib/cuprum/collections/scopes/criteria/parser.rb +24 -48
  83. data/lib/cuprum/collections/scopes/criteria.rb +7 -6
  84. data/lib/cuprum/collections/version.rb +4 -4
  85. data/lib/cuprum/collections.rb +5 -1
  86. metadata +47 -11
  87. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +0 -2127
  88. data/lib/cuprum/collections/rspec/contracts/basic.rb +0 -11
  89. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +0 -387
  90. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +0 -169
  91. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +0 -1264
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/adapter'
4
+ require 'cuprum/collections/adapters'
5
+
6
+ module Cuprum::Collections::Adapters
7
+ # Utility class for converting between attributes and a Stannum::Entity class.
8
+ class EntityAdapter < Cuprum::Collections::Adapter
9
+ # @param options [Hash] options for initializing the adapter.
10
+ #
11
+ # @option options attributes_names [Array<String, Symbol>] the valid
12
+ # attribute names for a data object. Defaults to the entity class's
13
+ # attributes. Must be a subset of the entity class's attributes.
14
+ # @option options default_contract [Stannum::Constraints:Base] the contract
15
+ # used to validate instances of the data object.
16
+ # @option options entity_class [Class] the class of the data objects. Must
17
+ # be a Stannum::Enttiy subclass.
18
+ def initialize(entity_class:, **options)
19
+ if options[:allow_extra_attributes]
20
+ raise ArgumentError, 'adapter does not support extra attributes'
21
+ end
22
+
23
+ attribute_names = options.fetch(:attribute_names) do
24
+ entity_class?(entity_class) ? entity_class&.attributes&.keys || [] : []
25
+ end
26
+
27
+ super(attribute_names:, entity_class:, **options)
28
+
29
+ verify_attribute_names_are_attributes
30
+ end
31
+
32
+ private
33
+
34
+ def build_entity(attributes:)
35
+ entity_class.new(**attributes)
36
+ end
37
+
38
+ def default_contract_for(**)
39
+ return default_contract if default_contract
40
+
41
+ entity_class.contract
42
+ end
43
+
44
+ def entity_class?(entity_class)
45
+ entity_class.is_a?(Class) && entity_class < Stannum::Entity
46
+ end
47
+
48
+ def merge_entity(attributes:, entity:)
49
+ entity.dup.tap { |copy| copy.assign_attributes(attributes) }
50
+ end
51
+
52
+ def serialize_entity(entity:)
53
+ entity.attributes
54
+ end
55
+
56
+ def validate_entity_class_parameter(entity_class, as: 'entity class')
57
+ tools.assertions.validate_class(entity_class, as:)
58
+
59
+ return if entity_class < Stannum::Entity
60
+
61
+ raise ArgumentError, "#{as} is not a Stannum::Entity"
62
+ end
63
+
64
+ def verify_attribute_names_are_attributes
65
+ invalid_names = attribute_names - (entity_class&.attributes&.keys || [])
66
+
67
+ return if invalid_names.empty?
68
+
69
+ error_message =
70
+ "attribute names #{invalid_names.join(', ')} are not attributes of " \
71
+ "#{entity_class.name || 'the entity class'}"
72
+
73
+ raise ArgumentError, error_message
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/adapter'
4
+ require 'cuprum/collections/adapters'
5
+
6
+ module Cuprum::Collections::Adapters
7
+ # Utility class for converting between raw attributes and a data Hash.
8
+ class HashAdapter < Cuprum::Collections::Adapter
9
+ # @param options [Hash] options for initializing the adapter.
10
+ #
11
+ # @option options allow_extra_attributes [true, false] if false, attributes
12
+ # methods return an error for attributes not in attributes_names. Defaults
13
+ # to true if attribute_names is empty, otherwise false.
14
+ # @option options attributes_names [Array<String, Symbol>] the valid
15
+ # attribute names for a data object. Defaults to [].
16
+ # @option options default_contract [Stannum::Constraints:Base] the contract
17
+ # used to validate instances of the data object.
18
+ def initialize(**options)
19
+ if options[:entity_class]
20
+ raise ArgumentError, 'adapter does not support entity class'
21
+ end
22
+
23
+ super(entity_class: Hash, **options)
24
+ end
25
+
26
+ private
27
+
28
+ def build_entity(attributes:)
29
+ attributes = tools.hash_tools.convert_keys_to_strings(attributes)
30
+
31
+ empty_attributes.merge(attributes)
32
+ end
33
+
34
+ def empty_attributes
35
+ @empty_attributes ||= attribute_names.to_h { |key| [key, nil] }
36
+ end
37
+
38
+ def merge_entity(attributes:, entity:)
39
+ attributes = tools.hash_tools.convert_keys_to_strings(attributes)
40
+
41
+ entity.merge(attributes)
42
+ end
43
+
44
+ def serialize_entity(entity:)
45
+ entity.dup
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections'
4
+
5
+ module Cuprum::Collections
6
+ # Namespace for adapter implementations.
7
+ #
8
+ # @see Cuprum::Collections::Adapter.
9
+ module Adapters
10
+ autoload :DataAdapter, 'cuprum/collections/adapters/data_adapter'
11
+ autoload :EntityAdapter, 'cuprum/collections/adapters/entity_adapter'
12
+ autoload :HashAdapter, 'cuprum/collections/adapters/hash_adapter'
13
+ end
14
+ end
@@ -27,7 +27,7 @@ module Cuprum::Collections::Basic
27
27
  # [Cuprum::Collections::Scopes::Base, Hash, Proc, nil] the configured
28
28
  # scope for the relation.
29
29
  def initialize(data: [], **parameters)
30
- super(**normalize_parameters(**parameters))
30
+ super(default_entity_class: Hash, **parameters)
31
31
 
32
32
  @data = data
33
33
  end
@@ -71,7 +71,7 @@ module Cuprum::Collections::Basic
71
71
  Cuprum::Collections::Basic::Commands::ValidateOne.new(collection: self)
72
72
  end
73
73
 
74
- # @return [Stannum::Constraints::Base, nil] the # default contract for
74
+ # @return [Stannum::Constraints::Base, nil] the default contract for
75
75
  # validating items in the collection.
76
76
  def default_contract
77
77
  @options[:default_contract]
@@ -98,23 +98,5 @@ module Cuprum::Collections::Basic
98
98
  def default_scope
99
99
  Cuprum::Collections::Basic::Scopes::AllScope.new
100
100
  end
101
-
102
- def normalize_parameters(**parameters) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
103
- return parameters if parameters.key?(:entity_class)
104
-
105
- return parameters unless parameters[:name] || parameters[:qualified_name]
106
-
107
- parameters = parameters.merge(entity_class: Hash)
108
-
109
- if parameters.key?(:name) && parameters.key?(:qualified_name)
110
- parameters
111
- elsif parameters.key?(:name)
112
- parameters.merge(qualified_name: parameters[:name])
113
- elsif parameters.key?(:qualified_name)
114
- name = parameters[:qualified_name].split('/').last
115
-
116
- parameters.merge(name:)
117
- end
118
- end
119
101
  end
120
102
  end
@@ -28,7 +28,7 @@ module Cuprum::Collections::Basic::Commands
28
28
  error = Cuprum::Collections::Errors::NotFound.new(
29
29
  attribute_name: primary_key_name,
30
30
  attribute_value: primary_key,
31
- collection_name:,
31
+ name:,
32
32
  primary_key: true
33
33
  )
34
34
  Cuprum::Result.new(error:)
@@ -10,36 +10,5 @@ module Cuprum::Collections::Basic::Commands
10
10
  # Command for finding multiple collection items by primary key.
11
11
  class FindMany < Cuprum::Collections::Basic::Command
12
12
  include Cuprum::Collections::Commands::AbstractFindMany
13
-
14
- # @!method call(primary_keys:, allow_partial: false, envelope: false)
15
- # Queries the collection for the items with the given primary keys.
16
- #
17
- # The command will find and return the entities with the given primary
18
- # keys. If any of the items are not found, the command will fail and
19
- # return a NotFound error. If the :allow_partial option is set, the
20
- # command will return a partial result unless none of the requested items
21
- # are found.
22
- #
23
- # When the :envelope option is true, the command wraps the items in a
24
- # Hash, using the name of the collection as the key.
25
- #
26
- # @param allow_partial [Boolean] If true, passes if any of the items are
27
- # found.
28
- # @param envelope [Boolean] If true, wraps the result value in a Hash.
29
- # @param primary_keys [Array] The primary keys of the requested items.
30
- #
31
- # @return [Cuprum::Result<Array<Hash{String, Object}>>] a result with the
32
- # requested items.
33
- validate :allow_partial, :boolean, optional: true
34
- validate :envelope, :boolean, optional: true
35
- validate :primary_keys
36
-
37
- private
38
-
39
- def items_with_primary_keys(items:)
40
- # :nocov:
41
- items.to_h { |item| [item[primary_key_name.to_s], item] }
42
- # :nocov:
43
- end
44
13
  end
45
14
  end
@@ -12,99 +12,5 @@ module Cuprum::Collections::Basic::Commands
12
12
  # Command for querying filtered, ordered data from a basic collection.
13
13
  class FindMatching < Cuprum::Collections::Basic::Command
14
14
  include Cuprum::Collections::Commands::AbstractFindMatching
15
-
16
- # @!method call(envelope: false, limit: nil, offset: nil, order: nil, scope: nil, where: nil, &block)
17
- # Queries the collection for items matching the given conditions.
18
- #
19
- # @param envelope [Boolean] If true, wraps the result value in a Hash.
20
- # @param limit [Integer] The maximum number of results to return.
21
- # @param offset [Integer] The initial ordered items to skip.
22
- # @param order [Array<String, Symbol>, Hash<{String, Symbol => Symbol}>]
23
- # The sort order of the returned items. Should be either an array of
24
- # attribute names or a hash of attribute names and directions.
25
- # @param scope [Cuprum::Collections::Basic::Query, nil] Optional scope for
26
- # the query. Items must match the scope as well as the :where filters.
27
- # @param where [Object] Additional filters for selecting data. The command
28
- # will only return data matching these filters.
29
- # @yield The given block is passed to a QueryBuilder, which converts the
30
- # block to query criteria and generates a new query using those
31
- # criteria.
32
- # @yieldreturn [Hash] The filters to apply to the query. The hash keys
33
- # should be the names of attributes or columns, and the corresponding
34
- # values should be either the literal value for that attribute or a
35
- # method call for a valid operation defined for the query.
36
- #
37
- # @example Querying all items in the collection.
38
- # command = FindMatching.new(collection_name: 'books', data: books)
39
- # command.call
40
- # #=> an enumerable iterating all items in the collection
41
- #
42
- # @example Querying all items matching some critera:
43
- # command.call { { author: 'Nnedi Okorafor' } }
44
- # #=> an enumerable iterating all items in the collection whose author
45
- # is 'Nnedi Okorafor'
46
- #
47
- # @example Ordering query results
48
- # command.call(order: :title) { { author: 'Nnedi Okorafor' } }
49
- # #=> an enumerable iterating all items in the collection whose author
50
- # # is 'Nnedi Okorafor', sorted by :title in ascending order
51
- #
52
- # @example Advanced filtering
53
- # command.call do
54
- # {
55
- # category: eq('Science Fiction and Fantasy'),
56
- # author: ne('J.R.R. Tolkien')
57
- # }
58
- # end
59
- # #=> an enumerable iterating all items in the collection whose category
60
- # # is 'Science Fiction and Fantasy', and whose author is not
61
- # # 'J.R.R. Tolkien'.
62
- #
63
- # @example Advanced ordering
64
- # order = { author: :asc, genre: :desc }
65
- # command.call(order: order) { { author: 'Nnedi Okorafor' } }
66
- # #=> an enumerable iterating all items in the collection whose author
67
- # # is 'Nnedi Okorafor', sorted first by :author in ascending order
68
- # # and within the same author by genre in descending order
69
- #
70
- # @example Filtering, ordering, and subsets
71
- # command.call(offset: 50, limit: 10, order: :author) do
72
- # { category: 'Science Fiction and Fantasy' }
73
- # end
74
- # #=> an enumerable iterating the 51st through 60th items in the
75
- # # collection whose category is 'Science Fiction and Fantasy', sorted
76
- # # by :author in ascending order.
77
- #
78
- # @example Wrapping the result in an envelope
79
- # command =
80
- # FindMatching.new(
81
- # collection_name: 'books',
82
- # data: books
83
- # )
84
- # command.call(envelope: true)
85
- # #=> {
86
- # 'books' => [] # an array containing the matching items
87
- # }
88
- #
89
- # @overload call(limit: nil, offset: nil, order: nil, &block)
90
- # When the :envelope option is false (default), the command returns an
91
- # Enumerator which can be iterated to return the matching items.
92
- #
93
- # @return [Cuprum::Result<Enumerator>] the matching items in the
94
- # specified order as an Enumerator.
95
- #
96
- # @overload call(limit: nil, offset: nil, order: nil, &block)
97
- # When the :envelope option is true, the command immediately evaluates
98
- # the query and wraps the resulting array in a Hash, using the name of
99
- # the collection as the key.
100
- #
101
- # @return [Cuprum::Result<Hash{String, Array<Hash{String, Object}>}>] a
102
- # hash with the collection name as key and the matching items as
103
- # value.
104
- validate :envelope, :boolean, optional: true
105
- validate :limit, Integer, optional: true
106
- validate :offset, Integer, optional: true
107
- validate :order
108
- validate :where
109
15
  end
110
16
  end
@@ -10,23 +10,5 @@ module Cuprum::Collections::Basic::Commands
10
10
  # Command for finding one collection item by primary key.
11
11
  class FindOne < Cuprum::Collections::Basic::Command
12
12
  include Cuprum::Collections::Commands::AbstractFindOne
13
-
14
- # @!method call(primary_key:, envelope: false)
15
- # Queries the collection for the item with the given primary key.
16
- #
17
- # The command will find and return the entity with the given primary key.
18
- # If the entity is not found, the command will fail and return a NotFound
19
- # error.
20
- #
21
- # When the :envelope option is true, the command wraps the item in a Hash,
22
- # using the singular name of the collection as the key.
23
- #
24
- # @param envelope [Boolean] If true, wraps the result value in a Hash.
25
- # @param primary_key [Object] The primary key of the requested item.
26
- #
27
- # @return [Cuprum::Result<Hash{String, Object}>] a result with the
28
- # requested item.
29
- validate :envelope, :boolean, optional: true
30
- validate :primary_key
31
13
  end
32
14
  end
@@ -31,7 +31,7 @@ module Cuprum::Collections::Basic::Commands
31
31
  error = Cuprum::Collections::Errors::AlreadyExists.new(
32
32
  attribute_name: primary_key_name,
33
33
  attribute_value: value,
34
- collection_name:,
34
+ name:,
35
35
  primary_key: true
36
36
  )
37
37
  failure(error)
@@ -31,7 +31,7 @@ module Cuprum::Collections::Basic::Commands
31
31
  error = Cuprum::Collections::Errors::NotFound.new(
32
32
  attribute_name: primary_key_name,
33
33
  attribute_value: entity[primary_key_name.to_s],
34
- collection_name:,
34
+ name:,
35
35
  primary_key: true
36
36
  )
37
37
  failure(error)
@@ -13,6 +13,40 @@ module Cuprum::Collections::Basic::Scopes
13
13
  Operators = Cuprum::Collections::Queries::Operators
14
14
  private_constant :Operators
15
15
 
16
+ FILTERS = {
17
+ Operators::EQUAL => lambda { |item, attribute, value|
18
+ item[attribute] == value
19
+ },
20
+ Operators::GREATER_THAN => lambda { |item, attribute, value|
21
+ item[attribute] > value
22
+ },
23
+ Operators::GREATER_THAN_OR_EQUAL_TO => lambda { |item, attribute, value|
24
+ item[attribute] >= value
25
+ },
26
+ Operators::LESS_THAN => lambda { |item, attribute, value|
27
+ item[attribute] < value
28
+ },
29
+ Operators::LESS_THAN_OR_EQUAL_TO => lambda { |item, attribute, value|
30
+ item[attribute] <= value
31
+ },
32
+ Operators::NOT_EQUAL => lambda { |item, attribute, value|
33
+ item[attribute] != value
34
+ },
35
+ Operators::NOT_NULL => lambda { |item, attribute, _value|
36
+ !item[attribute].nil?
37
+ },
38
+ Operators::NOT_ONE_OF => lambda { |item, attribute, value|
39
+ !value.include?(item[attribute])
40
+ },
41
+ Operators::NULL => lambda { |item, attribute, _value|
42
+ item[attribute].nil?
43
+ },
44
+ Operators::ONE_OF => lambda { |item, attribute, value|
45
+ value.include?(item[attribute])
46
+ }
47
+ }.freeze
48
+ private_constant :FILTERS
49
+
16
50
  # Returns true if the provided item matches the configured criteria.
17
51
  def match?(item:)
18
52
  super
@@ -31,27 +65,8 @@ module Cuprum::Collections::Basic::Scopes
31
65
 
32
66
  private
33
67
 
34
- def filter_for(operator) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
35
- case operator
36
- when Operators::EQUAL
37
- @eq_filter ||= ->(item, attribute, value) { item[attribute] == value }
38
- when Operators::GREATER_THAN
39
- @gt_filter ||= ->(item, attribute, value) { item[attribute] > value }
40
- when Operators::GREATER_THAN_OR_EQUAL_TO
41
- @gte_filter ||= ->(item, attribute, value) { item[attribute] >= value }
42
- when Operators::LESS_THAN
43
- @lt_filter ||= ->(item, attribute, value) { item[attribute] < value }
44
- when Operators::LESS_THAN_OR_EQUAL_TO
45
- @lte_filter ||= ->(item, attribute, value) { item[attribute] <= value }
46
- when Operators::NOT_EQUAL
47
- @ne_filter ||= ->(item, attribute, value) { item[attribute] != value }
48
- when Operators::NOT_ONE_OF
49
- @nin_filter ||=
50
- ->(item, attribute, value) { !value.include?(item[attribute]) }
51
- when Operators::ONE_OF
52
- @in_filter ||=
53
- ->(item, attribute, value) { value.include?(item[attribute]) }
54
- else
68
+ def filter_for(operator)
69
+ FILTERS.fetch(operator) do
55
70
  error_class = Cuprum::Collections::Queries::UnknownOperatorException
56
71
  message = %(unknown operator "#{operator}")
57
72
 
@@ -5,13 +5,14 @@ require 'cuprum/collections'
5
5
  module Cuprum::Collections
6
6
  # The Basic collection is an example, in-memory collection implementation.
7
7
  module Basic
8
- # Returns a new instance of Basic::Collection.
8
+ # @overload new(**options)
9
+ # Returns a new instance of Basic::Collection.
9
10
  #
10
- # @param options [Hash] Constructor options for the collection.
11
+ # @param options [Hash] Constructor options for the collection.
11
12
  #
12
- # @see Cuprum::Collections::Basic::Collection#initialize.
13
- def self.new(**options)
14
- Cuprum::Collections::Basic::Collection.new(**options)
13
+ # @see Cuprum::Collections::Basic::Collection#initialize.
14
+ def self.new(**)
15
+ Cuprum::Collections::Basic::Collection.new(**)
15
16
  end
16
17
 
17
18
  autoload :Collection, 'cuprum/collections/basic/collection'
@@ -66,6 +66,12 @@ module Cuprum::Collections
66
66
  )
67
67
  end
68
68
 
69
+ expected[:name] = expected[:name].to_s if expected[:name]
70
+
71
+ if expected[:qualified_name]
72
+ expected[:qualified_name] = expected[:qualified_name].to_s
73
+ end
74
+
69
75
  comparable_options >= expected
70
76
  end
71
77
 
@@ -46,7 +46,7 @@ module Cuprum::Collections
46
46
  collection.query
47
47
  end
48
48
 
49
- # @returnb [String] the name of an entity in the collection.
49
+ # @return [String] the name of an entity in the collection.
50
50
  def singular_name
51
51
  @singular_name ||= collection.singular_name
52
52
  end
@@ -1,11 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'cuprum/parameter_validation'
4
+ require 'stannum/constraints/boolean'
5
+
3
6
  require 'cuprum/collections/commands'
4
7
  require 'cuprum/collections/errors/not_found'
5
8
 
6
9
  module Cuprum::Collections::Commands
7
10
  # Abstract implementation of the FindMany command.
8
11
  module AbstractFindMany
12
+ include Cuprum::ParameterValidation
13
+
14
+ # @!method call(primary_keys:, allow_partial: false, envelope: false)
15
+ # Queries the collection for the items with the given primary keys.
16
+ #
17
+ # The command will find and return the entities with the given primary
18
+ # keys. If any of the items are not found, the command will fail and
19
+ # return a NotFound error. If the :allow_partial option is set, the
20
+ # command will return a partial result unless none of the requested items
21
+ # are found.
22
+ #
23
+ # When the :envelope option is true, the command wraps the items in a
24
+ # Hash, using the name of the collection as the key.
25
+ #
26
+ # @param allow_partial [Boolean] If true, passes if any of the items are
27
+ # found.
28
+ # @param envelope [Boolean] If true, wraps the result value in a Hash.
29
+ # @param primary_keys [Array] The primary keys of the requested items.
30
+ #
31
+ # @return [Cuprum::Result<Array<Hash{String, Object}>>] a result with the
32
+ # requested items.
33
+ validate :allow_partial, :boolean, optional: true
34
+ validate :envelope, :boolean, optional: true
35
+ validate :primary_keys
36
+
9
37
  private
10
38
 
11
39
  def apply_query(primary_keys:)
@@ -36,7 +64,16 @@ module Cuprum::Collections::Commands
36
64
 
37
65
  def items_with_primary_keys(items:)
38
66
  # :nocov:
39
- items.to_h { |item| [item.send(primary_key_name), item] }
67
+ items.to_h do |item|
68
+ primary_key_value =
69
+ if item.respond_to?(:[])
70
+ item[primary_key_name.to_s] || item[primary_key_name.to_sym]
71
+ else
72
+ item.send(primary_key_name)
73
+ end
74
+
75
+ [primary_key_value, item]
76
+ end
40
77
  # :nocov:
41
78
  end
42
79
 
@@ -44,7 +81,7 @@ module Cuprum::Collections::Commands
44
81
  Cuprum::Collections::Errors::NotFound.new(
45
82
  attribute_name: primary_key_name,
46
83
  attribute_value: primary_key_value,
47
- collection_name:,
84
+ name:,
48
85
  primary_key: true
49
86
  )
50
87
  end
@@ -62,7 +99,7 @@ module Cuprum::Collections::Commands
62
99
  end
63
100
 
64
101
  def wrap_items(items)
65
- { collection_name => items }
102
+ { name => items }
66
103
  end
67
104
  end
68
105
  end