cuprum-collections 0.1.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 (72) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +59 -0
  3. data/CODE_OF_CONDUCT.md +132 -0
  4. data/DEVELOPMENT.md +25 -0
  5. data/LICENSE +22 -0
  6. data/README.md +950 -0
  7. data/lib/cuprum/collections/base.rb +11 -0
  8. data/lib/cuprum/collections/basic/collection.rb +135 -0
  9. data/lib/cuprum/collections/basic/command.rb +112 -0
  10. data/lib/cuprum/collections/basic/commands/assign_one.rb +54 -0
  11. data/lib/cuprum/collections/basic/commands/build_one.rb +45 -0
  12. data/lib/cuprum/collections/basic/commands/destroy_one.rb +48 -0
  13. data/lib/cuprum/collections/basic/commands/find_many.rb +65 -0
  14. data/lib/cuprum/collections/basic/commands/find_matching.rb +126 -0
  15. data/lib/cuprum/collections/basic/commands/find_one.rb +49 -0
  16. data/lib/cuprum/collections/basic/commands/insert_one.rb +50 -0
  17. data/lib/cuprum/collections/basic/commands/update_one.rb +52 -0
  18. data/lib/cuprum/collections/basic/commands/validate_one.rb +69 -0
  19. data/lib/cuprum/collections/basic/commands.rb +18 -0
  20. data/lib/cuprum/collections/basic/query.rb +160 -0
  21. data/lib/cuprum/collections/basic/query_builder.rb +69 -0
  22. data/lib/cuprum/collections/basic/rspec/command_contract.rb +392 -0
  23. data/lib/cuprum/collections/basic/rspec.rb +8 -0
  24. data/lib/cuprum/collections/basic.rb +22 -0
  25. data/lib/cuprum/collections/command.rb +26 -0
  26. data/lib/cuprum/collections/commands/abstract_find_many.rb +77 -0
  27. data/lib/cuprum/collections/commands/abstract_find_matching.rb +64 -0
  28. data/lib/cuprum/collections/commands/abstract_find_one.rb +44 -0
  29. data/lib/cuprum/collections/commands.rb +8 -0
  30. data/lib/cuprum/collections/constraints/attribute_name.rb +22 -0
  31. data/lib/cuprum/collections/constraints/order/attributes_array.rb +26 -0
  32. data/lib/cuprum/collections/constraints/order/attributes_hash.rb +27 -0
  33. data/lib/cuprum/collections/constraints/order/complex_ordering.rb +46 -0
  34. data/lib/cuprum/collections/constraints/order/sort_direction.rb +32 -0
  35. data/lib/cuprum/collections/constraints/order.rb +8 -0
  36. data/lib/cuprum/collections/constraints/ordering.rb +114 -0
  37. data/lib/cuprum/collections/constraints/query_hash.rb +25 -0
  38. data/lib/cuprum/collections/constraints.rb +8 -0
  39. data/lib/cuprum/collections/errors/already_exists.rb +86 -0
  40. data/lib/cuprum/collections/errors/extra_attributes.rb +66 -0
  41. data/lib/cuprum/collections/errors/failed_validation.rb +66 -0
  42. data/lib/cuprum/collections/errors/invalid_parameters.rb +50 -0
  43. data/lib/cuprum/collections/errors/invalid_query.rb +55 -0
  44. data/lib/cuprum/collections/errors/missing_default_contract.rb +49 -0
  45. data/lib/cuprum/collections/errors/not_found.rb +81 -0
  46. data/lib/cuprum/collections/errors/unknown_operator.rb +71 -0
  47. data/lib/cuprum/collections/errors.rb +8 -0
  48. data/lib/cuprum/collections/queries/ordering.rb +74 -0
  49. data/lib/cuprum/collections/queries/parse.rb +22 -0
  50. data/lib/cuprum/collections/queries/parse_block.rb +206 -0
  51. data/lib/cuprum/collections/queries/parse_strategy.rb +91 -0
  52. data/lib/cuprum/collections/queries.rb +25 -0
  53. data/lib/cuprum/collections/query.rb +247 -0
  54. data/lib/cuprum/collections/query_builder.rb +61 -0
  55. data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +168 -0
  56. data/lib/cuprum/collections/rspec/build_one_command_contract.rb +93 -0
  57. data/lib/cuprum/collections/rspec/collection_contract.rb +153 -0
  58. data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +106 -0
  59. data/lib/cuprum/collections/rspec/find_many_command_contract.rb +327 -0
  60. data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +194 -0
  61. data/lib/cuprum/collections/rspec/find_one_command_contract.rb +154 -0
  62. data/lib/cuprum/collections/rspec/fixtures.rb +89 -0
  63. data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +83 -0
  64. data/lib/cuprum/collections/rspec/query_builder_contract.rb +92 -0
  65. data/lib/cuprum/collections/rspec/query_contract.rb +650 -0
  66. data/lib/cuprum/collections/rspec/querying_contract.rb +298 -0
  67. data/lib/cuprum/collections/rspec/update_one_command_contract.rb +79 -0
  68. data/lib/cuprum/collections/rspec/validate_one_command_contract.rb +96 -0
  69. data/lib/cuprum/collections/rspec.rb +8 -0
  70. data/lib/cuprum/collections/version.rb +59 -0
  71. data/lib/cuprum/collections.rb +26 -0
  72. metadata +219 -0
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/command_factory'
4
+
5
+ require 'cuprum/collections'
6
+
7
+ module Cuprum::Collections
8
+ # Abstract base class for Collection factories.
9
+ class Base < Cuprum::CommandFactory
10
+ end
11
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/command_factory'
4
+
5
+ require 'cuprum/collections/basic'
6
+ require 'cuprum/collections/basic/commands'
7
+
8
+ module Cuprum::Collections::Basic
9
+ # Wraps an in-memory array of hashes data store as a Cuprum collection.
10
+ class Collection < Cuprum::CommandFactory
11
+ # @param collection_name [String, Symbol] The name of the collection.
12
+ # @param data [Array<Hash>] The current data in the collection.
13
+ # @param default_contract [Stannum::Constraints::Base, nil] The default
14
+ # contract for validating items in the collection.
15
+ # @param member_name [String] The name of a collection entity.
16
+ # @param primary_key_name [Symbol] The name of the primary key attribute.
17
+ # Defaults to :id.
18
+ # @param primary_key_type [Class, Stannum::Constraint] The type of the
19
+ # primary key attribute. Defaults to Integer.
20
+ # @param options [Hash<Symbol>] Additional options for the command.
21
+ def initialize( # rubocop:disable Metrics/ParameterLists
22
+ collection_name:,
23
+ data:,
24
+ default_contract: nil,
25
+ member_name: nil,
26
+ primary_key_name: :id,
27
+ primary_key_type: Integer,
28
+ **options
29
+ )
30
+ super()
31
+
32
+ @collection_name = collection_name.to_s
33
+ @data = data
34
+ @default_contract = default_contract
35
+ @member_name =
36
+ member_name ? member_name.to_s : tools.str.singularize(@collection_name)
37
+ @options = options
38
+ @primary_key_name = primary_key_name
39
+ @primary_key_type = primary_key_type
40
+ end
41
+
42
+ # @return [String] the name of the collection.
43
+ attr_reader :collection_name
44
+
45
+ # @return [Array<Hash>] the current data in the collection.
46
+ attr_reader :data
47
+
48
+ # @return [Stannum::Constraints::Base, nil] the default contract for
49
+ # validating items in the collection.
50
+ attr_reader :default_contract
51
+
52
+ # @return [String] the name of a collection entity.
53
+ attr_reader :member_name
54
+
55
+ # @return [Hash<Symbol>] additional options for the command.
56
+ attr_reader :options
57
+
58
+ # @return [Symbol] the name of the primary key attribute.
59
+ attr_reader :primary_key_name
60
+
61
+ # @return [Class, Stannum::Constraint] the type of the primary key
62
+ # attribute.
63
+ attr_reader :primary_key_type
64
+
65
+ command_class :assign_one do
66
+ Cuprum::Collections::Basic::Commands::AssignOne
67
+ .subclass(**command_options)
68
+ end
69
+
70
+ command_class :build_one do
71
+ Cuprum::Collections::Basic::Commands::BuildOne
72
+ .subclass(**command_options)
73
+ end
74
+
75
+ command_class :destroy_one do
76
+ Cuprum::Collections::Basic::Commands::DestroyOne
77
+ .subclass(**command_options)
78
+ end
79
+
80
+ command_class :find_many do
81
+ Cuprum::Collections::Basic::Commands::FindMany
82
+ .subclass(**command_options)
83
+ end
84
+
85
+ command_class :find_matching do
86
+ Cuprum::Collections::Basic::Commands::FindMatching
87
+ .subclass(**command_options)
88
+ end
89
+
90
+ command_class :find_one do
91
+ Cuprum::Collections::Basic::Commands::FindOne
92
+ .subclass(**command_options)
93
+ end
94
+
95
+ command_class :insert_one do
96
+ Cuprum::Collections::Basic::Commands::InsertOne
97
+ .subclass(**command_options)
98
+ end
99
+
100
+ command_class :update_one do
101
+ Cuprum::Collections::Basic::Commands::UpdateOne
102
+ .subclass(**command_options)
103
+ end
104
+
105
+ command_class :validate_one do
106
+ Cuprum::Collections::Basic::Commands::ValidateOne
107
+ .subclass(**command_options)
108
+ end
109
+
110
+ # A new Query instance, used for querying against the collection data.
111
+ #
112
+ # @return [Cuprum::Collections::Basic::Query] the query.
113
+ def query
114
+ Cuprum::Collections::Basic::Query.new(data)
115
+ end
116
+
117
+ private
118
+
119
+ def command_options
120
+ @command_options ||= {
121
+ collection_name: collection_name,
122
+ data: data,
123
+ default_contract: default_contract,
124
+ member_name: member_name,
125
+ primary_key_name: primary_key_name,
126
+ primary_key_type: primary_key_type,
127
+ **options
128
+ }
129
+ end
130
+
131
+ def tools
132
+ SleepingKingStudios::Tools::Toolbelt.instance
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stannum/constraints/types/array_type'
4
+
5
+ require 'cuprum/collections/basic'
6
+
7
+ module Cuprum::Collections::Basic
8
+ # Abstract base class for basic collection commands.
9
+ class Command < Cuprum::Collections::Command
10
+ # Creates a subclass with the given parameters applied to the constructor.
11
+ def self.subclass(**default_options)
12
+ Class.new(self) do
13
+ define_method(:initialize) do |**options|
14
+ super(**default_options.merge(options))
15
+ end
16
+ end
17
+ end
18
+
19
+ # @param collection_name [String, Symbol] The name of the collection.
20
+ # @param data [Array<Hash>] The current data in the collection.
21
+ # @param default_contract [Stannum::Constraints::Base, nil] The default
22
+ # contract for validating items in the collection.
23
+ # @param member_name [String] The name of a collection entity.
24
+ # @param primary_key_name [Symbol] The name of the primary key attribute.
25
+ # Defaults to :id.
26
+ # @param primary_key_type [Class, Stannum::Constraint] The type of the
27
+ # primary key attribute. Defaults to Integer.
28
+ # @param options [Hash<Symbol>] Additional options for the command.
29
+ def initialize( # rubocop:disable Metrics/ParameterLists
30
+ collection_name:,
31
+ data:,
32
+ default_contract: nil,
33
+ member_name: nil,
34
+ primary_key_name: :id,
35
+ primary_key_type: Integer,
36
+ **options
37
+ )
38
+ super()
39
+
40
+ @collection_name = collection_name.to_s
41
+ @data = data
42
+ @default_contract = default_contract
43
+ @member_name =
44
+ member_name ? member_name.to_s : tools.str.singularize(@collection_name)
45
+ @options = options
46
+ @primary_key_name = primary_key_name
47
+ @primary_key_type = primary_key_type
48
+ end
49
+
50
+ # @return [String] the name of the collection.
51
+ attr_reader :collection_name
52
+
53
+ # @return [Array<Hash>] the current data in the collection.
54
+ attr_reader :data
55
+
56
+ # @return [Stannum::Constraints::Base, nil] the default contract for
57
+ # validating items in the collection.
58
+ attr_reader :default_contract
59
+
60
+ # @return [String] the name of a collection entity.
61
+ attr_reader :member_name
62
+
63
+ # @return [Hash<Symbol>] additional options for the command.
64
+ attr_reader :options
65
+
66
+ # @return [Symbol] the name of the primary key attribute.
67
+ attr_reader :primary_key_name
68
+
69
+ # @return [Class, Stannum::Constraint] the type of the primary key
70
+ # attribute.
71
+ attr_reader :primary_key_type
72
+
73
+ private
74
+
75
+ def primary_key_contract
76
+ type = primary_key_type
77
+
78
+ @primary_key_contract ||= Stannum::Contracts::ParametersContract.new do
79
+ keyword :primary_key, type
80
+ end
81
+ end
82
+
83
+ def primary_keys_contract
84
+ type = primary_key_type
85
+
86
+ @primary_keys_contract ||= Stannum::Contracts::ParametersContract.new do
87
+ keyword :primary_keys,
88
+ Stannum::Constraints::Types::ArrayType.new(item_type: type)
89
+ end
90
+ end
91
+
92
+ def tools
93
+ SleepingKingStudios::Tools::Toolbelt.instance
94
+ end
95
+
96
+ def validate_primary_key(primary_key)
97
+ match_parameters_to_contract(
98
+ contract: primary_key_contract,
99
+ keywords: { primary_key: primary_key },
100
+ method_name: :call
101
+ )
102
+ end
103
+
104
+ def validate_primary_keys(primary_keys)
105
+ match_parameters_to_contract(
106
+ contract: primary_keys_contract,
107
+ keywords: { primary_keys: primary_keys },
108
+ method_name: :call
109
+ )
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stannum/constraints/types/hash_with_indifferent_keys'
4
+ require 'stannum/constraints/types/hash_with_string_keys'
5
+
6
+ require 'cuprum/collections/basic/command'
7
+ require 'cuprum/collections/basic/commands'
8
+
9
+ module Cuprum::Collections::Basic::Commands
10
+ # Command for assigning attributes to a collection entity.
11
+ class AssignOne < Cuprum::Collections::Basic::Command
12
+ # @!method call(attributes:, entity:)
13
+ # Assigns the given attributes to the entity.
14
+ #
15
+ # Any attributes on the entity that are not part of the given attributes
16
+ # hash are unchanged.
17
+ #
18
+ # @param attributes [Hash] The attributes and values to update.
19
+ # @param entity [Hash] The collection entity to update.
20
+ #
21
+ # @return [Hash] a copy of the entity, merged with the given attributes.
22
+ #
23
+ # @example Assigning attributes
24
+ # entity = {
25
+ # 'title' => 'The Hobbit',
26
+ # 'author' => 'J.R.R. Tolkien',
27
+ # 'series' => nil,
28
+ # 'category' => 'Science Fiction and Fantasy'
29
+ # }
30
+ # attributes = { title: 'The Silmarillion' }
31
+ # command = AssignOne.new(collection_name: 'books', data: books)
32
+ # command.call(attributes: attributes, entity: entity)
33
+ # #=> {
34
+ # 'title' => 'The Silmarillion',
35
+ # 'author' => 'J.R.R. Tolkien',
36
+ # 'series' => nil,
37
+ # 'category' => 'Science Fiction and Fantasy'
38
+ # }
39
+ validate_parameters :call do
40
+ keyword :attributes,
41
+ Stannum::Constraints::Types::HashWithIndifferentKeys.new
42
+ keyword :entity,
43
+ Stannum::Constraints::Types::HashWithStringKeys.new
44
+ end
45
+
46
+ private
47
+
48
+ def process(attributes:, entity:)
49
+ attributes = tools.hsh.convert_keys_to_strings(attributes)
50
+
51
+ entity.merge(attributes)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stannum/constraints/types/hash_with_indifferent_keys'
4
+
5
+ require 'cuprum/collections/basic/command'
6
+ require 'cuprum/collections/basic/commands'
7
+
8
+ module Cuprum::Collections::Basic::Commands
9
+ # Command for generating a collection entity from an attributes hash.
10
+ class BuildOne < Cuprum::Collections::Basic::Command
11
+ # @!method call(attributes:, entity:)
12
+ # Builds a new entity with the given attributes.
13
+ #
14
+ # @param attributes [Hash] The attributes and values to assign.
15
+ #
16
+ # @return [Hash] the newly built entity.
17
+ #
18
+ # @example Building an entity
19
+ # attributes = {
20
+ # 'title' => 'The Hobbit',
21
+ # 'author' => 'J.R.R. Tolkien',
22
+ # 'series' => nil,
23
+ # 'category' => 'Science Fiction and Fantasy'
24
+ # }
25
+ # command = BuildOne.new(collection_name: 'books', data: books)
26
+ # result = command.call(attributes: attributes)
27
+ # result.value
28
+ # #=> {
29
+ # 'title' => 'The Silmarillion',
30
+ # 'author' => 'J.R.R. Tolkien',
31
+ # 'series' => nil,
32
+ # 'category' => 'Science Fiction and Fantasy'
33
+ # }
34
+ validate_parameters :call do
35
+ keyword :attributes,
36
+ Stannum::Constraints::Types::HashWithIndifferentKeys.new
37
+ end
38
+
39
+ private
40
+
41
+ def process(attributes:)
42
+ tools.hsh.convert_keys_to_strings(attributes)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/basic/command'
4
+ require 'cuprum/collections/basic/commands'
5
+ require 'cuprum/collections/errors/not_found'
6
+
7
+ module Cuprum::Collections::Basic::Commands
8
+ # Command for destroying one collection item by primary key.
9
+ class DestroyOne < Cuprum::Collections::Basic::Command
10
+ # @!method call(primary_key:)
11
+ # Finds and destroys the item with the given primary key.
12
+ #
13
+ # The command will find the entity with the given primary key and remove
14
+ # it from the collection. If the entity is not found, the command will
15
+ # fail and return a NotFound error.
16
+ #
17
+ # @param primary_key [Object] The primary key of the requested item.
18
+ #
19
+ # @return [Cuprum::Result<Hash{String, Object}>] a result with the
20
+ # destroyed item.
21
+ validate_parameters :call do
22
+ keyword :primary_key, Object
23
+ end
24
+
25
+ private
26
+
27
+ def handle_missing_item(index:, primary_key:)
28
+ return if index
29
+
30
+ error = Cuprum::Collections::Errors::NotFound.new(
31
+ collection_name: collection_name,
32
+ primary_key_name: primary_key_name,
33
+ primary_key_values: [primary_key]
34
+ )
35
+ Cuprum::Result.new(error: error)
36
+ end
37
+
38
+ def process(primary_key:)
39
+ step { validate_primary_key(primary_key) }
40
+
41
+ index = data.index { |item| item[primary_key_name.to_s] == primary_key }
42
+
43
+ step { handle_missing_item(index: index, primary_key: primary_key) }
44
+
45
+ data.delete_at(index)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stannum/constraints/boolean'
4
+
5
+ require 'cuprum/collections/basic/command'
6
+ require 'cuprum/collections/basic/commands'
7
+ require 'cuprum/collections/commands/abstract_find_many'
8
+
9
+ module Cuprum::Collections::Basic::Commands
10
+ # Command for finding multiple collection items by primary key.
11
+ class FindMany < Cuprum::Collections::Basic::Command
12
+ include Cuprum::Collections::Commands::AbstractFindMany
13
+
14
+ # @!method call(primary_keys:, allow_partial: false, envelope: false, scope: nil) # rubocop:disable Layout/LineLength
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
+ # @param scope [Cuprum::Collections::Basic::Query, nil] Optional scope for
31
+ # the query. Items must match the scope as well as the primary keys.
32
+ #
33
+ # @return [Cuprum::Result<Array<Hash{String, Object}>>] a result with the
34
+ # requested items.
35
+ validate_parameters :call do
36
+ keyword :allow_partial, Stannum::Constraints::Boolean.new, default: true
37
+ keyword :envelope, Stannum::Constraints::Boolean.new, default: true
38
+ keyword :primary_keys, Array
39
+ keyword :scope, Cuprum::Collections::Basic::Query, optional: true
40
+ end
41
+
42
+ private
43
+
44
+ def build_query
45
+ Cuprum::Collections::Basic::Query.new(data)
46
+ end
47
+
48
+ def items_with_primary_keys(items:)
49
+ # :nocov:
50
+ items.map { |item| [item[primary_key_name.to_s], item] }.to_h
51
+ # :nocov:
52
+ end
53
+
54
+ def process(
55
+ primary_keys:,
56
+ allow_partial: false,
57
+ envelope: false,
58
+ scope: nil
59
+ )
60
+ step { validate_primary_keys(primary_keys) }
61
+
62
+ super
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stannum/constraints/boolean'
4
+
5
+ require 'cuprum/collections/basic/command'
6
+ require 'cuprum/collections/basic/commands'
7
+ require 'cuprum/collections/basic/query'
8
+ require 'cuprum/collections/commands/abstract_find_matching'
9
+ require 'cuprum/collections/constraints/ordering'
10
+
11
+ module Cuprum::Collections::Basic::Commands
12
+ # Command for querying filtered, ordered data from a basic collection.
13
+ class FindMatching < Cuprum::Collections::Basic::Command
14
+ include Cuprum::Collections::Commands::AbstractFindMatching
15
+
16
+ # @!method call(envelope: false, limit: nil, offset: nil, order: nil, scope: nil, where: nil, &block) # rubocop:disable Layout/LineLength
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
+
105
+ validate_parameters :call do
106
+ keyword :envelope,
107
+ Stannum::Constraints::Boolean.new,
108
+ default: true
109
+ keyword :limit, Integer, optional: true
110
+ keyword :offset, Integer, optional: true
111
+ keyword :order,
112
+ Cuprum::Collections::Constraints::Ordering.new,
113
+ optional: true
114
+ keyword :scope,
115
+ Cuprum::Collections::Basic::Query,
116
+ optional: true
117
+ keyword :where, Object, optional: true
118
+ end
119
+
120
+ private
121
+
122
+ def build_query
123
+ Cuprum::Collections::Basic::Query.new(data)
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stannum/constraints/boolean'
4
+
5
+ require 'cuprum/collections/basic/command'
6
+ require 'cuprum/collections/basic/commands'
7
+ require 'cuprum/collections/commands/abstract_find_one'
8
+
9
+ module Cuprum::Collections::Basic::Commands
10
+ # Command for finding one collection item by primary key.
11
+ class FindOne < Cuprum::Collections::Basic::Command
12
+ include Cuprum::Collections::Commands::AbstractFindOne
13
+
14
+ # @!method call(primary_key:, envelope: false, scope: nil)
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
+ # @param scope [Cuprum::Collections::Basic::Query, nil] Optional scope for
27
+ # the query. The item must match the scope as well as the primary key.
28
+ #
29
+ # @return [Cuprum::Result<Hash{String, Object}>] a result with the
30
+ # requested item.
31
+ validate_parameters :call do
32
+ keyword :envelope, Stannum::Constraints::Boolean.new, default: true
33
+ keyword :primary_key, Object
34
+ keyword :scope, Cuprum::Collections::Basic::Query, optional: true
35
+ end
36
+
37
+ private
38
+
39
+ def build_query
40
+ Cuprum::Collections::Basic::Query.new(data)
41
+ end
42
+
43
+ def process(primary_key:, envelope: false, scope: nil)
44
+ step { validate_primary_key(primary_key) }
45
+
46
+ super
47
+ end
48
+ end
49
+ end