liquid_json/
liquid_json.rs

1use crate::{render_value, to_liquid_obj, Error};
2
3/// A JSON structured Liquid template.
4#[must_use]
5#[derive(Clone)]
6pub struct LiquidJson {
7    pub(crate) raw_template: serde_json::Value,
8}
9
10impl std::fmt::Debug for LiquidJson {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        f.debug_struct("LiquidTemplate")
13            .field("template", &self.raw_template)
14            .finish()
15    }
16}
17
18impl PartialEq for LiquidJson {
19    fn eq(&self, other: &Self) -> bool {
20        self.raw_template == other.raw_template
21    }
22}
23
24impl LiquidJson {
25    /// Create a new Liquid template from a JSON value.
26    pub fn new(raw_template: serde_json::Value) -> Self {
27        LiquidJson { raw_template }
28    }
29
30    /// Render the Liquid JSON template with the given data.
31    pub fn render(&self, data: &serde_json::Value) -> Result<serde_json::Value, Error> {
32        let data = to_liquid_obj(data)?;
33        render_value(&self.raw_template, &data)
34    }
35
36    /// Get the inner [serde_json::Value] value.
37    pub fn as_json(&self) -> &serde_json::Value {
38        &self.raw_template
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use rstest::rstest;
45    use serde_json::{json, Value};
46
47    use super::*;
48    use anyhow::Result;
49
50    #[rstest]
51    #[case(json!({"this":"{{ myval }}"}), json!({"myval": 5}), json!({"this":5}))]
52    #[case(json!({"this":"{{ myval }}"}), json!({"myval": f64::MAX}), json!({"this":f64::MAX  }))]
53    #[case(json!({"this":"{{ myval }}"}), json!({"myval": i64::MAX}), json!({"this":i64::MAX}))]
54    #[case(json!({"this":"{{ myval }}"}), json!({"myval": u32::MAX}), json!({"this":u32::MAX}))]
55    // #[case(json!({"this":"{{ myval }}"}), json!({"myval": u64::MAX}), json!({"this":u64::MAX}))] // Fails for now...
56    #[case(json!({"this":"{{ myval }}"}), json!({"myval": "5"}), json!({"this":"5"}))]
57    #[case(json!({"this":"{{ myval }}"}), json!({"myval": 5.1}), json!({"this":5.1}))]
58    #[case(json!({"this":"{{ myval }}"}), json!({"myval": [5.1,4.2]}), json!({"this":[5.1,4.2]}))]
59    #[case(json!({"this":"{{ myval | each: \"my num: {{el}}\" | output}}"}), json!({"myval": [5.1,4.2]}), json!({"this":["my num: 5.1","my num: 4.2"]}))]
60    #[case(json!({"this":"{{ myval | default: 'hey'}}"}), json!({}), json!({"this":"hey"}))]
61    fn basic(#[case] template: Value, #[case] data: Value, #[case] expected: Value) -> Result<()> {
62        let tmpl = LiquidJson::new(template);
63        let actual = tmpl.render(&data)?;
64        assert_eq!(actual, expected);
65        Ok(())
66    }
67}