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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -0
  3. data/README.md +5 -5
  4. data/lib/cuprum/collections/association.rb +9 -28
  5. data/lib/cuprum/collections/associations/belongs_to.rb +1 -8
  6. data/lib/cuprum/collections/associations/has_many.rb +1 -10
  7. data/lib/cuprum/collections/associations/has_one.rb +1 -10
  8. data/lib/cuprum/collections/basic/collection.rb +56 -49
  9. data/lib/cuprum/collections/basic/command.rb +22 -88
  10. data/lib/cuprum/collections/basic/commands/assign_one.rb +2 -6
  11. data/lib/cuprum/collections/basic/commands/build_one.rb +1 -4
  12. data/lib/cuprum/collections/basic/commands/destroy_one.rb +4 -8
  13. data/lib/cuprum/collections/basic/commands/find_many.rb +4 -24
  14. data/lib/cuprum/collections/basic/commands/find_matching.rb +5 -21
  15. data/lib/cuprum/collections/basic/commands/find_one.rb +3 -20
  16. data/lib/cuprum/collections/basic/commands/insert_one.rb +3 -6
  17. data/lib/cuprum/collections/basic/commands/update_one.rb +3 -6
  18. data/lib/cuprum/collections/basic/commands/validate_one.rb +13 -18
  19. data/lib/cuprum/collections/basic/query.rb +26 -40
  20. data/lib/cuprum/collections/basic/repository.rb +4 -3
  21. data/lib/cuprum/collections/basic/scopes/all_scope.rb +25 -0
  22. data/lib/cuprum/collections/basic/scopes/base.rb +32 -0
  23. data/lib/cuprum/collections/basic/scopes/builder.rb +39 -0
  24. data/lib/cuprum/collections/basic/scopes/conjunction_scope.rb +20 -0
  25. data/lib/cuprum/collections/basic/scopes/criteria_scope.rb +62 -0
  26. data/lib/cuprum/collections/basic/scopes/disjunction_scope.rb +20 -0
  27. data/lib/cuprum/collections/basic/scopes/none_scope.rb +33 -0
  28. data/lib/cuprum/collections/basic/scopes.rb +23 -0
  29. data/lib/cuprum/collections/basic.rb +1 -0
  30. data/lib/cuprum/collections/collection.rb +24 -82
  31. data/lib/cuprum/collections/collection_command.rb +116 -0
  32. data/lib/cuprum/collections/commands/abstract_find_many.rb +11 -21
  33. data/lib/cuprum/collections/commands/abstract_find_matching.rb +43 -24
  34. data/lib/cuprum/collections/commands/abstract_find_one.rb +7 -10
  35. data/lib/cuprum/collections/commands/associations/find_many.rb +3 -8
  36. data/lib/cuprum/collections/commands/associations/require_many.rb +5 -5
  37. data/lib/cuprum/collections/commands/create.rb +3 -3
  38. data/lib/cuprum/collections/commands/find_one_matching.rb +6 -6
  39. data/lib/cuprum/collections/commands/query_command.rb +19 -0
  40. data/lib/cuprum/collections/commands/update.rb +3 -3
  41. data/lib/cuprum/collections/commands/upsert.rb +10 -10
  42. data/lib/cuprum/collections/commands.rb +1 -0
  43. data/lib/cuprum/collections/constraints/ordering.rb +2 -2
  44. data/lib/cuprum/collections/errors/abstract_find_error.rb +25 -42
  45. data/lib/cuprum/collections/errors/extra_attributes.rb +3 -3
  46. data/lib/cuprum/collections/errors/failed_validation.rb +2 -2
  47. data/lib/cuprum/collections/errors/invalid_parameters.rb +2 -2
  48. data/lib/cuprum/collections/errors/invalid_query.rb +10 -16
  49. data/lib/cuprum/collections/errors/missing_default_contract.rb +1 -1
  50. data/lib/cuprum/collections/errors/unknown_operator.rb +1 -1
  51. data/lib/cuprum/collections/queries.rb +31 -0
  52. data/lib/cuprum/collections/query.rb +50 -62
  53. data/lib/cuprum/collections/relation.rb +5 -383
  54. data/lib/cuprum/collections/relations/cardinality.rb +66 -0
  55. data/lib/cuprum/collections/relations/options.rb +18 -0
  56. data/lib/cuprum/collections/relations/parameters.rb +217 -0
  57. data/lib/cuprum/collections/relations/primary_keys.rb +23 -0
  58. data/lib/cuprum/collections/relations/scope.rb +65 -0
  59. data/lib/cuprum/collections/relations.rb +14 -0
  60. data/lib/cuprum/collections/repository.rb +5 -5
  61. data/lib/cuprum/collections/resource.rb +10 -41
  62. data/lib/cuprum/collections/rspec/contracts/association_contracts.rb +80 -90
  63. data/lib/cuprum/collections/rspec/contracts/collection_contracts.rb +69 -111
  64. data/lib/cuprum/collections/rspec/contracts/command_contracts.rb +42 -1335
  65. data/lib/cuprum/collections/rspec/contracts/query_contracts.rb +352 -531
  66. data/lib/cuprum/collections/rspec/contracts/relation_contracts.rb +74 -191
  67. data/lib/cuprum/collections/rspec/contracts/repository_contracts.rb +13 -13
  68. data/lib/cuprum/collections/rspec/contracts/scope_contracts.rb +1029 -0
  69. data/lib/cuprum/collections/rspec/contracts/scopes/builder_contracts.rb +856 -0
  70. data/lib/cuprum/collections/rspec/contracts/scopes/composition_contracts.rb +1430 -0
  71. data/lib/cuprum/collections/rspec/contracts/scopes/criteria_contracts.rb +2217 -0
  72. data/lib/cuprum/collections/rspec/contracts/scopes/logical_contracts.rb +297 -0
  73. data/lib/cuprum/collections/rspec/contracts/scopes.rb +13 -0
  74. data/lib/cuprum/collections/rspec/contracts.rb +2 -0
  75. data/lib/cuprum/collections/rspec/deferred/association_examples.rb +2098 -0
  76. data/lib/cuprum/collections/rspec/deferred/collection_examples.rb +338 -0
  77. data/lib/cuprum/collections/rspec/deferred/command_examples.rb +160 -0
  78. data/lib/cuprum/collections/rspec/deferred/commands/assign_one_examples.rb +178 -0
  79. data/lib/cuprum/collections/rspec/deferred/commands/build_one_examples.rb +94 -0
  80. data/lib/cuprum/collections/rspec/deferred/commands/destroy_one_examples.rb +118 -0
  81. data/lib/cuprum/collections/rspec/deferred/commands/find_many_examples.rb +307 -0
  82. data/lib/cuprum/collections/rspec/deferred/commands/find_matching_examples.rb +143 -0
  83. data/lib/cuprum/collections/rspec/deferred/commands/find_one_examples.rb +116 -0
  84. data/lib/cuprum/collections/rspec/deferred/commands/insert_one_examples.rb +103 -0
  85. data/lib/cuprum/collections/rspec/deferred/commands/update_one_examples.rb +99 -0
  86. data/lib/cuprum/collections/rspec/deferred/commands/validate_one_examples.rb +117 -0
  87. data/lib/cuprum/collections/rspec/deferred/commands.rb +8 -0
  88. data/lib/cuprum/collections/rspec/deferred/relation_examples.rb +1437 -0
  89. data/lib/cuprum/collections/rspec/deferred/resource_examples.rb +26 -0
  90. data/lib/cuprum/collections/rspec/deferred.rb +8 -0
  91. data/lib/cuprum/collections/scope.rb +29 -0
  92. data/lib/cuprum/collections/scopes/all.rb +51 -0
  93. data/lib/cuprum/collections/scopes/all_scope.rb +18 -0
  94. data/lib/cuprum/collections/scopes/base.rb +79 -0
  95. data/lib/cuprum/collections/scopes/builder.rb +39 -0
  96. data/lib/cuprum/collections/scopes/building.rb +221 -0
  97. data/lib/cuprum/collections/scopes/composition.rb +162 -0
  98. data/lib/cuprum/collections/scopes/conjunction.rb +44 -0
  99. data/lib/cuprum/collections/scopes/conjunction_scope.rb +12 -0
  100. data/lib/cuprum/collections/scopes/container.rb +65 -0
  101. data/lib/cuprum/collections/scopes/criteria/parser.rb +241 -0
  102. data/lib/cuprum/collections/scopes/criteria.rb +206 -0
  103. data/lib/cuprum/collections/scopes/criteria_scope.rb +12 -0
  104. data/lib/cuprum/collections/scopes/disjunction.rb +45 -0
  105. data/lib/cuprum/collections/scopes/disjunction_scope.rb +12 -0
  106. data/lib/cuprum/collections/scopes/none.rb +62 -0
  107. data/lib/cuprum/collections/scopes/none_scope.rb +18 -0
  108. data/lib/cuprum/collections/scopes.rb +23 -0
  109. data/lib/cuprum/collections/version.rb +2 -2
  110. data/lib/cuprum/collections.rb +14 -9
  111. metadata +61 -15
  112. data/lib/cuprum/collections/basic/query_builder.rb +0 -69
  113. data/lib/cuprum/collections/command.rb +0 -26
  114. data/lib/cuprum/collections/queries/parse.rb +0 -22
  115. data/lib/cuprum/collections/queries/parse_block.rb +0 -206
  116. data/lib/cuprum/collections/queries/parse_strategy.rb +0 -91
  117. data/lib/cuprum/collections/query_builder.rb +0 -61
  118. data/lib/cuprum/collections/rspec/contracts/basic/command_contracts.rb +0 -484
@@ -0,0 +1,297 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/contracts'
4
+ require 'cuprum/collections/rspec/contracts/scope_contracts'
5
+ require 'cuprum/collections/rspec/contracts/scopes/composition_contracts'
6
+ require 'cuprum/collections/rspec/fixtures'
7
+
8
+ module Cuprum::Collections::RSpec::Contracts::Scopes
9
+ # Contracts for asserting on logical scope objects.
10
+ module LogicalContracts
11
+ include Cuprum::Collections::RSpec::Contracts::ScopeContracts
12
+ include Cuprum::Collections::RSpec::Contracts::Scopes::CompositionContracts
13
+
14
+ # Contract validating the behavior of a logical AND scope implementation.
15
+ module ShouldBeAConjunctionScopeContract
16
+ extend RSpec::SleepingKingStudios::Contract
17
+
18
+ # @!method apply(example_group, abstract: false)
19
+ # Adds the contract to the example group.
20
+ #
21
+ # @param example_group [RSpec::Core::ExampleGroup] the example group to
22
+ # which the contract is applied.
23
+ # @param abstract [Boolean] if true, the scope is abstract and does not
24
+ # define a #call implementation. Defaults to false.
25
+ contract do |abstract: false|
26
+ include_contract 'should be a container scope', invertible: true
27
+
28
+ include_contract 'should compose scopes for conjunction'
29
+
30
+ describe '#as_json' do
31
+ let(:expected) do
32
+ {
33
+ 'scopes' => subject.scopes.map(&:as_json),
34
+ 'type' => subject.type
35
+ }
36
+ end
37
+
38
+ it { expect(subject.as_json).to be == expected }
39
+
40
+ wrap_context 'with scopes' do
41
+ it { expect(subject.as_json).to be == expected }
42
+ end
43
+ end
44
+
45
+ describe '#call' do
46
+ next if abstract
47
+
48
+ include_contract 'should filter data by logical and'
49
+ end
50
+
51
+ describe '#invert' do
52
+ let(:expected) do
53
+ Cuprum::Collections::Scopes::DisjunctionScope.new(
54
+ scopes: subject.scopes.map(&:invert)
55
+ )
56
+ end
57
+
58
+ it { expect(subject.invert).to be == expected }
59
+
60
+ wrap_context 'with scopes' do
61
+ it { expect(subject.invert).to be == expected }
62
+ end
63
+ end
64
+
65
+ describe '#type' do
66
+ include_examples 'should define reader', :type, :conjunction
67
+ end
68
+ end
69
+ end
70
+
71
+ # Contract validating the behavior of a logical OR scope implementation.
72
+ module ShouldBeADisjunctionScopeContract
73
+ extend RSpec::SleepingKingStudios::Contract
74
+
75
+ # @!method apply(example_group, abstract: false)
76
+ # Adds the contract to the example group.
77
+ #
78
+ # @param example_group [RSpec::Core::ExampleGroup] the example group to
79
+ # which the contract is applied.
80
+ # @param abstract [Boolean] if true, the scope is abstract and does not
81
+ # define a #call implementation. Defaults to false.
82
+ contract do |abstract: false|
83
+ include_contract 'should be a container scope', invertible: true
84
+
85
+ include_contract 'should compose scopes for disjunction'
86
+
87
+ describe '#as_json' do
88
+ let(:expected) do
89
+ {
90
+ 'scopes' => subject.scopes.map(&:as_json),
91
+ 'type' => subject.type
92
+ }
93
+ end
94
+
95
+ it { expect(subject.as_json).to be == expected }
96
+
97
+ wrap_context 'with scopes' do
98
+ it { expect(subject.as_json).to be == expected }
99
+ end
100
+ end
101
+
102
+ describe '#call' do
103
+ next if abstract
104
+
105
+ include_contract 'should filter data by logical or'
106
+ end
107
+
108
+ describe '#invert' do
109
+ let(:expected) do
110
+ Cuprum::Collections::Scopes::ConjunctionScope.new(
111
+ scopes: subject.scopes.map(&:invert)
112
+ )
113
+ end
114
+
115
+ it { expect(subject.invert).to be == expected }
116
+
117
+ wrap_context 'with scopes' do
118
+ it { expect(subject.invert).to be == expected }
119
+ end
120
+ end
121
+
122
+ describe '#type' do
123
+ include_examples 'should define reader', :type, :disjunction
124
+ end
125
+ end
126
+ end
127
+
128
+ # Contract validating the behavior of a Conjunction scope implementation.
129
+ module ShouldFilterDataByLogicalAndContract
130
+ extend RSpec::SleepingKingStudios::Contract
131
+
132
+ # @!method apply(example_group)
133
+ # Adds the contract to the example group.
134
+ #
135
+ # @param example_group [RSpec::Core::ExampleGroup] the example group to
136
+ # which the contract is applied.
137
+ contract do
138
+ shared_context 'with data' do
139
+ let(:data) do
140
+ Cuprum::Collections::RSpec::Fixtures::BOOKS_FIXTURES
141
+ end
142
+ end
143
+
144
+ context 'when the scope has no child scopes' do
145
+ let(:scopes) { [] }
146
+
147
+ describe 'with empty data' do
148
+ let(:data) { [] }
149
+
150
+ it { expect(filtered_data).to be == [] }
151
+ end
152
+
153
+ wrap_context 'with data' do
154
+ let(:expected) { data }
155
+
156
+ it { expect(filtered_data).to match_array expected }
157
+ end
158
+ end
159
+
160
+ context 'when the scope has one child scope' do
161
+ let(:scopes) do
162
+ [
163
+ build_scope({ 'author' => 'J.R.R. Tolkien' })
164
+ ]
165
+ end
166
+
167
+ describe 'with empty data' do
168
+ let(:data) { [] }
169
+
170
+ it { expect(filtered_data).to be == [] }
171
+ end
172
+
173
+ wrap_context 'with data' do
174
+ let(:expected) do
175
+ data.select { |item| item['author'] == 'J.R.R. Tolkien' }
176
+ end
177
+
178
+ it { expect(filtered_data).to match_array expected }
179
+ end
180
+ end
181
+
182
+ context 'when the scope has many child scopes' do
183
+ let(:scopes) do
184
+ [
185
+ build_scope({ 'author' => 'J.R.R. Tolkien' }),
186
+ build_scope({ 'series' => 'The Lord of the Rings' }),
187
+ build_scope do |scope|
188
+ { 'published_at' => scope.less_than('1955-01-01') }
189
+ end
190
+ ]
191
+ end
192
+
193
+ describe 'with empty data' do
194
+ let(:data) { [] }
195
+
196
+ it { expect(filtered_data).to be == [] }
197
+ end
198
+
199
+ wrap_context 'with data' do
200
+ let(:expected) do
201
+ data
202
+ .select { |item| item['author'] == 'J.R.R. Tolkien' }
203
+ .select { |item| item['series'] == 'The Lord of the Rings' }
204
+ .select { |item| item['published_at'] < '1955-01-01' }
205
+ end
206
+
207
+ it { expect(filtered_data).to match_array expected }
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ # Contract validating the behavior of a Disjunction scope implementation.
214
+ module ShouldFilterDataByLogicalOrContract
215
+ extend RSpec::SleepingKingStudios::Contract
216
+
217
+ # @!method apply(example_group)
218
+ # Adds the contract to the example group.
219
+ #
220
+ # @param example_group [RSpec::Core::ExampleGroup] the example group to
221
+ # which the contract is applied.
222
+ contract do
223
+ shared_context 'with data' do
224
+ let(:data) do
225
+ Cuprum::Collections::RSpec::Fixtures::BOOKS_FIXTURES
226
+ end
227
+ end
228
+
229
+ context 'when the scope has no child scopes' do
230
+ let(:scopes) { [] }
231
+
232
+ describe 'with empty data' do
233
+ let(:data) { [] }
234
+
235
+ it { expect(filtered_data).to be == [] }
236
+ end
237
+
238
+ wrap_context 'with data' do
239
+ it { expect(filtered_data).to be == [] }
240
+ end
241
+ end
242
+
243
+ context 'when the scope has one child scope' do
244
+ let(:scopes) do
245
+ [
246
+ build_scope({ 'author' => 'J.R.R. Tolkien' })
247
+ ]
248
+ end
249
+
250
+ describe 'with empty data' do
251
+ let(:data) { [] }
252
+
253
+ it { expect(filtered_data).to be == [] }
254
+ end
255
+
256
+ wrap_context 'with data' do
257
+ let(:expected) do
258
+ data.select { |item| item['author'] == 'J.R.R. Tolkien' }
259
+ end
260
+
261
+ it { expect(filtered_data).to match_array expected }
262
+ end
263
+ end
264
+
265
+ context 'when the scope has many child scopes' do
266
+ let(:scopes) do
267
+ [
268
+ build_scope({ 'author' => 'J.R.R. Tolkien' }),
269
+ build_scope({ 'series' => 'The Lord of the Rings' }),
270
+ build_scope do |scope|
271
+ { 'published_at' => scope.less_than('1955-01-01') }
272
+ end
273
+ ]
274
+ end
275
+
276
+ describe 'with empty data' do
277
+ let(:data) { [] }
278
+
279
+ it { expect(filtered_data).to be == [] }
280
+ end
281
+
282
+ wrap_context 'with data' do
283
+ let(:expected) do
284
+ data.select do |item|
285
+ item['author'] == 'J.R.R. Tolkien' ||
286
+ item['series'] == 'The Lord of the Rings' ||
287
+ item['published_at'] < '1955-01-01'
288
+ end
289
+ end
290
+
291
+ it { expect(filtered_data).to match_array expected }
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/contracts'
4
+
5
+ module Cuprum::Collections::RSpec::Contracts
6
+ # Namespace for RSpec contracts validating the behavior of scopes.
7
+ module Scopes
8
+ autoload :CriteriaContracts,
9
+ 'cuprum/collections/rspec/contracts/scopes/criteria_contracts'
10
+ autoload :LogicalContracts,
11
+ 'cuprum/collections/rspec/contracts/scopes/logical_contracts'
12
+ end
13
+ end
@@ -19,5 +19,7 @@ module Cuprum::Collections::RSpec
19
19
  'cuprum/collections/rspec/contracts/relation_contracts'
20
20
  autoload :RepositoryContracts,
21
21
  'cuprum/collections/rspec/contracts/repository_contracts'
22
+ autoload :Scopes,
23
+ 'cuprum/collections/rspec/contracts/scopes'
22
24
  end
23
25
  end