forest_admin_agent 1.0.0.pre.beta.60 → 1.0.0.pre.beta.62
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 +4 -4
- data/lib/forest_admin_agent/routes/abstract_authenticated_route.rb +1 -1
- data/lib/forest_admin_agent/routes/abstract_related_route.rb +5 -1
- data/lib/forest_admin_agent/routes/resources/delete.rb +19 -0
- data/lib/forest_admin_agent/routes/resources/list.rb +1 -1
- data/lib/forest_admin_agent/routes/resources/related/associate_related.rb +26 -2
- data/lib/forest_admin_agent/routes/resources/related/dissociate_related.rb +7 -2
- data/lib/forest_admin_agent/routes/resources/related/update_related.rb +104 -12
- data/lib/forest_admin_agent/routes/resources/show.rb +1 -1
- data/lib/forest_admin_agent/routes/resources/store.rb +11 -3
- data/lib/forest_admin_agent/serializer/forest_serializer.rb +33 -14
- data/lib/forest_admin_agent/serializer/forest_serializer_override.rb +12 -2
- data/lib/forest_admin_agent/utils/query_string_parser.rb +7 -1
- data/lib/forest_admin_agent/utils/schema/generator_field.rb +44 -18
- data/lib/forest_admin_agent/utils/schema/schema_emitter.rb +1 -1
- data/lib/forest_admin_agent/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8094394fa87dd1d0c83fac337a16804b9aefa3592bf3398b4ae859a45de031af
|
4
|
+
data.tar.gz: 38438b2a1f495a1b448796e742189103a8180bb8322735ae5b88708557da505b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce0cf6bfd2a8da01400c0f12ee772e2274327613c3dcb4c89806415b1f13602b3c8e5fa397ad7f75dcbc511657ab3ebb7bb1f3e1555ba9dc2dcfb3f1186a2822
|
7
|
+
data.tar.gz: 2b1d5f879c66af69ccd73aa160261fd4c293a39cfdee463e536dc7efd8e367f4eca979e7231a517d7895607425b9f0580b2f835a1d3b2001caeb34b8c4eb6351
|
@@ -5,7 +5,11 @@ module ForestAdminAgent
|
|
5
5
|
super
|
6
6
|
|
7
7
|
relation = @collection.schema[:fields][args[:params]['relation_name']]
|
8
|
-
@child_collection =
|
8
|
+
@child_collection = if relation.type == 'PolymorphicManyToOne'
|
9
|
+
@datasource.get_collection(args[:params]['data']['type'])
|
10
|
+
else
|
11
|
+
@datasource.get_collection(relation.foreign_collection)
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
11
15
|
end
|
@@ -37,6 +37,25 @@ module ForestAdminAgent
|
|
37
37
|
def delete_records(args, selection_ids)
|
38
38
|
condition_tree_ids = ConditionTree::ConditionTreeFactory.match_records(@collection, selection_ids[:ids])
|
39
39
|
condition_tree_ids = condition_tree_ids.inverse if selection_ids[:are_excluded]
|
40
|
+
|
41
|
+
@collection.schema[:fields].each_value do |field_schema|
|
42
|
+
next unless field_schema.type == 'PolymorphicOneToOne' || field_schema.type == 'PolymorphicOneToMany'
|
43
|
+
|
44
|
+
condition_tree = Nodes::ConditionTreeBranch.new(
|
45
|
+
'And',
|
46
|
+
[
|
47
|
+
Nodes::ConditionTreeLeaf.new(field_schema.origin_key, Operators::IN,
|
48
|
+
selection_ids[:ids].map { |value| value['id'] }),
|
49
|
+
Nodes::ConditionTreeLeaf.new(field_schema.origin_type_field, Operators::EQUAL,
|
50
|
+
@collection.name.gsub('__', '::'))
|
51
|
+
]
|
52
|
+
)
|
53
|
+
filter = Filter.new(condition_tree: condition_tree)
|
54
|
+
@datasource.get_collection(field_schema.foreign_collection)
|
55
|
+
.update(@caller, filter, { field_schema.origin_key => nil,
|
56
|
+
field_schema.origin_type_field => nil })
|
57
|
+
end
|
58
|
+
|
40
59
|
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
41
60
|
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
42
61
|
[
|
@@ -38,7 +38,7 @@ module ForestAdminAgent
|
|
38
38
|
class_name: @collection.name,
|
39
39
|
is_collection: true,
|
40
40
|
serializer: Serializer::ForestSerializer,
|
41
|
-
include: projection.relations
|
41
|
+
include: projection.relations(only_keys: true),
|
42
42
|
meta: handle_search_decorator(args[:params]['search'], records)
|
43
43
|
)
|
44
44
|
}
|
@@ -28,10 +28,13 @@ module ForestAdminAgent
|
|
28
28
|
target_relation_id = Utils::Id.unpack_id(@child_collection, args[:params]['data'][0]['id'], with_key: true)
|
29
29
|
relation = Schema.get_to_many_relation(@collection, args[:params]['relation_name'])
|
30
30
|
|
31
|
-
|
31
|
+
case relation.type
|
32
|
+
when 'OneToMany'
|
32
33
|
associate_one_to_many(relation, parent_id, target_relation_id)
|
33
|
-
|
34
|
+
when 'ManyToMany'
|
34
35
|
associate_many_to_many(relation, parent_id, target_relation_id)
|
36
|
+
when 'PolymorphicOneToMany'
|
37
|
+
associate_polymorphic_one_to_many(relation, parent_id, target_relation_id)
|
35
38
|
end
|
36
39
|
|
37
40
|
{ content: nil, status: 204 }
|
@@ -55,6 +58,27 @@ module ForestAdminAgent
|
|
55
58
|
@child_collection.update(@caller, filter, { relation.origin_key => value })
|
56
59
|
end
|
57
60
|
|
61
|
+
def associate_polymorphic_one_to_many(relation, parent_id, target_relation_id)
|
62
|
+
id = Schema.primary_keys(@child_collection)[0]
|
63
|
+
value = Collection.get_value(@child_collection, @caller, target_relation_id, id)
|
64
|
+
filter = Filter.new(
|
65
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
66
|
+
[
|
67
|
+
ConditionTree::Nodes::ConditionTreeLeaf.new(id, 'Equal', value),
|
68
|
+
@permissions.get_scope(@collection)
|
69
|
+
]
|
70
|
+
)
|
71
|
+
)
|
72
|
+
|
73
|
+
value = Collection.get_value(@collection, @caller, parent_id, relation.origin_key_target)
|
74
|
+
|
75
|
+
@child_collection.update(
|
76
|
+
@caller,
|
77
|
+
filter,
|
78
|
+
{ relation.origin_key => value, relation.origin_type_field => @collection.name.gsub('__', '::') }
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
58
82
|
def associate_many_to_many(relation, parent_id, target_relation_id)
|
59
83
|
id = Schema.primary_keys(@child_collection)[0]
|
60
84
|
foreign_value = Collection.get_value(@child_collection, @caller, target_relation_id, id)
|
@@ -28,7 +28,7 @@ module ForestAdminAgent
|
|
28
28
|
filter = get_base_foreign_filter(args)
|
29
29
|
relation = Schema.get_to_many_relation(@collection, args[:params]['relation_name'])
|
30
30
|
|
31
|
-
if relation.type == 'OneToMany'
|
31
|
+
if relation.type == 'OneToMany' || relation.type == 'PolymorphicOneToMany'
|
32
32
|
dissociate_or_delete_one_to_many(relation, args[:params]['relation_name'], parent_id, is_delete_mode,
|
33
33
|
filter)
|
34
34
|
else
|
@@ -47,7 +47,12 @@ module ForestAdminAgent
|
|
47
47
|
if is_delete_mode
|
48
48
|
@child_collection.delete(@caller, foreign_filter)
|
49
49
|
else
|
50
|
-
|
50
|
+
patch = if relation.type == 'PolymorphicOneToMany'
|
51
|
+
{ relation.origin_key => nil, relation.origin_type_field => nil }
|
52
|
+
else
|
53
|
+
{ relation.origin_key => nil }
|
54
|
+
end
|
55
|
+
@child_collection.update(@caller, foreign_filter, patch)
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
@@ -8,6 +8,7 @@ module ForestAdminAgent
|
|
8
8
|
include ForestAdminAgent::Builder
|
9
9
|
include ForestAdminDatasourceToolkit::Utils
|
10
10
|
include ForestAdminDatasourceToolkit::Components::Query
|
11
|
+
|
11
12
|
def setup_routes
|
12
13
|
add_route(
|
13
14
|
'forest_related_update',
|
@@ -26,14 +27,19 @@ module ForestAdminAgent
|
|
26
27
|
relation = @collection.schema[:fields][args[:params]['relation_name']]
|
27
28
|
parent_id = Utils::Id.unpack_id(@collection, args[:params]['id'])
|
28
29
|
|
29
|
-
linked_id = if (id = args.dig(:params,
|
30
|
+
linked_id = if (id = args.dig(:params, 'data', 'id'))
|
30
31
|
Utils::Id.unpack_id(@child_collection, id)
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
+
case relation.type
|
35
|
+
when 'ManyToOne'
|
34
36
|
update_many_to_one(relation, parent_id, linked_id)
|
35
|
-
|
37
|
+
when 'PolymorphicManyToOne'
|
38
|
+
update_polymorphic_many_to_one(relation, parent_id, linked_id)
|
39
|
+
when 'OneToOne'
|
36
40
|
update_one_to_one(relation, parent_id, linked_id)
|
41
|
+
when 'PolymorphicOneToOne'
|
42
|
+
update_polymorphic_one_to_one(relation, parent_id, linked_id)
|
37
43
|
end
|
38
44
|
|
39
45
|
{ content: nil, status: 204 }
|
@@ -49,16 +55,104 @@ module ForestAdminAgent
|
|
49
55
|
@collection.update(@caller, Filter.new(condition_tree: fk_owner), { relation.foreign_key => foreign_value })
|
50
56
|
end
|
51
57
|
|
58
|
+
def update_polymorphic_many_to_one(relation, parent_id, linked_id)
|
59
|
+
foreign_value = if linked_id
|
60
|
+
Collection.get_value(
|
61
|
+
@child_collection,
|
62
|
+
@caller,
|
63
|
+
linked_id,
|
64
|
+
relation.foreign_key_targets[@child_collection.name]
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
polymorphic_type = @child_collection.name.gsub('__', '::')
|
69
|
+
fk_owner = ConditionTree::ConditionTreeFactory.match_ids(@collection, [parent_id])
|
70
|
+
@collection.update(
|
71
|
+
@caller,
|
72
|
+
Filter.new(condition_tree: fk_owner),
|
73
|
+
{
|
74
|
+
relation.foreign_key => foreign_value,
|
75
|
+
relation.foreign_key_type_field => polymorphic_type
|
76
|
+
}
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def update_polymorphic_one_to_one(relation, parent_id, linked_id)
|
81
|
+
origin_value = Collection.get_value(@collection, @caller, parent_id, relation.origin_key_target)
|
82
|
+
|
83
|
+
break_old_polymorphic_one_to_one_relationship(relation, origin_value, linked_id)
|
84
|
+
create_new_polymorphic_one_to_one_relationship(relation, origin_value, linked_id)
|
85
|
+
end
|
86
|
+
|
52
87
|
def update_one_to_one(relation, parent_id, linked_id)
|
53
88
|
origin_value = Collection.get_value(@collection, @caller, parent_id, relation.origin_key_target)
|
54
89
|
|
55
|
-
break_old_one_to_one_relationship(
|
56
|
-
create_new_one_to_one_relationship(
|
90
|
+
break_old_one_to_one_relationship(relation, origin_value, linked_id)
|
91
|
+
create_new_one_to_one_relationship(relation, origin_value, linked_id)
|
57
92
|
end
|
58
93
|
|
59
|
-
def
|
94
|
+
def break_old_polymorphic_one_to_one_relationship(relation, origin_value, linked_id)
|
60
95
|
linked_id ||= []
|
61
96
|
|
97
|
+
old_fk_owner_filter = Filter.new(
|
98
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
99
|
+
[
|
100
|
+
@permissions.get_scope(@collection),
|
101
|
+
ConditionTree::Nodes::ConditionTreeBranch.new(
|
102
|
+
'And',
|
103
|
+
[
|
104
|
+
ConditionTree::Nodes::ConditionTreeLeaf.new(
|
105
|
+
relation.origin_key,
|
106
|
+
ConditionTree::Operators::EQUAL,
|
107
|
+
origin_value
|
108
|
+
),
|
109
|
+
ConditionTree::Nodes::ConditionTreeLeaf.new(
|
110
|
+
relation.origin_type_field,
|
111
|
+
ConditionTree::Operators::EQUAL,
|
112
|
+
@collection.name.gsub('__', '::')
|
113
|
+
)
|
114
|
+
]
|
115
|
+
),
|
116
|
+
# Don't set the new record's field to null
|
117
|
+
# if it's already initialized with the right value
|
118
|
+
ConditionTree::ConditionTreeFactory.match_ids(@child_collection, [linked_id]).inverse
|
119
|
+
]
|
120
|
+
)
|
121
|
+
)
|
122
|
+
|
123
|
+
result = @child_collection.aggregate(@caller, old_fk_owner_filter, Aggregation.new(operation: 'Count'), 1)
|
124
|
+
return unless !(result[0]['value']).nil? && (result[0]['value']).positive?
|
125
|
+
|
126
|
+
# Avoids updating records to null if it's not authorized by the ORM
|
127
|
+
# and if there is no record to update (the filter returns no record)
|
128
|
+
|
129
|
+
@child_collection.update(
|
130
|
+
@caller,
|
131
|
+
old_fk_owner_filter,
|
132
|
+
{ relation.origin_key => nil, relation.origin_type_field => nil }
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
def create_new_polymorphic_one_to_one_relationship(relation, origin_value, linked_id)
|
137
|
+
return unless linked_id
|
138
|
+
|
139
|
+
new_fk_owner = ConditionTree::ConditionTreeFactory.match_ids(@child_collection, [linked_id])
|
140
|
+
|
141
|
+
@child_collection.update(
|
142
|
+
@caller,
|
143
|
+
Filter.new(
|
144
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
145
|
+
[
|
146
|
+
@permissions.get_scope(@collection), new_fk_owner
|
147
|
+
]
|
148
|
+
)
|
149
|
+
),
|
150
|
+
{ relation.origin_key => origin_value, relation.origin_type_field => @collection.name.gsub('__', '::') }
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
def break_old_one_to_one_relationship(relation, origin_value, linked_id)
|
155
|
+
linked_id ||= []
|
62
156
|
old_fk_owner_filter = Filter.new(
|
63
157
|
condition_tree: ConditionTree::ConditionTreeFactory.intersect(
|
64
158
|
[
|
@@ -67,18 +161,16 @@ module ForestAdminAgent
|
|
67
161
|
relation.origin_key,
|
68
162
|
ConditionTree::Operators::EQUAL,
|
69
163
|
origin_value
|
70
|
-
)
|
71
|
-
].push(
|
164
|
+
),
|
72
165
|
# Don't set the new record's field to null
|
73
166
|
# if it's already initialized with the right value
|
74
167
|
ConditionTree::ConditionTreeFactory.match_ids(@child_collection, [linked_id]).inverse
|
75
|
-
|
168
|
+
]
|
76
169
|
)
|
77
170
|
)
|
78
171
|
|
79
172
|
result = @child_collection.aggregate(@caller, old_fk_owner_filter, Aggregation.new(operation: 'Count'), 1)
|
80
|
-
|
81
|
-
return unless (result[0][:value]).positive?
|
173
|
+
return unless !(result[0]['value']).nil? && (result[0]['value']).positive?
|
82
174
|
|
83
175
|
# Avoids updating records to null if it's not authorized by the ORM
|
84
176
|
# and if there is no record to update (the filter returns no record)
|
@@ -86,7 +178,7 @@ module ForestAdminAgent
|
|
86
178
|
@child_collection.update(@caller, old_fk_owner_filter, { relation.origin_key => nil })
|
87
179
|
end
|
88
180
|
|
89
|
-
def create_new_one_to_one_relationship(
|
181
|
+
def create_new_one_to_one_relationship(relation, origin_value, linked_id)
|
90
182
|
return unless linked_id
|
91
183
|
|
92
184
|
new_fk_owner = ConditionTree::ConditionTreeFactory.match_ids(@child_collection, [linked_id])
|
@@ -20,10 +20,16 @@ module ForestAdminAgent
|
|
20
20
|
record = @collection.create(@caller, data)
|
21
21
|
link_one_to_one_relations(args, record)
|
22
22
|
|
23
|
+
id = Utils::Id.unpack_id(@collection, record['id'], with_key: true)
|
24
|
+
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
25
|
+
condition_tree: ConditionTree::ConditionTreeFactory.match_records(@collection, [id])
|
26
|
+
)
|
27
|
+
records = @collection.list(@caller, filter, ProjectionFactory.all(@collection))
|
28
|
+
|
23
29
|
{
|
24
30
|
name: args[:params]['collection_name'],
|
25
31
|
content: JSONAPI::Serializer.serialize(
|
26
|
-
|
32
|
+
records[0],
|
27
33
|
is_collection: false,
|
28
34
|
class_name: @collection.name,
|
29
35
|
serializer: Serializer::ForestSerializer
|
@@ -34,7 +40,7 @@ module ForestAdminAgent
|
|
34
40
|
def link_one_to_one_relations(args, record)
|
35
41
|
args[:params][:data][:relationships]&.map do |field, value|
|
36
42
|
schema = @collection.schema[:fields][field]
|
37
|
-
next unless schema.type == 'OneToOne'
|
43
|
+
next unless schema.type == 'OneToOne' || schema.type == 'PolymorphicOneToOne'
|
38
44
|
|
39
45
|
id = Utils::Id.unpack_id(@collection, value['data']['id'], with_key: true)
|
40
46
|
foreign_collection = @datasource.get_collection(schema.foreign_collection)
|
@@ -42,9 +48,11 @@ module ForestAdminAgent
|
|
42
48
|
origin_value = record[schema.origin_key_target]
|
43
49
|
|
44
50
|
# update new relation (may update zero or one records).
|
51
|
+
patch = { schema.origin_key => origin_value }
|
52
|
+
patch[schema.origin_type_field] = @collection.name.gsub('__', '::') if schema.type == 'PolymorphicOneToOne'
|
45
53
|
condition_tree = ConditionTree::ConditionTreeFactory.match_records(foreign_collection, [id])
|
46
54
|
filter = Filter.new(condition_tree: condition_tree)
|
47
|
-
foreign_collection.update(@caller, filter,
|
55
|
+
foreign_collection.update(@caller, filter, patch)
|
48
56
|
end
|
49
57
|
end
|
50
58
|
end
|
@@ -21,11 +21,13 @@ module ForestAdminAgent
|
|
21
21
|
|
22
22
|
def type
|
23
23
|
class_name = @options[:class_name]
|
24
|
-
@@class_names[class_name] ||= class_name
|
24
|
+
@@class_names[class_name] ||= class_name.gsub('::', '__')
|
25
25
|
end
|
26
26
|
|
27
27
|
def id
|
28
|
-
forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(
|
28
|
+
forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(
|
29
|
+
@options[:class_name].gsub('::', '__')
|
30
|
+
)
|
29
31
|
primary_keys = ForestAdminDatasourceToolkit::Utils::Schema.primary_keys(forest_collection)
|
30
32
|
id = []
|
31
33
|
primary_keys.each { |key| id << @object[key] }
|
@@ -50,7 +52,9 @@ module ForestAdminAgent
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def attributes
|
53
|
-
forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(
|
55
|
+
forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(
|
56
|
+
@options[:class_name].gsub('::', '__')
|
57
|
+
)
|
54
58
|
fields = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'Column' }
|
55
59
|
fields.each { |field_name, _field| add_attribute(field_name) }
|
56
60
|
return {} if attributes_map.nil?
|
@@ -110,9 +114,13 @@ module ForestAdminAgent
|
|
110
114
|
|
111
115
|
def relationships
|
112
116
|
datasource = ForestAdminAgent::Facades::Container.datasource
|
113
|
-
forest_collection = datasource.get_collection(@options[:class_name])
|
114
|
-
relations_to_many = forest_collection.schema[:fields].select
|
115
|
-
|
117
|
+
forest_collection = datasource.get_collection(@options[:class_name].gsub('::', '__'))
|
118
|
+
relations_to_many = forest_collection.schema[:fields].select do |_field_name, field|
|
119
|
+
%w[OneToMany ManyToMany PolymorphicOneToMany].include?(field.type)
|
120
|
+
end
|
121
|
+
relations_to_one = forest_collection.schema[:fields].select do |_field_name, field|
|
122
|
+
%w[OneToOne ManyToOne PolymorphicManyToOne PolymorphicOneToOne].include?(field.type)
|
123
|
+
end
|
116
124
|
|
117
125
|
relations_to_one.each { |field_name, _field| add_to_one_association(field_name) }
|
118
126
|
|
@@ -133,14 +141,24 @@ module ForestAdminAgent
|
|
133
141
|
if object.nil? || object.empty?
|
134
142
|
data[formatted_attribute_name]['data'] = nil
|
135
143
|
else
|
136
|
-
relation = datasource.get_collection(@options[:class_name])
|
144
|
+
relation = datasource.get_collection(@options[:class_name].gsub('::', '__'))
|
145
|
+
.schema[:fields][attribute_name.to_s]
|
137
146
|
options = @options.clone
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
'
|
142
|
-
|
143
|
-
|
147
|
+
if relation.type == 'PolymorphicManyToOne'
|
148
|
+
options[:class_name] = @object[relation.foreign_key_type_field]
|
149
|
+
related_object_serializer = ForestSerializer.new(object, options)
|
150
|
+
data[formatted_attribute_name]['data'] = {
|
151
|
+
'type' => related_object_serializer.type.to_s,
|
152
|
+
'id' => related_object_serializer.id.to_s,
|
153
|
+
}
|
154
|
+
else
|
155
|
+
options[:class_name] = datasource.get_collection(relation.foreign_collection).name
|
156
|
+
related_object_serializer = ForestSerializer.new(object, options)
|
157
|
+
data[formatted_attribute_name]['data'] = {
|
158
|
+
'type' => related_object_serializer.type.to_s,
|
159
|
+
'id' => related_object_serializer.id.to_s,
|
160
|
+
}
|
161
|
+
end
|
144
162
|
end
|
145
163
|
end
|
146
164
|
|
@@ -161,7 +179,7 @@ module ForestAdminAgent
|
|
161
179
|
if @_include_linkages.include?(formatted_attribute_name) || attr_data[:options][:include_data]
|
162
180
|
data[formatted_attribute_name]['data'] = []
|
163
181
|
objects = has_many_relationship(attribute_name, attr_data) || []
|
164
|
-
relation = datasource.get_collection(@options[:class_name]).schema[:fields][attribute_name.to_s]
|
182
|
+
relation = datasource.get_collection(@options[:class_name].gsub('::', '__')).schema[:fields][attribute_name.to_s]
|
165
183
|
options = @options.clone
|
166
184
|
options[:class_name] = datasource.get_collection(relation.foreign_collection).name
|
167
185
|
objects.each do |obj|
|
@@ -173,6 +191,7 @@ module ForestAdminAgent
|
|
173
191
|
end
|
174
192
|
end
|
175
193
|
end
|
194
|
+
|
176
195
|
data
|
177
196
|
end
|
178
197
|
|
@@ -25,6 +25,7 @@ module ForestAdminAgent
|
|
25
25
|
object = nil
|
26
26
|
is_collection = false
|
27
27
|
is_valid_attr = false
|
28
|
+
|
28
29
|
if serializer.has_one_relationships.key?(unformatted_attr_name)
|
29
30
|
is_valid_attr = true
|
30
31
|
attr_data = serializer.has_one_relationships[unformatted_attr_name]
|
@@ -58,8 +59,15 @@ module ForestAdminAgent
|
|
58
59
|
# If it is not set, that indicates that this is an inner path and not a leaf and will
|
59
60
|
# be followed by the recursion below.
|
60
61
|
objects.each do |obj|
|
61
|
-
relation = ForestAdminAgent::Facades::Container.datasource
|
62
|
-
|
62
|
+
relation = ForestAdminAgent::Facades::Container.datasource
|
63
|
+
.get_collection(options[:class_name].gsub('::', '__'))
|
64
|
+
.schema[:fields][attribute_name]
|
65
|
+
if relation.type == 'PolymorphicManyToOne'
|
66
|
+
relation_class_name = root_object[relation.foreign_key_type_field]
|
67
|
+
else
|
68
|
+
relation_class_name = ForestAdminAgent::Facades::Container.datasource.get_collection(relation.foreign_collection).name
|
69
|
+
end
|
70
|
+
|
63
71
|
option_relation = options.clone
|
64
72
|
option_relation[:class_name] = relation_class_name
|
65
73
|
obj_serializer = JSONAPI::Serializer.find_serializer(obj, option_relation)
|
@@ -203,6 +211,7 @@ module ForestAdminAgent
|
|
203
211
|
# of the internal special merging logic.
|
204
212
|
find_recursive_relationships(obj, inclusion_tree, relationship_data, passthrough_options)
|
205
213
|
end
|
214
|
+
|
206
215
|
result['included'] = relationship_data.map do |_, data|
|
207
216
|
included_passthrough_options = {}
|
208
217
|
included_passthrough_options[:base_url] = passthrough_options[:base_url]
|
@@ -216,6 +225,7 @@ module ForestAdminAgent
|
|
216
225
|
serialize_primary(data[:object], included_passthrough_options)
|
217
226
|
end
|
218
227
|
end
|
228
|
+
|
219
229
|
result
|
220
230
|
end
|
221
231
|
end
|
@@ -60,7 +60,13 @@ module ForestAdminAgent
|
|
60
60
|
|
61
61
|
fields = fields.split(',').map do |field_name|
|
62
62
|
column = collection.schema[:fields][field_name.strip]
|
63
|
-
column.type == 'Column'
|
63
|
+
if column.type == 'Column'
|
64
|
+
field_name.strip
|
65
|
+
elsif column.type == 'PolymorphicManyToOne'
|
66
|
+
"#{field_name.strip}:*"
|
67
|
+
else
|
68
|
+
"#{field_name.strip}:#{args[:params][:fields][field_name.strip]}"
|
69
|
+
end
|
64
70
|
end
|
65
71
|
|
66
72
|
Projection.new(fields)
|
@@ -4,20 +4,22 @@ module ForestAdminAgent
|
|
4
4
|
class GeneratorField
|
5
5
|
RELATION_MAP = {
|
6
6
|
'ManyToMany' => 'BelongsToMany',
|
7
|
+
'PolymorphicManyToOne' => 'BelongsTo',
|
7
8
|
'ManyToOne' => 'BelongsTo',
|
9
|
+
'PolymorphicOneToMany' => 'HasMany',
|
8
10
|
'OneToMany' => 'HasMany',
|
11
|
+
'PolymorphicOneToOne' => 'HasOne',
|
9
12
|
'OneToOne' => 'HasOne'
|
10
13
|
}.freeze
|
11
14
|
|
12
15
|
def self.build_schema(collection, name)
|
13
16
|
type = collection.schema[:fields][name].type
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
18
|
+
schema = if type == 'Column'
|
19
|
+
build_column_schema(collection, name)
|
20
|
+
else
|
21
|
+
build_relation_schema(collection, name)
|
22
|
+
end
|
21
23
|
|
22
24
|
schema.sort_by { |k, _v| k }.to_h
|
23
25
|
end
|
@@ -151,29 +153,53 @@ module ForestAdminAgent
|
|
151
153
|
)
|
152
154
|
end
|
153
155
|
|
156
|
+
def build_polymorphic_many_to_one_schema(relation, base_schema)
|
157
|
+
base_schema.merge(
|
158
|
+
{
|
159
|
+
type: 'Number', # default or take first foreign_key_targets ??,
|
160
|
+
defaultValue: nil,
|
161
|
+
isFilterable: false,
|
162
|
+
isPrimaryKey: false,
|
163
|
+
isRequired: false,
|
164
|
+
isReadOnly: false,
|
165
|
+
isSortable: false,
|
166
|
+
validations: [],
|
167
|
+
reference: "#{base_schema[:field]}.id",
|
168
|
+
polymorphic_referenced_models: relation.foreign_collections
|
169
|
+
}
|
170
|
+
)
|
171
|
+
end
|
172
|
+
|
154
173
|
def build_relation_schema(collection, name)
|
155
174
|
relation = collection.schema[:fields][name]
|
156
|
-
foreign_collection = collection.datasource.get_collection(relation.foreign_collection)
|
157
|
-
|
158
175
|
relation_schema = {
|
159
176
|
field: name,
|
160
177
|
enums: nil,
|
161
178
|
integration: nil,
|
162
179
|
isReadOnly: nil,
|
163
180
|
isVirtual: false,
|
164
|
-
inverseOf: ForestAdminDatasourceToolkit::Utils::Collection.get_inverse_relation(collection, name),
|
165
181
|
relationship: RELATION_MAP[relation.type]
|
166
182
|
}
|
167
183
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
184
|
+
if relation.type == 'PolymorphicManyToOne'
|
185
|
+
relation_schema[:inverseOf] = collection.name
|
186
|
+
build_polymorphic_many_to_one_schema(relation, relation_schema)
|
187
|
+
else
|
188
|
+
relation_schema[:inverseOf] = ForestAdminDatasourceToolkit::Utils::Collection.get_inverse_relation(
|
189
|
+
collection,
|
190
|
+
name
|
191
|
+
)
|
192
|
+
foreign_collection = collection.datasource.get_collection(relation.foreign_collection)
|
193
|
+
case relation.type
|
194
|
+
when 'ManyToMany'
|
195
|
+
build_many_to_many_schema(relation, collection, foreign_collection, relation_schema)
|
196
|
+
when 'OneToMany', 'PolymorphicOneToMany'
|
197
|
+
build_one_to_many_schema(relation, collection, foreign_collection, relation_schema)
|
198
|
+
when 'OneToOne', 'PolymorphicOneToOne'
|
199
|
+
build_one_to_one_schema(relation, collection, foreign_collection, relation_schema)
|
200
|
+
when 'ManyToOne'
|
201
|
+
build_many_to_one_schema(relation, collection, foreign_collection, relation_schema)
|
202
|
+
end
|
177
203
|
end
|
178
204
|
end
|
179
205
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forest_admin_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.beta.
|
4
|
+
version: 1.0.0.pre.beta.62
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthieu
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-08-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|