From 33612ba569cfb1c53f3b07eccb30718f8215a37f Mon Sep 17 00:00:00 2001 From: Dominik George <dominik.george@teckids.org> Date: Thu, 13 May 2021 23:59:40 +0200 Subject: [PATCH] [NSS] Refactor more jq program loading code into function --- src/oauth.rs | 88 ++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/src/oauth.rs b/src/oauth.rs index 72f3f62..8e5aa79 100644 --- a/src/oauth.rs +++ b/src/oauth.rs @@ -151,73 +151,67 @@ fn get_data(conf: &Config, prefix: &str, endpoint: &str, param: String, token: & .text()?) } -fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str, rev: bool) -> Option<String> { +fn get_jq_prog(conf: &Config, prefix: &str, endpoint: &str, multi: bool, rev: bool) -> jq_rs::Result<jq_rs::JqProgram> { + // Generate config key to find jq program under let prog_key = match rev { false => full_key(vec![prefix, "maps", endpoint]), true => full_key(vec![prefix, "maps.rev", endpoint]), }; - match get_optional(&conf, &prog_key) { - Some(v) => Some (v), + + // Retrieve jq program code from config + let mut jq_code: String = match get_optional(&conf, &prog_key) { + // We got the value immediately + Some(v) => v, None => { if rev { // Do not fallback to more generic program for reverse mapping - return None; - } - // Try falling back to more generic program - match endpoint.find('.') { - Some(i) => { - debug!("JQ mapping program for {} not found; trying more generic definition", endpoint); - get_jq_prog(conf, prefix, &endpoint[..i], rev) - }, - None => None + ".".to_string() + } else { + // Try falling back to more generic program + match endpoint.find('.') { + Some(i) => { + debug!("JQ mapping program for {} not found; trying more generic definition", endpoint); + // Call recursively (and return verbatim, as we get a compiled program) + return get_jq_prog(conf, prefix, &endpoint[..i], multi, rev) + } + // Lookup failed ultimately; fallback to jq "identity" (no-op) + None => ".".to_string() + } } } + }; + + // If multi mode is passed, the program will be applied to an array of entries + // We thus wrap it in a call to jq's `map()` + if multi { + jq_code = "map(".to_string() + &jq_code + ")"; } + + debug!("Compiling JQ program for endpoint {}: {}", endpoint, jq_code); + jq_rs::compile(&jq_code) } pub fn get_data_jq<T: for<'de> Deserialize<'de>, V: Serialize>(conf: &Config, prefix: &str, endpoint: &str, param: V, token: &BasicTokenResponse, multi: bool) -> Result<T, Box<dyn error::Error>> { - let res: Option<String> = get_jq_prog(&conf, prefix, endpoint, false); - let jq_code = match res { - Some(s) => { - debug!("Found jq mapping program for endpoint {}: {}", endpoint, s); - match multi { - true => "map(".to_string() + &s + ")", - false => s - } - }, - None => { - debug!("No jq mapping program for endpoint {}; using default (no-op)", endpoint); - ".".to_string() - } - }; - let mut jq_prog = jq_rs::compile(&jq_code)?; - let res: Option<String> = get_jq_prog(&conf, prefix, endpoint, true); - let jq_code = match res { - Some(s) => { - debug!("Found jq reverse mapping program for endpoint {}: {}", endpoint, s); - s - }, - None => { - debug!("No jq reverse mapping program for endpoint {}; using default (no-op)", endpoint); - ".".to_string() - } - }; - let mut jq_prog_rev = jq_rs::compile(&jq_code)?; + // Get jq mapping programs for forward and reverse mappings + let mut jq_prog_fwd = get_jq_prog(&conf, prefix, endpoint, multi, false)?; + let mut jq_prog_rev = get_jq_prog(&conf, prefix, endpoint, false, true)?; // Convert and transform the passed param using the reverse JQ mapping program // 1. Serialize into JSON value (atomic) to be bale to pass into jq - let param_serialized = serde_json::to_string(¶m)?; + let param = serde_json::to_string(¶m)?; // 2. Transform using the JQ program loaded above - let param_trans = jq_prog_rev.run(¶m_serialized)?.trim().to_string(); + let param = jq_prog_rev.run(¶m)?.trim().to_string(); // 3. Deserialize into serde_json value so we get numbers as numbers, strings properly unquoted - let param_deserialized: serde_json::Value = serde_json::from_str(¶m_trans)?; - let param = match param_deserialized { + let param: serde_json::Value = serde_json::from_str(¶m)?; + let param = match param { serde_json::Value::String(v) => v, // We want strings verbatim without JSON quoting - _ => param_deserialized.to_string() // We want numbers converted to string + _ => param.to_string() // We want numbers converted to string }; - let data_raw = get_data(&conf, prefix, endpoint, param, token)?; - let data_trans = jq_prog.run(&data_raw)?; + // Retrieve data via HTTP and transform using jq forward mapping program + let data = get_data(&conf, prefix, endpoint, param, token)?; + let data = jq_prog_fwd.run(&data)?; - Ok(serde_json::from_str(&data_trans)?) + // Deserialize transformed JSON and return + Ok(serde_json::from_str(&data)?) } -- GitLab