indexlake 0.6.0

An experimental table format with extensible index support.
Documentation
use std::collections::HashMap;
use std::sync::Arc;

use uuid::Uuid;

use crate::expr::Expr;
use crate::index::{FilterSupport, IndexBuilder, IndexDefinitionRef, IndexKind};
use crate::{ILError, ILResult};

#[derive(Debug, Clone)]
pub struct IndexManager {
    indexes: Vec<IndexDefinitionRef>,
    kinds: HashMap<String, Arc<dyn IndexKind>>,
}

impl IndexManager {
    pub(crate) fn try_new(
        indexes: Vec<IndexDefinitionRef>,
        kinds: HashMap<String, Arc<dyn IndexKind>>,
    ) -> ILResult<Self> {
        for index_def in &indexes {
            if !kinds.contains_key(&index_def.kind) {
                return Err(ILError::invalid_input(format!(
                    "Index kind {} not registered",
                    index_def.kind
                )));
            }
        }
        Ok(Self { indexes, kinds })
    }

    pub(crate) fn get_index(&self, index_name: &str) -> Option<&IndexDefinitionRef> {
        self.indexes.iter().find(|index| index.name == index_name)
    }

    pub(crate) fn get_index_kind(&self, kind: &str) -> Option<&Arc<dyn IndexKind>> {
        self.kinds.get(kind)
    }

    pub(crate) fn index_ids(&self) -> Vec<Uuid> {
        self.indexes.iter().map(|index| index.index_id).collect()
    }

    pub(crate) fn any_index_contains_field(&self, field_id: &Uuid) -> bool {
        let field_id_str = hex::encode(field_id);
        self.indexes
            .iter()
            .any(|def| def.key_columns.contains(&field_id_str))
    }

    pub(crate) fn index_ids_by_field_ids(&self, field_ids: &[String]) -> Vec<Uuid> {
        self.indexes
            .iter()
            .filter(|index_def| {
                field_ids
                    .iter()
                    .any(|field_id| index_def.key_columns.contains(field_id))
            })
            .map(|index_def| index_def.index_id)
            .collect()
    }

    pub(crate) fn supports_filter(&self, filter: &Expr) -> ILResult<FilterSupport> {
        let mut supports = FilterSupport::Unsupported;
        for index_def in &self.indexes {
            let index_kind = self
                .kinds
                .get(&index_def.kind)
                .expect("Index kind not found");
            match index_kind.supports_filter(index_def, filter)? {
                FilterSupport::Exact => return Ok(FilterSupport::Exact),
                FilterSupport::Inexact => supports = FilterSupport::Inexact,
                FilterSupport::Unsupported => (),
            }
        }
        Ok(supports)
    }

    pub(crate) fn iter_index_and_kind(
        &self,
    ) -> impl Iterator<Item = (&IndexDefinitionRef, &Arc<dyn IndexKind>)> {
        self.indexes.iter().map(|index_def| {
            let index_kind = self
                .kinds
                .get(&index_def.kind)
                .expect("Index kind not found");
            (index_def, index_kind)
        })
    }

    pub(crate) fn new_index_builders(
        &self,
        index_ids: Option<&[Uuid]>,
    ) -> ILResult<Vec<Box<dyn IndexBuilder>>> {
        self.indexes
            .iter()
            .filter(|index_def| index_ids.is_none_or(|ids| ids.contains(&index_def.index_id)))
            .map(|index_def| {
                let index_kind = self.kinds.get(&index_def.kind).ok_or_else(|| {
                    ILError::internal(format!("Index kind {} not found", index_def.kind))
                })?;
                index_kind.builder(index_def)
            })
            .collect()
    }

    pub(crate) fn new_index_builder(&self, index_id: &Uuid) -> ILResult<Box<dyn IndexBuilder>> {
        let index_def = self
            .indexes
            .iter()
            .find(|def| &def.index_id == index_id)
            .ok_or_else(|| ILError::internal(format!("Index {index_id} not found")))?;
        let index_kind = self
            .kinds
            .get(&index_def.kind)
            .ok_or_else(|| ILError::internal(format!("Index kind {} not found", index_def.kind)))?;
        index_kind.builder(index_def)
    }

    pub(crate) fn inline_index_segment_row_count(
        &self,
        index_def: &IndexDefinitionRef,
    ) -> ILResult<usize> {
        let index_kind = self
            .kinds
            .get(&index_def.kind)
            .ok_or_else(|| ILError::internal(format!("Index kind {} not found", index_def.kind)))?;
        Ok(index_def.inline_index_segment_row_count(index_kind.as_ref()))
    }
}