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