jpie 4.1.4.pre.202611030311 → 4.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 424c323cc11e74643e4496fea1f22ba10a221758899c991851c2393ccbe94c88
4
- data.tar.gz: eabe34694e9800c516ac9e4a7aaa42bc50ba9325335651bb49e1764793735074
3
+ metadata.gz: 618cb164f0b64934d5cd9a0c6e871b726bcc6b40f4add24c3204bea490a0cd5c
4
+ data.tar.gz: f4acc02e6f57760deae01dc2d4c49acb29fb5273acefb3eac290f7519e3f53d4
5
5
  SHA512:
6
- metadata.gz: c8fac7dbe88b50d3d4cf4a41316f53e5ba1a6ac3ef8110e3453885d317c03c2d42ea37737c923464b2f48a4043208115d0f7c6b9a23699959cc72644ac901e6f
7
- data.tar.gz: b692711be75fb09abc50b92fa1611eb97a2e6b74275d6af5c087a6e6aaf269c5bb16b9df9171611629446c3e9b53d93d7f9fe4791391baa94ec051c15ccb08a0
6
+ metadata.gz: b83a3b08c429dc700144718b112c578bb9c67243a05a2400ef7fdd9055f614e50852e4819bd63c6897e04cf168eee09e1f7d2b606da39340b9dc6acd2e723b8a
7
+ data.tar.gz: 79f17c229521c0c99541e9787e298e9e00268996759ca8a54f67fec95f212f3cd7f124ea672d8c9da65f65546c6ad02794c971b49a8a8fef7b874883eb601760
data/CHANGELOG.md CHANGED
@@ -7,6 +7,32 @@ at release time.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [4.1.5] - 2026-11-11
11
+
12
+ ### Fixed
13
+
14
+ - **Run resource preloads once for the subclasses of a polymorphic hop.** The
15
+ include preload step grouped the targets of a hop by exact class and ran the
16
+ `records` preloads of the resource once for each class. Five STI subclasses
17
+ that share one preload set ran each preload five times. The step now groups
18
+ the targets by the preloads their resource declares. Classes that share a
19
+ preload set run each preload once for all their records. A mixed STI set on
20
+ a hop that is not polymorphic now gets the preloads of every subclass. The
21
+ response does not change. Regression spec:
22
+ `polymorphic_sti_resource_preload_spec.rb`.
23
+
24
+ ## [4.1.4] - 2026-11-10
25
+
26
+ ### Fixed
27
+
28
+ - **Vet an STI include once for the base class.** The include filter vets
29
+ record ids under the class the association reads, the base class of an STI
30
+ tree. The warm step grouped the loaded records by their own subclass, so
31
+ the warm work was lost and the serializer ran its own query for each
32
+ parent. The warm step now uses the association class. An include of an STI
33
+ association costs one vetting query for the whole page. Regression spec:
34
+ `include_filter_sti_base_class_spec.rb`.
35
+
10
36
  ## [4.1.3] - 2026-10-10
11
37
 
12
38
  ### Fixed
@@ -66,7 +66,7 @@ module JSONAPI
66
66
  targets = collect_include_targets(records, association_name)
67
67
  next if targets.empty?
68
68
 
69
- apply_preloads_for_targets(targets, reflection.polymorphic?)
69
+ apply_resource_preloads(targets)
70
70
  next if subtree.empty?
71
71
 
72
72
  descend_resource_tree(targets, reflection, subtree)
@@ -85,11 +85,13 @@ module JSONAPI
85
85
  end
86
86
  end
87
87
 
88
- def apply_preloads_for_targets(targets, polymorphic)
89
- if polymorphic
90
- targets.group_by(&:class).each_value { |recs| apply_resource_preloads(recs) }
91
- else
92
- apply_resource_preloads(targets)
88
+ # Groups the targets by the preloads their resource declares, so classes that share them
89
+ # (STI subclasses and sibling resources) run each preload once for all their records.
90
+ def apply_resource_preloads(targets)
91
+ groups = Hash.new { |hash, values| hash[values] = [] }
92
+ targets.group_by(&:class).each { |klass, records| groups[resource_preload_values(klass)].concat(records) }
93
+ groups.each do |values, records|
94
+ ActiveRecord::Associations::Preloader.new(records:, associations: values).call unless values.empty?
93
95
  end
94
96
  end
95
97
 
@@ -100,15 +102,9 @@ module JSONAPI
100
102
  end.compact.uniq
101
103
  end
102
104
 
103
- def apply_resource_preloads(records)
104
- return if records.empty?
105
-
106
- klass = records.first.class
107
- resource_scope = ResourceLoader.find_for_model(klass, namespace: jsonapi_namespace).records
108
- preload_values = resource_scope.preload_values + resource_scope.includes_values
109
- return if preload_values.empty?
110
-
111
- ActiveRecord::Associations::Preloader.new(records:, associations: preload_values).call
105
+ def resource_preload_values(klass)
106
+ scope = ResourceLoader.find_for_model(klass, namespace: jsonapi_namespace).records
107
+ scope.preload_values + scope.includes_values
112
108
  end
113
109
  end
114
110
  end
@@ -71,9 +71,18 @@ module JSONAPI
71
71
  cache
72
72
  end
73
73
 
74
+ # The serializer vets a hop under the class its association reads, which
75
+ # is the base class of an STI tree. Warm under that same class, so both use
76
+ # one key, and warm once per class so the page size does not set the
77
+ # query count.
74
78
  def warm_include_level(cache, records, association_name)
75
- targets = records.flat_map { |record| loaded_association_targets(record, association_name) }
76
- targets.group_by(&:class).each { |klass, recs| cache.warm(klass, recs.filter_map(&:id)) }
79
+ ids_by_klass = Hash.new { |hash, klass| hash[klass] = [] }
80
+ targets = records.flat_map do |record|
81
+ found = loaded_association_targets(record, association_name)
82
+ ids_by_klass[record.association(association_name).klass].concat(found.filter_map(&:id)) if found.any?
83
+ found
84
+ end
85
+ ids_by_klass.each { |klass, ids| cache.warm(klass, ids) }
77
86
  targets
78
87
  end
79
88
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSONAPI
4
- VERSION = "4.1.4.pre.202611030311"
4
+ VERSION = "4.1.5"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jpie
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.4.pre.202611030311
4
+ version: 4.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Kampp