fhirpathrs 0.1.1

Fhirpath implementation in Rust
Documentation
use serde_json::Value;

use crate::parser::{
    expression::{Expression, Term, TermExpression},
    identifier::{Identifier, LiteralIdentifier},
    invocation::{FunctionInvocation, IdentifierAndParamList, Invocation, InvocationTerm},
};

use super::{filtering::repeat, nodes::resource_node::ResourceNode, EvaluateResult};

pub fn children<'a, 'b>(
    input: &'a ResourceNode<'a, 'b>,
    _expressions: &Vec<Box<Expression>>,
) -> EvaluateResult<ResourceNode<'a, 'b>> {
    let children = input
        .get_array()?
        .iter()
        .try_fold(vec![], |mut acc, item| {
            match item {
                Value::Object(obj) => {
                    let mut values: Vec<Value> = obj.values().map(|item| item.to_owned()).collect();

                    acc.append(&mut values);
                }
                _ => {}
            }

            Ok(acc)
        })?;

    Ok(ResourceNode::from_node(input, Value::Array(children)))
}

pub fn descendants<'a, 'b>(
    input: &'a ResourceNode<'a, 'b>,
    _expressions: &Vec<Box<Expression>>,
) -> EvaluateResult<ResourceNode<'a, 'b>> {
    let children_expression = Expression::TermExpression(Box::new(TermExpression {
        children: vec![Box::new(Term::InvocationTerm(Box::new(InvocationTerm {
            children: vec![Box::new(Invocation::FunctionInvocation(Box::new(
                FunctionInvocation {
                    children: vec![Box::new(IdentifierAndParamList::Identifier(Box::new(
                        Identifier::LiteralIdentifier(Box::new(LiteralIdentifier {
                            text: "children".to_string(),
                        })),
                    )))],
                },
            )))],
        })))],
    }));

    repeat(input, &vec![Box::new(children_expression)])
}

#[cfg(test)]
mod test {
    use serde_json::json;

    use crate::evaluate::test::test::{run_tests, Expected, TestCase};

    #[test]
    fn evaluate_children_path() {
        let patient = json!({
            "resourceType": "Patient",
            "a": 2,
            "b": 6
        });

        let test_cases: Vec<TestCase> = vec![
            TestCase {
                path: "Patient.children()".to_string(),
                input: patient.clone(),
                expected: Expected::Value(json!([2, 6, "Patient"])),
                options: None,
            },
            TestCase {
                path: "Patient.children()".to_string(),
                input: json!({
                  "resourceType": "Patient",
                  "a": [2, 3],
                  "b": 6
                }),
                expected: Expected::Value(json!([[2, 3], 6, "Patient"])),
                options: None,
            },
        ];

        run_tests(test_cases);
    }

    #[test]
    fn evaluate_descendants_path() {
        let patient = json!({
            "resourceType": "Patient",
            "a": 2,
            "b": 6
        });

        let test_cases: Vec<TestCase> = vec![
            TestCase {
                path: "Patient.descendants()".to_string(),
                input: patient.clone(),
                expected: Expected::Value(json!([2, 6, "Patient"])),
                options: None,
            },
            TestCase {
                path: "Patient.descendants()".to_string(),
                input: json!({
                  "resourceType": "Patient",
                  "a": [2, 3],
                  "b": 6
                }),
                expected: Expected::Value(json!([[2, 3], 6, "Patient"])),
                options: None,
            },
            TestCase {
                path: "Patient.descendants()".to_string(),
                input: json!({
                  "resourceType": "Patient",
                  "c": { "e": { "f": { "g": 2 } } }
                }),
                expected: Expected::Value(json!([{ "e": { "f": { "g": 2 } } }, "Patient", { "f": { "g": 2 } }, { "g": 2 }, 2])),
                options: None,
            },
            TestCase {
                path: "Patient.descendants()".to_string(),
                input: json!({
                  "resourceType": "Patient",
                  "a": [2, 3],
                  "b": 6,
                  "c": { "d": 1, "e": { "f": 2 } }
                }),
                expected: Expected::Value(json!([[2, 3], 6, { "d": 1, "e": { "f": 2 } }, "Patient", 1, { "f": 2 }, 2])),
                options: None,
            },
        ];

        run_tests(test_cases);
    }
}