Skip to main content

qa_spec/
computed.rs

1use crate::spec::form::FormSpec;
2use serde_json::{Map, Value};
3
4/// Builds a context used by expressions so answers can be addressed via question ids and the special `answers` key.
5pub fn build_expression_context(answers: &Value) -> Value {
6    let mut map = Map::new();
7    if let Some(object) = answers.as_object() {
8        for (key, value) in object {
9            map.insert(key.clone(), value.clone());
10        }
11    }
12    map.insert("answers".into(), answers.clone());
13    Value::Object(map)
14}
15
16/// Applies computed expressions defined in the spec and returns a new answer map that includes the derived values.
17pub fn apply_computed_answers(spec: &FormSpec, answers: &Value) -> Value {
18    let mut map = answers.as_object().cloned().unwrap_or_default();
19
20    for question in &spec.questions {
21        if let Some(expr) = &question.computed {
22            if map.contains_key(&question.id) && question.computed_overridable {
23                continue;
24            }
25            let context = build_expression_context(&Value::Object(map.clone()));
26            if let Some(value) = expr.evaluate_value(&context) {
27                map.insert(question.id.clone(), value);
28            } else {
29                map.remove(&question.id);
30            }
31        }
32    }
33
34    Value::Object(map)
35}