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(
129 crate::jsoneval::layout::LayoutResolutionState::default(),
130 ),
131 validation_cache: RwLock::new(
132 crate::jsoneval::validation_cache::ValidationCache::default(),
133 ),
134 }
135 });
136 time_block!(" parse_schema", {
137 parse_schema::legacy::parse_schema(&mut instance)
138 .map_err(serde_json::Error::custom)?
139 });
140 Ok(instance)
141 })
142 }
143
144 pub(crate) fn new_subform(
146 schema_val: Value,
147 context: Value,
148 static_arrays: Arc<IndexMap<String, Arc<Value>>>,
149 ) -> Result<Self, serde_json::Error> {
150 time_block!("JSONEval::new_subform() [total]", {
151 let data = Value::Object(serde_json::Map::new());
153 let evaluated_schema = schema_val.clone();
154
155 let engine_config = RLogicConfig::default();
157 let engine = RLogic::with_config(engine_config);
158 engine.set_static_arrays(Arc::clone(&static_arrays));
159
160 let mut instance = time_block!(" create instance struct", {
161 Self {
162 schema: Arc::new(schema_val),
163 evaluations: Arc::new(IndexMap::new()),
164 tables: Arc::new(IndexMap::new()),
165 table_metadata: Arc::new(IndexMap::new()),
166 dependencies: Arc::new(IndexMap::new()),
167 sorted_evaluations: Arc::new(Vec::new()),
168 dependents_evaluations: Arc::new(IndexMap::new()),
169 rules_evaluations: Arc::new(Vec::new()),
170 fields_with_rules: Arc::new(Vec::new()),
171 others_evaluations: Arc::new(Vec::new()),
172 value_evaluations: Arc::new(Vec::new()),
173 layout_paths: Arc::new(Vec::new()),
174 root_layout_paths: Arc::new(Vec::new()),
175 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
176 options_templates: Arc::new(Vec::new()),
177 subforms: IndexMap::new(),
178 engine: Arc::new(engine),
179 reffed_by: Arc::new(IndexMap::new()),
180 dep_formula_triggers: Arc::new(IndexMap::new()),
181 context: context.clone(),
182 data: data.clone(),
183 evaluated_schema: evaluated_schema.clone(),
184 eval_data: EvalData::with_schema_data_context(
185 &evaluated_schema,
186 &data,
187 &context,
188 ),
189 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
190 eval_lock: Mutex::new(()),
191 cached_msgpack_schema: None,
192 conditional_hidden_fields: Arc::new(Vec::new()),
193 conditional_readonly_fields: Arc::new(Vec::new()),
194 static_arrays,
195 regex_cache: RwLock::new(HashMap::new()),
196 layout_state: RwLock::new(
197 crate::jsoneval::layout::LayoutResolutionState::default(),
198 ),
199 validation_cache: RwLock::new(
200 crate::jsoneval::validation_cache::ValidationCache::default(),
201 ),
202 }
203 });
204 time_block!(" parse_schema", {
205 parse_schema::legacy::parse_schema(&mut instance)
206 .map_err(serde_json::Error::custom)?
207 });
208 Ok(instance)
209 })
210 }
211
212 pub fn new_from_msgpack(
224 schema_msgpack: &[u8],
225 context: Option<&str>,
226 data: Option<&str>,
227 ) -> Result<Self, String> {
228 let cached_msgpack = schema_msgpack.to_vec();
230
231 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
233 .map_err(|e| format!("Failed to deserialize MessagePack schema: {}", e))?;
234
235 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
236 .map_err(|e| format!("Failed to parse context: {}", e))?;
237 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
238 .map_err(|e| format!("Failed to parse data: {}", e))?;
239
240 let static_arrays = if let Some(params) = schema_val
242 .get_mut("$params")
243 .and_then(|v| v.as_object_mut())
244 {
245 crate::jsoneval::static_arrays::extract_from_params(params)
246 } else {
247 IndexMap::new()
248 };
249 let static_arrays = Arc::new(static_arrays);
250 let evaluated_schema = schema_val.clone();
251
252 let engine_config = RLogicConfig::default();
253 let engine = RLogic::with_config(engine_config);
254 engine.set_static_arrays(Arc::clone(&static_arrays));
255
256 let mut instance = Self {
257 schema: Arc::new(schema_val),
258 evaluations: Arc::new(IndexMap::new()),
259 tables: Arc::new(IndexMap::new()),
260 table_metadata: Arc::new(IndexMap::new()),
261 dependencies: Arc::new(IndexMap::new()),
262 sorted_evaluations: Arc::new(Vec::new()),
263 dependents_evaluations: Arc::new(IndexMap::new()),
264 rules_evaluations: Arc::new(Vec::new()),
265 fields_with_rules: Arc::new(Vec::new()),
266 others_evaluations: Arc::new(Vec::new()),
267 value_evaluations: Arc::new(Vec::new()),
268 layout_paths: Arc::new(Vec::new()),
269 root_layout_paths: Arc::new(Vec::new()),
270 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
271 options_templates: Arc::new(Vec::new()),
272 subforms: IndexMap::new(),
273 engine: Arc::new(engine),
274 reffed_by: Arc::new(IndexMap::new()),
275 dep_formula_triggers: Arc::new(IndexMap::new()),
276 context: context.clone(),
277 data: data.clone(),
278 evaluated_schema: evaluated_schema.clone(),
279 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
280 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
281 eval_lock: Mutex::new(()),
282 cached_msgpack_schema: Some(cached_msgpack),
283 conditional_hidden_fields: Arc::new(Vec::new()),
284 conditional_readonly_fields: Arc::new(Vec::new()),
285 static_arrays,
286 regex_cache: RwLock::new(HashMap::new()),
287 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
288 validation_cache: RwLock::new(
289 crate::jsoneval::validation_cache::ValidationCache::default(),
290 ),
291 };
292 parse_schema::legacy::parse_schema(&mut instance)?;
293 Ok(instance)
294 }
295
296 pub fn with_parsed_schema(
324 parsed: Arc<ParsedSchema>,
325 context: Option<&str>,
326 data: Option<&str>,
327 ) -> Result<Self, String> {
328 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
329 .map_err(|e| format!("Failed to parse context: {}", e))?;
330 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
331 .map_err(|e| format!("Failed to parse data: {}", e))?;
332
333 let evaluated_schema = parsed.schema.clone();
334
335 let engine = parsed.engine.clone();
338
339 let mut subforms = IndexMap::new();
342 for (path, subform_parsed) in &parsed.subforms {
343 let subform_eval =
345 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
346 subforms.insert(path.clone(), Box::new(subform_eval));
347 }
348
349 let instance = Self {
350 schema: Arc::clone(&parsed.schema),
351 evaluations: Arc::clone(&parsed.evaluations),
352 tables: Arc::clone(&parsed.tables),
353 table_metadata: Arc::clone(&parsed.table_metadata),
354 dependencies: Arc::clone(&parsed.dependencies),
355 sorted_evaluations: Arc::clone(&parsed.sorted_evaluations),
356 dependents_evaluations: Arc::clone(&parsed.dependents_evaluations),
357 rules_evaluations: Arc::clone(&parsed.rules_evaluations),
358 fields_with_rules: Arc::clone(&parsed.fields_with_rules),
359 others_evaluations: Arc::clone(&parsed.others_evaluations),
360 value_evaluations: Arc::clone(&parsed.value_evaluations),
361 layout_paths: Arc::clone(&parsed.layout_paths),
362 root_layout_paths: Arc::clone(&parsed.root_layout_paths),
363 layout_field_refs: Arc::clone(&parsed.layout_field_refs),
364 options_templates: Arc::clone(&parsed.options_templates),
365 subforms,
366 engine,
367 reffed_by: Arc::clone(&parsed.reffed_by),
368 dep_formula_triggers: Arc::clone(&parsed.dep_formula_triggers),
369 context: context.clone(),
370 data: data.clone(),
371 evaluated_schema: (*evaluated_schema).clone(),
372 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
373 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
374 eval_lock: Mutex::new(()),
375 cached_msgpack_schema: None,
376 conditional_hidden_fields: Arc::clone(&parsed.conditional_hidden_fields),
377 conditional_readonly_fields: Arc::clone(&parsed.conditional_readonly_fields),
378 static_arrays: Arc::clone(&parsed.static_arrays),
379 regex_cache: RwLock::new(HashMap::new()),
380 layout_state: RwLock::new(crate::jsoneval::layout::LayoutResolutionState::default()),
381 validation_cache: RwLock::new(
382 crate::jsoneval::validation_cache::ValidationCache::default(),
383 ),
384 };
385 Ok(instance)
386 }
387
388 pub fn reload_schema(
389 &mut self,
390 schema: &str,
391 context: Option<&str>,
392 data: Option<&str>,
393 ) -> Result<(), String> {
394 let mut schema_val: Value =
396 serde_json::from_str(schema).map_err(|e| format!("failed to parse schema: {e}"))?;
397 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
398 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
399 self.context = context.clone();
400 self.data = data.clone();
401
402 let static_arrays = if let Some(params) = schema_val
403 .get_mut("$params")
404 .and_then(|v| v.as_object_mut())
405 {
406 crate::jsoneval::static_arrays::extract_from_params(params)
407 } else {
408 IndexMap::new()
409 };
410 let static_arrays = Arc::new(static_arrays);
411 self.static_arrays = Arc::clone(&static_arrays);
412 self.schema = Arc::new(schema_val);
413 self.evaluated_schema = (*self.schema).clone();
414
415 let engine = RLogic::new();
416 engine.set_static_arrays(static_arrays);
417 self.engine = Arc::new(engine);
418
419 self.evaluations = Arc::new(IndexMap::new());
420 self.tables = Arc::new(IndexMap::new());
421 self.table_metadata = Arc::new(IndexMap::new());
422 self.dependencies = Arc::new(IndexMap::new());
423 self.sorted_evaluations = Arc::new(Vec::new());
424 self.dependents_evaluations = Arc::new(IndexMap::new());
425 self.rules_evaluations = Arc::new(Vec::new());
426 self.fields_with_rules = Arc::new(Vec::new());
427 self.others_evaluations = Arc::new(Vec::new());
428 self.value_evaluations = Arc::new(Vec::new());
429 self.layout_paths = Arc::new(Vec::new());
430 self.root_layout_paths = Arc::new(Vec::new());
431 self.options_templates = Arc::new(Vec::new());
432 self.reffed_by = Arc::new(IndexMap::new());
433 self.dep_formula_triggers = Arc::new(IndexMap::new());
434 self.conditional_hidden_fields = Arc::new(Vec::new());
435 self.conditional_readonly_fields = Arc::new(Vec::new());
436 self.subforms.clear();
437 parse_schema::legacy::parse_schema(self)?;
438
439 self.eval_data =
441 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
442 self.eval_cache.clear();
443 if let Ok(mut cache) = self.regex_cache.write() {
444 cache.clear();
445 }
446
447 self.cached_msgpack_schema = None;
449 self.invalidate_layout_cache();
450 self.invalidate_validation_cache();
451
452 Ok(())
453 }
454
455 pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>) {
477 let mut config = RLogicConfig::default();
479 if let Some(offset) = offset_minutes {
480 config = config.with_timezone_offset(offset);
481 }
482
483 let engine = RLogic::with_config(config);
486 engine.set_static_arrays(Arc::clone(&self.static_arrays));
487 self.engine = Arc::new(engine);
488
489 let _ = parse_schema::legacy::parse_schema(self);
490 }
491
492 pub fn reload_schema_msgpack(
504 &mut self,
505 schema_msgpack: &[u8],
506 context: Option<&str>,
507 data: Option<&str>,
508 ) -> Result<(), String> {
509 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
511 .map_err(|e| format!("failed to deserialize MessagePack schema: {e}"))?;
512
513 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
514 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
515
516 self.context = context.clone();
517 self.data = data.clone();
518
519 let static_arrays = if let Some(params) = schema_val
520 .get_mut("$params")
521 .and_then(|v| v.as_object_mut())
522 {
523 crate::jsoneval::static_arrays::extract_from_params(params)
524 } else {
525 IndexMap::new()
526 };
527 let static_arrays = Arc::new(static_arrays);
528 self.static_arrays = Arc::clone(&static_arrays);
529 self.schema = Arc::new(schema_val);
530 self.evaluated_schema = (*self.schema).clone();
531
532 let engine = RLogic::new();
533 engine.set_static_arrays(static_arrays);
534 self.engine = Arc::new(engine);
535 self.evaluations = Arc::new(IndexMap::new());
536 self.tables = Arc::new(IndexMap::new());
537 self.table_metadata = Arc::new(IndexMap::new());
538 self.dependencies = Arc::new(IndexMap::new());
539 self.sorted_evaluations = Arc::new(Vec::new());
540 self.dependents_evaluations = Arc::new(IndexMap::new());
541 self.rules_evaluations = Arc::new(Vec::new());
542 self.fields_with_rules = Arc::new(Vec::new());
543 self.others_evaluations = Arc::new(Vec::new());
544 self.value_evaluations = Arc::new(Vec::new());
545 self.layout_paths = Arc::new(Vec::new());
546 self.root_layout_paths = Arc::new(Vec::new());
547 self.options_templates = Arc::new(Vec::new());
548 self.reffed_by = Arc::new(IndexMap::new());
549 self.dep_formula_triggers = Arc::new(IndexMap::new());
550 self.conditional_hidden_fields = Arc::new(Vec::new());
551 self.conditional_readonly_fields = Arc::new(Vec::new());
552 self.subforms.clear();
553 parse_schema::legacy::parse_schema(self)?;
554
555 self.eval_data =
557 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
558 self.eval_cache.clear();
559 if let Ok(mut cache) = self.regex_cache.write() {
560 cache.clear();
561 }
562
563 self.cached_msgpack_schema = Some(schema_msgpack.to_vec());
565 self.invalidate_layout_cache();
566 self.invalidate_validation_cache();
567
568 Ok(())
569 }
570
571 pub fn reload_schema_parsed(
585 &mut self,
586 parsed: Arc<ParsedSchema>,
587 context: Option<&str>,
588 data: Option<&str>,
589 ) -> Result<(), String> {
590 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
591 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
592
593 self.schema = Arc::clone(&parsed.schema);
595 self.evaluations = parsed.evaluations.clone();
596 self.tables = parsed.tables.clone();
597 self.table_metadata = parsed.table_metadata.clone();
598 self.dependencies = parsed.dependencies.clone();
599 self.sorted_evaluations = parsed.sorted_evaluations.clone();
600 self.dependents_evaluations = parsed.dependents_evaluations.clone();
601 self.rules_evaluations = parsed.rules_evaluations.clone();
602 self.fields_with_rules = parsed.fields_with_rules.clone();
603 self.others_evaluations = parsed.others_evaluations.clone();
604 self.value_evaluations = parsed.value_evaluations.clone();
605 self.layout_paths = parsed.layout_paths.clone();
606 self.root_layout_paths = parsed.root_layout_paths.clone();
607 self.layout_field_refs = parsed.layout_field_refs.clone();
608 self.options_templates = parsed.options_templates.clone();
609 self.reffed_by = parsed.reffed_by.clone();
610 self.dep_formula_triggers = parsed.dep_formula_triggers.clone();
611 self.conditional_hidden_fields = parsed.conditional_hidden_fields.clone();
612 self.conditional_readonly_fields = parsed.conditional_readonly_fields.clone();
613 self.static_arrays = parsed.static_arrays.clone();
614
615 self.engine = parsed.engine.clone();
617
618 let mut subforms = IndexMap::new();
620 for (path, subform_parsed) in &parsed.subforms {
621 let subform_eval =
622 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
623 subforms.insert(path.clone(), Box::new(subform_eval));
624 }
625 self.subforms = subforms;
626
627 self.context = context.clone();
628 self.data = data.clone();
629 self.evaluated_schema = (*self.schema).clone();
630
631 self.eval_data =
633 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
634 self.eval_cache.clear();
635 self.engine.clear_indices();
636 if let Ok(mut cache) = self.regex_cache.write() {
637 cache.clear();
638 }
639
640 self.cached_msgpack_schema = None;
642 self.invalidate_layout_cache();
643 self.invalidate_validation_cache();
644
645 Ok(())
646 }
647
648 pub fn reload_schema_from_cache(
662 &mut self,
663 cache_key: &str,
664 context: Option<&str>,
665 data: Option<&str>,
666 ) -> Result<(), String> {
667 let parsed = PARSED_SCHEMA_CACHE
669 .get(cache_key)
670 .ok_or_else(|| format!("Schema '{}' not found in cache", cache_key))?;
671
672 self.reload_schema_parsed(parsed, context, data)
674 }
675}