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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +39 -2
  4. data/lib/generators/jsonapi/controller_generator.rb +2 -0
  5. data/lib/generators/jsonapi/resource_generator.rb +2 -0
  6. data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +3 -2
  7. data/lib/jsonapi/active_relation/join_manager.rb +30 -18
  8. data/lib/jsonapi/active_relation/join_manager_v10.rb +305 -0
  9. data/lib/jsonapi/active_relation_retrieval.rb +885 -0
  10. data/lib/jsonapi/active_relation_retrieval_v09.rb +715 -0
  11. data/lib/jsonapi/{active_relation_resource.rb → active_relation_retrieval_v10.rb} +113 -135
  12. data/lib/jsonapi/acts_as_resource_controller.rb +49 -49
  13. data/lib/jsonapi/cached_response_fragment.rb +4 -2
  14. data/lib/jsonapi/callbacks.rb +2 -0
  15. data/lib/jsonapi/compiled_json.rb +2 -0
  16. data/lib/jsonapi/configuration.rb +35 -15
  17. data/lib/jsonapi/error.rb +2 -0
  18. data/lib/jsonapi/error_codes.rb +2 -0
  19. data/lib/jsonapi/exceptions.rb +2 -0
  20. data/lib/jsonapi/formatter.rb +2 -0
  21. data/lib/jsonapi/include_directives.rb +77 -19
  22. data/lib/jsonapi/link_builder.rb +2 -0
  23. data/lib/jsonapi/mime_types.rb +6 -10
  24. data/lib/jsonapi/naive_cache.rb +2 -0
  25. data/lib/jsonapi/operation.rb +2 -0
  26. data/lib/jsonapi/operation_result.rb +2 -0
  27. data/lib/jsonapi/paginator.rb +2 -0
  28. data/lib/jsonapi/path.rb +2 -0
  29. data/lib/jsonapi/path_segment.rb +4 -2
  30. data/lib/jsonapi/processor.rb +95 -140
  31. data/lib/jsonapi/relationship.rb +89 -35
  32. data/lib/jsonapi/{request_parser.rb → request.rb} +157 -164
  33. data/lib/jsonapi/resource.rb +7 -2
  34. data/lib/jsonapi/{basic_resource.rb → resource_common.rb} +187 -88
  35. data/lib/jsonapi/resource_controller.rb +2 -0
  36. data/lib/jsonapi/resource_controller_metal.rb +2 -0
  37. data/lib/jsonapi/resource_fragment.rb +17 -15
  38. data/lib/jsonapi/resource_identity.rb +6 -0
  39. data/lib/jsonapi/resource_serializer.rb +20 -4
  40. data/lib/jsonapi/resource_set.rb +36 -16
  41. data/lib/jsonapi/resource_tree.rb +191 -0
  42. data/lib/jsonapi/resources/railtie.rb +3 -1
  43. data/lib/jsonapi/resources/version.rb +3 -1
  44. data/lib/jsonapi/response_document.rb +4 -2
  45. data/lib/jsonapi/routing_ext.rb +4 -2
  46. data/lib/jsonapi/simple_resource.rb +13 -0
  47. data/lib/jsonapi-resources.rb +10 -4
  48. data/lib/tasks/check_upgrade.rake +3 -1
  49. metadata +47 -15
  50. data/lib/jsonapi/resource_id_tree.rb +0 -112
@@ -1,8 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JSONAPI
2
- class ActiveRelationResource < BasicResource
3
- root_resource
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
- class << self
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::JoinManager.new(resource_klass: self,
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::JoinManager.new(resource_klass: self,
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, attributes: => {name => value}}}]
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[:include_directives] ? options[:include_directives].include_directives : {}
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::JoinManager.new(resource_klass: resource_klass,
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 |name|
127
- linkage_relationship = resource_klass._relationship(name)
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, attributes: => {name => value}, related: {relationship_name: [] }}}]
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(source_rids, relationship_name, options = {})
208
- relationship = _relationship(relationship_name)
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(source_rids, relationship, options, false)
210
+ find_related_monomorphic_fragments([source_fragment], relationship, options, false)
214
211
  end
215
212
  end
216
213
 
217
- def find_included_fragments(source_rids, relationship_name, options)
218
- relationship = _relationship(relationship_name)
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(source_rids, relationship, options, true)
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(source_rid, relationship_name, options = {})
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::JoinManager.new(resource_klass: self,
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: source_rid.id,
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. Only resources that have been previously
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(source_rids, relationship, options, connect_source_identity)
364
+ def find_related_monomorphic_fragments(source_fragments, relationship, options, connect_source_identity)
384
365
  filters = options.fetch(:filters, {})
385
- source_ids = source_rids.collect {|rid| rid.id}
366
+ source_ids = source_fragments.collect {|item| item.identity.id}
386
367
 
387
- include_directives = options[:include_directives] ? options[:include_directives].include_directives : {}
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::JoinManager.new(resource_klass: self,
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 |name|
429
- linkage_relationship = resource_klass._relationship(name)
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: name, resource_klass: klass}
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: name, resource_klass: klass}
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._relationships[relationship.inverse_relationship]
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(source_rids, relationship, options, connect_source_identity)
477
+ def find_related_polymorphic_fragments(source_fragments, relationship, options, connect_source_identity)
510
478
  filters = options.fetch(:filters, {})
511
- source_ids = source_rids.collect {|rid| rid.id}
479
+ source_ids = source_fragments.collect {|item| item.identity.id}
512
480
 
513
481
  resource_klass = relationship.resource_klass
514
- include_directives = options[:include_directives] ? options[:include_directives].include_directives : {}
482
+ include_directives = options.fetch(:include_directives, {})
515
483
 
516
- linkage_relationships = []
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
- linkage_relationships << "##{resource_type}.#{r}"
492
+ linkage_relationship_paths << "##{resource_type}.#{r.name}"
525
493
  end
526
494
  end
527
495
 
528
- join_manager = ActiveRelation::JoinManager.new(resource_klass: self,
496
+ join_manager = ActiveRelation::JoinManagerV10.new(resource_klass: self,
529
497
  source_relationship: relationship,
530
- relationships: linkage_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
- linkage_relationships.each do |linkage_relationship_path|
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._relationships[relationship.inverse_relationship]
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::JoinManager.new(resource_klass: self),
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? || field.to_s.include?('.')
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
- quote(field)
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
- "#{quote(table)}.#{quote(field)}"
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
- quote(field)
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
- quote("#{table.to_s}_#{field.to_s}")
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 quote(field)
839
- "\"#{field.to_s}\""
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