jsonapi-resources 0.10.6 → 0.11.0.beta2
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/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
|