Skip to main content

versatile_data/search/
result.rs

1use std::num::NonZeroU32;
2
3use futures::future;
4use idx_binary::{AvltrieeIter, AvltrieeSearch};
5
6use crate::{Condition, CustomSort, Data, FieldName, Order, RowSet, Search};
7
8use super::{Field, Number, Term};
9
10impl<'a> Search<'a> {
11    pub async fn result(&self) -> RowSet {
12        if !self.conditions.is_empty() {
13            self.data.result(&self.conditions).await
14        } else {
15            self.data.all()
16        }
17    }
18
19    pub async fn result_with_sort<C: CustomSort>(&self, orders: Vec<Order<C>>) -> Vec<NonZeroU32> {
20        self.data.sort(&self.result().await, &orders)
21    }
22}
23
24impl Data {
25    /// Returns search results by specifying [Condition].
26    pub async fn result_condition(&self, condition: &Condition<'_>) -> RowSet {
27        match condition {
28            Condition::Activity(condition) => {
29                if let Some(ref index) = self.activity {
30                    let activity = *condition as u8;
31                    index.iter_by(&activity).collect()
32                } else {
33                    RowSet::default()
34                }
35            }
36            Condition::Term(condition) => self.result_term(condition),
37            Condition::Field(field_name, condition) => self.result_field(field_name, condition),
38            Condition::Row(condition) => self.result_row(condition),
39            Condition::LastUpdated(condition) => self.result_last_updated(condition),
40            Condition::Uuid(uuid) => self.result_uuid(uuid),
41            Condition::Narrow(conditions) => Box::pin(self.result(conditions)).await,
42            Condition::Wide(conditions) => future::join_all(
43                conditions
44                    .iter()
45                    .map(|c| Box::pin(self.result_condition(c))),
46            )
47            .await
48            .into_iter()
49            .flatten()
50            .collect(),
51        }
52    }
53
54    async fn result(&self, conditions: &[Condition<'_>]) -> RowSet {
55        if conditions.is_empty() {
56            return self.all();
57        }
58        let (mut rows, _index, fs) = future::select_all(
59            conditions
60                .iter()
61                .map(|c| Box::pin(self.result_condition(c))),
62        )
63        .await;
64        for r in future::join_all(fs).await.into_iter() {
65            rows.retain(|v| r.contains(v));
66        }
67        rows
68    }
69
70    fn result_last_updated(&self, condition: &Number) -> RowSet {
71        if let Some(ref f) = self.last_updated {
72            match condition {
73                Number::Min(min) => {
74                    let min = *min as u64;
75                    f.iter_from(&min).collect()
76                }
77                Number::Max(max) => {
78                    let max = *max as u64;
79                    f.iter_to(&max).collect()
80                }
81                Number::Range(range) => f
82                    .iter_range(&(*range.start() as u64), &(*range.end() as u64))
83                    .collect(),
84                Number::In(rows) => rows.iter().flat_map(|i| f.iter_by(&(*i as u64))).collect(),
85            }
86        } else {
87            RowSet::default()
88        }
89    }
90
91    fn result_uuid(&self, uuids: &[u128]) -> RowSet {
92        if let Some(ref index) = self.uuid {
93            uuids.iter().flat_map(|uuid| index.iter_by(uuid)).collect()
94        } else {
95            RowSet::default()
96        }
97    }
98    fn result_term(&self, condition: &Term) -> RowSet {
99        match condition {
100            Term::In(base) => {
101                if let Some(ref term_begin) = self.term_begin {
102                    if let Some(ref term_end) = self.term_end {
103                        term_begin
104                            .iter_to(base)
105                            .filter(|row| {
106                                let end = term_end.value(*row).unwrap_or(&0);
107                                *end == 0 || end > base
108                            })
109                            .collect()
110                    } else {
111                        RowSet::default()
112                    }
113                } else {
114                    RowSet::default()
115                }
116            }
117            Term::Future(base) => {
118                if let Some(ref index) = self.term_begin {
119                    index.iter_from(base).collect()
120                } else {
121                    RowSet::default()
122                }
123            }
124            Term::Past(base) => {
125                if let Some(ref index) = self.term_end {
126                    index.iter_range(&1, base).collect()
127                } else {
128                    RowSet::default()
129                }
130            }
131        }
132    }
133
134    fn result_row(&self, condition: &Number) -> RowSet {
135        let to_row = |i: isize| u32::try_from(i).ok().and_then(NonZeroU32::new);
136        let exists = |row: &NonZeroU32| self.serial.node(*row).is_some();
137        match condition {
138            Number::Min(min) => self
139                .serial
140                .iter()
141                .filter(|i| i.get() as isize >= *min)
142                .collect(),
143            Number::Max(max) => self
144                .serial
145                .iter()
146                .filter(|i| i.get() as isize <= *max)
147                .collect(),
148            Number::Range(range) => {
149                let start = (*range.start()).max(1);
150                let end = (*range.end()).min(self.serial.rows_count() as isize);
151                (start..=end).filter_map(to_row).filter(exists).collect()
152            }
153            Number::In(rows) => rows
154                .iter()
155                .filter_map(|i| to_row(*i))
156                .filter(exists)
157                .collect(),
158        }
159    }
160
161    pub fn result_field(&self, name: &FieldName, condition: &Field) -> RowSet {
162        if let Some(field) = self.fields.get(name) {
163            match condition {
164                Field::Match(v) => AvltrieeIter::by(field, v).collect(),
165                Field::Min(min) => AvltrieeIter::from_asc(field, min).collect(),
166                Field::Max(max) => AvltrieeIter::to_asc(field, max).collect(),
167                Field::Range(min, max) => AvltrieeIter::range_asc(field, min, max).collect(),
168                Field::Forward(cont) => Self::result_field_sub(field, cont, Self::forward),
169                Field::Partial(cont) => Self::result_field_sub(field, cont, Self::partial),
170                Field::Backward(cont) => Self::result_field_sub(field, cont, Self::backward),
171                Field::ValueForward(cont) => {
172                    Self::result_field_sub(field, cont, Self::value_forward)
173                }
174                Field::ValuePartial(cont) => {
175                    Self::result_field_sub(field, cont, Self::value_partial)
176                }
177                Field::ValueBackward(cont) => {
178                    Self::result_field_sub(field, cont, Self::value_backward)
179                }
180            }
181        } else {
182            RowSet::default()
183        }
184    }
185
186    fn result_field_sub(
187        field: &crate::Field,
188        cont: &str,
189        func: fn(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool),
190    ) -> RowSet {
191        field
192            .as_ref()
193            .iter()
194            .map(|row| func(row, field, cont))
195            .filter_map(|(v, b)| b.then_some(v))
196            .collect()
197    }
198
199    fn forward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
200        (
201            row,
202            field
203                .value(row)
204                .is_some_and(|bytes| bytes.starts_with(cont.as_bytes())),
205        )
206    }
207
208    fn partial(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
209        (
210            row,
211            field.value(row).is_some_and(|bytes| {
212                let len = cont.len();
213                len <= bytes.len() && {
214                    let cont_bytes = cont.as_bytes();
215                    bytes
216                        .windows(len)
217                        .position(|window| window == cont_bytes)
218                        .is_some()
219                }
220            }),
221        )
222    }
223
224    fn backward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
225        (
226            row,
227            field
228                .value(row)
229                .is_some_and(|bytes| bytes.ends_with(cont.as_bytes())),
230        )
231    }
232
233    fn value_forward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
234        (
235            row,
236            field
237                .value(row)
238                .is_some_and(|bytes| cont.as_bytes().starts_with(bytes)),
239        )
240    }
241
242    fn value_partial(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
243        (
244            row,
245            field.value(row).is_some_and(|bytes| {
246                cont.as_bytes()
247                    .windows(bytes.len())
248                    .position(|window| window == bytes)
249                    .is_some()
250            }),
251        )
252    }
253
254    fn value_backward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
255        (
256            row,
257            field
258                .value(row)
259                .is_some_and(|bytes| cont.as_bytes().ends_with(bytes)),
260        )
261    }
262}