1 | use serde_json::value::Value as Json; |
2 | |
3 | use crate::context::Context; |
4 | use crate::error::RenderError; |
5 | use crate::helpers::HelperDef; |
6 | use crate::json::value::ScopedJson; |
7 | use crate::registry::Registry; |
8 | use crate::render::{Helper, RenderContext}; |
9 | |
10 | #[derive (Clone, Copy)] |
11 | pub struct LookupHelper; |
12 | |
13 | impl 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 | |
49 | pub static LOOKUP_HELPER: LookupHelper = LookupHelper; |
50 | |
51 | #[cfg (test)] |
52 | mod 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 | |