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