Skip to content

Commit 3d98753

Browse files
authored
fix: prevent error accessing foreign_collection on polymorphic relations (#211)
1 parent 36bc8c8 commit 3d98753

File tree

2 files changed

+120
-1
lines changed

2 files changed

+120
-1
lines changed

packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/relation/relation_collection_decorator.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ def re_project_in_place(caller, records, projection)
240240

241241
def re_project_relation_in_place(caller, records, name, projection)
242242
field_schema = schema[:fields][name]
243+
244+
return if field_schema.type == 'PolymorphicManyToOne'
245+
243246
association = datasource.get_collection(field_schema.foreign_collection)
244247

245248
if !@relations[name]

packages/forest_admin_datasource_customizer/spec/lib/forest_admin_datasource_customizer/decorators/relation/relation_collection_decorator_spec.rb

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,40 @@ module Relation
4545
{ 'id' => 203, 'other_id' => 203, 'name' => 'Joseph P. Rodriguez' }
4646
]
4747
end
48+
let(:comment_records) do
49+
[
50+
{
51+
'id' => 301,
52+
'text' => 'Great!',
53+
'commentable_id' => 101,
54+
'commentable_type' => 'passport',
55+
'commentable' => { 'commentable_id' => 101, 'commentable_type' => 'passport' }
56+
},
57+
{
58+
'id' => 302,
59+
'text' => 'Nice',
60+
'commentable_id' => 201,
61+
'commentable_type' => 'person',
62+
'commentable' => { 'commentable_id' => 201, 'commentable_type' => 'person' }
63+
}
64+
]
65+
end
66+
let(:address_records) do
67+
[
68+
{
69+
'id' => 401,
70+
'street' => '123 Main St',
71+
'addressable_id' => 201,
72+
'addressable_type' => 'person'
73+
},
74+
{
75+
'id' => 402,
76+
'street' => '456 Oak Ave',
77+
'addressable_id' => 202,
78+
'addressable_type' => 'person'
79+
}
80+
]
81+
end
4882

4983
before do
5084
datasource = Datasource.new
@@ -84,13 +118,40 @@ module Relation
84118
aggregation.apply(passport_records, caller.timezone, limit)
85119
end
86120

121+
collection_address = build_collection(
122+
name: 'address',
123+
schema: {
124+
fields: {
125+
'id' => ColumnSchema.new(column_type: PrimitiveType::NUMBER, is_primary_key: true, filter_operators: [Operators::EQUAL, Operators::IN]),
126+
'street' => ColumnSchema.new(column_type: PrimitiveType::STRING),
127+
'addressable_id' => ColumnSchema.new(column_type: PrimitiveType::NUMBER, filter_operators: [Operators::IN]),
128+
'addressable_type' => ColumnSchema.new(column_type: PrimitiveType::STRING)
129+
}
130+
},
131+
datasource: datasource
132+
)
133+
134+
allow(collection_address).to receive(:list) do |_caller, filter, projection|
135+
result = ForestAdminDatasourceToolkit::Utils::HashHelper.convert_keys(address_records, :to_s)
136+
result = filter.condition_tree.apply(result, collection_address, 'Europe/Paris') if filter&.condition_tree
137+
138+
projection.apply(result)
139+
end
140+
87141
collection_person = build_collection(
88142
name: 'person',
89143
schema: {
90144
fields: {
91145
'id' => ColumnSchema.new(column_type: PrimitiveType::NUMBER, is_primary_key: true, filter_operators: [Operators::EQUAL, Operators::IN]),
92146
'other_id' => ColumnSchema.new(column_type: PrimitiveType::NUMBER, filter_operators: [Operators::IN]),
93-
'name' => ColumnSchema.new(column_type: PrimitiveType::STRING, filter_operators: [Operators::IN])
147+
'name' => ColumnSchema.new(column_type: PrimitiveType::STRING, filter_operators: [Operators::IN]),
148+
'address' => Relations::PolymorphicOneToOneSchema.new(
149+
origin_key: 'addressable_id',
150+
origin_key_target: 'id',
151+
foreign_collection: 'address',
152+
origin_type_field: 'addressable_type',
153+
origin_type_value: 'person'
154+
)
94155
}
95156
},
96157
datasource: datasource
@@ -107,9 +168,37 @@ module Relation
107168
aggregation.apply(person_records, caller.timezone, limit)
108169
end
109170

171+
collection_comment = build_collection(
172+
name: 'comment',
173+
schema: {
174+
fields: {
175+
'id' => ColumnSchema.new(column_type: PrimitiveType::NUMBER, is_primary_key: true, filter_operators: [Operators::EQUAL, Operators::IN]),
176+
'text' => ColumnSchema.new(column_type: PrimitiveType::STRING),
177+
'commentable_id' => ColumnSchema.new(column_type: PrimitiveType::NUMBER, filter_operators: [Operators::IN]),
178+
'commentable_type' => ColumnSchema.new(column_type: PrimitiveType::STRING),
179+
'commentable' => Relations::PolymorphicManyToOneSchema.new(
180+
foreign_key_type_field: 'commentable_type',
181+
foreign_key: 'commentable_id',
182+
foreign_key_targets: { 'passport' => 'id', 'person' => 'id' },
183+
foreign_collections: %w[passport person]
184+
)
185+
}
186+
},
187+
datasource: datasource
188+
)
189+
190+
allow(collection_comment).to receive(:list) do |_caller, filter, projection|
191+
result = ForestAdminDatasourceToolkit::Utils::HashHelper.convert_keys(comment_records, :to_s)
192+
result = filter.condition_tree.apply(result, collection_comment, 'Europe/Paris') if filter&.condition_tree
193+
194+
projection.apply(result)
195+
end
196+
110197
datasource.add_collection(collection_picture)
111198
datasource.add_collection(collection_passport)
199+
datasource.add_collection(collection_address)
112200
datasource.add_collection(collection_person)
201+
datasource.add_collection(collection_comment)
113202

114203
@datasource_decorator = DatasourceDecorator.new(datasource, relation_collection_decorator)
115204
end
@@ -606,6 +695,33 @@ module Relation
606695
end
607696
end
608697
end
698+
699+
context 'with polymorphic relations' do
700+
it 'handles PolymorphicManyToOne without error' do
701+
records = @datasource_decorator.get_collection('comment').list(
702+
caller,
703+
Filter.new,
704+
Projection.new(%w[id text commentable:commentable_id])
705+
)
706+
707+
expect(records).to eq([
708+
{ 'id' => 301, 'text' => 'Great!', 'commentable' => { 'commentable_id' => 101 } },
709+
{ 'id' => 302, 'text' => 'Nice', 'commentable' => { 'commentable_id' => 201 } }
710+
])
711+
end
712+
713+
it 'handles PolymorphicOneToOne without error' do
714+
records = @datasource_decorator.get_collection('person').list(
715+
caller,
716+
Filter.new,
717+
Projection.new(%w[id name address:street])
718+
)
719+
720+
expect(records.length).to eq(3)
721+
expect(records.first).to have_key('id')
722+
expect(records.first).to have_key('name')
723+
end
724+
end
609725
end
610726
end
611727
end

0 commit comments

Comments
 (0)