rom 2.0.2 → 3.0.0.beta1

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 (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