rom 0.4.2 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +81 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile +12 -8
- data/Guardfile +17 -11
- data/README.md +7 -7
- data/Rakefile +29 -0
- data/lib/rom.rb +9 -66
- data/lib/rom/adapter.rb +45 -12
- data/lib/rom/adapter/memory.rb +0 -4
- data/lib/rom/adapter/memory/commands.rb +0 -10
- data/lib/rom/adapter/memory/dataset.rb +18 -6
- data/lib/rom/adapter/memory/storage.rb +0 -3
- data/lib/rom/command_registry.rb +24 -43
- data/lib/rom/commands.rb +5 -6
- data/lib/rom/commands/create.rb +5 -5
- data/lib/rom/commands/delete.rb +8 -6
- data/lib/rom/commands/result.rb +82 -0
- data/lib/rom/commands/update.rb +5 -4
- data/lib/rom/commands/with_options.rb +1 -4
- data/lib/rom/config.rb +70 -0
- data/lib/rom/env.rb +11 -3
- data/lib/rom/global.rb +107 -0
- data/lib/rom/header.rb +122 -89
- data/lib/rom/header/attribute.rb +148 -0
- data/lib/rom/mapper.rb +46 -67
- data/lib/rom/mapper_builder.rb +20 -73
- data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
- data/lib/rom/mapper_builder/model_dsl.rb +29 -0
- data/lib/rom/mapper_registry.rb +21 -0
- data/lib/rom/model_builder.rb +11 -17
- data/lib/rom/processor.rb +28 -0
- data/lib/rom/processor/transproc.rb +105 -0
- data/lib/rom/reader.rb +81 -21
- data/lib/rom/reader_builder.rb +14 -4
- data/lib/rom/relation.rb +19 -5
- data/lib/rom/relation_builder.rb +20 -6
- data/lib/rom/repository.rb +0 -2
- data/lib/rom/setup.rb +156 -0
- data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
- data/lib/rom/setup/command_dsl.rb +46 -0
- data/lib/rom/setup/finalize.rb +125 -0
- data/lib/rom/setup/mapper_dsl.rb +19 -0
- data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
- data/lib/rom/setup/schema_dsl.rb +33 -0
- data/lib/rom/support/registry.rb +10 -6
- data/lib/rom/version.rb +1 -1
- data/rom.gemspec +3 -1
- data/spec/integration/adapters/extending_relations_spec.rb +0 -2
- data/spec/integration/commands/create_spec.rb +2 -9
- data/spec/integration/commands/delete_spec.rb +4 -5
- data/spec/integration/commands/error_handling_spec.rb +4 -3
- data/spec/integration/commands/update_spec.rb +3 -8
- data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
- data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
- data/spec/integration/mappers/embedded_spec.rb +82 -0
- data/spec/integration/mappers/group_spec.rb +170 -0
- data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
- data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
- data/spec/integration/mappers/wrap_spec.rb +162 -0
- data/spec/integration/multi_repo_spec.rb +64 -0
- data/spec/integration/relations/reading_spec.rb +12 -8
- data/spec/integration/relations/registry_dsl_spec.rb +1 -3
- data/spec/integration/schema_spec.rb +10 -0
- data/spec/integration/setup_spec.rb +57 -6
- data/spec/spec_helper.rb +2 -1
- data/spec/unit/config_spec.rb +60 -0
- data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
- data/spec/unit/rom/adapter_spec.rb +31 -11
- data/spec/unit/rom/header_spec.rb +60 -16
- data/spec/unit/rom/mapper_builder_spec.rb +311 -0
- data/spec/unit/rom/mapper_registry_spec.rb +25 -0
- data/spec/unit/rom/mapper_spec.rb +4 -5
- data/spec/unit/rom/model_builder_spec.rb +15 -13
- data/spec/unit/rom/processor/transproc_spec.rb +331 -0
- data/spec/unit/rom/reader_spec.rb +73 -0
- data/spec/unit/rom/registry_spec.rb +38 -0
- data/spec/unit/rom/relation_spec.rb +0 -1
- data/spec/unit/rom/setup_spec.rb +55 -0
- data/spec/unit/rom_spec.rb +14 -0
- metadata +62 -22
- data/Gemfile.devtools +0 -71
- data/lib/rom/boot.rb +0 -197
- data/lib/rom/boot/command_dsl.rb +0 -48
- data/lib/rom/boot/dsl.rb +0 -37
- data/lib/rom/boot/mapper_dsl.rb +0 -23
- data/lib/rom/boot/schema_dsl.rb +0 -27
- data/lib/rom/ra.rb +0 -172
- data/lib/rom/ra/operation/group.rb +0 -47
- data/lib/rom/ra/operation/join.rb +0 -39
- data/lib/rom/ra/operation/wrap.rb +0 -45
- data/lib/rom/transformer.rb +0 -77
- data/spec/integration/ra/group_spec.rb +0 -46
- data/spec/integration/ra/join_spec.rb +0 -50
- data/spec/integration/ra/wrap_spec.rb +0 -37
- data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
- data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
- data/spec/unit/rom/transformer_spec.rb +0 -41
@@ -4,7 +4,7 @@ require 'ostruct'
|
|
4
4
|
|
5
5
|
describe ROM::Mapper do
|
6
6
|
subject(:mapper) do
|
7
|
-
ROM::Mapper.build(ROM::Header.coerce(relation.header.zip
|
7
|
+
ROM::Mapper.build(ROM::Header.coerce(relation.header.zip, user_model))
|
8
8
|
end
|
9
9
|
|
10
10
|
let(:relation) do
|
@@ -13,7 +13,7 @@ describe ROM::Mapper do
|
|
13
13
|
|
14
14
|
let(:dataset) do
|
15
15
|
ROM::Adapter::Memory::Dataset.new(
|
16
|
-
[{id: 1, name: 'Jane'}, {id: 2, name: 'Joe'}], [:id, :name]
|
16
|
+
[{ id: 1, name: 'Jane' }, { id: 2, name: 'Joe' }], [:id, :name]
|
17
17
|
)
|
18
18
|
end
|
19
19
|
|
@@ -28,12 +28,11 @@ describe ROM::Mapper do
|
|
28
28
|
it "yields all mapped objects" do
|
29
29
|
result = []
|
30
30
|
|
31
|
-
relation.each do |tuple|
|
32
|
-
result <<
|
31
|
+
mapper.process(relation).each do |tuple|
|
32
|
+
result << tuple
|
33
33
|
end
|
34
34
|
|
35
35
|
expect(result).to eql([jane, joe])
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
38
|
end
|
@@ -5,7 +5,7 @@ describe ROM::ModelBuilder do
|
|
5
5
|
it 'builds a class with a constructor accepting attributes' do
|
6
6
|
builder = ROM::ModelBuilder::PORO.new
|
7
7
|
|
8
|
-
klass = builder.call(name
|
8
|
+
klass = builder.call([:name])
|
9
9
|
|
10
10
|
object = klass.new(name: 'Jane')
|
11
11
|
|
@@ -13,7 +13,7 @@ describe ROM::ModelBuilder do
|
|
13
13
|
|
14
14
|
expect { object.name = 'Jane' }.to raise_error(NoMethodError)
|
15
15
|
|
16
|
-
klass = builder.call(name
|
16
|
+
klass = builder.call([:name, :email])
|
17
17
|
|
18
18
|
object = klass.new(name: 'Jane', email: 'jane@doe.org')
|
19
19
|
|
@@ -21,23 +21,25 @@ describe ROM::ModelBuilder do
|
|
21
21
|
expect(object.email).to eql('jane@doe.org')
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
context 'when :name option is present' do
|
25
|
+
it 'defines a constant for the model' do
|
26
|
+
builder = ROM::ModelBuilder::PORO.new(name: 'User')
|
26
27
|
|
27
|
-
|
28
|
+
builder.call([:name, :email])
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
expect(Object.const_defined?(:User)).to be(true)
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
it 'defines a constant within a namespace for the model' do
|
34
|
+
module MyApp; module Entities; end; end
|
34
35
|
|
35
|
-
|
36
|
+
builder = ROM::ModelBuilder::PORO.new(name: 'MyApp::Entities::User')
|
36
37
|
|
37
|
-
|
38
|
+
builder.call([:name, :email])
|
38
39
|
|
39
|
-
|
40
|
-
|
40
|
+
expect(MyApp::Entities.const_defined?(:User)).to be(true)
|
41
|
+
expect(Object.const_defined?(:User)).to be(false)
|
42
|
+
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ROM::Processor::Transproc do
|
4
|
+
subject(:transproc) { ROM::Processor::Transproc.build(header) }
|
5
|
+
|
6
|
+
let(:header) { ROM::Header.coerce(attributes) }
|
7
|
+
|
8
|
+
context 'no mapping' do
|
9
|
+
let(:attributes) { [[:name]] }
|
10
|
+
let(:relation) { [{ name: 'Jane' }, { name: 'Joe' }] }
|
11
|
+
|
12
|
+
it 'returns tuples' do
|
13
|
+
expect(transproc[relation]).to eql(relation)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'coercing values' do
|
18
|
+
let(:attributes) { [[:name, type: :string], [:age, type: :integer]] }
|
19
|
+
let(:relation) { [{ name: :Jane, age: '1' }, { name: :Joe, age: '2' }] }
|
20
|
+
|
21
|
+
it 'returns tuples' do
|
22
|
+
expect(transproc[relation]).to eql([
|
23
|
+
{ name: 'Jane', age: 1 }, { name: 'Joe', age: 2 }
|
24
|
+
])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'mapping to object' do
|
29
|
+
let(:header) { ROM::Header.coerce(attributes, model) }
|
30
|
+
|
31
|
+
let(:model) do
|
32
|
+
Class.new do
|
33
|
+
include Virtus.value_object
|
34
|
+
values { attribute :name }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:attributes) { [[:name]] }
|
39
|
+
let(:relation) { [{ name: 'Jane' }, { name: 'Joe' }] }
|
40
|
+
|
41
|
+
it 'returns tuples' do
|
42
|
+
expect(transproc[relation]).to eql([
|
43
|
+
model.new(name: 'Jane'), model.new(name: 'Joe')
|
44
|
+
])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'renaming keys' do
|
49
|
+
let(:attributes) { [[:name, from: 'name']] }
|
50
|
+
let(:relation) { [{ 'name' => 'Jane' }, { 'name' => 'Joe' }] }
|
51
|
+
|
52
|
+
it 'returns tuples with renamed keys' do
|
53
|
+
expect(transproc[relation]).to eql([{ name: 'Jane' }, { name: 'Joe' }])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'mapping nested hash' do
|
58
|
+
let(:relation) do
|
59
|
+
[
|
60
|
+
{ 'name' => 'Jane', 'task' => { 'title' => 'Task One' } },
|
61
|
+
{ 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } }
|
62
|
+
]
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when no mapping is needed' do
|
66
|
+
let(:attributes) { [['name'], ['task', type: :hash, header: [[:title]]]] }
|
67
|
+
|
68
|
+
it 'returns tuples' do
|
69
|
+
expect(transproc[relation]).to eql(relation)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with deeply nested hashes' do
|
74
|
+
context 'when no renaming is required' do
|
75
|
+
let(:relation) do
|
76
|
+
[
|
77
|
+
{ 'user' => { 'name' => 'Jane', 'task' => { 'title' => 'Task One' } } },
|
78
|
+
{ 'user' => { 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } } }
|
79
|
+
]
|
80
|
+
end
|
81
|
+
|
82
|
+
let(:attributes) do
|
83
|
+
[[
|
84
|
+
'user', type: :hash, header: [
|
85
|
+
['name'],
|
86
|
+
['task', type: :hash, header: [['title']]]
|
87
|
+
]
|
88
|
+
]]
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns tuples' do
|
92
|
+
expect(transproc[relation]).to eql(relation)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'when renaming is required' do
|
97
|
+
let(:relation) do
|
98
|
+
[
|
99
|
+
{ user: { name: 'Jane', task: { title: 'Task One' } } },
|
100
|
+
{ user: { name: 'Joe', task: { title: 'Task Two' } } }
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:attributes) do
|
105
|
+
[[
|
106
|
+
'user', type: :hash, header: [
|
107
|
+
['name'],
|
108
|
+
['task', type: :hash, header: [['title']]]
|
109
|
+
]
|
110
|
+
]]
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'returns tuples' do
|
114
|
+
expect(transproc[relation]).to eql(relation)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'renaming keys' do
|
120
|
+
context 'when only hash needs renaming' do
|
121
|
+
let(:attributes) do
|
122
|
+
[
|
123
|
+
['name'],
|
124
|
+
[:task, from: 'task', type: :hash, header: [[:title, from: 'title']]]
|
125
|
+
]
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'returns tuples with key renamed in the nested hash' do
|
129
|
+
expect(transproc[relation]).to eql([
|
130
|
+
{ 'name' => 'Jane', :task => { title: 'Task One' } },
|
131
|
+
{ 'name' => 'Joe', :task => { title: 'Task Two' } }
|
132
|
+
])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'when all attributes need renaming' do
|
137
|
+
let(:attributes) do
|
138
|
+
[
|
139
|
+
[:name, from: 'name'],
|
140
|
+
[:task, from: 'task', type: :hash, header: [[:title, from: 'title']]]
|
141
|
+
]
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'returns tuples with key renamed in the nested hash' do
|
145
|
+
expect(transproc[relation]).to eql([
|
146
|
+
{ name: 'Jane', task: { title: 'Task One' } },
|
147
|
+
{ name: 'Joe', task: { title: 'Task Two' } }
|
148
|
+
])
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'wrapping tuples' do
|
155
|
+
let(:relation) do
|
156
|
+
[
|
157
|
+
{ 'name' => 'Jane', 'title' => 'Task One' },
|
158
|
+
{ 'name' => 'Joe', 'title' => 'Task Two' }
|
159
|
+
]
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'when no mapping is needed' do
|
163
|
+
let(:attributes) do
|
164
|
+
[
|
165
|
+
['name'],
|
166
|
+
['task', type: :hash, wrap: true, header: [['title']]]
|
167
|
+
]
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'returns wrapped tuples' do
|
171
|
+
expect(transproc[relation]).to eql([
|
172
|
+
{ 'name' => 'Jane', 'task' => { 'title' => 'Task One' } },
|
173
|
+
{ 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } }
|
174
|
+
])
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'with deeply wrapped tuples' do
|
179
|
+
let(:attributes) do
|
180
|
+
[
|
181
|
+
['user', type: :hash, wrap: true, header: [
|
182
|
+
['name'],
|
183
|
+
['task', type: :hash, wrap: true, header: [['title']]]
|
184
|
+
]]
|
185
|
+
]
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'returns wrapped tuples' do
|
189
|
+
expect(transproc[relation]).to eql([
|
190
|
+
{ 'user' => { 'name' => 'Jane', 'task' => { 'title' => 'Task One' } } },
|
191
|
+
{ 'user' => { 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } } }
|
192
|
+
])
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'renaming keys' do
|
197
|
+
context 'when only wrapped tuple requires renaming' do
|
198
|
+
let(:attributes) do
|
199
|
+
[
|
200
|
+
['name'],
|
201
|
+
['task', type: :hash, wrap: true, header: [[:title, from: 'title']]]
|
202
|
+
]
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'returns wrapped tuples with renamed keys' do
|
206
|
+
expect(transproc[relation]).to eql([
|
207
|
+
{ 'name' => 'Jane', 'task' => { title: 'Task One' } },
|
208
|
+
{ 'name' => 'Joe', 'task' => { title: 'Task Two' } }
|
209
|
+
])
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'when all attributes require renaming' do
|
214
|
+
let(:attributes) do
|
215
|
+
[
|
216
|
+
[:name, from: 'name'],
|
217
|
+
[:task, type: :hash, wrap: true, header: [[:title, from: 'title']]]
|
218
|
+
]
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'returns wrapped tuples with all keys renamed' do
|
222
|
+
expect(transproc[relation]).to eql([
|
223
|
+
{ name: 'Jane', task: { title: 'Task One' } },
|
224
|
+
{ name: 'Joe', task: { title: 'Task Two' } }
|
225
|
+
])
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'grouping tuples' do
|
232
|
+
let(:relation) do
|
233
|
+
[
|
234
|
+
{ 'name' => 'Jane', 'title' => 'Task One' },
|
235
|
+
{ 'name' => 'Jane', 'title' => 'Task Two' },
|
236
|
+
{ 'name' => 'Joe', 'title' => 'Task One' }
|
237
|
+
]
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'when no mapping is needed' do
|
241
|
+
let(:attributes) do
|
242
|
+
[
|
243
|
+
['name'],
|
244
|
+
['tasks', type: :array, group: true, header: [['title']]]
|
245
|
+
]
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'returns wrapped tuples with all keys renamed' do
|
249
|
+
expect(transproc[relation]).to eql([
|
250
|
+
{ 'name' => 'Jane',
|
251
|
+
'tasks' => [{ 'title' => 'Task One' }, { 'title' => 'Task Two' }] },
|
252
|
+
{ 'name' => 'Joe',
|
253
|
+
'tasks' => [{ 'title' => 'Task One' }] }
|
254
|
+
])
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
context 'renaming keys' do
|
259
|
+
context 'when only grouped tuple requires renaming' do
|
260
|
+
let(:attributes) do
|
261
|
+
[
|
262
|
+
['name'],
|
263
|
+
['tasks', type: :array, group: true, header: [[:title, from: 'title']]]
|
264
|
+
]
|
265
|
+
end
|
266
|
+
|
267
|
+
it 'returns grouped tuples with renamed keys' do
|
268
|
+
expect(transproc[relation]).to eql([
|
269
|
+
{ 'name' => 'Jane',
|
270
|
+
'tasks' => [{ title: 'Task One' }, { title: 'Task Two' }] },
|
271
|
+
{ 'name' => 'Joe',
|
272
|
+
'tasks' => [{ title: 'Task One' }] }
|
273
|
+
])
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'when all attributes require renaming' do
|
278
|
+
let(:attributes) do
|
279
|
+
[
|
280
|
+
[:name, from: 'name'],
|
281
|
+
[:tasks, type: :array, group: true, header: [[:title, from: 'title']]]
|
282
|
+
]
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'returns grouped tuples with all keys renamed' do
|
286
|
+
expect(transproc[relation]).to eql([
|
287
|
+
{ name: 'Jane',
|
288
|
+
tasks: [{ title: 'Task One' }, { title: 'Task Two' }] },
|
289
|
+
{ name: 'Joe',
|
290
|
+
tasks: [{ title: 'Task One' }] }
|
291
|
+
])
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
context 'nested grouping' do
|
297
|
+
let(:relation) do
|
298
|
+
[
|
299
|
+
{ name: 'Jane', title: 'Task One', tag: 'red' },
|
300
|
+
{ name: 'Jane', title: 'Task One', tag: 'green' },
|
301
|
+
{ name: 'Joe', title: 'Task One', tag: 'blue' }
|
302
|
+
]
|
303
|
+
end
|
304
|
+
|
305
|
+
let(:attributes) do
|
306
|
+
[
|
307
|
+
[:name],
|
308
|
+
[:tasks, type: :array, group: true, header: [
|
309
|
+
[:title],
|
310
|
+
[:tags, type: :array, group: true, header: [[:tag]]]
|
311
|
+
]]
|
312
|
+
]
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'returns deeply grouped tuples' do
|
316
|
+
expect(transproc[relation]).to eql([
|
317
|
+
{ name: 'Jane',
|
318
|
+
tasks: [
|
319
|
+
{ title: 'Task One', tags: [{ tag: 'red' }, { tag: 'green' }] }
|
320
|
+
]
|
321
|
+
},
|
322
|
+
{ name: 'Joe',
|
323
|
+
tasks: [
|
324
|
+
{ title: 'Task One', tags: [{ tag: 'blue' }] }
|
325
|
+
]
|
326
|
+
}
|
327
|
+
])
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ROM::Reader do
|
4
|
+
subject(:reader) { ROM::Reader.new(name, relation, mappers) }
|
5
|
+
|
6
|
+
let(:name) { :users }
|
7
|
+
let(:relation) { [jane, joe] }
|
8
|
+
let(:jane) { { name: 'Jane' } }
|
9
|
+
let(:joe) { { name: 'Joe' } }
|
10
|
+
let(:mappers) { ROM::MapperRegistry.new(users: mapper) }
|
11
|
+
let(:mapper) { double('mapper', header: []) }
|
12
|
+
|
13
|
+
describe '#initialize' do
|
14
|
+
it 'raises error when mapper cannot be found' do
|
15
|
+
expect { ROM::Reader.new(:not_here, relation, mappers) }
|
16
|
+
.to raise_error(ROM::Reader::MapperMissingError, /not_here/)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#each' do
|
21
|
+
it 'yields mapped tuples from relations' do
|
22
|
+
expect(mapper).to receive(:process)
|
23
|
+
.with(relation)
|
24
|
+
.and_yield(jane).and_yield(joe)
|
25
|
+
|
26
|
+
result = []
|
27
|
+
reader.each { |user| result << user }
|
28
|
+
expect(result).to eql([jane, joe])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '.build' do
|
33
|
+
subject(:reader) { ROM::Reader.build(name, relation, mappers, [:all]) }
|
34
|
+
|
35
|
+
before do
|
36
|
+
relation.instance_exec do
|
37
|
+
def name
|
38
|
+
'users'
|
39
|
+
end
|
40
|
+
|
41
|
+
def all(*_args)
|
42
|
+
find_all
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'sets reader class name' do
|
48
|
+
expect(reader.class.name).to eql("ROM::Reader[Users]")
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'defines methods from relation' do
|
52
|
+
block = proc {}
|
53
|
+
|
54
|
+
expect(relation).to receive(:all)
|
55
|
+
.with(1, &block)
|
56
|
+
.and_return([joe])
|
57
|
+
|
58
|
+
expect(mapper).to receive(:process)
|
59
|
+
.with([joe])
|
60
|
+
.and_yield(joe)
|
61
|
+
|
62
|
+
result = reader.all(1, &block)
|
63
|
+
|
64
|
+
expect(result.path).to eql('users.all')
|
65
|
+
expect(result.to_a).to eql([joe])
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises error when relation does not respond to the method' do
|
69
|
+
expect { reader.not_here }
|
70
|
+
.to raise_error(ROM::NoRelationError, /not_here/)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|