semilattice_database_session/session/
sort.rs

1use std::{cmp::Ordering, fmt::Debug, num::NonZeroI64};
2
3use hashbrown::HashMap;
4use semilattice_database::{
5    idx_binary::{AvltrieeSearch, IdxBinary},
6    FieldName,
7};
8
9use super::TemporaryDataEntity;
10use crate::{Collection, Session};
11
12pub trait SessionCustomOrder {
13    fn compare(&self, a: NonZeroI64, b: NonZeroI64) -> Ordering;
14    fn asc(&self) -> Vec<NonZeroI64>;
15    fn desc(&self) -> Vec<NonZeroI64>;
16}
17impl Debug for dyn SessionCustomOrder {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        writeln!(f, "SessionCustomOrder")?;
20        Ok(())
21    }
22}
23
24#[derive(Debug)]
25pub enum SessionOrderKey<C: SessionCustomOrder> {
26    Serial,
27    Row,
28    TermBegin,
29    TermEnd,
30    LastUpdated,
31    Field(FieldName),
32    Custom(C),
33}
34
35#[derive(Debug)]
36pub enum SessionOrder<C: SessionCustomOrder> {
37    Asc(SessionOrderKey<C>),
38    Desc(SessionOrderKey<C>),
39}
40
41impl Session {
42    pub fn sort<C: SessionCustomOrder>(
43        &self,
44        collection: &Collection,
45        mut rows: Vec<NonZeroI64>,
46        orders: &Vec<SessionOrder<C>>,
47    ) -> Vec<NonZeroI64> {
48        if orders.len() > 0 {
49            let collection_id = collection.id();
50            if let Some(tmp) = self.temporary_data.get(&collection_id) {
51                rows.sort_by(|a, b| {
52                    for i in 0..orders.len() {
53                        match &orders[i] {
54                            SessionOrder::Asc(order_key) => match order_key {
55                                SessionOrderKey::Serial => {
56                                    let (a, b) = serial(collection, *a, *b);
57                                    let ord = a.cmp(&b);
58                                    if ord != Ordering::Equal {
59                                        return ord;
60                                    }
61                                }
62                                SessionOrderKey::Row => return a.cmp(b),
63                                SessionOrderKey::TermBegin => {
64                                    let (a, b) = term_begin(tmp, collection, *a, *b);
65                                    let ord = a.cmp(&b);
66                                    if ord != Ordering::Equal {
67                                        return ord;
68                                    }
69                                }
70                                SessionOrderKey::TermEnd => {
71                                    let (a, b) = term_end(tmp, collection, *a, *b);
72                                    let ord = a.cmp(&b);
73                                    if ord != Ordering::Equal {
74                                        return ord;
75                                    }
76                                }
77                                SessionOrderKey::LastUpdated => {
78                                    let (a, b) = last_updated(collection, *a, *b);
79                                    let ord = a.cmp(&b);
80                                    if ord != Ordering::Equal {
81                                        return ord;
82                                    }
83                                }
84                                SessionOrderKey::Field(field_name) => {
85                                    let ord = IdxBinary::cmp(
86                                        field(tmp, collection, *a, field_name),
87                                        field(tmp, collection, *b, field_name),
88                                    );
89                                    if ord != Ordering::Equal {
90                                        return ord;
91                                    }
92                                }
93                                SessionOrderKey::Custom(custom_order) => {
94                                    if a.get() > 0 && b.get() > 0 {
95                                        let ord = custom_order.compare(*a, *b);
96                                        if ord != Ordering::Equal {
97                                            return ord;
98                                        }
99                                    }
100                                }
101                            },
102                            SessionOrder::Desc(order_key) => match order_key {
103                                SessionOrderKey::Serial => {
104                                    let (a, b) = serial(collection, *a, *b);
105                                    let ord = b.cmp(&a);
106                                    if ord != Ordering::Equal {
107                                        return ord;
108                                    }
109                                }
110                                SessionOrderKey::Row => {
111                                    return b.cmp(a);
112                                }
113                                SessionOrderKey::TermBegin => {
114                                    let (a, b) = term_begin(tmp, collection, *a, *b);
115                                    let ord = b.cmp(&a);
116                                    if ord != Ordering::Equal {
117                                        return ord;
118                                    }
119                                }
120                                SessionOrderKey::TermEnd => {
121                                    let (a, b) = term_end(tmp, collection, *a, *b);
122                                    let ord = b.cmp(&a);
123                                    if ord != Ordering::Equal {
124                                        return ord;
125                                    }
126                                }
127                                SessionOrderKey::LastUpdated => {
128                                    let (a, b) = last_updated(collection, *a, *b);
129                                    let ord = b.cmp(&a);
130                                    if ord != Ordering::Equal {
131                                        return ord;
132                                    }
133                                }
134                                SessionOrderKey::Field(field_name) => {
135                                    let ord = IdxBinary::cmp(
136                                        field(tmp, collection, *b, field_name),
137                                        field(tmp, collection, *a, field_name),
138                                    );
139                                    if ord != Ordering::Equal {
140                                        return ord;
141                                    }
142                                }
143                                SessionOrderKey::Custom(custom_order) => {
144                                    let ord = custom_order.compare(*b, *a);
145                                    if ord != Ordering::Equal {
146                                        return ord;
147                                    }
148                                }
149                            },
150                        }
151                    }
152                    Ordering::Equal
153                });
154            }
155        }
156        rows
157    }
158}
159
160fn serial(collection: &Collection, a: NonZeroI64, b: NonZeroI64) -> (u32, u32) {
161    (
162        if a.get() < 0 {
163            0
164        } else {
165            *collection.serial(a.try_into().unwrap())
166        },
167        if b.get() < 0 {
168            0
169        } else {
170            *collection.serial(b.try_into().unwrap())
171        },
172    )
173}
174
175fn term_begin(
176    temporary_collection: &HashMap<NonZeroI64, TemporaryDataEntity>,
177    collection: &Collection,
178    a: NonZeroI64,
179    b: NonZeroI64,
180) -> (u64, u64) {
181    (
182        if a.get() < 0 {
183            temporary_collection.get(&a).unwrap().term_begin()
184        } else {
185            *collection.term_begin(a.try_into().unwrap()).unwrap_or(&0)
186        },
187        if b.get() < 0 {
188            temporary_collection.get(&b).unwrap().term_begin()
189        } else {
190            *collection.term_begin(b.try_into().unwrap()).unwrap_or(&0)
191        },
192    )
193}
194
195fn term_end(
196    temporary_collection: &HashMap<NonZeroI64, TemporaryDataEntity>,
197    collection: &Collection,
198    a: NonZeroI64,
199    b: NonZeroI64,
200) -> (u64, u64) {
201    (
202        if a.get() < 0 {
203            temporary_collection.get(&a).unwrap().term_end()
204        } else {
205            *collection.term_end(a.try_into().unwrap()).unwrap_or(&0)
206        },
207        if b.get() < 0 {
208            temporary_collection.get(&b).unwrap().term_end()
209        } else {
210            *collection.term_end(b.try_into().unwrap()).unwrap_or(&0)
211        },
212    )
213}
214
215fn last_updated(collection: &Collection, a: NonZeroI64, b: NonZeroI64) -> (u64, u64) {
216    (
217        if a.get() < 0 {
218            0
219        } else {
220            *collection.last_updated(a.try_into().unwrap()).unwrap_or(&0)
221        },
222        if b.get() < 0 {
223            0
224        } else {
225            *collection.last_updated(b.try_into().unwrap()).unwrap_or(&0)
226        },
227    )
228}
229
230fn field<'a>(
231    temporary_collection: &'a HashMap<NonZeroI64, TemporaryDataEntity>,
232    collection: &'a Collection,
233    row: NonZeroI64,
234    field_name: &FieldName,
235) -> &'a [u8] {
236    if row.get() < 0 {
237        temporary_collection
238            .get(&row)
239            .unwrap()
240            .fields()
241            .get(field_name)
242            .map_or(b"", |v| v)
243    } else {
244        collection.field_bytes(row.try_into().unwrap(), field_name)
245    }
246}