semilattice_database/search/
result.rs

1use std::{num::NonZeroU32, sync::Arc};
2
3use futures::future;
4use hashbrown::HashMap;
5use versatile_data::{CustomSort, Order, RowSet};
6
7use crate::{Collection, Condition, Database, RelationIndex, Search};
8
9#[derive(Clone, Debug, PartialEq)]
10pub struct SearchResult {
11    search: Option<Search>,
12    rows: RowSet,
13    join: HashMap<Arc<String>, HashMap<NonZeroU32, SearchResult>>,
14}
15
16impl SearchResult {
17    pub fn new(
18        search: Option<Search>,
19        rows: RowSet,
20        join: HashMap<Arc<String>, HashMap<NonZeroU32, SearchResult>>,
21    ) -> Self {
22        Self { search, rows, join }
23    }
24
25    pub fn search(&self) -> Option<&Search> {
26        self.search.as_ref()
27    }
28
29    pub fn rows(&self) -> &RowSet {
30        &self.rows
31    }
32
33    pub fn join(&self) -> &HashMap<Arc<String>, HashMap<NonZeroU32, SearchResult>> {
34        &self.join
35    }
36
37    pub fn sort<C: CustomSort>(&self, database: &Database, orders: &[Order<C>]) -> Vec<NonZeroU32> {
38        if let Some(search) = self.search() {
39            if let Some(collection) = database.collection(search.collection_id) {
40                return if orders.len() > 0 {
41                    collection.data().sort(&self.rows, &orders)
42                } else {
43                    self.rows.iter().cloned().collect()
44                };
45            }
46        }
47        vec![]
48    }
49}
50
51impl Search {
52    pub(crate) async fn result_conditions(
53        collection: &Collection,
54        conditions: &Vec<Condition>,
55        relation: &RelationIndex,
56    ) -> RowSet {
57        let (mut rows, _index, fs) = future::select_all(
58            conditions
59                .into_iter()
60                .map(|c| c.result(collection, relation)),
61        )
62        .await;
63        for r in future::join_all(fs).await.into_iter() {
64            rows.retain(|v| r.contains(v));
65        }
66        rows
67    }
68
69    pub async fn result(self, database: &Database) -> SearchResult {
70        let collection_id = self.collection_id;
71        if let Some(collection) = database.collection(collection_id) {
72            let rows = if self.conditions.len() > 0 {
73                Self::result_conditions(collection, &self.conditions, &database.relation).await
74            } else {
75                collection.data().all()
76            };
77
78            let join = future::join_all(self.join.iter().map(|(name, join)| async {
79                (
80                    name.to_owned(),
81                    join.join_result(database, self.collection_id, &rows).await,
82                )
83            }))
84            .await
85            .into_iter()
86            .collect();
87
88            SearchResult {
89                search: Some(self),
90                rows,
91                join,
92            }
93        } else {
94            SearchResult {
95                search: Some(self),
96                rows: Default::default(),
97                join: Default::default(),
98            }
99        }
100    }
101}