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 layout_field_refs: self.layout_field_refs.clone(),
34 options_templates: self.options_templates.clone(),
35 subforms: self.subforms.clone(),
36 reffed_by: self.reffed_by.clone(),
37 dep_formula_triggers: self.dep_formula_triggers.clone(),
38 context: self.context.clone(),
39 data: self.data.clone(),
40 evaluated_schema: self.evaluated_schema.clone(),
41 eval_data: self.eval_data.clone(),
42 eval_cache: self.eval_cache.clone(),
43 eval_lock: Mutex::new(()), cached_msgpack_schema: self.cached_msgpack_schema.clone(),
45 resolved_layout_cache: None,
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_hidden_refs: indexmap::IndexSet::new(),
51 layout_visible_refs: indexmap::IndexSet::new(),
52 layout_condition_hidden_refs: indexmap::IndexSet::new(),
53 }
54 }
55}
56
57impl JSONEval {
58 pub fn new(
59 schema: &str,
60 context: Option<&str>,
61 data: Option<&str>,
62 ) -> Result<Self, serde_json::Error> {
63 time_block!("JSONEval::new() [total]", {
64 let mut schema_val: Value =
66 time_block!(" parse schema JSON", { serde_json::from_str(schema)? });
67 let context: Value = time_block!(" parse context JSON", {
68 json_parser::parse_json_str(context.unwrap_or("{}"))
69 .map_err(serde_json::Error::custom)?
70 });
71 let data: Value = time_block!(" parse data JSON", {
72 json_parser::parse_json_str(data.unwrap_or("{}"))
73 .map_err(serde_json::Error::custom)?
74 });
75
76 let static_arrays = if let Some(params) = schema_val
78 .get_mut("$params")
79 .and_then(|v| v.as_object_mut())
80 {
81 crate::jsoneval::static_arrays::extract_from_params(params)
82 } else {
83 IndexMap::new()
84 };
85 let static_arrays = Arc::new(static_arrays);
86 let evaluated_schema = schema_val.clone();
87
88 let engine_config = RLogicConfig::default();
90 let mut engine = RLogic::with_config(engine_config);
91 engine.set_static_arrays(Arc::clone(&static_arrays));
92
93 let mut instance = time_block!(" create instance struct", {
94 Self {
95 schema: Arc::new(schema_val),
96 evaluations: Arc::new(IndexMap::new()),
97 tables: Arc::new(IndexMap::new()),
98 table_metadata: Arc::new(IndexMap::new()),
99 dependencies: Arc::new(IndexMap::new()),
100 sorted_evaluations: Arc::new(Vec::new()),
101 dependents_evaluations: Arc::new(IndexMap::new()),
102 rules_evaluations: Arc::new(Vec::new()),
103 fields_with_rules: Arc::new(Vec::new()),
104 others_evaluations: Arc::new(Vec::new()),
105 value_evaluations: Arc::new(Vec::new()),
106 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 resolved_layout_cache: None,
125 conditional_hidden_fields: Arc::new(Vec::new()),
126 conditional_readonly_fields: Arc::new(Vec::new()),
127 static_arrays,
128 regex_cache: RwLock::new(HashMap::new()),
129 layout_hidden_refs: indexmap::IndexSet::new(),
130 layout_visible_refs: indexmap::IndexSet::new(),
131 layout_condition_hidden_refs: indexmap::IndexSet::new(),
132 }
133 });
134 time_block!(" parse_schema", {
135 parse_schema::legacy::parse_schema(&mut instance)
136 .map_err(serde_json::Error::custom)?
137 });
138 Ok(instance)
139 })
140 }
141
142 pub(crate) fn new_subform(
144 schema_val: Value,
145 context: Value,
146 static_arrays: Arc<IndexMap<String, Arc<Value>>>,
147 ) -> Result<Self, serde_json::Error> {
148 time_block!("JSONEval::new_subform() [total]", {
149 let data = Value::Object(serde_json::Map::new());
151 let evaluated_schema = schema_val.clone();
152
153 let engine_config = RLogicConfig::default();
155 let mut engine = RLogic::with_config(engine_config);
156 engine.set_static_arrays(Arc::clone(&static_arrays));
157
158 let mut instance = time_block!(" create instance struct", {
159 Self {
160 schema: Arc::new(schema_val),
161 evaluations: Arc::new(IndexMap::new()),
162 tables: Arc::new(IndexMap::new()),
163 table_metadata: Arc::new(IndexMap::new()),
164 dependencies: Arc::new(IndexMap::new()),
165 sorted_evaluations: Arc::new(Vec::new()),
166 dependents_evaluations: Arc::new(IndexMap::new()),
167 rules_evaluations: Arc::new(Vec::new()),
168 fields_with_rules: Arc::new(Vec::new()),
169 others_evaluations: Arc::new(Vec::new()),
170 value_evaluations: Arc::new(Vec::new()),
171 layout_paths: Arc::new(Vec::new()),
172 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
173 options_templates: Arc::new(Vec::new()),
174 subforms: IndexMap::new(),
175 engine: Arc::new(engine),
176 reffed_by: Arc::new(IndexMap::new()),
177 dep_formula_triggers: Arc::new(IndexMap::new()),
178 context: context.clone(),
179 data: data.clone(),
180 evaluated_schema: evaluated_schema.clone(),
181 eval_data: EvalData::with_schema_data_context(
182 &evaluated_schema,
183 &data,
184 &context,
185 ),
186 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
187 eval_lock: Mutex::new(()),
188 cached_msgpack_schema: None,
189 resolved_layout_cache: None,
190 conditional_hidden_fields: Arc::new(Vec::new()),
191 conditional_readonly_fields: Arc::new(Vec::new()),
192 static_arrays,
193 regex_cache: RwLock::new(HashMap::new()),
194 layout_hidden_refs: indexmap::IndexSet::new(),
195 layout_visible_refs: indexmap::IndexSet::new(),
196 layout_condition_hidden_refs: indexmap::IndexSet::new(),
197 }
198 });
199 time_block!(" parse_schema", {
200 parse_schema::legacy::parse_schema(&mut instance)
201 .map_err(serde_json::Error::custom)?
202 });
203 Ok(instance)
204 })
205 }
206
207 pub fn new_from_msgpack(
219 schema_msgpack: &[u8],
220 context: Option<&str>,
221 data: Option<&str>,
222 ) -> Result<Self, String> {
223 let cached_msgpack = schema_msgpack.to_vec();
225
226 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
228 .map_err(|e| format!("Failed to deserialize MessagePack schema: {}", e))?;
229
230 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
231 .map_err(|e| format!("Failed to parse context: {}", e))?;
232 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
233 .map_err(|e| format!("Failed to parse data: {}", e))?;
234
235 let static_arrays = if let Some(params) = schema_val
237 .get_mut("$params")
238 .and_then(|v| v.as_object_mut())
239 {
240 crate::jsoneval::static_arrays::extract_from_params(params)
241 } else {
242 IndexMap::new()
243 };
244 let static_arrays = Arc::new(static_arrays);
245 let evaluated_schema = schema_val.clone();
246
247 let engine_config = RLogicConfig::default();
248 let mut engine = RLogic::with_config(engine_config);
249 engine.set_static_arrays(Arc::clone(&static_arrays));
250
251 let mut instance = Self {
252 schema: Arc::new(schema_val),
253 evaluations: Arc::new(IndexMap::new()),
254 tables: Arc::new(IndexMap::new()),
255 table_metadata: Arc::new(IndexMap::new()),
256 dependencies: Arc::new(IndexMap::new()),
257 sorted_evaluations: Arc::new(Vec::new()),
258 dependents_evaluations: Arc::new(IndexMap::new()),
259 rules_evaluations: Arc::new(Vec::new()),
260 fields_with_rules: Arc::new(Vec::new()),
261 others_evaluations: Arc::new(Vec::new()),
262 value_evaluations: Arc::new(Vec::new()),
263 layout_paths: Arc::new(Vec::new()),
264 layout_field_refs: Arc::new(indexmap::IndexSet::new()),
265 options_templates: Arc::new(Vec::new()),
266 subforms: IndexMap::new(),
267 engine: Arc::new(engine),
268 reffed_by: Arc::new(IndexMap::new()),
269 dep_formula_triggers: Arc::new(IndexMap::new()),
270 context: context.clone(),
271 data: data.clone(),
272 evaluated_schema: evaluated_schema.clone(),
273 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
274 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
275 eval_lock: Mutex::new(()),
276 cached_msgpack_schema: Some(cached_msgpack),
277 resolved_layout_cache: None,
278 conditional_hidden_fields: Arc::new(Vec::new()),
279 conditional_readonly_fields: Arc::new(Vec::new()),
280 static_arrays,
281 regex_cache: RwLock::new(HashMap::new()),
282 layout_hidden_refs: indexmap::IndexSet::new(),
283 layout_visible_refs: indexmap::IndexSet::new(),
284 layout_condition_hidden_refs: indexmap::IndexSet::new(),
285 };
286 parse_schema::legacy::parse_schema(&mut instance)?;
287 Ok(instance)
288 }
289
290 pub fn with_parsed_schema(
318 parsed: Arc<ParsedSchema>,
319 context: Option<&str>,
320 data: Option<&str>,
321 ) -> Result<Self, String> {
322 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
323 .map_err(|e| format!("Failed to parse context: {}", e))?;
324 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
325 .map_err(|e| format!("Failed to parse data: {}", e))?;
326
327 let evaluated_schema = parsed.schema.clone();
328
329 let engine = parsed.engine.clone();
332
333 let mut subforms = IndexMap::new();
336 for (path, subform_parsed) in &parsed.subforms {
337 let subform_eval =
339 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
340 subforms.insert(path.clone(), Box::new(subform_eval));
341 }
342
343 let instance = Self {
344 schema: Arc::clone(&parsed.schema),
345 evaluations: Arc::clone(&parsed.evaluations),
346 tables: Arc::clone(&parsed.tables),
347 table_metadata: Arc::clone(&parsed.table_metadata),
348 dependencies: Arc::clone(&parsed.dependencies),
349 sorted_evaluations: Arc::clone(&parsed.sorted_evaluations),
350 dependents_evaluations: Arc::clone(&parsed.dependents_evaluations),
351 rules_evaluations: Arc::clone(&parsed.rules_evaluations),
352 fields_with_rules: Arc::clone(&parsed.fields_with_rules),
353 others_evaluations: Arc::clone(&parsed.others_evaluations),
354 value_evaluations: Arc::clone(&parsed.value_evaluations),
355 layout_paths: Arc::clone(&parsed.layout_paths),
356 layout_field_refs: Arc::clone(&parsed.layout_field_refs),
357 options_templates: Arc::clone(&parsed.options_templates),
358 subforms,
359 engine,
360 reffed_by: Arc::clone(&parsed.reffed_by),
361 dep_formula_triggers: Arc::clone(&parsed.dep_formula_triggers),
362 context: context.clone(),
363 data: data.clone(),
364 evaluated_schema: (*evaluated_schema).clone(),
365 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
366 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
367 eval_lock: Mutex::new(()),
368 cached_msgpack_schema: None,
369 resolved_layout_cache: None,
370 conditional_hidden_fields: Arc::clone(&parsed.conditional_hidden_fields),
371 conditional_readonly_fields: Arc::clone(&parsed.conditional_readonly_fields),
372 static_arrays: Arc::clone(&parsed.static_arrays),
373 regex_cache: RwLock::new(HashMap::new()),
374 layout_hidden_refs: indexmap::IndexSet::new(),
375 layout_visible_refs: indexmap::IndexSet::new(),
376 layout_condition_hidden_refs: indexmap::IndexSet::new(),
377 };
378 Ok(instance)
379 }
380
381 pub fn reload_schema(
382 &mut self,
383 schema: &str,
384 context: Option<&str>,
385 data: Option<&str>,
386 ) -> Result<(), String> {
387 let mut schema_val: Value =
389 serde_json::from_str(schema).map_err(|e| format!("failed to parse schema: {e}"))?;
390 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
391 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
392 self.context = context.clone();
393 self.data = data.clone();
394
395 let static_arrays = if let Some(params) = schema_val
396 .get_mut("$params")
397 .and_then(|v| v.as_object_mut())
398 {
399 crate::jsoneval::static_arrays::extract_from_params(params)
400 } else {
401 IndexMap::new()
402 };
403 let static_arrays = Arc::new(static_arrays);
404 self.static_arrays = Arc::clone(&static_arrays);
405 self.schema = Arc::new(schema_val);
406 self.evaluated_schema = (*self.schema).clone();
407
408 let mut engine = RLogic::new();
409 engine.set_static_arrays(static_arrays);
410 self.engine = Arc::new(engine);
411
412 self.evaluations = Arc::new(IndexMap::new());
413 self.tables = Arc::new(IndexMap::new());
414 self.table_metadata = Arc::new(IndexMap::new());
415 self.dependencies = Arc::new(IndexMap::new());
416 self.sorted_evaluations = Arc::new(Vec::new());
417 self.dependents_evaluations = Arc::new(IndexMap::new());
418 self.rules_evaluations = Arc::new(Vec::new());
419 self.fields_with_rules = Arc::new(Vec::new());
420 self.others_evaluations = Arc::new(Vec::new());
421 self.value_evaluations = Arc::new(Vec::new());
422 self.layout_paths = Arc::new(Vec::new());
423 self.options_templates = Arc::new(Vec::new());
424 self.reffed_by = Arc::new(IndexMap::new());
425 self.dep_formula_triggers = Arc::new(IndexMap::new());
426 self.conditional_hidden_fields = Arc::new(Vec::new());
427 self.conditional_readonly_fields = Arc::new(Vec::new());
428 self.subforms.clear();
429 parse_schema::legacy::parse_schema(self)?;
430
431 self.eval_data =
433 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
434 self.eval_cache.clear();
435 if let Ok(mut cache) = self.regex_cache.write() {
436 cache.clear();
437 }
438
439 self.cached_msgpack_schema = None;
441 self.resolved_layout_cache = None;
442 self.layout_hidden_refs.clear();
443 self.layout_visible_refs.clear();
444 self.layout_condition_hidden_refs.clear();
445
446 Ok(())
447 }
448
449 pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>) {
471 let mut config = RLogicConfig::default();
473 if let Some(offset) = offset_minutes {
474 config = config.with_timezone_offset(offset);
475 }
476
477 let mut engine = RLogic::with_config(config);
480 engine.set_static_arrays(Arc::clone(&self.static_arrays));
481 self.engine = Arc::new(engine);
482
483 let _ = parse_schema::legacy::parse_schema(self);
484 }
485
486 pub fn reload_schema_msgpack(
498 &mut self,
499 schema_msgpack: &[u8],
500 context: Option<&str>,
501 data: Option<&str>,
502 ) -> Result<(), String> {
503 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
505 .map_err(|e| format!("failed to deserialize MessagePack schema: {e}"))?;
506
507 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
508 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
509
510 self.context = context.clone();
511 self.data = data.clone();
512
513 let static_arrays = if let Some(params) = schema_val
514 .get_mut("$params")
515 .and_then(|v| v.as_object_mut())
516 {
517 crate::jsoneval::static_arrays::extract_from_params(params)
518 } else {
519 IndexMap::new()
520 };
521 let static_arrays = Arc::new(static_arrays);
522 self.static_arrays = Arc::clone(&static_arrays);
523 self.schema = Arc::new(schema_val);
524 self.evaluated_schema = (*self.schema).clone();
525
526 let mut engine = RLogic::new();
527 engine.set_static_arrays(static_arrays);
528 self.engine = Arc::new(engine);
529 self.evaluations = Arc::new(IndexMap::new());
530 self.tables = Arc::new(IndexMap::new());
531 self.table_metadata = Arc::new(IndexMap::new());
532 self.dependencies = Arc::new(IndexMap::new());
533 self.sorted_evaluations = Arc::new(Vec::new());
534 self.dependents_evaluations = Arc::new(IndexMap::new());
535 self.rules_evaluations = Arc::new(Vec::new());
536 self.fields_with_rules = Arc::new(Vec::new());
537 self.others_evaluations = Arc::new(Vec::new());
538 self.value_evaluations = Arc::new(Vec::new());
539 self.layout_paths = Arc::new(Vec::new());
540 self.options_templates = Arc::new(Vec::new());
541 self.reffed_by = Arc::new(IndexMap::new());
542 self.dep_formula_triggers = Arc::new(IndexMap::new());
543 self.conditional_hidden_fields = Arc::new(Vec::new());
544 self.conditional_readonly_fields = Arc::new(Vec::new());
545 self.subforms.clear();
546 parse_schema::legacy::parse_schema(self)?;
547
548 self.eval_data =
550 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
551 self.eval_cache.clear();
552 if let Ok(mut cache) = self.regex_cache.write() {
553 cache.clear();
554 }
555
556 self.cached_msgpack_schema = Some(schema_msgpack.to_vec());
558 self.resolved_layout_cache = None;
559 self.layout_hidden_refs.clear();
560 self.layout_visible_refs.clear();
561 self.layout_condition_hidden_refs.clear();
562
563 Ok(())
564 }
565
566 pub fn reload_schema_parsed(
580 &mut self,
581 parsed: Arc<ParsedSchema>,
582 context: Option<&str>,
583 data: Option<&str>,
584 ) -> Result<(), String> {
585 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
586 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
587
588 self.schema = Arc::clone(&parsed.schema);
590 self.evaluations = parsed.evaluations.clone();
591 self.tables = parsed.tables.clone();
592 self.table_metadata = parsed.table_metadata.clone();
593 self.dependencies = parsed.dependencies.clone();
594 self.sorted_evaluations = parsed.sorted_evaluations.clone();
595 self.dependents_evaluations = parsed.dependents_evaluations.clone();
596 self.rules_evaluations = parsed.rules_evaluations.clone();
597 self.fields_with_rules = parsed.fields_with_rules.clone();
598 self.others_evaluations = parsed.others_evaluations.clone();
599 self.value_evaluations = parsed.value_evaluations.clone();
600 self.layout_paths = parsed.layout_paths.clone();
601 self.options_templates = parsed.options_templates.clone();
602 self.static_arrays = parsed.static_arrays.clone();
603 self.dep_formula_triggers = parsed.dep_formula_triggers.clone();
604
605 self.engine = parsed.engine.clone();
607
608 let mut subforms = IndexMap::new();
610 for (path, subform_parsed) in &parsed.subforms {
611 let subform_eval =
612 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
613 subforms.insert(path.clone(), Box::new(subform_eval));
614 }
615 self.subforms = subforms;
616
617 self.context = context.clone();
618 self.data = data.clone();
619 self.evaluated_schema = (*self.schema).clone();
620
621 self.eval_data =
623 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
624 self.eval_cache.clear();
625 self.engine.clear_indices();
626 if let Ok(mut cache) = self.regex_cache.write() {
627 cache.clear();
628 }
629
630 self.cached_msgpack_schema = None;
632 self.resolved_layout_cache = None;
633 self.layout_hidden_refs.clear();
634 self.layout_visible_refs.clear();
635 self.layout_condition_hidden_refs.clear();
636
637 Ok(())
638 }
639
640 pub fn reload_schema_from_cache(
654 &mut self,
655 cache_key: &str,
656 context: Option<&str>,
657 data: Option<&str>,
658 ) -> Result<(), String> {
659 let parsed = PARSED_SCHEMA_CACHE
661 .get(cache_key)
662 .ok_or_else(|| format!("Schema '{}' not found in cache", cache_key))?;
663
664 self.reload_schema_parsed(parsed, context, data)
666 }
667}