Skip to main content

teaql_core/
list.rs

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