cuprum-collections 0.4.0 → 0.5.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 +73 -0
- data/README.md +5 -5
- data/lib/cuprum/collections/association.rb +9 -28
- data/lib/cuprum/collections/associations/belongs_to.rb +1 -8
- data/lib/cuprum/collections/associations/has_many.rb +1 -10
- data/lib/cuprum/collections/associations/has_one.rb +1 -10
- data/lib/cuprum/collections/basic/collection.rb +56 -49
- data/lib/cuprum/collections/basic/command.rb +22 -88
- data/lib/cuprum/collections/basic/commands/assign_one.rb +2 -6
- data/lib/cuprum/collections/basic/commands/build_one.rb +1 -4
- data/lib/cuprum/collections/basic/commands/destroy_one.rb +4 -8
- data/lib/cuprum/collections/basic/commands/find_many.rb +4 -24
- data/lib/cuprum/collections/basic/commands/find_matching.rb +5 -21
- data/lib/cuprum/collections/basic/commands/find_one.rb +3 -20
- data/lib/cuprum/collections/basic/commands/insert_one.rb +3 -6
- data/lib/cuprum/collections/basic/commands/update_one.rb +3 -6
- data/lib/cuprum/collections/basic/commands/validate_one.rb +13 -18
- data/lib/cuprum/collections/basic/query.rb +26 -40
- data/lib/cuprum/collections/basic/repository.rb +4 -3
- data/lib/cuprum/collections/basic/scopes/all_scope.rb +25 -0
- data/lib/cuprum/collections/basic/scopes/base.rb +32 -0
- data/lib/cuprum/collections/basic/scopes/builder.rb +39 -0
- data/lib/cuprum/collections/basic/scopes/conjunction_scope.rb +20 -0
- data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +62 -0
- data/lib/cuprum/collections/basic/scopes/disjunction_scope.rb +20 -0
- data/lib/cuprum/collections/basic/scopes/none_scope.rb +33 -0
- data/lib/cuprum/collections/basic/scopes.rb +23 -0
- data/lib/cuprum/collections/basic.rb +1 -0
- data/lib/cuprum/collections/collection.rb +24 -82
- data/lib/cuprum/collections/collection_command.rb +116 -0
- data/lib/cuprum/collections/commands/abstract_find_many.rb +11 -21
- data/lib/cuprum/collections/commands/abstract_find_matching.rb +43 -24
- data/lib/cuprum/collections/commands/abstract_find_one.rb +7 -10
- data/lib/cuprum/collections/commands/associations/find_many.rb +3 -8
- data/lib/cuprum/collections/commands/associations/require_many.rb +5 -5
- data/lib/cuprum/collections/commands/create.rb +3 -3
- data/lib/cuprum/collections/commands/find_one_matching.rb +6 -6
- data/lib/cuprum/collections/commands/query_command.rb +19 -0
- data/lib/cuprum/collections/commands/update.rb +3 -3
- data/lib/cuprum/collections/commands/upsert.rb +10 -10
- data/lib/cuprum/collections/commands.rb +1 -0
- data/lib/cuprum/collections/constraints/ordering.rb +2 -2
- data/lib/cuprum/collections/errors/abstract_find_error.rb +25 -42
- data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
- data/lib/cuprum/collections/errors/failed_validation.rb +2 -2
- data/lib/cuprum/collections/errors/invalid_parameters.rb +2 -2
- data/lib/cuprum/collections/errors/invalid_query.rb +10 -16
- data/lib/cuprum/collections/errors/missing_default_contract.rb +1 -1
- data/lib/cuprum/collections/errors/unknown_operator.rb +1 -1
- data/lib/cuprum/collections/queries.rb +31 -0
- data/lib/cuprum/collections/query.rb +50 -62
- data/lib/cuprum/collections/relation.rb +5 -383
- data/lib/cuprum/collections/relations/cardinality.rb +66 -0
- data/lib/cuprum/collections/relations/options.rb +18 -0
- data/lib/cuprum/collections/relations/parameters.rb +217 -0
- data/lib/cuprum/collections/relations/primary_keys.rb +23 -0
- data/lib/cuprum/collections/relations/scope.rb +65 -0
- data/lib/cuprum/collections/relations.rb +14 -0
- data/lib/cuprum/collections/repository.rb +5 -5
- data/lib/cuprum/collections/resource.rb +10 -41
- data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +80 -90
- data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +69 -111
- data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +42 -1335
- data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +352 -531
- data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +74 -191
- data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +13 -13
- data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +1029 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +856 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +1430 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +2217 -0
- data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +297 -0
- data/lib/cuprum/collections/rspec/contracts/scopes.rb +13 -0
- data/lib/cuprum/collections/rspec/contracts.rb +2 -0
- data/lib/cuprum/collections/rspec/deferred/association_examples.rb +2098 -0
- data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +338 -0
- data/lib/cuprum/collections/rspec/deferred/command_examples.rb +160 -0
- data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +178 -0
- data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +94 -0
- data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +118 -0
- data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +307 -0
- data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +143 -0
- data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +116 -0
- data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +103 -0
- data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +99 -0
- data/lib/cuprum/collections/rspec/deferred/commands/validate_one_examples.rb +117 -0
- data/lib/cuprum/collections/rspec/deferred/commands.rb +8 -0
- data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +1437 -0
- data/lib/cuprum/collections/rspec/deferred/resource_examples.rb +26 -0
- data/lib/cuprum/collections/rspec/deferred.rb +8 -0
- data/lib/cuprum/collections/scope.rb +29 -0
- data/lib/cuprum/collections/scopes/all.rb +51 -0
- data/lib/cuprum/collections/scopes/all_scope.rb +18 -0
- data/lib/cuprum/collections/scopes/base.rb +79 -0
- data/lib/cuprum/collections/scopes/builder.rb +39 -0
- data/lib/cuprum/collections/scopes/building.rb +221 -0
- data/lib/cuprum/collections/scopes/composition.rb +162 -0
- data/lib/cuprum/collections/scopes/conjunction.rb +44 -0
- data/lib/cuprum/collections/scopes/conjunction_scope.rb +12 -0
- data/lib/cuprum/collections/scopes/container.rb +65 -0
- data/lib/cuprum/collections/scopes/criteria/parser.rb +241 -0
- data/lib/cuprum/collections/scopes/criteria.rb +206 -0
- data/lib/cuprum/collections/scopes/criteria_scope.rb +12 -0
- data/lib/cuprum/collections/scopes/disjunction.rb +45 -0
- data/lib/cuprum/collections/scopes/disjunction_scope.rb +12 -0
- data/lib/cuprum/collections/scopes/none.rb +62 -0
- data/lib/cuprum/collections/scopes/none_scope.rb +18 -0
- data/lib/cuprum/collections/scopes.rb +23 -0
- data/lib/cuprum/collections/version.rb +2 -2
- data/lib/cuprum/collections.rb +14 -9
- metadata +61 -15
- data/lib/cuprum/collections/basic/query_builder.rb +0 -69
- data/lib/cuprum/collections/command.rb +0 -26
- data/lib/cuprum/collections/queries/parse.rb +0 -22
- data/lib/cuprum/collections/queries/parse_block.rb +0 -206
- data/lib/cuprum/collections/queries/parse_strategy.rb +0 -91
- data/lib/cuprum/collections/query_builder.rb +0 -61
- data/lib/cuprum/collections/rspec/contracts/basic/command_contracts.rb +0 -484
@@ -4,28 +4,24 @@ require 'cuprum/command_factory'
|
|
4
4
|
|
5
5
|
require 'cuprum/collections'
|
6
6
|
require 'cuprum/collections/relation'
|
7
|
+
require 'cuprum/collections/relations/options'
|
8
|
+
require 'cuprum/collections/relations/parameters'
|
9
|
+
require 'cuprum/collections/relations/primary_keys'
|
10
|
+
require 'cuprum/collections/relations/scope'
|
11
|
+
require 'cuprum/collections/scopes/all_scope'
|
7
12
|
|
8
13
|
module Cuprum::Collections
|
9
14
|
# Provides a base implementation for collections.
|
10
15
|
class Collection < Cuprum::CommandFactory
|
11
|
-
include Cuprum::Collections::
|
12
|
-
include Cuprum::Collections::
|
13
|
-
include Cuprum::Collections::
|
16
|
+
include Cuprum::Collections::Relations::Options
|
17
|
+
include Cuprum::Collections::Relations::Parameters
|
18
|
+
include Cuprum::Collections::Relations::PrimaryKeys
|
19
|
+
include Cuprum::Collections::Relations::Scope
|
14
20
|
|
15
21
|
# Error raised when trying to call an abstract collection method.
|
16
22
|
class AbstractCollectionError < StandardError; end
|
17
23
|
|
18
|
-
|
19
|
-
collection_name
|
20
|
-
entity_class
|
21
|
-
member_name
|
22
|
-
name
|
23
|
-
qualified_name
|
24
|
-
singular_name
|
25
|
-
].freeze
|
26
|
-
private_constant :IGNORED_PARAMETERS
|
27
|
-
|
28
|
-
# @overload initialize(entity_class: nil, name: nil, qualified_name: nil, singular_name: nil, **options)
|
24
|
+
# @!method initialize(entity_class: nil, name: nil, qualified_name: nil, singular_name: nil, **options)
|
29
25
|
# @param entity_class [Class, String] the class of entity represented by
|
30
26
|
# the relation.
|
31
27
|
# @param name [String] the name of the relation.
|
@@ -35,27 +31,11 @@ module Cuprum::Collections
|
|
35
31
|
#
|
36
32
|
# @option options primary_key_name [String] the name of the primary key
|
37
33
|
# attribute. Defaults to 'id'.
|
38
|
-
# @option primary_key_type [Class, Stannum::Constraint] the type
|
39
|
-
# the primary key attribute. Defaults to Integer.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
relation_params = resolve_parameters(
|
44
|
-
parameters,
|
45
|
-
name: :collection_name,
|
46
|
-
singular_name: :member_name
|
47
|
-
)
|
48
|
-
@entity_class = relation_params[:entity_class]
|
49
|
-
@name = relation_params[:name]
|
50
|
-
@plural_name = relation_params[:plural_name]
|
51
|
-
@qualified_name = relation_params[:qualified_name]
|
52
|
-
@singular_name = relation_params[:singular_name]
|
53
|
-
|
54
|
-
@options = ignore_parameters(**parameters)
|
55
|
-
end
|
56
|
-
|
57
|
-
# @return [Hash<Symbol>] additional options for the collection.
|
58
|
-
attr_reader :options
|
34
|
+
# @option options primary_key_type [Class, Stannum::Constraint] the type
|
35
|
+
# of the primary key attribute. Defaults to Integer.
|
36
|
+
# @option options scope
|
37
|
+
# [Cuprum::Collections::Scopes::Base, Hash, Proc, nil] the configured
|
38
|
+
# scope for the relation.
|
59
39
|
|
60
40
|
# @param other [Object] The object to compare.
|
61
41
|
#
|
@@ -67,14 +47,6 @@ module Cuprum::Collections
|
|
67
47
|
comparable_options == other.comparable_options
|
68
48
|
end
|
69
49
|
|
70
|
-
# @return [String] the name of the collection.
|
71
|
-
def collection_name
|
72
|
-
tools.core_tools.deprecate '#collection_name method',
|
73
|
-
message: 'Use #name instead'
|
74
|
-
|
75
|
-
name
|
76
|
-
end
|
77
|
-
|
78
50
|
# @return [Integer] the count of items in the collection.
|
79
51
|
def count
|
80
52
|
query.count
|
@@ -97,58 +69,28 @@ module Cuprum::Collections
|
|
97
69
|
comparable_options >= expected
|
98
70
|
end
|
99
71
|
|
100
|
-
# @return [String] the name of an entity in the relation.
|
101
|
-
def member_name
|
102
|
-
tools.core_tools.deprecate '#member_name method',
|
103
|
-
message: 'Use #singular_name instead'
|
104
|
-
|
105
|
-
singular_name
|
106
|
-
end
|
107
|
-
|
108
72
|
# A new Query instance, used for querying against the collection data.
|
109
73
|
#
|
110
74
|
# @return [Object] the query.
|
111
75
|
def query
|
112
76
|
raise AbstractCollectionError,
|
113
|
-
"#{self.class.name} is an abstract class. Define a
|
77
|
+
"#{self.class.name} is an abstract class. Define a collection " \
|
114
78
|
'subclass and implement the #query method.'
|
115
79
|
end
|
116
80
|
|
117
81
|
protected
|
118
82
|
|
119
83
|
def comparable_options
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
def command_options
|
130
|
-
@command_options ||= {
|
131
|
-
collection_name: name,
|
132
|
-
entity_class: entity_class,
|
133
|
-
member_name: singular_name,
|
134
|
-
primary_key_name: primary_key_name,
|
135
|
-
primary_key_type: primary_key_type,
|
84
|
+
@comparable_options ||= {
|
85
|
+
entity_class:,
|
86
|
+
name:,
|
87
|
+
primary_key_name:,
|
88
|
+
primary_key_type:,
|
89
|
+
qualified_name:,
|
90
|
+
scope:,
|
91
|
+
singular_name:,
|
136
92
|
**options
|
137
93
|
}
|
138
94
|
end
|
139
|
-
|
140
|
-
def ignore_parameters(**parameters)
|
141
|
-
parameters
|
142
|
-
.reject { |key, _| ignored_parameters.include?(key) }
|
143
|
-
.to_h
|
144
|
-
end
|
145
|
-
|
146
|
-
def ignored_parameters
|
147
|
-
@ignored_parameters ||= Set.new(IGNORED_PARAMETERS)
|
148
|
-
end
|
149
|
-
|
150
|
-
def tools
|
151
|
-
SleepingKingStudios::Tools::Toolbelt.instance
|
152
|
-
end
|
153
95
|
end
|
154
96
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/parameter_validation'
|
4
|
+
|
5
|
+
require 'cuprum/collections'
|
6
|
+
require 'cuprum/collections/errors/invalid_parameters'
|
7
|
+
|
8
|
+
module Cuprum::Collections
|
9
|
+
# Abstract base class for commands implementing collection actions.
|
10
|
+
class CollectionCommand < Cuprum::Command
|
11
|
+
include Cuprum::ParameterValidation
|
12
|
+
|
13
|
+
# @param collection [Cuprum::Collections::Collection] the collection to
|
14
|
+
# which the command belongs.
|
15
|
+
def initialize(collection:)
|
16
|
+
super()
|
17
|
+
|
18
|
+
@collection = collection
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Cuprum::Collections::Collection] the collection to which the
|
22
|
+
# command belongs.
|
23
|
+
attr_reader :collection
|
24
|
+
|
25
|
+
# @return [String] the name of the relation.
|
26
|
+
def name
|
27
|
+
@name ||= collection.name
|
28
|
+
end
|
29
|
+
alias collection_name name
|
30
|
+
|
31
|
+
# @return [String] the name of the primary key attribute. Defaults to 'id'.
|
32
|
+
def primary_key_name
|
33
|
+
@primary_key_name ||= collection.primary_key_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [Class, Stannum::Constraint] the type of the primary key
|
37
|
+
# attribute. Defaults to Integer.
|
38
|
+
def primary_key_type
|
39
|
+
@primary_key_type ||= collection.primary_key_type
|
40
|
+
end
|
41
|
+
|
42
|
+
# A new Query instance, used for querying against the collection data.
|
43
|
+
#
|
44
|
+
# @return [Object] the query.
|
45
|
+
def query
|
46
|
+
collection.query
|
47
|
+
end
|
48
|
+
|
49
|
+
# @returnb [String] the name of an entity in the collection.
|
50
|
+
def singular_name
|
51
|
+
@singular_name ||= collection.singular_name
|
52
|
+
end
|
53
|
+
alias member_name singular_name
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def error_message_for(message = nil, as:, expected:)
|
58
|
+
tools.assertions.error_message_for(
|
59
|
+
message || 'sleeping_king_studios.tools.assertions.instance_of',
|
60
|
+
as:,
|
61
|
+
expected:
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def tools
|
66
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_attributes(value, as: 'attributes')
|
70
|
+
return error_message_for(as:, expected: Hash) unless value.is_a?(Hash)
|
71
|
+
|
72
|
+
return [] if value.empty?
|
73
|
+
|
74
|
+
validator = tools.assertions.aggregator_class.new
|
75
|
+
|
76
|
+
value.each_key do |key|
|
77
|
+
validator.validate_name(
|
78
|
+
key,
|
79
|
+
as: "#{as}[#{key.inspect}] key"
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
validator.each.to_a
|
84
|
+
end
|
85
|
+
|
86
|
+
def validate_primary_key(value, as: nil)
|
87
|
+
return nil if primary_key_type.nil?
|
88
|
+
|
89
|
+
if primary_key_type.is_a?(Stannum::Constraints::Base)
|
90
|
+
match, errors = primary_key_type.match(value)
|
91
|
+
|
92
|
+
return match ? nil : "#{as || primary_key_name} #{errors.summary}"
|
93
|
+
end
|
94
|
+
|
95
|
+
return nil if value.is_a?(primary_key_type)
|
96
|
+
|
97
|
+
error_message_for(as: as || primary_key_name, expected: primary_key_type)
|
98
|
+
end
|
99
|
+
|
100
|
+
def validate_primary_keys(primary_keys, as: 'value')
|
101
|
+
unless primary_keys.is_a?(Array)
|
102
|
+
return error_message_for(as:, expected: Array)
|
103
|
+
end
|
104
|
+
|
105
|
+
messages = []
|
106
|
+
|
107
|
+
primary_keys.each.with_index do |item, index|
|
108
|
+
message = validate_primary_key(item, as: "#{as}[#{index}]")
|
109
|
+
|
110
|
+
messages << message if message
|
111
|
+
end
|
112
|
+
|
113
|
+
messages
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -5,16 +5,13 @@ require 'cuprum/collections/errors/not_found'
|
|
5
5
|
|
6
6
|
module Cuprum::Collections::Commands
|
7
7
|
# Abstract implementation of the FindMany command.
|
8
|
-
#
|
9
|
-
# Subclasses must define the #build_query method, which returns an empty
|
10
|
-
# Query instance for that collection.
|
11
8
|
module AbstractFindMany
|
12
9
|
private
|
13
10
|
|
14
|
-
def apply_query(primary_keys
|
11
|
+
def apply_query(primary_keys:)
|
15
12
|
key = primary_key_name
|
16
13
|
|
17
|
-
|
14
|
+
query.where { |scope| { key => scope.one_of(primary_keys) } }
|
18
15
|
end
|
19
16
|
|
20
17
|
def build_results(items:, primary_keys:)
|
@@ -26,16 +23,14 @@ module Cuprum::Collections::Commands
|
|
26
23
|
end
|
27
24
|
|
28
25
|
def build_result_list(results, allow_partial:, envelope:)
|
29
|
-
unless envelope
|
30
|
-
return Cuprum::ResultList.new(*results, allow_partial: allow_partial)
|
31
|
-
end
|
26
|
+
return Cuprum::ResultList.new(*results, allow_partial:) unless envelope
|
32
27
|
|
33
28
|
value = envelope ? wrap_items(results.map(&:value)) : nil
|
34
29
|
|
35
30
|
Cuprum::ResultList.new(
|
36
31
|
*results,
|
37
|
-
allow_partial
|
38
|
-
value:
|
32
|
+
allow_partial:,
|
33
|
+
value:
|
39
34
|
)
|
40
35
|
end
|
41
36
|
|
@@ -49,25 +44,20 @@ module Cuprum::Collections::Commands
|
|
49
44
|
Cuprum::Collections::Errors::NotFound.new(
|
50
45
|
attribute_name: primary_key_name,
|
51
46
|
attribute_value: primary_key_value,
|
52
|
-
collection_name
|
47
|
+
collection_name:,
|
53
48
|
primary_key: true
|
54
49
|
)
|
55
50
|
end
|
56
51
|
|
57
|
-
def process(
|
58
|
-
primary_keys
|
59
|
-
allow_partial: false,
|
60
|
-
envelope: false,
|
61
|
-
scope: nil
|
62
|
-
)
|
63
|
-
query = apply_query(primary_keys: primary_keys, scope: scope)
|
52
|
+
def process(primary_keys:, allow_partial: false, envelope: false)
|
53
|
+
query = apply_query(primary_keys:)
|
64
54
|
items = items_with_primary_keys(items: query.to_a)
|
65
|
-
results = build_results(items
|
55
|
+
results = build_results(items:, primary_keys:)
|
66
56
|
|
67
57
|
build_result_list(
|
68
58
|
results,
|
69
|
-
allow_partial
|
70
|
-
envelope:
|
59
|
+
allow_partial:,
|
60
|
+
envelope:
|
71
61
|
)
|
72
62
|
end
|
73
63
|
|
@@ -1,62 +1,81 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'cuprum/collections/commands'
|
4
|
-
require 'cuprum/collections/
|
4
|
+
require 'cuprum/collections/constraints/ordering'
|
5
|
+
require 'cuprum/collections/errors/invalid_query'
|
5
6
|
|
6
7
|
module Cuprum::Collections::Commands
|
7
8
|
# Abstract implementation of the FindMatching command.
|
8
|
-
#
|
9
|
-
# Subclasses must define the #build_query method, which returns an empty
|
10
|
-
# Query instance for that collection.
|
11
9
|
module AbstractFindMatching
|
12
10
|
private
|
13
11
|
|
14
|
-
def apply_query(
|
15
|
-
query =
|
12
|
+
def apply_query(limit:, offset:, order:, scope:)
|
13
|
+
query = self.query
|
16
14
|
query = query.limit(limit) if limit
|
17
15
|
query = query.offset(offset) if offset
|
18
16
|
query = query.order(order) if order
|
19
|
-
query = query.where(
|
17
|
+
query = query.where(scope) if scope
|
20
18
|
|
21
19
|
success(query)
|
22
20
|
end
|
23
21
|
|
24
|
-
def
|
25
|
-
return
|
22
|
+
def build_scope(value, &)
|
23
|
+
return Cuprum::Collections::Scope.build(&) if block_given?
|
26
24
|
|
27
|
-
Cuprum::Collections::
|
28
|
-
|
29
|
-
|
25
|
+
return value if value.is_a?(Cuprum::Collections::Scopes::Base)
|
26
|
+
|
27
|
+
Cuprum::Collections::Scope.build(value) if value
|
28
|
+
rescue ArgumentError => exception
|
29
|
+
error = Cuprum::Collections::Errors::InvalidQuery.new(
|
30
|
+
message: exception.message,
|
31
|
+
query: value
|
30
32
|
)
|
33
|
+
|
34
|
+
failure(error)
|
31
35
|
end
|
32
36
|
|
33
|
-
def process(
|
37
|
+
def process(
|
34
38
|
envelope: false,
|
35
39
|
limit: nil,
|
36
40
|
offset: nil,
|
37
41
|
order: nil,
|
38
|
-
scope: nil,
|
39
|
-
strategy: nil,
|
40
42
|
where: nil,
|
41
43
|
&block
|
42
44
|
)
|
43
|
-
|
44
|
-
parse_criteria(strategy: strategy, where: where, &block)
|
45
|
-
end
|
46
|
-
|
45
|
+
scope = step { build_scope(where, &block) }
|
47
46
|
query = step do
|
48
47
|
apply_query(
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
scope: scope
|
48
|
+
limit:,
|
49
|
+
offset:,
|
50
|
+
order:,
|
51
|
+
scope:
|
54
52
|
)
|
55
53
|
end
|
56
54
|
|
57
55
|
envelope ? wrap_query(query) : query.each
|
58
56
|
end
|
59
57
|
|
58
|
+
def validate_order(value, as: 'order')
|
59
|
+
return if value.nil?
|
60
|
+
|
61
|
+
match, errors =
|
62
|
+
Cuprum::Collections::Constraints::Ordering.new.match(value)
|
63
|
+
|
64
|
+
return if match
|
65
|
+
|
66
|
+
"#{as} #{errors.summary}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_where(value, as: 'where')
|
70
|
+
return if value.nil?
|
71
|
+
|
72
|
+
return if value.is_a?(Cuprum::Collections::Scopes::Base)
|
73
|
+
|
74
|
+
return if validate_attributes(value, as:).empty?
|
75
|
+
|
76
|
+
"#{as} is not a scope or query hash"
|
77
|
+
end
|
78
|
+
|
60
79
|
def wrap_query(query)
|
61
80
|
{ collection_name => query.to_a }
|
62
81
|
end
|
@@ -5,16 +5,13 @@ require 'cuprum/collections/errors/not_found'
|
|
5
5
|
|
6
6
|
module Cuprum::Collections::Commands
|
7
7
|
# Abstract implementation of the FindOne command.
|
8
|
-
#
|
9
|
-
# Subclasses must define the #build_query method, which returns an empty
|
10
|
-
# Query instance for that collection.
|
11
8
|
module AbstractFindOne
|
12
9
|
private
|
13
10
|
|
14
|
-
def apply_query(primary_key
|
11
|
+
def apply_query(primary_key:)
|
15
12
|
key = primary_key_name
|
16
13
|
|
17
|
-
|
14
|
+
query.where { |scope| { key => scope.equals(primary_key) } }.limit(1)
|
18
15
|
end
|
19
16
|
|
20
17
|
def handle_missing_item(item:, primary_key:)
|
@@ -23,17 +20,17 @@ module Cuprum::Collections::Commands
|
|
23
20
|
error = Cuprum::Collections::Errors::NotFound.new(
|
24
21
|
attribute_name: primary_key_name,
|
25
22
|
attribute_value: primary_key,
|
26
|
-
collection_name
|
23
|
+
collection_name:,
|
27
24
|
primary_key: true
|
28
25
|
)
|
29
|
-
Cuprum::Result.new(error:
|
26
|
+
Cuprum::Result.new(error:)
|
30
27
|
end
|
31
28
|
|
32
|
-
def process(
|
33
|
-
query = apply_query(primary_key:
|
29
|
+
def process(primary_key:, envelope: false)
|
30
|
+
query = apply_query(primary_key:)
|
34
31
|
item = query.to_a.first
|
35
32
|
|
36
|
-
step { handle_missing_item(item
|
33
|
+
step { handle_missing_item(item:, primary_key:) }
|
37
34
|
|
38
35
|
envelope ? wrap_item(item) : item
|
39
36
|
end
|
@@ -75,7 +75,6 @@ module Cuprum::Collections::Commands::Associations
|
|
75
75
|
|
76
76
|
def collection
|
77
77
|
repository.find_or_create(
|
78
|
-
name: tools.string_tools.pluralize(association.name),
|
79
78
|
qualified_name: association.qualified_name
|
80
79
|
)
|
81
80
|
end
|
@@ -132,9 +131,9 @@ module Cuprum::Collections::Commands::Associations
|
|
132
131
|
|
133
132
|
values = step do
|
134
133
|
perform_query(
|
135
|
-
association
|
136
|
-
expected_keys
|
137
|
-
plural:
|
134
|
+
association:,
|
135
|
+
expected_keys:,
|
136
|
+
plural:
|
138
137
|
)
|
139
138
|
end
|
140
139
|
|
@@ -153,9 +152,5 @@ module Cuprum::Collections::Commands::Associations
|
|
153
152
|
|
154
153
|
[keys, plural]
|
155
154
|
end
|
156
|
-
|
157
|
-
def tools
|
158
|
-
SleepingKingStudios::Tools::Toolbelt.instance
|
159
|
-
end
|
160
155
|
end
|
161
156
|
end
|
@@ -10,7 +10,7 @@ module Cuprum::Collections::Commands::Associations
|
|
10
10
|
private
|
11
11
|
|
12
12
|
def find_missing_keys(entities:, expected_keys:)
|
13
|
-
expected_keys - map_entity_keys(entities:
|
13
|
+
expected_keys - map_entity_keys(entities:)
|
14
14
|
end
|
15
15
|
|
16
16
|
def map_entity_keys(entities:)
|
@@ -23,7 +23,7 @@ module Cuprum::Collections::Commands::Associations
|
|
23
23
|
|
24
24
|
Cuprum::Collections::Errors::NotFound.new(
|
25
25
|
attribute_name: association.query_key_name,
|
26
|
-
attribute_value
|
26
|
+
attribute_value:,
|
27
27
|
collection_name: association.name,
|
28
28
|
primary_key: association.primary_key_query?
|
29
29
|
)
|
@@ -32,15 +32,15 @@ module Cuprum::Collections::Commands::Associations
|
|
32
32
|
def perform_query(association:, expected_keys:, plural:, **)
|
33
33
|
entities = step { super }
|
34
34
|
missing_keys = find_missing_keys(
|
35
|
-
entities
|
36
|
-
expected_keys:
|
35
|
+
entities:,
|
36
|
+
expected_keys:
|
37
37
|
)
|
38
38
|
|
39
39
|
return success(entities) if missing_keys.empty?
|
40
40
|
|
41
41
|
missing_keys = missing_keys.first unless plural
|
42
42
|
error =
|
43
|
-
missing_keys_error(missing_keys
|
43
|
+
missing_keys_error(missing_keys:, plural:)
|
44
44
|
|
45
45
|
failure(error)
|
46
46
|
end
|
@@ -50,11 +50,11 @@ module Cuprum::Collections::Commands
|
|
50
50
|
private
|
51
51
|
|
52
52
|
def process(attributes:)
|
53
|
-
entity = step { collection.build_one.call(attributes:
|
53
|
+
entity = step { collection.build_one.call(attributes:) }
|
54
54
|
|
55
|
-
step { collection.validate_one.call(contract
|
55
|
+
step { collection.validate_one.call(contract:, entity:) }
|
56
56
|
|
57
|
-
collection.insert_one.call(entity:
|
57
|
+
collection.insert_one.call(entity:)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -96,20 +96,20 @@ module Cuprum::Collections::Commands
|
|
96
96
|
if block_given?
|
97
97
|
{ query: collection.query.where(&block) }
|
98
98
|
else
|
99
|
-
{ attributes:
|
99
|
+
{ attributes: }
|
100
100
|
end
|
101
101
|
)
|
102
102
|
end
|
103
103
|
|
104
104
|
def not_found_error(attributes: nil, &block)
|
105
105
|
Cuprum::Collections::Errors::NotFound.new(
|
106
|
-
**error_params_for(attributes
|
106
|
+
**error_params_for(attributes:, &block)
|
107
107
|
)
|
108
108
|
end
|
109
109
|
|
110
110
|
def not_unique_error(attributes: nil, &block)
|
111
111
|
Cuprum::Collections::Errors::NotUnique.new(
|
112
|
-
**error_params_for(attributes
|
112
|
+
**error_params_for(attributes:, &block)
|
113
113
|
)
|
114
114
|
end
|
115
115
|
|
@@ -117,17 +117,17 @@ module Cuprum::Collections::Commands
|
|
117
117
|
query = block || -> { attributes }
|
118
118
|
entities = step { collection.find_matching.call(limit: 2, &query) }
|
119
119
|
|
120
|
-
require_one_entity(attributes
|
120
|
+
require_one_entity(attributes:, entities:, &block)
|
121
121
|
end
|
122
122
|
|
123
123
|
def require_one_entity(attributes:, entities:, &block)
|
124
124
|
case entities.count
|
125
125
|
when 0
|
126
|
-
failure(not_found_error(attributes
|
126
|
+
failure(not_found_error(attributes:, &block))
|
127
127
|
when 1
|
128
128
|
entities.first
|
129
129
|
when 2
|
130
|
-
failure(not_unique_error(attributes
|
130
|
+
failure(not_unique_error(attributes:, &block))
|
131
131
|
end
|
132
132
|
end
|
133
133
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/collections/commands'
|
4
|
+
|
5
|
+
module Cuprum::Collections::Commands
|
6
|
+
# Shared functionality for defining commands that query the collection.
|
7
|
+
module QueryCommand
|
8
|
+
# @param query [#call] the query object used to access the collection data.
|
9
|
+
# @param options [Hash] additional options for the collection.
|
10
|
+
def initialize(query:, **options)
|
11
|
+
super(**options)
|
12
|
+
|
13
|
+
@query = query
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [#call] the query object used to access the collection data.
|
17
|
+
attr_reader :query
|
18
|
+
end
|
19
|
+
end
|
@@ -63,12 +63,12 @@ module Cuprum::Collections::Commands
|
|
63
63
|
|
64
64
|
def process(attributes:, entity:)
|
65
65
|
entity = step do
|
66
|
-
collection.assign_one.call(attributes
|
66
|
+
collection.assign_one.call(attributes:, entity:)
|
67
67
|
end
|
68
68
|
|
69
|
-
step { collection.validate_one.call(entity
|
69
|
+
step { collection.validate_one.call(entity:, contract:) }
|
70
70
|
|
71
|
-
step { collection.update_one.call(entity:
|
71
|
+
step { collection.update_one.call(entity:) }
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|