jsonapi-resources 0.10.6 → 0.11.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +39 -2
- data/lib/generators/jsonapi/controller_generator.rb +2 -0
- data/lib/generators/jsonapi/resource_generator.rb +2 -0
- data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +3 -2
- data/lib/jsonapi/active_relation/join_manager.rb +30 -18
- data/lib/jsonapi/active_relation/join_manager_v10.rb +305 -0
- data/lib/jsonapi/active_relation_retrieval.rb +885 -0
- data/lib/jsonapi/active_relation_retrieval_v09.rb +715 -0
- data/lib/jsonapi/{active_relation_resource.rb → active_relation_retrieval_v10.rb} +113 -135
- data/lib/jsonapi/acts_as_resource_controller.rb +49 -49
- data/lib/jsonapi/cached_response_fragment.rb +4 -2
- data/lib/jsonapi/callbacks.rb +2 -0
- data/lib/jsonapi/compiled_json.rb +2 -0
- data/lib/jsonapi/configuration.rb +35 -15
- data/lib/jsonapi/error.rb +2 -0
- data/lib/jsonapi/error_codes.rb +2 -0
- data/lib/jsonapi/exceptions.rb +2 -0
- data/lib/jsonapi/formatter.rb +2 -0
- data/lib/jsonapi/include_directives.rb +77 -19
- data/lib/jsonapi/link_builder.rb +2 -0
- data/lib/jsonapi/mime_types.rb +6 -10
- data/lib/jsonapi/naive_cache.rb +2 -0
- data/lib/jsonapi/operation.rb +2 -0
- data/lib/jsonapi/operation_result.rb +2 -0
- data/lib/jsonapi/paginator.rb +2 -0
- data/lib/jsonapi/path.rb +2 -0
- data/lib/jsonapi/path_segment.rb +4 -2
- data/lib/jsonapi/processor.rb +95 -140
- data/lib/jsonapi/relationship.rb +89 -35
- data/lib/jsonapi/{request_parser.rb → request.rb} +157 -164
- data/lib/jsonapi/resource.rb +7 -2
- data/lib/jsonapi/{basic_resource.rb → resource_common.rb} +187 -88
- data/lib/jsonapi/resource_controller.rb +2 -0
- data/lib/jsonapi/resource_controller_metal.rb +2 -0
- data/lib/jsonapi/resource_fragment.rb +17 -15
- data/lib/jsonapi/resource_identity.rb +6 -0
- data/lib/jsonapi/resource_serializer.rb +20 -4
- data/lib/jsonapi/resource_set.rb +36 -16
- data/lib/jsonapi/resource_tree.rb +191 -0
- data/lib/jsonapi/resources/railtie.rb +3 -1
- data/lib/jsonapi/resources/version.rb +3 -1
- data/lib/jsonapi/response_document.rb +4 -2
- data/lib/jsonapi/routing_ext.rb +4 -2
- data/lib/jsonapi/simple_resource.rb +13 -0
- data/lib/jsonapi-resources.rb +10 -4
- data/lib/tasks/check_upgrade.rake +3 -1
- metadata +47 -15
- data/lib/jsonapi/resource_id_tree.rb +0 -112
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
|
-
|
3
|
-
|
4
|
+
module ActiveRelationRetrievalV10
|
5
|
+
def find_related_ids(relationship, options = {})
|
6
|
+
self.class.find_related_fragments(self, relationship, options).keys.collect { |rid| rid.id }
|
7
|
+
end
|
4
8
|
|
5
|
-
|
9
|
+
module ClassMethods
|
6
10
|
# Finds Resources using the `filters`. Pagination and sort options are used when provided
|
7
11
|
#
|
8
12
|
# @param filters [Hash] the filters hash
|
@@ -14,7 +18,7 @@ module JSONAPI
|
|
14
18
|
def find(filters, options = {})
|
15
19
|
sort_criteria = options.fetch(:sort_criteria) { [] }
|
16
20
|
|
17
|
-
join_manager = ActiveRelation::
|
21
|
+
join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: self,
|
18
22
|
filters: filters,
|
19
23
|
sort_criteria: sort_criteria)
|
20
24
|
|
@@ -36,7 +40,7 @@ module JSONAPI
|
|
36
40
|
#
|
37
41
|
# @return [Integer] the count
|
38
42
|
def count(filters, options = {})
|
39
|
-
join_manager = ActiveRelation::
|
43
|
+
join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: self,
|
40
44
|
filters: filters)
|
41
45
|
|
42
46
|
records = apply_request_settings_to_records(records: records(options),
|
@@ -76,29 +80,30 @@ module JSONAPI
|
|
76
80
|
end
|
77
81
|
|
78
82
|
# Finds Resource fragments using the `filters`. Pagination and sort options are used when provided.
|
79
|
-
# Retrieving the ResourceIdentities and attributes does not instantiate a model instance.
|
80
83
|
# Note: This is incompatible with Polymorphic resources (which are going to come from two separate tables)
|
81
84
|
#
|
82
85
|
# @param filters [Hash] the filters hash
|
83
86
|
# @option options [Hash] :context The context of the request, set in the controller
|
84
87
|
# @option options [Hash] :sort_criteria The `sort criteria`
|
85
88
|
# @option options [Hash] :include_directives The `include_directives`
|
86
|
-
# @option options [Hash] :attributes Additional fields to be retrieved.
|
87
89
|
# @option options [Boolean] :cache Return the resources' cache field
|
88
90
|
#
|
89
|
-
# @return [Hash{ResourceIdentity => {identity: => ResourceIdentity, cache: cache_field
|
91
|
+
# @return [Hash{ResourceIdentity => {identity: => ResourceIdentity, cache: cache_field}]
|
90
92
|
# the ResourceInstances matching the filters, sorting, and pagination rules along with any request
|
91
93
|
# additional_field values
|
92
94
|
def find_fragments(filters, options = {})
|
93
|
-
include_directives = options
|
95
|
+
include_directives = options.fetch(:include_directives, {})
|
94
96
|
resource_klass = self
|
97
|
+
|
98
|
+
fragments = {}
|
99
|
+
|
95
100
|
linkage_relationships = to_one_relationships_for_linkage(include_directives[:include_related])
|
96
101
|
|
97
102
|
sort_criteria = options.fetch(:sort_criteria) { [] }
|
98
103
|
|
99
|
-
join_manager = ActiveRelation::
|
104
|
+
join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: resource_klass,
|
100
105
|
source_relationship: nil,
|
101
|
-
relationships: linkage_relationships,
|
106
|
+
relationships: linkage_relationships.collect(&:name),
|
102
107
|
sort_criteria: sort_criteria,
|
103
108
|
filters: filters)
|
104
109
|
|
@@ -123,42 +128,41 @@ module JSONAPI
|
|
123
128
|
|
124
129
|
linkage_fields = []
|
125
130
|
|
126
|
-
linkage_relationships.each do |
|
127
|
-
|
131
|
+
linkage_relationships.each do |linkage_relationship|
|
132
|
+
linkage_relationship_name = linkage_relationship.name
|
128
133
|
|
129
134
|
if linkage_relationship.polymorphic? && linkage_relationship.belongs_to?
|
130
135
|
linkage_relationship.resource_types.each do |resource_type|
|
131
136
|
klass = resource_klass_for(resource_type)
|
132
|
-
linkage_fields << {relationship_name: name, resource_klass: klass}
|
133
|
-
|
134
137
|
linkage_table_alias = join_manager.join_details_by_polymorphic_relationship(linkage_relationship, resource_type)[:alias]
|
135
138
|
primary_key = klass._primary_key
|
139
|
+
|
140
|
+
linkage_fields << {relationship_name: linkage_relationship_name,
|
141
|
+
resource_klass: klass,
|
142
|
+
field: sql_field_with_alias(linkage_table_alias, primary_key),
|
143
|
+
alias: alias_table_field(linkage_table_alias, primary_key)}
|
144
|
+
|
136
145
|
pluck_fields << sql_field_with_alias(linkage_table_alias, primary_key)
|
137
146
|
end
|
138
147
|
else
|
139
148
|
klass = linkage_relationship.resource_klass
|
140
|
-
linkage_fields << {relationship_name: name, resource_klass: klass}
|
141
|
-
|
142
149
|
linkage_table_alias = join_manager.join_details_by_relationship(linkage_relationship)[:alias]
|
143
150
|
primary_key = klass._primary_key
|
151
|
+
|
152
|
+
linkage_fields << {relationship_name: linkage_relationship_name,
|
153
|
+
resource_klass: klass,
|
154
|
+
field: sql_field_with_alias(linkage_table_alias, primary_key),
|
155
|
+
alias: alias_table_field(linkage_table_alias, primary_key)}
|
156
|
+
|
144
157
|
pluck_fields << sql_field_with_alias(linkage_table_alias, primary_key)
|
145
158
|
end
|
146
159
|
end
|
147
160
|
|
148
|
-
model_fields = {}
|
149
|
-
attributes = options[:attributes]
|
150
|
-
attributes.try(:each) do |attribute|
|
151
|
-
model_field = resource_klass.attribute_to_model_field(attribute)
|
152
|
-
model_fields[attribute] = model_field
|
153
|
-
pluck_fields << sql_field_with_alias(resource_table_alias, model_field[:name])
|
154
|
-
end
|
155
|
-
|
156
161
|
sort_fields = options.dig(:_relation_helper_options, :sort_fields)
|
157
162
|
sort_fields.try(:each) do |field|
|
158
163
|
pluck_fields << Arel.sql(field)
|
159
164
|
end
|
160
165
|
|
161
|
-
fragments = {}
|
162
166
|
rows = records.pluck(*pluck_fields)
|
163
167
|
rows.each do |row|
|
164
168
|
rid = JSONAPI::ResourceIdentity.new(resource_klass, pluck_fields.length == 1 ? row : row[0])
|
@@ -180,10 +184,6 @@ module JSONAPI
|
|
180
184
|
end
|
181
185
|
attributes_offset+= 1
|
182
186
|
end
|
183
|
-
|
184
|
-
model_fields.each_with_index do |k, idx|
|
185
|
-
fragments[rid].attributes[k[0]]= cast_to_attribute_type(row[idx + attributes_offset], k[1][:type])
|
186
|
-
end
|
187
187
|
end
|
188
188
|
|
189
189
|
if JSONAPI.configuration.warn_on_performance_issues && (rows.length > fragments.length)
|
@@ -198,29 +198,24 @@ module JSONAPI
|
|
198
198
|
# @param source_rids [Array<ResourceIdentity>] The resources to find related ResourcesIdentities for
|
199
199
|
# @param relationship_name [String | Symbol] The name of the relationship
|
200
200
|
# @option options [Hash] :context The context of the request, set in the controller
|
201
|
-
# @option options [Hash] :attributes Additional fields to be retrieved.
|
202
201
|
# @option options [Boolean] :cache Return the resources' cache field
|
203
202
|
#
|
204
|
-
# @return [Hash{ResourceIdentity => {identity: => ResourceIdentity, cache: cache_field,
|
203
|
+
# @return [Hash{ResourceIdentity => {identity: => ResourceIdentity, cache: cache_field, related: {relationship_name: [] }}}]
|
205
204
|
# the ResourceInstances matching the filters, sorting, and pagination rules along with any request
|
206
205
|
# additional_field values
|
207
|
-
def find_related_fragments(
|
208
|
-
relationship
|
209
|
-
|
210
|
-
if relationship.polymorphic? # && relationship.foreign_key_on == :self
|
211
|
-
find_related_polymorphic_fragments(source_rids, relationship, options, false)
|
206
|
+
def find_related_fragments(source_fragment, relationship, options = {})
|
207
|
+
if relationship.polymorphic?
|
208
|
+
find_related_polymorphic_fragments([source_fragment], relationship, options, false)
|
212
209
|
else
|
213
|
-
find_related_monomorphic_fragments(
|
210
|
+
find_related_monomorphic_fragments([source_fragment], relationship, options, false)
|
214
211
|
end
|
215
212
|
end
|
216
213
|
|
217
|
-
def find_included_fragments(
|
218
|
-
relationship
|
219
|
-
|
220
|
-
if relationship.polymorphic? # && relationship.foreign_key_on == :self
|
221
|
-
find_related_polymorphic_fragments(source_rids, relationship, options, true)
|
214
|
+
def find_included_fragments(source_fragments, relationship, options)
|
215
|
+
if relationship.polymorphic?
|
216
|
+
find_related_polymorphic_fragments(source_fragments, relationship, options, true)
|
222
217
|
else
|
223
|
-
find_related_monomorphic_fragments(
|
218
|
+
find_related_monomorphic_fragments(source_fragments, relationship, options, true)
|
224
219
|
end
|
225
220
|
end
|
226
221
|
|
@@ -231,20 +226,19 @@ module JSONAPI
|
|
231
226
|
# @option options [Hash] :context The context of the request, set in the controller
|
232
227
|
#
|
233
228
|
# @return [Integer] the count
|
234
|
-
def count_related(
|
235
|
-
relationship = _relationship(relationship_name)
|
229
|
+
def count_related(source_resource, relationship, options = {})
|
236
230
|
related_klass = relationship.resource_klass
|
237
231
|
|
238
232
|
filters = options.fetch(:filters, {})
|
239
233
|
|
240
234
|
# Joins in this case are related to the related_klass
|
241
|
-
join_manager = ActiveRelation::
|
235
|
+
join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: self,
|
242
236
|
source_relationship: relationship,
|
243
237
|
filters: filters)
|
244
238
|
|
245
239
|
records = apply_request_settings_to_records(records: records(options),
|
246
240
|
resource_klass: related_klass,
|
247
|
-
primary_keys:
|
241
|
+
primary_keys: source_resource.id,
|
248
242
|
join_manager: join_manager,
|
249
243
|
filters: filters,
|
250
244
|
options: options)
|
@@ -294,9 +288,7 @@ module JSONAPI
|
|
294
288
|
records_base(options)
|
295
289
|
end
|
296
290
|
|
297
|
-
# The `ActiveRecord::Relation` used for the finding related resources.
|
298
|
-
# identified through the `records` method will be accessed and used as the basis to find related resources. Thus
|
299
|
-
# it should not be necessary to reapply permissions checks.
|
291
|
+
# The `ActiveRecord::Relation` used for the finding related resources.
|
300
292
|
#
|
301
293
|
# @option options [Hash] :context The context of the request, set in the controller
|
302
294
|
#
|
@@ -357,18 +349,7 @@ module JSONAPI
|
|
357
349
|
records.merge(relationship_records)
|
358
350
|
end
|
359
351
|
|
360
|
-
protected
|
361
|
-
|
362
|
-
def to_one_relationships_for_linkage(include_related)
|
363
|
-
include_related ||= {}
|
364
|
-
relationships = []
|
365
|
-
_relationships.each do |name, relationship|
|
366
|
-
if relationship.is_a?(JSONAPI::Relationship::ToOne) && !include_related.has_key?(name) && relationship.include_optional_linkage_data?
|
367
|
-
relationships << name
|
368
|
-
end
|
369
|
-
end
|
370
|
-
relationships
|
371
|
-
end
|
352
|
+
# protected
|
372
353
|
|
373
354
|
def find_record_by_key(key, options = {})
|
374
355
|
record = apply_request_settings_to_records(records: records(options), primary_keys: key, options: options).first
|
@@ -380,11 +361,11 @@ module JSONAPI
|
|
380
361
|
apply_request_settings_to_records(records: records(options), primary_keys: keys, options: options)
|
381
362
|
end
|
382
363
|
|
383
|
-
def find_related_monomorphic_fragments(
|
364
|
+
def find_related_monomorphic_fragments(source_fragments, relationship, options, connect_source_identity)
|
384
365
|
filters = options.fetch(:filters, {})
|
385
|
-
source_ids =
|
366
|
+
source_ids = source_fragments.collect {|item| item.identity.id}
|
386
367
|
|
387
|
-
include_directives = options
|
368
|
+
include_directives = options.fetch(:include_directives, {})
|
388
369
|
resource_klass = relationship.resource_klass
|
389
370
|
linkage_relationships = resource_klass.to_one_relationships_for_linkage(include_directives[:include_related])
|
390
371
|
|
@@ -394,9 +375,9 @@ module JSONAPI
|
|
394
375
|
sort_criteria << { field: field, direction: sort[:direction] }
|
395
376
|
end
|
396
377
|
|
397
|
-
join_manager = ActiveRelation::
|
378
|
+
join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: self,
|
398
379
|
source_relationship: relationship,
|
399
|
-
relationships: linkage_relationships,
|
380
|
+
relationships: linkage_relationships.collect(&:name),
|
400
381
|
sort_criteria: sort_criteria,
|
401
382
|
filters: filters)
|
402
383
|
|
@@ -425,13 +406,13 @@ module JSONAPI
|
|
425
406
|
|
426
407
|
linkage_fields = []
|
427
408
|
|
428
|
-
linkage_relationships.each do |
|
429
|
-
|
409
|
+
linkage_relationships.each do |linkage_relationship|
|
410
|
+
linkage_relationship_name = linkage_relationship.name
|
430
411
|
|
431
412
|
if linkage_relationship.polymorphic? && linkage_relationship.belongs_to?
|
432
413
|
linkage_relationship.resource_types.each do |resource_type|
|
433
414
|
klass = resource_klass_for(resource_type)
|
434
|
-
linkage_fields << {relationship_name:
|
415
|
+
linkage_fields << {relationship_name: linkage_relationship_name, resource_klass: klass}
|
435
416
|
|
436
417
|
linkage_table_alias = join_manager.join_details_by_polymorphic_relationship(linkage_relationship, resource_type)[:alias]
|
437
418
|
primary_key = klass._primary_key
|
@@ -439,7 +420,7 @@ module JSONAPI
|
|
439
420
|
end
|
440
421
|
else
|
441
422
|
klass = linkage_relationship.resource_klass
|
442
|
-
linkage_fields << {relationship_name:
|
423
|
+
linkage_fields << {relationship_name: linkage_relationship_name, resource_klass: klass}
|
443
424
|
|
444
425
|
linkage_table_alias = join_manager.join_details_by_relationship(linkage_relationship)[:alias]
|
445
426
|
primary_key = klass._primary_key
|
@@ -447,14 +428,6 @@ module JSONAPI
|
|
447
428
|
end
|
448
429
|
end
|
449
430
|
|
450
|
-
model_fields = {}
|
451
|
-
attributes = options[:attributes]
|
452
|
-
attributes.try(:each) do |attribute|
|
453
|
-
model_field = resource_klass.attribute_to_model_field(attribute)
|
454
|
-
model_fields[attribute] = model_field
|
455
|
-
pluck_fields << sql_field_with_alias(resource_table_alias, model_field[:name])
|
456
|
-
end
|
457
|
-
|
458
431
|
sort_fields = options.dig(:_relation_helper_options, :sort_fields)
|
459
432
|
sort_fields.try(:each) do |field|
|
460
433
|
pluck_fields << Arel.sql(field)
|
@@ -474,11 +447,6 @@ module JSONAPI
|
|
474
447
|
attributes_offset+= 1
|
475
448
|
end
|
476
449
|
|
477
|
-
model_fields.each_with_index do |k, idx|
|
478
|
-
fragments[rid].add_attribute(k[0], cast_to_attribute_type(row[idx + attributes_offset], k[1][:type]))
|
479
|
-
attributes_offset+= 1
|
480
|
-
end
|
481
|
-
|
482
450
|
source_rid = JSONAPI::ResourceIdentity.new(self, row[0])
|
483
451
|
|
484
452
|
fragments[rid].add_related_from(source_rid)
|
@@ -494,7 +462,7 @@ module JSONAPI
|
|
494
462
|
end
|
495
463
|
|
496
464
|
if connect_source_identity
|
497
|
-
related_relationship = resource_klass.
|
465
|
+
related_relationship = resource_klass._relationship(relationship.inverse_relationship)
|
498
466
|
if related_relationship
|
499
467
|
fragments[rid].add_related_identity(related_relationship.name, source_rid)
|
500
468
|
end
|
@@ -506,14 +474,14 @@ module JSONAPI
|
|
506
474
|
|
507
475
|
# Gets resource identities where the related resource is polymorphic and the resource type and id
|
508
476
|
# are stored on the primary resources. Cache fields will always be on the related resources.
|
509
|
-
def find_related_polymorphic_fragments(
|
477
|
+
def find_related_polymorphic_fragments(source_fragments, relationship, options, connect_source_identity)
|
510
478
|
filters = options.fetch(:filters, {})
|
511
|
-
source_ids =
|
479
|
+
source_ids = source_fragments.collect {|item| item.identity.id}
|
512
480
|
|
513
481
|
resource_klass = relationship.resource_klass
|
514
|
-
include_directives = options
|
482
|
+
include_directives = options.fetch(:include_directives, {})
|
515
483
|
|
516
|
-
|
484
|
+
linkage_relationship_paths = []
|
517
485
|
|
518
486
|
resource_types = relationship.resource_types
|
519
487
|
|
@@ -521,13 +489,13 @@ module JSONAPI
|
|
521
489
|
related_resource_klass = resource_klass_for(resource_type)
|
522
490
|
relationships = related_resource_klass.to_one_relationships_for_linkage(include_directives[:include_related])
|
523
491
|
relationships.each do |r|
|
524
|
-
|
492
|
+
linkage_relationship_paths << "##{resource_type}.#{r.name}"
|
525
493
|
end
|
526
494
|
end
|
527
495
|
|
528
|
-
join_manager = ActiveRelation::
|
496
|
+
join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: self,
|
529
497
|
source_relationship: relationship,
|
530
|
-
relationships:
|
498
|
+
relationships: linkage_relationship_paths,
|
531
499
|
filters: filters)
|
532
500
|
|
533
501
|
paginator = options[:paginator]
|
@@ -558,8 +526,6 @@ module JSONAPI
|
|
558
526
|
relation_positions = {}
|
559
527
|
relation_index = pluck_fields.length
|
560
528
|
|
561
|
-
attributes = options.fetch(:attributes, [])
|
562
|
-
|
563
529
|
# Add resource specific fields
|
564
530
|
if resource_types.nil? || resource_types.length == 0
|
565
531
|
# :nocov:
|
@@ -579,27 +545,9 @@ module JSONAPI
|
|
579
545
|
relation_index+= 1
|
580
546
|
end
|
581
547
|
|
582
|
-
model_fields = {}
|
583
|
-
field_offset = relation_index
|
584
|
-
attributes.try(:each) do |attribute|
|
585
|
-
model_field = related_klass.attribute_to_model_field(attribute)
|
586
|
-
model_fields[attribute] = model_field
|
587
|
-
pluck_fields << sql_field_with_alias(table_alias, model_field[:name])
|
588
|
-
relation_index+= 1
|
589
|
-
end
|
590
|
-
|
591
|
-
model_offset = relation_index
|
592
|
-
model_fields.each do |_k, v|
|
593
|
-
pluck_fields << Arel.sql("#{concat_table_field(table_alias, v[:name])}")
|
594
|
-
relation_index+= 1
|
595
|
-
end
|
596
|
-
|
597
548
|
relation_positions[type] = {relation_klass: related_klass,
|
598
549
|
cache_field: cache_field,
|
599
|
-
cache_offset: cache_offset
|
600
|
-
model_fields: model_fields,
|
601
|
-
model_offset: model_offset,
|
602
|
-
field_offset: field_offset}
|
550
|
+
cache_offset: cache_offset}
|
603
551
|
end
|
604
552
|
end
|
605
553
|
|
@@ -607,7 +555,7 @@ module JSONAPI
|
|
607
555
|
linkage_fields = []
|
608
556
|
linkage_offset = relation_index
|
609
557
|
|
610
|
-
|
558
|
+
linkage_relationship_paths.each do |linkage_relationship_path|
|
611
559
|
path = JSONAPI::Path.new(resource_klass: self,
|
612
560
|
path_string: "#{relationship.name}#{linkage_relationship_path}",
|
613
561
|
ensure_default_field: false)
|
@@ -648,7 +596,7 @@ module JSONAPI
|
|
648
596
|
related_fragments[rid].add_related_from(source_rid)
|
649
597
|
|
650
598
|
if connect_source_identity
|
651
|
-
related_relationship = related_klass.
|
599
|
+
related_relationship = related_klass._relationship(relationship.inverse_relationship)
|
652
600
|
if related_relationship
|
653
601
|
related_fragments[rid].add_related_identity(related_relationship.name, source_rid)
|
654
602
|
end
|
@@ -664,12 +612,6 @@ module JSONAPI
|
|
664
612
|
related_fragments[rid].cache = cast_to_attribute_type(row[cache_offset], cache_field[:type])
|
665
613
|
end
|
666
614
|
|
667
|
-
if attributes.length > 0
|
668
|
-
model_fields.each_with_index do |k, idx|
|
669
|
-
related_fragments[rid].add_attribute(k[0], cast_to_attribute_type(row[idx + field_offset], k[1][:type]))
|
670
|
-
end
|
671
|
-
end
|
672
|
-
|
673
615
|
linkage_fields.each_with_index do |linkage_field_details, idx|
|
674
616
|
relationship = linkage_field_details[:relationship]
|
675
617
|
related_fragments[rid].initialize_related(relationship.name)
|
@@ -686,7 +628,7 @@ module JSONAPI
|
|
686
628
|
end
|
687
629
|
|
688
630
|
def apply_request_settings_to_records(records:,
|
689
|
-
join_manager: ActiveRelation::
|
631
|
+
join_manager: ActiveRelation::JoinManagerV10.new(resource_klass: self),
|
690
632
|
resource_klass: self,
|
691
633
|
filters: {},
|
692
634
|
primary_keys: nil,
|
@@ -791,18 +733,29 @@ module JSONAPI
|
|
791
733
|
apply_sort(records, order_options, options)
|
792
734
|
end
|
793
735
|
|
736
|
+
def sql_field_with_alias(table, field, quoted = true)
|
737
|
+
Arel.sql("#{concat_table_field(table, field, quoted)} AS #{alias_table_field(table, field, quoted)}")
|
738
|
+
end
|
739
|
+
|
794
740
|
def concat_table_field(table, field, quoted = false)
|
795
|
-
if table.blank?
|
741
|
+
if table.blank?
|
742
|
+
split_table, split_field = field.to_s.split('.')
|
743
|
+
if split_table && split_field
|
744
|
+
table = split_table
|
745
|
+
field = split_field
|
746
|
+
end
|
747
|
+
end
|
748
|
+
if table.blank?
|
796
749
|
# :nocov:
|
797
750
|
if quoted
|
798
|
-
|
751
|
+
quote_column_name(field)
|
799
752
|
else
|
800
753
|
field.to_s
|
801
754
|
end
|
802
755
|
# :nocov:
|
803
756
|
else
|
804
757
|
if quoted
|
805
|
-
"#{
|
758
|
+
"#{quote_table_name(table)}.#{quote_column_name(field)}"
|
806
759
|
else
|
807
760
|
# :nocov:
|
808
761
|
"#{table.to_s}.#{field.to_s}"
|
@@ -811,15 +764,11 @@ module JSONAPI
|
|
811
764
|
end
|
812
765
|
end
|
813
766
|
|
814
|
-
def sql_field_with_alias(table, field, quoted = true)
|
815
|
-
Arel.sql("#{concat_table_field(table, field, quoted)} AS #{alias_table_field(table, field, quoted)}")
|
816
|
-
end
|
817
|
-
|
818
767
|
def alias_table_field(table, field, quoted = false)
|
819
768
|
if table.blank? || field.to_s.include?('.')
|
820
769
|
# :nocov:
|
821
770
|
if quoted
|
822
|
-
|
771
|
+
quote_column_name(field)
|
823
772
|
else
|
824
773
|
field.to_s
|
825
774
|
end
|
@@ -827,7 +776,7 @@ module JSONAPI
|
|
827
776
|
else
|
828
777
|
if quoted
|
829
778
|
# :nocov:
|
830
|
-
|
779
|
+
quote_column_name("#{table.to_s}_#{field.to_s}")
|
831
780
|
# :nocov:
|
832
781
|
else
|
833
782
|
"#{table.to_s}_#{field.to_s}"
|
@@ -835,10 +784,27 @@ module JSONAPI
|
|
835
784
|
end
|
836
785
|
end
|
837
786
|
|
838
|
-
def
|
839
|
-
|
787
|
+
def quote_table_name(table_name)
|
788
|
+
if _model_class&.connection
|
789
|
+
_model_class.connection.quote_table_name(table_name)
|
790
|
+
else
|
791
|
+
quote(table_name)
|
792
|
+
end
|
840
793
|
end
|
841
794
|
|
795
|
+
def quote_column_name(column_name)
|
796
|
+
return column_name if column_name == "*"
|
797
|
+
if _model_class&.connection
|
798
|
+
_model_class.connection.quote_column_name(column_name)
|
799
|
+
else
|
800
|
+
quote(column_name)
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
# fallback quote identifier when database adapter not available
|
805
|
+
def quote(field)
|
806
|
+
%{"#{field.to_s}"}
|
807
|
+
end
|
842
808
|
|
843
809
|
def apply_filters(records, filters, options = {})
|
844
810
|
if filters
|
@@ -873,12 +839,24 @@ module JSONAPI
|
|
873
839
|
records = call_method_or_proc(strategy, records, value, options)
|
874
840
|
else
|
875
841
|
join_manager = options.dig(:_relation_helper_options, :join_manager)
|
876
|
-
field = join_manager ? get_aliased_field(filter, join_manager) : filter
|
842
|
+
field = join_manager ? get_aliased_field(filter, join_manager) : filter.to_s
|
877
843
|
records = records.where(Arel.sql(field) => value)
|
878
844
|
end
|
879
845
|
|
880
846
|
records
|
881
847
|
end
|
848
|
+
|
849
|
+
def warn_about_unused_methods
|
850
|
+
if Rails.env.development?
|
851
|
+
if !caching? && implements_class_method?(:records_for_populate)
|
852
|
+
warn "#{self}: The `records_for_populate` method is not used when caching is disabled."
|
853
|
+
end
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
857
|
+
def implements_class_method?(method_name)
|
858
|
+
methods(false).include?(method_name)
|
859
|
+
end
|
882
860
|
end
|
883
861
|
end
|
884
862
|
end
|