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 conditional_hidden_fields: self.conditional_hidden_fields.clone(),
45 conditional_readonly_fields: self.conditional_readonly_fields.clone(),
46 static_arrays: self.static_arrays.clone(),
47 regex_cache: RwLock::new(HashMap::new()),
48 }
49 }
50}
51
52impl JSONEval {
53 pub fn new(
54 schema: &str,
55 context: Option<&str>,
56 data: Option<&str>,
57 ) -> Result<Self, serde_json::Error> {
58 time_block!("JSONEval::new() [total]", {
59 let mut schema_val: Value =
61 time_block!(" parse schema JSON", { serde_json::from_str(schema)? });
62 let context: Value = time_block!(" parse context JSON", {
63 json_parser::parse_json_str(context.unwrap_or("{}"))
64 .map_err(serde_json::Error::custom)?
65 });
66 let data: Value = time_block!(" parse data JSON", {
67 json_parser::parse_json_str(data.unwrap_or("{}"))
68 .map_err(serde_json::Error::custom)?
69 });
70
71 let static_arrays = if let Some(params) = schema_val
73 .get_mut("$params")
74 .and_then(|v| v.as_object_mut())
75 {
76 crate::jsoneval::static_arrays::extract_from_params(params)
77 } else {
78 IndexMap::new()
79 };
80 let static_arrays = Arc::new(static_arrays);
81 let evaluated_schema = schema_val.clone();
82
83 let engine_config = RLogicConfig::default();
85 let mut engine = RLogic::with_config(engine_config);
86 engine.set_static_arrays(Arc::clone(&static_arrays));
87
88 let mut instance = time_block!(" create instance struct", {
89 Self {
90 schema: Arc::new(schema_val),
91 evaluations: Arc::new(IndexMap::new()),
92 tables: Arc::new(IndexMap::new()),
93 table_metadata: Arc::new(IndexMap::new()),
94 dependencies: Arc::new(IndexMap::new()),
95 sorted_evaluations: Arc::new(Vec::new()),
96 dependents_evaluations: Arc::new(IndexMap::new()),
97 rules_evaluations: Arc::new(Vec::new()),
98 fields_with_rules: Arc::new(Vec::new()),
99 others_evaluations: Arc::new(Vec::new()),
100 value_evaluations: Arc::new(Vec::new()),
101 layout_paths: Arc::new(Vec::new()),
102 options_templates: Arc::new(Vec::new()),
103 subforms: IndexMap::new(),
104 engine: Arc::new(engine),
105 reffed_by: Arc::new(IndexMap::new()),
106 dep_formula_triggers: Arc::new(IndexMap::new()),
107 context: context.clone(),
108 data: data.clone(),
109 evaluated_schema: evaluated_schema.clone(),
110 eval_data: EvalData::with_schema_data_context(
111 &evaluated_schema,
112 &data,
113 &context,
114 ),
115 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
116 eval_lock: Mutex::new(()),
117 cached_msgpack_schema: None,
118 conditional_hidden_fields: Arc::new(Vec::new()),
119 conditional_readonly_fields: Arc::new(Vec::new()),
120 static_arrays,
121 regex_cache: RwLock::new(HashMap::new()),
122 }
123 });
124 time_block!(" parse_schema", {
125 parse_schema::legacy::parse_schema(&mut instance)
126 .map_err(serde_json::Error::custom)?
127 });
128 Ok(instance)
129 })
130 }
131
132 pub(crate) fn new_subform(
134 schema_val: Value,
135 context: Value,
136 static_arrays: Arc<IndexMap<String, Arc<Value>>>,
137 ) -> Result<Self, serde_json::Error> {
138 time_block!("JSONEval::new_subform() [total]", {
139 let data = Value::Object(serde_json::Map::new());
141 let evaluated_schema = schema_val.clone();
142
143 let engine_config = RLogicConfig::default();
145 let mut engine = RLogic::with_config(engine_config);
146 engine.set_static_arrays(Arc::clone(&static_arrays));
147
148 let mut instance = time_block!(" create instance struct", {
149 Self {
150 schema: Arc::new(schema_val),
151 evaluations: Arc::new(IndexMap::new()),
152 tables: Arc::new(IndexMap::new()),
153 table_metadata: Arc::new(IndexMap::new()),
154 dependencies: Arc::new(IndexMap::new()),
155 sorted_evaluations: Arc::new(Vec::new()),
156 dependents_evaluations: Arc::new(IndexMap::new()),
157 rules_evaluations: Arc::new(Vec::new()),
158 fields_with_rules: Arc::new(Vec::new()),
159 others_evaluations: Arc::new(Vec::new()),
160 value_evaluations: Arc::new(Vec::new()),
161 layout_paths: Arc::new(Vec::new()),
162 options_templates: Arc::new(Vec::new()),
163 subforms: IndexMap::new(),
164 engine: Arc::new(engine),
165 reffed_by: Arc::new(IndexMap::new()),
166 dep_formula_triggers: Arc::new(IndexMap::new()),
167 context: context.clone(),
168 data: data.clone(),
169 evaluated_schema: evaluated_schema.clone(),
170 eval_data: EvalData::with_schema_data_context(
171 &evaluated_schema,
172 &data,
173 &context,
174 ),
175 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
176 eval_lock: Mutex::new(()),
177 cached_msgpack_schema: None,
178 conditional_hidden_fields: Arc::new(Vec::new()),
179 conditional_readonly_fields: Arc::new(Vec::new()),
180 static_arrays,
181 regex_cache: RwLock::new(HashMap::new()),
182 }
183 });
184 time_block!(" parse_schema", {
185 parse_schema::legacy::parse_schema(&mut instance)
186 .map_err(serde_json::Error::custom)?
187 });
188 Ok(instance)
189 })
190 }
191
192 pub fn new_from_msgpack(
204 schema_msgpack: &[u8],
205 context: Option<&str>,
206 data: Option<&str>,
207 ) -> Result<Self, String> {
208 let cached_msgpack = schema_msgpack.to_vec();
210
211 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
213 .map_err(|e| format!("Failed to deserialize MessagePack schema: {}", e))?;
214
215 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
216 .map_err(|e| format!("Failed to parse context: {}", e))?;
217 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
218 .map_err(|e| format!("Failed to parse data: {}", e))?;
219
220 let static_arrays = if let Some(params) = schema_val
222 .get_mut("$params")
223 .and_then(|v| v.as_object_mut())
224 {
225 crate::jsoneval::static_arrays::extract_from_params(params)
226 } else {
227 IndexMap::new()
228 };
229 let static_arrays = Arc::new(static_arrays);
230 let evaluated_schema = schema_val.clone();
231
232 let engine_config = RLogicConfig::default();
233 let mut engine = RLogic::with_config(engine_config);
234 engine.set_static_arrays(Arc::clone(&static_arrays));
235
236 let mut instance = Self {
237 schema: Arc::new(schema_val),
238 evaluations: Arc::new(IndexMap::new()),
239 tables: Arc::new(IndexMap::new()),
240 table_metadata: Arc::new(IndexMap::new()),
241 dependencies: Arc::new(IndexMap::new()),
242 sorted_evaluations: Arc::new(Vec::new()),
243 dependents_evaluations: Arc::new(IndexMap::new()),
244 rules_evaluations: Arc::new(Vec::new()),
245 fields_with_rules: Arc::new(Vec::new()),
246 others_evaluations: Arc::new(Vec::new()),
247 value_evaluations: Arc::new(Vec::new()),
248 layout_paths: Arc::new(Vec::new()),
249 options_templates: Arc::new(Vec::new()),
250 subforms: IndexMap::new(),
251 engine: Arc::new(engine),
252 reffed_by: Arc::new(IndexMap::new()),
253 dep_formula_triggers: Arc::new(IndexMap::new()),
254 context: context.clone(),
255 data: data.clone(),
256 evaluated_schema: evaluated_schema.clone(),
257 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
258 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
259 eval_lock: Mutex::new(()),
260 cached_msgpack_schema: Some(cached_msgpack),
261 conditional_hidden_fields: Arc::new(Vec::new()),
262 conditional_readonly_fields: Arc::new(Vec::new()),
263 static_arrays,
264 regex_cache: RwLock::new(HashMap::new()),
265 };
266 parse_schema::legacy::parse_schema(&mut instance)?;
267 Ok(instance)
268 }
269
270 pub fn with_parsed_schema(
298 parsed: Arc<ParsedSchema>,
299 context: Option<&str>,
300 data: Option<&str>,
301 ) -> Result<Self, String> {
302 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))
303 .map_err(|e| format!("Failed to parse context: {}", e))?;
304 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))
305 .map_err(|e| format!("Failed to parse data: {}", e))?;
306
307 let evaluated_schema = parsed.schema.clone();
308
309 let engine = parsed.engine.clone();
312
313 let mut subforms = IndexMap::new();
316 for (path, subform_parsed) in &parsed.subforms {
317 let subform_eval =
319 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
320 subforms.insert(path.clone(), Box::new(subform_eval));
321 }
322
323 let instance = Self {
324 schema: Arc::clone(&parsed.schema),
325 evaluations: Arc::clone(&parsed.evaluations),
326 tables: Arc::clone(&parsed.tables),
327 table_metadata: Arc::clone(&parsed.table_metadata),
328 dependencies: Arc::clone(&parsed.dependencies),
329 sorted_evaluations: Arc::clone(&parsed.sorted_evaluations),
330 dependents_evaluations: Arc::clone(&parsed.dependents_evaluations),
331 rules_evaluations: Arc::clone(&parsed.rules_evaluations),
332 fields_with_rules: Arc::clone(&parsed.fields_with_rules),
333 others_evaluations: Arc::clone(&parsed.others_evaluations),
334 value_evaluations: Arc::clone(&parsed.value_evaluations),
335 layout_paths: Arc::clone(&parsed.layout_paths),
336 options_templates: Arc::clone(&parsed.options_templates),
337 subforms,
338 engine,
339 reffed_by: Arc::clone(&parsed.reffed_by),
340 dep_formula_triggers: Arc::clone(&parsed.dep_formula_triggers),
341 context: context.clone(),
342 data: data.clone(),
343 evaluated_schema: (*evaluated_schema).clone(),
344 eval_data: EvalData::with_schema_data_context(&evaluated_schema, &data, &context),
345 eval_cache: crate::jsoneval::eval_cache::EvalCache::new(),
346 eval_lock: Mutex::new(()),
347 cached_msgpack_schema: None,
348 conditional_hidden_fields: Arc::clone(&parsed.conditional_hidden_fields),
349 conditional_readonly_fields: Arc::clone(&parsed.conditional_readonly_fields),
350 static_arrays: Arc::clone(&parsed.static_arrays),
351 regex_cache: RwLock::new(HashMap::new()),
352 };
353 Ok(instance)
354 }
355
356 pub fn reload_schema(
357 &mut self,
358 schema: &str,
359 context: Option<&str>,
360 data: Option<&str>,
361 ) -> Result<(), String> {
362 let mut schema_val: Value =
364 serde_json::from_str(schema).map_err(|e| format!("failed to parse schema: {e}"))?;
365 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
366 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
367 self.context = context.clone();
368 self.data = data.clone();
369
370 let static_arrays = if let Some(params) = schema_val
371 .get_mut("$params")
372 .and_then(|v| v.as_object_mut())
373 {
374 crate::jsoneval::static_arrays::extract_from_params(params)
375 } else {
376 IndexMap::new()
377 };
378 let static_arrays = Arc::new(static_arrays);
379 self.static_arrays = Arc::clone(&static_arrays);
380 self.schema = Arc::new(schema_val);
381 self.evaluated_schema = (*self.schema).clone();
382
383 let mut engine = RLogic::new();
384 engine.set_static_arrays(static_arrays);
385 self.engine = Arc::new(engine);
386
387 self.evaluations = Arc::new(IndexMap::new());
388 self.tables = Arc::new(IndexMap::new());
389 self.table_metadata = Arc::new(IndexMap::new());
390 self.dependencies = Arc::new(IndexMap::new());
391 self.sorted_evaluations = Arc::new(Vec::new());
392 self.dependents_evaluations = Arc::new(IndexMap::new());
393 self.rules_evaluations = Arc::new(Vec::new());
394 self.fields_with_rules = Arc::new(Vec::new());
395 self.others_evaluations = Arc::new(Vec::new());
396 self.value_evaluations = Arc::new(Vec::new());
397 self.layout_paths = Arc::new(Vec::new());
398 self.options_templates = Arc::new(Vec::new());
399 self.reffed_by = Arc::new(IndexMap::new());
400 self.dep_formula_triggers = Arc::new(IndexMap::new());
401 self.conditional_hidden_fields = Arc::new(Vec::new());
402 self.conditional_readonly_fields = Arc::new(Vec::new());
403 self.subforms.clear();
404 parse_schema::legacy::parse_schema(self)?;
405
406 self.eval_data =
408 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
409 self.eval_cache.clear();
410 if let Ok(mut cache) = self.regex_cache.write() {
411 cache.clear();
412 }
413
414 self.cached_msgpack_schema = None;
416
417 Ok(())
418 }
419
420 pub fn set_timezone_offset(&mut self, offset_minutes: Option<i32>) {
442 let mut config = RLogicConfig::default();
444 if let Some(offset) = offset_minutes {
445 config = config.with_timezone_offset(offset);
446 }
447
448 let mut engine = RLogic::with_config(config);
451 engine.set_static_arrays(Arc::clone(&self.static_arrays));
452 self.engine = Arc::new(engine);
453
454 let _ = parse_schema::legacy::parse_schema(self);
455 }
456
457 pub fn reload_schema_msgpack(
469 &mut self,
470 schema_msgpack: &[u8],
471 context: Option<&str>,
472 data: Option<&str>,
473 ) -> Result<(), String> {
474 let mut schema_val: Value = rmp_serde::from_slice(schema_msgpack)
476 .map_err(|e| format!("failed to deserialize MessagePack schema: {e}"))?;
477
478 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
479 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
480
481 self.context = context.clone();
482 self.data = data.clone();
483
484 let static_arrays = if let Some(params) = schema_val
485 .get_mut("$params")
486 .and_then(|v| v.as_object_mut())
487 {
488 crate::jsoneval::static_arrays::extract_from_params(params)
489 } else {
490 IndexMap::new()
491 };
492 let static_arrays = Arc::new(static_arrays);
493 self.static_arrays = Arc::clone(&static_arrays);
494 self.schema = Arc::new(schema_val);
495 self.evaluated_schema = (*self.schema).clone();
496
497 let mut engine = RLogic::new();
498 engine.set_static_arrays(static_arrays);
499 self.engine = Arc::new(engine);
500 self.evaluations = Arc::new(IndexMap::new());
501 self.tables = Arc::new(IndexMap::new());
502 self.table_metadata = Arc::new(IndexMap::new());
503 self.dependencies = Arc::new(IndexMap::new());
504 self.sorted_evaluations = Arc::new(Vec::new());
505 self.dependents_evaluations = Arc::new(IndexMap::new());
506 self.rules_evaluations = Arc::new(Vec::new());
507 self.fields_with_rules = Arc::new(Vec::new());
508 self.others_evaluations = Arc::new(Vec::new());
509 self.value_evaluations = Arc::new(Vec::new());
510 self.layout_paths = Arc::new(Vec::new());
511 self.options_templates = Arc::new(Vec::new());
512 self.reffed_by = Arc::new(IndexMap::new());
513 self.dep_formula_triggers = Arc::new(IndexMap::new());
514 self.conditional_hidden_fields = Arc::new(Vec::new());
515 self.conditional_readonly_fields = Arc::new(Vec::new());
516 self.subforms.clear();
517 parse_schema::legacy::parse_schema(self)?;
518
519 self.eval_data =
521 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
522 self.eval_cache.clear();
523 if let Ok(mut cache) = self.regex_cache.write() {
524 cache.clear();
525 }
526
527 self.cached_msgpack_schema = Some(schema_msgpack.to_vec());
529
530 Ok(())
531 }
532
533 pub fn reload_schema_parsed(
547 &mut self,
548 parsed: Arc<ParsedSchema>,
549 context: Option<&str>,
550 data: Option<&str>,
551 ) -> Result<(), String> {
552 let context: Value = json_parser::parse_json_str(context.unwrap_or("{}"))?;
553 let data: Value = json_parser::parse_json_str(data.unwrap_or("{}"))?;
554
555 self.schema = Arc::clone(&parsed.schema);
557 self.evaluations = parsed.evaluations.clone();
558 self.tables = parsed.tables.clone();
559 self.table_metadata = parsed.table_metadata.clone();
560 self.dependencies = parsed.dependencies.clone();
561 self.sorted_evaluations = parsed.sorted_evaluations.clone();
562 self.dependents_evaluations = parsed.dependents_evaluations.clone();
563 self.rules_evaluations = parsed.rules_evaluations.clone();
564 self.fields_with_rules = parsed.fields_with_rules.clone();
565 self.others_evaluations = parsed.others_evaluations.clone();
566 self.value_evaluations = parsed.value_evaluations.clone();
567 self.layout_paths = parsed.layout_paths.clone();
568 self.options_templates = parsed.options_templates.clone();
569 self.static_arrays = parsed.static_arrays.clone();
570 self.dep_formula_triggers = parsed.dep_formula_triggers.clone();
571
572 self.engine = parsed.engine.clone();
574
575 let mut subforms = IndexMap::new();
577 for (path, subform_parsed) in &parsed.subforms {
578 let subform_eval =
579 JSONEval::with_parsed_schema(subform_parsed.clone(), Some("{}"), None)?;
580 subforms.insert(path.clone(), Box::new(subform_eval));
581 }
582 self.subforms = subforms;
583
584 self.context = context.clone();
585 self.data = data.clone();
586 self.evaluated_schema = (*self.schema).clone();
587
588 self.eval_data =
590 EvalData::with_schema_data_context(&self.evaluated_schema, &data, &context);
591 self.eval_cache.clear();
592 self.engine.clear_indices();
593 if let Ok(mut cache) = self.regex_cache.write() {
594 cache.clear();
595 }
596
597 self.cached_msgpack_schema = None;
599
600 Ok(())
601 }
602
603 pub fn reload_schema_from_cache(
617 &mut self,
618 cache_key: &str,
619 context: Option<&str>,
620 data: Option<&str>,
621 ) -> Result<(), String> {
622 let parsed = PARSED_SCHEMA_CACHE
624 .get(cache_key)
625 .ok_or_else(|| format!("Schema '{}' not found in cache", cache_key))?;
626
627 self.reload_schema_parsed(parsed, context, data)
629 }
630}