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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +59 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/DEVELOPMENT.md +25 -0
- data/LICENSE +22 -0
- data/README.md +950 -0
- data/lib/cuprum/collections/base.rb +11 -0
- data/lib/cuprum/collections/basic/collection.rb +135 -0
- data/lib/cuprum/collections/basic/command.rb +112 -0
- data/lib/cuprum/collections/basic/commands/assign_one.rb +54 -0
- data/lib/cuprum/collections/basic/commands/build_one.rb +45 -0
- data/lib/cuprum/collections/basic/commands/destroy_one.rb +48 -0
- data/lib/cuprum/collections/basic/commands/find_many.rb +65 -0
- data/lib/cuprum/collections/basic/commands/find_matching.rb +126 -0
- data/lib/cuprum/collections/basic/commands/find_one.rb +49 -0
- data/lib/cuprum/collections/basic/commands/insert_one.rb +50 -0
- data/lib/cuprum/collections/basic/commands/update_one.rb +52 -0
- data/lib/cuprum/collections/basic/commands/validate_one.rb +69 -0
- data/lib/cuprum/collections/basic/commands.rb +18 -0
- data/lib/cuprum/collections/basic/query.rb +160 -0
- data/lib/cuprum/collections/basic/query_builder.rb +69 -0
- data/lib/cuprum/collections/basic/rspec/command_contract.rb +392 -0
- data/lib/cuprum/collections/basic/rspec.rb +8 -0
- data/lib/cuprum/collections/basic.rb +22 -0
- data/lib/cuprum/collections/command.rb +26 -0
- data/lib/cuprum/collections/commands/abstract_find_many.rb +77 -0
- data/lib/cuprum/collections/commands/abstract_find_matching.rb +64 -0
- data/lib/cuprum/collections/commands/abstract_find_one.rb +44 -0
- data/lib/cuprum/collections/commands.rb +8 -0
- data/lib/cuprum/collections/constraints/attribute_name.rb +22 -0
- data/lib/cuprum/collections/constraints/order/attributes_array.rb +26 -0
- data/lib/cuprum/collections/constraints/order/attributes_hash.rb +27 -0
- data/lib/cuprum/collections/constraints/order/complex_ordering.rb +46 -0
- data/lib/cuprum/collections/constraints/order/sort_direction.rb +32 -0
- data/lib/cuprum/collections/constraints/order.rb +8 -0
- data/lib/cuprum/collections/constraints/ordering.rb +114 -0
- data/lib/cuprum/collections/constraints/query_hash.rb +25 -0
- data/lib/cuprum/collections/constraints.rb +8 -0
- data/lib/cuprum/collections/errors/already_exists.rb +86 -0
- data/lib/cuprum/collections/errors/extra_attributes.rb +66 -0
- data/lib/cuprum/collections/errors/failed_validation.rb +66 -0
- data/lib/cuprum/collections/errors/invalid_parameters.rb +50 -0
- data/lib/cuprum/collections/errors/invalid_query.rb +55 -0
- data/lib/cuprum/collections/errors/missing_default_contract.rb +49 -0
- data/lib/cuprum/collections/errors/not_found.rb +81 -0
- data/lib/cuprum/collections/errors/unknown_operator.rb +71 -0
- data/lib/cuprum/collections/errors.rb +8 -0
- data/lib/cuprum/collections/queries/ordering.rb +74 -0
- data/lib/cuprum/collections/queries/parse.rb +22 -0
- data/lib/cuprum/collections/queries/parse_block.rb +206 -0
- data/lib/cuprum/collections/queries/parse_strategy.rb +91 -0
- data/lib/cuprum/collections/queries.rb +25 -0
- data/lib/cuprum/collections/query.rb +247 -0
- data/lib/cuprum/collections/query_builder.rb +61 -0
- data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +168 -0
- data/lib/cuprum/collections/rspec/build_one_command_contract.rb +93 -0
- data/lib/cuprum/collections/rspec/collection_contract.rb +153 -0
- data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +106 -0
- data/lib/cuprum/collections/rspec/find_many_command_contract.rb +327 -0
- data/lib/cuprum/collections/rspec/find_matching_command_contract.rb +194 -0
- data/lib/cuprum/collections/rspec/find_one_command_contract.rb +154 -0
- data/lib/cuprum/collections/rspec/fixtures.rb +89 -0
- data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +83 -0
- data/lib/cuprum/collections/rspec/query_builder_contract.rb +92 -0
- data/lib/cuprum/collections/rspec/query_contract.rb +650 -0
- data/lib/cuprum/collections/rspec/querying_contract.rb +298 -0
- data/lib/cuprum/collections/rspec/update_one_command_contract.rb +79 -0
- data/lib/cuprum/collections/rspec/validate_one_command_contract.rb +96 -0
- data/lib/cuprum/collections/rspec.rb +8 -0
- data/lib/cuprum/collections/version.rb +59 -0
- data/lib/cuprum/collections.rb +26 -0
- metadata +219 -0
@@ -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
|