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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/lib/cuprum/collections/adaptable/collection.rb +18 -0
- data/lib/cuprum/collections/adaptable/command.rb +22 -0
- data/lib/cuprum/collections/adaptable/commands/abstract_assign_one.rb +27 -0
- data/lib/cuprum/collections/adaptable/commands/abstract_build_one.rb +25 -0
- data/lib/cuprum/collections/adaptable/commands/abstract_validate_one.rb +35 -0
- data/lib/cuprum/collections/adaptable/commands.rb +15 -0
- data/lib/cuprum/collections/adaptable/query.rb +64 -0
- data/lib/cuprum/collections/adaptable.rb +13 -0
- data/lib/cuprum/collections/adapter.rb +300 -0
- data/lib/cuprum/collections/adapters/data_adapter.rb +82 -0
- data/lib/cuprum/collections/adapters/entity_adapter.rb +76 -0
- data/lib/cuprum/collections/adapters/hash_adapter.rb +48 -0
- data/lib/cuprum/collections/adapters.rb +14 -0
- data/lib/cuprum/collections/basic/collection.rb +2 -20
- data/lib/cuprum/collections/basic/commands/destroy_one.rb +1 -1
- data/lib/cuprum/collections/basic/commands/find_many.rb +0 -31
- data/lib/cuprum/collections/basic/commands/find_matching.rb +0 -94
- data/lib/cuprum/collections/basic/commands/find_one.rb +0 -18
- data/lib/cuprum/collections/basic/commands/insert_one.rb +1 -1
- data/lib/cuprum/collections/basic/commands/update_one.rb +1 -1
- data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +36 -21
- data/lib/cuprum/collections/basic.rb +6 -5
- data/lib/cuprum/collections/collection.rb +6 -0
- data/lib/cuprum/collections/collection_command.rb +1 -1
- data/lib/cuprum/collections/commands/abstract_find_many.rb +40 -3
- data/lib/cuprum/collections/commands/abstract_find_matching.rb +102 -0
- data/lib/cuprum/collections/commands/abstract_find_one.rb +23 -1
- data/lib/cuprum/collections/commands/associations/find_many.rb +1 -3
- data/lib/cuprum/collections/commands/associations/require_many.rb +1 -1
- data/lib/cuprum/collections/commands/find_one_matching.rb +10 -10
- data/lib/cuprum/collections/commands/query_command.rb +6 -4
- data/lib/cuprum/collections/commands/upsert.rb +0 -2
- data/lib/cuprum/collections/constraints/order/attributes_array.rb +5 -4
- data/lib/cuprum/collections/constraints/order/attributes_hash.rb +5 -4
- data/lib/cuprum/collections/constraints/order/sort_direction.rb +2 -2
- data/lib/cuprum/collections/constraints/ordering.rb +11 -9
- data/lib/cuprum/collections/constraints/query_hash.rb +2 -2
- data/lib/cuprum/collections/errors/abstract_find_error.rb +101 -23
- data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
- data/lib/cuprum/collections/errors/failed_validation.rb +3 -3
- data/lib/cuprum/collections/errors/missing_default_contract.rb +12 -4
- data/lib/cuprum/collections/queries.rb +4 -0
- data/lib/cuprum/collections/relation.rb +0 -2
- data/lib/cuprum/collections/relations/parameters.rb +120 -68
- data/lib/cuprum/collections/repository.rb +71 -6
- data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +23 -4
- data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +18 -0
- data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +51 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +10 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +8 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +18 -366
- data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +30 -0
- data/lib/cuprum/collections/rspec/contracts/scopes.rb +2 -0
- data/lib/cuprum/collections/rspec/contracts.rb +2 -10
- data/lib/cuprum/collections/rspec/deferred/adapter_examples.rb +1077 -0
- data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +27 -7
- data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +4 -4
- data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +2 -2
- data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +2 -2
- data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +5 -5
- data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +45 -12
- data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +2 -2
- data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +1 -1
- data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +1 -1
- data/lib/cuprum/collections/rspec/deferred/query_examples.rb +930 -0
- data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +48 -17
- data/lib/cuprum/collections/rspec/deferred/repository_examples.rb +961 -0
- data/lib/cuprum/collections/rspec/deferred/scope_examples.rb +598 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/all_examples.rb +391 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/builder_examples.rb +857 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/composition_examples.rb +93 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/conjunction_examples.rb +438 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/criteria_examples.rb +1941 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/disjunction_examples.rb +415 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/none_examples.rb +385 -0
- data/lib/cuprum/collections/rspec/deferred/scopes/parser_examples.rb +740 -0
- data/lib/cuprum/collections/rspec/deferred/scopes.rb +8 -0
- data/lib/cuprum/collections/scope.rb +2 -2
- data/lib/cuprum/collections/scopes/container.rb +5 -4
- data/lib/cuprum/collections/scopes/criteria/parser.rb +24 -48
- data/lib/cuprum/collections/scopes/criteria.rb +7 -6
- data/lib/cuprum/collections/version.rb +4 -4
- data/lib/cuprum/collections.rb +5 -1
- metadata +47 -11
- data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +0 -2127
- data/lib/cuprum/collections/rspec/contracts/basic.rb +0 -11
- data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +0 -387
- data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +0 -169
- 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(**
|
|
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
|
|
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
|
|
@@ -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::NotFound.new(
|
|
32
32
|
attribute_name: primary_key_name,
|
|
33
33
|
attribute_value: entity[primary_key_name.to_s],
|
|
34
|
-
|
|
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)
|
|
35
|
-
|
|
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
|
-
#
|
|
8
|
+
# @overload new(**options)
|
|
9
|
+
# Returns a new instance of Basic::Collection.
|
|
9
10
|
#
|
|
10
|
-
#
|
|
11
|
+
# @param options [Hash] Constructor options for the collection.
|
|
11
12
|
#
|
|
12
|
-
#
|
|
13
|
-
def self.new(**
|
|
14
|
-
Cuprum::Collections::Basic::Collection.new(**
|
|
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
|
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
{
|
|
102
|
+
{ name => items }
|
|
66
103
|
end
|
|
67
104
|
end
|
|
68
105
|
end
|