forest_admin_datasource_active_record 1.45.1 → 1.45.2
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/forest_admin_datasource_active_record.gemspec +1 -0
- data/lib/forest_admin_datasource_active_record/collection.rb +3 -2
- data/lib/forest_admin_datasource_active_record/utils/active_record_serializer.rb +47 -46
- data/lib/forest_admin_datasource_active_record/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc1197c09a580dd96b9ad3c9966560332df92ce4ffe97922e6d57967c883b4c9
|
|
4
|
+
data.tar.gz: 8e8de31895904e2c9bd2820f23148d2cc8e8357d4667fd97b55502ce0d56dc47
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45d04f5fbc9f9dcb16933f007a1fd3e240df3534f970cce7173c071bfe1e557f3e79d9f22f2e7860fb1a58b9298ef739218b3dd83ef5c117a1f3845268eae58b
|
|
7
|
+
data.tar.gz: 734ba95d343b8a85daadd567379f2428d3bb16a6950f3cdeaa751a9a40e7fba9756c27d7395a071450a171cecdee1443edb197b4fdc24b7913633576471aec47
|
|
@@ -39,6 +39,7 @@ admin work on any Ruby application."
|
|
|
39
39
|
spec.add_dependency "bigdecimal"
|
|
40
40
|
spec.add_dependency "cgi"
|
|
41
41
|
spec.add_dependency "csv"
|
|
42
|
+
spec.add_dependency "forest_admin_datasource_toolkit", ">= #{ForestAdminDatasourceActiveRecord::VERSION}"
|
|
42
43
|
spec.add_dependency "logger"
|
|
43
44
|
spec.add_dependency "mutex_m"
|
|
44
45
|
spec.add_dependency "ostruct"
|
|
@@ -28,7 +28,8 @@ module ForestAdminDatasourceActiveRecord
|
|
|
28
28
|
query = Utils::Query.new(self, projection, filter)
|
|
29
29
|
records = query.get
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
serializer = Utils::ActiveRecordSerializer.new(projection, query.joined_relations)
|
|
32
|
+
records.map { |record| serializer.serialize(record) }
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
def aggregate(_caller, filter, aggregation, limit = nil)
|
|
@@ -37,7 +38,7 @@ module ForestAdminDatasourceActiveRecord
|
|
|
37
38
|
|
|
38
39
|
def create(_caller, data)
|
|
39
40
|
Utils::ErrorHandler.handle_errors(:create) do
|
|
40
|
-
Utils::ActiveRecordSerializer.new(
|
|
41
|
+
Utils::ActiveRecordSerializer.new(ProjectionFactory.all(self)).serialize(@model.create!(data))
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
|
|
@@ -2,73 +2,85 @@ module ForestAdminDatasourceActiveRecord
|
|
|
2
2
|
module Utils
|
|
3
3
|
# Relations in `joined_relations` (see Query#collect_joined_selects) are hydrated from the flat
|
|
4
4
|
# row's aliased columns; every other relation is read from its preloaded ActiveRecord association.
|
|
5
|
-
ActiveRecordSerializer
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
class ActiveRecordSerializer
|
|
6
|
+
ONE_ASSOCIATIONS = %i[has_one belongs_to].freeze
|
|
7
|
+
MANY_ASSOCIATIONS = %i[has_many has_and_belongs_to_many].freeze
|
|
8
|
+
|
|
9
|
+
def initialize(projection, joined_relations = nil)
|
|
10
|
+
@tree = ForestAdminDatasourceToolkit::Components::Query::ProjectionTree.build(projection || ForestAdminDatasourceToolkit::Components::Query::Projection.new)
|
|
11
|
+
@joined_relations = joined_relations || {}
|
|
12
|
+
@join_aliases = @joined_relations.values.flat_map { |meta| meta[:columns].values }.uniq
|
|
13
|
+
@polymorphic_belongs_to = {}
|
|
14
|
+
@target_models = {}
|
|
8
15
|
end
|
|
9
16
|
|
|
10
|
-
def
|
|
17
|
+
def serialize(object)
|
|
18
|
+
hash_object(object, object, @tree)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def target_model(root_model, relation_path)
|
|
22
|
+
@target_models.fetch([root_model, relation_path]) do |key|
|
|
23
|
+
@target_models[key] = resolve_target_model(root_model, relation_path)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def hash_object(root, object, tree, path: [])
|
|
11
30
|
return if object.nil?
|
|
12
31
|
|
|
13
32
|
# root keeps all its selected columns (attributes + FKs); a related record is restricted to
|
|
14
33
|
# its projected columns, matching the JOINed hydration
|
|
15
|
-
hash = path.empty?
|
|
34
|
+
hash = path.empty? ? base_attributes(object) : projected_columns(object, tree)
|
|
16
35
|
hash = normalize_polymorphic_types(object.class, hash)
|
|
17
36
|
|
|
18
|
-
serialize_associations(object,
|
|
37
|
+
serialize_associations(root, object, tree, hash, path)
|
|
19
38
|
|
|
20
39
|
hash
|
|
21
40
|
end
|
|
22
41
|
|
|
23
42
|
def base_attributes(object)
|
|
24
|
-
return object.attributes if join_aliases.empty?
|
|
43
|
+
return object.attributes if @join_aliases.empty?
|
|
25
44
|
|
|
26
|
-
object.attributes.except(
|
|
45
|
+
object.attributes.except(*@join_aliases)
|
|
27
46
|
end
|
|
28
47
|
|
|
29
|
-
def projected_columns(object,
|
|
30
|
-
|
|
48
|
+
def projected_columns(object, tree)
|
|
49
|
+
tree.columns.to_h { |column| [column, object[column]] }
|
|
31
50
|
end
|
|
32
51
|
|
|
33
|
-
def serialize_associations(object,
|
|
34
|
-
|
|
35
|
-
many_associations = %i[has_many has_and_belongs_to_many]
|
|
36
|
-
|
|
37
|
-
projection.relations.each_key do |association_name|
|
|
52
|
+
def serialize_associations(root, object, tree, hash, path)
|
|
53
|
+
tree.relations.each do |association_name, sub_tree|
|
|
38
54
|
relation_path = path + [association_name]
|
|
39
55
|
|
|
40
|
-
if
|
|
41
|
-
hash[association_name] = hash_joined_relation(
|
|
56
|
+
if @joined_relations.key?(relation_path.join('.'))
|
|
57
|
+
hash[association_name] = hash_joined_relation(root, sub_tree, relation_path)
|
|
42
58
|
next
|
|
43
59
|
end
|
|
44
60
|
|
|
45
61
|
association = object.class.reflect_on_association(association_name.to_sym)
|
|
46
62
|
next if association.nil?
|
|
47
63
|
|
|
48
|
-
if
|
|
49
|
-
hash[association_name] = hash_object(
|
|
50
|
-
|
|
51
|
-
projection.relations[association_name],
|
|
52
|
-
path: relation_path
|
|
53
|
-
)
|
|
54
|
-
elsif many_associations.include?(association.macro)
|
|
64
|
+
if ONE_ASSOCIATIONS.include?(association.macro)
|
|
65
|
+
hash[association_name] = hash_object(root, object.send(association_name), sub_tree, path: relation_path)
|
|
66
|
+
elsif MANY_ASSOCIATIONS.include?(association.macro)
|
|
55
67
|
hash[association_name] = object.send(association_name).map do |item|
|
|
56
|
-
hash_object(item,
|
|
68
|
+
hash_object(root, item, sub_tree, path: relation_path)
|
|
57
69
|
end
|
|
58
70
|
end
|
|
59
71
|
end
|
|
60
72
|
end
|
|
61
73
|
|
|
62
74
|
# Reads a JOINed relation's columns from the aliases on the root object (not a nested one).
|
|
63
|
-
def hash_joined_relation(
|
|
64
|
-
meta = joined_relations[relation_path.join('.')]
|
|
65
|
-
return nil if
|
|
75
|
+
def hash_joined_relation(root, tree, relation_path)
|
|
76
|
+
meta = @joined_relations[relation_path.join('.')]
|
|
77
|
+
return nil if root[meta[:pk_alias]].nil?
|
|
66
78
|
|
|
67
79
|
hash = {}
|
|
68
|
-
|
|
69
|
-
hash = normalize_polymorphic_types(target_model(relation_path), hash)
|
|
70
|
-
|
|
71
|
-
hash[nested_name] = hash_joined_relation(
|
|
80
|
+
tree.columns.each { |column| hash[column] = root[meta[:columns][column]] }
|
|
81
|
+
hash = normalize_polymorphic_types(target_model(root.class, relation_path), hash)
|
|
82
|
+
tree.relations.each do |nested_name, nested_tree|
|
|
83
|
+
hash[nested_name] = hash_joined_relation(root, nested_tree, relation_path + [nested_name])
|
|
72
84
|
end
|
|
73
85
|
|
|
74
86
|
hash
|
|
@@ -88,19 +100,16 @@ module ForestAdminDatasourceActiveRecord
|
|
|
88
100
|
hash
|
|
89
101
|
end
|
|
90
102
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
relation_path.reduce(object.class) do |model, name|
|
|
103
|
+
def resolve_target_model(root_model, relation_path)
|
|
104
|
+
relation_path.reduce(root_model) do |model, name|
|
|
94
105
|
model&.reflect_on_association(name.to_sym)&.klass
|
|
95
106
|
end
|
|
96
107
|
rescue NameError
|
|
97
108
|
nil
|
|
98
109
|
end
|
|
99
110
|
|
|
100
|
-
private
|
|
101
|
-
|
|
102
111
|
def polymorphic_belongs_to(model_class)
|
|
103
|
-
|
|
112
|
+
@polymorphic_belongs_to[model_class] ||=
|
|
104
113
|
model_class.reflect_on_all_associations(:belongs_to).select(&:polymorphic?)
|
|
105
114
|
end
|
|
106
115
|
|
|
@@ -110,14 +119,6 @@ module ForestAdminDatasourceActiveRecord
|
|
|
110
119
|
"in model '#{model_class.name}': #{error.message}. Keeping the stored value."
|
|
111
120
|
)
|
|
112
121
|
end
|
|
113
|
-
|
|
114
|
-
def joined_relation?(relation_path)
|
|
115
|
-
!joined_relations.nil? && joined_relations.key?(relation_path.join('.'))
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def join_aliases
|
|
119
|
-
@join_aliases ||= (joined_relations || {}).values.flat_map { |meta| meta[:columns].values }.uniq
|
|
120
|
-
end
|
|
121
122
|
end
|
|
122
123
|
end
|
|
123
124
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_admin_datasource_active_record
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.45.
|
|
4
|
+
version: 1.45.2
|
|
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: 2026-10-
|
|
12
|
+
date: 2026-10-14 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: activerecord
|
|
@@ -109,6 +109,20 @@ dependencies:
|
|
|
109
109
|
- - ">="
|
|
110
110
|
- !ruby/object:Gem::Version
|
|
111
111
|
version: '0'
|
|
112
|
+
- !ruby/object:Gem::Dependency
|
|
113
|
+
name: forest_admin_datasource_toolkit
|
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: 1.45.2
|
|
119
|
+
type: :runtime
|
|
120
|
+
prerelease: false
|
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: 1.45.2
|
|
112
126
|
- !ruby/object:Gem::Dependency
|
|
113
127
|
name: logger
|
|
114
128
|
requirement: !ruby/object:Gem::Requirement
|