forest_admin_datasource_active_record 1.34.2 → 1.35.0
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 04e8352c5b26a43ce466ea857586a38f235d32b38b252c4c37e51bef43e2f4f4
|
|
4
|
+
data.tar.gz: ffcfe8fd892725000f743ac15323015a35d06238680fb80b2c2467ee45b16afc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c8995e225a4300c5a25737a74715c35ddf991c4fdf8bef82722d25b89836cd2e2a1e42c35aabf905aa3bf538413e6e164e18f12f0effcb6a4211bfd2390c0c09
|
|
7
|
+
data.tar.gz: ad3209330ba9e93b06d98fafc26648b06eda6f80309f5b3373d5ff2c0fe28609430c63d9a3f93d75500edde838bae1fc476d43a2cca6009ac2868c9a86b0f1a6
|
|
@@ -100,21 +100,32 @@ module ForestAdminDatasourceActiveRecord
|
|
|
100
100
|
source_polymorphic = association.source_reflection&.polymorphic? &&
|
|
101
101
|
association.options[:source_type].present?
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
103
|
+
if is_polymorphic || source_polymorphic
|
|
104
|
+
add_field(
|
|
105
|
+
association.name.to_s,
|
|
106
|
+
ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
|
|
107
|
+
foreign_collection: format_model_name(association.klass.name),
|
|
108
|
+
origin_key: through_reflection.foreign_key,
|
|
109
|
+
origin_key_target: through_reflection.join_foreign_key,
|
|
110
|
+
foreign_key: association.join_foreign_key,
|
|
111
|
+
foreign_key_target: association.association_primary_key,
|
|
112
|
+
through_collection: format_model_name(through_reflection.klass.name),
|
|
113
|
+
origin_type_field: is_polymorphic ? through_reflection.type : nil,
|
|
114
|
+
origin_type_value: is_polymorphic ? @model.name : nil,
|
|
115
|
+
foreign_type_field: source_polymorphic ? association.source_reflection.foreign_type : nil,
|
|
116
|
+
foreign_type_value: source_polymorphic ? association.options[:source_type] : nil
|
|
117
|
+
)
|
|
116
118
|
)
|
|
117
|
-
|
|
119
|
+
else
|
|
120
|
+
add_field(
|
|
121
|
+
association.name.to_s,
|
|
122
|
+
ForestAdminDatasourceToolkit::Schema::Relations::OneToOneSchema.new(
|
|
123
|
+
foreign_collection: format_model_name(association.klass.name),
|
|
124
|
+
origin_key: association.klass.primary_key,
|
|
125
|
+
origin_key_target: @model.primary_key
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
end
|
|
118
129
|
elsif association.inverse_of&.polymorphic?
|
|
119
130
|
add_field(
|
|
120
131
|
association.name.to_s,
|
|
@@ -196,6 +196,10 @@ module ForestAdminDatasourceActiveRecord
|
|
|
196
196
|
if collection.model.table_name == @collection.model.table_name
|
|
197
197
|
if one_to_one_relations.include?(relation_schema.type)
|
|
198
198
|
@select << "#{collection.model.table_name}.#{relation_schema.origin_key_target}"
|
|
199
|
+
# foreign_key is an array for a composite-key belongs_to through hop
|
|
200
|
+
Array(root_through_foreign_key(collection, relation_name)).each do |through_fk|
|
|
201
|
+
@select << "#{collection.model.table_name}.#{through_fk}"
|
|
202
|
+
end
|
|
199
203
|
elsif many_to_one_relations.include?(relation_schema.type)
|
|
200
204
|
@select << "#{collection.model.table_name}.#{relation_schema.foreign_key}"
|
|
201
205
|
end
|
|
@@ -275,7 +279,7 @@ module ForestAdminDatasourceActiveRecord
|
|
|
275
279
|
target = joinable_target(collection, relation_name, used_tables)
|
|
276
280
|
return nil if target.nil?
|
|
277
281
|
|
|
278
|
-
tables = Set[target.model.table_name]
|
|
282
|
+
tables = Set[target.model.table_name] | through_tables(collection, relation_name)
|
|
279
283
|
sub_projection.relations.each do |nested_name, nested_projection|
|
|
280
284
|
nested = joinable_tables(target, nested_name, nested_projection, used_tables | tables)
|
|
281
285
|
return nil if nested.nil?
|
|
@@ -288,23 +292,50 @@ module ForestAdminDatasourceActiveRecord
|
|
|
288
292
|
# The target collection when this hop is safe to collapse into a JOIN, else nil (-> preload).
|
|
289
293
|
def joinable_target(collection, relation_name, used_tables)
|
|
290
294
|
relation_schema = collection.schema[:fields][relation_name]
|
|
291
|
-
|
|
292
|
-
# (a has_one child may not be unique)
|
|
293
|
-
return unless relation_schema.type == 'ManyToOne' && relation_schema.respond_to?(:foreign_collection)
|
|
295
|
+
return unless relation_schema.respond_to?(:foreign_collection)
|
|
294
296
|
|
|
295
297
|
# a scoped association applies its scope to the JOIN and may inject raw/unqualified SQL or
|
|
296
298
|
# extra joins (e.g. `belongs_to :x, -> { where('id > ?', 1) }`)
|
|
297
299
|
reflection = collection.model.reflect_on_association(relation_name.to_sym)
|
|
298
300
|
return if reflection.nil? || reflection.scope
|
|
299
301
|
|
|
302
|
+
case relation_schema.type
|
|
303
|
+
when 'ManyToOne' then nil
|
|
304
|
+
when 'OneToOne' then return unless belongs_to_chain_through?(reflection)
|
|
305
|
+
else return
|
|
306
|
+
end
|
|
307
|
+
|
|
300
308
|
target = local_ar_collection(collection.datasource, relation_schema.foreign_collection)
|
|
301
309
|
return if target.nil? || !target.model.default_scopes.empty? # same risk as a scoped association
|
|
302
310
|
return unless same_database?(collection.model, target.model)
|
|
303
311
|
return if used_tables.include?(target.model.table_name) # a table joined twice would be aliased by AR
|
|
312
|
+
return if through_tables(collection, relation_name).intersect?(used_tables)
|
|
304
313
|
|
|
305
314
|
target
|
|
306
315
|
end
|
|
307
316
|
|
|
317
|
+
def through_tables(collection, relation_name)
|
|
318
|
+
through = collection.model.reflect_on_association(relation_name.to_sym)&.through_reflection
|
|
319
|
+
return Set[] unless through
|
|
320
|
+
|
|
321
|
+
Set[through.table_name]
|
|
322
|
+
rescue StandardError
|
|
323
|
+
Set[]
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def belongs_to_chain_through?(reflection)
|
|
327
|
+
return false unless reflection.through_reflection?
|
|
328
|
+
|
|
329
|
+
through = reflection.through_reflection
|
|
330
|
+
source = reflection.source_reflection
|
|
331
|
+
|
|
332
|
+
through && source && through.belongs_to? && source.belongs_to? &&
|
|
333
|
+
through.scope.nil? && source.scope.nil? && through.klass.default_scopes.empty? &&
|
|
334
|
+
same_database?(reflection.active_record, through.klass)
|
|
335
|
+
rescue StandardError
|
|
336
|
+
false
|
|
337
|
+
end
|
|
338
|
+
|
|
308
339
|
def same_database?(model_a, model_b)
|
|
309
340
|
# compare the pools, not connection_specification_name (only an owner class name, shared across shards)
|
|
310
341
|
model_a.connection_pool == model_b.connection_pool
|
|
@@ -330,6 +361,15 @@ module ForestAdminDatasourceActiveRecord
|
|
|
330
361
|
@query
|
|
331
362
|
end
|
|
332
363
|
|
|
364
|
+
def root_through_foreign_key(collection, relation_name)
|
|
365
|
+
through = collection.model.reflect_on_association(relation_name.to_sym)&.through_reflection
|
|
366
|
+
return unless through&.belongs_to?
|
|
367
|
+
|
|
368
|
+
through.foreign_key
|
|
369
|
+
rescue StandardError
|
|
370
|
+
nil
|
|
371
|
+
end
|
|
372
|
+
|
|
333
373
|
def resolve_field(original_field)
|
|
334
374
|
if original_field.include?(':')
|
|
335
375
|
relation_name, column_name = original_field.split(':')
|