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,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/deferred/command_examples'
4
+ require 'cuprum/collections/rspec/deferred/commands'
5
+
6
+ module Cuprum::Collections::RSpec::Deferred::Commands
7
+ # Namespace for deferred example groups for validating FindOne commands.
8
+ module FindOneExamples
9
+ include RSpec::SleepingKingStudios::Deferred::Provider
10
+
11
+ deferred_examples 'should implement the FindOne command' do
12
+ describe '#call' do
13
+ include Cuprum::Collections::RSpec::Deferred::CommandExamples
14
+
15
+ let(:mapped_data) do
16
+ defined?(super()) ? super() : data
17
+ end
18
+ let(:primary_key_name) { defined?(super()) ? super() : 'id' }
19
+ let(:primary_key_type) { defined?(super()) ? super() : Integer }
20
+ let(:invalid_primary_key_value) do
21
+ defined?(super()) ? super() : 100
22
+ end
23
+ let(:valid_primary_key_value) do
24
+ defined?(super()) ? super() : 0
25
+ end
26
+ let(:primary_key) { valid_primary_key_value }
27
+ let(:options) { {} }
28
+
29
+ def call_command
30
+ command.call(primary_key:, **options)
31
+ end
32
+
33
+ include_deferred 'should validate the primary key parameter'
34
+
35
+ describe 'with an invalid envelope value' do
36
+ let(:options) { super().merge(envelope: Object.new.freeze) }
37
+
38
+ include_deferred 'should validate the parameter',
39
+ :envelope,
40
+ 'sleeping_king_studios.tools.assertions.boolean'
41
+ end
42
+
43
+ describe 'with an invalid primary key' do
44
+ let(:primary_key) { invalid_primary_key_value }
45
+ let(:expected_error) do
46
+ Cuprum::Collections::Errors::NotFound.new(
47
+ attribute_name: collection.primary_key_name,
48
+ attribute_value: primary_key,
49
+ collection_name: collection.name,
50
+ primary_key: true
51
+ )
52
+ end
53
+
54
+ it 'should return a failing result' do
55
+ expect(command.call(primary_key:))
56
+ .to be_a_failing_result
57
+ .with_error(expected_error)
58
+ end
59
+ end
60
+
61
+ context 'when the collection has many items' do
62
+ let(:data) { fixtures_data }
63
+ let(:matching_data) do
64
+ mapped_data
65
+ .find { |item| item[primary_key_name.to_s] == primary_key }
66
+ end
67
+ let(:expected_data) do
68
+ defined?(super()) ? super() : matching_data
69
+ end
70
+
71
+ describe 'with an invalid primary key' do
72
+ let(:primary_key) { invalid_primary_key_value }
73
+ let(:expected_error) do
74
+ Cuprum::Collections::Errors::NotFound.new(
75
+ attribute_name: collection.primary_key_name,
76
+ attribute_value: primary_key,
77
+ collection_name: collection.name,
78
+ primary_key: true
79
+ )
80
+ end
81
+
82
+ it 'should return a failing result' do
83
+ expect(command.call(primary_key:))
84
+ .to be_a_failing_result
85
+ .with_error(expected_error)
86
+ end
87
+ end
88
+
89
+ describe 'with a valid primary key' do
90
+ let(:primary_key) { valid_primary_key_value }
91
+
92
+ it 'should return a passing result' do
93
+ expect(command.call(primary_key:))
94
+ .to be_a_passing_result
95
+ .with_value(expected_data)
96
+ end
97
+ end
98
+
99
+ describe 'with envelope: true' do
100
+ let(:member_name) { collection.singular_name }
101
+
102
+ describe 'with a valid primary key' do
103
+ let(:primary_key) { valid_primary_key_value }
104
+
105
+ it 'should return a passing result' do
106
+ expect(command.call(primary_key:, envelope: true))
107
+ .to be_a_passing_result
108
+ .with_value(match({ member_name => expected_data }))
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/deferred/command_examples'
4
+ require 'cuprum/collections/rspec/deferred/commands'
5
+
6
+ module Cuprum::Collections::RSpec::Deferred::Commands
7
+ # Namespace for deferred example groups for validating InsertOne commands.
8
+ module InsertOneExamples
9
+ include RSpec::SleepingKingStudios::Deferred::Provider
10
+
11
+ deferred_examples 'should implement the InsertOne command' do
12
+ describe '#call' do
13
+ include Cuprum::Collections::RSpec::Deferred::CommandExamples
14
+
15
+ let(:matching_data) { attributes }
16
+ let(:expected_data) do
17
+ defined?(super()) ? super() : matching_data
18
+ end
19
+ let(:primary_key_name) do
20
+ defined?(super()) ? super() : 'id'
21
+ end
22
+ let(:primary_key_type) do
23
+ defined?(super()) ? super() : Integer
24
+ end
25
+ let(:scoped) do
26
+ key = primary_key_name
27
+ value = entity[primary_key_name.to_s]
28
+
29
+ collection.query.where { { key => value } }
30
+ end
31
+
32
+ def call_command
33
+ command.call(entity:)
34
+ end
35
+
36
+ if defined_deferred_examples? 'should validate the entity'
37
+ include_deferred 'should validate the entity'
38
+ else
39
+ # :nocov:
40
+ pending \
41
+ 'the command should validate the entity parameter, but entity ' \
42
+ 'validation is not defined - implement a "should validate the ' \
43
+ 'entity" deferred example group to resolve this warning'
44
+ # :nocov:
45
+ end
46
+
47
+ context 'when the item does not exist in the collection' do
48
+ it 'should return a passing result' do
49
+ expect(command.call(entity:))
50
+ .to be_a_passing_result
51
+ .with_value(match(expected_data))
52
+ end
53
+
54
+ it 'should append an item to the collection' do
55
+ expect { command.call(entity:) }
56
+ .to(
57
+ change { collection.query.count }
58
+ .by(1)
59
+ )
60
+ end
61
+
62
+ it 'should add the entity to the collection' do
63
+ expect { command.call(entity:) }
64
+ .to change(scoped, :exists?)
65
+ .to be true
66
+ end
67
+
68
+ it 'should set the attributes' do
69
+ command.call(entity:)
70
+
71
+ expect(scoped.to_a.first).to match(expected_data)
72
+ end
73
+ end
74
+
75
+ context 'when the item exists in the collection' do
76
+ let(:data) { fixtures_data }
77
+ let(:expected_error) do
78
+ Cuprum::Collections::Errors::AlreadyExists.new(
79
+ attribute_name: collection.primary_key_name,
80
+ attribute_value: attributes.fetch(
81
+ primary_key_name.to_s,
82
+ attributes[primary_key_name.intern]
83
+ ),
84
+ collection_name: collection.name,
85
+ primary_key: true
86
+ )
87
+ end
88
+
89
+ it 'should return a failing result' do
90
+ expect(command.call(entity:))
91
+ .to be_a_failing_result
92
+ .with_error(expected_error)
93
+ end
94
+
95
+ it 'should not append an item to the collection' do
96
+ expect { command.call(entity:) }
97
+ .not_to(change { collection.query.count })
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/deferred/command_examples'
4
+ require 'cuprum/collections/rspec/deferred/commands'
5
+
6
+ module Cuprum::Collections::RSpec::Deferred::Commands
7
+ # Namespace for deferred example groups for validating UpdateOne commands.
8
+ module UpdateOneExamples
9
+ include RSpec::SleepingKingStudios::Deferred::Provider
10
+
11
+ deferred_examples 'should implement the UpdateOne command' do
12
+ describe '#call' do
13
+ include Cuprum::Collections::RSpec::Deferred::CommandExamples
14
+
15
+ let(:mapped_data) do
16
+ defined?(super()) ? super() : data
17
+ end
18
+ let(:matching_data) { attributes }
19
+ let(:expected_data) do
20
+ defined?(super()) ? super() : matching_data
21
+ end
22
+ let(:primary_key_name) do
23
+ defined?(super()) ? super() : 'id'
24
+ end
25
+ let(:scoped) do
26
+ key = primary_key_name
27
+ value = entity[primary_key_name.to_s]
28
+
29
+ collection.query.where { { key => value } }
30
+ end
31
+
32
+ def call_command
33
+ command.call(entity:)
34
+ end
35
+
36
+ if defined_deferred_examples? 'should validate the entity'
37
+ include_deferred 'should validate the entity'
38
+ else
39
+ # :nocov:
40
+ pending \
41
+ 'the command should validate the entity parameter, but entity ' \
42
+ 'validation is not defined - implement a "should validate the ' \
43
+ 'entity" deferred example group to resolve this warning'
44
+ # :nocov:
45
+ end
46
+
47
+ context 'when the item does not exist in the collection' do
48
+ let(:expected_error) do
49
+ Cuprum::Collections::Errors::NotFound.new(
50
+ attribute_name: collection.primary_key_name,
51
+ attribute_value: attributes.fetch(
52
+ primary_key_name.to_s,
53
+ attributes[primary_key_name.intern]
54
+ ),
55
+ collection_name: collection.name,
56
+ primary_key: true
57
+ )
58
+ end
59
+ let(:matching_data) { mapped_data.first }
60
+
61
+ it 'should return a failing result' do
62
+ expect(command.call(entity:))
63
+ .to be_a_failing_result
64
+ .with_error(expected_error)
65
+ end
66
+
67
+ it 'should not append an item to the collection' do
68
+ expect { command.call(entity:) }
69
+ .not_to(change { collection.query.count })
70
+ end
71
+ end
72
+
73
+ context 'when the item exists in the collection' do
74
+ let(:data) { fixtures_data }
75
+ let(:matching_data) do
76
+ mapped_data.first.merge(super())
77
+ end
78
+
79
+ it 'should return a passing result' do
80
+ expect(command.call(entity:))
81
+ .to be_a_passing_result
82
+ .with_value(be == expected_data)
83
+ end
84
+
85
+ it 'should not append an item to the collection' do
86
+ expect { command.call(entity:) }
87
+ .not_to(change { collection.query.count })
88
+ end
89
+
90
+ it 'should set the attributes' do
91
+ command.call(entity:)
92
+
93
+ expect(scoped.to_a.first).to be == expected_data
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/deferred/command_examples'
4
+ require 'cuprum/collections/rspec/deferred/commands'
5
+
6
+ module Cuprum::Collections::RSpec::Deferred::Commands
7
+ # Namespace for deferred example groups for validating ValidateOne commands.
8
+ module ValidateOneExamples
9
+ include RSpec::SleepingKingStudios::Deferred::Provider
10
+
11
+ deferred_examples 'should implement the ValidateOne command' \
12
+ do |default_contract: false|
13
+ describe '#call' do
14
+ include Cuprum::Collections::RSpec::Deferred::CommandExamples
15
+
16
+ let(:attributes) { defined?(super()) ? super() : {} }
17
+ let(:contract) { defined?(super()) ? super() : nil }
18
+
19
+ def call_command
20
+ command.call(contract:, entity:)
21
+ end
22
+
23
+ if defined_deferred_examples? 'should validate the entity'
24
+ include_deferred 'should validate the entity'
25
+ else
26
+ # :nocov:
27
+ pending \
28
+ 'the command should validate the entity parameter, but entity ' \
29
+ 'validation is not defined - implement a "should validate the ' \
30
+ 'entity" deferred example group to resolve this warning'
31
+ # :nocov:
32
+ end
33
+
34
+ describe 'with an invalid contract value' do
35
+ let(:contract) { Object.new.freeze }
36
+
37
+ include_deferred 'should validate the parameter',
38
+ :contract,
39
+ 'sleeping_king_studios.tools.assertions.instance_of',
40
+ expected: Stannum::Constraints::Base
41
+ end
42
+
43
+ describe 'with contract: nil' do
44
+ if default_contract
45
+ context 'when the entity does not match the default contract' do
46
+ let(:attributes) { invalid_default_attributes }
47
+ let(:expected_error) do
48
+ Cuprum::Collections::Errors::FailedValidation.new(
49
+ entity_class: entity.class,
50
+ errors: expected_errors
51
+ )
52
+ end
53
+
54
+ it 'should return a failing result' do
55
+ expect(command.call(entity:))
56
+ .to be_a_failing_result
57
+ .with_error(expected_error)
58
+ end
59
+ end
60
+
61
+ context 'when the entity matches the default contract' do
62
+ let(:attributes) { valid_default_attributes }
63
+
64
+ it 'should return a passing result' do
65
+ expect(command.call(entity:))
66
+ .to be_a_passing_result
67
+ .with_value(entity)
68
+ end
69
+ end
70
+ else
71
+ let(:attributes) { valid_attributes }
72
+ let(:expected_error) do
73
+ Cuprum::Collections::Errors::MissingDefaultContract.new(
74
+ entity_class: entity.class
75
+ )
76
+ end
77
+
78
+ it 'should return a failing result' do
79
+ expect(command.call(entity:))
80
+ .to be_a_failing_result
81
+ .with_error(expected_error)
82
+ end
83
+ end
84
+ end
85
+
86
+ describe 'with contract: value' do
87
+ context 'when the entity does not match the contract' do
88
+ let(:attributes) { invalid_attributes }
89
+ let(:errors) { contract.errors_for(entity) }
90
+ let(:expected_error) do
91
+ Cuprum::Collections::Errors::FailedValidation.new(
92
+ entity_class: entity.class,
93
+ errors:
94
+ )
95
+ end
96
+
97
+ it 'should return a failing result' do
98
+ expect(command.call(contract:, entity:))
99
+ .to be_a_failing_result
100
+ .with_error(expected_error)
101
+ end
102
+ end
103
+
104
+ context 'when the entity matches the contract' do
105
+ let(:attributes) { valid_attributes }
106
+
107
+ it 'should return a passing result' do
108
+ expect(command.call(contract:, entity:))
109
+ .to be_a_passing_result
110
+ .with_value(entity)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/rspec/deferred'
4
+
5
+ module Cuprum::Collections::RSpec::Deferred
6
+ # Namespace for deferred example groups for validating collection commands.
7
+ module Commands; end
8
+ end