From cc9bd2bc70dec004fd192b7aac20775e85edfff0 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Wed, 31 Jul 2024 07:32:37 -0700 Subject: [PATCH] Template function return Result --- .github/workflows/release.yml | 4 ++ src-tauri/Cargo.lock | 3 ++ src-tauri/src/lib.rs | 1 + src-tauri/src/render.rs | 19 ++++----- src-tauri/src/template_fns.rs | 64 +++++++++++++++++++++++++++++ src-tauri/templates/Cargo.toml | 1 + src-tauri/templates/src/renderer.rs | 44 ++++++++++++++++---- 7 files changed, 115 insertions(+), 21 deletions(-) create mode 100644 src-tauri/src/template_fns.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a7b29a29..63165aac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ad35051a..560bd7f4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -5999,6 +5999,9 @@ dependencies = [ [[package]] name = "templates" version = "0.1.0" +dependencies = [ + "log", +] [[package]] name = "tendril" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 41c6ceec..316bbea1 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -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; diff --git a/src-tauri/src/render.rs b/src-tauri/src/render.rs index 79470e63..fb177564 100644 --- a/src-tauri/src/render.rs +++ b/src-tauri/src/render.rs @@ -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 { parse_and_render(template, vars, Some(template_callback)) } -fn template_callback(name: &str, _args: HashMap) -> String { +fn template_callback(name: &str, args: HashMap) -> Result { match name { - "timestamp" => { - let now = SystemTime::now(); - let now: DateTime = now.into(); - now.to_rfc3339() - }, - _ => { - "".to_string() - } + "timestamp" => timestamp(args), + _ => Err(format!("Unknown template function {name}")), } } diff --git a/src-tauri/src/template_fns.rs b/src-tauri/src/template_fns.rs new file mode 100644 index 00000000..76cdb43d --- /dev/null +++ b/src-tauri/src/template_fns.rs @@ -0,0 +1,64 @@ +use chrono::{DateTime, Utc}; +use std::collections::HashMap; + +pub fn timestamp(args: HashMap) -> Result { + 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 = 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())); + } +} diff --git a/src-tauri/templates/Cargo.toml b/src-tauri/templates/Cargo.toml index afe2a9bf..8f4e26d2 100644 --- a/src-tauri/templates/Cargo.toml +++ b/src-tauri/templates/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +log = "0.4.22" diff --git a/src-tauri/templates/src/renderer.rs b/src-tauri/templates/src/renderer.rs index d3ac8989..a0b767c7 100644 --- a/src-tauri/templates/src/renderer.rs +++ b/src-tauri/templates/src/renderer.rs @@ -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; +type TemplateCallback = fn(name: &str, args: HashMap) -> Result; pub fn parse_and_render( template: &str, @@ -61,7 +61,13 @@ fn render_tag(val: Val, vars: &HashMap, cb: Option>(); 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 { - format!("{name}: {}, {:?} {:?}", args.len(), args.get("a"), args.get("b")) + fn cb(name: &str, args: HashMap) -> Result { + 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 { - match name { + fn cb(name: &str, args: HashMap) -> Result { + 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) -> Result { + Err("Failed to do it!".to_string()) } assert_eq!(