praxis 2.0.pre.29 → 2.0.pre.30
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 +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +24 -0
- data/SELECTOR_NOTES.txt +0 -0
- data/lib/praxis/application.rb +4 -0
- data/lib/praxis/blueprint.rb +13 -1
- data/lib/praxis/blueprint_attribute_group.rb +29 -0
- data/lib/praxis/docs/open_api/schema_object.rb +8 -7
- data/lib/praxis/endpoint_definition.rb +1 -1
- data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +11 -11
- data/lib/praxis/extensions/attribute_filtering/filter_tree_node.rb +0 -1
- data/lib/praxis/extensions/attribute_filtering/filters_parser.rb +1 -1
- data/lib/praxis/extensions/pagination/active_record_pagination_handler.rb +54 -4
- data/lib/praxis/extensions/pagination/ordering_params.rb +38 -10
- data/lib/praxis/extensions/pagination/pagination_handler.rb +3 -3
- data/lib/praxis/extensions/pagination/sequel_pagination_handler.rb +1 -1
- data/lib/praxis/mapper/resource.rb +155 -14
- data/lib/praxis/mapper/selector_generator.rb +248 -46
- data/lib/praxis/media_type_identifier.rb +1 -1
- data/lib/praxis/multipart/part.rb +2 -2
- data/lib/praxis/plugins/mapper_plugin.rb +4 -3
- data/lib/praxis/renderer.rb +1 -1
- data/lib/praxis/routing_config.rb +1 -1
- data/lib/praxis/tasks/console.rb +21 -26
- data/lib/praxis/types/multipart_array.rb +1 -1
- data/lib/praxis/version.rb +1 -1
- data/lib/praxis.rb +1 -0
- data/praxis.gemspec +1 -1
- data/spec/functional_library_spec.rb +187 -0
- data/spec/praxis/extensions/attribute_filtering/active_record_filter_query_builder_spec.rb +11 -1
- data/spec/praxis/extensions/attribute_filtering/filter_tree_node_spec.rb +16 -4
- data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +0 -2
- data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +0 -2
- data/spec/praxis/extensions/pagination/active_record_pagination_handler_spec.rb +111 -25
- data/spec/praxis/extensions/pagination/ordering_params_spec.rb +70 -0
- data/spec/praxis/mapper/resource_spec.rb +40 -4
- data/spec/praxis/mapper/selector_generator_spec.rb +979 -296
- data/spec/praxis/request_stages/action_spec.rb +1 -1
- data/spec/spec_app/app/controllers/authors.rb +37 -0
- data/spec/spec_app/app/controllers/books.rb +31 -0
- data/spec/spec_app/app/resources/author.rb +21 -0
- data/spec/spec_app/app/resources/base.rb +14 -0
- data/spec/spec_app/app/resources/book.rb +43 -0
- data/spec/spec_app/app/resources/tag.rb +9 -0
- data/spec/spec_app/app/resources/tagging.rb +9 -0
- data/spec/spec_app/config/environment.rb +16 -1
- data/spec/spec_app/design/media_types/author.rb +13 -0
- data/spec/spec_app/design/media_types/book.rb +22 -0
- data/spec/spec_app/design/media_types/tag.rb +11 -0
- data/spec/spec_app/design/media_types/tagging.rb +10 -0
- data/spec/spec_app/design/resources/authors.rb +35 -0
- data/spec/spec_app/design/resources/books.rb +39 -0
- data/spec/spec_helper.rb +0 -1
- data/spec/support/spec_resources.rb +20 -7
- data/spec/{praxis/extensions/support → support}/spec_resources_active_model.rb +14 -0
- metadata +24 -7
- /data/spec/{functional_spec.rb → functional_cloud_spec.rb} +0 -0
- /data/spec/{praxis/extensions/support → support}/spec_resources_sequel.rb +0 -0
@@ -9,134 +9,471 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
9
9
|
context '#add' do
|
10
10
|
let(:resource) { SimpleResource }
|
11
11
|
shared_examples 'a proper selector' do
|
12
|
-
it
|
12
|
+
it do
|
13
|
+
dumped = generator.add(resource, fields).selectors.dump
|
14
|
+
# puts JSON.pretty_generate(dumped)
|
15
|
+
expect(dumped).to be_deep_equal selectors
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
columns: %i[id foobar]
|
22
|
-
}
|
23
|
-
end
|
24
|
-
it_behaves_like 'a proper selector'
|
19
|
+
shared_examples 'a proper fields selector' do
|
20
|
+
it do
|
21
|
+
result = generator.add(resource, fields).selectors
|
22
|
+
dumped = result.dump(mode: :fields)
|
23
|
+
# puts JSON.pretty_generate(dumped)
|
24
|
+
expect(dumped).to be_deep_equal selectors
|
25
25
|
end
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
let(:
|
30
|
-
|
31
|
-
|
32
|
-
columns: %i[id simple_name]
|
33
|
-
}
|
28
|
+
context 'selecting columns and tracks' do
|
29
|
+
context '#add' do
|
30
|
+
let(:resource) { SimpleResource }
|
31
|
+
shared_examples 'a proper selector' do
|
32
|
+
it { expect(generator.add(resource, fields).selectors.dump).to be_deep_equal selectors }
|
34
33
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
model: SimpleModel,
|
43
|
-
columns: [:other_model_id], # FK of the other_model association
|
44
|
-
tracks: {
|
45
|
-
other_model: {
|
46
|
-
columns: [:id], # joining key for the association
|
47
|
-
model: OtherModel
|
34
|
+
context 'basic combos' do
|
35
|
+
context 'direct column fields' do
|
36
|
+
let(:fields) { { id: true, foobar: true } }
|
37
|
+
let(:selectors) do
|
38
|
+
{
|
39
|
+
model: SimpleModel,
|
40
|
+
columns: %i[id foobar]
|
48
41
|
}
|
49
|
-
|
50
|
-
|
42
|
+
end
|
43
|
+
it_behaves_like 'a proper selector'
|
44
|
+
end
|
45
|
+
context 'aliased column fields' do
|
46
|
+
let(:fields) { { id: true, name: true } }
|
47
|
+
let(:selectors) do
|
48
|
+
{
|
49
|
+
model: SimpleModel,
|
50
|
+
columns: %i[id simple_name]
|
51
|
+
}
|
52
|
+
end
|
53
|
+
it_behaves_like 'a proper selector'
|
54
|
+
end
|
55
|
+
context 'pure associations without recursion' do
|
56
|
+
let(:fields) { { other_model: true } }
|
57
|
+
let(:selectors) do
|
58
|
+
{
|
59
|
+
model: SimpleModel,
|
60
|
+
columns: [:other_model_id], # FK of the other_model association
|
61
|
+
tracks: {
|
62
|
+
other_model: {
|
63
|
+
columns: [:id], # joining key for the association
|
64
|
+
model: OtherModel
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
it_behaves_like 'a proper selector'
|
70
|
+
end
|
71
|
+
context 'aliased associations without recursion' do
|
72
|
+
let(:fields) { { other_resource: true } }
|
73
|
+
let(:selectors) do
|
74
|
+
{
|
75
|
+
model: SimpleModel,
|
76
|
+
columns: [:other_model_id], # FK of the other_model association
|
77
|
+
tracks: {
|
78
|
+
other_model: {
|
79
|
+
columns: [:id], # joining key for the association
|
80
|
+
model: OtherModel
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
end
|
85
|
+
it_behaves_like 'a proper selector'
|
86
|
+
end
|
87
|
+
context 'aliased associations without recursion (that map to columns and other associations)' do
|
88
|
+
let(:fields) { { aliased_method: true } }
|
89
|
+
let(:selectors) do
|
90
|
+
{
|
91
|
+
model: SimpleModel,
|
92
|
+
columns: %i[column1 other_model_id], # other_model_id => because of the association
|
93
|
+
tracks: {
|
94
|
+
other_model: {
|
95
|
+
columns: [:id], # joining key for the association
|
96
|
+
model: OtherModel
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
it_behaves_like 'a proper selector'
|
102
|
+
end
|
103
|
+
context 'redefined associations that add some extra columns (would need both the underlying association AND the columns in place)' do
|
104
|
+
let(:fields) { { parent: true } }
|
105
|
+
let(:selectors) do
|
106
|
+
{
|
107
|
+
model: SimpleModel,
|
108
|
+
columns: %i[parent_id added_column],
|
109
|
+
tracks: {
|
110
|
+
parent: {
|
111
|
+
columns: [:id],
|
112
|
+
model: ParentModel
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
end
|
117
|
+
it_behaves_like 'a proper selector'
|
118
|
+
end
|
119
|
+
context 'a simple property that requires all fields' do
|
120
|
+
let(:fields) { { everything: true } }
|
121
|
+
let(:selectors) do
|
122
|
+
{
|
123
|
+
model: SimpleModel,
|
124
|
+
columns: [:*]
|
125
|
+
}
|
126
|
+
end
|
127
|
+
it_behaves_like 'a proper selector'
|
128
|
+
end
|
129
|
+
context 'a simple property that requires itself' do
|
130
|
+
let(:fields) { { circular_dep: true } }
|
131
|
+
let(:selectors) do
|
132
|
+
{
|
133
|
+
model: SimpleModel,
|
134
|
+
columns: %i[circular_dep column1] # allows to "expand" the dependency into itself + others
|
135
|
+
}
|
136
|
+
end
|
137
|
+
it_behaves_like 'a proper selector'
|
138
|
+
end
|
139
|
+
context 'a simple property without dependencies' do
|
140
|
+
let(:fields) { { no_deps: true } }
|
141
|
+
let(:selectors) do
|
142
|
+
{
|
143
|
+
model: SimpleModel
|
144
|
+
}
|
145
|
+
end
|
146
|
+
it_behaves_like 'a proper selector'
|
147
|
+
end
|
51
148
|
end
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
model: SimpleModel,
|
60
|
-
columns: [:other_model_id], # FK of the other_model association
|
61
|
-
tracks: {
|
62
|
-
other_model: {
|
63
|
-
columns: [:id], # joining key for the association
|
64
|
-
model: OtherModel
|
149
|
+
context 'nested tracking' do
|
150
|
+
context 'pure associations follow the nested fields' do
|
151
|
+
let(:fields) do
|
152
|
+
{
|
153
|
+
other_model: {
|
154
|
+
id: true
|
155
|
+
}
|
65
156
|
}
|
66
|
-
|
67
|
-
|
157
|
+
end
|
158
|
+
let(:selectors) do
|
159
|
+
{
|
160
|
+
model: SimpleModel,
|
161
|
+
columns: [:other_model_id],
|
162
|
+
tracks: {
|
163
|
+
other_model: {
|
164
|
+
model: OtherModel,
|
165
|
+
columns: [:id]
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
end
|
170
|
+
it_behaves_like 'a proper selector'
|
171
|
+
end
|
172
|
+
context 'Aliased resources disregard any nested fields...' do
|
173
|
+
let(:fields) do
|
174
|
+
{
|
175
|
+
other_resource: {
|
176
|
+
id: true
|
177
|
+
}
|
178
|
+
}
|
179
|
+
end
|
180
|
+
let(:selectors) do
|
181
|
+
{
|
182
|
+
model: SimpleModel,
|
183
|
+
columns: [:other_model_id],
|
184
|
+
tracks: {
|
185
|
+
other_model: {
|
186
|
+
model: OtherModel,
|
187
|
+
columns: [:id]
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
it_behaves_like 'a proper selector'
|
193
|
+
end
|
194
|
+
context 'merging multiple tracks with the same name within a node' do
|
195
|
+
let(:fields) do
|
196
|
+
{ # Both everything_from_parent and parent will track the underlying 'parent' assoc
|
197
|
+
# ...and the final respective fields and tracks will need to be merged together.
|
198
|
+
# columns will be merged by just *, and tracks will merge true with simple children
|
199
|
+
everything_from_parent: true,
|
200
|
+
parent: {
|
201
|
+
simple_children: true
|
202
|
+
}
|
203
|
+
}
|
204
|
+
end
|
205
|
+
let(:selectors) do
|
206
|
+
{
|
207
|
+
model: SimpleModel,
|
208
|
+
columns: %i[parent_id added_column],
|
209
|
+
tracks: {
|
210
|
+
parent: {
|
211
|
+
model: ParentModel,
|
212
|
+
columns: [:*],
|
213
|
+
tracks: {
|
214
|
+
simple_children: {
|
215
|
+
model: SimpleModel,
|
216
|
+
columns: [:parent_id]
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
end
|
223
|
+
it_behaves_like 'a proper selector'
|
224
|
+
end
|
225
|
+
context 'Aliased underlying associations follows any nested fields...' do
|
226
|
+
let(:fields) do
|
227
|
+
{
|
228
|
+
parent_id: true,
|
229
|
+
aliased_association: {
|
230
|
+
display_name: true
|
231
|
+
}
|
232
|
+
}
|
233
|
+
end
|
234
|
+
let(:selectors) do
|
235
|
+
{
|
236
|
+
model: SimpleModel,
|
237
|
+
columns: %i[other_model_id parent_id],
|
238
|
+
tracks: {
|
239
|
+
other_model: {
|
240
|
+
model: OtherModel,
|
241
|
+
columns: %i[id name]
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
end
|
246
|
+
it_behaves_like 'a proper selector'
|
247
|
+
end
|
248
|
+
context 'Deep aliased underlying associations also follows any nested fields at the end of the chain...' do
|
249
|
+
let(:fields) do
|
250
|
+
{
|
251
|
+
parent_id: true,
|
252
|
+
deep_aliased_association: {
|
253
|
+
name: true
|
254
|
+
}
|
255
|
+
}
|
256
|
+
end
|
257
|
+
# TODO: Legitimate failure!! there is a name in the parent column track...which shouldn't be there
|
258
|
+
let(:selectors) do
|
259
|
+
{
|
260
|
+
model: SimpleModel,
|
261
|
+
columns: %i[parent_id],
|
262
|
+
tracks: {
|
263
|
+
parent: {
|
264
|
+
model: ParentModel,
|
265
|
+
columns: %i[id],
|
266
|
+
tracks: {
|
267
|
+
simple_children: {
|
268
|
+
model: SimpleModel,
|
269
|
+
columns: %i[parent_id simple_name]
|
270
|
+
}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
end
|
276
|
+
it_behaves_like 'a proper selector'
|
277
|
+
end
|
278
|
+
context 'Using self for the underlying association: follows any nested fields skipping the association name and still applies dependencies' do
|
279
|
+
let(:fields) do
|
280
|
+
{
|
281
|
+
parent_id: true,
|
282
|
+
sub_struct: {
|
283
|
+
display_name: true
|
284
|
+
}
|
285
|
+
}
|
286
|
+
end
|
287
|
+
let(:selectors) do
|
288
|
+
{
|
289
|
+
model: SimpleModel,
|
290
|
+
# Parent_id is because we asked for it at the top
|
291
|
+
# display_name because we asked for it under sub_struct, but it is marked as :self
|
292
|
+
# alway_necessary_attribute because it is a dependency of sub_struct
|
293
|
+
columns: %i[parent_id display_name]
|
294
|
+
}
|
295
|
+
end
|
296
|
+
it_behaves_like 'a proper selector'
|
297
|
+
end
|
68
298
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
299
|
+
context 'string associations' do
|
300
|
+
context 'that specify a direct existing colum in the target dependency' do
|
301
|
+
let(:fields) { { direct_other_name: true } }
|
302
|
+
let(:selectors) do
|
303
|
+
{
|
304
|
+
model: SimpleModel,
|
305
|
+
columns: [:other_model_id],
|
306
|
+
tracks: {
|
307
|
+
other_model: {
|
308
|
+
model: OtherModel,
|
309
|
+
columns: %i[id name]
|
310
|
+
}
|
311
|
+
}
|
81
312
|
}
|
82
|
-
|
83
|
-
|
313
|
+
end
|
314
|
+
it_behaves_like 'a proper selector'
|
315
|
+
end
|
316
|
+
context 'that specify an aliased property in the target dependency' do
|
317
|
+
let(:fields) { { aliased_other_name: true } }
|
318
|
+
let(:selectors) do
|
319
|
+
{
|
320
|
+
model: SimpleModel,
|
321
|
+
columns: [:other_model_id],
|
322
|
+
tracks: {
|
323
|
+
other_model: {
|
324
|
+
model: OtherModel,
|
325
|
+
columns: %i[id name]
|
326
|
+
}
|
327
|
+
}
|
328
|
+
}
|
329
|
+
end
|
330
|
+
it_behaves_like 'a proper selector'
|
331
|
+
end
|
332
|
+
|
333
|
+
context 'for a property that requires all fields from an association' do
|
334
|
+
let(:fields) { { everything_from_parent: true } }
|
335
|
+
let(:selectors) do
|
336
|
+
{
|
337
|
+
model: SimpleModel,
|
338
|
+
columns: [:parent_id],
|
339
|
+
tracks: {
|
340
|
+
parent: {
|
341
|
+
model: ParentModel,
|
342
|
+
columns: [:*]
|
343
|
+
}
|
344
|
+
}
|
345
|
+
}
|
346
|
+
end
|
347
|
+
it_behaves_like 'a proper selector'
|
348
|
+
end
|
84
349
|
end
|
85
|
-
it_behaves_like 'a proper selector'
|
86
|
-
end
|
87
350
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
351
|
+
context 'required extra select fields due to associations' do
|
352
|
+
context 'many_to_one' do
|
353
|
+
let(:fields) { { other_model: true } }
|
354
|
+
let(:selectors) do
|
355
|
+
{
|
356
|
+
model: SimpleModel,
|
357
|
+
columns: [:other_model_id], # FK of the other_model association
|
358
|
+
tracks: {
|
359
|
+
other_model: {
|
360
|
+
columns: [:id],
|
361
|
+
model: OtherModel
|
362
|
+
}
|
363
|
+
}
|
98
364
|
}
|
99
|
-
|
100
|
-
|
365
|
+
end
|
366
|
+
it_behaves_like 'a proper selector'
|
367
|
+
end
|
368
|
+
context 'one_to_many' do
|
369
|
+
let(:resource) { ParentResource }
|
370
|
+
let(:fields) { { simple_children: true } }
|
371
|
+
let(:selectors) do
|
372
|
+
{
|
373
|
+
model: ParentModel,
|
374
|
+
columns: [:id], # No FKs in the source model for one_to_many
|
375
|
+
tracks: {
|
376
|
+
simple_children: {
|
377
|
+
columns: [:parent_id],
|
378
|
+
model: SimpleModel
|
379
|
+
}
|
380
|
+
}
|
381
|
+
}
|
382
|
+
end
|
383
|
+
it_behaves_like 'a proper selector'
|
384
|
+
end
|
385
|
+
context 'many_to_many' do
|
386
|
+
let(:resource) { OtherResource }
|
387
|
+
let(:fields) { { simple_models: true } }
|
388
|
+
let(:selectors) do
|
389
|
+
{
|
390
|
+
model: OtherModel,
|
391
|
+
columns: [:id], # join key in the source model for many_to_many (where the middle table points to)
|
392
|
+
tracks: {
|
393
|
+
simple_models: {
|
394
|
+
columns: [:id], # join key in the target model for many_to_many (where the middle table points to)
|
395
|
+
model: SimpleModel
|
396
|
+
}
|
397
|
+
}
|
398
|
+
}
|
399
|
+
end
|
400
|
+
it_behaves_like 'a proper selector'
|
401
|
+
end
|
402
|
+
|
403
|
+
context 'that are several attriutes deep' do
|
404
|
+
let(:fields) { { deep_nested_deps: true } }
|
405
|
+
let(:selectors) do
|
406
|
+
{
|
407
|
+
model: SimpleModel,
|
408
|
+
columns: [:parent_id],
|
409
|
+
tracks: {
|
410
|
+
parent: {
|
411
|
+
model: ParentModel,
|
412
|
+
columns: [:id], # No FKs in the source model for one_to_many
|
413
|
+
tracks: {
|
414
|
+
simple_children: {
|
415
|
+
columns: %i[parent_id other_model_id],
|
416
|
+
model: SimpleModel,
|
417
|
+
tracks: {
|
418
|
+
other_model: {
|
419
|
+
model: OtherModel,
|
420
|
+
columns: %i[id parent_id],
|
421
|
+
tracks: {
|
422
|
+
parent: {
|
423
|
+
model: ParentModel,
|
424
|
+
columns: %i[id simple_name other_attribute]
|
425
|
+
}
|
426
|
+
}
|
427
|
+
}
|
428
|
+
}
|
429
|
+
}
|
430
|
+
}
|
431
|
+
}
|
432
|
+
}
|
433
|
+
}
|
434
|
+
end
|
435
|
+
it_behaves_like 'a proper selector'
|
436
|
+
end
|
101
437
|
end
|
102
|
-
it_behaves_like 'a proper selector'
|
103
438
|
end
|
439
|
+
end
|
104
440
|
|
105
|
-
|
106
|
-
|
107
|
-
let(:
|
441
|
+
context 'selecting fields and subfields' do
|
442
|
+
context 'with nil dependencies' do
|
443
|
+
let(:fields) do
|
108
444
|
{
|
109
|
-
|
110
|
-
columns: [:*]
|
445
|
+
nil_deps: true
|
111
446
|
}
|
112
447
|
end
|
113
|
-
it_behaves_like 'a proper selector'
|
114
|
-
end
|
115
|
-
|
116
|
-
context 'a simple property that requires itself' do
|
117
|
-
let(:fields) { { circular_dep: true } }
|
118
448
|
let(:selectors) do
|
119
449
|
{
|
120
450
|
model: SimpleModel,
|
121
|
-
|
451
|
+
fields: {
|
452
|
+
nil_deps: {
|
453
|
+
deps: %i[nil_deps]
|
454
|
+
}
|
455
|
+
}
|
122
456
|
}
|
123
457
|
end
|
124
|
-
it_behaves_like 'a proper selector'
|
458
|
+
it_behaves_like 'a proper fields selector'
|
125
459
|
end
|
126
|
-
|
127
|
-
context 'a simple property without dependencies' do
|
460
|
+
context 'with empty array dependencies' do
|
128
461
|
let(:fields) { { no_deps: true } }
|
129
462
|
let(:selectors) do
|
130
463
|
{
|
131
|
-
model: SimpleModel
|
464
|
+
model: SimpleModel,
|
465
|
+
fields: {
|
466
|
+
no_deps: {
|
467
|
+
deps: %i[no_deps]
|
468
|
+
}
|
469
|
+
}
|
132
470
|
}
|
133
471
|
end
|
134
|
-
it_behaves_like 'a proper selector'
|
472
|
+
it_behaves_like 'a proper fields selector'
|
135
473
|
end
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
context 'pure associations follow the nested fields' do
|
474
|
+
context 'following nested fields from pure implicit association properties (not defined and no deps)' do
|
475
|
+
# For implicit properties that aren't defined, but that have a name that matches an association
|
476
|
+
# we want to make it work like an as: association, therefore subfield following will work.
|
140
477
|
let(:fields) do
|
141
478
|
{
|
142
479
|
other_model: {
|
@@ -147,276 +484,622 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
147
484
|
let(:selectors) do
|
148
485
|
{
|
149
486
|
model: SimpleModel,
|
150
|
-
|
487
|
+
fields: {
|
488
|
+
other_model: {
|
489
|
+
references: 'Linked to resource: OtherResource'
|
490
|
+
}
|
491
|
+
},
|
151
492
|
tracks: {
|
152
493
|
other_model: {
|
153
494
|
model: OtherModel,
|
154
|
-
|
495
|
+
fields: {
|
496
|
+
id: {
|
497
|
+
deps: %i[id]
|
498
|
+
}
|
499
|
+
}
|
155
500
|
}
|
156
501
|
}
|
157
502
|
}
|
158
503
|
end
|
159
|
-
it_behaves_like 'a proper selector'
|
504
|
+
it_behaves_like 'a proper fields selector'
|
160
505
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
id: true
|
506
|
+
context 'implicit (not defined) properties that are direct associations can follow fields' do
|
507
|
+
context 'using a direct association name' do
|
508
|
+
let(:fields) do
|
509
|
+
{
|
510
|
+
other_model: true
|
167
511
|
}
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
512
|
+
end
|
513
|
+
let(:selectors) do
|
514
|
+
{
|
515
|
+
model: SimpleModel,
|
516
|
+
fields: {
|
517
|
+
other_model: {
|
518
|
+
references: 'Linked to resource: OtherResource' # because other_model is implicit, without deps
|
519
|
+
}
|
520
|
+
},
|
521
|
+
tracks: {
|
522
|
+
other_model: {
|
523
|
+
model: OtherModel,
|
524
|
+
fields: {
|
525
|
+
id: { deps: %i[id] }
|
526
|
+
}
|
527
|
+
}
|
178
528
|
}
|
179
529
|
}
|
180
|
-
|
530
|
+
end
|
531
|
+
it_behaves_like 'a proper fields selector'
|
181
532
|
end
|
182
|
-
it_behaves_like 'a proper selector'
|
183
533
|
end
|
534
|
+
context 'properties with dependencies' do
|
535
|
+
context 'simple direct column name' do
|
536
|
+
let(:fields) do
|
537
|
+
{
|
538
|
+
simple_name: true
|
539
|
+
}
|
540
|
+
end
|
541
|
+
let(:selectors) do
|
542
|
+
{
|
543
|
+
model: SimpleModel,
|
544
|
+
fields: {
|
545
|
+
simple_name: {
|
546
|
+
deps: %i[simple_name]
|
547
|
+
}
|
548
|
+
}
|
549
|
+
}
|
550
|
+
end
|
551
|
+
it_behaves_like 'a proper fields selector'
|
552
|
+
end
|
553
|
+
context 'needing to resolve dependencies recursively' do
|
554
|
+
let(:fields) do
|
555
|
+
{
|
556
|
+
name: true
|
557
|
+
}
|
558
|
+
end
|
559
|
+
let(:selectors) do
|
560
|
+
{
|
561
|
+
model: SimpleModel,
|
562
|
+
fields: {
|
563
|
+
name: {
|
564
|
+
deps: %i[name nested_name simple_name]
|
565
|
+
}
|
566
|
+
}
|
567
|
+
}
|
568
|
+
end
|
569
|
+
it_behaves_like 'a proper fields selector'
|
570
|
+
end
|
184
571
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
572
|
+
context 'a simple property that requires all fields' do
|
573
|
+
let(:fields) { { everything: true } }
|
574
|
+
let(:selectors) do
|
575
|
+
{
|
576
|
+
model: SimpleModel,
|
577
|
+
fields: {
|
578
|
+
everything: {
|
579
|
+
deps: %i[everything]
|
580
|
+
}
|
581
|
+
}
|
193
582
|
}
|
194
|
-
|
583
|
+
end
|
584
|
+
it_behaves_like 'a proper fields selector'
|
195
585
|
end
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
586
|
+
context 'self referential' do
|
587
|
+
let(:fields) do
|
588
|
+
{
|
589
|
+
circular_dep: true
|
590
|
+
}
|
591
|
+
end
|
592
|
+
let(:selectors) do
|
593
|
+
{
|
594
|
+
model: SimpleModel,
|
595
|
+
fields: {
|
596
|
+
circular_dep: {
|
597
|
+
deps: %i[circular_dep column1]
|
598
|
+
}
|
599
|
+
}
|
600
|
+
}
|
601
|
+
end
|
602
|
+
it_behaves_like 'a proper fields selector'
|
603
|
+
end
|
604
|
+
context 'combining dependencies with other properties and associacions (stops at the property)' do
|
605
|
+
# There won't be any references or anything as it is a property with dependencies...so we just
|
606
|
+
# unroll them, and discard any nested fields (in this case there aren't any though)
|
607
|
+
let(:fields) do
|
608
|
+
{
|
609
|
+
aliased_method: true
|
610
|
+
}
|
611
|
+
end
|
612
|
+
let(:selectors) do
|
613
|
+
{
|
614
|
+
model: SimpleModel,
|
615
|
+
fields: {
|
616
|
+
aliased_method: {
|
617
|
+
deps: %i[aliased_method other_model column1]
|
618
|
+
}
|
619
|
+
},
|
620
|
+
tracks: {
|
621
|
+
other_model: {
|
622
|
+
model: OtherModel,
|
623
|
+
fields: {
|
624
|
+
id: { deps: %i[id] }
|
208
625
|
}
|
209
626
|
}
|
210
627
|
}
|
211
628
|
}
|
212
|
-
|
629
|
+
end
|
630
|
+
it_behaves_like 'a proper fields selector'
|
213
631
|
end
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
display_name: true
|
632
|
+
context 'following nested fields from a property that has dependencies (does not work, same result as above)' do
|
633
|
+
# This means we will track up to the property name (nothing under that will be reflected in fields, even references)
|
634
|
+
let(:fields) do
|
635
|
+
{
|
636
|
+
aliased_method: {
|
637
|
+
display_name: true
|
638
|
+
}
|
222
639
|
}
|
223
|
-
|
640
|
+
end
|
641
|
+
let(:selectors) do
|
642
|
+
{
|
643
|
+
model: SimpleModel,
|
644
|
+
fields: {
|
645
|
+
aliased_method: {
|
646
|
+
deps: %i[aliased_method other_model column1]
|
647
|
+
}
|
648
|
+
},
|
649
|
+
tracks: {
|
650
|
+
other_model: {
|
651
|
+
model: OtherModel,
|
652
|
+
fields: {
|
653
|
+
id: {
|
654
|
+
deps: %i[id] # There is no further tracking of display name here...since it is not an as: property
|
655
|
+
}
|
656
|
+
}
|
657
|
+
}
|
658
|
+
}
|
659
|
+
}
|
660
|
+
end
|
661
|
+
it_behaves_like 'a proper fields selector'
|
224
662
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
663
|
+
context 'a true substructure object' do
|
664
|
+
# once we hit true_struct, we know it is not a property group, so we'll bring ALL the inner dependencies
|
665
|
+
# even if the fields required are only a subset of it
|
666
|
+
let(:fields) do
|
667
|
+
{
|
668
|
+
true_struct: true
|
669
|
+
}
|
670
|
+
end
|
671
|
+
let(:selectors) do
|
672
|
+
{
|
673
|
+
model: SimpleModel,
|
674
|
+
fields: {
|
675
|
+
true_struct: {
|
676
|
+
deps: %i[true_struct name nested_name simple_name sub_id inner_sub_id id]
|
677
|
+
}
|
233
678
|
}
|
234
679
|
}
|
235
|
-
|
680
|
+
end
|
681
|
+
it_behaves_like 'a proper fields selector'
|
682
|
+
end
|
683
|
+
context 'string associations' do
|
684
|
+
context 'that specify a direct existing colum in the target dependency' do
|
685
|
+
let(:fields) { { direct_other_name: true } }
|
686
|
+
let(:selectors) do
|
687
|
+
{
|
688
|
+
model: SimpleModel,
|
689
|
+
fields: {
|
690
|
+
direct_other_name: {
|
691
|
+
deps: %i[direct_other_name]
|
692
|
+
}
|
693
|
+
},
|
694
|
+
tracks: {
|
695
|
+
other_model: {
|
696
|
+
model: OtherModel,
|
697
|
+
fields: {
|
698
|
+
id: {
|
699
|
+
deps: %i[id]
|
700
|
+
},
|
701
|
+
name: {
|
702
|
+
deps: %i[name]
|
703
|
+
}
|
704
|
+
}
|
705
|
+
}
|
706
|
+
}
|
707
|
+
}
|
708
|
+
end
|
709
|
+
it_behaves_like 'a proper fields selector'
|
710
|
+
end
|
711
|
+
context 'that specify an aliased property in the target dependency' do
|
712
|
+
let(:fields) { { aliased_other_name: true } }
|
713
|
+
let(:selectors) do
|
714
|
+
{
|
715
|
+
model: SimpleModel,
|
716
|
+
fields: {
|
717
|
+
aliased_other_name: {
|
718
|
+
deps: %i[aliased_other_name]
|
719
|
+
}
|
720
|
+
},
|
721
|
+
tracks: {
|
722
|
+
other_model: {
|
723
|
+
model: OtherModel,
|
724
|
+
fields: {
|
725
|
+
id: {
|
726
|
+
deps: %i[id]
|
727
|
+
},
|
728
|
+
display_name: {
|
729
|
+
deps: %i[display_name name]
|
730
|
+
}
|
731
|
+
}
|
732
|
+
}
|
733
|
+
}
|
734
|
+
}
|
735
|
+
end
|
736
|
+
it_behaves_like 'a proper fields selector'
|
737
|
+
end
|
738
|
+
context 'for a property that requires all fields from an association' do
|
739
|
+
let(:fields) { { everything_from_parent: true } }
|
740
|
+
let(:selectors) do
|
741
|
+
{
|
742
|
+
model: SimpleModel,
|
743
|
+
fields: {
|
744
|
+
everything_from_parent: {
|
745
|
+
deps: %i[everything_from_parent]
|
746
|
+
}
|
747
|
+
},
|
748
|
+
tracks: {
|
749
|
+
parent: {
|
750
|
+
model: ParentModel
|
751
|
+
}
|
752
|
+
}
|
753
|
+
}
|
754
|
+
end
|
755
|
+
it_behaves_like 'a proper fields selector'
|
756
|
+
end
|
236
757
|
end
|
237
|
-
it_behaves_like 'a proper selector'
|
238
758
|
end
|
239
|
-
context '
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
name: true
|
759
|
+
context 'entire forwarding (i.e., association_name: true) associations (as: aliases)' do
|
760
|
+
context 'using a forwarding association name with 1 level deep' do
|
761
|
+
let(:fields) do
|
762
|
+
{
|
763
|
+
aliased_association: true
|
245
764
|
}
|
246
|
-
|
765
|
+
end
|
766
|
+
let(:selectors) do
|
767
|
+
{
|
768
|
+
model: SimpleModel,
|
769
|
+
fields: {
|
770
|
+
aliased_association: {
|
771
|
+
deps: [:aliased_association],
|
772
|
+
references: 'Linked to resource: OtherResource'
|
773
|
+
}
|
774
|
+
},
|
775
|
+
tracks: {
|
776
|
+
other_model: {
|
777
|
+
model: OtherModel,
|
778
|
+
fields: {
|
779
|
+
id: {
|
780
|
+
deps: %i[id]
|
781
|
+
}
|
782
|
+
}
|
783
|
+
}
|
784
|
+
}
|
785
|
+
}
|
786
|
+
end
|
787
|
+
it_behaves_like 'a proper fields selector'
|
247
788
|
end
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
789
|
+
|
790
|
+
context 'using a forwarding association name with 2 levels deep' do
|
791
|
+
let(:fields) do
|
792
|
+
{
|
793
|
+
deep_aliased_association: true
|
794
|
+
}
|
795
|
+
end
|
796
|
+
let(:selectors) do
|
797
|
+
{
|
798
|
+
model: SimpleModel,
|
799
|
+
fields: {
|
800
|
+
deep_aliased_association: {
|
801
|
+
deps: [:deep_aliased_association],
|
802
|
+
references: 'Linked to resource: SimpleResource'
|
803
|
+
}
|
804
|
+
},
|
805
|
+
tracks: {
|
806
|
+
parent: {
|
807
|
+
model: ParentModel,
|
808
|
+
fields: {
|
809
|
+
id: {
|
810
|
+
deps: %i[id]
|
811
|
+
}
|
812
|
+
},
|
813
|
+
tracks: {
|
814
|
+
simple_children: {
|
815
|
+
model: SimpleModel,
|
816
|
+
fields: {
|
817
|
+
parent_id: {
|
818
|
+
deps: %i[parent_id]
|
819
|
+
}
|
820
|
+
}
|
821
|
+
}
|
260
822
|
}
|
261
823
|
}
|
262
824
|
}
|
263
825
|
}
|
264
|
-
|
826
|
+
end
|
827
|
+
it_behaves_like 'a proper fields selector'
|
828
|
+
end
|
829
|
+
context 'using a self forwarding association ' do
|
830
|
+
let(:fields) do
|
831
|
+
{
|
832
|
+
sub_struct: true
|
833
|
+
}
|
834
|
+
end
|
835
|
+
let(:selectors) do
|
836
|
+
{
|
837
|
+
model: SimpleModel,
|
838
|
+
fields: {
|
839
|
+
sub_struct: {
|
840
|
+
deps: %i[sub_struct]
|
841
|
+
}
|
842
|
+
}
|
843
|
+
}
|
844
|
+
end
|
845
|
+
it_behaves_like 'a proper fields selector'
|
265
846
|
end
|
266
|
-
it_behaves_like 'a proper selector'
|
267
847
|
end
|
268
|
-
context '
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
848
|
+
context 'forwarding associations (as: aliases) but specifying sub-fields' do
|
849
|
+
context 'using a self forwarding association name with 2 levels deep' do
|
850
|
+
let(:fields) do
|
851
|
+
{
|
852
|
+
sub_struct: {
|
853
|
+
name: true
|
854
|
+
}
|
274
855
|
}
|
275
|
-
|
856
|
+
end
|
857
|
+
let(:selectors) do
|
858
|
+
{
|
859
|
+
model: SimpleModel,
|
860
|
+
fields: {
|
861
|
+
sub_struct: {
|
862
|
+
deps: %i[sub_struct],
|
863
|
+
fields: {
|
864
|
+
name: {
|
865
|
+
deps: %i[name nested_name simple_name]
|
866
|
+
}
|
867
|
+
}
|
868
|
+
}
|
869
|
+
}
|
870
|
+
}
|
871
|
+
end
|
872
|
+
it_behaves_like 'a proper fields selector'
|
276
873
|
end
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
874
|
+
context 'using a self forwarding association name with multiple levels which include deep forwarding associations' do
|
875
|
+
let(:fields) do
|
876
|
+
{
|
877
|
+
sub_struct: {
|
878
|
+
name: true,
|
879
|
+
deep_aliased_association: true
|
880
|
+
}
|
881
|
+
}
|
882
|
+
end
|
883
|
+
let(:selectors) do
|
884
|
+
{
|
885
|
+
model: SimpleModel,
|
886
|
+
fields: {
|
887
|
+
sub_struct: {
|
888
|
+
deps: %i[sub_struct],
|
889
|
+
fields: {
|
890
|
+
name: {
|
891
|
+
deps: %i[name nested_name simple_name]
|
892
|
+
},
|
893
|
+
deep_aliased_association: {
|
894
|
+
deps: %i[deep_aliased_association],
|
895
|
+
references: 'Linked to resource: SimpleResource'
|
896
|
+
}
|
897
|
+
}
|
898
|
+
}
|
899
|
+
},
|
900
|
+
tracks: {
|
901
|
+
parent: {
|
902
|
+
model: ParentModel,
|
903
|
+
fields: {
|
904
|
+
id: {
|
905
|
+
deps: %i[id]
|
906
|
+
}
|
907
|
+
},
|
908
|
+
tracks: {
|
909
|
+
simple_children: {
|
910
|
+
model: SimpleModel,
|
911
|
+
fields: {
|
912
|
+
parent_id: {
|
913
|
+
deps: %i[parent_id]
|
914
|
+
}
|
915
|
+
}
|
916
|
+
}
|
917
|
+
}
|
918
|
+
}
|
919
|
+
}
|
920
|
+
}
|
921
|
+
end
|
922
|
+
it_behaves_like 'a proper fields selector'
|
285
923
|
end
|
286
|
-
it_behaves_like 'a proper selector'
|
287
924
|
end
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
tracks: {
|
298
|
-
other_model: {
|
299
|
-
model: OtherModel,
|
300
|
-
columns: %i[id name]
|
925
|
+
context 'property groups' do
|
926
|
+
context 'a property group substructure object, but asking only 1 of the subfields' do
|
927
|
+
let(:resource) { Resources::Book }
|
928
|
+
let(:fields) do
|
929
|
+
{
|
930
|
+
grouped: {
|
931
|
+
# id: true,
|
932
|
+
name: true
|
933
|
+
# moar_tags
|
301
934
|
}
|
302
935
|
}
|
303
|
-
|
936
|
+
end
|
937
|
+
let(:selectors) do
|
938
|
+
{
|
939
|
+
model: ::ActiveBook,
|
940
|
+
fields: {
|
941
|
+
grouped: {
|
942
|
+
deps: %i[grouped],
|
943
|
+
fields: {
|
944
|
+
name: {
|
945
|
+
deps: %i[grouped_name name nested_name simple_name]
|
946
|
+
}
|
947
|
+
}
|
948
|
+
# NO id or group_id or tags of any sort should be traversed and appear, as we didn't ask for them
|
949
|
+
}
|
950
|
+
}
|
951
|
+
}
|
952
|
+
end
|
953
|
+
it_behaves_like 'a proper fields selector'
|
304
954
|
end
|
305
|
-
it_behaves_like 'a proper selector'
|
306
|
-
end
|
307
955
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
956
|
+
context 'a property group substructure object, but asking only a subset of fields, going deep in an association' do
|
957
|
+
let(:resource) { Resources::Book }
|
958
|
+
let(:fields) do
|
959
|
+
{
|
960
|
+
grouped: {
|
961
|
+
id: true,
|
962
|
+
# name: true,
|
963
|
+
moar_tags: {
|
964
|
+
# name: true,
|
965
|
+
label: true
|
966
|
+
}
|
318
967
|
}
|
319
968
|
}
|
320
|
-
|
969
|
+
end
|
970
|
+
let(:selectors) do
|
971
|
+
{
|
972
|
+
model: ::ActiveBook,
|
973
|
+
fields: {
|
974
|
+
grouped: {
|
975
|
+
deps: %i[grouped],
|
976
|
+
fields: {
|
977
|
+
id: {
|
978
|
+
deps: %i[grouped_id id]
|
979
|
+
},
|
980
|
+
moar_tags: {
|
981
|
+
deps: %i[grouped_moar_tags],
|
982
|
+
references: 'Linked to resource: Resources::Tag'
|
983
|
+
}
|
984
|
+
}
|
985
|
+
# NO name of any other name related things
|
986
|
+
}
|
987
|
+
},
|
988
|
+
tracks: {
|
989
|
+
tags: {
|
990
|
+
model: ActiveTag,
|
991
|
+
fields: {
|
992
|
+
id: {
|
993
|
+
deps: %i[id]
|
994
|
+
},
|
995
|
+
label: {
|
996
|
+
deps: %i[label]
|
997
|
+
}
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
}
|
1001
|
+
}
|
1002
|
+
end
|
1003
|
+
it_behaves_like 'a proper fields selector'
|
321
1004
|
end
|
322
|
-
it_behaves_like 'a proper selector'
|
323
1005
|
end
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
columns: [:*]
|
1006
|
+
context 'true structs' do
|
1007
|
+
context 'with any named subattributes' do
|
1008
|
+
# once we hit true_struct, we know it is not a property group, so we'll bring ALL the inner dependencies
|
1009
|
+
# even if the fields required are only a subset of it
|
1010
|
+
let(:fields) do
|
1011
|
+
{
|
1012
|
+
true_struct: {
|
1013
|
+
sub_id: {
|
1014
|
+
sub_sub_id: true
|
1015
|
+
}
|
335
1016
|
}
|
336
1017
|
}
|
337
|
-
|
1018
|
+
end
|
1019
|
+
let(:selectors) do
|
1020
|
+
{
|
1021
|
+
model: SimpleModel,
|
1022
|
+
fields: {
|
1023
|
+
true_struct: {
|
1024
|
+
deps: %i[true_struct name nested_name simple_name sub_id inner_sub_id id]
|
1025
|
+
}
|
1026
|
+
}
|
1027
|
+
}
|
1028
|
+
end
|
1029
|
+
it_behaves_like 'a proper fields selector'
|
338
1030
|
end
|
339
|
-
it_behaves_like 'a proper selector'
|
340
|
-
end
|
341
|
-
end
|
342
1031
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
model: SimpleModel,
|
349
|
-
columns: [:other_model_id], # FK of the other_model association
|
350
|
-
tracks: {
|
351
|
-
other_model: {
|
352
|
-
columns: [:id],
|
353
|
-
model: OtherModel
|
1032
|
+
context 'a true substructure object with property names prefixed like a property group (is still treated as a struct loading it all)' do
|
1033
|
+
let(:fields) do
|
1034
|
+
{
|
1035
|
+
agroup: {
|
1036
|
+
id: true
|
354
1037
|
}
|
355
1038
|
}
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
{
|
365
|
-
model: ParentModel,
|
366
|
-
columns: [:id], # No FKs in the source model for one_to_many
|
367
|
-
tracks: {
|
368
|
-
simple_children: {
|
369
|
-
columns: [:parent_id],
|
370
|
-
model: SimpleModel
|
1039
|
+
end
|
1040
|
+
let(:selectors) do
|
1041
|
+
{
|
1042
|
+
model: SimpleModel,
|
1043
|
+
fields: {
|
1044
|
+
agroup: {
|
1045
|
+
deps: %i[agroup agroup_id id agroup_name name nested_name simple_name]
|
1046
|
+
}
|
371
1047
|
}
|
372
1048
|
}
|
373
|
-
|
1049
|
+
end
|
1050
|
+
it_behaves_like 'a proper fields selector'
|
374
1051
|
end
|
375
|
-
it_behaves_like 'a proper selector'
|
376
1052
|
end
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
1053
|
+
end
|
1054
|
+
|
1055
|
+
context 'Traversal of field deps experiments' do
|
1056
|
+
context 'using a self forwarding association name with multiple levels which include deep forwarding associations' do
|
1057
|
+
let(:fields) do
|
381
1058
|
{
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
columns: [:id], # join key in the target model for many_to_many (where the middle table points to)
|
387
|
-
model: SimpleModel
|
1059
|
+
sub_struct: {
|
1060
|
+
name: true,
|
1061
|
+
deep_aliased_association: {
|
1062
|
+
nested_name: true
|
388
1063
|
}
|
389
1064
|
}
|
390
1065
|
}
|
391
1066
|
end
|
392
|
-
it_behaves_like 'a proper selector'
|
393
|
-
end
|
394
|
-
|
395
|
-
context 'that are several attriutes deep' do
|
396
|
-
let(:fields) { { deep_nested_deps: true } }
|
397
1067
|
let(:selectors) do
|
398
1068
|
{
|
399
1069
|
model: SimpleModel,
|
400
|
-
|
1070
|
+
fields: {
|
1071
|
+
sub_struct: {
|
1072
|
+
deps: %i[sub_struct],
|
1073
|
+
fields: {
|
1074
|
+
name: {
|
1075
|
+
deps: %i[name nested_name simple_name]
|
1076
|
+
},
|
1077
|
+
deep_aliased_association: {
|
1078
|
+
deps: %i[deep_aliased_association],
|
1079
|
+
references: 'Linked to resource: SimpleResource'
|
1080
|
+
}
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
},
|
401
1084
|
tracks: {
|
402
1085
|
parent: {
|
403
1086
|
model: ParentModel,
|
404
|
-
|
1087
|
+
fields: {
|
1088
|
+
id: {
|
1089
|
+
deps: %i[id]
|
1090
|
+
}
|
1091
|
+
},
|
405
1092
|
tracks: {
|
406
1093
|
simple_children: {
|
407
|
-
columns: %i[parent_id other_model_id],
|
408
1094
|
model: SimpleModel,
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
model: ParentModel,
|
416
|
-
columns: %i[id simple_name other_attribute]
|
417
|
-
}
|
418
|
-
}
|
1095
|
+
fields: {
|
1096
|
+
parent_id: {
|
1097
|
+
deps: %i[parent_id]
|
1098
|
+
},
|
1099
|
+
nested_name: {
|
1100
|
+
deps: %i[nested_name simple_name]
|
419
1101
|
}
|
1102
|
+
|
420
1103
|
}
|
421
1104
|
}
|
422
1105
|
}
|
@@ -424,7 +1107,7 @@ describe Praxis::Mapper::SelectorGenerator do
|
|
424
1107
|
}
|
425
1108
|
}
|
426
1109
|
end
|
427
|
-
it_behaves_like 'a proper selector'
|
1110
|
+
it_behaves_like 'a proper fields selector'
|
428
1111
|
end
|
429
1112
|
end
|
430
1113
|
end
|