storage-kit 0.0.1

Portable database and transactional state-store Kit.
Documentation
use crate::{
    DenseVector, FilterExpr, NearestRequest, Projection, QueryResponse, ScoreKind, StorageError,
    StorageLocator, VectorCoercionPolicy, VectorSearchParams,
};

use super::super::{codec, mapper};
use super::{LanceManager, shared};

pub(super) async fn nearest(
    db: &LanceManager,
    request: NearestRequest,
) -> Result<QueryResponse, StorageError> {
    LanceVectorQuery {
        db,
        vector_column: db
            .default_vector_column(request.query.options.vector_field.as_ref())?
            .to_owned(),
        locator: request.query.scope.locator,
        seed: request.vector,
        filter: request.query.scope.filter,
        projection: request.query.scope.projection,
        params: request.query.options.params,
    }
    .execute()
    .await
}

struct LanceVectorQuery<'a> {
    db: &'a LanceManager,
    locator: StorageLocator,
    vector_column: String,
    seed: DenseVector,
    filter: Option<FilterExpr>,
    projection: Projection,
    params: VectorSearchParams,
}

impl LanceVectorQuery<'_> {
    async fn execute(self) -> Result<QueryResponse, StorageError> {
        use futures::TryStreamExt;
        use lancedb::query::ExecutableQuery;

        let table = self.db.table_ops(&self.locator).open().await?;
        let query = table
            .query()
            .nearest_to(self.seed.to_f32(VectorCoercionPolicy::Lossless)?)
            .map_err(|error| self.db.map_err("nearest_to", error))?
            .column(&self.vector_column);
        let schema = table
            .schema()
            .await
            .map_err(|error| self.db.map_err("schema", error))?;
        let filter_sql = mapper::LanceExpressions::new(schema).optional(self.filter.as_ref())?;
        let query = mapper::apply_vector_options(
            query,
            &self.params,
            filter_sql.as_deref(),
            &self.projection,
        )?;
        let batches = query
            .execute()
            .await
            .map_err(|error| self.db.map_err("nearest.execute", error))?
            .try_collect::<Vec<_>>()
            .await
            .map_err(|error| self.db.map_err("nearest.try_collect", error))?;
        let page = codec::decode_batches(&batches)?;
        Ok(shared::records_page_to_query_response(
            page,
            ScoreKind::Distance,
        ))
    }
}