diff --git a/src/webserver/request_variables.rs b/src/webserver/request_variables.rs index 0aa9879a..651058b2 100644 --- a/src/webserver/request_variables.rs +++ b/src/webserver/request_variables.rs @@ -1,4 +1,7 @@ -use std::collections::{hash_map::Entry, HashMap}; +use std::{ + cell::{Ref, RefCell}, + collections::{hash_map::Entry, HashMap}, +}; use super::http::SingleOrVec; @@ -25,3 +28,41 @@ pub fn param_map>(values: PAIRS) -> map }) } + +/// This holds both the base variables set by URL parameters or form submission values in the initial +/// HTTP request, +/// and potential additional variables set by the programmer. +/// The same variable can be defined multiple times if there are multiple nested `run_sql` calls +struct RequestVariables { + root_variables: ParamMap, + set_variables: RefCell>, +} + +impl RequestVariables { + fn new(root_variables: ParamMap) -> Self { + RequestVariables { + root_variables, + set_variables: RefCell::new(Vec::new()), + } + } + + pub fn edit(&self, name: String, f: impl FnOnce(Entry<'_, String, SingleOrVec>) -> R) -> R { + let mut vars_list = self.set_variables.borrow_mut(); + if vars_list.is_empty() { + vars_list.push(ParamMap::new()); + } + let vars = vars_list.last_mut().unwrap(); + f(vars.entry(name)) + } + + pub fn read_value(&self, name: &str, f: impl FnOnce(Option<&SingleOrVec>) -> R) -> R { + let var_list = &self.set_variables.borrow(); + let val = var_list + .iter() + .rev() + .flat_map(|m| m.get(name)) + .next() + .or_else(|| self.root_variables.get(name)); + f(val) + } +}