diff --git a/radicle/src/cob/op.rs b/radicle/src/cob/op.rs index c958065d..db34e53b 100644 --- a/radicle/src/cob/op.rs +++ b/radicle/src/cob/op.rs @@ -3,6 +3,7 @@ use radicle_cob::Manifest; use serde::Serialize; use thiserror::Error; +use radicle_cob as cob; use radicle_cob::history::{Entry, EntryId}; use radicle_crypto::PublicKey; @@ -23,6 +24,23 @@ pub enum OpEncodingError { Git(#[from] git2::Error), } +/// Error loading an `Op` from storage. +#[derive(Error, Debug)] +pub enum LoadError { + #[error("failed to load Op at '{object}': {err}")] + Load { + object: git::Oid, + #[source] + err: Box, + }, + #[error("failed to decode Op at '{object}': {err}")] + Encoding { + object: git::Oid, + #[source] + err: OpEncodingError, + }, +} + /// The `Op` is the operation that is applied onto a state to form a CRDT. /// /// Everything that can be done in the system is represented by an `Op`. @@ -93,6 +111,23 @@ impl Op { Some(head) => repo.identity_doc_at(head).map(Some), } } + + /// Get the `Op` identified by the `id` in the provided `store`. + pub fn load(store: &S, id: git::Oid) -> Result + where + S: cob::change::Storage< + ObjectId = git::Oid, + Parent = git::Oid, + Signatures = crypto::ssh::ExtendedSignature, + >, + for<'de> A: serde::Deserialize<'de>, + { + let entry = store.load(id).map_err(|err| LoadError::Load { + object: id, + err: Box::new(err), + })?; + Op::try_from(&entry).map_err(|err| LoadError::Encoding { object: id, err }) + } } impl From for Op> {