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
|
@@ -15,7 +15,9 @@ module Cuprum::Collections
|
|
|
15
15
|
LESS_THAN: :less_than,
|
|
16
16
|
LESS_THAN_OR_EQUAL_TO: :less_than_or_equal_to,
|
|
17
17
|
NOT_EQUAL: :not_equal,
|
|
18
|
+
NOT_NULL: :not_null,
|
|
18
19
|
NOT_ONE_OF: :not_one_of,
|
|
20
|
+
NULL: :null,
|
|
19
21
|
ONE_OF: :one_of
|
|
20
22
|
).freeze
|
|
21
23
|
|
|
@@ -46,7 +48,9 @@ module Cuprum::Collections
|
|
|
46
48
|
Operators::LESS_THAN => Operators::GREATER_THAN_OR_EQUAL_TO, # rubocop:disable Layout/LineLength
|
|
47
49
|
Operators::LESS_THAN_OR_EQUAL_TO => Operators::GREATER_THAN,
|
|
48
50
|
Operators::NOT_EQUAL => Operators::EQUAL,
|
|
51
|
+
Operators::NOT_NULL => Operators::NULL,
|
|
49
52
|
Operators::NOT_ONE_OF => Operators::ONE_OF,
|
|
53
|
+
Operators::NULL => Operators::NOT_NULL,
|
|
50
54
|
Operators::ONE_OF => Operators::NOT_ONE_OF
|
|
51
55
|
}.freeze
|
|
52
56
|
|
|
@@ -13,40 +13,48 @@ module Cuprum::Collections::Relations
|
|
|
13
13
|
].freeze
|
|
14
14
|
private_constant :IGNORED_PARAMETERS
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
OPTIONAL_PARAMETER_KEYS =
|
|
17
|
+
%i[default_entity_class plural_name singular_name].freeze
|
|
18
|
+
private_constant :OPTIONAL_PARAMETER_KEYS
|
|
19
|
+
|
|
20
|
+
REQUIRED_PARAMETER_KEYS = %i[entity_class name qualified_name].freeze
|
|
21
|
+
private_constant :REQUIRED_PARAMETER_KEYS
|
|
22
|
+
|
|
23
|
+
PARAMETER_KEYS = (OPTIONAL_PARAMETER_KEYS + REQUIRED_PARAMETER_KEYS).freeze
|
|
17
24
|
private_constant :PARAMETER_KEYS
|
|
18
25
|
|
|
19
26
|
class << self # rubocop:disable Metrics/ClassLength
|
|
20
|
-
# @overload resolve_parameters(
|
|
27
|
+
# @overload resolve_parameters(**options)
|
|
21
28
|
# Helper method for resolving a Relation's required parameters.
|
|
22
29
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
30
|
+
# At least one of the following options must be provided: name,
|
|
31
|
+
# qualified_name, or entity_class. The returned Hash will include the
|
|
32
|
+
# above keys as well as :singular_name and :plural_name.
|
|
25
33
|
#
|
|
26
|
-
# @param
|
|
27
|
-
#
|
|
28
|
-
# @
|
|
29
|
-
#
|
|
30
|
-
#
|
|
34
|
+
# @param options [Hash] the parameters to resolve.
|
|
35
|
+
#
|
|
36
|
+
# @option options default_entity_class [Class, String, nil] if given,
|
|
37
|
+
# this value will be assigned to the entity class if the entity_class
|
|
38
|
+
# is absent; it will *not* be used to derive other properties.
|
|
39
|
+
# @option options entity_class [Class, String] the class of entity
|
|
40
|
+
# represented by the relation.
|
|
41
|
+
# @option options name [String] the name of the relation.
|
|
42
|
+
# @option options plural_name [String] the name of a group of entities
|
|
43
|
+
# in the relation.
|
|
44
|
+
# @option options qualified_name [String] a scoped name for the
|
|
45
|
+
# relation.
|
|
46
|
+
# @option options singular_name [String] the name of an entity in the
|
|
47
|
+
# relation.
|
|
31
48
|
#
|
|
32
49
|
# @return [Hash] the resolved parameters.
|
|
33
|
-
def resolve_parameters(params)
|
|
50
|
+
def resolve_parameters(params)
|
|
34
51
|
validate_parameters(**params)
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
singular_name = singular_name_from(**params, name:)
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
entity_class:,
|
|
45
|
-
name:,
|
|
46
|
-
plural_name:,
|
|
47
|
-
qualified_name:,
|
|
48
|
-
singular_name:
|
|
49
|
-
}
|
|
53
|
+
if has_key?(params, :entity_class)
|
|
54
|
+
resolve_parameters_from_entity_class(**params)
|
|
55
|
+
else
|
|
56
|
+
resolve_parameters_from_name(**params)
|
|
57
|
+
end
|
|
50
58
|
end
|
|
51
59
|
|
|
52
60
|
private
|
|
@@ -59,65 +67,109 @@ module Cuprum::Collections::Relations
|
|
|
59
67
|
.join('::')
|
|
60
68
|
end
|
|
61
69
|
|
|
62
|
-
def entity_class_from(**params)
|
|
63
|
-
if has_key?(params, :entity_class)
|
|
64
|
-
entity_class = params[:entity_class]
|
|
65
|
-
|
|
66
|
-
return entity_class.is_a?(Class) ? entity_class : entity_class.to_s
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
if has_key?(params, :qualified_name)
|
|
70
|
-
return classify(params[:qualified_name])
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
classify(params[:name])
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def entity_class_name(entity_class, scoped: true)
|
|
77
|
-
(entity_class.is_a?(Class) ? entity_class.name : entity_class)
|
|
78
|
-
.split('::')
|
|
79
|
-
.map { |str| tools.string_tools.underscore(str) }
|
|
80
|
-
.then { |ary| scoped ? ary.join('/') : ary.last }
|
|
81
|
-
end
|
|
82
|
-
|
|
83
70
|
def has_key?(params, key) # rubocop:disable Naming/PredicatePrefix
|
|
84
71
|
return false unless params.key?(key)
|
|
85
72
|
|
|
86
73
|
!params[key].nil?
|
|
87
74
|
end
|
|
88
75
|
|
|
89
|
-
def
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
76
|
+
def resolve_entity_class(params)
|
|
77
|
+
entity_class =
|
|
78
|
+
if has_key?(params, :default_entity_class)
|
|
79
|
+
params[:default_entity_class]
|
|
80
|
+
else
|
|
81
|
+
classify(params[:qualified_name])
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
params.update(entity_class:)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def resolve_entity_name(params)
|
|
88
|
+
entity_class = params[:entity_class]
|
|
89
|
+
entity_name =
|
|
90
|
+
(entity_class.is_a?(Class) ? entity_class.name : entity_class)
|
|
91
|
+
.split('::')
|
|
92
|
+
.map { |str| tools.string_tools.underscore(str) }
|
|
93
|
+
.join('/')
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
params.update(entity_name:)
|
|
98
96
|
end
|
|
99
97
|
|
|
100
|
-
def
|
|
101
|
-
|
|
98
|
+
def resolve_name(params)
|
|
99
|
+
name =
|
|
100
|
+
if has_key?(params, :name)
|
|
101
|
+
params[:name].to_s
|
|
102
|
+
elsif has_key?(params, :entity_name)
|
|
103
|
+
tools.string_tools.pluralize(params[:entity_name].split('/').last)
|
|
104
|
+
else
|
|
105
|
+
params[:qualified_name].split('/').last
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
params.update(name:)
|
|
109
|
+
end
|
|
102
110
|
|
|
103
|
-
|
|
111
|
+
def resolve_parameters_from_entity_class(**params)
|
|
112
|
+
params
|
|
113
|
+
.slice(*PARAMETER_KEYS)
|
|
114
|
+
.then { |hsh| resolve_entity_name(hsh) }
|
|
115
|
+
.then { |hsh| resolve_qualified_name(hsh) }
|
|
116
|
+
.then { |hsh| resolve_name(hsh) }
|
|
117
|
+
.then { |hsh| resolve_plural_name(hsh) }
|
|
118
|
+
.then { |hsh| resolve_singular_name(hsh) }
|
|
119
|
+
.tap { |hsh| hsh.delete(:default_entity_class) }
|
|
120
|
+
.tap { |hsh| hsh.delete(:entity_name) }
|
|
104
121
|
end
|
|
105
122
|
|
|
106
|
-
def
|
|
107
|
-
|
|
123
|
+
def resolve_parameters_from_name(**params)
|
|
124
|
+
params
|
|
125
|
+
.slice(*PARAMETER_KEYS)
|
|
126
|
+
.then { |hsh| resolve_qualified_name(hsh) }
|
|
127
|
+
.then { |hsh| resolve_name(hsh) }
|
|
128
|
+
.then { |hsh| resolve_plural_name(hsh) }
|
|
129
|
+
.then { |hsh| resolve_singular_name(hsh) }
|
|
130
|
+
.then { |hsh| resolve_entity_class(hsh) }
|
|
131
|
+
.tap { |hsh| hsh.delete(:default_entity_class) }
|
|
132
|
+
end
|
|
108
133
|
|
|
109
|
-
|
|
134
|
+
def resolve_plural_name(params)
|
|
135
|
+
plural_name =
|
|
136
|
+
if has_key?(params, :plural_name)
|
|
137
|
+
validate_parameter(
|
|
138
|
+
params[:plural_name],
|
|
139
|
+
as: 'plural name'
|
|
140
|
+
)
|
|
141
|
+
else
|
|
142
|
+
tools.string_tools.pluralize(params[:name])
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
params.update(plural_name:)
|
|
110
146
|
end
|
|
111
147
|
|
|
112
|
-
def
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
148
|
+
def resolve_qualified_name(params)
|
|
149
|
+
qualified_name =
|
|
150
|
+
if has_key?(params, :qualified_name)
|
|
151
|
+
params[:qualified_name].to_s
|
|
152
|
+
elsif has_key?(params, :entity_name)
|
|
153
|
+
tools.string_tools.pluralize(params[:entity_name])
|
|
154
|
+
elsif has_key?(params, :name)
|
|
155
|
+
tools.string_tools.pluralize(params[:name])
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
params.update(qualified_name:)
|
|
159
|
+
end
|
|
119
160
|
|
|
120
|
-
|
|
161
|
+
def resolve_singular_name(params)
|
|
162
|
+
singular_name =
|
|
163
|
+
if has_key?(params, :singular_name)
|
|
164
|
+
validate_parameter(
|
|
165
|
+
params[:singular_name],
|
|
166
|
+
as: 'singular name'
|
|
167
|
+
)
|
|
168
|
+
else
|
|
169
|
+
tools.string_tools.singularize(params[:name])
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
params.update(singular_name:)
|
|
121
173
|
end
|
|
122
174
|
|
|
123
175
|
def tools
|
|
@@ -144,7 +196,7 @@ module Cuprum::Collections::Relations
|
|
|
144
196
|
end
|
|
145
197
|
|
|
146
198
|
def validate_parameter_keys(params)
|
|
147
|
-
return if
|
|
199
|
+
return if REQUIRED_PARAMETER_KEYS.any? { |key| has_key?(params, key) }
|
|
148
200
|
|
|
149
201
|
raise ArgumentError, "name or entity class can't be blank"
|
|
150
202
|
end
|
|
@@ -14,7 +14,7 @@ module Cuprum::Collections
|
|
|
14
14
|
# and so on. The application may instead aggregate all of its collections into
|
|
15
15
|
# a single repository, relying on the shared interface of all Collection
|
|
16
16
|
# implementations.
|
|
17
|
-
class Repository
|
|
17
|
+
class Repository # rubocop:disable Metrics/ClassLength
|
|
18
18
|
extend Forwardable
|
|
19
19
|
|
|
20
20
|
# Error raised when trying to call an abstract repository method.
|
|
@@ -29,8 +29,11 @@ module Cuprum::Collections
|
|
|
29
29
|
# Error raised when trying to access a collection that is not defined.
|
|
30
30
|
class UndefinedCollectionError < StandardError; end
|
|
31
31
|
|
|
32
|
+
# @yieldparam [Cuprum::Collections::Repository] the created repository.
|
|
32
33
|
def initialize
|
|
33
34
|
@collections = {}
|
|
35
|
+
|
|
36
|
+
yield self if block_given?
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
# @!method keys
|
|
@@ -73,6 +76,8 @@ module Cuprum::Collections
|
|
|
73
76
|
def add(collection, force: false)
|
|
74
77
|
validate_collection!(collection)
|
|
75
78
|
|
|
79
|
+
raise FrozenError, frozen_error_message if frozen?
|
|
80
|
+
|
|
76
81
|
if !force && key?(collection.qualified_name.to_s)
|
|
77
82
|
raise DuplicateCollectionError,
|
|
78
83
|
"collection #{collection.qualified_name} already exists"
|
|
@@ -84,10 +89,10 @@ module Cuprum::Collections
|
|
|
84
89
|
end
|
|
85
90
|
alias << add
|
|
86
91
|
|
|
87
|
-
# @overload create(
|
|
92
|
+
# @overload create(name: nil, entity_class: nil, force: false, **options)
|
|
88
93
|
# Adds a new collection with the given name to the repository.
|
|
89
94
|
#
|
|
90
|
-
# @param
|
|
95
|
+
# @param name [String] the name of the new collection.
|
|
91
96
|
# @param entity_class [Class, String] the class of entity represented in
|
|
92
97
|
# the collection.
|
|
93
98
|
# @param force [true, false] if true, override an existing collection with
|
|
@@ -98,14 +103,31 @@ module Cuprum::Collections
|
|
|
98
103
|
#
|
|
99
104
|
# @raise [DuplicateCollectionError] if a collection with the same name
|
|
100
105
|
# already exists in the repository.
|
|
101
|
-
def create(force: false, **
|
|
102
|
-
collection = build_collection(**
|
|
106
|
+
def create(force: false, **)
|
|
107
|
+
collection = build_collection(**)
|
|
103
108
|
|
|
104
109
|
add(collection, force:)
|
|
105
110
|
|
|
106
111
|
collection
|
|
107
112
|
end
|
|
108
113
|
|
|
114
|
+
# @overload find(name: nil, entity_class: nil, **options)
|
|
115
|
+
def find(**parameters)
|
|
116
|
+
qualified_name = qualified_name_for(**parameters)
|
|
117
|
+
collection = @collections[qualified_name]
|
|
118
|
+
|
|
119
|
+
unless collection
|
|
120
|
+
raise UndefinedCollectionError,
|
|
121
|
+
"repository does not define collection #{qualified_name.inspect}"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
return collection if collection.matches?(**parameters)
|
|
125
|
+
|
|
126
|
+
error_message = partial_match_error_message(collection:, parameters:)
|
|
127
|
+
|
|
128
|
+
raise DuplicateCollectionError, error_message
|
|
129
|
+
end
|
|
130
|
+
|
|
109
131
|
# @overload find_or_create(collection_name: nil, entity_class: nil, **options)
|
|
110
132
|
# Finds or creates a new collection with the given name.
|
|
111
133
|
#
|
|
@@ -118,7 +140,12 @@ module Cuprum::Collections
|
|
|
118
140
|
#
|
|
119
141
|
# @raise [DuplicateCollectionError] if a collection with the same name
|
|
120
142
|
# but different parameters already exists in the repository.
|
|
121
|
-
def find_or_create(**parameters)
|
|
143
|
+
def find_or_create(**parameters) # rubocop:disable Metrics/MethodLength
|
|
144
|
+
tools.core_tools.deprecate(
|
|
145
|
+
"#{self.class.name}#find_or_create()",
|
|
146
|
+
message: 'Use #create or #find method.'
|
|
147
|
+
)
|
|
148
|
+
|
|
122
149
|
qualified_name = qualified_name_for(**parameters)
|
|
123
150
|
|
|
124
151
|
unless key?(qualified_name)
|
|
@@ -144,6 +171,22 @@ module Cuprum::Collections
|
|
|
144
171
|
@collections.key?(qualified_name.to_s)
|
|
145
172
|
end
|
|
146
173
|
|
|
174
|
+
# Removes the specified collection from the repository.
|
|
175
|
+
#
|
|
176
|
+
# @param qualified_name [String, Symbol] the name of the collection to
|
|
177
|
+
# remove.
|
|
178
|
+
#
|
|
179
|
+
# @return [Cuprum::Collections::Collection] the removed collection.
|
|
180
|
+
def remove(qualified_name:)
|
|
181
|
+
raise FrozenError, frozen_error_message if frozen?
|
|
182
|
+
|
|
183
|
+
collection = find(qualified_name:)
|
|
184
|
+
|
|
185
|
+
@collections.delete(collection.qualified_name)
|
|
186
|
+
|
|
187
|
+
collection
|
|
188
|
+
end
|
|
189
|
+
|
|
147
190
|
private
|
|
148
191
|
|
|
149
192
|
def build_collection(**)
|
|
@@ -152,12 +195,34 @@ module Cuprum::Collections
|
|
|
152
195
|
'subclass and implement the #build_collection method.'
|
|
153
196
|
end
|
|
154
197
|
|
|
198
|
+
def frozen_error_message
|
|
199
|
+
"can't modify frozen #{self.class.name}"
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def partial_match_error_message(collection:, parameters:)
|
|
203
|
+
non_matching =
|
|
204
|
+
parameters
|
|
205
|
+
.each_key
|
|
206
|
+
.reject { |key| collection.public_send(key) == parameters[key] }
|
|
207
|
+
expected = parameters.slice(*non_matching)
|
|
208
|
+
actual = non_matching.to_h { |key| [key, collection.public_send(key)] }
|
|
209
|
+
name = collection.qualified_name.inspect
|
|
210
|
+
|
|
211
|
+
"collection #{name} exists but does not match:\n" \
|
|
212
|
+
"\n expected: #{expected.inspect}" \
|
|
213
|
+
"\n actual: #{actual.inspect}"
|
|
214
|
+
end
|
|
215
|
+
|
|
155
216
|
def qualified_name_for(**parameters)
|
|
156
217
|
Cuprum::Collections::Relations::Parameters
|
|
157
218
|
.resolve_parameters(parameters)
|
|
158
219
|
.fetch(:qualified_name)
|
|
159
220
|
end
|
|
160
221
|
|
|
222
|
+
def tools
|
|
223
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
|
224
|
+
end
|
|
225
|
+
|
|
161
226
|
def valid_collection?(collection)
|
|
162
227
|
collection.respond_to?(:qualified_name)
|
|
163
228
|
end
|
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
require 'cuprum/collections/queries'
|
|
4
4
|
require 'cuprum/collections/rspec/contracts'
|
|
5
|
+
require 'cuprum/collections/rspec/deferred/query_examples'
|
|
5
6
|
require 'cuprum/collections/rspec/fixtures'
|
|
6
7
|
|
|
7
8
|
module Cuprum::Collections::RSpec::Contracts
|
|
8
9
|
# Contracts for asserting on Query objects.
|
|
9
10
|
module QueryContracts
|
|
11
|
+
include Cuprum::Collections::RSpec::Deferred::QueryExamples
|
|
12
|
+
|
|
10
13
|
# Contract validating the behavior of a Query implementation.
|
|
14
|
+
#
|
|
15
|
+
# @deprecated 0.6.0
|
|
11
16
|
module ShouldBeAQuery
|
|
12
17
|
extend RSpec::SleepingKingStudios::Contract
|
|
13
18
|
|
|
@@ -27,6 +32,11 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
27
32
|
contract do |abstract: false|
|
|
28
33
|
include Cuprum::Collections::RSpec::Contracts::QueryContracts
|
|
29
34
|
|
|
35
|
+
SleepingKingStudios::Tools::CoreTools.deprecate(
|
|
36
|
+
'QueryContracts "should be a query"',
|
|
37
|
+
message: 'Use Deferred::QueryExamples instead.'
|
|
38
|
+
)
|
|
39
|
+
|
|
30
40
|
shared_context 'when initialized with a scope' do
|
|
31
41
|
let(:initial_scope) do
|
|
32
42
|
Cuprum::Collections::Scope.new do |scope|
|
|
@@ -97,7 +107,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
97
107
|
context 'when the collection has many items' do
|
|
98
108
|
let(:data) { BOOKS_FIXTURES }
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
include_deferred 'should query the collection', ignore_order: true \
|
|
111
|
+
do
|
|
101
112
|
it { expect(scoped_query.count).to be == expected_data.count }
|
|
102
113
|
|
|
103
114
|
wrap_context 'when the query has composed filters' do
|
|
@@ -167,7 +178,7 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
167
178
|
context 'when the collection has many items' do
|
|
168
179
|
let(:data) { BOOKS_FIXTURES }
|
|
169
180
|
|
|
170
|
-
|
|
181
|
+
include_deferred 'should query the collection' do
|
|
171
182
|
include_examples 'should enumerate the matching data'
|
|
172
183
|
|
|
173
184
|
wrap_context 'when the query has composed filters' do
|
|
@@ -215,7 +226,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
215
226
|
context 'when the collection has many items' do
|
|
216
227
|
let(:data) { BOOKS_FIXTURES }
|
|
217
228
|
|
|
218
|
-
|
|
229
|
+
include_deferred 'should query the collection', ignore_order: true \
|
|
230
|
+
do
|
|
219
231
|
include_examples 'should check the existence of matching data'
|
|
220
232
|
|
|
221
233
|
wrap_context 'when the query has composed filters' do
|
|
@@ -549,7 +561,7 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
549
561
|
context 'when the collection has many items' do
|
|
550
562
|
let(:data) { BOOKS_FIXTURES }
|
|
551
563
|
|
|
552
|
-
|
|
564
|
+
include_deferred 'should query the collection' do
|
|
553
565
|
it { expect(queried_data).to be == expected_data }
|
|
554
566
|
|
|
555
567
|
wrap_context 'when the query has composed filters' do
|
|
@@ -766,12 +778,19 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
766
778
|
end
|
|
767
779
|
|
|
768
780
|
# Contract validating the behavior when performing queries.
|
|
781
|
+
#
|
|
782
|
+
# @deprecate 0.6.0 Use Deferred::QueryExamples instead.
|
|
769
783
|
module ShouldQueryTheCollectionContract
|
|
770
784
|
extend RSpec::SleepingKingStudios::Contract
|
|
771
785
|
|
|
772
786
|
contract do |*tags, &examples|
|
|
773
787
|
ignore_order = tags.include?(:ignore_order)
|
|
774
788
|
|
|
789
|
+
SleepingKingStudios::Tools::CoreTools.deprecate(
|
|
790
|
+
'QueryContracts "should query the collection"',
|
|
791
|
+
message: 'Use Deferred::QueryExamples instead.'
|
|
792
|
+
)
|
|
793
|
+
|
|
775
794
|
shared_examples 'should query the collection' do
|
|
776
795
|
# :nocov:
|
|
777
796
|
if examples
|
|
@@ -4,8 +4,13 @@ require 'cuprum/collections/rspec/contracts'
|
|
|
4
4
|
|
|
5
5
|
module Cuprum::Collections::RSpec::Contracts
|
|
6
6
|
# Contracts for asserting on Repository objects.
|
|
7
|
+
#
|
|
8
|
+
# @deprecated 0.6.0 Use RepositoryExamples instead.
|
|
9
|
+
# Note - requires defining a #build_collection(**options) helper method.
|
|
7
10
|
module RepositoryContracts
|
|
8
11
|
# Contract validating the behavior of a Repository.
|
|
12
|
+
#
|
|
13
|
+
# @deprecated 0.6.0
|
|
9
14
|
module ShouldBeARepositoryContract
|
|
10
15
|
extend RSpec::SleepingKingStudios::Contract
|
|
11
16
|
|
|
@@ -23,6 +28,14 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
23
28
|
# @option options entity_class [Class, String] the expected entity
|
|
24
29
|
# class.
|
|
25
30
|
contract do |abstract: false, **options|
|
|
31
|
+
SleepingKingStudios::Tools::Toolbelt
|
|
32
|
+
.instance
|
|
33
|
+
.core_tools
|
|
34
|
+
.deprecate(
|
|
35
|
+
'Cuprum::Collections::RSpec::Contracts::RepositoryContracts',
|
|
36
|
+
message: 'Use RepositoryExamples instead.'
|
|
37
|
+
)
|
|
38
|
+
|
|
26
39
|
shared_examples 'should create the collection' do
|
|
27
40
|
let(:configured_collection_class) do
|
|
28
41
|
return super() if defined?(super())
|
|
@@ -443,6 +456,11 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
443
456
|
'repository subclass and implement the #build_collection method.'
|
|
444
457
|
end
|
|
445
458
|
|
|
459
|
+
before(:example) do
|
|
460
|
+
allow(SleepingKingStudios::Tools::Toolbelt.instance.core_tools)
|
|
461
|
+
.to receive(:deprecate)
|
|
462
|
+
end
|
|
463
|
+
|
|
446
464
|
def create_collection(safe: true, **options)
|
|
447
465
|
if safe
|
|
448
466
|
begin
|
|
@@ -8,6 +8,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
8
8
|
# Contracts for asserting on scope objects.
|
|
9
9
|
module ScopeContracts
|
|
10
10
|
# Contract validating the behavior of a scope implementation.
|
|
11
|
+
#
|
|
12
|
+
# @deprecated 0.6.0
|
|
11
13
|
module ShouldBeAScopeContract
|
|
12
14
|
extend RSpec::SleepingKingStudios::Contract
|
|
13
15
|
|
|
@@ -19,6 +21,16 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
19
21
|
# @param invertible [Boolean] if true, the scope defines an
|
|
20
22
|
# implementation of the #invert method. Defaults to false.
|
|
21
23
|
contract do |invertible: false|
|
|
24
|
+
message = 'Use deferred examples "should implement the Scope methods"'
|
|
25
|
+
|
|
26
|
+
SleepingKingStudios::Tools::Toolbelt
|
|
27
|
+
.instance
|
|
28
|
+
.core_tools
|
|
29
|
+
.deprecate(
|
|
30
|
+
'ShouldBeAScopeContract',
|
|
31
|
+
message:
|
|
32
|
+
)
|
|
33
|
+
|
|
22
34
|
describe '#==' do
|
|
23
35
|
it { expect(subject == nil).to be false } # rubocop:disable Style/NilComparison
|
|
24
36
|
|
|
@@ -73,6 +85,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
73
85
|
end
|
|
74
86
|
|
|
75
87
|
# Contract validating the behavior of a Container scope implementation.
|
|
88
|
+
#
|
|
89
|
+
# @deprecated 0.6.0
|
|
76
90
|
module ShouldBeAContainerScopeContract
|
|
77
91
|
extend RSpec::SleepingKingStudios::Contract
|
|
78
92
|
|
|
@@ -84,6 +98,17 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
84
98
|
# @param invertible [Boolean] if true, the scope defines an
|
|
85
99
|
# implementation of the #invert method. Defaults to false.
|
|
86
100
|
contract do |invertible: false|
|
|
101
|
+
message =
|
|
102
|
+
'Use deferred examples "should implement the Scope methods" and ' \
|
|
103
|
+
'"should define child scopes"'
|
|
104
|
+
SleepingKingStudios::Tools::Toolbelt
|
|
105
|
+
.instance
|
|
106
|
+
.core_tools
|
|
107
|
+
.deprecate(
|
|
108
|
+
'ShouldBeADisjunctionScopeContract',
|
|
109
|
+
message:
|
|
110
|
+
)
|
|
111
|
+
|
|
87
112
|
shared_context 'with scopes' do
|
|
88
113
|
let(:scopes) do
|
|
89
114
|
[
|
|
@@ -272,6 +297,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
272
297
|
end
|
|
273
298
|
|
|
274
299
|
# Contract validating the behavior of an All scope implementation.
|
|
300
|
+
#
|
|
301
|
+
# @deprecated 0.6.0
|
|
275
302
|
module ShouldBeAnAllScopeContract
|
|
276
303
|
extend RSpec::SleepingKingStudios::Contract
|
|
277
304
|
|
|
@@ -283,6 +310,17 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
283
310
|
# @param abstract [Boolean] if true, the scope is abstract and does not
|
|
284
311
|
# define a #call implementation. Defaults to false.
|
|
285
312
|
contract do |abstract: false|
|
|
313
|
+
message =
|
|
314
|
+
'Use deferred examples "should implement the AllScope methods"'
|
|
315
|
+
|
|
316
|
+
SleepingKingStudios::Tools::Toolbelt
|
|
317
|
+
.instance
|
|
318
|
+
.core_tools
|
|
319
|
+
.deprecate(
|
|
320
|
+
'ShouldBeAnAllScopeContract',
|
|
321
|
+
message:
|
|
322
|
+
)
|
|
323
|
+
|
|
286
324
|
include_contract 'should be a scope', invertible: true
|
|
287
325
|
|
|
288
326
|
describe '#==' do
|
|
@@ -653,6 +691,8 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
653
691
|
end
|
|
654
692
|
|
|
655
693
|
# Contract validating the behavior of a None scope implementation.
|
|
694
|
+
#
|
|
695
|
+
# @deprecated 0.6.0
|
|
656
696
|
module ShouldBeANoneScopeContract
|
|
657
697
|
extend RSpec::SleepingKingStudios::Contract
|
|
658
698
|
|
|
@@ -664,6 +704,17 @@ module Cuprum::Collections::RSpec::Contracts
|
|
|
664
704
|
# @param abstract [Boolean] if true, the scope is abstract and does not
|
|
665
705
|
# define a #call implementation. Defaults to false.
|
|
666
706
|
contract do |abstract: false|
|
|
707
|
+
message =
|
|
708
|
+
'Use deferred examples "should implement the NoneScope methods"'
|
|
709
|
+
|
|
710
|
+
SleepingKingStudios::Tools::Toolbelt
|
|
711
|
+
.instance
|
|
712
|
+
.core_tools
|
|
713
|
+
.deprecate(
|
|
714
|
+
'ShouldBeANoneScopeContract',
|
|
715
|
+
message:
|
|
716
|
+
)
|
|
717
|
+
|
|
667
718
|
include_contract 'should be a scope', invertible: true
|
|
668
719
|
|
|
669
720
|
describe '#==' do
|
|
@@ -15,6 +15,8 @@ module Cuprum::Collections::RSpec::Contracts::Scopes
|
|
|
15
15
|
include Cuprum::Collections::RSpec::Contracts::Scopes::CriteriaContracts
|
|
16
16
|
|
|
17
17
|
# Contract validating the behavior of a scope builder implementation.
|
|
18
|
+
#
|
|
19
|
+
# @deprecated 0.6.0
|
|
18
20
|
module ShouldBeAScopeBuilderContract
|
|
19
21
|
extend RSpec::SleepingKingStudios::Contract
|
|
20
22
|
|
|
@@ -44,6 +46,14 @@ module Cuprum::Collections::RSpec::Contracts::Scopes
|
|
|
44
46
|
disjunction_scope_class = contract_options[:disjunction_class]
|
|
45
47
|
none_scope_class = contract_options[:none_class]
|
|
46
48
|
|
|
49
|
+
SleepingKingStudios::Tools::Toolbelt
|
|
50
|
+
.instance
|
|
51
|
+
.core_tools
|
|
52
|
+
.deprecate(
|
|
53
|
+
'ShouldBeAScopeBuilderContract',
|
|
54
|
+
message: 'Use deferred examples "should build collection Scopes"'
|
|
55
|
+
)
|
|
56
|
+
|
|
47
57
|
shared_context 'with container scope helpers' do
|
|
48
58
|
let(:scope) { build_container(scopes:) }
|
|
49
59
|
|