cuprum-collections 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +255 -8
  4. data/lib/cuprum/collections/basic/collection.rb +13 -0
  5. data/lib/cuprum/collections/basic/commands/destroy_one.rb +4 -3
  6. data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
  7. data/lib/cuprum/collections/basic/commands/insert_one.rb +4 -3
  8. data/lib/cuprum/collections/basic/commands/update_one.rb +4 -3
  9. data/lib/cuprum/collections/basic/query.rb +3 -3
  10. data/lib/cuprum/collections/commands/abstract_find_many.rb +33 -32
  11. data/lib/cuprum/collections/commands/abstract_find_one.rb +4 -3
  12. data/lib/cuprum/collections/commands/create.rb +60 -0
  13. data/lib/cuprum/collections/commands/find_one_matching.rb +134 -0
  14. data/lib/cuprum/collections/commands/update.rb +74 -0
  15. data/lib/cuprum/collections/commands/upsert.rb +162 -0
  16. data/lib/cuprum/collections/commands.rb +7 -2
  17. data/lib/cuprum/collections/errors/abstract_find_error.rb +210 -0
  18. data/lib/cuprum/collections/errors/already_exists.rb +4 -72
  19. data/lib/cuprum/collections/errors/extra_attributes.rb +8 -18
  20. data/lib/cuprum/collections/errors/failed_validation.rb +5 -18
  21. data/lib/cuprum/collections/errors/invalid_parameters.rb +7 -15
  22. data/lib/cuprum/collections/errors/invalid_query.rb +5 -15
  23. data/lib/cuprum/collections/errors/missing_default_contract.rb +5 -17
  24. data/lib/cuprum/collections/errors/not_found.rb +4 -67
  25. data/lib/cuprum/collections/errors/not_unique.rb +18 -0
  26. data/lib/cuprum/collections/errors/unknown_operator.rb +7 -17
  27. data/lib/cuprum/collections/errors.rb +13 -1
  28. data/lib/cuprum/collections/queries/ordering.rb +2 -2
  29. data/lib/cuprum/collections/repository.rb +23 -10
  30. data/lib/cuprum/collections/rspec/collection_contract.rb +140 -103
  31. data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +8 -6
  32. data/lib/cuprum/collections/rspec/find_many_command_contract.rb +114 -34
  33. data/lib/cuprum/collections/rspec/find_one_command_contract.rb +12 -9
  34. data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +4 -3
  35. data/lib/cuprum/collections/rspec/query_contract.rb +3 -3
  36. data/lib/cuprum/collections/rspec/querying_contract.rb +2 -2
  37. data/lib/cuprum/collections/rspec/repository_contract.rb +167 -93
  38. data/lib/cuprum/collections/rspec/update_one_command_contract.rb +4 -3
  39. data/lib/cuprum/collections/version.rb +1 -1
  40. data/lib/cuprum/collections.rb +1 -0
  41. metadata +20 -89
@@ -1,57 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'rspec/sleeping_king_studios/contract'
4
+
3
5
  require 'cuprum/collections/rspec'
4
6
 
5
7
  module Cuprum::Collections::RSpec
6
8
  # Contract validating the behavior of a Repository.
7
- REPOSITORY_CONTRACT = lambda do
8
- describe '#[]' do
9
- let(:error_class) do
10
- described_class::UndefinedCollectionError
11
- end
12
- let(:error_message) do
13
- "repository does not define collection #{collection_name.inspect}"
14
- end
15
-
16
- it { expect(repository).to respond_to(:[]).with(1).argument }
17
-
18
- describe 'with nil' do
19
- let(:collection_name) { nil }
20
-
21
- it 'should raise an exception' do
22
- expect { repository[collection_name] }
23
- .to raise_error(error_class, error_message)
9
+ module RepositoryContract
10
+ extend RSpec::SleepingKingStudios::Contract
11
+
12
+ # @!method apply(example_group)
13
+ # Adds the contract to the example group.
14
+ #
15
+ # @param example_group [RSpec::Core::ExampleGroup] The example group to
16
+ # which the contract is applied.
17
+ contract do
18
+ describe '#[]' do
19
+ let(:error_class) do
20
+ described_class::UndefinedCollectionError
24
21
  end
25
- end
26
-
27
- describe 'with an object' do
28
- let(:collection_name) { Object.new.freeze }
29
-
30
- it 'should raise an exception' do
31
- expect { repository[collection_name] }
32
- .to raise_error(error_class, error_message)
22
+ let(:error_message) do
23
+ "repository does not define collection #{collection_name.inspect}"
33
24
  end
34
- end
35
25
 
36
- describe 'with an invalid string' do
37
- let(:collection_name) { 'invalid_name' }
26
+ it { expect(repository).to respond_to(:[]).with(1).argument }
38
27
 
39
- it 'should raise an exception' do
40
- expect { repository[collection_name] }
41
- .to raise_error(error_class, error_message)
28
+ describe 'with nil' do
29
+ let(:collection_name) { nil }
30
+
31
+ it 'should raise an exception' do
32
+ expect { repository[collection_name] }
33
+ .to raise_error(error_class, error_message)
34
+ end
42
35
  end
43
- end
44
36
 
45
- describe 'with an invalid symbol' do
46
- let(:collection_name) { :invalid_name }
37
+ describe 'with an object' do
38
+ let(:collection_name) { Object.new.freeze }
47
39
 
48
- it 'should raise an exception' do
49
- expect { repository[collection_name] }
50
- .to raise_error(error_class, error_message)
40
+ it 'should raise an exception' do
41
+ expect { repository[collection_name] }
42
+ .to raise_error(error_class, error_message)
43
+ end
51
44
  end
52
- end
53
45
 
54
- wrap_context 'when the repository has many collections' do
55
46
  describe 'with an invalid string' do
56
47
  let(:collection_name) { 'invalid_name' }
57
48
 
@@ -70,91 +61,174 @@ module Cuprum::Collections::RSpec
70
61
  end
71
62
  end
72
63
 
73
- describe 'with a valid string' do
74
- let(:collection_name) { collection_names.first }
64
+ wrap_context 'when the repository has many collections' do
65
+ describe 'with an invalid string' do
66
+ let(:collection_name) { 'invalid_name' }
75
67
 
76
- it { expect(repository[collection_name]).to be books_collection }
77
- end
68
+ it 'should raise an exception' do
69
+ expect { repository[collection_name] }
70
+ .to raise_error(error_class, error_message)
71
+ end
72
+ end
78
73
 
79
- describe 'with a valid symbol' do
80
- let(:collection_name) { collection_names.first.intern }
74
+ describe 'with an invalid symbol' do
75
+ let(:collection_name) { :invalid_name }
81
76
 
82
- it { expect(repository[collection_name]).to be books_collection }
77
+ it 'should raise an exception' do
78
+ expect { repository[collection_name] }
79
+ .to raise_error(error_class, error_message)
80
+ end
81
+ end
82
+
83
+ describe 'with a valid string' do
84
+ let(:collection) { collections.values.first }
85
+ let(:collection_name) { collections.keys.first }
86
+
87
+ it { expect(repository[collection_name]).to be collection }
88
+ end
89
+
90
+ describe 'with a valid symbol' do
91
+ let(:collection) { collections.values.first }
92
+ let(:collection_name) { collections.keys.first.intern }
93
+
94
+ it { expect(repository[collection_name]).to be collection }
95
+ end
83
96
  end
84
97
  end
85
- end
86
98
 
87
- describe '#add' do
88
- let(:error_class) do
89
- described_class::InvalidCollectionError
90
- end
91
- let(:error_message) do
92
- "#{collection.inspect} is not a valid collection"
93
- end
99
+ describe '#add' do
100
+ let(:error_class) do
101
+ described_class::InvalidCollectionError
102
+ end
103
+ let(:error_message) do
104
+ "#{collection.inspect} is not a valid collection"
105
+ end
94
106
 
95
- it { expect(repository).to respond_to(:add).with(1).argument }
107
+ it 'should define the method' do
108
+ expect(repository)
109
+ .to respond_to(:add)
110
+ .with(1).argument
111
+ .and_keywords(:force)
112
+ end
96
113
 
97
- it 'should alias #add as #<<' do
98
- expect(repository.method(:<<)).to be == repository.method(:add)
99
- end
114
+ it 'should alias #add as #<<' do
115
+ expect(repository.method(:<<)).to be == repository.method(:add)
116
+ end
100
117
 
101
- describe 'with nil' do
102
- let(:collection) { nil }
118
+ describe 'with nil' do
119
+ let(:collection) { nil }
103
120
 
104
- it 'should raise an exception' do
105
- expect { repository.add(collection) }
106
- .to raise_error(error_class, error_message)
121
+ it 'should raise an exception' do
122
+ expect { repository.add(collection) }
123
+ .to raise_error(error_class, error_message)
124
+ end
107
125
  end
108
- end
109
126
 
110
- describe 'with an object' do
111
- let(:collection) { Object.new.freeze }
127
+ describe 'with an object' do
128
+ let(:collection) { Object.new.freeze }
112
129
 
113
- it 'should raise an exception' do
114
- expect { repository.add(collection) }
115
- .to raise_error(error_class, error_message)
130
+ it 'should raise an exception' do
131
+ expect { repository.add(collection) }
132
+ .to raise_error(error_class, error_message)
133
+ end
116
134
  end
117
- end
118
135
 
119
- describe 'with a collection' do
120
- it { expect(repository.add(example_collection)).to be repository }
136
+ describe 'with a collection' do
137
+ it { expect(repository.add(example_collection)).to be repository }
121
138
 
122
- it 'should add the collection to the repository' do
123
- repository.add(example_collection)
139
+ it 'should add the collection to the repository' do
140
+ repository.add(example_collection)
124
141
 
125
- expect(repository[example_collection.collection_name])
126
- .to be example_collection
127
- end
128
- end
129
- end
142
+ expect(repository[example_collection.qualified_name])
143
+ .to be example_collection
144
+ end
130
145
 
131
- describe '#key?' do
132
- it { expect(repository).to respond_to(:key?).with(1).argument }
146
+ describe 'with force: true' do
147
+ it 'should add the collection to the repository' do
148
+ repository.add(example_collection, force: true)
133
149
 
134
- it { expect(repository.key? nil).to be false }
150
+ expect(repository[example_collection.qualified_name])
151
+ .to be example_collection
152
+ end
153
+ end
135
154
 
136
- it { expect(repository.key? Object.new.freeze).to be false }
155
+ context 'when the collection already exists' do
156
+ let(:error_message) do
157
+ "collection #{example_collection.qualified_name} already exists"
158
+ end
159
+
160
+ before(:example) do
161
+ allow(repository)
162
+ .to receive(:key?)
163
+ .with(example_collection.qualified_name)
164
+ .and_return(true)
165
+ end
166
+
167
+ it 'should raise an exception' do
168
+ expect { repository.add(example_collection) }
169
+ .to raise_error(
170
+ described_class::DuplicateCollectionError,
171
+ error_message
172
+ )
173
+ end
174
+
175
+ it 'should not update the repository' do
176
+ begin
177
+ repository.add(example_collection)
178
+ rescue described_class::DuplicateCollectionError
179
+ # Do nothing.
180
+ end
181
+
182
+ expect { repository[example_collection.qualified_name] }
183
+ .to raise_error(
184
+ described_class::UndefinedCollectionError,
185
+ 'repository does not define collection ' \
186
+ "#{example_collection.qualified_name.inspect}"
187
+ )
188
+ end
189
+
190
+ describe 'with force: true' do
191
+ it 'should add the collection to the repository' do
192
+ repository.add(example_collection, force: true)
193
+
194
+ expect(repository[example_collection.qualified_name])
195
+ .to be example_collection
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
137
201
 
138
- it { expect(repository.key? 'invalid_name').to be false }
202
+ describe '#key?' do
203
+ it { expect(repository).to respond_to(:key?).with(1).argument }
139
204
 
140
- it { expect(repository.key? :invalid_name).to be false }
205
+ it { expect(repository.key? nil).to be false }
206
+
207
+ it { expect(repository.key? Object.new.freeze).to be false }
141
208
 
142
- wrap_context 'when the repository has many collections' do
143
209
  it { expect(repository.key? 'invalid_name').to be false }
144
210
 
145
211
  it { expect(repository.key? :invalid_name).to be false }
146
212
 
147
- it { expect(repository.key? collection_names.first).to be true }
213
+ wrap_context 'when the repository has many collections' do
214
+ it { expect(repository.key? 'invalid_name').to be false }
215
+
216
+ it { expect(repository.key? :invalid_name).to be false }
148
217
 
149
- it { expect(repository.key? collection_names.first.intern).to be true }
218
+ it { expect(repository.key? collections.keys.first).to be true }
219
+
220
+ it 'should include the key' do
221
+ expect(repository.key? collections.keys.first.intern).to be true
222
+ end
223
+ end
150
224
  end
151
- end
152
225
 
153
- describe '#keys' do
154
- include_examples 'should define reader', :keys, []
226
+ describe '#keys' do
227
+ include_examples 'should define reader', :keys, []
155
228
 
156
- wrap_context 'when the repository has many collections' do
157
- it { expect(repository.keys).to be == collection_names }
229
+ wrap_context 'when the repository has many collections' do
230
+ it { expect(repository.keys).to be == collections.keys }
231
+ end
158
232
  end
159
233
  end
160
234
  end
@@ -32,9 +32,10 @@ module Cuprum::Collections::RSpec
32
32
  context 'when the item does not exist in the collection' do
33
33
  let(:expected_error) do
34
34
  Cuprum::Collections::Errors::NotFound.new(
35
- collection_name: collection_name,
36
- primary_key_name: primary_key_name,
37
- primary_key_values: attributes[primary_key_name]
35
+ attribute_name: primary_key_name,
36
+ attribute_value: attributes[primary_key_name],
37
+ collection_name: collection_name,
38
+ primary_key: true
38
39
  )
39
40
  end
40
41
  let(:matching_data) { mapped_data.first }
@@ -11,7 +11,7 @@ module Cuprum
11
11
  # Major version.
12
12
  MAJOR = 0
13
13
  # Minor version.
14
- MINOR = 2
14
+ MINOR = 3
15
15
  # Patch version.
16
16
  PATCH = 0
17
17
  # Prerelease version.
@@ -9,6 +9,7 @@ module Cuprum
9
9
  autoload :Base, 'cuprum/collections/base'
10
10
  autoload :Basic, 'cuprum/collections/basic'
11
11
  autoload :Command, 'cuprum/collections/command'
12
+ autoload :Errors, 'cuprum/collections/errors'
12
13
 
13
14
  # @return [String] the absolute path to the gem directory.
14
15
  def self.gem_path
metadata CHANGED
@@ -1,119 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuprum-collections
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob "Merlin" Smith
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-31 00:00:00.000000000 Z
11
+ date: 2023-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cuprum
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0.11'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '2.0'
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: '0.11'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '2.0'
33
- - !ruby/object:Gem::Dependency
34
- name: stannum
35
15
  requirement: !ruby/object:Gem::Requirement
36
16
  requirements:
37
17
  - - "~>"
38
18
  - !ruby/object:Gem::Version
39
- version: '0.2'
19
+ version: '1.1'
40
20
  type: :runtime
41
21
  prerelease: false
42
22
  version_requirements: !ruby/object:Gem::Requirement
43
23
  requirements:
44
24
  - - "~>"
45
25
  - !ruby/object:Gem::Version
46
- version: '0.2'
47
- - !ruby/object:Gem::Dependency
48
- name: rspec
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '3.9'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '3.9'
61
- - !ruby/object:Gem::Dependency
62
- name: rspec-sleeping_king_studios
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '2.5'
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '2.5'
26
+ version: '1.1'
75
27
  - !ruby/object:Gem::Dependency
76
- name: rubocop
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '1.22'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '1.22'
89
- - !ruby/object:Gem::Dependency
90
- name: rubocop-rspec
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '2.5'
96
- type: :development
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '2.5'
103
- - !ruby/object:Gem::Dependency
104
- name: simplecov
28
+ name: stannum
105
29
  requirement: !ruby/object:Gem::Requirement
106
30
  requirements:
107
31
  - - "~>"
108
32
  - !ruby/object:Gem::Version
109
- version: '0.18'
110
- type: :development
33
+ version: '0.3'
34
+ type: :runtime
111
35
  prerelease: false
112
36
  version_requirements: !ruby/object:Gem::Requirement
113
37
  requirements:
114
38
  - - "~>"
115
39
  - !ruby/object:Gem::Version
116
- version: '0.18'
40
+ version: '0.3'
117
41
  description: An adapter library to provide a consistent interface between data stores.
118
42
  email:
119
43
  - merlin@sleepingkingstudios.com
@@ -151,6 +75,10 @@ files:
151
75
  - lib/cuprum/collections/commands/abstract_find_many.rb
152
76
  - lib/cuprum/collections/commands/abstract_find_matching.rb
153
77
  - lib/cuprum/collections/commands/abstract_find_one.rb
78
+ - lib/cuprum/collections/commands/create.rb
79
+ - lib/cuprum/collections/commands/find_one_matching.rb
80
+ - lib/cuprum/collections/commands/update.rb
81
+ - lib/cuprum/collections/commands/upsert.rb
154
82
  - lib/cuprum/collections/constraints.rb
155
83
  - lib/cuprum/collections/constraints/attribute_name.rb
156
84
  - lib/cuprum/collections/constraints/order.rb
@@ -161,6 +89,7 @@ files:
161
89
  - lib/cuprum/collections/constraints/ordering.rb
162
90
  - lib/cuprum/collections/constraints/query_hash.rb
163
91
  - lib/cuprum/collections/errors.rb
92
+ - lib/cuprum/collections/errors/abstract_find_error.rb
164
93
  - lib/cuprum/collections/errors/already_exists.rb
165
94
  - lib/cuprum/collections/errors/extra_attributes.rb
166
95
  - lib/cuprum/collections/errors/failed_validation.rb
@@ -168,6 +97,7 @@ files:
168
97
  - lib/cuprum/collections/errors/invalid_query.rb
169
98
  - lib/cuprum/collections/errors/missing_default_contract.rb
170
99
  - lib/cuprum/collections/errors/not_found.rb
100
+ - lib/cuprum/collections/errors/not_unique.rb
171
101
  - lib/cuprum/collections/errors/unknown_operator.rb
172
102
  - lib/cuprum/collections/queries.rb
173
103
  - lib/cuprum/collections/queries/ordering.rb
@@ -200,7 +130,8 @@ licenses:
200
130
  metadata:
201
131
  bug_tracker_uri: https://github.com/sleepingkingstudios/cuprum-collections/issues
202
132
  source_code_uri: https://github.com/sleepingkingstudios/cuprum-collections
203
- post_install_message:
133
+ rubygems_mfa_required: 'true'
134
+ post_install_message:
204
135
  rdoc_options: []
205
136
  require_paths:
206
137
  - lib
@@ -208,15 +139,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
139
  requirements:
209
140
  - - ">="
210
141
  - !ruby/object:Gem::Version
211
- version: 2.6.0
142
+ version: 2.7.0
212
143
  required_rubygems_version: !ruby/object:Gem::Requirement
213
144
  requirements:
214
145
  - - ">="
215
146
  - !ruby/object:Gem::Version
216
147
  version: '0'
217
148
  requirements: []
218
- rubygems_version: 3.1.2
219
- signing_key:
149
+ rubygems_version: 3.4.13
150
+ signing_key:
220
151
  specification_version: 4
221
152
  summary: A data abstraction layer based on the Cuprum library.
222
153
  test_files: []