spiral-sdk 0.1.10

Rust SDK for Spiral resource and table APIs
Documentation
//! Locations resolved on a branch, and the Tasks that refresh their inventories.

use uuid::Uuid;

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

const LOCATION_KIND: &str = "location";

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

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

impl Snapshot {
    /// Resolve the Location at `path` in this snapshot.
    pub async fn location(&self, path: &str) -> Result<Location, Error> {
        let address = path.parse::<ResourceAddress>()?;
        if address.reference().is_some() {
            return Err(Error::invalid(
                "select the Location's branch with the snapshot, not an `@` reference",
            ));
        }
        let resource = self.resource_at_path(address.path()).await?;
        if resource.descriptor.kind.0 != LOCATION_KIND {
            return Err(Error::invalid(format!("`{path}` is not a Location")));
        }
        Ok(Location {
            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 Location {
    /// The Location's stable resource identifier.
    pub fn resource_id(&self) -> Uuid {
        self.resource_id
    }

    /// The exact Location version this handle resolved.
    pub fn version_id(&self) -> Uuid {
        self.version_id
    }

    /// Submit a refresh of the latest Location version on this snapshot's branch.
    ///
    /// The refresh lists the root, reconciles the inventory, and publishes the inventory
    /// and a new Location version in one commit. Its result lists the new Location
    /// version, preceded by the inventory version when the listing changed it. Returns
    /// `None` when a refresh of this Location and branch is already waiting to run; that
    /// refresh covers this request.
    pub async fn refresh(&self, run: Run) -> Result<Option<TaskHandle>, Error> {
        let branch_id = self.branch_id.ok_or_else(|| {
            Error::invalid("refreshing a Location needs a branch snapshot, not an exact commit")
        })?;
        let definition = TaskDefinition::LocationRefresh(LocationRefreshDefinition {
            read_target: TaskReadTarget::LatestOnBranch(TaskReadTargetLatestOnBranch {
                branch_id: branch_id.as_uuid(),
            }),
            location_resource_id: self.resource_id,
        });
        self.project.submit_task(definition, None, run).await
    }
}