rom-mapper 0.5.1 → 1.0.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.
@@ -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