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 dep_formula_triggers: self.dep_formula_triggers.clone(),
37 context: self.context.clone(),
38 data: self.data.clone(),
39 evaluated_schema: self.evaluated_schema.clone(),
40 eval_data: self.eval_data.clone(),
41 eval_cache: self.eval_cache.clone(),
42 eval_lock: Mutex::new(()), cached_msgpack_schema: self.cached_msgpack_schema.clone(),
44 resolved_layout_cache: None,
45 conditional_hidden_fields: self.conditional_hidden_fields.clone(),
46 conditional_readonly_fields: self.conditional_readonly_fields.clone(),
47 static_arrays: self.static_arrays.clone(),
48 regex_cache: RwLock::new(HashMap::new()),
49 layout_hidden_refs: indexmap::IndexSet::new(),
50 layout_visible_refs: indexmap::IndexSet::new(),
51 layout_condition_hidden_refs: indexmap::IndexSet::new(),
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 mut 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 options_templates: Arc::new(Vec::new()),
107 subforms: IndexMap::new(),
108 engine: Arc::new(engine),
109 reffed_by: Arc::new(IndexMap::new()),
110 dep_formula_triggers: Arc::new(IndexMap::new()),
111 context: context.clone(),
112 data: data.clone(),
113 evaluated_schema: evaluated_schema.clone(),
114 eval_data: EvalData::with_schema_data_context(
115 &evaluated_schema,
116 &data,
117 &context,
118 ),
119 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
120 eval_lock: Mutex::new(()),
121 cached_msgpack_schema: None,
122 resolved_layout_cache: None,
123 conditional_hidden_fields: Arc::new(Vec::new()),
124 conditional_readonly_fields: Arc::new(Vec::new()),
125 static_arrays,
126 regex_cache: RwLock::new(HashMap::new()),
127 layout_hidden_refs: indexmap::IndexSet::new(),
128 layout_visible_refs: indexmap::IndexSet::new(),
129 layout_condition_hidden_refs: indexmap::IndexSet::new(),
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 mut 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 options_templates: Arc::new(Vec::new()),
171 subforms: IndexMap::new(),
172 engine: Arc::new(engine),
173 reffed_by: Arc::new(IndexMap::new()),
174 dep_formula_triggers: Arc::new(IndexMap::new()),
175 context: context.clone(),
176 data: data.clone(),
177 evaluated_schema: evaluated_schema.clone(),
178 eval_data: EvalData::with_schema_data_context(
179 &evaluated_schema,
180 &data,
181 &context,
182 ),
183 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
184 eval_lock: Mutex::new(()),
185 cached_msgpack_schema: None,
186 resolved_layout_cache: None,
187 conditional_hidden_fields: Arc::new(Vec::new()),
188 conditional_readonly_fields: Arc::new(Vec::new()),
189 static_arrays,
190 regex_cache: RwLock::new(HashMap::new()),
191 layout_hidden_refs: indexmap::IndexSet::new(),
192 layout_visible_refs: indexmap::IndexSet::new(),
193 layout_condition_hidden_refs: indexmap::IndexSet::new(),
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 mut 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 options_templates: Arc::new(Vec::new()),
262 subforms: IndexMap::new(),
263 engine: Arc::new(engine),
264 reffed_by: Arc::new(IndexMap::new()),
265 dep_formula_triggers: Arc::new(IndexMap::new()),
266 context: context.clone(),
267 data: data.clone(),
268 evaluated_schema: evaluated_schema.clone(),
269 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
270 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
271 eval_lock: Mutex::new(()),
272 cached_msgpack_schema: Some(cached_msgpack),
273 resolved_layout_cache: None,
274 conditional_hidden_fields: Arc::new(Vec::new()),
275 conditional_readonly_fields: Arc::new(Vec::new()),
276 static_arrays,
277 regex_cache: RwLock::new(HashMap::new()),
278 layout_hidden_refs: indexmap::IndexSet::new(),
279 layout_visible_refs: indexmap::IndexSet::new(),
280 layout_condition_hidden_refs: indexmap::IndexSet::new(),
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 options_templates: Arc::clone(&parsed.options_templates),
353 subforms,
354 engine,
355 reffed_by: Arc::clone(&parsed.reffed_by),
356 dep_formula_triggers: Arc::clone(&parsed.dep_formula_triggers),
357 context: context.clone(),
358 data: data.clone(),
359 evaluated_schema: (*evaluated_schema).clone(),
360 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
361 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
362 eval_lock: Mutex::new(()),
363 cached_msgpack_schema: None,
364 resolved_layout_cache: None,
365 conditional_hidden_fields: Arc::clone(&parsed.conditional_hidden_fields),
366 conditional_readonly_fields: Arc::clone(&parsed.conditional_readonly_fields),
367 static_arrays: Arc::clone(&parsed.static_arrays),
368 regex_cache: RwLock::new(HashMap::new()),
369 layout_hidden_refs: indexmap::IndexSet::new(),
370 layout_visible_refs: indexmap::IndexSet::new(),
371 layout_condition_hidden_refs: indexmap::IndexSet::new(),
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 mut 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.options_templates = Arc::new(Vec::new());
419 self.reffed_by = Arc::new(IndexMap::new());
420 self.dep_formula_triggers = Arc::new(IndexMap::new());
421 self.conditional_hidden_fields = Arc::new(Vec::new());
422 self.conditional_readonly_fields = Arc::new(Vec::new());
423 self.subforms.clear();
424 parse_schema::legacy::parse_schema(self)?;
425
426 self.eval_data =
428 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
429 self.eval_cache.clear();
430 if let Ok(mut cache) = self.regex_cache.write() {
431 cache.clear();
432 }
433
434 self.cached_msgpack_schema = None;
436 self.resolved_layout_cache = None;
437 self.layout_hidden_refs.clear();
438 self.layout_visible_refs.clear();
439 self.layout_condition_hidden_refs.clear();
440
441 Ok(())
442 }
443
444 pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>) {
466 let mut config = RLogicConfig::default();
468 if let Some(offset) = offset_minutes {
469 config = config.with_timezone_offset(offset);
470 }
471
472 let mut engine = RLogic::with_config(config);
475 engine.set_static_arrays(Arc::clone(&self.static_arrays));
476 self.engine = Arc::new(engine);
477
478 let _ = parse_schema::legacy::parse_schema(self);
479 }
480
481 pub fn reload_schema_msgpack(
493 &mut self,
494 schema_msgpack: &[u8],
495 context: Option<&str>,
496 data: Option<&str>,
497 ) -> Result<(), String> {
498 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
500 .map_err(|e| format!("failed to deserialize MessagePack schema: {e}"))?;
501
502 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
503 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
504
505 self.context = context.clone();
506 self.data = data.clone();
507
508 let static_arrays = if let Some(params) = schema_val
509 .get_mut("$params")
510 .and_then(|v| v.as_object_mut())
511 {
512 crate::jsoneval::static_arrays::extract_from_params(params)
513 } else {
514 IndexMap::new()
515 };
516 let static_arrays = Arc::new(static_arrays);
517 self.static_arrays = Arc::clone(&static_arrays);
518 self.schema = Arc::new(schema_val);
519 self.evaluated_schema = (*self.schema).clone();
520
521 let mut engine = RLogic::new();
522 engine.set_static_arrays(static_arrays);
523 self.engine = Arc::new(engine);
524 self.evaluations = Arc::new(IndexMap::new());
525 self.tables = Arc::new(IndexMap::new());
526 self.table_metadata = Arc::new(IndexMap::new());
527 self.dependencies = Arc::new(IndexMap::new());
528 self.sorted_evaluations = Arc::new(Vec::new());
529 self.dependents_evaluations = Arc::new(IndexMap::new());
530 self.rules_evaluations = Arc::new(Vec::new());
531 self.fields_with_rules = Arc::new(Vec::new());
532 self.others_evaluations = Arc::new(Vec::new());
533 self.value_evaluations = Arc::new(Vec::new());
534 self.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.resolved_layout_cache = None;
554 self.layout_hidden_refs.clear();
555 self.layout_visible_refs.clear();
556 self.layout_condition_hidden_refs.clear();
557
558 Ok(())
559 }
560
561 pub fn reload_schema_parsed(
575 &mut self,
576 parsed: Arc<ParsedSchema>,
577 context: Option<&str>,
578 data: Option<&str>,
579 ) -> Result<(), String> {
580 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
581 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
582
583 self.schema = Arc::clone(&parsed.schema);
585 self.evaluations = parsed.evaluations.clone();
586 self.tables = parsed.tables.clone();
587 self.table_metadata = parsed.table_metadata.clone();
588 self.dependencies = parsed.dependencies.clone();
589 self.sorted_evaluations = parsed.sorted_evaluations.clone();
590 self.dependents_evaluations = parsed.dependents_evaluations.clone();
591 self.rules_evaluations = parsed.rules_evaluations.clone();
592 self.fields_with_rules = parsed.fields_with_rules.clone();
593 self.others_evaluations = parsed.others_evaluations.clone();
594 self.value_evaluations = parsed.value_evaluations.clone();
595 self.layout_paths = parsed.layout_paths.clone();
596 self.options_templates = parsed.options_templates.clone();
597 self.static_arrays = parsed.static_arrays.clone();
598 self.dep_formula_triggers = parsed.dep_formula_triggers.clone();
599
600 self.engine = parsed.engine.clone();
602
603 let mut subforms = IndexMap::new();
605 for (path, subform_parsed) in &parsed.subforms {
606 let subform_eval =
607 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
608 subforms.insert(path.clone(), Box::new(subform_eval));
609 }
610 self.subforms = subforms;
611
612 self.context = context.clone();
613 self.data = data.clone();
614 self.evaluated_schema = (*self.schema).clone();
615
616 self.eval_data =
618 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
619 self.eval_cache.clear();
620 self.engine.clear_indices();
621 if let Ok(mut cache) = self.regex_cache.write() {
622 cache.clear();
623 }
624
625 self.cached_msgpack_schema = None;
627 self.resolved_layout_cache = None;
628 self.layout_hidden_refs.clear();
629 self.layout_visible_refs.clear();
630 self.layout_condition_hidden_refs.clear();
631
632 Ok(())
633 }
634
635 pub fn reload_schema_from_cache(
649 &mut self,
650 cache_key: &str,
651 context: Option<&str>,
652 data: Option<&str>,
653 ) -> Result<(), String> {
654 let parsed = PARSED_SCHEMA_CACHE
656 .get(cache_key)
657 .ok_or_else(|| format!("Schema '{}' not found in cache", cache_key))?;
658
659 self.reload_schema_parsed(parsed, context, data)
661 }
662}