semilattice_database_session/session/
search.rs

1use std::{
2    collections::BTreeSet,
3    num::{NonZeroI32, NonZeroI64, NonZeroU32},
4    sync::Arc,
5};
6
7use async_recursion::async_recursion;
8use hashbrown::HashMap;
9use semilattice_database::{
10    idx_binary::AvltrieeSearch, search, Collection, Condition, Depend, FieldName, SearchResult,
11};
12
13use crate::{Session, SessionDatabase};
14
15use super::{SessionOperation, TemporaryDataEntity};
16
17#[derive(Debug, Clone, PartialEq)]
18pub struct SessionSearchResult {
19    collection_id: i32,
20    rows: BTreeSet<NonZeroI64>,
21    join: HashMap<Arc<String>, HashMap<NonZeroI64, SessionSearchResult>>,
22}
23
24impl SessionSearchResult {
25    pub fn rows(&self) -> &BTreeSet<NonZeroI64> {
26        &self.rows
27    }
28
29    pub fn join(&self) -> &HashMap<Arc<String>, HashMap<NonZeroI64, SessionSearchResult>> {
30        &self.join
31    }
32}
33
34impl Session {
35    fn temporary_data_match(
36        row: NonZeroI64,
37        ent: &TemporaryDataEntity,
38        condition: &Condition,
39    ) -> bool {
40        match condition {
41            Condition::Row(cond) => match cond {
42                search::Number::In(c) => c.contains(&(row.get() as isize)),
43                search::Number::Max(c) => row.get() <= *c as i64,
44                search::Number::Min(c) => row.get() >= *c as i64,
45                search::Number::Range(c) => c.contains(&(row.get() as isize)),
46            },
47            Condition::Uuid(uuid) => uuid.contains(&ent.uuid),
48            Condition::Activity(activity) => ent.activity == *activity,
49            Condition::Term(cond) => match cond {
50                search::Term::In(c) => {
51                    ent.term_begin < *c && (ent.term_end == 0 || ent.term_end > *c)
52                }
53                search::Term::Past(c) => ent.term_end >= *c,
54                search::Term::Future(c) => ent.term_begin >= *c,
55            },
56            Condition::Field(field_id, cond) => {
57                ent.fields.get(field_id).map_or(false, |f| match cond {
58                    search::Field::Match(v) => f == v,
59                    search::Field::Range(min, max) => min <= f && max >= f,
60                    search::Field::Min(min) => min <= f,
61                    search::Field::Max(max) => max >= f,
62                    search::Field::Forward(v) => {
63                        unsafe { std::str::from_utf8_unchecked(f) }.starts_with(v.as_ref())
64                    }
65                    search::Field::Partial(v) => {
66                        unsafe { std::str::from_utf8_unchecked(f) }.contains(v.as_ref())
67                    }
68                    search::Field::Backward(v) => {
69                        unsafe { std::str::from_utf8_unchecked(f) }.ends_with(v.as_ref())
70                    }
71                    search::Field::ValueForward(v) => {
72                        v.starts_with(unsafe { std::str::from_utf8_unchecked(f) })
73                    }
74                    search::Field::ValueBackward(v) => {
75                        v.ends_with(unsafe { std::str::from_utf8_unchecked(f) })
76                    }
77                    search::Field::ValuePartial(v) => {
78                        v.contains(unsafe { std::str::from_utf8_unchecked(f) })
79                    }
80                })
81            }
82            Condition::Narrow(conditions) => {
83                let mut is_match = true;
84                for c in conditions.into_iter() {
85                    is_match &= Self::temporary_data_match(row, ent, c);
86                    if !is_match {
87                        break;
88                    }
89                }
90                is_match
91            }
92            Condition::Wide(conditions) => {
93                let mut is_match = false;
94                for c in conditions.into_iter() {
95                    is_match |= Self::temporary_data_match(row, ent, c);
96                    if is_match {
97                        break;
98                    }
99                }
100                is_match
101            }
102            Condition::Depend(key, collection_row) => {
103                let mut is_match = true;
104                for depend in &ent.depends {
105                    is_match = key.as_ref().map_or(true, |key| key == depend.key())
106                        && collection_row == &**depend;
107                    if is_match {
108                        break;
109                    }
110                }
111                is_match
112            }
113            Condition::LastUpdated(_) => true,
114        }
115    }
116
117    fn temprary_data_match_conditions(
118        conditions: &Vec<Condition>,
119        row: NonZeroI64,
120        ent: &TemporaryDataEntity,
121    ) -> bool {
122        for c in conditions.into_iter() {
123            if !Self::temporary_data_match(row, ent, c) {
124                return false;
125            }
126        }
127        true
128    }
129
130    #[async_recursion(?Send)]
131    async fn join(
132        &self,
133        join_result: &HashMap<Arc<String>, HashMap<NonZeroU32, SearchResult>>,
134    ) -> HashMap<Arc<String>, HashMap<NonZeroI64, SessionSearchResult>> {
135        let mut map = HashMap::new();
136        for (name, row_join) in join_result {
137            let mut map_inner = HashMap::new();
138            for (row, result) in row_join {
139                let result = self.result_with(result).await;
140                map_inner.insert((*row).into(), result);
141            }
142            map.insert(name.to_owned(), map_inner);
143        }
144        map
145    }
146
147    pub async fn result_with(&self, search_result: &SearchResult) -> SessionSearchResult {
148        let (collection_id, rows) = if let Some(search) = search_result.search() {
149            let collection_id = search.collection_id();
150            (
151                collection_id.get(),
152                if let Some(tmp) = self.temporary_data.get(&collection_id) {
153                    let mut rows: BTreeSet<NonZeroI64> = BTreeSet::new();
154                    for row in search_result.rows().into_iter() {
155                        let row = NonZeroI64::from(*row);
156                        if let Some(ent) = tmp.get(&row) {
157                            if ent.operation != SessionOperation::Delete {
158                                if Self::temprary_data_match_conditions(
159                                    search.conditions(),
160                                    row,
161                                    ent,
162                                ) {
163                                    rows.insert(row);
164                                }
165                            }
166                        } else {
167                            rows.insert(row);
168                        }
169                    }
170                    for (row, _) in tmp.into_iter() {
171                        if row.get() < 0 {
172                            if let Some(ent) = tmp.get(row) {
173                                if ent.operation != SessionOperation::Delete {
174                                    if Self::temprary_data_match_conditions(
175                                        search.conditions(),
176                                        *row,
177                                        ent,
178                                    ) {
179                                        rows.insert(*row);
180                                    }
181                                }
182                            }
183                        }
184                    }
185                    rows
186                } else {
187                    search_result
188                        .rows()
189                        .into_iter()
190                        .map(|x| NonZeroI64::from(*x))
191                        .collect()
192                },
193            )
194        } else {
195            (0, BTreeSet::new())
196        };
197        let join = self.join(search_result.join()).await;
198
199        SessionSearchResult {
200            collection_id,
201            rows,
202            join,
203        }
204    }
205
206    pub fn field_bytes<'a>(
207        &'a self,
208        database: &'a SessionDatabase,
209        collection_id: NonZeroI32,
210        row: NonZeroI64,
211        field_name: &FieldName,
212    ) -> &[u8] {
213        if let Some(temporary_collection) = self.temporary_data.get(&collection_id) {
214            if let Some(tmp_row) = temporary_collection.get(&row) {
215                if let Some(val) = tmp_row.fields.get(field_name) {
216                    return val;
217                }
218            }
219        }
220        if row.get() > 0 {
221            if let Some(collection) = database.collection(collection_id) {
222                return collection.field_bytes(row.try_into().unwrap(), field_name);
223            }
224        }
225        b""
226    }
227
228    pub fn collection_field_bytes<'a>(
229        &'a self,
230        collection: &'a Collection,
231        row: NonZeroI64,
232        field_name: &FieldName,
233    ) -> &[u8] {
234        if let Some(temprary_collection) = self.temporary_data.get(&collection.id()) {
235            if let Some(temprary_row) = temprary_collection.get(&row) {
236                if let Some(val) = temprary_row.fields.get(field_name) {
237                    return val;
238                }
239            }
240        }
241        if row.get() > 0 {
242            collection.field_bytes(row.try_into().unwrap(), field_name)
243        } else {
244            b""
245        }
246    }
247
248    pub fn temporary_collection(
249        &self,
250        collection_id: NonZeroI32,
251    ) -> Option<&HashMap<NonZeroI64, TemporaryDataEntity>> {
252        self.temporary_data.get(&collection_id)
253    }
254
255    pub fn depends(&self, key: Option<Arc<String>>, pend_row: NonZeroU32) -> Option<Vec<Depend>> {
256        self.session_data.as_ref().and_then(move |session_data| {
257            key.map_or_else(
258                || {
259                    Some(
260                        session_data
261                            .relation
262                            .rows
263                            .session_row
264                            .iter_by(&pend_row.get())
265                            .filter_map(|relation_row| {
266                                if let (Some(key), Some(depend)) = (
267                                    session_data.relation.rows.key.value(relation_row),
268                                    session_data.relation.rows.depend.value(relation_row),
269                                ) {
270                                    return Some(Depend::new(
271                                        Arc::new(
272                                            unsafe {
273                                                std::str::from_utf8_unchecked(
274                                                    session_data
275                                                        .relation
276                                                        .key_names
277                                                        .value(NonZeroU32::new(*key).unwrap())
278                                                        .unwrap(),
279                                                )
280                                            }
281                                            .into(),
282                                        ),
283                                        depend.clone(),
284                                    ));
285                                }
286                                None
287                            })
288                            .collect(),
289                    )
290                },
291                |key_name| {
292                    session_data
293                        .relation
294                        .key_names
295                        .row(key_name.as_bytes())
296                        .map(|key_id| {
297                            session_data
298                                .relation
299                                .rows
300                                .session_row
301                                .iter_by(&pend_row.get())
302                                .filter_map(|relation_row| {
303                                    if let (Some(key), Some(depend)) = (
304                                        session_data.relation.rows.key.value(relation_row),
305                                        session_data.relation.rows.depend.value(relation_row),
306                                    ) {
307                                        if *key == key_id.get() {
308                                            return Some(Depend::new(
309                                                Arc::clone(&key_name),
310                                                depend.clone(),
311                                            ));
312                                        }
313                                    }
314                                    None
315                                })
316                                .collect()
317                        })
318                },
319            )
320        })
321    }
322}