spiral-sdk 0.1.10

Rust SDK for Spiral resource and table APIs
Documentation
//! Vector Indexes resolved on a branch, and the Tasks that refresh them.

use uuid::Uuid;

use crate::api::tasks::{
    TaskDefinition, TaskReadTarget, TaskReadTargetLatestOnBranch, VectorIndexBuildMode,
    VectorIndexRefreshDefinition,
};
use crate::catalog_types::ProjectBranchId;
use crate::{Error, Project, ResourceAddress, Run, Snapshot, TaskHandle};

const VECTOR_INDEX_KIND: &str = "vector-index";

/// One Vector Index at the commit a [`Snapshot`] selects.
#[derive(Clone)]
pub struct VectorIndex {
    project: Project,
    branch_id: Option<ProjectBranchId>,
    resource_id: Uuid,
    version_id: Uuid,
}

impl Project {
    /// Pin the head of `branch` and resolve the Vector Index at `path`.
    pub async fn vector_index(&self, branch: &str, path: &str) -> Result<VectorIndex, Error> {
        self.branch(branch)
            .await?
            .snapshot()
            .vector_index(path)
            .await
    }
}

impl Snapshot {
    /// Resolve the Vector Index at `path` in this snapshot.
    pub async fn vector_index(&self, path: &str) -> Result<VectorIndex, Error> {
        let address = path.parse::<ResourceAddress>()?;
        if address.reference().is_some() {
            return Err(Error::invalid(
                "select the Vector Index's branch with the snapshot, not an `@` reference",
            ));
        }
        let resource = self.resource_at_path(address.path()).await?;
        if resource.descriptor.kind.0 != VECTOR_INDEX_KIND {
            return Err(Error::invalid(format!("`{path}` is not a Vector Index")));
        }
        Ok(VectorIndex {
            project: self.project.clone(),
            branch_id: self.branch_id,
            resource_id: resource.descriptor.resource_id.as_uuid(),
            version_id: resource.version_id.as_uuid(),
        })
    }
}

impl VectorIndex {
    /// The Vector Index's stable resource identifier.
    pub fn resource_id(&self) -> Uuid {
        self.resource_id
    }

    /// The exact version this snapshot binds.
    pub fn version_id(&self) -> Uuid {
        self.version_id
    }

    /// Submit a build of the index's successor from the latest source Table on this
    /// snapshot's branch.
    ///
    /// Its result lists the new Vector Index version. Returns `None` when a refresh of this
    /// index and branch is already waiting to run.
    pub async fn refresh(
        &self,
        mode: VectorIndexBuildMode,
        run: Run,
    ) -> Result<Option<TaskHandle>, Error> {
        let branch_id = self.branch_id.ok_or_else(|| {
            Error::invalid("refreshing a Vector Index needs a branch snapshot, not an exact commit")
        })?;
        let read = self
            .project
            .client
            .vector_indexes()
            .read_version(self.resource_id, self.version_id)
            .await?;
        let source_resource_id =
            read.definition
                .source_resource_id
                .parse::<Uuid>()
                .map_err(|_| {
                    Error::Protocol("the Vector Index's source is not a resource ID".into())
                })?;
        let definition = TaskDefinition::VectorIndexRefresh(VectorIndexRefreshDefinition {
            read_target: TaskReadTarget::LatestOnBranch(TaskReadTargetLatestOnBranch {
                branch_id: branch_id.as_uuid(),
            }),
            vector_index_id: self.resource_id,
            vector_index_resource_id: self.resource_id,
            source_resource_id,
            mode,
            latest: None,
        });
        self.project.submit_task(definition, None, run).await
    }
}