handlebars/helpers/
helper_lookup.rs
1use serde_json::value::Value as Json;
2
3use crate::context::Context;
4use crate::error::RenderError;
5use crate::helpers::HelperDef;
6use crate::json::value::ScopedJson;
7use crate::registry::Registry;
8use crate::render::{Helper, RenderContext};
9use crate::RenderErrorReason;
10
11#[derive(Clone, Copy)]
12pub struct LookupHelper;
13
14impl HelperDef for LookupHelper {
15 fn call_inner<'reg: 'rc, 'rc>(
16 &self,
17 h: &Helper<'rc>,
18 r: &'reg Registry<'reg>,
19 _: &'rc Context,
20 _: &mut RenderContext<'reg, 'rc>,
21 ) -> Result<ScopedJson<'rc>, RenderError> {
22 let collection_value = h
23 .param(0)
24 .ok_or(RenderErrorReason::ParamNotFoundForIndex("lookup", 0))?;
25 let index = h
26 .param(1)
27 .ok_or(RenderErrorReason::ParamNotFoundForIndex("lookup", 1))?;
28
29 let value = match *collection_value.value() {
30 Json::Array(ref v) => index.value().as_u64().and_then(|u| v.get(u as usize)),
31 Json::Object(ref m) => index.value().as_str().and_then(|k| m.get(k)),
32 _ => None,
33 };
34 if r.strict_mode() && value.is_none() {
35 Err(RenderError::strict_error(None))
36 } else {
37 Ok(value.unwrap_or(&Json::Null).clone().into())
38 }
39 }
40}
41
42pub static LOOKUP_HELPER: LookupHelper = LookupHelper;
43
44#[cfg(test)]
45mod test {
46 use crate::registry::Registry;
47
48 #[test]
49 fn test_lookup() {
50 let mut handlebars = Registry::new();
51 assert!(handlebars
52 .register_template_string("t0", "{{#each v1}}{{lookup ../v2 @index}}{{/each}}")
53 .is_ok());
54 assert!(handlebars
55 .register_template_string("t1", "{{#each v1}}{{lookup ../v2 1}}{{/each}}")
56 .is_ok());
57 assert!(handlebars
58 .register_template_string("t2", "{{lookup kk \"a\"}}")
59 .is_ok());
60
61 let m = json!({"v1": [1,2,3], "v2": [9,8,7]});
62
63 let m2 = json!({
64 "kk": {"a": "world"}
65 });
66
67 let r0 = handlebars.render("t0", &m);
68 assert_eq!(r0.ok().unwrap(), "987".to_string());
69
70 let r1 = handlebars.render("t1", &m);
71 assert_eq!(r1.ok().unwrap(), "888".to_string());
72
73 let r2 = handlebars.render("t2", &m2);
74 assert_eq!(r2.ok().unwrap(), "world".to_string());
75
76 assert!(handlebars.render_template("{{lookup}}", &m).is_err());
77 assert!(handlebars.render_template("{{lookup v1}}", &m).is_err());
78 assert_eq!(
79 handlebars.render_template("{{lookup null 1}}", &m).unwrap(),
80 ""
81 );
82 assert_eq!(
83 handlebars.render_template("{{lookup v1 3}}", &m).unwrap(),
84 ""
85 );
86 }
87
88 #[test]
89 fn test_strict_lookup() {
90 let mut hbs = Registry::new();
91
92 assert_eq!(
93 hbs.render_template("{{lookup kk 1}}", &json!({"kk": []}))
94 .unwrap(),
95 ""
96 );
97 assert!(hbs
98 .render_template("{{lookup kk 0}}", &json!({ "kk": [null] }))
99 .is_ok());
100
101 hbs.set_strict_mode(true);
102
103 assert!(hbs
104 .render_template("{{lookup kk 1}}", &json!({"kk": []}))
105 .is_err());
106 assert!(hbs
107 .render_template("{{lookup kk 0}}", &json!({ "kk": [null] }))
108 .is_ok());
109 }
110}