cuprum-collections 0.1.0 → 0.3.0.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +321 -15
- data/lib/cuprum/collections/basic/collection.rb +13 -0
- data/lib/cuprum/collections/basic/commands/destroy_one.rb +4 -3
- data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
- data/lib/cuprum/collections/basic/commands/insert_one.rb +4 -3
- data/lib/cuprum/collections/basic/commands/update_one.rb +4 -3
- data/lib/cuprum/collections/basic/query.rb +3 -3
- data/lib/cuprum/collections/basic/repository.rb +67 -0
- data/lib/cuprum/collections/commands/abstract_find_many.rb +33 -32
- data/lib/cuprum/collections/commands/abstract_find_one.rb +4 -3
- data/lib/cuprum/collections/commands/create.rb +60 -0
- data/lib/cuprum/collections/commands/find_one_matching.rb +134 -0
- data/lib/cuprum/collections/commands/update.rb +74 -0
- data/lib/cuprum/collections/commands/upsert.rb +162 -0
- data/lib/cuprum/collections/commands.rb +7 -2
- data/lib/cuprum/collections/errors/abstract_find_error.rb +210 -0
- data/lib/cuprum/collections/errors/already_exists.rb +4 -72
- data/lib/cuprum/collections/errors/extra_attributes.rb +8 -18
- data/lib/cuprum/collections/errors/failed_validation.rb +5 -18
- data/lib/cuprum/collections/errors/invalid_parameters.rb +7 -15
- data/lib/cuprum/collections/errors/invalid_query.rb +5 -15
- data/lib/cuprum/collections/errors/missing_default_contract.rb +5 -17
- data/lib/cuprum/collections/errors/not_found.rb +4 -67
- data/lib/cuprum/collections/errors/not_unique.rb +18 -0
- data/lib/cuprum/collections/errors/unknown_operator.rb +7 -17
- data/lib/cuprum/collections/errors.rb +13 -1
- data/lib/cuprum/collections/queries/ordering.rb +4 -2
- data/lib/cuprum/collections/repository.rb +105 -0
- data/lib/cuprum/collections/rspec/assign_one_command_contract.rb +2 -2
- data/lib/cuprum/collections/rspec/build_one_command_contract.rb +1 -1
- data/lib/cuprum/collections/rspec/collection_contract.rb +140 -103
- data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +8 -6
- data/lib/cuprum/collections/rspec/find_many_command_contract.rb +114 -34
- data/lib/cuprum/collections/rspec/find_one_command_contract.rb +12 -9
- data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +4 -3
- data/lib/cuprum/collections/rspec/query_contract.rb +3 -3
- data/lib/cuprum/collections/rspec/querying_contract.rb +2 -2
- data/lib/cuprum/collections/rspec/repository_contract.rb +235 -0
- data/lib/cuprum/collections/rspec/update_one_command_contract.rb +4 -3
- data/lib/cuprum/collections/version.rb +3 -3
- data/lib/cuprum/collections.rb +1 -0
- metadata +25 -91
@@ -0,0 +1,210 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/collections/errors'
|
4
|
+
|
5
|
+
module Cuprum::Collections::Errors
|
6
|
+
# Abstract base class for failed query errors.
|
7
|
+
class AbstractFindError < Cuprum::Error # rubocop:disable Metrics/ClassLength
|
8
|
+
PERMITTED_KEYWORDS = %i[
|
9
|
+
attribute_name
|
10
|
+
attribute_value
|
11
|
+
attributes
|
12
|
+
primary_key
|
13
|
+
query
|
14
|
+
].freeze
|
15
|
+
private_constant :PERMITTED_KEYWORDS
|
16
|
+
|
17
|
+
# @overload initialize(attribute_name:, attribute_value:, collection_name:, primary_key: false) # rubocop:disable Layout/LineLength
|
18
|
+
# @param attribute_name [String] The name of the queried attribute.
|
19
|
+
# @param attribute_value [Object] The value of the queried attribute.
|
20
|
+
# @param collection_name [String] The name of the collection.
|
21
|
+
# @param primary_key [true, false] Indicates that the queried attribute is
|
22
|
+
# the primary key for the collection.
|
23
|
+
#
|
24
|
+
# @overload initialize(attributes:, collection_name:)
|
25
|
+
# @param attributes [Hash<String=>Object>] The queried attributes.
|
26
|
+
# @param collection_name [String] The name of the collection.
|
27
|
+
#
|
28
|
+
# @overload initialize(query:, collection_name:)
|
29
|
+
# @param collection_name [String] The name of the collection.
|
30
|
+
# @param query [Cuprum::Collections::Query] The performed query.
|
31
|
+
def initialize(collection_name:, **options) # rubocop:disable Metrics/MethodLength
|
32
|
+
@collection_name = collection_name
|
33
|
+
@primary_key = false
|
34
|
+
|
35
|
+
resolve_options(**options)
|
36
|
+
|
37
|
+
super(
|
38
|
+
attribute_name: attribute_name,
|
39
|
+
attribute_value: attribute_value,
|
40
|
+
attributes: attributes,
|
41
|
+
collection_name: collection_name,
|
42
|
+
message: generate_message,
|
43
|
+
query: query&.criteria
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [String] the name of the queried attribute, if any.
|
48
|
+
attr_reader :attribute_name
|
49
|
+
|
50
|
+
# @return [Object] the value of the queried attribute, if any.
|
51
|
+
attr_reader :attribute_value
|
52
|
+
|
53
|
+
# @return [Hash<String=>Object>] The queried attributes.
|
54
|
+
attr_reader :attributes
|
55
|
+
|
56
|
+
# @return [String] the name of the collection.
|
57
|
+
attr_reader :collection_name
|
58
|
+
|
59
|
+
# @return [Cuprum::Collections::Query] the performed query, if any.
|
60
|
+
attr_reader :query
|
61
|
+
|
62
|
+
# @return [Array<Array>] the details of the query, in query criteria format.
|
63
|
+
def details
|
64
|
+
if attribute_name
|
65
|
+
[[attribute_name, :equal, attribute_value]]
|
66
|
+
elsif attributes
|
67
|
+
attributes
|
68
|
+
.map { |attr_name, attr_value| [attr_name, :equal, attr_value] }
|
69
|
+
elsif query
|
70
|
+
query.criteria
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [true, false] indicates that the queried attribute is the primary
|
75
|
+
# key for the collection.
|
76
|
+
def primary_key?
|
77
|
+
@primary_key
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def as_json_data
|
83
|
+
{
|
84
|
+
'collection_name' => collection_name,
|
85
|
+
'details' => details
|
86
|
+
}.merge(find_data)
|
87
|
+
end
|
88
|
+
|
89
|
+
def entity_name
|
90
|
+
titleize(tools.str.singularize(collection_name))
|
91
|
+
end
|
92
|
+
|
93
|
+
def find_data # rubocop:disable Metrics/MethodLength
|
94
|
+
if attribute_name
|
95
|
+
{
|
96
|
+
'attribute_name' => attribute_name,
|
97
|
+
'attribute_value' => attribute_value,
|
98
|
+
'primary_key' => primary_key?
|
99
|
+
}
|
100
|
+
elsif attributes
|
101
|
+
hsh = tools.hash_tools.convert_keys_to_strings(attributes)
|
102
|
+
|
103
|
+
{ 'attributes' => hsh }
|
104
|
+
else
|
105
|
+
{}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def generate_message
|
110
|
+
core_message = "#{entity_name} #{message_fragment}"
|
111
|
+
|
112
|
+
if attribute_name
|
113
|
+
"#{core_message} with #{attribute_name.inspect} " \
|
114
|
+
"#{attribute_value.inspect}" \
|
115
|
+
"#{primary_key? ? ' (primary key)' : ''}"
|
116
|
+
elsif attributes
|
117
|
+
"#{core_message} with attributes #{attributes.inspect}"
|
118
|
+
elsif query
|
119
|
+
"#{core_message} matching the query"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def message_fragment
|
124
|
+
'query failed'
|
125
|
+
end
|
126
|
+
|
127
|
+
def resolve_attribute_options(**options)
|
128
|
+
options = options.dup
|
129
|
+
@attribute_name = options.delete(:attribute_name)
|
130
|
+
@attribute_value = options.delete(:attribute_value)
|
131
|
+
@primary_key = options.delete(:primary_key) || false
|
132
|
+
|
133
|
+
validate_keywords(extra_keywords: options.keys)
|
134
|
+
end
|
135
|
+
|
136
|
+
def resolve_attributes_options(**options)
|
137
|
+
options = options.dup
|
138
|
+
@attributes = options.delete(:attributes)
|
139
|
+
|
140
|
+
validate_keywords(extra_keywords: options.keys)
|
141
|
+
end
|
142
|
+
|
143
|
+
def resolve_query_options(**options)
|
144
|
+
options = options.dup
|
145
|
+
@query = options.delete(:query)
|
146
|
+
|
147
|
+
validate_keywords(extra_keywords: options.keys)
|
148
|
+
end
|
149
|
+
|
150
|
+
def resolve_options(**options) # rubocop:disable Metrics/MethodLength
|
151
|
+
if options[:primary_key_name] && options[:primary_key_values]
|
152
|
+
resolve_primary_key_options(**options)
|
153
|
+
elsif options[:attribute_name] && options.key?(:attribute_value)
|
154
|
+
resolve_attribute_options(**options)
|
155
|
+
elsif options[:attributes]
|
156
|
+
resolve_attributes_options(**options)
|
157
|
+
elsif options[:query]
|
158
|
+
resolve_query_options(**options)
|
159
|
+
else
|
160
|
+
raise ArgumentError,
|
161
|
+
'missing keywords :attribute_name, :attribute_value or :attributes ' \
|
162
|
+
'or :query'
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def resolve_primary_key_options(**options) # rubocop:disable Metrics/MethodLength
|
167
|
+
values = Array(options[:primary_key_values])
|
168
|
+
|
169
|
+
unless values.size == 1
|
170
|
+
raise ArgumentError,
|
171
|
+
'deprecated mode does not support empty or multiple attribute values'
|
172
|
+
end
|
173
|
+
|
174
|
+
SleepingKingStudios::Tools::CoreTools
|
175
|
+
.instance
|
176
|
+
.deprecate(
|
177
|
+
'NotFound.new(primary_key_name:, primary_key_values:)',
|
178
|
+
message: 'use NotFound.new(attribute_name:, attribute_value:)'
|
179
|
+
)
|
180
|
+
|
181
|
+
@attribute_name = options[:primary_key_name]
|
182
|
+
@attribute_value = values.first
|
183
|
+
@primary_key = true
|
184
|
+
end
|
185
|
+
|
186
|
+
def titleize(string)
|
187
|
+
tools.str.underscore(string).split('_').map(&:capitalize).join(' ')
|
188
|
+
end
|
189
|
+
|
190
|
+
def tools
|
191
|
+
SleepingKingStudios::Tools::Toolbelt.instance
|
192
|
+
end
|
193
|
+
|
194
|
+
def validate_keywords(extra_keywords:) # rubocop:disable Metrics/MethodLength
|
195
|
+
return if extra_keywords.empty?
|
196
|
+
|
197
|
+
ambiguous_keywords = extra_keywords & PERMITTED_KEYWORDS
|
198
|
+
|
199
|
+
if ambiguous_keywords.empty?
|
200
|
+
raise ArgumentError,
|
201
|
+
"unknown keyword#{extra_keywords.size == 1 ? '' : 's'} " \
|
202
|
+
"#{extra_keywords.map(&:inspect).join(', ')}"
|
203
|
+
else
|
204
|
+
raise ArgumentError,
|
205
|
+
"ambiguous keyword#{extra_keywords.size == 1 ? '' : 's'} " \
|
206
|
+
"#{ambiguous_keywords.map(&:inspect).join(', ')}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -1,86 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'cuprum/error'
|
4
|
-
|
5
3
|
require 'cuprum/collections/errors'
|
4
|
+
require 'cuprum/collections/errors/abstract_find_error'
|
6
5
|
|
7
6
|
module Cuprum::Collections::Errors
|
8
7
|
# Returned when an insert command is called with an existing record.
|
9
|
-
class AlreadyExists < Cuprum::
|
8
|
+
class AlreadyExists < Cuprum::Collections::Errors::AbstractFindError
|
10
9
|
# Short string used to identify the type of error.
|
11
10
|
TYPE = 'cuprum.collections.errors.already_exists'
|
12
11
|
|
13
|
-
# @param collection_name [String, Symbol] The name of the collection.
|
14
|
-
# @param primary_key_name [String, Symbol] The name of the primary key
|
15
|
-
# attribute.
|
16
|
-
# @param primary_key_values [Object, Array] The expected values of the
|
17
|
-
# primary key attribute.
|
18
|
-
def initialize(collection_name:, primary_key_name:, primary_key_values:)
|
19
|
-
@collection_name = collection_name
|
20
|
-
@primary_key_name = primary_key_name
|
21
|
-
@primary_key_values = Array(primary_key_values)
|
22
|
-
|
23
|
-
super(
|
24
|
-
collection_name: collection_name,
|
25
|
-
message: default_message,
|
26
|
-
primary_key_name: primary_key_name,
|
27
|
-
primary_key_values: primary_key_values
|
28
|
-
)
|
29
|
-
end
|
30
|
-
|
31
|
-
# @return [String, Symbol] the name of the collection.
|
32
|
-
attr_reader :collection_name
|
33
|
-
|
34
|
-
# @return [String, Symbol] the name of the primary key attribute.
|
35
|
-
attr_reader :primary_key_name
|
36
|
-
|
37
|
-
# @return [Array] The expected values of the primary key attribute.
|
38
|
-
attr_reader :primary_key_values
|
39
|
-
|
40
|
-
# @return [Hash] a serializable hash representation of the error.
|
41
|
-
def as_json
|
42
|
-
{
|
43
|
-
'data' => {
|
44
|
-
'collection_name' => collection_name,
|
45
|
-
'primary_key_name' => primary_key_name,
|
46
|
-
'primary_key_values' => primary_key_values
|
47
|
-
},
|
48
|
-
'message' => message,
|
49
|
-
'type' => type
|
50
|
-
}
|
51
|
-
end
|
52
|
-
|
53
|
-
# @return [String] short string used to identify the type of error.
|
54
|
-
def type
|
55
|
-
TYPE
|
56
|
-
end
|
57
|
-
|
58
12
|
private
|
59
13
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
"#{entity_name} already exist#{singular? ? 's' : ''} with" \
|
64
|
-
" #{primary_key_name} #{primary_keys}"
|
65
|
-
end
|
66
|
-
|
67
|
-
def entity_name
|
68
|
-
entity_name = collection_name
|
69
|
-
entity_name = tools.str.singularize(entity_name) if singular?
|
70
|
-
|
71
|
-
titleize(entity_name)
|
72
|
-
end
|
73
|
-
|
74
|
-
def singular?
|
75
|
-
primary_key_values.size == 1
|
76
|
-
end
|
77
|
-
|
78
|
-
def titleize(string)
|
79
|
-
tools.str.underscore(string).split('_').map(&:capitalize).join(' ')
|
80
|
-
end
|
81
|
-
|
82
|
-
def tools
|
83
|
-
SleepingKingStudios::Tools::Toolbelt.instance
|
14
|
+
def message_fragment
|
15
|
+
'already exists'
|
84
16
|
end
|
85
17
|
end
|
86
18
|
end
|
@@ -38,29 +38,19 @@ module Cuprum::Collections::Errors
|
|
38
38
|
# @return [Array<String>] The names of valid attributes for the entity.
|
39
39
|
attr_reader :valid_attributes
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
private
|
42
|
+
|
43
|
+
def as_json_data
|
43
44
|
{
|
44
|
-
'
|
45
|
-
|
46
|
-
|
47
|
-
'valid_attributes' => valid_attributes
|
48
|
-
},
|
49
|
-
'message' => message,
|
50
|
-
'type' => type
|
45
|
+
'entity_class' => entity_class.name,
|
46
|
+
'extra_attributes' => extra_attributes,
|
47
|
+
'valid_attributes' => valid_attributes
|
51
48
|
}
|
52
49
|
end
|
53
50
|
|
54
|
-
# @return [String] short string used to identify the type of error.
|
55
|
-
def type
|
56
|
-
TYPE
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
51
|
def default_message
|
62
|
-
"invalid attributes for #{entity_class.name}:" \
|
63
|
-
"
|
52
|
+
"invalid attributes for #{entity_class.name}: " \
|
53
|
+
"#{extra_attributes.join(', ')}"
|
64
54
|
end
|
65
55
|
end
|
66
56
|
end
|
@@ -7,9 +7,6 @@ require 'cuprum/collections/errors'
|
|
7
7
|
module Cuprum::Collections::Errors
|
8
8
|
# Error returned when a collection item fails validation.
|
9
9
|
class FailedValidation < Cuprum::Error
|
10
|
-
COMPARABLE_PROPERTIES = %i[entity_class errors message].freeze
|
11
|
-
private_constant :COMPARABLE_PROPERTIES
|
12
|
-
|
13
10
|
# Short string used to identify the type of error.
|
14
11
|
TYPE = 'cuprum.collections.errors.failed_validation'
|
15
12
|
|
@@ -33,25 +30,15 @@ module Cuprum::Collections::Errors
|
|
33
30
|
# @return [Stannum::Errors] The errors generated when validating the entity.
|
34
31
|
attr_reader :errors
|
35
32
|
|
36
|
-
|
37
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
def as_json_data
|
38
36
|
{
|
39
|
-
'
|
40
|
-
|
41
|
-
'errors' => format_errors
|
42
|
-
},
|
43
|
-
'message' => message,
|
44
|
-
'type' => type
|
37
|
+
'entity_class' => entity_class.name,
|
38
|
+
'errors' => format_errors
|
45
39
|
}
|
46
40
|
end
|
47
41
|
|
48
|
-
# @return [String] short string used to identify the type of error.
|
49
|
-
def type
|
50
|
-
TYPE
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
42
|
def default_message
|
56
43
|
"#{entity_class.name} failed validation"
|
57
44
|
end
|
@@ -24,27 +24,19 @@ module Cuprum::Collections::Errors
|
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
|
-
# @return [Hash] a serializable hash representation of the error.
|
28
|
-
def as_json
|
29
|
-
{
|
30
|
-
'data' => {
|
31
|
-
'command_class' => command.class.name,
|
32
|
-
'errors' => errors.to_a
|
33
|
-
},
|
34
|
-
'message' => message,
|
35
|
-
'type' => type
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
27
|
# @return [Cuprum::Command] the called command.
|
40
28
|
attr_reader :command
|
41
29
|
|
42
30
|
# @return [Stannum::Errors] the errors returned by the parameters contract.
|
43
31
|
attr_reader :errors
|
44
32
|
|
45
|
-
|
46
|
-
|
47
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
def as_json_data
|
36
|
+
{
|
37
|
+
'command_class' => command.class.name,
|
38
|
+
'errors' => errors.to_a
|
39
|
+
}
|
48
40
|
end
|
49
41
|
end
|
50
42
|
end
|
@@ -29,25 +29,15 @@ module Cuprum::Collections::Errors
|
|
29
29
|
# @return [Symbol] the strategy used to construct the query.
|
30
30
|
attr_reader :strategy
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
private
|
33
|
+
|
34
|
+
def as_json_data
|
34
35
|
{
|
35
|
-
'
|
36
|
-
|
37
|
-
'strategy' => strategy
|
38
|
-
},
|
39
|
-
'message' => message,
|
40
|
-
'type' => type
|
36
|
+
'errors' => errors.to_a,
|
37
|
+
'strategy' => strategy
|
41
38
|
}
|
42
39
|
end
|
43
40
|
|
44
|
-
# @return [String] short string used to identify the type of error.
|
45
|
-
def type
|
46
|
-
TYPE
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
41
|
def default_message
|
52
42
|
"unable to parse query with strategy #{strategy.inspect}"
|
53
43
|
end
|
@@ -23,27 +23,15 @@ module Cuprum::Collections::Errors
|
|
23
23
|
# @return [Class] the class of the assigned entity.
|
24
24
|
attr_reader :entity_class
|
25
25
|
|
26
|
-
|
27
|
-
def as_json
|
28
|
-
{
|
29
|
-
'data' => {
|
30
|
-
'entity_class' => entity_class.name
|
31
|
-
},
|
32
|
-
'message' => message,
|
33
|
-
'type' => type
|
34
|
-
}
|
35
|
-
end
|
26
|
+
private
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
TYPE
|
28
|
+
def as_json_data
|
29
|
+
{ 'entity_class' => entity_class.name }
|
40
30
|
end
|
41
31
|
|
42
|
-
private
|
43
|
-
|
44
32
|
def default_message
|
45
|
-
"attempted to validate a #{entity_class.name}, but
|
46
|
-
|
33
|
+
"attempted to validate a #{entity_class.name}, but " \
|
34
|
+
"#{entity_class.name} does not define a default contract"
|
47
35
|
end
|
48
36
|
end
|
49
37
|
end
|
@@ -1,81 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'cuprum/error'
|
4
|
-
require 'sleeping_king_studios/tools/toolbelt'
|
5
|
-
|
6
3
|
require 'cuprum/collections/errors'
|
4
|
+
require 'cuprum/collections/errors/abstract_find_error'
|
7
5
|
|
8
6
|
module Cuprum::Collections::Errors
|
9
7
|
# Returned when a find command does not find the requested items.
|
10
|
-
class NotFound < Cuprum::
|
8
|
+
class NotFound < Cuprum::Collections::Errors::AbstractFindError
|
11
9
|
# Short string used to identify the type of error.
|
12
10
|
TYPE = 'cuprum.collections.errors.not_found'
|
13
11
|
|
14
|
-
# @param collection_name [String, Symbol] The name of the collection.
|
15
|
-
# @param primary_key_name [String, Symbol] The name of the primary key
|
16
|
-
# attribute.
|
17
|
-
# @param primary_key_values [Object, Array] The expected values of the
|
18
|
-
# primary key attribute.
|
19
|
-
def initialize(collection_name:, primary_key_name:, primary_key_values:)
|
20
|
-
@collection_name = collection_name
|
21
|
-
@primary_key_name = primary_key_name
|
22
|
-
@primary_key_values = Array(primary_key_values)
|
23
|
-
|
24
|
-
super(message: default_message)
|
25
|
-
end
|
26
|
-
|
27
|
-
# @return [String, Symbol] the name of the collection.
|
28
|
-
attr_reader :collection_name
|
29
|
-
|
30
|
-
# @return [String, Symbol] the name of the primary key attribute.
|
31
|
-
attr_reader :primary_key_name
|
32
|
-
|
33
|
-
# @return [Array] The expected values of the primary key attribute.
|
34
|
-
attr_reader :primary_key_values
|
35
|
-
|
36
|
-
# @return [Hash] a serializable hash representation of the error.
|
37
|
-
def as_json
|
38
|
-
{
|
39
|
-
'data' => {
|
40
|
-
'collection_name' => collection_name,
|
41
|
-
'primary_key_name' => primary_key_name,
|
42
|
-
'primary_key_values' => primary_key_values
|
43
|
-
},
|
44
|
-
'message' => message,
|
45
|
-
'type' => type
|
46
|
-
}
|
47
|
-
end
|
48
|
-
|
49
|
-
# @return [String] short string used to identify the type of error.
|
50
|
-
def type
|
51
|
-
TYPE
|
52
|
-
end
|
53
|
-
|
54
12
|
private
|
55
13
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
"#{entity_name} not found with #{primary_key_name} #{primary_keys}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def entity_name
|
63
|
-
entity_name = collection_name
|
64
|
-
entity_name = tools.str.singularize(entity_name) if singular?
|
65
|
-
|
66
|
-
titleize(entity_name)
|
67
|
-
end
|
68
|
-
|
69
|
-
def singular?
|
70
|
-
primary_key_values.size == 1
|
71
|
-
end
|
72
|
-
|
73
|
-
def titleize(string)
|
74
|
-
tools.str.underscore(string).split('_').map(&:capitalize).join(' ')
|
75
|
-
end
|
76
|
-
|
77
|
-
def tools
|
78
|
-
SleepingKingStudios::Tools::Toolbelt.instance
|
14
|
+
def message_fragment
|
15
|
+
'not found'
|
79
16
|
end
|
80
17
|
end
|
81
18
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cuprum/collections/errors'
|
4
|
+
require 'cuprum/collections/errors/abstract_find_error'
|
5
|
+
|
6
|
+
module Cuprum::Collections::Errors
|
7
|
+
# Returned when a unique find command does finds multiple items.
|
8
|
+
class NotUnique < Cuprum::Collections::Errors::AbstractFindError
|
9
|
+
# Short string used to identify the type of error.
|
10
|
+
TYPE = 'cuprum.collections.errors.not_unique'
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def message_fragment
|
15
|
+
'not unique'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -22,18 +22,6 @@ module Cuprum::Collections::Errors
|
|
22
22
|
# @return [String, Symbol] the unknown operator.
|
23
23
|
attr_reader :operator
|
24
24
|
|
25
|
-
# @return [Hash] a serializable hash representation of the error.
|
26
|
-
def as_json
|
27
|
-
{
|
28
|
-
'data' => {
|
29
|
-
'corrections' => corrections,
|
30
|
-
'operator' => operator
|
31
|
-
},
|
32
|
-
'message' => message,
|
33
|
-
'type' => type
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
25
|
# @return [Array<String>] Suggested possible values for the operator.
|
38
26
|
def corrections
|
39
27
|
@corrections ||=
|
@@ -42,13 +30,15 @@ module Cuprum::Collections::Errors
|
|
42
30
|
.correct(operator)
|
43
31
|
end
|
44
32
|
|
45
|
-
# @return [String] short string used to identify the type of error.
|
46
|
-
def type
|
47
|
-
TYPE
|
48
|
-
end
|
49
|
-
|
50
33
|
private
|
51
34
|
|
35
|
+
def as_json_data
|
36
|
+
{
|
37
|
+
'corrections' => corrections,
|
38
|
+
'operator' => operator
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
52
42
|
def generate_message
|
53
43
|
message = "unknown operator #{operator.inspect}"
|
54
44
|
|
@@ -4,5 +4,17 @@ require 'cuprum/collections'
|
|
4
4
|
|
5
5
|
module Cuprum::Collections
|
6
6
|
# Namespace for errors, which represent failure states of commands.
|
7
|
-
module Errors
|
7
|
+
module Errors
|
8
|
+
autoload :AbstractFindError, 'cuprum/collections/errors/abstract_find_error'
|
9
|
+
autoload :AlreadyExists, 'cuprum/collections/errors/already_exists'
|
10
|
+
autoload :ExtraAttributes, 'cuprum/collections/errors/extra_attributes'
|
11
|
+
autoload :FailedValidation, 'cuprum/collections/errors/failed_validation'
|
12
|
+
autoload :InvalidParameters, 'cuprum/collections/errors/invalid_parameters'
|
13
|
+
autoload :InvalidQuery, 'cuprum/collections/errors/invalid_query'
|
14
|
+
autoload :MissingDefaultContract,
|
15
|
+
'cuprum/collections/errors/missing_default_contract'
|
16
|
+
autoload :NotFound, 'cuprum/collections/errors/not_found'
|
17
|
+
autoload :NotUnique, 'cuprum/collections/errors/not_unique'
|
18
|
+
autoload :UnknownOperator, 'cuprum/collections/errors/unknown_operator'
|
19
|
+
end
|
8
20
|
end
|
@@ -33,6 +33,8 @@ module Cuprum::Collections::Queries
|
|
33
33
|
# @raise InvalidOrderError if any of the hash keys are invalid attribute
|
34
34
|
# names, or any of the hash values are invalid sort directions.
|
35
35
|
def normalize(*attributes)
|
36
|
+
attributes = attributes.flatten if attributes.first.is_a?(Array)
|
37
|
+
|
36
38
|
validate_ordering!(attributes)
|
37
39
|
|
38
40
|
qualified = attributes.last.is_a?(Hash) ? attributes.pop : {}
|
@@ -66,8 +68,8 @@ module Cuprum::Collections::Queries
|
|
66
68
|
return if ordering_constraint.matches?(attributes)
|
67
69
|
|
68
70
|
raise InvalidOrderError,
|
69
|
-
'order must be a list of attribute names and/or a hash of
|
70
|
-
' names with values :asc or :desc'
|
71
|
+
'order must be a list of attribute names and/or a hash of ' \
|
72
|
+
'attribute names with values :asc or :desc'
|
71
73
|
end
|
72
74
|
end
|
73
75
|
end
|