Skip to content

Commit a3c33e4

Browse files
committed
Refactor: Update URLParameters handling in set_variable function
- Replaced serde_json::Map with a custom URLParameters struct for better management of URL parameters. - Introduced methods for handling single and vector values in URLParameters. - Updated tests to reflect changes in the set_variable function's behavior.
1 parent c1f4c55 commit a3c33e4

File tree

3 files changed

+74
-42
lines changed

3 files changed

+74
-42
lines changed

src/webserver/database/sqlpage_functions/functions.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -618,26 +618,21 @@ async fn set_variable<'a>(
618618
name: Cow<'a, str>,
619619
value: Option<Cow<'a, str>>,
620620
) -> anyhow::Result<String> {
621-
let mut params_map = serde_json::Map::with_capacity(context.url_params.len() + 1);
621+
let mut params = URLParameters::new();
622622

623623
for (k, v) in &context.url_params {
624-
params_map.insert(k.clone(), serde_json::to_value(v)?);
624+
if k == &name {
625+
continue;
626+
}
627+
params.push_single_or_vec(k, v.clone());
625628
}
626629

627630
if let Some(value) = value {
628-
params_map.insert(
629-
name.into_owned(),
630-
serde_json::Value::String(value.into_owned()),
631-
);
632-
} else {
633-
params_map.remove(&*name);
631+
params.push_single_or_vec(&name, SingleOrVec::Single(value.into_owned()));
634632
}
635633

636-
let json_val = serde_json::Value::Object(params_map);
637-
let encoded: URLParameters = serde_json::from_str(&json_val.to_string())?;
638-
639634
let mut url = context.path.clone();
640-
let encoded_str = encoded.get();
635+
let encoded_str = params.get();
641636
if !encoded_str.is_empty() {
642637
url.push('?');
643638
url.push_str(encoded_str);

src/webserver/database/sqlpage_functions/url_parameter_deserializer.rs

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::webserver::single_or_vec::SingleOrVec;
12
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
23
use serde::{Deserialize, Deserializer};
34
use serde_json::Value;
@@ -6,7 +7,17 @@ use std::fmt;
67

78
pub struct URLParameters(String);
89

10+
impl Default for URLParameters {
11+
fn default() -> Self {
12+
Self(String::new())
13+
}
14+
}
15+
916
impl URLParameters {
17+
pub fn new() -> Self {
18+
Self::default()
19+
}
20+
1021
fn encode_and_push(&mut self, v: &str) {
1122
let val: Cow<str> = percent_encode(v.as_bytes(), NON_ALPHANUMERIC).into();
1223
self.0.push_str(&val);
@@ -19,6 +30,49 @@ impl URLParameters {
1930
self.0.push('=');
2031
self.encode_and_push(value);
2132
}
33+
34+
fn push_array_entry(&mut self, key: &str, value: &str) {
35+
if !self.0.is_empty() {
36+
self.0.push('&');
37+
}
38+
self.encode_and_push(key);
39+
self.0.push_str("[]=");
40+
self.encode_and_push(value);
41+
}
42+
43+
fn push_array(&mut self, key: &str, values: Vec<Value>) {
44+
for val in values {
45+
let val_str = match val {
46+
Value::String(s) => s,
47+
other => other.to_string(),
48+
};
49+
self.push_array_entry(key, &val_str);
50+
}
51+
}
52+
53+
pub fn push_single_or_vec(&mut self, key: &str, val: SingleOrVec) {
54+
match val {
55+
SingleOrVec::Single(v) => self.push_kv(key, &v),
56+
SingleOrVec::Vec(v) => {
57+
for s in v {
58+
self.push_array_entry(key, &s);
59+
}
60+
}
61+
}
62+
}
63+
64+
fn add_from_json(&mut self, key: &str, raw_json_value: &str) {
65+
if let Ok(str_val) = serde_json::from_str::<Option<Cow<str>>>(raw_json_value) {
66+
if let Some(str_val) = str_val {
67+
self.push_kv(key, &str_val);
68+
}
69+
} else if let Ok(vec_val) = serde_json::from_str::<Vec<Value>>(raw_json_value) {
70+
self.push_array(key, vec_val);
71+
} else {
72+
self.push_kv(key, raw_json_value);
73+
}
74+
}
75+
2276
pub fn get(&self) -> &str {
2377
&self.0
2478
}
@@ -47,31 +101,7 @@ impl<'de> Deserialize<'de> for URLParameters {
47101
while let Some((key, value)) =
48102
map.next_entry::<Cow<str>, Cow<serde_json::value::RawValue>>()?
49103
{
50-
let value = value.get();
51-
if let Ok(str_val) = serde_json::from_str::<Option<Cow<str>>>(value) {
52-
if let Some(str_val) = str_val {
53-
out.push_kv(&key, &str_val);
54-
}
55-
} else if let Ok(vec_val) =
56-
serde_json::from_str::<Vec<serde_json::Value>>(value)
57-
{
58-
for val in vec_val {
59-
if !out.0.is_empty() {
60-
out.0.push('&');
61-
}
62-
out.encode_and_push(&key);
63-
out.0.push_str("[]");
64-
out.0.push('=');
65-
66-
let val = match val {
67-
Value::String(s) => s,
68-
other => other.to_string(),
69-
};
70-
out.encode_and_push(&val);
71-
}
72-
} else {
73-
out.push_kv(&key, value);
74-
}
104+
out.add_from_json(&key, value.get());
75105
}
76106

77107
Ok(out)
@@ -136,3 +166,14 @@ fn test_url_parameters_deserializer_issue_879() {
136166
"name=John%20Doe%20%26%20Son%27s&items[]=1&items[]=item%202%20%26%203&items[]=true&special%5Fchar=%25%26%3D%2B%20"
137167
);
138168
}
169+
170+
#[test]
171+
fn test_push_single_or_vec() {
172+
let mut params = URLParameters(String::new());
173+
params.push_single_or_vec("k", SingleOrVec::Single("v".to_string()));
174+
assert_eq!(params.get(), "k=v");
175+
176+
let mut params = URLParameters(String::new());
177+
params.push_single_or_vec("arr", SingleOrVec::Vec(vec!["a".to_string(), "b".to_string()]));
178+
assert_eq!(params.get(), "arr[]=a&arr[]=b");
179+
}

tests/components/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,8 @@ use crate::common::get_request_to;
55

66
#[actix_web::test]
77
async fn test_overwrite_variable() -> actix_web::Result<()> {
8-
let req = get_request_to("/tests/sql_test_files/it_works_set_variable.sql")
8+
let req = get_request_to("/tests/sql_test_files/it_works_set_variable_nomssql.sql")
99
.await?
10-
.set_form(std::collections::HashMap::<&str, &str>::from_iter([(
11-
"what_does_it_do",
12-
"does not overwrite variables",
13-
)]))
1410
.to_srv_request();
1511
let resp = main_handler(req).await?;
1612

0 commit comments

Comments
 (0)