rom-mapper 0.5.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,479 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe ROM::Mapper do
4
- subject(:mapper) do
5
- klass = Class.new(parent)
6
- options.each do |k, v|
7
- klass.send(k, v)
8
- end
9
- klass
10
- end
11
-
12
- let(:parent) { Class.new(ROM::Mapper) }
13
-
14
- let(:options) { {} }
15
- let(:header) { mapper.header }
16
-
17
- let(:expected_header) { ROM::Header.coerce(attributes) }
18
-
19
- describe '#attribute' do
20
- context 'simple attribute' do
21
- let(:attributes) { [[:name]] }
22
-
23
- it 'adds an attribute for the header' do
24
- mapper.attribute :name
25
-
26
- expect(header).to eql(expected_header)
27
- end
28
- end
29
-
30
- context 'aliased attribute' do
31
- let(:attributes) { [[:name, from: :user_name]] }
32
-
33
- it 'adds an aliased attribute for the header' do
34
- mapper.attribute :name, from: :user_name
35
-
36
- expect(header).to eql(expected_header)
37
- end
38
- end
39
-
40
- context 'prefixed attribute' do
41
- let(:attributes) { [[:name, from: :user_name]] }
42
- let(:options) { { prefix: :user } }
43
-
44
- it 'adds an aliased attribute for the header using configured :prefix' do
45
- mapper.attribute :name
46
-
47
- expect(header).to eql(expected_header)
48
- end
49
- end
50
-
51
- context 'prefixed attribute using custom separator' do
52
- let(:attributes) { [[:name, from: :'u.name']] }
53
- let(:options) { { prefix: :u, prefix_separator: '.' } }
54
-
55
- it 'adds an aliased attribute for the header using configured :prefix' do
56
- mapper.attribute :name
57
-
58
- expect(header).to eql(expected_header)
59
- end
60
- end
61
-
62
- context 'symbolized attribute' do
63
- let(:attributes) { [[:name, from: 'name']] }
64
- let(:options) { { symbolize_keys: true } }
65
-
66
- it 'adds an attribute with symbolized alias' do
67
- mapper.attribute :name
68
-
69
- expect(header).to eql(expected_header)
70
- end
71
- end
72
- end
73
-
74
- describe 'copy_keys' do
75
- let(:attributes) { [[:name, type: :string]] }
76
- let(:options) { { copy_keys: true } }
77
-
78
- it 'sets copy_keys for the header' do
79
- mapper.copy_keys true
80
- mapper.attribute :name, type: :string
81
-
82
- expect(header).to eql(expected_header)
83
- end
84
- end
85
-
86
- describe 'reject_keys' do
87
- let(:attributes) { [[:name, type: :string]] }
88
- let(:options) { { reject_keys: true } }
89
-
90
- it 'sets reject_keys for the header' do
91
- mapper.reject_keys true
92
- mapper.attribute :name, type: :string
93
-
94
- expect(header).to eql(expected_header)
95
- end
96
- end
97
-
98
- describe 'overriding inherited attributes' do
99
- context 'when name matches' do
100
- let(:attributes) { [[:name, type: :string]] }
101
-
102
- it 'excludes the inherited attribute' do
103
- parent.attribute :name
104
-
105
- mapper.attribute :name, type: :string
106
-
107
- expect(header).to eql(expected_header)
108
- end
109
- end
110
-
111
- context 'when alias matches' do
112
- let(:attributes) { [[:name, from: 'name', type: :string]] }
113
-
114
- it 'excludes the inherited attribute' do
115
- parent.attribute 'name'
116
-
117
- mapper.attribute :name, from: 'name', type: :string
118
-
119
- expect(header).to eql(expected_header)
120
- end
121
- end
122
-
123
- context 'when name in a wrapped attribute matches' do
124
- let(:attributes) do
125
- [
126
- [:city, type: :hash, wrap: true, header: [[:name, from: :city_name]]]
127
- ]
128
- end
129
-
130
- it 'excludes the inherited attribute' do
131
- parent.attribute :city_name
132
-
133
- mapper.wrap :city do
134
- attribute :name, from: :city_name
135
- end
136
-
137
- expect(header).to eql(expected_header)
138
- end
139
- end
140
-
141
- context 'when name in a grouped attribute matches' do
142
- let(:attributes) do
143
- [
144
- [:tags, type: :array, group: true, header: [[:name, from: :tag_name]]]
145
- ]
146
- end
147
-
148
- it 'excludes the inherited attribute' do
149
- parent.attribute :tag_name
150
-
151
- mapper.group :tags do
152
- attribute :name, from: :tag_name
153
- end
154
-
155
- expect(header).to eql(expected_header)
156
- end
157
- end
158
-
159
- context 'when name in a hash attribute matches' do
160
- let(:attributes) do
161
- [
162
- [:city, type: :hash, header: [[:name, from: :city_name]]]
163
- ]
164
- end
165
-
166
- it 'excludes the inherited attribute' do
167
- parent.attribute :city
168
-
169
- mapper.embedded :city, type: :hash do
170
- attribute :name, from: :city_name
171
- end
172
-
173
- expect(header).to eql(expected_header)
174
- end
175
- end
176
-
177
- context 'when name of an array attribute matches' do
178
- let(:attributes) do
179
- [
180
- [:tags, type: :array, header: [[:name, from: :tag_name]]]
181
- ]
182
- end
183
-
184
- it 'excludes the inherited attribute' do
185
- parent.attribute :tags
186
-
187
- mapper.embedded :tags, type: :array do
188
- attribute :name, from: :tag_name
189
- end
190
-
191
- expect(header).to eql(expected_header)
192
- end
193
- end
194
- end
195
-
196
- describe '#exclude' do
197
- let(:attributes) { [[:name, from: 'name']] }
198
-
199
- it 'removes an attribute from the inherited header' do
200
- mapper.attribute :name, from: 'name'
201
- expect(header).to eql(expected_header)
202
- end
203
- end
204
-
205
- describe '#embedded' do
206
- context 'when :type is set to :hash' do
207
- let(:attributes) { [[:city, type: :hash, header: [[:name]]]] }
208
-
209
- it 'adds an embedded hash attribute' do
210
- mapper.embedded :city, type: :hash do
211
- attribute :name
212
- end
213
-
214
- expect(header).to eql(expected_header)
215
- end
216
- end
217
-
218
- context 'when :type is set to :array' do
219
- let(:attributes) { [[:tags, type: :array, header: [[:name]]]] }
220
-
221
- it 'adds an embedded array attribute' do
222
- mapper.embedded :tags, type: :array do
223
- attribute :name
224
- end
225
-
226
- expect(header).to eql(expected_header)
227
- end
228
- end
229
- end
230
-
231
- describe '#wrap' do
232
- let(:attributes) { [[:city, type: :hash, wrap: true, header: [[:name]]]] }
233
-
234
- it 'adds an wrapped hash attribute using a block to define attributes' do
235
- mapper.wrap :city do
236
- attribute :name
237
- end
238
-
239
- expect(header).to eql(expected_header)
240
- end
241
-
242
- it 'adds an wrapped hash attribute using a options define attributes' do
243
- mapper.wrap city: [:name]
244
-
245
- expect(header).to eql(expected_header)
246
- end
247
-
248
- it 'raises an exception when using a block and options to define attributes' do
249
- expect {
250
- mapper.wrap(city: [:name]) { attribute :other_name }
251
- }.to raise_error(ROM::MapperMisconfiguredError)
252
- end
253
-
254
- it 'raises an exception when using options and a mapper to define attributes' do
255
- task_mapper = Class.new(ROM::Mapper) { attribute :title }
256
- expect {
257
- mapper.wrap city: [:name], mapper: task_mapper
258
- }.to raise_error(ROM::MapperMisconfiguredError)
259
- end
260
- end
261
-
262
- describe '#group' do
263
- let(:attributes) { [[:tags, type: :array, group: true, header: [[:name]]]] }
264
-
265
- it 'adds a group attribute using a block to define attributes' do
266
- mapper.group :tags do
267
- attribute :name
268
- end
269
-
270
- expect(header).to eql(expected_header)
271
- end
272
-
273
- it 'adds a group attribute using a options define attributes' do
274
- mapper.group tags: [:name]
275
-
276
- expect(header).to eql(expected_header)
277
- end
278
-
279
- it 'raises an exception when using a block and options to define attributes' do
280
- expect {
281
- mapper.group(cities: [:name]) { attribute :other_name }
282
- }.to raise_error(ROM::MapperMisconfiguredError)
283
- end
284
-
285
- it 'raises an exception when using options and a mapper to define attributes' do
286
- task_mapper = Class.new(ROM::Mapper) { attribute :title }
287
- expect {
288
- mapper.group cities: [:name], mapper: task_mapper
289
- }.to raise_error(ROM::MapperMisconfiguredError)
290
- end
291
- end
292
-
293
- describe 'top-level :prefix option' do
294
- let(:options) do
295
- { prefix: :user }
296
- end
297
-
298
- context 'when no attribute overrides top-level setting' do
299
- let(:attributes) do
300
- [
301
- [:name, from: :user_name],
302
- [:address, from: :user_address, type: :hash, header: [
303
- [:city, from: :user_city]]
304
- ],
305
- [:contact, type: :hash, wrap: true, header: [
306
- [:mobile, from: :user_mobile]]
307
- ],
308
- [:tasks, type: :array, group: true, header: [
309
- [:title, from: :user_title]]
310
- ]
311
- ]
312
- end
313
-
314
- it 'sets aliased attributes using prefix automatically' do
315
- mapper.attribute :name
316
-
317
- mapper.embedded :address, type: :hash do
318
- attribute :city
319
- end
320
-
321
- mapper.wrap :contact do
322
- attribute :mobile
323
- end
324
-
325
- mapper.group :tasks do
326
- attribute :title
327
- end
328
-
329
- expect(header).to eql(expected_header)
330
- end
331
- end
332
-
333
- context 'when an attribute overrides top-level setting' do
334
- let(:attributes) do
335
- [
336
- [:name, from: :user_name],
337
- [:birthday, from: :user_birthday, type: :hash, header: [
338
- [:year, from: :bd_year],
339
- [:month, from: :bd_month],
340
- [:day, from: :bd_day]]
341
- ],
342
- [:address, from: :user_address, type: :hash, header: [[:city]]],
343
- [:contact, type: :hash, wrap: true, header: [
344
- [:mobile, from: :contact_mobile]]
345
- ],
346
- [:tasks, type: :array, group: true, header: [
347
- [:title, from: :task_title]]
348
- ]
349
- ]
350
- end
351
-
352
- it 'excludes from aliasing the ones which override it' do
353
- mapper.attribute :name
354
-
355
- mapper.embedded :birthday, type: :hash, prefix: :bd do
356
- attribute :year
357
- attribute :month
358
- attribute :day
359
- end
360
-
361
- mapper.embedded :address, type: :hash, prefix: false do
362
- attribute :city
363
- end
364
-
365
- mapper.wrap :contact, prefix: :contact do
366
- attribute :mobile
367
- end
368
-
369
- mapper.group :tasks, prefix: :task do
370
- attribute :title
371
- end
372
-
373
- expect(header).to eql(expected_header)
374
- end
375
- end
376
- end
377
-
378
- context 'reusing mappers' do
379
- describe '#group' do
380
- let(:task_mapper) do
381
- Class.new(ROM::Mapper) { attribute :title }
382
- end
383
-
384
- let(:attributes) do
385
- [
386
- [:name],
387
- [:tasks, type: :array, group: true, header: task_mapper.header]
388
- ]
389
- end
390
-
391
- it 'uses other mapper header' do
392
- mapper.attribute :name
393
- mapper.group :tasks, mapper: task_mapper
394
-
395
- expect(header).to eql(expected_header)
396
- end
397
- end
398
-
399
- describe '#wrap' do
400
- let(:task_mapper) do
401
- Class.new(ROM::Mapper) { attribute :title }
402
- end
403
-
404
- let(:attributes) do
405
- [
406
- [:name],
407
- [:task, type: :hash, wrap: true, header: task_mapper.header]
408
- ]
409
- end
410
-
411
- it 'uses other mapper header' do
412
- mapper.attribute :name
413
- mapper.wrap :task, mapper: task_mapper
414
-
415
- expect(header).to eql(expected_header)
416
- end
417
- end
418
-
419
- describe '#embedded' do
420
- let(:task_mapper) do
421
- Class.new(ROM::Mapper) { attribute :title }
422
- end
423
-
424
- let(:attributes) do
425
- [
426
- [:name],
427
- [:task, type: :hash, header: task_mapper.header]
428
- ]
429
- end
430
-
431
- it 'uses other mapper header' do
432
- mapper.attribute :name
433
- mapper.embedded :task, mapper: task_mapper, type: :hash
434
-
435
- expect(header).to eql(expected_header)
436
- end
437
- end
438
- end
439
-
440
- describe '#combine' do
441
- let(:attributes) do
442
- [
443
- [:title],
444
- [:tasks, combine: true, type: :array, header: [[:title]]]
445
- ]
446
- end
447
-
448
- it 'adds combine attributes' do
449
- mapper.attribute :title
450
-
451
- mapper.combine :tasks, on: { title: :title } do
452
- attribute :title
453
- end
454
-
455
- expect(header).to eql(expected_header)
456
- end
457
-
458
- it 'works without a block' do
459
- expected_header = ROM::Header.coerce(
460
- [
461
- [:title],
462
- [:tasks, combine: true, type: :array, header: []]
463
- ]
464
- )
465
-
466
- mapper.attribute :title
467
-
468
- mapper.combine :tasks, on: { title: :title }
469
-
470
- expect(header).to eql(expected_header)
471
- end
472
- end
473
-
474
- describe '#method_missing' do
475
- it 'responds to DSL methods' do
476
- expect(mapper).to respond_to(:attribute)
477
- end
478
- end
479
- end
@@ -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