forest_admin_rpc_agent 1.18.2 → 2.0.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 +4 -4
- data/lib/forest_admin_rpc_agent/agent.rb +162 -37
- data/lib/forest_admin_rpc_agent/version.rb +1 -1
- data/lib/forest_admin_rpc_agent.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: '06883f603b147464ddf1ad642f47af2c3230b41cd043cf663ad9214ad22f98ec'
|
|
4
|
+
data.tar.gz: 13cdf53f4abc7147fd38d73efa4ee74f7829abbf320ce363ac315f42e8f1e322
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2e680dc41c11c375aafe885afee8870b78ee67c81b9853f33c8eb214f1ddd4a60e82c4fe11bbd78f30c894c7288ad66f211c1d354cc7c780fb4c22e5abe4cb48
|
|
7
|
+
data.tar.gz: 02e09ab9ba06a77619dcd42785c3965f578e799014517a85535234c6079e673d4d31b0491fced672764b82fa7186022394b8570415d63f7797a4cc7ee2d9e760
|
|
@@ -2,7 +2,7 @@ require 'digest'
|
|
|
2
2
|
require 'fileutils'
|
|
3
3
|
|
|
4
4
|
module ForestAdminRpcAgent
|
|
5
|
-
class Agent < ForestAdminAgent::Builder::AgentFactory
|
|
5
|
+
class Agent < ForestAdminAgent::Builder::AgentFactory # rubocop:disable Metrics/ClassLength
|
|
6
6
|
include ForestAdminAgent::Http::Exceptions
|
|
7
7
|
|
|
8
8
|
attr_reader :rpc_collections, :cached_schema, :cached_schema_hash
|
|
@@ -17,23 +17,35 @@ module ForestAdminRpcAgent
|
|
|
17
17
|
def send_schema(force: false)
|
|
18
18
|
if should_skip_schema_update? && !force
|
|
19
19
|
log_schema_skip
|
|
20
|
+
load_and_cache_schema
|
|
20
21
|
return
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
schema_path = ForestAdminRpcAgent::Facades::Container.cache(:schema_path)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
if ForestAdminRpcAgent::Facades::Container.cache(:is_production)
|
|
27
|
+
unless schema_path && File.exist?(schema_path)
|
|
28
|
+
raise InternalServerError.new(
|
|
29
|
+
'Schema file not found in production',
|
|
30
|
+
details: { schema_path: schema_path }
|
|
31
|
+
)
|
|
32
|
+
end
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
load_and_cache_schema_from_file(schema_path)
|
|
35
|
+
|
|
36
|
+
ForestAdminRpcAgent::Facades::Container.logger.log(
|
|
37
|
+
'Info',
|
|
38
|
+
'RPC agent running in production mode, using existing schema file.'
|
|
39
|
+
)
|
|
40
|
+
else
|
|
41
|
+
generate_and_cache_schema(schema_path)
|
|
42
|
+
|
|
43
|
+
ForestAdminRpcAgent::Facades::Container.logger.log(
|
|
44
|
+
'Info',
|
|
45
|
+
"RPC agent schema generated and saved to #{schema_path}"
|
|
46
|
+
)
|
|
47
|
+
end
|
|
32
48
|
|
|
33
|
-
ForestAdminRpcAgent::Facades::Container.logger.log(
|
|
34
|
-
'Info',
|
|
35
|
-
'RPC agent schema computed from datasource and cached.'
|
|
36
|
-
)
|
|
37
49
|
ForestAdminRpcAgent::Facades::Container.logger.log(
|
|
38
50
|
'Info',
|
|
39
51
|
'RPC agent does not send schema to Forest Admin servers.'
|
|
@@ -50,7 +62,7 @@ module ForestAdminRpcAgent
|
|
|
50
62
|
def rpc_schema
|
|
51
63
|
return @cached_schema if @cached_schema
|
|
52
64
|
|
|
53
|
-
|
|
65
|
+
build_and_cache_schema_from_datasource
|
|
54
66
|
@cached_schema
|
|
55
67
|
end
|
|
56
68
|
|
|
@@ -70,21 +82,50 @@ module ForestAdminRpcAgent
|
|
|
70
82
|
def log_schema_skip
|
|
71
83
|
logger = ForestAdminRpcAgent::Facades::Container.logger
|
|
72
84
|
logger.log('Warn', '[ForestAdmin] Schema update skipped (skip_schema_update flag is true)')
|
|
85
|
+
environment = ForestAdminRpcAgent::Facades::Container.cache(:is_production) ? 'production' : 'development'
|
|
86
|
+
logger.log('Info', "[ForestAdmin] RPC agent running in #{environment} mode")
|
|
73
87
|
end
|
|
74
88
|
|
|
75
|
-
def
|
|
89
|
+
def load_and_cache_schema
|
|
76
90
|
schema_path = ForestAdminRpcAgent::Facades::Container.cache(:schema_path)
|
|
91
|
+
|
|
92
|
+
if ForestAdminRpcAgent::Facades::Container.cache(:is_production) && schema_path && File.exist?(schema_path)
|
|
93
|
+
load_and_cache_schema_from_file(schema_path)
|
|
94
|
+
else
|
|
95
|
+
# In development with skip_schema_update, still build from datasource
|
|
96
|
+
build_and_cache_schema_from_datasource
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def load_and_cache_schema_from_file(_schema_path)
|
|
101
|
+
# File exists but RPC schema needs internal format - build from datasource
|
|
102
|
+
# The file is kept for reference/frontend but RPC always uses internal format
|
|
103
|
+
datasource = @container.resolve(:datasource)
|
|
104
|
+
@cached_schema = build_rpc_schema_from_datasource(datasource)
|
|
105
|
+
compute_and_cache_hash
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def generate_and_cache_schema(schema_path)
|
|
109
|
+
datasource = @container.resolve(:datasource)
|
|
110
|
+
|
|
111
|
+
# Generate frontend schema for file (used by Forest Admin)
|
|
112
|
+
generated = ForestAdminAgent::Utils::Schema::SchemaEmitter.generate(datasource)
|
|
113
|
+
meta = ForestAdminAgent::Utils::Schema::SchemaEmitter.meta
|
|
114
|
+
|
|
115
|
+
schema = {
|
|
116
|
+
meta: meta,
|
|
117
|
+
collections: generated
|
|
118
|
+
}
|
|
119
|
+
|
|
77
120
|
FileUtils.mkdir_p(File.dirname(schema_path))
|
|
78
|
-
|
|
79
|
-
File.write(schema_path, JSON.pretty_generate(JSON.parse(@cached_schema.to_json)))
|
|
121
|
+
File.write(schema_path, format_schema_json(schema))
|
|
80
122
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
123
|
+
# Build RPC schema in internal format (used by master agent)
|
|
124
|
+
@cached_schema = build_rpc_schema_from_datasource(datasource)
|
|
125
|
+
compute_and_cache_hash
|
|
85
126
|
end
|
|
86
127
|
|
|
87
|
-
def
|
|
128
|
+
def build_and_cache_schema_from_datasource
|
|
88
129
|
datasource = @container.resolve(:datasource)
|
|
89
130
|
|
|
90
131
|
@cached_schema = build_rpc_schema_from_datasource(datasource)
|
|
@@ -94,30 +135,114 @@ module ForestAdminRpcAgent
|
|
|
94
135
|
def build_rpc_schema_from_datasource(datasource)
|
|
95
136
|
schema = customizer.schema
|
|
96
137
|
|
|
97
|
-
schema
|
|
98
|
-
|
|
99
|
-
|
|
138
|
+
# Serialize collections with internal schema format (fields as hash with :type keys)
|
|
139
|
+
collections = datasource.collections.map { |_name, collection| serialize_collection_for_rpc(collection) }
|
|
140
|
+
schema[:collections] = collections.sort_by { |c| c[:name] }
|
|
100
141
|
|
|
101
|
-
|
|
102
|
-
|
|
142
|
+
connections = datasource.live_query_connections.keys.map { |connection_name| { name: connection_name } }
|
|
143
|
+
schema[:native_query_connections] = connections
|
|
103
144
|
|
|
104
145
|
schema
|
|
105
146
|
end
|
|
106
147
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
148
|
+
def serialize_collection_for_rpc(collection)
|
|
149
|
+
{
|
|
150
|
+
name: collection.name,
|
|
151
|
+
countable: collection.schema[:countable],
|
|
152
|
+
searchable: collection.schema[:searchable],
|
|
153
|
+
segments: collection.schema[:segments] || [],
|
|
154
|
+
charts: collection.schema[:charts] || [],
|
|
155
|
+
actions: serialize_actions_for_rpc(collection.schema[:actions] || {}),
|
|
156
|
+
fields: serialize_fields_for_rpc(collection.schema[:fields] || {})
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def serialize_fields_for_rpc(fields)
|
|
161
|
+
fields.transform_values do |field_schema|
|
|
162
|
+
serialize_field_schema(field_schema)
|
|
163
|
+
end
|
|
113
164
|
end
|
|
114
165
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
166
|
+
def serialize_field_schema(field_schema)
|
|
167
|
+
case field_schema
|
|
168
|
+
when ForestAdminDatasourceToolkit::Schema::ColumnSchema
|
|
169
|
+
{
|
|
170
|
+
type: 'Column',
|
|
171
|
+
column_type: field_schema.column_type,
|
|
172
|
+
filter_operators: field_schema.filter_operators,
|
|
173
|
+
is_primary_key: field_schema.is_primary_key,
|
|
174
|
+
is_read_only: field_schema.is_read_only,
|
|
175
|
+
is_sortable: field_schema.is_sortable,
|
|
176
|
+
default_value: field_schema.default_value,
|
|
177
|
+
enum_values: field_schema.enum_values,
|
|
178
|
+
validation: field_schema.validation
|
|
179
|
+
}
|
|
180
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::ManyToOneSchema
|
|
181
|
+
{
|
|
182
|
+
type: 'ManyToOne',
|
|
183
|
+
foreign_collection: field_schema.foreign_collection,
|
|
184
|
+
foreign_key: field_schema.foreign_key,
|
|
185
|
+
foreign_key_target: field_schema.foreign_key_target
|
|
186
|
+
}
|
|
187
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::OneToOneSchema
|
|
188
|
+
{
|
|
189
|
+
type: 'OneToOne',
|
|
190
|
+
foreign_collection: field_schema.foreign_collection,
|
|
191
|
+
origin_key: field_schema.origin_key,
|
|
192
|
+
origin_key_target: field_schema.origin_key_target
|
|
193
|
+
}
|
|
194
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::OneToManySchema
|
|
195
|
+
{
|
|
196
|
+
type: 'OneToMany',
|
|
197
|
+
foreign_collection: field_schema.foreign_collection,
|
|
198
|
+
origin_key: field_schema.origin_key,
|
|
199
|
+
origin_key_target: field_schema.origin_key_target
|
|
200
|
+
}
|
|
201
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema
|
|
202
|
+
{
|
|
203
|
+
type: 'ManyToMany',
|
|
204
|
+
foreign_collection: field_schema.foreign_collection,
|
|
205
|
+
foreign_key: field_schema.foreign_key,
|
|
206
|
+
foreign_key_target: field_schema.foreign_key_target,
|
|
207
|
+
origin_key: field_schema.origin_key,
|
|
208
|
+
origin_key_target: field_schema.origin_key_target,
|
|
209
|
+
through_collection: field_schema.through_collection
|
|
210
|
+
}
|
|
211
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::PolymorphicManyToOneSchema
|
|
212
|
+
{
|
|
213
|
+
type: 'PolymorphicManyToOne',
|
|
214
|
+
foreign_collections: field_schema.foreign_collections,
|
|
215
|
+
foreign_key: field_schema.foreign_key,
|
|
216
|
+
foreign_key_type_field: field_schema.foreign_key_type_field,
|
|
217
|
+
foreign_key_targets: field_schema.foreign_key_targets
|
|
218
|
+
}
|
|
219
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::PolymorphicOneToOneSchema
|
|
220
|
+
{
|
|
221
|
+
type: 'PolymorphicOneToOne',
|
|
222
|
+
foreign_collection: field_schema.foreign_collection,
|
|
223
|
+
origin_key: field_schema.origin_key,
|
|
224
|
+
origin_key_target: field_schema.origin_key_target,
|
|
225
|
+
origin_type_field: field_schema.origin_type_field,
|
|
226
|
+
origin_type_value: field_schema.origin_type_value
|
|
227
|
+
}
|
|
228
|
+
when ForestAdminDatasourceToolkit::Schema::Relations::PolymorphicOneToManySchema
|
|
229
|
+
{
|
|
230
|
+
type: 'PolymorphicOneToMany',
|
|
231
|
+
foreign_collection: field_schema.foreign_collection,
|
|
232
|
+
origin_key: field_schema.origin_key,
|
|
233
|
+
origin_key_target: field_schema.origin_key_target,
|
|
234
|
+
origin_type_field: field_schema.origin_type_field,
|
|
235
|
+
origin_type_value: field_schema.origin_type_value
|
|
236
|
+
}
|
|
237
|
+
else
|
|
238
|
+
# Fallback: try to convert to hash if possible
|
|
239
|
+
field_schema.respond_to?(:to_h) ? field_schema.to_h : field_schema
|
|
240
|
+
end
|
|
241
|
+
end
|
|
118
242
|
|
|
119
|
-
|
|
120
|
-
|
|
243
|
+
def serialize_actions_for_rpc(actions)
|
|
244
|
+
actions.transform_values do |action|
|
|
245
|
+
action.respond_to?(:to_h) ? action.to_h : action
|
|
121
246
|
end
|
|
122
247
|
end
|
|
123
248
|
|
|
@@ -20,7 +20,7 @@ module ForestAdminRpcAgent
|
|
|
20
20
|
setting :prefix, default: nil
|
|
21
21
|
setting :cache_dir, default: :'tmp/cache/forest_admin'
|
|
22
22
|
setting :project_dir, default: Dir.pwd
|
|
23
|
-
setting :schema_path, default: File.join(Dir.pwd, '.forestadmin-
|
|
23
|
+
setting :schema_path, default: File.join(Dir.pwd, '.forestadmin-schema.json')
|
|
24
24
|
setting :skip_schema_update, default: false
|
|
25
25
|
setting :logger_level, default: 'info'
|
|
26
26
|
setting :logger, default: nil
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_admin_rpc_agent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matthieu
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2025-12-
|
|
12
|
+
date: 2025-12-11 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: base64
|