jsonapi-resources 0.10.0.beta2 → 0.10.0.beta2.1
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 +5 -5
- data/lib/jsonapi-resources.rb +2 -1
- data/lib/jsonapi/active_relation_resource_finder.rb +117 -130
- data/lib/jsonapi/active_relation_resource_finder/join_manager.rb +297 -0
- data/lib/jsonapi/cached_response_fragment.rb +66 -49
- data/lib/jsonapi/path.rb +8 -0
- data/lib/jsonapi/path_segment.rb +17 -5
- data/lib/jsonapi/relationship.rb +1 -0
- data/lib/jsonapi/resource_set.rb +118 -48
- data/lib/jsonapi/resources/railtie.rb +9 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/tasks/check_upgrade.rake +52 -0
- metadata +6 -5
- data/lib/jsonapi/active_relation_resource_finder/join_tree.rb +0 -227
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 27565577133e3fc1b27ecf7d66b45e0a7870197599fbcfddb75b9e32ad7182a8
|
4
|
+
data.tar.gz: f4b5ff6b6d45c34bba767876d7e37444931490e73d355d5e386cc76ee427532f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff0f10f2b82b13e6bf144536673b3844fd89675b0cc218ab7c7bd7c347eae7db28e659a7e67dc59adcf2c0f1e951b891f176d02571950f32289751380998d2c5
|
7
|
+
data.tar.gz: c410a7335f49d3140dd3fe7252cee2d6945ae0c6cfbff6b48ff4a63af2e4aaebacdeb6d874e43a1549d4ac07bec19d1cb8d1819edaef7167d9bf62a110bb69b9
|
data/lib/jsonapi-resources.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'jsonapi/resources/railtie'
|
1
2
|
require 'jsonapi/naive_cache'
|
2
3
|
require 'jsonapi/compiled_json'
|
3
4
|
require 'jsonapi/resource'
|
@@ -25,7 +26,7 @@ require 'jsonapi/operation_result'
|
|
25
26
|
require 'jsonapi/callbacks'
|
26
27
|
require 'jsonapi/link_builder'
|
27
28
|
require 'jsonapi/active_relation_resource_finder'
|
28
|
-
require 'jsonapi/active_relation_resource_finder/
|
29
|
+
require 'jsonapi/active_relation_resource_finder/join_manager'
|
29
30
|
require 'jsonapi/resource_identity'
|
30
31
|
require 'jsonapi/resource_fragment'
|
31
32
|
require 'jsonapi/resource_id_tree'
|
@@ -19,16 +19,15 @@ module JSONAPI
|
|
19
19
|
def find(filters, options = {})
|
20
20
|
sort_criteria = options.fetch(:sort_criteria) { [] }
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
sort_criteria: sort_criteria)
|
22
|
+
join_manager = JoinManager.new(resource_klass: self,
|
23
|
+
filters: filters,
|
24
|
+
sort_criteria: sort_criteria)
|
26
25
|
|
27
26
|
paginator = options[:paginator]
|
28
27
|
|
29
|
-
records =
|
30
|
-
filters: filters,
|
31
|
-
|
28
|
+
records = apply_request_settings_to_records(records: records(options),
|
29
|
+
sort_criteria: sort_criteria,filters: filters,
|
30
|
+
join_manager: join_manager,
|
32
31
|
paginator: paginator,
|
33
32
|
options: options)
|
34
33
|
|
@@ -42,13 +41,12 @@ module JSONAPI
|
|
42
41
|
#
|
43
42
|
# @return [Integer] the count
|
44
43
|
def count(filters, options = {})
|
45
|
-
|
46
|
-
|
47
|
-
filters: filters)
|
44
|
+
join_manager = JoinManager.new(resource_klass: self,
|
45
|
+
filters: filters)
|
48
46
|
|
49
|
-
records =
|
47
|
+
records = apply_request_settings_to_records(records: records(options),
|
50
48
|
filters: filters,
|
51
|
-
|
49
|
+
join_manager: join_manager,
|
52
50
|
options: options)
|
53
51
|
|
54
52
|
count_records(records)
|
@@ -93,26 +91,23 @@ module JSONAPI
|
|
93
91
|
|
94
92
|
sort_criteria = options.fetch(:sort_criteria) { [] }
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
options: options)
|
94
|
+
join_manager = JoinManager.new(resource_klass: resource_klass,
|
95
|
+
source_relationship: nil,
|
96
|
+
relationships: linkage_relationships,
|
97
|
+
sort_criteria: sort_criteria,
|
98
|
+
filters: filters)
|
102
99
|
|
103
100
|
paginator = options[:paginator]
|
104
101
|
|
105
|
-
records =
|
102
|
+
records = apply_request_settings_to_records(records: records(options),
|
106
103
|
filters: filters,
|
107
104
|
sort_criteria: sort_criteria,
|
108
105
|
paginator: paginator,
|
109
|
-
|
106
|
+
join_manager: join_manager,
|
110
107
|
options: options)
|
111
108
|
|
112
|
-
joins = join_tree.joins
|
113
|
-
|
114
109
|
# This alias is going to be resolve down to the model's table name and will not actually be an alias
|
115
|
-
resource_table_alias =
|
110
|
+
resource_table_alias = resource_klass._table_name
|
116
111
|
|
117
112
|
pluck_fields = [Arel.sql("#{concat_table_field(resource_table_alias, resource_klass._primary_key)} AS #{resource_table_alias}_#{resource_klass._primary_key}")]
|
118
113
|
|
@@ -131,7 +126,7 @@ module JSONAPI
|
|
131
126
|
klass = resource_klass_for(resource_type)
|
132
127
|
linkage_fields << {relationship_name: name, resource_klass: klass}
|
133
128
|
|
134
|
-
linkage_table_alias =
|
129
|
+
linkage_table_alias = join_manager.join_details_by_polymorphic_relationship(linkage_relationship, resource_type)[:alias]
|
135
130
|
primary_key = klass._primary_key
|
136
131
|
pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
|
137
132
|
end
|
@@ -139,7 +134,7 @@ module JSONAPI
|
|
139
134
|
klass = linkage_relationship.resource_klass
|
140
135
|
linkage_fields << {relationship_name: name, resource_klass: klass}
|
141
136
|
|
142
|
-
linkage_table_alias =
|
137
|
+
linkage_table_alias = join_manager.join_details_by_relationship(linkage_relationship)[:alias]
|
143
138
|
primary_key = klass._primary_key
|
144
139
|
pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
|
145
140
|
end
|
@@ -154,7 +149,7 @@ module JSONAPI
|
|
154
149
|
end
|
155
150
|
|
156
151
|
fragments = {}
|
157
|
-
rows = records.pluck(*pluck_fields)
|
152
|
+
rows = records.distinct.pluck(*pluck_fields)
|
158
153
|
rows.collect do |row|
|
159
154
|
rid = JSONAPI::ResourceIdentity.new(resource_klass, pluck_fields.length == 1 ? row : row[0])
|
160
155
|
|
@@ -229,20 +224,18 @@ module JSONAPI
|
|
229
224
|
filters = options.fetch(:filters, {})
|
230
225
|
|
231
226
|
# Joins in this case are related to the related_klass
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
options: options)
|
227
|
+
join_manager = JoinManager.new(resource_klass: self,
|
228
|
+
source_relationship: relationship,
|
229
|
+
filters: filters)
|
236
230
|
|
237
|
-
records =
|
231
|
+
records = apply_request_settings_to_records(records: records(options),
|
238
232
|
resource_klass: related_klass,
|
239
233
|
primary_keys: source_rid.id,
|
240
|
-
|
234
|
+
join_manager: join_manager,
|
241
235
|
filters: filters,
|
242
236
|
options: options)
|
243
237
|
|
244
|
-
|
245
|
-
related_alias = joins[''][:alias]
|
238
|
+
related_alias = join_manager.join_details_by_relationship(relationship)[:alias]
|
246
239
|
|
247
240
|
records = records.select(Arel.sql("#{concat_table_field(related_alias, related_klass._primary_key)}"))
|
248
241
|
|
@@ -250,7 +243,52 @@ module JSONAPI
|
|
250
243
|
end
|
251
244
|
|
252
245
|
def records(_options = {})
|
253
|
-
_model_class.
|
246
|
+
_model_class.all
|
247
|
+
end
|
248
|
+
|
249
|
+
def apply_join(records:, relationship:, resource_type:, join_type:, options:)
|
250
|
+
if relationship.polymorphic? && relationship.belongs_to?
|
251
|
+
case join_type
|
252
|
+
when :inner
|
253
|
+
records = records.joins(resource_type.to_s.singularize.to_sym)
|
254
|
+
when :left
|
255
|
+
records = records.joins_left(resource_type.to_s.singularize.to_sym)
|
256
|
+
end
|
257
|
+
else
|
258
|
+
relation_name = relationship.relation_name(options)
|
259
|
+
case join_type
|
260
|
+
when :inner
|
261
|
+
records = records.joins(relation_name)
|
262
|
+
when :left
|
263
|
+
records = records.joins_left(relation_name)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
records
|
267
|
+
end
|
268
|
+
|
269
|
+
def relationship_records(relationship:, join_type: :inner, resource_type: nil, options: {})
|
270
|
+
records = relationship.parent_resource.records(options)
|
271
|
+
strategy = relationship.options[:apply_join]
|
272
|
+
|
273
|
+
if strategy
|
274
|
+
records = call_method_or_proc(strategy, records, relationship, resource_type, join_type, options)
|
275
|
+
else
|
276
|
+
records = apply_join(records: records,
|
277
|
+
relationship: relationship,
|
278
|
+
resource_type: resource_type,
|
279
|
+
join_type: join_type,
|
280
|
+
options: options)
|
281
|
+
end
|
282
|
+
|
283
|
+
records
|
284
|
+
end
|
285
|
+
|
286
|
+
def join_relationship(records:, relationship:, resource_type: nil, join_type: :inner, options: {})
|
287
|
+
relationship_records = relationship_records(relationship: relationship,
|
288
|
+
join_type: join_type,
|
289
|
+
resource_type: resource_type,
|
290
|
+
options: options)
|
291
|
+
records.merge(relationship_records)
|
254
292
|
end
|
255
293
|
|
256
294
|
protected
|
@@ -267,13 +305,13 @@ module JSONAPI
|
|
267
305
|
end
|
268
306
|
|
269
307
|
def find_record_by_key(key, options = {})
|
270
|
-
record =
|
308
|
+
record = apply_request_settings_to_records(records: records(options), primary_keys: key, options: options).first
|
271
309
|
fail JSONAPI::Exceptions::RecordNotFound.new(key) if record.nil?
|
272
310
|
record
|
273
311
|
end
|
274
312
|
|
275
313
|
def find_records_by_keys(keys, options = {})
|
276
|
-
|
314
|
+
apply_request_settings_to_records(records: records(options), primary_keys: keys, options: options)
|
277
315
|
end
|
278
316
|
|
279
317
|
def find_related_monomorphic_fragments(source_rids, relationship, options, connect_source_identity)
|
@@ -290,26 +328,24 @@ module JSONAPI
|
|
290
328
|
sort_criteria << { field: field, direction: sort[:direction] }
|
291
329
|
end
|
292
330
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
options: options)
|
331
|
+
join_manager = JoinManager.new(resource_klass: self,
|
332
|
+
source_relationship: relationship,
|
333
|
+
relationships: linkage_relationships,
|
334
|
+
sort_criteria: sort_criteria,
|
335
|
+
filters: filters)
|
299
336
|
|
300
337
|
paginator = options[:paginator] if source_rids.count == 1
|
301
338
|
|
302
|
-
records =
|
339
|
+
records = apply_request_settings_to_records(records: records(options),
|
303
340
|
resource_klass: resource_klass,
|
304
341
|
sort_criteria: sort_criteria,
|
305
342
|
primary_keys: source_ids,
|
306
343
|
paginator: paginator,
|
307
344
|
filters: filters,
|
308
|
-
|
345
|
+
join_manager: join_manager,
|
309
346
|
options: options)
|
310
347
|
|
311
|
-
|
312
|
-
resource_table_alias = joins[''][:alias]
|
348
|
+
resource_table_alias = join_manager.join_details_by_relationship(relationship)[:alias]
|
313
349
|
|
314
350
|
pluck_fields = [
|
315
351
|
Arel.sql("#{_table_name}.#{_primary_key} AS source_id"),
|
@@ -331,7 +367,7 @@ module JSONAPI
|
|
331
367
|
klass = resource_klass_for(resource_type)
|
332
368
|
linkage_fields << {relationship_name: name, resource_klass: klass}
|
333
369
|
|
334
|
-
linkage_table_alias =
|
370
|
+
linkage_table_alias = join_manager.join_details_by_polymorphic_relationship(linkage_relationship, resource_type)[:alias]
|
335
371
|
primary_key = klass._primary_key
|
336
372
|
pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
|
337
373
|
end
|
@@ -339,7 +375,7 @@ module JSONAPI
|
|
339
375
|
klass = linkage_relationship.resource_klass
|
340
376
|
linkage_fields << {relationship_name: name, resource_klass: klass}
|
341
377
|
|
342
|
-
linkage_table_alias =
|
378
|
+
linkage_table_alias = join_manager.join_details_by_relationship(linkage_relationship)[:alias]
|
343
379
|
primary_key = klass._primary_key
|
344
380
|
pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
|
345
381
|
end
|
@@ -354,7 +390,7 @@ module JSONAPI
|
|
354
390
|
end
|
355
391
|
|
356
392
|
fragments = {}
|
357
|
-
rows = records.pluck(*pluck_fields)
|
393
|
+
rows = records.distinct.pluck(*pluck_fields)
|
358
394
|
rows.each do |row|
|
359
395
|
rid = JSONAPI::ResourceIdentity.new(resource_klass, row[1])
|
360
396
|
|
@@ -418,27 +454,24 @@ module JSONAPI
|
|
418
454
|
end
|
419
455
|
end
|
420
456
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
options: options)
|
457
|
+
join_manager = JoinManager.new(resource_klass: self,
|
458
|
+
source_relationship: relationship,
|
459
|
+
relationships: linkage_relationships,
|
460
|
+
filters: filters)
|
426
461
|
|
427
462
|
paginator = options[:paginator] if source_rids.count == 1
|
428
463
|
|
429
464
|
# Note: We will sort by the source table. Without using unions we can't sort on a polymorphic relationship
|
430
465
|
# in any manner that makes sense
|
431
|
-
records =
|
466
|
+
records = apply_request_settings_to_records(records: records(options),
|
432
467
|
resource_klass: resource_klass,
|
433
468
|
sort_primary: true,
|
434
469
|
primary_keys: source_ids,
|
435
470
|
paginator: paginator,
|
436
471
|
filters: filters,
|
437
|
-
|
472
|
+
join_manager: join_manager,
|
438
473
|
options: options)
|
439
474
|
|
440
|
-
joins = join_tree.joins
|
441
|
-
|
442
475
|
primary_key = concat_table_field(_table_name, _primary_key)
|
443
476
|
related_key = concat_table_field(_table_name, relationship.foreign_key)
|
444
477
|
related_type = concat_table_field(_table_name, relationship.polymorphic_type)
|
@@ -467,7 +500,7 @@ module JSONAPI
|
|
467
500
|
|
468
501
|
cache_field = related_klass.attribute_to_model_field(:_cache_field) if options[:cache]
|
469
502
|
|
470
|
-
table_alias =
|
503
|
+
table_alias = join_manager.source_join_details(type)[:alias]
|
471
504
|
|
472
505
|
cache_offset = relation_index
|
473
506
|
if cache_field
|
@@ -515,7 +548,7 @@ module JSONAPI
|
|
515
548
|
klass = resource_klass_for(resource_type)
|
516
549
|
linkage_fields << {relationship: linkage_relationship, resource_klass: klass}
|
517
550
|
|
518
|
-
linkage_table_alias =
|
551
|
+
linkage_table_alias = join_manager.join_details_by_polymorphic_relationship(linkage_relationship, resource_type)[:alias]
|
519
552
|
primary_key = klass._primary_key
|
520
553
|
pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
|
521
554
|
end
|
@@ -523,13 +556,13 @@ module JSONAPI
|
|
523
556
|
klass = linkage_relationship.resource_klass
|
524
557
|
linkage_fields << {relationship: linkage_relationship, resource_klass: klass}
|
525
558
|
|
526
|
-
linkage_table_alias =
|
559
|
+
linkage_table_alias = join_manager.join_details_by_relationship(linkage_relationship)[:alias]
|
527
560
|
primary_key = klass._primary_key
|
528
561
|
pluck_fields << Arel.sql("#{concat_table_field(linkage_table_alias, primary_key)} AS #{linkage_table_alias}_#{primary_key}")
|
529
562
|
end
|
530
563
|
end
|
531
564
|
|
532
|
-
rows = records.pluck(*pluck_fields)
|
565
|
+
rows = records.distinct.pluck(*pluck_fields)
|
533
566
|
|
534
567
|
related_fragments = {}
|
535
568
|
|
@@ -581,10 +614,10 @@ module JSONAPI
|
|
581
614
|
related_fragments
|
582
615
|
end
|
583
616
|
|
584
|
-
def
|
585
|
-
|
617
|
+
def apply_request_settings_to_records(records:,
|
618
|
+
join_manager: JoinManager.new(resource_klass: self),
|
586
619
|
resource_klass: self,
|
587
|
-
filters:
|
620
|
+
filters: {},
|
588
621
|
primary_keys: nil,
|
589
622
|
sort_criteria: nil,
|
590
623
|
sort_primary: nil,
|
@@ -592,15 +625,15 @@ module JSONAPI
|
|
592
625
|
options: {})
|
593
626
|
|
594
627
|
opts = options.dup
|
595
|
-
records = resource_klass.apply_joins(records,
|
628
|
+
records = resource_klass.apply_joins(records, join_manager, opts)
|
596
629
|
|
597
630
|
if primary_keys
|
598
631
|
records = records.where(_primary_key => primary_keys)
|
599
632
|
end
|
600
633
|
|
601
|
-
opts[:
|
634
|
+
opts[:join_manager] = join_manager
|
602
635
|
|
603
|
-
|
636
|
+
unless filters.empty?
|
604
637
|
records = resource_klass.filter_records(records, filters, opts)
|
605
638
|
end
|
606
639
|
|
@@ -618,52 +651,8 @@ module JSONAPI
|
|
618
651
|
records
|
619
652
|
end
|
620
653
|
|
621
|
-
def
|
622
|
-
|
623
|
-
init_join_sources_length = init_join_sources.length
|
624
|
-
|
625
|
-
records = yield(records)
|
626
|
-
|
627
|
-
join_sources = records.arel.join_sources
|
628
|
-
if join_sources.length > init_join_sources_length
|
629
|
-
last_join = (join_sources - init_join_sources).last
|
630
|
-
join_alias =
|
631
|
-
case last_join.left
|
632
|
-
when Arel::Table
|
633
|
-
last_join.left.name
|
634
|
-
when Arel::Nodes::TableAlias
|
635
|
-
last_join.left.right
|
636
|
-
when Arel::Nodes::StringJoin
|
637
|
-
# :nocov:
|
638
|
-
warn "get_join_alias: Unsupported join type - use custom filtering and sorting"
|
639
|
-
nil
|
640
|
-
# :nocov:
|
641
|
-
end
|
642
|
-
else
|
643
|
-
# :nocov:
|
644
|
-
warn "get_join_alias: No join added"
|
645
|
-
join_alias = nil
|
646
|
-
# :nocov:
|
647
|
-
end
|
648
|
-
|
649
|
-
return records, join_alias
|
650
|
-
end
|
651
|
-
|
652
|
-
def apply_joins(records, join_tree, _options)
|
653
|
-
joins = join_tree.joins
|
654
|
-
|
655
|
-
joins.each_value do |join|
|
656
|
-
case join[:join_type]
|
657
|
-
when :inner
|
658
|
-
records, join_alias = get_join_alias(records) { |records| records.joins(join[:relation_join_hash]) }
|
659
|
-
join[:alias] = join_alias
|
660
|
-
when :left
|
661
|
-
records, join_alias = get_join_alias(records) { |records| records.joins_left(join[:relation_join_hash]) }
|
662
|
-
join[:alias] = join_alias
|
663
|
-
end
|
664
|
-
end
|
665
|
-
|
666
|
-
return records
|
654
|
+
def apply_joins(records, join_manager, options)
|
655
|
+
join_manager.join(records, options)
|
667
656
|
end
|
668
657
|
|
669
658
|
def apply_pagination(records, paginator, order_options)
|
@@ -689,9 +678,9 @@ module JSONAPI
|
|
689
678
|
if strategy
|
690
679
|
records = call_method_or_proc(strategy, records, direction, context)
|
691
680
|
else
|
692
|
-
|
681
|
+
join_manager = options[:join_manager]
|
693
682
|
|
694
|
-
records = records.order("#{get_aliased_field(field,
|
683
|
+
records = records.order(Arel.sql("#{get_aliased_field(field, join_manager)} #{direction}"))
|
695
684
|
end
|
696
685
|
records
|
697
686
|
end
|
@@ -758,22 +747,20 @@ module JSONAPI
|
|
758
747
|
records
|
759
748
|
end
|
760
749
|
|
761
|
-
def get_aliased_field(path_with_field,
|
750
|
+
def get_aliased_field(path_with_field, join_manager)
|
762
751
|
path = JSONAPI::Path.new(resource_klass: self, path_string: path_with_field)
|
763
752
|
|
764
|
-
|
765
|
-
|
766
|
-
relationship_path = path.relationship_path_string
|
753
|
+
relationship_segment = path.segments[-2]
|
754
|
+
field_segment = path.segments[-1]
|
767
755
|
|
768
|
-
if
|
769
|
-
|
770
|
-
|
771
|
-
|
756
|
+
if relationship_segment
|
757
|
+
join_details = join_manager.join_details[path.last_relationship]
|
758
|
+
table_alias = join_details[:alias]
|
759
|
+
else
|
760
|
+
table_alias = self._table_name
|
772
761
|
end
|
773
762
|
|
774
|
-
table_alias
|
775
|
-
|
776
|
-
concat_table_field(table_alias, field.delegated_field_name)
|
763
|
+
concat_table_field(table_alias, field_segment.delegated_field_name)
|
777
764
|
end
|
778
765
|
|
779
766
|
def apply_filter(records, filter, value, options = {})
|
@@ -782,8 +769,8 @@ module JSONAPI
|
|
782
769
|
if strategy
|
783
770
|
records = call_method_or_proc(strategy, records, value, options)
|
784
771
|
else
|
785
|
-
|
786
|
-
records = records.where(get_aliased_field(filter,
|
772
|
+
join_manager = options[:join_manager]
|
773
|
+
records = records.where(Arel.sql(get_aliased_field(filter, join_manager)) => value)
|
787
774
|
end
|
788
775
|
|
789
776
|
records
|