rom-mapper 0.5.1 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,19 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe ROM::Mapper::ModelDSL do
4
- describe '#model' do
5
- it 'calls the builder with non-excluded attributes only' do
6
- definition_class = Class.new do
7
- include ROM::Mapper::ModelDSL
8
-
9
- def initialize
10
- @attributes = [[:name], [:title, { exclude: true }]]
11
- @builder = ->(attrs) { Struct.new(*attrs) }
12
- end
13
- end
14
- model_instance = definition_class.new.model.new
15
- expect(model_instance).to respond_to(:name)
16
- expect(model_instance).to_not respond_to(:title)
17
- end
18
- end
19
- end
@@ -1,83 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'ostruct'
4
-
5
- RSpec.describe ROM::Mapper do
6
- subject(:mapper) { mapper_class.build }
7
-
8
- let(:mapper_class) do
9
- user_model = self.user_model
10
-
11
- Class.new(ROM::Mapper) do
12
- attribute :id
13
- attribute :name
14
- model user_model
15
- end
16
- end
17
-
18
- let(:relation) do
19
- [{ id: 1, name: 'Jane' }, { id: 2, name: 'Joe' }]
20
- end
21
-
22
- let(:user_model) do
23
- Class.new(OpenStruct) { include Equalizer.new(:id, :name) }
24
- end
25
-
26
- let(:jane) { user_model.new(id: 1, name: 'Jane') }
27
- let(:joe) { user_model.new(id: 2, name: 'Joe') }
28
-
29
- describe '.registry' do
30
- it 'builds mapper class registry for base and virtual relations' do
31
- users = Class.new(ROM::Mapper) { relation(:users) }
32
- entity = Class.new(ROM::Mapper) do
33
- relation(:users)
34
- register_as(:entity)
35
- end
36
- active = Class.new(users) { relation(:active) }
37
- admins = Class.new(users) { relation(:admins) }
38
- custom = Class.new(users) { register_as(:custom) }
39
-
40
- registry = ROM::Mapper.registry([users, entity, active, admins, custom])
41
-
42
- expect(registry).to eql(
43
- users: {
44
- users: users.build,
45
- entity: entity.build,
46
- active: active.build,
47
- admins: admins.build,
48
- custom: custom.build
49
- }
50
- )
51
- end
52
- end
53
-
54
- describe '.relation' do
55
- it 'inherits from parent' do
56
- base = Class.new(ROM::Mapper) { relation(:users) }
57
- virt = Class.new(base)
58
-
59
- expect(virt.relation).to be(:users)
60
- expect(virt.base_relation).to be(:users)
61
- end
62
-
63
- it 'allows overriding' do
64
- base = Class.new(ROM::Mapper) { relation(:users) }
65
- virt = Class.new(base) { relation(:active) }
66
-
67
- expect(virt.relation).to be(:active)
68
- expect(virt.base_relation).to be(:users)
69
- end
70
- end
71
-
72
- describe "#each" do
73
- it "yields all mapped objects" do
74
- result = []
75
-
76
- mapper.call(relation).each do |tuple|
77
- result << tuple
78
- end
79
-
80
- expect(result).to eql([jane, joe])
81
- end
82
- end
83
- end
@@ -1,506 +0,0 @@
1
- require 'spec_helper'
2
- require 'virtus'
3
-
4
- RSpec.describe ROM::Processor::Transproc do
5
- subject(:transproc) { ROM::Processor::Transproc.build(binding, header) }
6
-
7
- let(:binding) { nil }
8
- let(:header) { ROM::Header.coerce(attributes, options) }
9
- let(:options) { {} }
10
-
11
- context 'no mapping' do
12
- let(:attributes) { [[:name]] }
13
- let(:relation) { [{ name: 'Jane' }, { name: 'Joe' }] }
14
-
15
- it 'returns tuples' do
16
- expect(transproc[relation]).to eql(relation)
17
- end
18
- end
19
-
20
- context 'coercing values' do
21
- let(:attributes) { [[:name, type: :string], [:age, type: :integer]] }
22
- let(:relation) { [{ name: :Jane, age: '1' }, { name: :Joe, age: '2' }] }
23
-
24
- it 'returns tuples' do
25
- expect(transproc[relation]).to eql([
26
- { name: 'Jane', age: 1 }, { name: 'Joe', age: 2 }
27
- ])
28
- end
29
- end
30
-
31
- context 'mapping to object' do
32
- let(:options) { { model: model } }
33
-
34
- let(:model) do
35
- Class.new do
36
- include Virtus.value_object
37
- values { attribute :name }
38
- end
39
- end
40
-
41
- let(:attributes) { [[:name]] }
42
- let(:relation) { [{ name: 'Jane' }, { name: 'Joe' }] }
43
-
44
- it 'returns tuples' do
45
- expect(transproc[relation]).to eql([
46
- model.new(name: 'Jane'), model.new(name: 'Joe')
47
- ])
48
- end
49
- end
50
-
51
- context 'renaming keys' do
52
- let(:attributes) do
53
- [[:name, from: 'name']]
54
- end
55
-
56
- let(:options) do
57
- { reject_keys: true }
58
- end
59
-
60
- let(:relation) do
61
- [
62
- { 'name' => 'Jane', 'age' => 21 }, { 'name' => 'Joe', age: 22 }
63
- ]
64
- end
65
-
66
- it 'returns tuples with rejected keys' do
67
- expect(transproc[relation]).to eql([{ name: 'Jane' }, { name: 'Joe' }])
68
- end
69
- end
70
-
71
- context 'copying keys' do
72
- let(:options) do
73
- { copy_keys: true }
74
- end
75
-
76
- let(:attributes) do
77
- [['b', from: 'a'], ['c', from: 'b']]
78
- end
79
-
80
- let(:relation) do
81
- [{ 'a' => 'copy' }]
82
- end
83
-
84
- it 'copies without removing the original' do
85
- expect(transproc[relation]).to eql([{ 'a' => 'copy', 'b' => 'copy', 'c' => 'copy' }])
86
- end
87
- end
88
-
89
- context 'key from existing keys' do
90
- let(:attributes) do
91
- coercer = ->(a, b) { b + a }
92
- [[:c, { from: [:a, :b], coercer: coercer }]]
93
- end
94
-
95
- let(:relation) do
96
- [
97
- { a: 'works', b: 'this' }
98
- ]
99
- end
100
-
101
- let(:expected_result) do
102
- [
103
- { c: 'thisworks' }
104
- ]
105
- end
106
-
107
- let(:copy_keys_expected_result) do
108
- [
109
- { a: 'works', b: 'this', c: 'thisworks'}
110
- ]
111
- end
112
-
113
- it 'returns tuples a new key added based on exsiting keys' do
114
- expect(transproc[relation]).to eql(expected_result)
115
- end
116
-
117
- it 'raises a configuration exception if coercer block does not exist' do
118
- attributes[0][1][:coercer] = nil
119
- expect { transproc[relation] }.to raise_error(ROM::MapperMisconfiguredError)
120
- end
121
-
122
- it 'honors the copy_keys option' do
123
- options.merge!({ copy_keys: true })
124
- expect(transproc[relation]).to eql(copy_keys_expected_result)
125
- end
126
- end
127
-
128
- describe 'rejecting keys' do
129
- let(:options) { { reject_keys: true } }
130
-
131
- let(:attributes) do
132
- [
133
- ['name'],
134
- ['tasks', type: :array, group: true, header: [['title']]]
135
- ]
136
- end
137
-
138
- let(:relation) do
139
- [
140
- { 'name' => 'Jane', 'age' => 21, 'title' => 'Task One' },
141
- { 'name' => 'Jane', 'age' => 21, 'title' => 'Task Two' },
142
- { 'name' => 'Joe', 'age' => 22, 'title' => 'Task One' }
143
- ]
144
- end
145
-
146
- it 'returns tuples with unknown keys rejected' do
147
- expect(transproc[relation]).to eql([
148
- { 'name' => 'Jane',
149
- 'tasks' => [{ 'title' => 'Task One' }, { 'title' => 'Task Two' }] },
150
- { 'name' => 'Joe',
151
- 'tasks' => [{ 'title' => 'Task One' }] }
152
- ])
153
- end
154
- end
155
-
156
- context 'mapping nested hash' do
157
- let(:relation) do
158
- [
159
- { 'name' => 'Jane', 'task' => { 'title' => 'Task One' } },
160
- { 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } }
161
- ]
162
- end
163
-
164
- context 'when no mapping is needed' do
165
- let(:attributes) { [['name'], ['task', type: :hash, header: [[:title]]]] }
166
-
167
- it 'returns tuples' do
168
- expect(transproc[relation]).to eql(relation)
169
- end
170
- end
171
-
172
- context 'with deeply nested hashes' do
173
- context 'when no renaming is required' do
174
- let(:relation) do
175
- [
176
- { 'user' => { 'name' => 'Jane', 'task' => { 'title' => 'Task One' } } },
177
- { 'user' => { 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } } }
178
- ]
179
- end
180
-
181
- let(:attributes) do
182
- [[
183
- 'user', type: :hash, header: [
184
- ['name'],
185
- ['task', type: :hash, header: [['title']]]
186
- ]
187
- ]]
188
- end
189
-
190
- it 'returns tuples' do
191
- expect(transproc[relation]).to eql(relation)
192
- end
193
- end
194
-
195
- context 'when renaming is required' do
196
- let(:relation) do
197
- [
198
- { user: { name: 'Jane', task: { title: 'Task One' } } },
199
- { user: { name: 'Joe', task: { title: 'Task Two' } } }
200
- ]
201
- end
202
-
203
- let(:attributes) do
204
- [[
205
- 'user', type: :hash, header: [
206
- ['name'],
207
- ['task', type: :hash, header: [['title']]]
208
- ]
209
- ]]
210
- end
211
-
212
- it 'returns tuples' do
213
- expect(transproc[relation]).to eql(relation)
214
- end
215
- end
216
- end
217
-
218
- context 'renaming keys' do
219
- context 'when only hash needs renaming' do
220
- let(:attributes) do
221
- [
222
- ['name'],
223
- [:task, from: 'task', type: :hash, header: [[:title, from: 'title']]]
224
- ]
225
- end
226
-
227
- it 'returns tuples with key renamed in the nested hash' do
228
- expect(transproc[relation]).to eql([
229
- { 'name' => 'Jane', :task => { title: 'Task One' } },
230
- { 'name' => 'Joe', :task => { title: 'Task Two' } }
231
- ])
232
- end
233
- end
234
-
235
- context 'when all attributes need renaming' do
236
- let(:attributes) do
237
- [
238
- [:name, from: 'name'],
239
- [:task, from: 'task', type: :hash, header: [[:title, from: 'title']]]
240
- ]
241
- end
242
-
243
- it 'returns tuples with key renamed in the nested hash' do
244
- expect(transproc[relation]).to eql([
245
- { name: 'Jane', task: { title: 'Task One' } },
246
- { name: 'Joe', task: { title: 'Task Two' } }
247
- ])
248
- end
249
- end
250
- end
251
- end
252
-
253
- context 'wrapping tuples' do
254
- let(:relation) do
255
- [
256
- { 'name' => 'Jane', 'title' => 'Task One' },
257
- { 'name' => 'Joe', 'title' => 'Task Two' }
258
- ]
259
- end
260
-
261
- context 'when no mapping is needed' do
262
- let(:attributes) do
263
- [
264
- ['name'],
265
- ['task', type: :hash, wrap: true, header: [['title']]]
266
- ]
267
- end
268
-
269
- it 'returns wrapped tuples' do
270
- expect(transproc[relation]).to eql([
271
- { 'name' => 'Jane', 'task' => { 'title' => 'Task One' } },
272
- { 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } }
273
- ])
274
- end
275
- end
276
-
277
- context 'with deeply wrapped tuples' do
278
- let(:attributes) do
279
- [
280
- ['user', type: :hash, wrap: true, header: [
281
- ['name'],
282
- ['task', type: :hash, wrap: true, header: [['title']]]
283
- ]]
284
- ]
285
- end
286
-
287
- it 'returns wrapped tuples' do
288
- expect(transproc[relation]).to eql([
289
- { 'user' => { 'name' => 'Jane', 'task' => { 'title' => 'Task One' } } },
290
- { 'user' => { 'name' => 'Joe', 'task' => { 'title' => 'Task Two' } } }
291
- ])
292
- end
293
- end
294
-
295
- context 'renaming keys' do
296
- context 'when only wrapped tuple requires renaming' do
297
- let(:attributes) do
298
- [
299
- ['name'],
300
- ['task', type: :hash, wrap: true, header: [[:title, from: 'title']]]
301
- ]
302
- end
303
-
304
- it 'returns wrapped tuples with renamed keys' do
305
- expect(transproc[relation]).to eql([
306
- { 'name' => 'Jane', 'task' => { title: 'Task One' } },
307
- { 'name' => 'Joe', 'task' => { title: 'Task Two' } }
308
- ])
309
- end
310
- end
311
-
312
- context 'when all attributes require renaming' do
313
- let(:attributes) do
314
- [
315
- [:name, from: 'name'],
316
- [:task, type: :hash, wrap: true, header: [[:title, from: 'title']]]
317
- ]
318
- end
319
-
320
- it 'returns wrapped tuples with all keys renamed' do
321
- expect(transproc[relation]).to eql([
322
- { name: 'Jane', task: { title: 'Task One' } },
323
- { name: 'Joe', task: { title: 'Task Two' } }
324
- ])
325
- end
326
- end
327
- end
328
- end
329
-
330
- context 'unwrapping tuples' do
331
- let(:relation) do
332
- [
333
- { 'user' => { 'name' => 'Leo', 'task' => { 'title' => 'Task 1' } } },
334
- { 'user' => { 'name' => 'Joe', 'task' => { 'title' => 'Task 2' } } }
335
- ]
336
- end
337
-
338
- context 'when no mapping is needed' do
339
- let(:attributes) do
340
- [
341
- ['user', type: :hash, unwrap: true, header: [['name'], ['task']]]
342
- ]
343
- end
344
-
345
- it 'returns unwrapped tuples' do
346
- expect(transproc[relation]).to eql([
347
- { 'name' => 'Leo', 'task' => { 'title' => 'Task 1' } },
348
- { 'name' => 'Joe', 'task' => { 'title' => 'Task 2' } }
349
- ])
350
- end
351
- end
352
-
353
- context 'partially' do
354
- context 'without renaming the rest of the wrap' do
355
- let(:attributes) do
356
- [
357
- ['user', type: :hash, unwrap: true, header: [['task']]]
358
- ]
359
- end
360
-
361
- it 'returns unwrapped tuples' do
362
- expect(transproc[relation]).to eql([
363
- { 'user' => { 'name' => 'Leo' }, 'task' => { 'title' => 'Task 1' } },
364
- { 'user' => { 'name' => 'Joe' }, 'task' => { 'title' => 'Task 2' } }
365
- ])
366
- end
367
- end
368
-
369
- context 'with renaming the rest of the wrap' do
370
- let(:attributes) do
371
- [
372
- ['man', from: 'user', type: :hash, unwrap: true, header: [['task']]]
373
- ]
374
- end
375
-
376
- it 'returns unwrapped tuples' do
377
- expect(transproc[relation]).to eql([
378
- { 'man' => { 'name' => 'Leo' }, 'task' => { 'title' => 'Task 1' } },
379
- { 'man' => { 'name' => 'Joe' }, 'task' => { 'title' => 'Task 2' } }
380
- ])
381
- end
382
- end
383
- end
384
-
385
- context 'deeply' do
386
- let(:attributes) do
387
- [
388
- ['user', type: :hash, unwrap: true, header: [
389
- ['name'],
390
- ['title'],
391
- ['task', type: :hash, unwrap: true, header: [['title']]]
392
- ]]
393
- ]
394
- end
395
-
396
- it 'returns unwrapped tuples' do
397
- expect(transproc[relation]).to eql([
398
- { 'name' => 'Leo', 'title' => 'Task 1' },
399
- { 'name' => 'Joe', 'title' => 'Task 2' }
400
- ])
401
- end
402
- end
403
- end
404
-
405
- context 'grouping tuples' do
406
- let(:relation) do
407
- [
408
- { 'name' => 'Jane', 'title' => 'Task One' },
409
- { 'name' => 'Jane', 'title' => 'Task Two' },
410
- { 'name' => 'Joe', 'title' => 'Task One' },
411
- { 'name' => 'Joe', 'title' => nil }
412
- ]
413
- end
414
-
415
- context 'when no mapping is needed' do
416
- let(:attributes) do
417
- [
418
- ['name'],
419
- ['tasks', type: :array, group: true, header: [['title']]]
420
- ]
421
- end
422
-
423
- it 'returns wrapped tuples with all keys renamed' do
424
- expect(transproc[relation]).to eql([
425
- { 'name' => 'Jane',
426
- 'tasks' => [{ 'title' => 'Task One' }, { 'title' => 'Task Two' }] },
427
- { 'name' => 'Joe',
428
- 'tasks' => [{ 'title' => 'Task One' }] }
429
- ])
430
- end
431
- end
432
-
433
- context 'renaming keys' do
434
- context 'when only grouped tuple requires renaming' do
435
- let(:attributes) do
436
- [
437
- ['name'],
438
- ['tasks', type: :array, group: true, header: [[:title, from: 'title']]]
439
- ]
440
- end
441
-
442
- it 'returns grouped tuples with renamed keys' do
443
- expect(transproc[relation]).to eql([
444
- { 'name' => 'Jane',
445
- 'tasks' => [{ title: 'Task One' }, { title: 'Task Two' }] },
446
- { 'name' => 'Joe',
447
- 'tasks' => [{ title: 'Task One' }] }
448
- ])
449
- end
450
- end
451
-
452
- context 'when all attributes require renaming' do
453
- let(:attributes) do
454
- [
455
- [:name, from: 'name'],
456
- [:tasks, type: :array, group: true, header: [[:title, from: 'title']]]
457
- ]
458
- end
459
-
460
- it 'returns grouped tuples with all keys renamed' do
461
- expect(transproc[relation]).to eql([
462
- { name: 'Jane',
463
- tasks: [{ title: 'Task One' }, { title: 'Task Two' }] },
464
- { name: 'Joe',
465
- tasks: [{ title: 'Task One' }] }
466
- ])
467
- end
468
- end
469
- end
470
-
471
- context 'nested grouping' do
472
- let(:relation) do
473
- [
474
- { name: 'Jane', title: 'Task One', tag: 'red' },
475
- { name: 'Jane', title: 'Task One', tag: 'green' },
476
- { name: 'Joe', title: 'Task One', tag: 'blue' }
477
- ]
478
- end
479
-
480
- let(:attributes) do
481
- [
482
- [:name],
483
- [:tasks, type: :array, group: true, header: [
484
- [:title],
485
- [:tags, type: :array, group: true, header: [[:tag]]]
486
- ]]
487
- ]
488
- end
489
-
490
- it 'returns deeply grouped tuples' do
491
- expect(transproc[relation]).to eql([
492
- { name: 'Jane',
493
- tasks: [
494
- { title: 'Task One', tags: [{ tag: 'red' }, { tag: 'green' }] }
495
- ]
496
- },
497
- { name: 'Joe',
498
- tasks: [
499
- { title: 'Task One', tags: [{ tag: 'blue' }] }
500
- ]
501
- }
502
- ])
503
- end
504
- end
505
- end
506
- end