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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85145674f5df7ae4706d7664df0afa3d9d6d175fdc4da0135076062f375c5520
4
- data.tar.gz: 5bdcfb2db9533cb53a4502f1cd2665ef7cbcff47e28e693d6a5335d872b493b1
3
+ metadata.gz: '06883f603b147464ddf1ad642f47af2c3230b41cd043cf663ad9214ad22f98ec'
4
+ data.tar.gz: 13cdf53f4abc7147fd38d73efa4ee74f7829abbf320ce363ac315f42e8f1e322
5
5
  SHA512:
6
- metadata.gz: a87cb0be55321842a0f6cb0ced398ac1a4c5a4942fc176d1fbbca17456aad5bc4de51498cbced0884fb57d80feda95f6c0485a6721683af9aeb34132fbdd613a
7
- data.tar.gz: baa517eef52210a9389f8fc1842daf579326a64aa0982b7cc1cb976b355f51b9948eda5d068681d6c7685d890c4d30f4f85aeebc5a97cd38147f6c058e67448e
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
- datasource = @container.resolve(:datasource)
24
+ schema_path = ForestAdminRpcAgent::Facades::Container.cache(:schema_path)
24
25
 
25
- # Build and cache RPC schema from live datasource
26
- @cached_schema = build_rpc_schema_from_datasource(datasource)
27
- compute_and_cache_hash
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
- # Write schema file for reference (only in development mode)
30
- # Uses the same serialization as the /rpc-schema route
31
- write_schema_file_for_reference unless ForestAdminRpcAgent::Facades::Container.cache(:is_production)
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
- build_and_cache_rpc_schema_from_datasource
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 write_schema_file_for_reference
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
- # Use the same serialization as the /rpc-schema route (.to_json)
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
- ForestAdminRpcAgent::Facades::Container.logger.log(
82
- 'Info',
83
- "RPC agent schema file saved to #{schema_path}"
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 build_and_cache_rpc_schema_from_datasource
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[:collections] = datasource.collections
98
- .map { |_name, collection| serialize_collection_schema(collection) }
99
- .sort_by { |c| c[:name] }
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
- schema[:native_query_connections] = datasource.live_query_connections.keys
102
- .map { |connection_name| { name: connection_name } }
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
- # Serialize collection schema, converting field objects to plain hashes
108
- def serialize_collection_schema(collection)
109
- schema = collection.schema.dup
110
- schema[:name] = collection.name
111
- schema[:fields] = schema[:fields].transform_values { |field| object_to_hash(field) }
112
- schema
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
- # Convert any object to a hash using its instance variables
116
- def object_to_hash(obj)
117
- return obj if obj.is_a?(Hash) || obj.is_a?(Array) || obj.is_a?(String) || obj.is_a?(Numeric) || obj.nil?
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
- obj.instance_variables.to_h do |var|
120
- [var.to_s.delete('@').to_sym, obj.instance_variable_get(var)]
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
 
@@ -1,3 +1,3 @@
1
1
  module ForestAdminRpcAgent
2
- VERSION = "1.18.2"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -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-rpc-schema.json')
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: 1.18.2
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 00:00:00.000000000 Z
12
+ date: 2025-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: base64