1use super::JSONEval;
2use crate::jsoneval::eval_data::EvalData;
3use crate::jsoneval::json_parser;
4use crate::jsoneval::parsed_schema::ParsedSchema;
5use crate::jsoneval::parsed_schema_cache::PARSED_SCHEMA_CACHE;
6use crate::parse_schema;
7use crate::rlogic::{RLogic, RLogicConfig};
8
9use crate::time_block;
10
11use indexmap::IndexMap;
12use serde::de::Error as _;
13use serde_json::Value;
14use std::collections::HashMap;
15use std::sync::{Arc, Mutex, RwLock};
16
17impl Clone for JSONEval {
18 fn clone(&self) -> Self {
19 Self {
20 schema: Arc::clone(&self.schema),
21 engine: Arc::clone(&self.engine),
22 evaluations: self.evaluations.clone(),
23 tables: self.tables.clone(),
24 table_metadata: self.table_metadata.clone(),
25 dependencies: self.dependencies.clone(),
26 sorted_evaluations: self.sorted_evaluations.clone(),
27 dependents_evaluations: self.dependents_evaluations.clone(),
28 rules_evaluations: self.rules_evaluations.clone(),
29 fields_with_rules: self.fields_with_rules.clone(),
30 others_evaluations: self.others_evaluations.clone(),
31 value_evaluations: self.value_evaluations.clone(),
32 layout_paths: self.layout_paths.clone(),
33 options_templates: self.options_templates.clone(),
34 subforms: self.subforms.clone(),
35 reffed_by: self.reffed_by.clone(),
36 context: self.context.clone(),
37 data: self.data.clone(),
38 evaluated_schema: self.evaluated_schema.clone(),
39 eval_data: self.eval_data.clone(),
40 eval_cache: self.eval_cache.clone(),
41 eval_lock: Mutex::new(()), cached_msgpack_schema: self.cached_msgpack_schema.clone(),
43 conditional_hidden_fields: self.conditional_hidden_fields.clone(),
44 conditional_readonly_fields: self.conditional_readonly_fields.clone(),
45 static_arrays: self.static_arrays.clone(),
46 regex_cache: RwLock::new(HashMap::new()),
47 }
48 }
49}
50
51impl JSONEval {
52 pub fn new(
53 schema: &str,
54 context: Option<&str>,
55 data: Option<&str>,
56 ) -> Result<Self, serde_json::Error> {
57 time_block!("JSONEval::new() [total]", {
58 let mut schema_val: Value =
60 time_block!(" parse schema JSON", { serde_json::from_str(schema)? });
61 let context: Value = time_block!(" parse context JSON", {
62 json_parser::parse_json_str(context.unwrap_or("{}"))
63 .map_err(serde_json::Error::custom)?
64 });
65 let data: Value = time_block!(" parse data JSON", {
66 json_parser::parse_json_str(data.unwrap_or("{}"))
67 .map_err(serde_json::Error::custom)?
68 });
69
70 let static_arrays = if let Some(params) = schema_val
72 .get_mut("$params")
73 .and_then(|v| v.as_object_mut())
74 {
75 crate::jsoneval::static_arrays::extract_from_params(params)
76 } else {
77 IndexMap::new()
78 };
79 let static_arrays = Arc::new(static_arrays);
80 let evaluated_schema = schema_val.clone();
81
82 let engine_config = RLogicConfig::default();
84 let mut engine = RLogic::with_config(engine_config);
85 engine.set_static_arrays(Arc::clone(&static_arrays));
86
87 let mut instance = time_block!(" create instance struct", {
88 Self {
89 schema: Arc::new(schema_val),
90 evaluations: Arc::new(IndexMap::new()),
91 tables: Arc::new(IndexMap::new()),
92 table_metadata: Arc::new(IndexMap::new()),
93 dependencies: Arc::new(IndexMap::new()),
94 sorted_evaluations: Arc::new(Vec::new()),
95 dependents_evaluations: Arc::new(IndexMap::new()),
96 rules_evaluations: Arc::new(Vec::new()),
97 fields_with_rules: Arc::new(Vec::new()),
98 others_evaluations: Arc::new(Vec::new()),
99 value_evaluations: Arc::new(Vec::new()),
100 layout_paths: Arc::new(Vec::new()),
101 options_templates: Arc::new(Vec::new()),
102 subforms: IndexMap::new(),
103 engine: Arc::new(engine),
104 reffed_by: Arc::new(IndexMap::new()),
105 context: context.clone(),
106 data: data.clone(),
107 evaluated_schema: evaluated_schema.clone(),
108 eval_data: EvalData::with_schema_data_context(
109 &evaluated_schema,
110 &data,
111 &context,
112 ),
113 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
114 eval_lock: Mutex::new(()),
115 cached_msgpack_schema: None,
116 conditional_hidden_fields: Arc::new(Vec::new()),
117 conditional_readonly_fields: Arc::new(Vec::new()),
118 static_arrays,
119 regex_cache: RwLock::new(HashMap::new()),
120 }
121 });
122 time_block!(" parse_schema", {
123 parse_schema::legacy::parse_schema(&mut instance)
124 .map_err(serde_json::Error::custom)?
125 });
126 Ok(instance)
127 })
128 }
129
130 pub(crate) fn new_subform(
132 schema_val: Value,
133 context: Value,
134 static_arrays: Arc<IndexMap<String, Arc<Value>>>,
135 ) -> Result<Self, serde_json::Error> {
136 time_block!("JSONEval::new_subform() [total]", {
137 let data = Value::Object(serde_json::Map::new());
139 let evaluated_schema = schema_val.clone();
140
141 let engine_config = RLogicConfig::default();
143 let mut engine = RLogic::with_config(engine_config);
144 engine.set_static_arrays(Arc::clone(&static_arrays));
145
146 let mut instance = time_block!(" create instance struct", {
147 Self {
148 schema: Arc::new(schema_val),
149 evaluations: Arc::new(IndexMap::new()),
150 tables: Arc::new(IndexMap::new()),
151 table_metadata: Arc::new(IndexMap::new()),
152 dependencies: Arc::new(IndexMap::new()),
153 sorted_evaluations: Arc::new(Vec::new()),
154 dependents_evaluations: Arc::new(IndexMap::new()),
155 rules_evaluations: Arc::new(Vec::new()),
156 fields_with_rules: Arc::new(Vec::new()),
157 others_evaluations: Arc::new(Vec::new()),
158 value_evaluations: Arc::new(Vec::new()),
159 layout_paths: Arc::new(Vec::new()),
160 options_templates: Arc::new(Vec::new()),
161 subforms: IndexMap::new(),
162 engine: Arc::new(engine),
163 reffed_by: Arc::new(IndexMap::new()),
164 context: context.clone(),
165 data: data.clone(),
166 evaluated_schema: evaluated_schema.clone(),
167 eval_data: EvalData::with_schema_data_context(
168 &evaluated_schema,
169 &data,
170 &context,
171 ),
172 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
173 eval_lock: Mutex::new(()),
174 cached_msgpack_schema: None,
175 conditional_hidden_fields: Arc::new(Vec::new()),
176 conditional_readonly_fields: Arc::new(Vec::new()),
177 static_arrays,
178 regex_cache: RwLock::new(HashMap::new()),
179 }
180 });
181 time_block!(" parse_schema", {
182 parse_schema::legacy::parse_schema(&mut instance)
183 .map_err(serde_json::Error::custom)?
184 });
185 Ok(instance)
186 })
187 }
188
189 pub fn new_from_msgpack(
201 schema_msgpack: &[u8],
202 context: Option<&str>,
203 data: Option<&str>,
204 ) -> Result<Self, String> {
205 let cached_msgpack = schema_msgpack.to_vec();
207
208 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
210 .map_err(|e| format!("Failed to deserialize MessagePack schema: {}", e))?;
211
212 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
213 .map_err(|e| format!("Failed to parse context: {}", e))?;
214 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
215 .map_err(|e| format!("Failed to parse data: {}", e))?;
216
217 let static_arrays = if let Some(params) = schema_val
219 .get_mut("$params")
220 .and_then(|v| v.as_object_mut())
221 {
222 crate::jsoneval::static_arrays::extract_from_params(params)
223 } else {
224 IndexMap::new()
225 };
226 let static_arrays = Arc::new(static_arrays);
227 let evaluated_schema = schema_val.clone();
228
229 let engine_config = RLogicConfig::default();
230 let mut engine = RLogic::with_config(engine_config);
231 engine.set_static_arrays(Arc::clone(&static_arrays));
232
233 let mut instance = Self {
234 schema: Arc::new(schema_val),
235 evaluations: Arc::new(IndexMap::new()),
236 tables: Arc::new(IndexMap::new()),
237 table_metadata: Arc::new(IndexMap::new()),
238 dependencies: Arc::new(IndexMap::new()),
239 sorted_evaluations: Arc::new(Vec::new()),
240 dependents_evaluations: Arc::new(IndexMap::new()),
241 rules_evaluations: Arc::new(Vec::new()),
242 fields_with_rules: Arc::new(Vec::new()),
243 others_evaluations: Arc::new(Vec::new()),
244 value_evaluations: Arc::new(Vec::new()),
245 layout_paths: Arc::new(Vec::new()),
246 options_templates: Arc::new(Vec::new()),
247 subforms: IndexMap::new(),
248 engine: Arc::new(engine),
249 reffed_by: Arc::new(IndexMap::new()),
250 context: context.clone(),
251 data: data.clone(),
252 evaluated_schema: evaluated_schema.clone(),
253 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
254 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
255 eval_lock: Mutex::new(()),
256 cached_msgpack_schema: Some(cached_msgpack),
257 conditional_hidden_fields: Arc::new(Vec::new()),
258 conditional_readonly_fields: Arc::new(Vec::new()),
259 static_arrays,
260 regex_cache: RwLock::new(HashMap::new()),
261 };
262 parse_schema::legacy::parse_schema(&mut instance)?;
263 Ok(instance)
264 }
265
266 pub fn with_parsed_schema(
294 parsed: Arc<ParsedSchema>,
295 context: Option<&str>,
296 data: Option<&str>,
297 ) -> Result<Self, String> {
298 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
299 .map_err(|e| format!("Failed to parse context: {}", e))?;
300 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
301 .map_err(|e| format!("Failed to parse data: {}", e))?;
302
303 let evaluated_schema = parsed.schema.clone();
304
305 let engine = parsed.engine.clone();
308
309 let mut subforms = IndexMap::new();
312 for (path, subform_parsed) in &parsed.subforms {
313 let subform_eval =
315 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
316 subforms.insert(path.clone(), Box::new(subform_eval));
317 }
318
319 let instance = Self {
320 schema: Arc::clone(&parsed.schema),
321 evaluations: Arc::clone(&parsed.evaluations),
322 tables: Arc::clone(&parsed.tables),
323 table_metadata: Arc::clone(&parsed.table_metadata),
324 dependencies: Arc::clone(&parsed.dependencies),
325 sorted_evaluations: Arc::clone(&parsed.sorted_evaluations),
326 dependents_evaluations: Arc::clone(&parsed.dependents_evaluations),
327 rules_evaluations: Arc::clone(&parsed.rules_evaluations),
328 fields_with_rules: Arc::clone(&parsed.fields_with_rules),
329 others_evaluations: Arc::clone(&parsed.others_evaluations),
330 value_evaluations: Arc::clone(&parsed.value_evaluations),
331 layout_paths: Arc::clone(&parsed.layout_paths),
332 options_templates: Arc::clone(&parsed.options_templates),
333 subforms,
334 engine,
335 reffed_by: Arc::clone(&parsed.reffed_by),
336 context: context.clone(),
337 data: data.clone(),
338 evaluated_schema: (*evaluated_schema).clone(),
339 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
340 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
341 eval_lock: Mutex::new(()),
342 cached_msgpack_schema: None,
343 conditional_hidden_fields: Arc::clone(&parsed.conditional_hidden_fields),
344 conditional_readonly_fields: Arc::clone(&parsed.conditional_readonly_fields),
345 static_arrays: Arc::clone(&parsed.static_arrays),
346 regex_cache: RwLock::new(HashMap::new()),
347 };
348 Ok(instance)
349 }
350
351 pub fn reload_schema(
352 &mut self,
353 schema: &str,
354 context: Option<&str>,
355 data: Option<&str>,
356 ) -> Result<(), String> {
357 let mut schema_val: Value =
359 serde_json::from_str(schema).map_err(|e| format!("failed to parse schema: {e}"))?;
360 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
361 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
362 self.context = context.clone();
363 self.data = data.clone();
364
365 let static_arrays = if let Some(params) = schema_val
366 .get_mut("$params")
367 .and_then(|v| v.as_object_mut())
368 {
369 crate::jsoneval::static_arrays::extract_from_params(params)
370 } else {
371 IndexMap::new()
372 };
373 let static_arrays = Arc::new(static_arrays);
374 self.static_arrays = Arc::clone(&static_arrays);
375 self.schema = Arc::new(schema_val);
376 self.evaluated_schema = (*self.schema).clone();
377
378 let mut engine = RLogic::new();
379 engine.set_static_arrays(static_arrays);
380 self.engine = Arc::new(engine);
381
382 self.evaluations = Arc::new(IndexMap::new());
383 self.tables = Arc::new(IndexMap::new());
384 self.table_metadata = Arc::new(IndexMap::new());
385 self.dependencies = Arc::new(IndexMap::new());
386 self.sorted_evaluations = Arc::new(Vec::new());
387 self.dependents_evaluations = Arc::new(IndexMap::new());
388 self.rules_evaluations = Arc::new(Vec::new());
389 self.fields_with_rules = Arc::new(Vec::new());
390 self.others_evaluations = Arc::new(Vec::new());
391 self.value_evaluations = Arc::new(Vec::new());
392 self.layout_paths = Arc::new(Vec::new());
393 self.options_templates = Arc::new(Vec::new());
394 self.reffed_by = Arc::new(IndexMap::new());
395 self.conditional_hidden_fields = Arc::new(Vec::new());
396 self.conditional_readonly_fields = Arc::new(Vec::new());
397 self.subforms.clear();
398 parse_schema::legacy::parse_schema(self)?;
399
400 self.eval_data =
402 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
403 self.eval_cache.clear();
404 if let Ok(mut cache) = self.regex_cache.write() {
405 cache.clear();
406 }
407
408 self.cached_msgpack_schema = None;
410
411 Ok(())
412 }
413
414 pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>) {
436 let mut config = RLogicConfig::default();
438 if let Some(offset) = offset_minutes {
439 config = config.with_timezone_offset(offset);
440 }
441
442 let mut engine = RLogic::with_config(config);
445 engine.set_static_arrays(Arc::clone(&self.static_arrays));
446 self.engine = Arc::new(engine);
447
448 let _ = parse_schema::legacy::parse_schema(self);
449 }
450
451 pub fn reload_schema_msgpack(
463 &mut self,
464 schema_msgpack: &[u8],
465 context: Option<&str>,
466 data: Option<&str>,
467 ) -> Result<(), String> {
468 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
470 .map_err(|e| format!("failed to deserialize MessagePack schema: {e}"))?;
471
472 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
473 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
474
475 self.context = context.clone();
476 self.data = data.clone();
477
478 let static_arrays = if let Some(params) = schema_val
479 .get_mut("$params")
480 .and_then(|v| v.as_object_mut())
481 {
482 crate::jsoneval::static_arrays::extract_from_params(params)
483 } else {
484 IndexMap::new()
485 };
486 let static_arrays = Arc::new(static_arrays);
487 self.static_arrays = Arc::clone(&static_arrays);
488 self.schema = Arc::new(schema_val);
489 self.evaluated_schema = (*self.schema).clone();
490
491 let mut engine = RLogic::new();
492 engine.set_static_arrays(static_arrays);
493 self.engine = Arc::new(engine);
494 self.evaluations = Arc::new(IndexMap::new());
495 self.tables = Arc::new(IndexMap::new());
496 self.table_metadata = Arc::new(IndexMap::new());
497 self.dependencies = Arc::new(IndexMap::new());
498 self.sorted_evaluations = Arc::new(Vec::new());
499 self.dependents_evaluations = Arc::new(IndexMap::new());
500 self.rules_evaluations = Arc::new(Vec::new());
501 self.fields_with_rules = Arc::new(Vec::new());
502 self.others_evaluations = Arc::new(Vec::new());
503 self.value_evaluations = Arc::new(Vec::new());
504 self.layout_paths = Arc::new(Vec::new());
505 self.options_templates = Arc::new(Vec::new());
506 self.reffed_by = Arc::new(IndexMap::new());
507 self.conditional_hidden_fields = Arc::new(Vec::new());
508 self.conditional_readonly_fields = Arc::new(Vec::new());
509 self.subforms.clear();
510 parse_schema::legacy::parse_schema(self)?;
511
512 self.eval_data =
514 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
515 self.eval_cache.clear();
516 if let Ok(mut cache) = self.regex_cache.write() {
517 cache.clear();
518 }
519
520 self.cached_msgpack_schema = Some(schema_msgpack.to_vec());
522
523 Ok(())
524 }
525
526 pub fn reload_schema_parsed(
540 &mut self,
541 parsed: Arc<ParsedSchema>,
542 context: Option<&str>,
543 data: Option<&str>,
544 ) -> Result<(), String> {
545 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
546 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
547
548 self.schema = Arc::clone(&parsed.schema);
550 self.evaluations = parsed.evaluations.clone();
551 self.tables = parsed.tables.clone();
552 self.table_metadata = parsed.table_metadata.clone();
553 self.dependencies = parsed.dependencies.clone();
554 self.sorted_evaluations = parsed.sorted_evaluations.clone();
555 self.dependents_evaluations = parsed.dependents_evaluations.clone();
556 self.rules_evaluations = parsed.rules_evaluations.clone();
557 self.fields_with_rules = parsed.fields_with_rules.clone();
558 self.others_evaluations = parsed.others_evaluations.clone();
559 self.value_evaluations = parsed.value_evaluations.clone();
560 self.layout_paths = parsed.layout_paths.clone();
561 self.options_templates = parsed.options_templates.clone();
562 self.static_arrays = parsed.static_arrays.clone();
563
564 self.engine = parsed.engine.clone();
566
567 let mut subforms = IndexMap::new();
569 for (path, subform_parsed) in &parsed.subforms {
570 let subform_eval =
571 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
572 subforms.insert(path.clone(), Box::new(subform_eval));
573 }
574 self.subforms = subforms;
575
576 self.context = context.clone();
577 self.data = data.clone();
578 self.evaluated_schema = (*self.schema).clone();
579
580 self.eval_data =
582 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
583 self.eval_cache.clear();
584 self.engine.clear_indices();
585 if let Ok(mut cache) = self.regex_cache.write() {
586 cache.clear();
587 }
588
589 self.cached_msgpack_schema = None;
591
592 Ok(())
593 }
594
595 pub fn reload_schema_from_cache(
609 &mut self,
610 cache_key: &str,
611 context: Option<&str>,
612 data: Option<&str>,
613 ) -> Result<(), String> {
614 let parsed = PARSED_SCHEMA_CACHE
616 .get(cache_key)
617 .ok_or_else(|| format!("Schema '{}' not found in cache", cache_key))?;
618
619 self.reload_schema_parsed(parsed, context, data)
621 }
622}