versatile-data 0.117.0

A library for databases that has convenient datasets that group together commonly used fields and gives you the flexibility to create your own fields.
Documentation
use std::num::NonZeroU32;

use futures::future;
use idx_binary::{AvltrieeIter, AvltrieeSearch};

use crate::{Condition, CustomSort, Data, FieldName, Order, RowSet, Search};

use super::{Field, Number, Term};

impl<'a> Search<'a> {
    pub async fn result(&self) -> RowSet {
        if !self.conditions.is_empty() {
            self.data.result(&self.conditions).await
        } else {
            self.data.all()
        }
    }

    pub async fn result_with_sort<C: CustomSort>(&self, orders: Vec<Order<C>>) -> Vec<NonZeroU32> {
        self.data.sort(&self.result().await, &orders)
    }
}

impl Data {
    /// Returns search results by specifying [Condition].
    pub async fn result_condition(&self, condition: &Condition<'_>) -> RowSet {
        match condition {
            Condition::Activity(condition) => {
                if let Some(ref index) = self.activity {
                    let activity = *condition as u8;
                    index.iter_by(&activity).collect()
                } else {
                    RowSet::default()
                }
            }
            Condition::Term(condition) => self.result_term(condition),
            Condition::Field(field_name, condition) => self.result_field(field_name, condition),
            Condition::Row(condition) => self.result_row(condition),
            Condition::LastUpdated(condition) => self.result_last_updated(condition),
            Condition::Uuid(uuid) => self.result_uuid(uuid),
            Condition::Narrow(conditions) => Box::pin(self.result(conditions)).await,
            Condition::Wide(conditions) => future::join_all(
                conditions
                    .iter()
                    .map(|c| Box::pin(self.result_condition(c))),
            )
            .await
            .into_iter()
            .flatten()
            .collect(),
        }
    }

    async fn result(&self, conditions: &[Condition<'_>]) -> RowSet {
        if conditions.is_empty() {
            return self.all();
        }
        let (mut rows, _index, fs) = future::select_all(
            conditions
                .iter()
                .map(|c| Box::pin(self.result_condition(c))),
        )
        .await;
        for r in future::join_all(fs).await.into_iter() {
            rows.retain(|v| r.contains(v));
        }
        rows
    }

    fn result_last_updated(&self, condition: &Number) -> RowSet {
        if let Some(ref f) = self.last_updated {
            match condition {
                Number::Min(min) => {
                    let min = *min as u64;
                    f.iter_from(&min).collect()
                }
                Number::Max(max) => {
                    let max = *max as u64;
                    f.iter_to(&max).collect()
                }
                Number::Range(range) => f
                    .iter_range(&(*range.start() as u64), &(*range.end() as u64))
                    .collect(),
                Number::In(rows) => rows.iter().flat_map(|i| f.iter_by(&(*i as u64))).collect(),
            }
        } else {
            RowSet::default()
        }
    }

    fn result_uuid(&self, uuids: &[u128]) -> RowSet {
        if let Some(ref index) = self.uuid {
            uuids.iter().flat_map(|uuid| index.iter_by(uuid)).collect()
        } else {
            RowSet::default()
        }
    }
    fn result_term(&self, condition: &Term) -> RowSet {
        match condition {
            Term::In(base) => {
                if let Some(ref term_begin) = self.term_begin {
                    if let Some(ref term_end) = self.term_end {
                        term_begin
                            .iter_to(base)
                            .filter(|row| {
                                let end = term_end.value(*row).unwrap_or(&0);
                                *end == 0 || end > base
                            })
                            .collect()
                    } else {
                        RowSet::default()
                    }
                } else {
                    RowSet::default()
                }
            }
            Term::Future(base) => {
                if let Some(ref index) = self.term_begin {
                    index.iter_from(base).collect()
                } else {
                    RowSet::default()
                }
            }
            Term::Past(base) => {
                if let Some(ref index) = self.term_end {
                    index.iter_range(&1, base).collect()
                } else {
                    RowSet::default()
                }
            }
        }
    }

    fn result_row(&self, condition: &Number) -> RowSet {
        let to_row = |i: isize| u32::try_from(i).ok().and_then(NonZeroU32::new);
        let exists = |row: &NonZeroU32| self.serial.node(*row).is_some();
        match condition {
            Number::Min(min) => self
                .serial
                .iter()
                .filter(|i| i.get() as isize >= *min)
                .collect(),
            Number::Max(max) => self
                .serial
                .iter()
                .filter(|i| i.get() as isize <= *max)
                .collect(),
            Number::Range(range) => {
                let start = (*range.start()).max(1);
                let end = (*range.end()).min(self.serial.rows_count() as isize);
                (start..=end).filter_map(to_row).filter(exists).collect()
            }
            Number::In(rows) => rows
                .iter()
                .filter_map(|i| to_row(*i))
                .filter(exists)
                .collect(),
        }
    }

    pub fn result_field(&self, name: &FieldName, condition: &Field) -> RowSet {
        if let Some(field) = self.fields.get(name) {
            match condition {
                Field::Match(v) => AvltrieeIter::by(field, v).collect(),
                Field::Min(min) => AvltrieeIter::from_asc(field, min).collect(),
                Field::Max(max) => AvltrieeIter::to_asc(field, max).collect(),
                Field::Range(min, max) => AvltrieeIter::range_asc(field, min, max).collect(),
                Field::Forward(cont) => Self::result_field_sub(field, cont, Self::forward),
                Field::Partial(cont) => Self::result_field_sub(field, cont, Self::partial),
                Field::Backward(cont) => Self::result_field_sub(field, cont, Self::backward),
                Field::ValueForward(cont) => {
                    Self::result_field_sub(field, cont, Self::value_forward)
                }
                Field::ValuePartial(cont) => {
                    Self::result_field_sub(field, cont, Self::value_partial)
                }
                Field::ValueBackward(cont) => {
                    Self::result_field_sub(field, cont, Self::value_backward)
                }
            }
        } else {
            RowSet::default()
        }
    }

    fn result_field_sub(
        field: &crate::Field,
        cont: &str,
        func: fn(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool),
    ) -> RowSet {
        field
            .as_ref()
            .iter()
            .map(|row| func(row, field, cont))
            .filter_map(|(v, b)| b.then_some(v))
            .collect()
    }

    fn forward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
        (
            row,
            field
                .value(row)
                .is_some_and(|bytes| bytes.starts_with(cont.as_bytes())),
        )
    }

    fn partial(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
        (
            row,
            field.value(row).is_some_and(|bytes| {
                let len = cont.len();
                len <= bytes.len() && {
                    let cont_bytes = cont.as_bytes();
                    bytes
                        .windows(len)
                        .position(|window| window == cont_bytes)
                        .is_some()
                }
            }),
        )
    }

    fn backward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
        (
            row,
            field
                .value(row)
                .is_some_and(|bytes| bytes.ends_with(cont.as_bytes())),
        )
    }

    fn value_forward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
        (
            row,
            field
                .value(row)
                .is_some_and(|bytes| cont.as_bytes().starts_with(bytes)),
        )
    }

    fn value_partial(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
        (
            row,
            field.value(row).is_some_and(|bytes| {
                cont.as_bytes()
                    .windows(bytes.len())
                    .position(|window| window == bytes)
                    .is_some()
            }),
        )
    }

    fn value_backward(row: NonZeroU32, field: &crate::Field, cont: &str) -> (NonZeroU32, bool) {
        (
            row,
            field
                .value(row)
                .is_some_and(|bytes| cont.as_bytes().ends_with(bytes)),
        )
    }
}