semilattice_database/search/
result.rs1use 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}