1use std::collections::HashMap;
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6use crate::qdrant::{GeoPoint, Struct, Value};
7
8#[derive(Clone, PartialEq, Debug, Default)]
52#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
53#[cfg_attr(feature = "serde", serde(transparent))]
54pub struct Payload(pub(crate) HashMap<String, Value>);
55
56impl Payload {
57 pub fn new() -> Self {
59 Self(HashMap::new())
60 }
61
62 #[deprecated(since = "1.10.0", note = "use `Payload::from` instead")]
64 pub fn new_from_hashmap(payload: HashMap<String, Value>) -> Self {
65 Self(payload)
66 }
67
68 pub fn insert(&mut self, key: impl ToString, val: impl Into<Value>) {
70 self.0.insert(key.to_string(), val.into());
71 }
72}
73
74impl From<HashMap<String, Value>> for Payload {
75 #[inline]
76 fn from(payload: HashMap<String, Value>) -> Self {
77 Self(payload)
78 }
79}
80
81impl From<HashMap<&str, Value>> for Payload {
82 #[inline]
83 fn from(payload: HashMap<&str, Value>) -> Self {
84 Self(
85 payload
86 .into_iter()
87 .map(|(k, v)| (k.to_string(), v))
88 .collect(),
89 )
90 }
91}
92
93impl From<Payload> for HashMap<String, Value> {
94 #[inline]
95 fn from(payload: Payload) -> Self {
96 payload.0
97 }
98}
99
100#[cfg(feature = "serde")]
101impl From<Payload> for serde_json::Value {
102 #[inline]
103 fn from(value: Payload) -> serde_json::Value {
104 serde_json::Value::Object(value.into())
105 }
106}
107
108#[cfg(feature = "serde")]
109impl From<Payload> for serde_json::Map<String, serde_json::Value> {
110 #[inline]
111 fn from(value: Payload) -> serde_json::Map<String, serde_json::Value> {
112 value
113 .0
114 .into_iter()
115 .map(|(k, v)| (k, v.into()))
116 .collect::<serde_json::Map<String, serde_json::Value>>()
117 }
118}
119
120#[cfg(feature = "serde")]
121impl TryFrom<serde_json::Value> for Payload {
122 type Error = crate::QdrantError;
123
124 #[inline]
135 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
136 if let serde_json::Value::Object(object) = value {
137 Ok(object.into())
138 } else {
139 Err(crate::QdrantError::JsonToPayload(value))
140 }
141 }
142}
143
144#[cfg(feature = "serde")]
145impl From<serde_json::Map<String, serde_json::Value>> for Payload {
146 #[inline]
151 fn from(object: serde_json::Map<String, serde_json::Value>) -> Self {
152 Payload::from(
153 object
154 .into_iter()
155 .map(|(k, v)| (k, v.into()))
156 .collect::<HashMap<String, Value>>(),
157 )
158 }
159}
160
161impl<K, const N: usize> From<[(K, Value); N]> for Payload
162where
163 K: Into<String>,
164{
165 fn from(values: [(K, Value); N]) -> Self {
166 let mut map = HashMap::with_capacity(N);
167 for (k, v) in values {
168 map.insert(k.into(), v);
169 }
170 Self(map)
171 }
172}
173
174impl From<GeoPoint> for Value {
175 fn from(point: GeoPoint) -> Self {
176 use crate::qdrant::value::Kind;
177
178 let map = HashMap::from([
179 ("lat".to_string(), point.lat.into()),
180 ("lon".to_string(), point.lon.into()),
181 ]);
182
183 Self {
184 kind: Some(Kind::StructValue(Struct { fields: map })),
185 }
186 }
187}
188
189#[cfg(feature = "serde")]
190#[cfg(test)]
191mod tests {
192 use serde_json::json;
193
194 use super::*;
195 use crate::client::Payload;
196
197 #[test]
198 fn json_payload_round_trip() {
199 let payload: Payload = vec![
200 ("some_string", "Bar".into()),
201 ("some_bool", true.into()),
202 ("some_int", 12.into()),
203 ("some_float", 2.3.into()),
204 ("some_seq", vec!["elem1", "elem2"].into()),
205 ("some_obj", vec![("key", "value")].into()),
206 ]
207 .into_iter()
208 .collect::<HashMap<_, Value>>()
209 .into();
210
211 let json_value = serde_json::to_string(&payload).unwrap();
213
214 let payload_back: Payload = serde_json::from_str(&json_value).unwrap();
216
217 assert_eq!(payload, payload_back);
219 }
220
221 #[test]
222 fn payload_from_string() {
223 let json = r#"{
224 "some_string": "Bar",
225 "some_bool": true,
226 "some_int": 12,
227 "some_float": 2.3,
228 "some_seq": ["elem1", "elem2"],
229 "some_obj": {"key": "value"}
230 }"#;
231
232 let parsed_payload: Payload = serde_json::from_str(json).unwrap();
234
235 let expected: Payload = vec![
236 ("some_string", "Bar".into()),
237 ("some_bool", true.into()),
238 ("some_int", 12.into()),
239 ("some_float", 2.3.into()),
240 ("some_seq", vec!["elem1", "elem2"].into()),
241 ("some_obj", vec![("key", "value")].into()),
242 ]
243 .into_iter()
244 .collect::<HashMap<_, Value>>()
245 .into();
246
247 assert_eq!(parsed_payload, expected);
249 }
250
251 #[test]
252 fn test_json_macro() {
253 let json_value = json!({
254 "some_string": "Bar",
255 "some_bool": true,
256 "some_int": 12,
257 "some_float": 2.3,
258 "some_seq": ["elem1", "elem2"],
259 "some_obj": {"key": "value"}
260 });
261
262 let payload: Payload = Payload::try_from(json_value).unwrap();
263
264 eprintln!("payload = {payload:#?}");
265 }
266}