use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use dotenvy::dotenv;
use eyre::Result;
use serde_json::{from_value, Value};
use tera::{Context, Error, Function, Tera};
use crate::contracts::Facade;
use crate::facades::Container;
#[derive(Clone, Debug)]
pub struct Template(Tera);
impl Facade for Template {
fn new(container: &Container) -> Self {
let mut tera = Tera::default();
tera.register_function("env", env());
Self(tera)
}
}
fn env() -> impl Function {
Box::new(
move |args: &HashMap<String, Value>| -> tera::Result<Value> {
let name = match args.get("name") {
Some(val) => match from_value::<String>(val.clone()) {
Ok(v) => v,
Err(_) => {
return Err(Error::msg(format!(
"Function `env` received name={} but `name` can only be a string",
val
)));
}
},
None => {
return Err(Error::msg(
"Function `env` didn't receive a `name` argument",
))
}
};
dotenv().ok();
match std::env::var(&name).ok() {
Some(res) => Ok(Value::String(res)),
None => match args.get("default") {
Some(default) => Ok(default.clone()),
None => Err(Error::msg(format!(
"Environment variable `{}` not found",
&name
))),
},
}
},
)
}
impl Deref for Template {
type Target = Tera;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Template {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Template {
pub fn render(&mut self, input: &str, context: &Value) -> Result<String> {
let text = self.render_str(input, &Context::from_serialize(context)?)?;
Ok(text)
}
}