rom 2.0.2 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -4
  3. data/CHANGELOG.md +34 -1
  4. data/Gemfile +16 -2
  5. data/Rakefile +7 -2
  6. data/lib/rom/array_dataset.rb +44 -0
  7. data/lib/rom/association_set.rb +11 -5
  8. data/lib/rom/auto_curry.rb +55 -0
  9. data/lib/rom/command.rb +70 -41
  10. data/lib/rom/command_registry.rb +7 -18
  11. data/lib/rom/commands/class_interface.rb +7 -6
  12. data/lib/rom/commands/composite.rb +0 -1
  13. data/lib/rom/commands/graph.rb +7 -15
  14. data/lib/rom/commands/lazy/update.rb +1 -1
  15. data/lib/rom/configuration_dsl/command.rb +6 -8
  16. data/lib/rom/configuration_dsl/mapper.rb +2 -3
  17. data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -1
  18. data/lib/rom/configuration_dsl/relation.rb +4 -4
  19. data/lib/rom/configuration_dsl.rb +0 -4
  20. data/lib/rom/constants.rb +1 -1
  21. data/lib/rom/container.rb +0 -2
  22. data/lib/rom/create_container.rb +0 -2
  23. data/lib/rom/data_proxy.rb +94 -0
  24. data/lib/rom/enumerable_dataset.rb +68 -0
  25. data/lib/rom/gateway.rb +23 -6
  26. data/lib/rom/global/plugin_dsl.rb +0 -2
  27. data/lib/rom/global.rb +0 -2
  28. data/lib/rom/initializer.rb +26 -0
  29. data/lib/rom/lint/gateway.rb +17 -0
  30. data/lib/rom/mapper_registry.rb +1 -1
  31. data/lib/rom/memory/commands.rb +0 -2
  32. data/lib/rom/memory/dataset.rb +1 -2
  33. data/lib/rom/memory/relation.rb +14 -1
  34. data/lib/rom/memory/schema.rb +13 -0
  35. data/lib/rom/plugin_registry.rb +1 -1
  36. data/lib/rom/plugins/configuration/configuration_dsl.rb +6 -2
  37. data/lib/rom/plugins/relation/key_inference.rb +4 -2
  38. data/lib/rom/plugins/relation/registry_reader.rb +5 -1
  39. data/lib/rom/registry.rb +50 -0
  40. data/lib/rom/relation/class_interface.rb +94 -26
  41. data/lib/rom/relation/curried.rb +15 -15
  42. data/lib/rom/relation/view_dsl.rb +31 -0
  43. data/lib/rom/relation.rb +49 -34
  44. data/lib/rom/schema/dsl.rb +7 -9
  45. data/lib/rom/schema/type.rb +115 -0
  46. data/lib/rom/schema.rb +218 -18
  47. data/lib/rom/setup/auto_registration.rb +20 -17
  48. data/lib/rom/setup/auto_registration_strategies/base.rb +8 -3
  49. data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +4 -3
  50. data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +5 -4
  51. data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +3 -3
  52. data/lib/rom/setup/finalize/finalize_commands.rb +1 -1
  53. data/lib/rom/setup/finalize/finalize_mappers.rb +1 -1
  54. data/lib/rom/setup/finalize/finalize_relations.rb +3 -1
  55. data/lib/rom/setup/finalize.rb +1 -1
  56. data/lib/rom/transaction.rb +24 -0
  57. data/lib/rom/types.rb +9 -1
  58. data/lib/rom/version.rb +1 -1
  59. data/lib/rom.rb +4 -8
  60. data/rom.gemspec +4 -3
  61. data/spec/integration/command_registry_spec.rb +1 -14
  62. data/spec/integration/commands/create_spec.rb +5 -25
  63. data/spec/integration/commands/delete_spec.rb +1 -1
  64. data/spec/integration/commands/error_handling_spec.rb +1 -1
  65. data/spec/integration/commands/graph_spec.rb +20 -14
  66. data/spec/integration/commands/update_spec.rb +4 -27
  67. data/spec/integration/commands_spec.rb +1 -1
  68. data/spec/integration/{repositories → gateways}/extending_relations_spec.rb +1 -1
  69. data/spec/integration/{repositories → gateways}/setting_logger_spec.rb +2 -2
  70. data/spec/integration/mappers/combine_spec.rb +1 -1
  71. data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
  72. data/spec/integration/mappers/definition_dsl_spec.rb +1 -1
  73. data/spec/integration/mappers/embedded_spec.rb +1 -1
  74. data/spec/integration/mappers/exclude_spec.rb +1 -1
  75. data/spec/integration/mappers/fold_spec.rb +1 -1
  76. data/spec/integration/mappers/group_spec.rb +1 -1
  77. data/spec/integration/mappers/overwrite_attributes_value_spec.rb +1 -1
  78. data/spec/integration/mappers/prefix_separator_spec.rb +1 -1
  79. data/spec/integration/mappers/prefix_spec.rb +1 -1
  80. data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
  81. data/spec/integration/mappers/registering_custom_mappers_spec.rb +1 -1
  82. data/spec/integration/mappers/renaming_attributes_spec.rb +1 -1
  83. data/spec/integration/mappers/reusing_mappers_spec.rb +1 -1
  84. data/spec/integration/mappers/step_spec.rb +1 -1
  85. data/spec/integration/mappers/symbolizing_attributes_spec.rb +1 -1
  86. data/spec/integration/mappers/unfold_spec.rb +1 -1
  87. data/spec/integration/mappers/ungroup_spec.rb +1 -1
  88. data/spec/integration/mappers/unwrap_spec.rb +2 -2
  89. data/spec/integration/mappers/wrap_spec.rb +1 -1
  90. data/spec/integration/memory/commands/create_spec.rb +1 -1
  91. data/spec/integration/memory/commands/delete_spec.rb +1 -1
  92. data/spec/integration/memory/commands/update_spec.rb +1 -1
  93. data/spec/integration/multi_env_spec.rb +1 -1
  94. data/spec/integration/multi_repo_spec.rb +1 -1
  95. data/spec/integration/relations/default_dataset_spec.rb +1 -1
  96. data/spec/integration/relations/reading_spec.rb +1 -1
  97. data/spec/integration/relations/registry_dsl_spec.rb +1 -1
  98. data/spec/integration/setup_spec.rb +10 -4
  99. data/spec/shared/command_graph.rb +8 -4
  100. data/spec/shared/enumerable_dataset.rb +1 -1
  101. data/spec/spec_helper.rb +7 -9
  102. data/spec/support/schema.rb +14 -0
  103. data/spec/unit/rom/array_dataset_spec.rb +59 -0
  104. data/spec/unit/rom/association_set_spec.rb +4 -0
  105. data/spec/unit/rom/auto_curry_spec.rb +63 -0
  106. data/spec/unit/rom/commands/graph_spec.rb +12 -11
  107. data/spec/unit/rom/commands/lazy_spec.rb +8 -5
  108. data/spec/unit/rom/commands/pre_and_post_processors_spec.rb +269 -0
  109. data/spec/unit/rom/commands/result_spec.rb +1 -1
  110. data/spec/unit/rom/commands_spec.rb +9 -3
  111. data/spec/unit/rom/configuration_spec.rb +1 -1
  112. data/spec/unit/rom/container_spec.rb +11 -5
  113. data/spec/unit/rom/create_container_spec.rb +1 -1
  114. data/spec/unit/rom/enumerable_dataset_spec.rb +15 -0
  115. data/spec/unit/rom/gateway_spec.rb +1 -1
  116. data/spec/unit/rom/mapper_registry_spec.rb +1 -1
  117. data/spec/unit/rom/memory/commands_spec.rb +1 -1
  118. data/spec/unit/rom/memory/dataset_spec.rb +1 -1
  119. data/spec/unit/rom/memory/{repository_spec.rb → gateway_spec.rb} +1 -1
  120. data/spec/unit/rom/memory/inheritance_spec.rb +32 -0
  121. data/spec/unit/rom/memory/relation_spec.rb +15 -3
  122. data/spec/unit/rom/memory/storage_spec.rb +1 -1
  123. data/spec/unit/rom/plugin_spec.rb +1 -1
  124. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +1 -1
  125. data/spec/unit/rom/registry_spec.rb +86 -0
  126. data/spec/unit/rom/relation/attribute_reader_spec.rb +17 -0
  127. data/spec/unit/rom/relation/composite_spec.rb +1 -1
  128. data/spec/unit/rom/relation/graph_spec.rb +1 -1
  129. data/spec/unit/rom/relation/lazy/combine_spec.rb +1 -1
  130. data/spec/unit/rom/relation/lazy_spec.rb +1 -1
  131. data/spec/unit/rom/relation/loaded_spec.rb +1 -1
  132. data/spec/unit/rom/relation/schema_spec.rb +10 -6
  133. data/spec/unit/rom/relation/view_spec.rb +112 -0
  134. data/spec/unit/rom/relation_spec.rb +16 -2
  135. data/spec/unit/rom/schema/accessing_attributes_spec.rb +52 -0
  136. data/spec/unit/rom/schema/exclude_spec.rb +15 -0
  137. data/spec/unit/rom/schema/finalize_spec.rb +59 -0
  138. data/spec/unit/rom/schema/key_predicate_spec.rb +15 -0
  139. data/spec/unit/rom/schema/merge_spec.rb +17 -0
  140. data/spec/unit/rom/schema/prefix_spec.rb +16 -0
  141. data/spec/unit/rom/schema/project_spec.rb +15 -0
  142. data/spec/unit/rom/schema/rename_spec.rb +22 -0
  143. data/spec/unit/rom/schema/type_spec.rb +49 -0
  144. data/spec/unit/rom/schema/wrap_spec.rb +17 -0
  145. data/spec/unit/rom/schema_spec.rb +2 -2
  146. metadata +69 -17
  147. data/lib/rom/plugins/relation/view/dsl.rb +0 -32
  148. data/lib/rom/plugins/relation/view.rb +0 -95
  149. data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
@@ -0,0 +1,86 @@
1
+ require 'rom/registry'
2
+
3
+ RSpec.shared_examples_for 'registry fetch' do
4
+ it 'raises an ArgumentError when nil is used as a key' do
5
+ expect {
6
+ registry.public_send(fetch_method, nil)
7
+ }.to raise_error(ArgumentError, "key cannot be nil")
8
+ end
9
+
10
+ it 'returns registered element identified by name' do
11
+ expect(registry.public_send(fetch_method, :mars)).to be(mars)
12
+ end
13
+
14
+ it 'raises error when element is not found' do
15
+ expect { registry.public_send(fetch_method, :twix) }.to raise_error(
16
+ ROM::Registry::ElementNotFoundError,
17
+ ":twix doesn't exist in Candy registry"
18
+ )
19
+ end
20
+
21
+ it 'returns the value from an optional block when key is not found' do
22
+ value = registry.public_send(fetch_method, :candy) { :twix }
23
+
24
+ expect(value).to eq(:twix)
25
+ end
26
+
27
+ it 'calls #to_sym on a key before fetching' do
28
+ expect(registry.public_send(fetch_method, double(to_sym: :mars))).to be(mars)
29
+ end
30
+ end
31
+
32
+ RSpec.describe ROM::Registry do
33
+ subject(:registry) { registry_class.new(mars: mars) }
34
+
35
+ let(:mars) { double('mars') }
36
+
37
+ let(:registry_class) do
38
+ Class.new(ROM::Registry) do
39
+ def self.name
40
+ 'Candy'
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#fetch' do
46
+ let(:fetch_method) { :fetch }
47
+
48
+ it_behaves_like 'registry fetch'
49
+ end
50
+
51
+ describe '#[]' do
52
+ let(:fetch_method) { :[] }
53
+
54
+ it_behaves_like 'registry fetch'
55
+ end
56
+
57
+ describe '#method_missing' do
58
+ it 'returns registered element identified by name' do
59
+ expect(registry.mars).to be(mars)
60
+ end
61
+
62
+ it 'raises no-method error when element is not there' do
63
+ expect { registry.twix }.to raise_error(NoMethodError)
64
+ end
65
+ end
66
+
67
+ describe '#key?' do
68
+ let(:mars) { double(to_sym: :mars) }
69
+
70
+ it 'calls #to_sym on a key before checking if it exists' do
71
+ registry.key?(:mars)
72
+ end
73
+
74
+ it 'returns true for an existing key' do
75
+ expect(registry.key?(:mars)).to be(true)
76
+ end
77
+
78
+ it 'returns false for a non-existing key' do
79
+ expect(registry.key?(:twix)).to be(false)
80
+ end
81
+
82
+ it 'returns false for a nil key' do
83
+ expect(registry.key?(nil)).to be(false)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,17 @@
1
+ require 'rom/memory'
2
+
3
+ RSpec.describe ROM::Relation, '#[]' do
4
+ it 'defines a canonical schema for a relation' do
5
+ class Test::Users < ROM::Relation[:memory]
6
+ schema do
7
+ attribute :id, Types::Int
8
+ attribute :name, Types::String
9
+ end
10
+ end
11
+
12
+ relation = Test::Users.new([])
13
+
14
+ expect(relation[:id]).to be(Test::Users.schema[:id])
15
+ expect(relation[:name]).to be(Test::Users.schema[:name])
16
+ end
17
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ROM::Relation::Composite do
3
+ RSpec.describe ROM::Relation::Composite do
4
4
  include_context 'gateway only'
5
5
  include_context 'users and tasks'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ROM::Relation::Graph do
3
+ RSpec.describe ROM::Relation::Graph do
4
4
  include_context 'gateway only'
5
5
  include_context 'users and tasks'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ROM::Relation, '#combine' do
3
+ RSpec.describe ROM::Relation, '#combine' do
4
4
  include_context 'gateway only'
5
5
  include_context 'users and tasks'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ROM::Relation do
3
+ RSpec.describe ROM::Relation do
4
4
  include_context 'gateway only'
5
5
  include_context 'users and tasks'
6
6
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ROM::Relation::Loaded do
3
+ RSpec.describe ROM::Relation::Loaded do
4
4
  include_context 'no container'
5
5
  include_context 'users and tasks'
6
6
 
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'rom/memory'
3
3
 
4
- describe ROM::Relation, '.schema' do
4
+ RSpec.describe ROM::Relation, '.schema' do
5
5
  it 'defines a canonical schema for a relation' do
6
6
  class Test::Users < ROM::Relation[:memory]
7
7
  schema do
@@ -13,11 +13,15 @@ describe ROM::Relation, '.schema' do
13
13
 
14
14
  Test::Users.schema.finalize!
15
15
 
16
- schema = ROM::Schema.new(
16
+ relation_name = ROM::Relation::Name[:test_users]
17
+
18
+ schema = ROM::Memory::Schema.define(
17
19
  ROM::Relation::Name.new(:test_users),
18
- id: ROM::Memory::Types::Int.meta(primary_key: true, name: :id),
19
- name: ROM::Memory::Types::String.meta(name: :name),
20
- admin: ROM::Memory::Types::Bool.meta(name: :admin)
20
+ attributes: [
21
+ ROM::Memory::Types::Int.meta(primary_key: true, name: :id, source: relation_name),
22
+ ROM::Memory::Types::String.meta(name: :name, source: relation_name),
23
+ ROM::Memory::Types::Bool.meta(name: :admin, source: relation_name)
24
+ ]
21
25
  ).finalize!
22
26
 
23
27
  expect(Test::Users.schema.primary_key).to eql([Test::Users.schema[:id]])
@@ -111,7 +115,7 @@ describe ROM::Relation, '.schema' do
111
115
  end
112
116
  end
113
117
 
114
- expect(Test::Users.schema[:admin]).to eql(ROM::Types::Bool.meta(name: :admin))
118
+ expect(Test::Users.schema[:admin]).to eql(ROM::Types::Bool.meta(name: :admin, source: ROM::Relation::Name[:test_users]))
115
119
  end
116
120
  end
117
121
  end
@@ -0,0 +1,112 @@
1
+ require 'rom'
2
+ require 'rom/memory'
3
+
4
+ RSpec.describe ROM::Relation do
5
+ subject(:relation) { relation_class.new(ROM::Memory::Dataset.new([])) }
6
+
7
+ shared_context 'relation with views' do
8
+ before do
9
+ relation << { id: 1, name: 'Joe' }
10
+ relation << { id: 2, name: 'Jane' }
11
+ end
12
+
13
+ it 'uses projected schema for view schema' do
14
+ expect(relation.schemas[:names].map(&:name)).to eql(%i[name])
15
+ end
16
+
17
+ it 'auto-projects the relation via schema' do
18
+ new_rel = relation_class.new([{ name: 'Jane' }, { name: 'Joe' }])
19
+ names_schema = relation_class.schemas[:names]
20
+
21
+ expect(names_schema).to receive(:call).with(relation).and_return(new_rel)
22
+ expect(relation.names).to eql(new_rel)
23
+ end
24
+
25
+ it 'auto-projects a restricted relation via schema' do
26
+ new_rel = relation_class.new([{ id: 2 }])
27
+ ids_schema = relation_class.schemas[:ids_for_names]
28
+
29
+ expect(ids_schema).to receive(:call).with(relation.restrict(name: ['Jane'])).and_return(new_rel)
30
+ expect(relation.ids_for_names(['Jane'])).to eql(new_rel)
31
+ end
32
+ end
33
+
34
+ context 'with an explicit schema' do
35
+ before do
36
+ # this is normally called automatically during setup
37
+ relation_class.finalize({}, relation)
38
+ end
39
+
40
+ include_context 'relation with views' do
41
+ let(:relation_class) do
42
+ Class.new(ROM::Memory::Relation) do
43
+ schema(:users) do
44
+ attribute :id, ROM::Types::Int
45
+ attribute :name, ROM::Types::String
46
+ end
47
+
48
+ view(:names) do
49
+ schema do
50
+ project(:name)
51
+ end
52
+
53
+ relation do
54
+ self
55
+ end
56
+ end
57
+
58
+ view(:ids_for_names) do
59
+ schema do
60
+ project(:id)
61
+ end
62
+
63
+ relation do |names|
64
+ restrict(name: names)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ context 'with an inferred schema' do
73
+ before do
74
+ # this is normally called automatically during setup
75
+ relation_class.schema.finalize!
76
+ relation_class.finalize({}, relation)
77
+ end
78
+
79
+ include_context 'relation with views' do
80
+ let(:relation_class) do
81
+ Class.new(ROM::Memory::Relation) do
82
+ schema_inferrer -> dataset, gateway {
83
+ [[ROM::Types::Int.meta(name: :id, source: :users),
84
+ ROM::Types::String.meta(name: :name, source: :users)], []]
85
+ }
86
+
87
+ schema(:users, infer: true)
88
+
89
+ view(:names) do
90
+ schema do
91
+ project(:name)
92
+ end
93
+
94
+ relation do
95
+ self
96
+ end
97
+ end
98
+
99
+ view(:ids_for_names) do
100
+ schema do
101
+ project(:id)
102
+ end
103
+
104
+ relation do |names|
105
+ restrict(name: names)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1,6 +1,6 @@
1
1
  require 'rom/memory'
2
2
 
3
- describe ROM::Relation do
3
+ RSpec.describe ROM::Relation do
4
4
  subject(:relation) { Class.new(ROM::Relation).new(dataset) }
5
5
 
6
6
  let(:dataset) { ROM::Memory::Dataset.new([jane, joe]) }
@@ -196,7 +196,7 @@ describe ROM::Relation do
196
196
 
197
197
  describe "#with" do
198
198
  it "returns a new instance with the original dataset and given custom options" do
199
- relation = Class.new(ROM::Relation) { option :custom }.new([])
199
+ relation = Class.new(ROM::Relation) { option :custom }.new([], custom: true)
200
200
 
201
201
  custom_opts = { mappers: "Custom Mapper Registry" }
202
202
  new_relation = relation.with(custom_opts).with(custom: true)
@@ -217,6 +217,20 @@ describe ROM::Relation do
217
217
  end
218
218
  end
219
219
 
220
+ describe '#schema' do
221
+ it 'returns an empty schema by default' do
222
+ relation = Class.new(ROM::Relation[:memory]) {
223
+ def self.name
224
+ 'SomeRelation'
225
+ end
226
+ }.new([])
227
+
228
+ expect(relation.schema).to be_empty
229
+ expect(relation.schema.name).to be(:some_relation)
230
+ expect(relation.schema?).to be(false)
231
+ end
232
+ end
233
+
220
234
  describe '#schema_hash' do
221
235
  it 'returns a schema hash type' do
222
236
  relation = Class.new(ROM::Relation[:memory]) do
@@ -0,0 +1,52 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#[]' do
4
+ context 'with a schema' do
5
+ subject(:schema) do
6
+ define_schema(:users, id: :Int, name: :String, email: :String)
7
+ end
8
+
9
+ it 'returns an attribute identified by its canonical name' do
10
+ expect(schema[:email]).to eql(define_type(:email, :String, source: :users))
11
+ end
12
+
13
+ it 'returns an aliased attribute identified by its canonical name' do
14
+ expect(schema.rename(id: :user_id)[:id]).to eql(define_type(:id, :Int, source: :users, alias: :user_id))
15
+ end
16
+
17
+ it 'raises KeyError when attribute is not found' do
18
+ expect { schema[:not_here] }.to raise_error(KeyError, /not_here/)
19
+ end
20
+ end
21
+
22
+ context 'with a merged schema' do
23
+ subject(:schema) do
24
+ left.merge(right.__send__(:new, right.map { |attr| attr.meta(source: :tasks) }))
25
+ end
26
+
27
+ let(:left) do
28
+ define_schema(:users, id: :Int, name: :String)
29
+ end
30
+
31
+ let(:right) do
32
+ define_schema(:tasks, id: :Int, title: :String)
33
+ end
34
+
35
+ it 'returns an attribute identified by its canonical name' do
36
+ expect(schema[:id]).to eql(define_type(:id, :Int, source: :users))
37
+ end
38
+
39
+ it 'returns an attribute identified by its canonical name when its unique' do
40
+ expect(schema[:title]).to eql(define_type(:title, :String, source: :tasks))
41
+ end
42
+
43
+ it 'returns an attribute identified by its canonical name and its source' do
44
+ expect(schema[:id, :tasks]).to eql(define_type(:id, :Int, source: :tasks))
45
+ end
46
+
47
+ it 'raises KeyError when attribute is not found' do
48
+ expect { schema[:not_here] }.to raise_error(KeyError, /not_here/)
49
+ expect { schema[:not_here, :tasks] }.to raise_error(KeyError, /not_here/)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#exclude' do
4
+ subject(:schema) do
5
+ define_schema(:users, id: :Int, name: :String, email: :String)
6
+ end
7
+
8
+ let(:excluded) do
9
+ schema.exclude(:id, :name)
10
+ end
11
+
12
+ it 'returns projected schema with renamed attributes using provided prefix' do
13
+ expect(excluded.map(&:name)).to eql(%i[email])
14
+ end
15
+ end
@@ -0,0 +1,59 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#finalize!' do
4
+ context 'without inferrer' do
5
+ subject(:schema) do
6
+ define_schema(:users, id: :Int, name: :String)
7
+ end
8
+
9
+ before { schema.finalize! }
10
+
11
+ it 'returns a frozen canonical schema' do
12
+ expect(schema).to be_frozen
13
+ end
14
+ end
15
+
16
+ context 'with inferrer' do
17
+ subject(:schema) do
18
+ ROM::Schema.define(:users, attributes: attributes, inferrer: inferrer)
19
+ end
20
+
21
+ let(:inferrer) do
22
+ proc { [[define_type(:name, :String)], [:id, :age]]}
23
+ end
24
+
25
+ context 'when all required attributes are present' do
26
+ let(:attributes) do
27
+ [define_type(:id, :Int), define_type(:age, :Int)]
28
+ end
29
+
30
+ it 'concats defined attributes with inferred attributes' do
31
+ expect(schema.finalize!.map(&:name)).to eql(%i[id age name])
32
+ end
33
+ end
34
+
35
+ context 'when inferred attributes are overridden' do
36
+ let(:attributes) do
37
+ [define_type(:id, :Int),
38
+ define_type(:age, :Int),
39
+ define_type(:name, :String).meta(custom: true)]
40
+ end
41
+
42
+ it 'respects overridden attributes' do
43
+ expect(schema.finalize!.map(&:name)).to eql(%i[id age name])
44
+ expect(schema[:name].meta[:custom]).to be(true)
45
+ end
46
+ end
47
+
48
+ context 'when some attributes are missing' do
49
+ let(:attributes) do
50
+ []
51
+ end
52
+
53
+ it 'raises error' do
54
+ expect { schema.finalize! }.
55
+ to raise_error(ROM::Schema::MissingAttributesError, /missing attributes in :users schema: :id, :age/)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,15 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#key?' do
4
+ subject(:schema) do
5
+ define_schema(:users, name: :String)
6
+ end
7
+
8
+ it 'returns true when an attribute exists' do
9
+ expect(schema.key?(:name)).to be(true)
10
+ end
11
+
12
+ it 'returns false when an attribute does not exist' do
13
+ expect(schema.key?(:foo)).to be(false)
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#merge' do
4
+ subject(:schema) { left.merge(right) }
5
+
6
+ let(:left) do
7
+ define_schema(:users, id: :Int, name: :String)
8
+ end
9
+
10
+ let(:right) do
11
+ define_schema(:tasks, user_id: :Int)
12
+ end
13
+
14
+ it 'returns a new schema with attributes from two schemas' do
15
+ expect(schema.map(&:name)).to eql(%i[id name user_id])
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#prefix' do
4
+ subject(:schema) do
5
+ define_schema(:users, id: :Int, name: :String)
6
+ end
7
+
8
+ let(:prefixed) do
9
+ schema.prefix(:user)
10
+ end
11
+
12
+ it 'returns projected schema with renamed attributes using provided prefix' do
13
+ expect(prefixed.map(&:alias)).to eql(%i[user_id user_name])
14
+ expect(prefixed.map { |attr| attr.meta[:name] }).to eql(%i[id name])
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#project' do
4
+ subject(:schema) do
5
+ define_schema(:users, id: :Int, name: :String, age: :Int)
6
+ end
7
+
8
+ it 'projects provided attribute names' do
9
+ expect(schema.project(:name, :age).map(&:name)).to eql(%i[name age])
10
+ end
11
+
12
+ it 'projects provided attributes' do
13
+ expect(schema.project(schema[:name], schema[:age]).map(&:name)).to eql(%i[name age])
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#rename' do
4
+ subject(:schema) do
5
+ define_schema(
6
+ :users,
7
+ user_id: :Int, user_name: :String, user_email: :String
8
+ )
9
+ end
10
+
11
+ let(:renamed) do
12
+ schema.rename(user_id: :id, user_name: :name)
13
+ end
14
+
15
+ it 'returns projected schema with renamed attributes' do
16
+ expect(renamed.map(&:name)).to eql(%i[user_id user_name user_email])
17
+ expect(renamed.map(&:alias)).to eql([:id, :name, nil])
18
+ expect(renamed.all?(&:aliased?)).to be(false)
19
+ expect(renamed[:user_id]).to be_aliased
20
+ expect(renamed[:user_name]).to be_aliased
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ require 'rom/schema/type'
2
+
3
+ RSpec.describe ROM::Schema::Type do
4
+ describe '#inspect' do
5
+ context 'with a primitive definition' do
6
+ subject(:type) do
7
+ ROM::Schema::Type.new(ROM::Types::Int).meta(name: :id, primary_key: true)
8
+ end
9
+
10
+ specify do
11
+ expect(type.inspect).to eql("#<ROM::Schema::Type[Integer] name=:id primary_key=true>")
12
+ end
13
+ end
14
+
15
+ context 'with a sum' do
16
+ subject(:type) do
17
+ ROM::Schema::Type.new(ROM::Types::Bool).meta(name: :admin)
18
+ end
19
+
20
+ specify do
21
+ expect(type.inspect).to eql("#<ROM::Schema::Type[TrueClass | FalseClass] name=:admin>")
22
+ end
23
+ end
24
+ end
25
+
26
+ describe '#aliased' do
27
+ subject(:type) do
28
+ ROM::Schema::Type.new(ROM::Types::String).meta(name: :user_name)
29
+ end
30
+
31
+ specify do
32
+ expect(type.as(:name).meta[:alias]).to eql(:name)
33
+ end
34
+ end
35
+
36
+ describe '#method_missing' do
37
+ subject(:type) do
38
+ ROM::Schema::Type.new(ROM::Types::Int).meta(name: :id, primary_key: true)
39
+ end
40
+
41
+ specify do
42
+ expect(type.meta).to eql(name: :id, primary_key: true)
43
+ end
44
+
45
+ specify do
46
+ expect { type.not_here }.to raise_error(NoMethodError, /not_here/)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ require 'rom/schema'
2
+
3
+ RSpec.describe ROM::Schema, '#wrap' do
4
+ subject(:schema) do
5
+ define_schema(:users, id: :Int, name: :String)
6
+ end
7
+
8
+ let(:wrapped) do
9
+ schema.wrap(:users)
10
+ end
11
+
12
+ it 'returns projected schema with renamed attributes using provided prefix' do
13
+ expect(wrapped.map(&:alias)).to eql(%i[users_id users_name])
14
+ expect(wrapped.map { |attr| attr.meta[:name] }).to eql(%i[id name])
15
+ expect(wrapped.all?(&:wrapped?)).to be(true)
16
+ end
17
+ end
@@ -1,8 +1,8 @@
1
1
  RSpec.describe ROM::Schema do
2
2
  describe '#to_h' do
3
3
  it 'returns hash with attributes' do
4
- attrs = { id: ROM::Types::Int, name: ROM::Types::String }
5
- schema = ROM::Schema.new(:name, attrs)
4
+ attrs = { id: ROM::Types::Int.meta(name: :id), name: ROM::Types::String.meta(name: :name) }
5
+ schema = ROM::Schema.define(:name, attributes: attrs.values)
6
6
 
7
7
  expect(schema.to_h).to eql(attrs)
8
8
  end