@@ -37,10 +37,10 @@ def perform
37
37
end
38
38
39
39
if includes . empty? || has_smart_fields
40
- @records = optimize_record_loading ( @resource , @records )
40
+ @records = optimize_record_loading ( @resource , @records , false )
41
41
else
42
42
select = compute_select_fields
43
- @records = optimize_record_loading ( @resource , @records ) . references ( includes ) . select ( *select )
43
+ @records = optimize_record_loading ( @resource , @records , false ) . references ( includes ) . select ( *select )
44
44
end
45
45
46
46
@records
@@ -55,7 +55,79 @@ def query_for_batch
55
55
end
56
56
57
57
def records
58
- @records . offset ( offset ) . limit ( limit ) . to_a
58
+ records = @records . offset ( offset ) . limit ( limit ) . to_a
59
+
60
+ polymorphic_association , preload_loads = analyze_associations ( @resource )
61
+ if polymorphic_association && Rails ::VERSION ::MAJOR >= 7
62
+ # TODO
63
+ end
64
+
65
+ preload_cross_database_associations ( records , preload_loads )
66
+
67
+ records
68
+ end
69
+
70
+ def preload_cross_database_associations ( records , preload_loads )
71
+ preload_loads . each do |association_name |
72
+ association = @resource . reflect_on_association ( association_name )
73
+ next unless separate_database? ( @resource , association )
74
+
75
+ columns = columns_for_cross_database_association ( association_name )
76
+
77
+ if association . macro == :belongs_to
78
+ foreign_key = association . foreign_key
79
+ primary_key = association . klass . primary_key
80
+
81
+ ids = records . map { |r | r . public_send ( foreign_key ) } . compact . uniq
82
+ next if ids . empty?
83
+
84
+ associated = association . klass . where ( primary_key => ids )
85
+ . select ( columns )
86
+ . index_by { |record | record . public_send ( primary_key ) }
87
+
88
+ records . each do |record |
89
+ record . define_singleton_method ( association_name ) do
90
+ associated [ record . send ( foreign_key . to_sym ) ] || nil
91
+ end
92
+ end
93
+ end
94
+
95
+ if association . macro == :has_one
96
+ foreign_key = association . foreign_key
97
+ primary_key = association . active_record_primary_key
98
+
99
+ ids = records . map { |r | r . public_send ( primary_key ) } . compact . uniq
100
+ next if ids . empty?
101
+
102
+ associated = association . klass . where ( foreign_key => ids )
103
+ . select ( columns )
104
+ . index_by { |record | record . public_send ( foreign_key . to_sym ) }
105
+
106
+ records . each do |record |
107
+ record . define_singleton_method ( association_name ) do
108
+ associated [ record . send ( primary_key . to_sym ) ] || nil
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ def columns_for_cross_database_association ( association_name )
116
+ return [ :id ] unless @params [ :fields ] . present?
117
+
118
+ fields = @params [ :fields ] [ association_name . to_s ]
119
+ return [ :id ] unless fields
120
+
121
+ base_fields = fields . split ( ',' ) . map ( &:strip ) . map ( &:to_sym ) | [ :id ]
122
+
123
+ association = @resource . reflect_on_association ( association_name )
124
+ extra_key = association . foreign_key
125
+
126
+ # Add the foreign key used for the association to ensure it's available in the preloaded records
127
+ # This is necessary for has_one associations, without it calling record.public_send(foreign_key) would raise a "missing attribute" error
128
+ base_fields << extra_key if association . macro == :has_one
129
+
130
+ base_fields . uniq
59
131
end
60
132
61
133
def compute_includes
0 commit comments