Template function return Result

This commit is contained in:
Gregory Schier
2024-07-31 07:32:37 -07:00
parent 90bf96c7c1
commit cc9bd2bc70
7 changed files with 115 additions and 21 deletions

View File

@@ -83,6 +83,10 @@ jobs:
- name: Install yaak CLI
run: go install github.com/yaakapp/yaakcli@latest
- name: Rust test
working-directory: src-tauri
run: cargo test --all
- name: Run lint
run: npm run lint

3
src-tauri/Cargo.lock generated
View File

@@ -5999,6 +5999,9 @@ dependencies = [
[[package]]
name = "templates"
version = "0.1.0"
dependencies = [
"log",
]
[[package]]
name = "tendril"

View File

@@ -70,6 +70,7 @@ mod render;
mod tauri_plugin_mac_window;
mod updates;
mod window_menu;
mod template_fns;
const DEFAULT_WINDOW_WIDTH: f64 = 1100.0;
const DEFAULT_WINDOW_HEIGHT: f64 = 600.0;

View File

@@ -1,12 +1,13 @@
use std::collections::HashMap;
use std::time::SystemTime;
use chrono::{DateTime, Utc};
use sqlx::types::{Json, JsonValue};
use templates::parse_and_render;
use crate::models::{
Environment, EnvironmentVariable, HttpRequest, HttpRequestHeader, HttpUrlParameter, Workspace,
};
use templates::parse_and_render;
use crate::template_fns::timestamp;
pub fn render_request(r: &HttpRequest, w: &Workspace, e: Option<&Environment>) -> HttpRequest {
let r = r.clone();
@@ -107,16 +108,10 @@ pub fn render(template: &str, vars: &HashMap<String, String>) -> String {
parse_and_render(template, vars, Some(template_callback))
}
fn template_callback(name: &str, _args: HashMap<String, String>) -> String {
fn template_callback(name: &str, args: HashMap<String, String>) -> Result<String, String> {
match name {
"timestamp" => {
let now = SystemTime::now();
let now: DateTime<Utc> = now.into();
now.to_rfc3339()
},
_ => {
"".to_string()
}
"timestamp" => timestamp(args),
_ => Err(format!("Unknown template function {name}")),
}
}

View File

@@ -0,0 +1,64 @@
use chrono::{DateTime, Utc};
use std::collections::HashMap;
pub fn timestamp(args: HashMap<String, String>) -> Result<String, String> {
let from = args.get("from").map(|v| v.as_str()).unwrap_or("now");
let format = args.get("format").map(|v| v.as_str()).unwrap_or("rfc3339");
let dt = match from {
"now" => {
let now = Utc::now();
now
}
_ => {
let json_from = serde_json::to_string(from).unwrap_or_default();
let now: DateTime<Utc> = serde_json::from_str(json_from.as_str()).unwrap();
now
}
};
let result = match format {
"rfc3339" => dt.to_rfc3339(),
"unix" => dt.timestamp().to_string(),
"unix_millis" => dt.timestamp_millis().to_string(),
_ => "".to_string(),
};
Ok(result)
}
// Test it
#[cfg(test)]
mod tests {
use crate::template_fns::timestamp;
use std::collections::HashMap;
#[test]
fn timestamp_empty() {
let args = HashMap::new();
assert_ne!(timestamp(args), Ok("".to_string()));
}
#[test]
fn timestamp_from() {
let mut args = HashMap::new();
args.insert("from".to_string(), "2024-07-31T14:16:41.983Z".to_string());
assert_eq!(timestamp(args), Ok("2024-07-31T14:16:41.983+00:00".to_string()));
}
#[test]
fn timestamp_format_unix() {
let mut args = HashMap::new();
args.insert("from".to_string(), "2024-07-31T14:16:41.983Z".to_string());
args.insert("format".to_string(), "unix".to_string());
assert_eq!(timestamp(args), Ok("1722435401".to_string()));
}
#[test]
fn timestamp_format_unix_millis() {
let mut args = HashMap::new();
args.insert("from".to_string(), "2024-07-31T14:16:41.983Z".to_string());
args.insert("format".to_string(), "unix_millis".to_string());
assert_eq!(timestamp(args), Ok("1722435401983".to_string()));
}
}

View File

@@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
log = "0.4.22"

View File

@@ -1,8 +1,8 @@
use crate::{FnArg, Parser, Token, Val};
use log::warn;
use std::collections::HashMap;
use crate::{FnArg, Parser, Token, Val};
type TemplateCallback = fn(name: &str, args: HashMap<String, String>) -> String;
type TemplateCallback = fn(name: &str, args: HashMap<String, String>) -> Result<String, String>;
pub fn parse_and_render(
template: &str,
@@ -61,7 +61,13 @@ fn render_tag(val: Val, vars: &HashMap<String, String>, cb: Option<TemplateCallb
})
.collect::<HashMap<String, String>>();
match cb {
Some(cb) => cb(name.as_str(), resolved_args),
Some(cb) => match cb(name.as_str(), resolved_args.clone()) {
Ok(s) => s,
Err(e) => {
warn!("Failed to run template callback {}({:?}): {}", name, resolved_args, e);
"".to_string()
}
},
None => "".into(),
}
}
@@ -112,8 +118,13 @@ mod tests {
let template = r#"${[ say_hello(a="John", b="Kate") ]}"#;
let result = r#"say_hello: 2, Some("John") Some("Kate")"#;
fn cb(name: &str, args: HashMap<String, String>) -> String {
format!("{name}: {}, {:?} {:?}", args.len(), args.get("a"), args.get("b"))
fn cb(name: &str, args: HashMap<String, String>) -> Result<String, String> {
Ok(format!(
"{name}: {}, {:?} {:?}",
args.len(),
args.get("a"),
args.get("b")
))
}
assert_eq!(parse_and_render(template, &vars, Some(cb)), result);
}
@@ -123,12 +134,27 @@ mod tests {
let vars = HashMap::new();
let template = r#"${[ upper(foo=secret()) ]}"#;
let result = r#"ABC"#;
fn cb(name: &str, args: HashMap<String, String>) -> String {
match name {
fn cb(name: &str, args: HashMap<String, String>) -> Result<String, String> {
Ok(match name {
"secret" => "abc".to_string(),
"upper" => args["foo"].to_string().to_uppercase(),
_ => "".to_string(),
}
})
}
assert_eq!(
parse_and_render(template, &vars, Some(cb)),
result.to_string()
);
}
#[test]
fn render_fn_err() {
let vars = HashMap::new();
let template = r#"${[ error() ]}"#;
let result = r#""#;
fn cb(_name: &str, _args: HashMap<String, String>) -> Result<String, String> {
Err("Failed to do it!".to_string())
}
assert_eq!(