1use std::collections::BTreeMap;
2use std::hash::Hash;
3use std::ops::{Index, IndexMut};
4
5use crate::{Entity, IdentifiableEntity, Record, Value, VersionedEntity};
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct SmartList<T> {
9 pub data: Vec<T>,
10 pub total_count: Option<u64>,
11 pub aggregations: Record,
12 pub summary: Record,
13 pub facets: BTreeMap<String, SmartList<Record>>,
14 pub is_loaded: bool,
15}
16
17impl<T> SmartList<T> {
18 pub fn empty() -> Self {
19 let mut list = Self::new(Vec::new());
20 list.is_loaded = false;
21 list
22 }
23
24 pub fn into_value(self) -> Option<Value> where T: Entity {
25 let mut has_changes = false;
26 let mut items = Vec::new();
27 for entity in self.data.into_iter() {
28 if Entity::is_new(&entity)
29 || Entity::dirty_fields(&entity).is_some()
30 || Entity::is_marked_as_delete(&entity)
31 {
32 has_changes = true;
33 }
34 items.push(Value::object(Entity::into_record(entity)));
35 }
36
37 (self.is_loaded || has_changes).then(|| Value::List(items))
38 }
39
40 pub fn new(data: Vec<T>) -> Self {
41 Self {
42 data,
43 total_count: None,
44 aggregations: Record::new(),
45 summary: Record::new(),
46 facets: BTreeMap::new(),
47 is_loaded: true,
48 }
49 }
50
51 pub fn with_total_count(mut self, total_count: u64) -> Self {
52 self.total_count = Some(total_count);
53 self
54 }
55
56 pub fn with_aggregation(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
57 self.aggregations.insert(key.into(), value.into());
58 self
59 }
60
61 pub fn with_summary(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
62 self.summary.insert(key.into(), value.into());
63 self
64 }
65
66 pub fn with_facet(mut self, key: impl Into<String>, facet: SmartList<Record>) -> Self {
67 self.facets.insert(key.into(), facet);
68 self
69 }
70
71 pub fn add_facet(&mut self, key: impl Into<String>, facet: SmartList<Record>) {
72 self.facets.insert(key.into(), facet);
73 }
74
75 pub fn facets(&self) -> &BTreeMap<String, SmartList<Record>> {
76 &self.facets
77 }
78
79 pub fn facets_mut(&mut self) -> &mut BTreeMap<String, SmartList<Record>> {
80 &mut self.facets
81 }
82
83 pub fn facet(&self, key: &str) -> Option<&SmartList<Record>> {
84 self.facets.get(key)
85 }
86
87 pub fn facet_mut(&mut self, key: &str) -> Option<&mut SmartList<Record>> {
88 self.facets.get_mut(key)
89 }
90
91 pub fn remove_facet(&mut self, key: &str) -> Option<SmartList<Record>> {
92 self.facets.remove(key)
93 }
94
95 pub fn take_facets(&mut self) -> BTreeMap<String, SmartList<Record>> {
96 std::mem::take(&mut self.facets)
97 }
98
99 pub fn push(&mut self, value: T) {
100 self.data.push(value);
101 }
102
103 pub fn extend(&mut self, values: impl IntoIterator<Item = T>) {
104 self.data.extend(values);
105 }
106
107 pub fn set(&mut self, index: usize, value: T) -> Option<T> {
108 if index >= self.data.len() {
109 return None;
110 }
111 Some(std::mem::replace(&mut self.data[index], value))
112 }
113
114 pub fn get(&self, index: usize) -> Option<&T> {
115 self.data.get(index)
116 }
117
118 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
119 self.data.get_mut(index)
120 }
121
122 pub fn last(&self) -> Option<&T> {
123 self.data.last()
124 }
125
126 pub fn len(&self) -> usize {
127 self.data.len()
128 }
129
130 pub fn is_empty(&self) -> bool {
131 self.data.is_empty()
132 }
133
134 pub fn first(&self) -> Option<&T> {
135 self.data.first()
136 }
137
138 pub fn iter(&self) -> std::slice::Iter<'_, T> {
139 self.data.iter()
140 }
141
142 pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
143 self.data.iter_mut()
144 }
145
146 pub fn as_slice(&self) -> &[T] {
147 &self.data
148 }
149
150 pub fn as_mut_slice(&mut self) -> &mut [T] {
151 &mut self.data
152 }
153
154 pub fn retain(&mut self, filter: impl FnMut(&T) -> bool) {
155 self.data.retain(filter);
156 }
157
158 pub fn total_count_or_len(&self) -> u64 {
159 self.total_count.unwrap_or(self.data.len() as u64)
160 }
161
162 pub fn aggregation(&self, key: &str) -> Option<&Value> {
163 self.aggregations.get(key)
164 }
165
166 pub fn summary(&self, key: &str) -> Option<&Value> {
167 self.summary.get(key)
168 }
169
170 pub fn aggregation_json(&self) -> serde_json::Value {
171 crate::record_to_json_value(&self.aggregations)
172 }
173
174 pub fn summary_json(&self) -> serde_json::Value {
175 crate::record_to_json_value(&self.summary)
176 }
177
178 pub fn into_vec(self) -> Vec<T> {
179 self.data
180 }
181
182 pub fn map<U>(self, mapper: impl FnMut(T) -> U) -> SmartList<U> {
183 SmartList {
184 data: self.data.into_iter().map(mapper).collect(),
185 total_count: self.total_count,
186 aggregations: self.aggregations,
187 summary: self.summary,
188 facets: self.facets,
189 is_loaded: self.is_loaded,
190 }
191 }
192
193 pub fn to_list<U>(&self, mapper: impl FnMut(&T) -> U) -> Vec<U> {
194 self.data.iter().map(mapper).collect()
195 }
196
197 pub fn to_set<U>(&self, mapper: impl FnMut(&T) -> U) -> std::collections::BTreeSet<U>
198 where
199 U: Ord,
200 {
201 self.data.iter().map(mapper).collect()
202 }
203
204 pub fn identity_map<K>(&self, mut key: impl FnMut(&T) -> K) -> BTreeMap<K, T>
205 where
206 K: Ord,
207 T: Clone,
208 {
209 self.data
210 .iter()
211 .map(|item| (key(item), item.clone()))
212 .collect()
213 }
214
215 pub fn group_by<K>(&self, mut key: impl FnMut(&T) -> K) -> BTreeMap<K, Vec<T>>
216 where
217 K: Ord,
218 T: Clone,
219 {
220 let mut groups = BTreeMap::new();
221 for item in &self.data {
222 groups
223 .entry(key(item))
224 .or_insert_with(Vec::new)
225 .push(item.clone());
226 }
227 groups
228 }
229
230 pub fn merge_by<K>(
231 &mut self,
232 incoming: impl IntoIterator<Item = T>,
233 mut key: impl FnMut(&T) -> K,
234 ) where
235 K: Eq + Hash,
236 {
237 let mut positions = self
238 .data
239 .iter()
240 .enumerate()
241 .map(|(index, item)| (key(item), index))
242 .collect::<std::collections::HashMap<_, _>>();
243 for item in incoming {
244 let item_key = key(&item);
245 match positions.get(&item_key).copied() {
246 Some(index) => self.data[index] = item,
247 None => {
248 positions.insert(item_key, self.data.len());
249 self.data.push(item);
250 }
251 }
252 }
253 }
254
255 pub fn into_records(self) -> SmartList<Record>
256 where
257 T: Entity,
258 {
259 SmartList {
260 data: self.data.into_iter().map(Entity::into_record).collect(),
261 total_count: self.total_count,
262 aggregations: self.aggregations,
263 summary: self.summary,
264 facets: self.facets,
265 is_loaded: self.is_loaded,
266 }
267 }
268}
269
270impl<T> SmartList<T>
271where
272 T: IdentifiableEntity,
273{
274 pub fn ids(&self) -> Vec<Value> {
275 self.data.iter().map(IdentifiableEntity::id_value).collect()
276 }
277
278 pub fn map_by_id(&self) -> BTreeMap<String, T>
279 where
280 T: Clone,
281 {
282 self.data
283 .iter()
284 .map(|item| (id_key(&item.id_value()), item.clone()))
285 .collect()
286 }
287}
288
289impl<T> SmartList<T>
290where
291 T: VersionedEntity,
292{
293 pub fn versions(&self) -> Vec<i64> {
294 self.data.iter().map(VersionedEntity::version).collect()
295 }
296}
297
298impl<T> From<Vec<T>> for SmartList<T> {
299 fn from(data: Vec<T>) -> Self {
300 Self::new(data)
301 }
302}
303
304impl<T> Default for SmartList<T> {
305 fn default() -> Self {
306 Self::empty()
307 }
308}
309
310impl<T> IntoIterator for SmartList<T> {
311 type Item = T;
312 type IntoIter = std::vec::IntoIter<T>;
313
314 fn into_iter(self) -> Self::IntoIter {
315 self.data.into_iter()
316 }
317}
318
319impl<'a, T> IntoIterator for &'a SmartList<T> {
320 type Item = &'a T;
321 type IntoIter = std::slice::Iter<'a, T>;
322
323 fn into_iter(self) -> Self::IntoIter {
324 self.data.iter()
325 }
326}
327
328impl<'a, T> IntoIterator for &'a mut SmartList<T> {
329 type Item = &'a mut T;
330 type IntoIter = std::slice::IterMut<'a, T>;
331
332 fn into_iter(self) -> Self::IntoIter {
333 self.data.iter_mut()
334 }
335}
336
337impl<T> FromIterator<T> for SmartList<T> {
338 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
339 Self::new(iter.into_iter().collect())
340 }
341}
342
343impl<T> Extend<T> for SmartList<T> {
344 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
345 self.data.extend(iter);
346 }
347}
348
349impl<T> Index<usize> for SmartList<T> {
350 type Output = T;
351
352 fn index(&self, index: usize) -> &Self::Output {
353 &self.data[index]
354 }
355}
356
357impl<T> IndexMut<usize> for SmartList<T> {
358 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
359 &mut self.data[index]
360 }
361}
362
363impl<T> std::ops::Deref for SmartList<T> {
364 type Target = [T];
365
366 #[inline(always)]
367 fn deref(&self) -> &Self::Target {
368 &self.data
369 }
370}
371
372impl<T> std::ops::DerefMut for SmartList<T> {
373 #[inline(always)]
374 fn deref_mut(&mut self) -> &mut Self::Target {
375 &mut self.data
376 }
377}
378
379impl<T> From<SmartList<T>> for Vec<T> {
380 #[inline(always)]
381 fn from(list: SmartList<T>) -> Self {
382 list.data
383 }
384}
385
386
387fn id_key(value: &Value) -> String {
388 match value {
389 Value::Null => "null".to_owned(),
390 Value::Bool(value) => format!("b:{value}"),
391 Value::I64(value) => format!("i:{value}"),
392 Value::U64(value) => format!("u:{value}"),
393 Value::F64(value) => format!("f:{value}"),
394 Value::Decimal(value) => format!("decimal:{value}"),
395 Value::Text(value) => format!("t:{value}"),
396 Value::Json(value) => format!("j:{value}"),
397 Value::Date(value) => format!("date:{value}"),
398 Value::Timestamp(value) => format!("ts:{}", value.to_rfc3339()),
399 Value::Object(_) => "object".to_owned(),
400 Value::List(_) => "list".to_owned(),
401 }
402}