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 root_layout_paths: self.root_layout_paths.clone(),
34 layout_field_refs: self.layout_field_refs.clone(),
35 options_templates: self.options_templates.clone(),
36 subforms: self.subforms.clone(),
37 reffed_by: self.reffed_by.clone(),
38 dep_formula_triggers: self.dep_formula_triggers.clone(),
39 context: self.context.clone(),
40 data: self.data.clone(),
41 evaluated_schema: self.evaluated_schema.clone(),
42 eval_data: self.eval_data.clone(),
43 eval_cache: self.eval_cache.clone(),
44 eval_lock: Mutex::new(()), cached_msgpack_schema: self.cached_msgpack_schema.clone(),
46 conditional_hidden_fields: self.conditional_hidden_fields.clone(),
47 conditional_readonly_fields: self.conditional_readonly_fields.clone(),
48 static_arrays: self.static_arrays.clone(),
49 regex_cache: RwLock::new(HashMap::new()),
50 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
51 validation_cache: RwLock::new(self.validation_cache.read().unwrap().clone()),
52 }
53 }
54}
55
56impl JSONEval {
57 pub fn new(
58 schema: &str,
59 context: Option<&str>,
60 data: Option<&str>,
61 ) -> Result<Self, serde_json::Error> {
62 time_block!("JSONEval::new() [total]", {
63 let mut schema_val: Value =
65 time_block!(" parse schema JSON", { serde_json::from_str(schema)? });
66 let context: Value = time_block!(" parse context JSON", {
67 json_parser::parse_json_str(context.unwrap_or("{}"))
68 .map_err(serde_json::Error::custom)?
69 });
70 let data: Value = time_block!(" parse data JSON", {
71 json_parser::parse_json_str(data.unwrap_or("{}"))
72 .map_err(serde_json::Error::custom)?
73 });
74
75 let static_arrays = if let Some(params) = schema_val
77 .get_mut("$params")
78 .and_then(|v| v.as_object_mut())
79 {
80 crate::jsoneval::static_arrays::extract_from_params(params)
81 } else {
82 IndexMap::new()
83 };
84 let static_arrays = Arc::new(static_arrays);
85 let evaluated_schema = schema_val.clone();
86
87 let engine_config = RLogicConfig::default();
89 let engine = RLogic::with_config(engine_config);
90 engine.set_static_arrays(Arc::clone(&static_arrays));
91
92 let mut instance = time_block!(" create instance struct", {
93 Self {
94 schema: Arc::new(schema_val),
95 evaluations: Arc::new(IndexMap::new()),
96 tables: Arc::new(IndexMap::new()),
97 table_metadata: Arc::new(IndexMap::new()),
98 dependencies: Arc::new(IndexMap::new()),
99 sorted_evaluations: Arc::new(Vec::new()),
100 dependents_evaluations: Arc::new(IndexMap::new()),
101 rules_evaluations: Arc::new(Vec::new()),
102 fields_with_rules: Arc::new(Vec::new()),
103 others_evaluations: Arc::new(Vec::new()),
104 value_evaluations: Arc::new(Vec::new()),
105 layout_paths: Arc::new(Vec::new()),
106 root_layout_paths: Arc::new(Vec::new()),
107 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
108 options_templates: Arc::new(Vec::new()),
109 subforms: IndexMap::new(),
110 engine: Arc::new(engine),
111 reffed_by: Arc::new(IndexMap::new()),
112 dep_formula_triggers: Arc::new(IndexMap::new()),
113 context: context.clone(),
114 data: data.clone(),
115 evaluated_schema: evaluated_schema.clone(),
116 eval_data: EvalData::with_schema_data_context(
117 &evaluated_schema,
118 &data,
119 &context,
120 ),
121 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
122 eval_lock: Mutex::new(()),
123 cached_msgpack_schema: None,
124 conditional_hidden_fields: Arc::new(Vec::new()),
125 conditional_readonly_fields: Arc::new(Vec::new()),
126 static_arrays,
127 regex_cache: RwLock::new(HashMap::new()),
128 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
129 validation_cache: RwLock::new(crate::jsoneval::validation_cache::ValidationCache::default()),
130 }
131 });
132 time_block!(" parse_schema", {
133 parse_schema::legacy::parse_schema(&mut instance)
134 .map_err(serde_json::Error::custom)?
135 });
136 Ok(instance)
137 })
138 }
139
140 pub(crate) fn new_subform(
142 schema_val: Value,
143 context: Value,
144 static_arrays: Arc<IndexMap<String, Arc<Value>>>,
145 ) -> Result<Self, serde_json::Error> {
146 time_block!("JSONEval::new_subform() [total]", {
147 let data = Value::Object(serde_json::Map::new());
149 let evaluated_schema = schema_val.clone();
150
151 let engine_config = RLogicConfig::default();
153 let engine = RLogic::with_config(engine_config);
154 engine.set_static_arrays(Arc::clone(&static_arrays));
155
156 let mut instance = time_block!(" create instance struct", {
157 Self {
158 schema: Arc::new(schema_val),
159 evaluations: Arc::new(IndexMap::new()),
160 tables: Arc::new(IndexMap::new()),
161 table_metadata: Arc::new(IndexMap::new()),
162 dependencies: Arc::new(IndexMap::new()),
163 sorted_evaluations: Arc::new(Vec::new()),
164 dependents_evaluations: Arc::new(IndexMap::new()),
165 rules_evaluations: Arc::new(Vec::new()),
166 fields_with_rules: Arc::new(Vec::new()),
167 others_evaluations: Arc::new(Vec::new()),
168 value_evaluations: Arc::new(Vec::new()),
169 layout_paths: Arc::new(Vec::new()),
170 root_layout_paths: Arc::new(Vec::new()),
171 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
172 options_templates: Arc::new(Vec::new()),
173 subforms: IndexMap::new(),
174 engine: Arc::new(engine),
175 reffed_by: Arc::new(IndexMap::new()),
176 dep_formula_triggers: Arc::new(IndexMap::new()),
177 context: context.clone(),
178 data: data.clone(),
179 evaluated_schema: evaluated_schema.clone(),
180 eval_data: EvalData::with_schema_data_context(
181 &evaluated_schema,
182 &data,
183 &context,
184 ),
185 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
186 eval_lock: Mutex::new(()),
187 cached_msgpack_schema: None,
188 conditional_hidden_fields: Arc::new(Vec::new()),
189 conditional_readonly_fields: Arc::new(Vec::new()),
190 static_arrays,
191 regex_cache: RwLock::new(HashMap::new()),
192 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
193 validation_cache: RwLock::new(crate::jsoneval::validation_cache::ValidationCache::default()),
194 }
195 });
196 time_block!(" parse_schema", {
197 parse_schema::legacy::parse_schema(&mut instance)
198 .map_err(serde_json::Error::custom)?
199 });
200 Ok(instance)
201 })
202 }
203
204 pub fn new_from_msgpack(
216 schema_msgpack: &[u8],
217 context: Option<&str>,
218 data: Option<&str>,
219 ) -> Result<Self, String> {
220 let cached_msgpack = schema_msgpack.to_vec();
222
223 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
225 .map_err(|e| format!("Failed to deserialize MessagePack schema: {}", e))?;
226
227 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
228 .map_err(|e| format!("Failed to parse context: {}", e))?;
229 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
230 .map_err(|e| format!("Failed to parse data: {}", e))?;
231
232 let static_arrays = if let Some(params) = schema_val
234 .get_mut("$params")
235 .and_then(|v| v.as_object_mut())
236 {
237 crate::jsoneval::static_arrays::extract_from_params(params)
238 } else {
239 IndexMap::new()
240 };
241 let static_arrays = Arc::new(static_arrays);
242 let evaluated_schema = schema_val.clone();
243
244 let engine_config = RLogicConfig::default();
245 let engine = RLogic::with_config(engine_config);
246 engine.set_static_arrays(Arc::clone(&static_arrays));
247
248 let mut instance = Self {
249 schema: Arc::new(schema_val),
250 evaluations: Arc::new(IndexMap::new()),
251 tables: Arc::new(IndexMap::new()),
252 table_metadata: Arc::new(IndexMap::new()),
253 dependencies: Arc::new(IndexMap::new()),
254 sorted_evaluations: Arc::new(Vec::new()),
255 dependents_evaluations: Arc::new(IndexMap::new()),
256 rules_evaluations: Arc::new(Vec::new()),
257 fields_with_rules: Arc::new(Vec::new()),
258 others_evaluations: Arc::new(Vec::new()),
259 value_evaluations: Arc::new(Vec::new()),
260 layout_paths: Arc::new(Vec::new()),
261 root_layout_paths: Arc::new(Vec::new()),
262 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
263 options_templates: Arc::new(Vec::new()),
264 subforms: IndexMap::new(),
265 engine: Arc::new(engine),
266 reffed_by: Arc::new(IndexMap::new()),
267 dep_formula_triggers: Arc::new(IndexMap::new()),
268 context: context.clone(),
269 data: data.clone(),
270 evaluated_schema: evaluated_schema.clone(),
271 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
272 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
273 eval_lock: Mutex::new(()),
274 cached_msgpack_schema: Some(cached_msgpack),
275 conditional_hidden_fields: Arc::new(Vec::new()),
276 conditional_readonly_fields: Arc::new(Vec::new()),
277 static_arrays,
278 regex_cache: RwLock::new(HashMap::new()),
279 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
280 validation_cache: RwLock::new(crate::jsoneval::validation_cache::ValidationCache::default()),
281 };
282 parse_schema::legacy::parse_schema(&mut instance)?;
283 Ok(instance)
284 }
285
286 pub fn with_parsed_schema(
314 parsed: Arc<ParsedSchema>,
315 context: Option<&str>,
316 data: Option<&str>,
317 ) -> Result<Self, String> {
318 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
319 .map_err(|e| format!("Failed to parse context: {}", e))?;
320 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
321 .map_err(|e| format!("Failed to parse data: {}", e))?;
322
323 let evaluated_schema = parsed.schema.clone();
324
325 let engine = parsed.engine.clone();
328
329 let mut subforms = IndexMap::new();
332 for (path, subform_parsed) in &parsed.subforms {
333 let subform_eval =
335 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
336 subforms.insert(path.clone(), Box::new(subform_eval));
337 }
338
339 let instance = Self {
340 schema: Arc::clone(&parsed.schema),
341 evaluations: Arc::clone(&parsed.evaluations),
342 tables: Arc::clone(&parsed.tables),
343 table_metadata: Arc::clone(&parsed.table_metadata),
344 dependencies: Arc::clone(&parsed.dependencies),
345 sorted_evaluations: Arc::clone(&parsed.sorted_evaluations),
346 dependents_evaluations: Arc::clone(&parsed.dependents_evaluations),
347 rules_evaluations: Arc::clone(&parsed.rules_evaluations),
348 fields_with_rules: Arc::clone(&parsed.fields_with_rules),
349 others_evaluations: Arc::clone(&parsed.others_evaluations),
350 value_evaluations: Arc::clone(&parsed.value_evaluations),
351 layout_paths: Arc::clone(&parsed.layout_paths),
352 root_layout_paths: Arc::clone(&parsed.root_layout_paths),
353 layout_field_refs: Arc::clone(&parsed.layout_field_refs),
354 options_templates: Arc::clone(&parsed.options_templates),
355 subforms,
356 engine,
357 reffed_by: Arc::clone(&parsed.reffed_by),
358 dep_formula_triggers: Arc::clone(&parsed.dep_formula_triggers),
359 context: context.clone(),
360 data: data.clone(),
361 evaluated_schema: (*evaluated_schema).clone(),
362 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
363 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
364 eval_lock: Mutex::new(()),
365 cached_msgpack_schema: None,
366 conditional_hidden_fields: Arc::clone(&parsed.conditional_hidden_fields),
367 conditional_readonly_fields: Arc::clone(&parsed.conditional_readonly_fields),
368 static_arrays: Arc::clone(&parsed.static_arrays),
369 regex_cache: RwLock::new(HashMap::new()),
370 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
371 validation_cache: RwLock::new(crate::jsoneval::validation_cache::ValidationCache::default()),
372 };
373 Ok(instance)
374 }
375
376 pub fn reload_schema(
377 &mut self,
378 schema: &str,
379 context: Option<&str>,
380 data: Option<&str>,
381 ) -> Result<(), String> {
382 let mut schema_val: Value =
384 serde_json::from_str(schema).map_err(|e| format!("failed to parse schema: {e}"))?;
385 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
386 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
387 self.context = context.clone();
388 self.data = data.clone();
389
390 let static_arrays = if let Some(params) = schema_val
391 .get_mut("$params")
392 .and_then(|v| v.as_object_mut())
393 {
394 crate::jsoneval::static_arrays::extract_from_params(params)
395 } else {
396 IndexMap::new()
397 };
398 let static_arrays = Arc::new(static_arrays);
399 self.static_arrays = Arc::clone(&static_arrays);
400 self.schema = Arc::new(schema_val);
401 self.evaluated_schema = (*self.schema).clone();
402
403 let engine = RLogic::new();
404 engine.set_static_arrays(static_arrays);
405 self.engine = Arc::new(engine);
406
407 self.evaluations = Arc::new(IndexMap::new());
408 self.tables = Arc::new(IndexMap::new());
409 self.table_metadata = Arc::new(IndexMap::new());
410 self.dependencies = Arc::new(IndexMap::new());
411 self.sorted_evaluations = Arc::new(Vec::new());
412 self.dependents_evaluations = Arc::new(IndexMap::new());
413 self.rules_evaluations = Arc::new(Vec::new());
414 self.fields_with_rules = Arc::new(Vec::new());
415 self.others_evaluations = Arc::new(Vec::new());
416 self.value_evaluations = Arc::new(Vec::new());
417 self.layout_paths = Arc::new(Vec::new());
418 self.root_layout_paths = Arc::new(Vec::new());
419 self.options_templates = Arc::new(Vec::new());
420 self.reffed_by = Arc::new(IndexMap::new());
421 self.dep_formula_triggers = Arc::new(IndexMap::new());
422 self.conditional_hidden_fields = Arc::new(Vec::new());
423 self.conditional_readonly_fields = Arc::new(Vec::new());
424 self.subforms.clear();
425 parse_schema::legacy::parse_schema(self)?;
426
427 self.eval_data =
429 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
430 self.eval_cache.clear();
431 if let Ok(mut cache) = self.regex_cache.write() {
432 cache.clear();
433 }
434
435 self.cached_msgpack_schema = None;
437 self.invalidate_layout_cache();
438 self.invalidate_validation_cache();
439
440 Ok(())
441 }
442
443 pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>) {
465 let mut config = RLogicConfig::default();
467 if let Some(offset) = offset_minutes {
468 config = config.with_timezone_offset(offset);
469 }
470
471 let engine = RLogic::with_config(config);
474 engine.set_static_arrays(Arc::clone(&self.static_arrays));
475 self.engine = Arc::new(engine);
476
477 let _ = parse_schema::legacy::parse_schema(self);
478 }
479
480 pub fn reload_schema_msgpack(
492 &mut self,
493 schema_msgpack: &[u8],
494 context: Option<&str>,
495 data: Option<&str>,
496 ) -> Result<(), String> {
497 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
499 .map_err(|e| format!("failed to deserialize MessagePack schema: {e}"))?;
500
501 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
502 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
503
504 self.context = context.clone();
505 self.data = data.clone();
506
507 let static_arrays = if let Some(params) = schema_val
508 .get_mut("$params")
509 .and_then(|v| v.as_object_mut())
510 {
511 crate::jsoneval::static_arrays::extract_from_params(params)
512 } else {
513 IndexMap::new()
514 };
515 let static_arrays = Arc::new(static_arrays);
516 self.static_arrays = Arc::clone(&static_arrays);
517 self.schema = Arc::new(schema_val);
518 self.evaluated_schema = (*self.schema).clone();
519
520 let engine = RLogic::new();
521 engine.set_static_arrays(static_arrays);
522 self.engine = Arc::new(engine);
523 self.evaluations = Arc::new(IndexMap::new());
524 self.tables = Arc::new(IndexMap::new());
525 self.table_metadata = Arc::new(IndexMap::new());
526 self.dependencies = Arc::new(IndexMap::new());
527 self.sorted_evaluations = Arc::new(Vec::new());
528 self.dependents_evaluations = Arc::new(IndexMap::new());
529 self.rules_evaluations = Arc::new(Vec::new());
530 self.fields_with_rules = Arc::new(Vec::new());
531 self.others_evaluations = Arc::new(Vec::new());
532 self.value_evaluations = Arc::new(Vec::new());
533 self.layout_paths = Arc::new(Vec::new());
534 self.root_layout_paths = Arc::new(Vec::new());
535 self.options_templates = Arc::new(Vec::new());
536 self.reffed_by = Arc::new(IndexMap::new());
537 self.dep_formula_triggers = Arc::new(IndexMap::new());
538 self.conditional_hidden_fields = Arc::new(Vec::new());
539 self.conditional_readonly_fields = Arc::new(Vec::new());
540 self.subforms.clear();
541 parse_schema::legacy::parse_schema(self)?;
542
543 self.eval_data =
545 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
546 self.eval_cache.clear();
547 if let Ok(mut cache) = self.regex_cache.write() {
548 cache.clear();
549 }
550
551 self.cached_msgpack_schema = Some(schema_msgpack.to_vec());
553 self.invalidate_layout_cache();
554 self.invalidate_validation_cache();
555
556 Ok(())
557 }
558
559 pub fn reload_schema_parsed(
573 &mut self,
574 parsed: Arc<ParsedSchema>,
575 context: Option<&str>,
576 data: Option<&str>,
577 ) -> Result<(), String> {
578 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
579 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
580
581 self.schema = Arc::clone(&parsed.schema);
583 self.evaluations = parsed.evaluations.clone();
584 self.tables = parsed.tables.clone();
585 self.table_metadata = parsed.table_metadata.clone();
586 self.dependencies = parsed.dependencies.clone();
587 self.sorted_evaluations = parsed.sorted_evaluations.clone();
588 self.dependents_evaluations = parsed.dependents_evaluations.clone();
589 self.rules_evaluations = parsed.rules_evaluations.clone();
590 self.fields_with_rules = parsed.fields_with_rules.clone();
591 self.others_evaluations = parsed.others_evaluations.clone();
592 self.value_evaluations = parsed.value_evaluations.clone();
593 self.layout_paths = parsed.layout_paths.clone();
594 self.root_layout_paths = parsed.root_layout_paths.clone();
595 self.layout_field_refs = parsed.layout_field_refs.clone();
596 self.options_templates = parsed.options_templates.clone();
597 self.reffed_by = parsed.reffed_by.clone();
598 self.dep_formula_triggers = parsed.dep_formula_triggers.clone();
599 self.conditional_hidden_fields = parsed.conditional_hidden_fields.clone();
600 self.conditional_readonly_fields = parsed.conditional_readonly_fields.clone();
601 self.static_arrays = parsed.static_arrays.clone();
602
603 self.engine = parsed.engine.clone();
605
606 let mut subforms = IndexMap::new();
608 for (path, subform_parsed) in &parsed.subforms {
609 let subform_eval =
610 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
611 subforms.insert(path.clone(), Box::new(subform_eval));
612 }
613 self.subforms = subforms;
614
615 self.context = context.clone();
616 self.data = data.clone();
617 self.evaluated_schema = (*self.schema).clone();
618
619 self.eval_data =
621 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
622 self.eval_cache.clear();
623 self.engine.clear_indices();
624 if let Ok(mut cache) = self.regex_cache.write() {
625 cache.clear();
626 }
627
628 self.cached_msgpack_schema = None;
630 self.invalidate_layout_cache();
631 self.invalidate_validation_cache();
632
633 Ok(())
634 }
635
636 pub fn reload_schema_from_cache(
650 &mut self,
651 cache_key: &str,
652 context: Option<&str>,
653 data: Option<&str>,
654 ) -> Result<(), String> {
655 let parsed = PARSED_SCHEMA_CACHE
657 .get(cache_key)
658 .ok_or_else(|| format!("Schema '{}' not found in cache", cache_key))?;
659
660 self.reload_schema_parsed(parsed, context, data)
662 }
663}