1use std::collections::HashMap;
2
3#[cfg(feature = "serde")]
4use serde::de::IntoDeserializer;
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use crate::qdrant::{GeoPoint, Struct, Value};
9#[cfg(feature = "serde")]
10use crate::QdrantError;
11
12#[derive(Clone, PartialEq, Debug, Default)]
56#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57#[cfg_attr(feature = "serde", serde(transparent))]
58pub struct Payload(pub(crate) HashMap<String, Value>);
59
60impl Payload {
61 pub fn new() -> Self {
63 Self(HashMap::new())
64 }
65
66 pub fn with_capacity(capacity: usize) -> Self {
68 Self(HashMap::with_capacity(capacity))
69 }
70
71 pub fn insert(&mut self, key: impl ToString, val: impl Into<Value>) {
73 self.0.insert(key.to_string(), val.into());
74 }
75
76 #[cfg(feature = "serde")]
102 pub fn deserialize<T: serde::de::DeserializeOwned>(self) -> Result<T, QdrantError> {
103 Ok(T::deserialize(
104 Struct { fields: self.0 }.into_deserializer(),
105 )?)
106 }
107}
108
109impl From<HashMap<String, Value>> for Payload {
110 #[inline]
111 fn from(payload: HashMap<String, Value>) -> Self {
112 Self(payload)
113 }
114}
115
116impl From<HashMap<&str, Value>> for Payload {
117 #[inline]
118 fn from(payload: HashMap<&str, Value>) -> Self {
119 Self(
120 payload
121 .into_iter()
122 .map(|(k, v)| (k.to_string(), v))
123 .collect(),
124 )
125 }
126}
127
128impl From<Payload> for HashMap<String, Value> {
129 #[inline]
130 fn from(payload: Payload) -> Self {
131 payload.0
132 }
133}
134
135#[cfg(feature = "serde")]
136impl From<Payload> for serde_json::Value {
137 #[inline]
138 fn from(value: Payload) -> serde_json::Value {
139 serde_json::Value::Object(value.into())
140 }
141}
142
143#[cfg(feature = "serde")]
144impl From<Payload> for serde_json::Map<String, serde_json::Value> {
145 #[inline]
146 fn from(value: Payload) -> serde_json::Map<String, serde_json::Value> {
147 value
148 .0
149 .into_iter()
150 .map(|(k, v)| (k, v.into()))
151 .collect::<serde_json::Map<String, serde_json::Value>>()
152 }
153}
154
155#[cfg(feature = "serde")]
156impl TryFrom<serde_json::Value> for Payload {
157 type Error = crate::QdrantError;
158
159 #[inline]
170 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
171 if let serde_json::Value::Object(object) = value {
172 Ok(object.into())
173 } else {
174 Err(crate::QdrantError::JsonToPayload(value))
175 }
176 }
177}
178
179#[cfg(feature = "serde")]
180impl From<serde_json::Map<String, serde_json::Value>> for Payload {
181 #[inline]
186 fn from(object: serde_json::Map<String, serde_json::Value>) -> Self {
187 Payload::from(
188 object
189 .into_iter()
190 .map(|(k, v)| (k, v.into()))
191 .collect::<HashMap<String, Value>>(),
192 )
193 }
194}
195
196#[cfg(feature = "serde")]
197impl From<HashMap<String, serde_json::Value>> for Payload {
198 fn from(value: HashMap<String, serde_json::Value>) -> Self {
199 Payload::from(
200 value
201 .into_iter()
202 .map(|(k, v)| (k, v.into()))
203 .collect::<HashMap<String, Value>>(),
204 )
205 }
206}
207
208impl<K, const N: usize> From<[(K, Value); N]> for Payload
209where
210 K: Into<String>,
211{
212 fn from(values: [(K, Value); N]) -> Self {
213 let mut map = HashMap::with_capacity(N);
214 for (k, v) in values {
215 map.insert(k.into(), v);
216 }
217 Self(map)
218 }
219}
220
221impl From<GeoPoint> for Value {
222 fn from(point: GeoPoint) -> Self {
223 use crate::qdrant::value::Kind;
224
225 let map = HashMap::from([
226 ("lat".to_string(), point.lat.into()),
227 ("lon".to_string(), point.lon.into()),
228 ]);
229
230 Self {
231 kind: Some(Kind::StructValue(Struct { fields: map })),
232 }
233 }
234}
235
236#[cfg(feature = "serde")]
237#[cfg(test)]
238mod tests {
239 use serde_json::json;
240
241 use super::{Payload, *};
242
243 #[test]
244 fn json_payload_round_trip() {
245 let payload: Payload = vec![
246 ("some_string", "Bar".into()),
247 ("some_bool", true.into()),
248 ("some_int", 12.into()),
249 ("some_float", 2.3.into()),
250 ("some_seq", vec!["elem1", "elem2"].into()),
251 ("some_obj", vec![("key", "value")].into()),
252 ]
253 .into_iter()
254 .collect::<HashMap<_, Value>>()
255 .into();
256
257 let json_value = serde_json::to_string(&payload).unwrap();
259
260 let payload_back: Payload = serde_json::from_str(&json_value).unwrap();
262
263 assert_eq!(payload, payload_back);
265 }
266
267 #[test]
268 fn payload_from_string() {
269 let json = r#"{
270 "some_string": "Bar",
271 "some_bool": true,
272 "some_int": 12,
273 "some_float": 2.3,
274 "some_seq": ["elem1", "elem2"],
275 "some_obj": {"key": "value"}
276 }"#;
277
278 let parsed_payload: Payload = serde_json::from_str(json).unwrap();
280
281 let expected: Payload = vec![
282 ("some_string", "Bar".into()),
283 ("some_bool", true.into()),
284 ("some_int", 12.into()),
285 ("some_float", 2.3.into()),
286 ("some_seq", vec!["elem1", "elem2"].into()),
287 ("some_obj", vec![("key", "value")].into()),
288 ]
289 .into_iter()
290 .collect::<HashMap<_, Value>>()
291 .into();
292
293 assert_eq!(parsed_payload, expected);
295 }
296
297 #[test]
298 fn test_json_macro() {
299 let json_value = json!({
300 "some_string": "Bar",
301 "some_bool": true,
302 "some_int": 12,
303 "some_float": 2.3,
304 "some_seq": ["elem1", "elem2"],
305 "some_obj": {"key": "value"}
306 });
307
308 let payload: Payload = Payload::try_from(json_value).unwrap();
309
310 eprintln!("payload = {payload:#?}");
311 }
312}