semilattice_database_session/session/
sort.rs1use 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}