Skip to content

Commit f7aa516

Browse files
committed
fix: serialize AlbTargetGroupRequest::query_string_parameters with the last value of each key
and prevent unnecessary mem alloc. awslabs#954
1 parent e29dc51 commit f7aa516

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

lambda-events/src/custom_serde/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ pub(crate) mod float_unix_epoch;
3333
#[cfg(any(feature = "alb", feature = "apigw"))]
3434
pub(crate) mod http_method;
3535

36+
#[cfg(feature = "alb")]
37+
mod query_string_parameters;
38+
#[cfg(feature = "alb")]
39+
pub(crate) use self::query_string_parameters::*;
40+
3641
pub(crate) fn deserialize_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
3742
where
3843
D: Deserializer<'de>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use query_map::QueryMap;
2+
use serde::{ser::SerializeMap, Serializer};
3+
use std::collections::HashMap;
4+
5+
/// Serializes `QueryMap`, converting value from `Vec<String>` to `String` using the last value.
6+
pub fn serialize_query_string_parameters<S>(value: &QueryMap, serializer: S) -> Result<S::Ok, S::Error>
7+
where
8+
S: Serializer,
9+
{
10+
let mut query_string_parameters = HashMap::new();
11+
12+
if let Some((mut last_key, mut last_value)) = value.iter().next() {
13+
// insert the last value for each key
14+
value.iter().for_each(|(k, v)| {
15+
if k != last_key {
16+
query_string_parameters.insert(last_key, last_value);
17+
last_key = k;
18+
}
19+
last_value = v;
20+
});
21+
// insert the last pair
22+
query_string_parameters.insert(last_key, last_value);
23+
}
24+
25+
let mut map = serializer.serialize_map(Some(query_string_parameters.len()))?;
26+
for (k, v) in &query_string_parameters {
27+
map.serialize_entry(k, v)?;
28+
}
29+
map.end()
30+
}
31+
32+
#[cfg(test)]
33+
mod tests {
34+
use super::*;
35+
use serde::Serialize;
36+
use serde_json::Value;
37+
38+
#[test]
39+
fn test_serialize_query_string_parameters() {
40+
#[derive(Serialize)]
41+
struct Test {
42+
#[serde(serialize_with = "serialize_query_string_parameters")]
43+
pub v: QueryMap,
44+
}
45+
46+
fn s(value: &str) -> String {
47+
value.to_string()
48+
}
49+
50+
let query = QueryMap::from(HashMap::from([
51+
(s("key1"), vec![s("value1"), s("value2"), s("value3")]),
52+
(s("key2"), vec![s("value4")]),
53+
(s("key3"), vec![s("value5"), s("value6")]),
54+
]));
55+
56+
let serialized = serde_json::to_string(&Test { v: query }).unwrap();
57+
let parsed: Value = serde_json::from_str(&serialized).unwrap();
58+
59+
assert_eq!(parsed["v"]["key1"], Value::String("value3".to_string()));
60+
assert_eq!(parsed["v"]["key2"], Value::String("value4".to_string()));
61+
assert_eq!(parsed["v"]["key3"], Value::String("value6".to_string()));
62+
}
63+
}

lambda-events/src/event/alb/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
custom_serde::{
3-
deserialize_headers, deserialize_nullish_boolean, http_method, serialize_headers, serialize_multi_value_headers,
3+
deserialize_headers, deserialize_nullish_boolean, http_method, serialize_headers,
4+
serialize_multi_value_headers, serialize_query_string_parameters,
45
},
56
encodings::Body,
67
};
@@ -17,7 +18,7 @@ pub struct AlbTargetGroupRequest {
1718
#[serde(default)]
1819
pub path: Option<String>,
1920
#[serde(default)]
20-
#[serde(serialize_with = "query_map::serde::aws_api_gateway_v1::serialize_query_string_parameters")]
21+
#[serde(serialize_with = "serialize_query_string_parameters")]
2122
pub query_string_parameters: QueryMap,
2223
#[serde(default)]
2324
pub multi_value_query_string_parameters: QueryMap,

0 commit comments

Comments
 (0)