cob: Parametrize `cob::Store` with repository type
The additional flexibility in choosing a backend for the COB store will allow things like "draft" COBs that are stored in a different location, without changing much of the logic.
This commit is contained in:
parent
45ccbde226
commit
c9162121b0
|
|
@ -14,7 +14,7 @@ use radicle::node::{AliasStore, Handle};
|
||||||
use radicle::prelude::Did;
|
use radicle::prelude::Did;
|
||||||
use radicle::profile;
|
use radicle::profile;
|
||||||
use radicle::storage;
|
use radicle::storage;
|
||||||
use radicle::storage::WriteStorage;
|
use radicle::storage::{WriteRepository, WriteStorage};
|
||||||
use radicle::{cob, Node};
|
use radicle::{cob, Node};
|
||||||
use radicle_term::table::TableOptions;
|
use radicle_term::table::TableOptions;
|
||||||
use radicle_term::{Paint, Table, VStack};
|
use radicle_term::{Paint, Table, VStack};
|
||||||
|
|
@ -359,8 +359,8 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(
|
fn list<R: WriteRepository + cob::Store>(
|
||||||
issues: &Issues,
|
issues: &Issues<R>,
|
||||||
assigned: &Option<Assigned>,
|
assigned: &Option<Assigned>,
|
||||||
state: &Option<State>,
|
state: &Option<State>,
|
||||||
profile: &profile::Profile,
|
profile: &profile::Profile,
|
||||||
|
|
@ -544,12 +544,12 @@ fn prompt_issue(
|
||||||
Ok(Some((meta, description)))
|
Ok(Some((meta, description)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open<G: Signer>(
|
fn open<R: WriteRepository + cob::Store, G: Signer>(
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
tags: Vec<Tag>,
|
tags: Vec<Tag>,
|
||||||
options: &Options,
|
options: &Options,
|
||||||
issues: &mut Issues,
|
issues: &mut Issues<R>,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let Some((meta, description)) = prompt_issue(
|
let Some((meta, description)) = prompt_issue(
|
||||||
|
|
@ -579,8 +579,8 @@ fn open<G: Signer>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit<G: radicle::crypto::Signer>(
|
fn edit<R: WriteRepository + cob::Store, G: radicle::crypto::Signer>(
|
||||||
issues: &mut issue::Issues,
|
issues: &mut issue::Issues<R>,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
repo: &storage::git::Repository,
|
repo: &storage::git::Repository,
|
||||||
id: Rev,
|
id: Rev,
|
||||||
|
|
|
||||||
|
|
@ -116,9 +116,9 @@ mod tests;
|
||||||
/// [`git2::Repository`]. It is expected that the underlying storage
|
/// [`git2::Repository`]. It is expected that the underlying storage
|
||||||
/// for `object::Storage` will also be `git2::Repository`, but if not
|
/// for `object::Storage` will also be `git2::Repository`, but if not
|
||||||
/// please open an issue to change the definition of `Store` :)
|
/// please open an issue to change the definition of `Store` :)
|
||||||
pub trait Store
|
pub trait Store<I = crypto::PublicKey>
|
||||||
where
|
where
|
||||||
Self: object::Storage
|
Self: object::Storage<Identifier = I>
|
||||||
+ change::Storage<
|
+ change::Storage<
|
||||||
StoreError = git::change::error::Create,
|
StoreError = git::change::error::Create,
|
||||||
LoadError = git::change::error::Load,
|
LoadError = git::change::error::Load,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ impl Create {
|
||||||
///
|
///
|
||||||
/// The `args` are the metadata for this [`CollaborativeObject`]. See
|
/// The `args` are the metadata for this [`CollaborativeObject`]. See
|
||||||
/// [`Create`] for further information.
|
/// [`Create`] for further information.
|
||||||
pub fn create<S, G>(
|
pub fn create<S, I, G>(
|
||||||
storage: &S,
|
storage: &S,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
resource: Oid,
|
resource: Oid,
|
||||||
|
|
@ -57,7 +57,7 @@ pub fn create<S, G>(
|
||||||
args: Create,
|
args: Create,
|
||||||
) -> Result<CollaborativeObject, error::Create>
|
) -> Result<CollaborativeObject, error::Create>
|
||||||
where
|
where
|
||||||
S: Store,
|
S: Store<I>,
|
||||||
G: crypto::Signer,
|
G: crypto::Signer,
|
||||||
{
|
{
|
||||||
let Create { ref typename, .. } = &args;
|
let Create { ref typename, .. } = &args;
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ use super::error;
|
||||||
/// The `typename` is the type of object to be found, while the
|
/// The `typename` is the type of object to be found, while the
|
||||||
/// `object_id` is the identifier for the particular object under that
|
/// `object_id` is the identifier for the particular object under that
|
||||||
/// type.
|
/// type.
|
||||||
pub fn get<S>(
|
pub fn get<S, I>(
|
||||||
storage: &S,
|
storage: &S,
|
||||||
typename: &TypeName,
|
typename: &TypeName,
|
||||||
oid: &ObjectId,
|
oid: &ObjectId,
|
||||||
) -> Result<Option<CollaborativeObject>, error::Retrieve>
|
) -> Result<Option<CollaborativeObject>, error::Retrieve>
|
||||||
where
|
where
|
||||||
S: Store,
|
S: Store<I>,
|
||||||
{
|
{
|
||||||
let tip_refs = storage
|
let tip_refs = storage
|
||||||
.objects(typename, oid)
|
.objects(typename, oid)
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@ use super::error;
|
||||||
/// [`Store`] for further information.
|
/// [`Store`] for further information.
|
||||||
///
|
///
|
||||||
/// The `typename` is the type of objects to be listed.
|
/// The `typename` is the type of objects to be listed.
|
||||||
pub fn list<S>(
|
pub fn list<S, I>(
|
||||||
storage: &S,
|
storage: &S,
|
||||||
typename: &TypeName,
|
typename: &TypeName,
|
||||||
) -> Result<Vec<CollaborativeObject>, error::Retrieve>
|
) -> Result<Vec<CollaborativeObject>, error::Retrieve>
|
||||||
where
|
where
|
||||||
S: Store,
|
S: Store<I>,
|
||||||
{
|
{
|
||||||
let references = storage
|
let references = storage
|
||||||
.types(typename)
|
.types(typename)
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ use super::error;
|
||||||
/// The `typename` is the type of object to be found, while the
|
/// The `typename` is the type of object to be found, while the
|
||||||
/// `object_id` is the identifier for the particular object under that
|
/// `object_id` is the identifier for the particular object under that
|
||||||
/// type.
|
/// type.
|
||||||
pub fn remove<S>(
|
pub fn remove<S, I>(
|
||||||
storage: &S,
|
storage: &S,
|
||||||
identifier: &S::Identifier,
|
identifier: &S::Identifier,
|
||||||
typename: &TypeName,
|
typename: &TypeName,
|
||||||
oid: &ObjectId,
|
oid: &ObjectId,
|
||||||
) -> Result<(), error::Remove>
|
) -> Result<(), error::Remove>
|
||||||
where
|
where
|
||||||
S: Store,
|
S: Store<I>,
|
||||||
{
|
{
|
||||||
storage
|
storage
|
||||||
.remove(identifier, typename, oid)
|
.remove(identifier, typename, oid)
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ pub struct Update {
|
||||||
///
|
///
|
||||||
/// The `args` are the metadata for this [`CollaborativeObject`]
|
/// The `args` are the metadata for this [`CollaborativeObject`]
|
||||||
/// udpate. See [`Update`] for further information.
|
/// udpate. See [`Update`] for further information.
|
||||||
pub fn update<S, G>(
|
pub fn update<S, I, G>(
|
||||||
storage: &S,
|
storage: &S,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
resource: Oid,
|
resource: Oid,
|
||||||
|
|
@ -58,7 +58,7 @@ pub fn update<S, G>(
|
||||||
args: Update,
|
args: Update,
|
||||||
) -> Result<Updated, error::Update>
|
) -> Result<Updated, error::Update>
|
||||||
where
|
where
|
||||||
S: Store,
|
S: Store<I>,
|
||||||
G: crypto::Signer,
|
G: crypto::Signer,
|
||||||
{
|
{
|
||||||
let Update {
|
let Update {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use crate::{ObjectId, TypeName};
|
||||||
|
|
||||||
/// The [`Reference`]s that refer to the commits that make up a
|
/// The [`Reference`]s that refer to the commits that make up a
|
||||||
/// [`crate::CollaborativeObject`].
|
/// [`crate::CollaborativeObject`].
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Objects(Vec<Reference>);
|
pub struct Objects(Vec<Reference>);
|
||||||
|
|
||||||
impl Objects {
|
impl Objects {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl Storage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Store for Storage {}
|
impl Store<Urn> for Storage {}
|
||||||
|
|
||||||
impl change::Storage for Storage {
|
impl change::Storage for Storage {
|
||||||
type StoreError = <git2::Repository as change::Storage>::StoreError;
|
type StoreError = <git2::Repository as change::Storage>::StoreError;
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ pub mod thread;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test;
|
pub mod test;
|
||||||
|
|
||||||
pub use cob::{create, get, list, remove, update};
|
|
||||||
pub use cob::{
|
pub use cob::{
|
||||||
history::EntryId, object::collaboration::error, CollaborativeObject, Contents, Create, Entry,
|
change, history::EntryId, object, object::collaboration::error, CollaborativeObject, Contents,
|
||||||
History, ObjectId, TypeName, Update, Updated,
|
Create, Entry, History, ObjectId, Store, TypeName, Update, Updated,
|
||||||
};
|
};
|
||||||
|
pub use cob::{create, get, list, remove, update};
|
||||||
pub use common::*;
|
pub use common::*;
|
||||||
pub use op::{ActorId, Op};
|
pub use op::{ActorId, Op};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
identity::{doc::DocError, Did, Identity, IdentityError},
|
identity::{doc::DocError, Did, Identity, IdentityError},
|
||||||
prelude::{Doc, ReadRepository},
|
prelude::{Doc, ReadRepository},
|
||||||
storage::{git as storage, RemoteId, WriteRepository},
|
storage::{RemoteId, WriteRepository},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
|
@ -561,20 +561,23 @@ impl store::Transaction<Proposal> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProposalMut<'a, 'g> {
|
pub struct ProposalMut<'a, 'g, R> {
|
||||||
pub id: ObjectId,
|
pub id: ObjectId,
|
||||||
|
|
||||||
proposal: Proposal,
|
proposal: Proposal,
|
||||||
clock: clock::Lamport,
|
clock: clock::Lamport,
|
||||||
store: &'g mut Proposals<'a>,
|
store: &'g mut Proposals<'a, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'g> ProposalMut<'a, 'g> {
|
impl<'a, 'g, R> ProposalMut<'a, 'g, R>
|
||||||
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
proposal: Proposal,
|
proposal: Proposal,
|
||||||
clock: clock::Lamport,
|
clock: clock::Lamport,
|
||||||
store: &'g mut Proposals<'a>,
|
store: &'g mut Proposals<'a, R>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
|
@ -672,7 +675,7 @@ impl<'a, 'g> ProposalMut<'a, 'g> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'g> Deref for ProposalMut<'a, 'g> {
|
impl<'a, 'g, R> Deref for ProposalMut<'a, 'g, R> {
|
||||||
type Target = Proposal;
|
type Target = Proposal;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
@ -680,21 +683,24 @@ impl<'a, 'g> Deref for ProposalMut<'a, 'g> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Proposals<'a> {
|
pub struct Proposals<'a, R> {
|
||||||
raw: store::Store<'a, Proposal>,
|
raw: store::Store<'a, Proposal, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for Proposals<'a> {
|
impl<'a, R> Deref for Proposals<'a, R> {
|
||||||
type Target = store::Store<'a, Proposal>;
|
type Target = store::Store<'a, Proposal, R>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.raw
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Proposals<'a> {
|
impl<'a, R: WriteRepository> Proposals<'a, R>
|
||||||
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
|
{
|
||||||
/// Open a proposals store.
|
/// Open a proposals store.
|
||||||
pub fn open(repository: &'a storage::Repository) -> Result<Self, store::Error> {
|
pub fn open(repository: &'a R) -> Result<Self, store::Error> {
|
||||||
let raw = store::Store::open(repository)?;
|
let raw = store::Store::open(repository)?;
|
||||||
|
|
||||||
Ok(Self { raw })
|
Ok(Self { raw })
|
||||||
|
|
@ -708,7 +714,7 @@ impl<'a> Proposals<'a> {
|
||||||
current: impl Into<Oid>,
|
current: impl Into<Oid>,
|
||||||
proposed: Doc<Verified>,
|
proposed: Doc<Verified>,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> Result<ProposalMut<'a, 'g>, Error> {
|
) -> Result<ProposalMut<'a, 'g, R>, Error> {
|
||||||
let (id, proposal, clock) =
|
let (id, proposal, clock) =
|
||||||
Transaction::initial("Create proposal", &mut self.raw, signer, |tx| {
|
Transaction::initial("Create proposal", &mut self.raw, signer, |tx| {
|
||||||
tx.revision(current.into(), proposed)?;
|
tx.revision(current.into(), proposed)?;
|
||||||
|
|
@ -728,7 +734,10 @@ impl<'a> Proposals<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a proposal mutably.
|
/// Get a proposal mutably.
|
||||||
pub fn get_mut<'g>(&'g mut self, id: &ObjectId) -> Result<ProposalMut<'a, 'g>, store::Error> {
|
pub fn get_mut<'g>(
|
||||||
|
&'g mut self,
|
||||||
|
id: &ObjectId,
|
||||||
|
) -> Result<ProposalMut<'a, 'g, R>, store::Error> {
|
||||||
let (proposal, clock) = self
|
let (proposal, clock) = self
|
||||||
.raw
|
.raw
|
||||||
.get(id)?
|
.get(id)?
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ use crate::cob::thread::{CommentId, Thread};
|
||||||
use crate::cob::{store, ActorId, EntryId, ObjectId, TypeName};
|
use crate::cob::{store, ActorId, EntryId, ObjectId, TypeName};
|
||||||
use crate::crypto::Signer;
|
use crate::crypto::Signer;
|
||||||
use crate::prelude::{Did, ReadRepository};
|
use crate::prelude::{Did, ReadRepository};
|
||||||
use crate::storage::git as storage;
|
use crate::storage::WriteRepository;
|
||||||
|
|
||||||
/// Issue operation.
|
/// Issue operation.
|
||||||
pub type Op = cob::Op<Action>;
|
pub type Op = cob::Op<Action>;
|
||||||
|
|
@ -331,14 +331,17 @@ impl store::Transaction<Issue> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IssueMut<'a, 'g> {
|
pub struct IssueMut<'a, 'g, R> {
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
clock: clock::Lamport,
|
clock: clock::Lamport,
|
||||||
issue: Issue,
|
issue: Issue,
|
||||||
store: &'g mut Issues<'a>,
|
store: &'g mut Issues<'a, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'g> IssueMut<'a, 'g> {
|
impl<'a, 'g, R> IssueMut<'a, 'g, R>
|
||||||
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
|
{
|
||||||
/// Get the issue id.
|
/// Get the issue id.
|
||||||
pub fn id(&self) -> &ObjectId {
|
pub fn id(&self) -> &ObjectId {
|
||||||
&self.id
|
&self.id
|
||||||
|
|
@ -457,7 +460,7 @@ impl<'a, 'g> IssueMut<'a, 'g> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'g> Deref for IssueMut<'a, 'g> {
|
impl<'a, 'g, R> Deref for IssueMut<'a, 'g, R> {
|
||||||
type Target = Issue;
|
type Target = Issue;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
@ -465,12 +468,12 @@ impl<'a, 'g> Deref for IssueMut<'a, 'g> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Issues<'a> {
|
pub struct Issues<'a, R> {
|
||||||
raw: store::Store<'a, Issue>,
|
raw: store::Store<'a, Issue, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for Issues<'a> {
|
impl<'a, R> Deref for Issues<'a, R> {
|
||||||
type Target = store::Store<'a, Issue>;
|
type Target = store::Store<'a, Issue, R>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.raw
|
&self.raw
|
||||||
|
|
@ -485,9 +488,12 @@ pub struct IssueCounts {
|
||||||
pub closed: usize,
|
pub closed: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Issues<'a> {
|
impl<'a, R: WriteRepository> Issues<'a, R>
|
||||||
|
where
|
||||||
|
R: ReadRepository + cob::Store,
|
||||||
|
{
|
||||||
/// Open an issues store.
|
/// Open an issues store.
|
||||||
pub fn open(repository: &'a storage::Repository) -> Result<Self, store::Error> {
|
pub fn open(repository: &'a R) -> Result<Self, store::Error> {
|
||||||
let raw = store::Store::open(repository)?;
|
let raw = store::Store::open(repository)?;
|
||||||
|
|
||||||
Ok(Self { raw })
|
Ok(Self { raw })
|
||||||
|
|
@ -499,7 +505,7 @@ impl<'a> Issues<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an issue mutably.
|
/// Get an issue mutably.
|
||||||
pub fn get_mut<'g>(&'g mut self, id: &ObjectId) -> Result<IssueMut<'a, 'g>, store::Error> {
|
pub fn get_mut<'g>(&'g mut self, id: &ObjectId) -> Result<IssueMut<'a, 'g, R>, store::Error> {
|
||||||
let (issue, clock) = self
|
let (issue, clock) = self
|
||||||
.raw
|
.raw
|
||||||
.get(id)?
|
.get(id)?
|
||||||
|
|
@ -521,7 +527,7 @@ impl<'a> Issues<'a> {
|
||||||
tags: &[Tag],
|
tags: &[Tag],
|
||||||
assignees: &[ActorId],
|
assignees: &[ActorId],
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> Result<IssueMut<'a, 'g>, Error> {
|
) -> Result<IssueMut<'a, 'g, R>, Error> {
|
||||||
let (id, issue, clock) =
|
let (id, issue, clock) =
|
||||||
Transaction::initial("Create issue", &mut self.raw, signer, |tx| {
|
Transaction::initial("Create issue", &mut self.raw, signer, |tx| {
|
||||||
tx.thread(description)?;
|
tx.thread(description)?;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ use crate::identity;
|
||||||
use crate::identity::doc::DocError;
|
use crate::identity::doc::DocError;
|
||||||
use crate::identity::PayloadError;
|
use crate::identity::PayloadError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::storage::git as storage;
|
|
||||||
|
|
||||||
/// The logical clock we use to order operations to patches.
|
/// The logical clock we use to order operations to patches.
|
||||||
pub use clock::Lamport as Clock;
|
pub use clock::Lamport as Clock;
|
||||||
|
|
@ -1143,20 +1142,23 @@ impl store::Transaction<Patch> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PatchMut<'a, 'g> {
|
pub struct PatchMut<'a, 'g, R> {
|
||||||
pub id: ObjectId,
|
pub id: ObjectId,
|
||||||
|
|
||||||
patch: Patch,
|
patch: Patch,
|
||||||
clock: clock::Lamport,
|
clock: clock::Lamport,
|
||||||
store: &'g mut Patches<'a>,
|
store: &'g mut Patches<'a, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'g> PatchMut<'a, 'g> {
|
impl<'a, 'g, R> PatchMut<'a, 'g, R>
|
||||||
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
patch: Patch,
|
patch: Patch,
|
||||||
clock: clock::Lamport,
|
clock: clock::Lamport,
|
||||||
store: &'g mut Patches<'a>,
|
store: &'g mut Patches<'a, R>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
|
|
@ -1358,7 +1360,7 @@ impl<'a, 'g> PatchMut<'a, 'g> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'g> Deref for PatchMut<'a, 'g> {
|
impl<'a, 'g, R> Deref for PatchMut<'a, 'g, R> {
|
||||||
type Target = Patch;
|
type Target = Patch;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
@ -1376,21 +1378,24 @@ pub struct PatchCounts {
|
||||||
pub merged: usize,
|
pub merged: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Patches<'a> {
|
pub struct Patches<'a, R> {
|
||||||
raw: store::Store<'a, Patch>,
|
raw: store::Store<'a, Patch, R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for Patches<'a> {
|
impl<'a, R> Deref for Patches<'a, R> {
|
||||||
type Target = store::Store<'a, Patch>;
|
type Target = store::Store<'a, Patch, R>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.raw
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Patches<'a> {
|
impl<'a, R> Patches<'a, R>
|
||||||
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
|
{
|
||||||
/// Open an patches store.
|
/// Open an patches store.
|
||||||
pub fn open(repository: &'a storage::Repository) -> Result<Self, store::Error> {
|
pub fn open(repository: &'a R) -> Result<Self, store::Error> {
|
||||||
let raw = store::Store::open(repository)?;
|
let raw = store::Store::open(repository)?;
|
||||||
|
|
||||||
Ok(Self { raw })
|
Ok(Self { raw })
|
||||||
|
|
@ -1406,7 +1411,7 @@ impl<'a> Patches<'a> {
|
||||||
oid: impl Into<git::Oid>,
|
oid: impl Into<git::Oid>,
|
||||||
tags: &[Tag],
|
tags: &[Tag],
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> Result<PatchMut<'a, 'g>, Error> {
|
) -> Result<PatchMut<'a, 'g, R>, Error> {
|
||||||
self._create(
|
self._create(
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
|
@ -1429,7 +1434,7 @@ impl<'a> Patches<'a> {
|
||||||
oid: impl Into<git::Oid>,
|
oid: impl Into<git::Oid>,
|
||||||
tags: &[Tag],
|
tags: &[Tag],
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> Result<PatchMut<'a, 'g>, Error> {
|
) -> Result<PatchMut<'a, 'g, R>, Error> {
|
||||||
self._create(
|
self._create(
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
|
@ -1484,7 +1489,7 @@ impl<'a> Patches<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a patch mutably.
|
/// Get a patch mutably.
|
||||||
pub fn get_mut<'g>(&'g mut self, id: &ObjectId) -> Result<PatchMut<'a, 'g>, store::Error> {
|
pub fn get_mut<'g>(&'g mut self, id: &ObjectId) -> Result<PatchMut<'a, 'g, R>, store::Error> {
|
||||||
let (patch, clock) = self
|
let (patch, clock) = self
|
||||||
.raw
|
.raw
|
||||||
.get(id)?
|
.get(id)?
|
||||||
|
|
@ -1531,7 +1536,7 @@ impl<'a> Patches<'a> {
|
||||||
tags: &[Tag],
|
tags: &[Tag],
|
||||||
state: State,
|
state: State,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> Result<PatchMut<'a, 'g>, Error> {
|
) -> Result<PatchMut<'a, 'g, R>, Error> {
|
||||||
let (id, patch, clock) =
|
let (id, patch, clock) =
|
||||||
Transaction::initial("Create patch", &mut self.raw, signer, |tx| {
|
Transaction::initial("Create patch", &mut self.raw, signer, |tx| {
|
||||||
tx.revision(description, base, oid)?;
|
tx.revision(description, base, oid)?;
|
||||||
|
|
|
||||||
|
|
@ -128,21 +128,21 @@ impl Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Storage for collaborative objects of a specific type `T` in a single repository.
|
/// Storage for collaborative objects of a specific type `T` in a single repository.
|
||||||
pub struct Store<'a, T> {
|
pub struct Store<'a, T, R> {
|
||||||
identity: git::Oid,
|
identity: git::Oid,
|
||||||
repo: &'a storage::Repository,
|
repo: &'a R,
|
||||||
witness: PhantomData<T>,
|
witness: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> AsRef<storage::Repository> for Store<'a, T> {
|
impl<'a, T, R> AsRef<R> for Store<'a, T, R> {
|
||||||
fn as_ref(&self) -> &storage::Repository {
|
fn as_ref(&self) -> &R {
|
||||||
self.repo
|
self.repo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Store<'a, T> {
|
impl<'a, T, R: ReadRepository> Store<'a, T, R> {
|
||||||
/// Open a new generic store.
|
/// Open a new generic store.
|
||||||
pub fn open(repo: &'a storage::Repository) -> Result<Self, Error> {
|
pub fn open(repo: &'a R) -> Result<Self, Error> {
|
||||||
let identity = repo.identity()?;
|
let identity = repo.identity()?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
@ -153,8 +153,10 @@ impl<'a, T> Store<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: FromHistory> Store<'a, T>
|
impl<'a, T, R> Store<'a, T, R>
|
||||||
where
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
|
T: FromHistory,
|
||||||
T::Action: Serialize,
|
T::Action: Serialize,
|
||||||
{
|
{
|
||||||
/// Update an object.
|
/// Update an object.
|
||||||
|
|
@ -299,15 +301,16 @@ impl<T: FromHistory> Transaction<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new transaction to be used as the initial set of operations for a COB.
|
/// Create a new transaction to be used as the initial set of operations for a COB.
|
||||||
pub fn initial<G, F>(
|
pub fn initial<R, G, F>(
|
||||||
message: &str,
|
message: &str,
|
||||||
store: &mut Store<T>,
|
store: &mut Store<T, R>,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
operations: F,
|
operations: F,
|
||||||
) -> Result<(ObjectId, T, Lamport), Error>
|
) -> Result<(ObjectId, T, Lamport), Error>
|
||||||
where
|
where
|
||||||
G: Signer,
|
G: Signer,
|
||||||
F: FnOnce(&mut Self) -> Result<(), Error>,
|
F: FnOnce(&mut Self) -> Result<(), Error>,
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
T::Action: Serialize + Clone,
|
T::Action: Serialize + Clone,
|
||||||
{
|
{
|
||||||
let actor = *signer.public_key();
|
let actor = *signer.public_key();
|
||||||
|
|
@ -339,14 +342,15 @@ impl<T: FromHistory> Transaction<T> {
|
||||||
/// Commit transaction.
|
/// Commit transaction.
|
||||||
///
|
///
|
||||||
/// Returns a list of operations that can be applied onto an in-memory CRDT.
|
/// Returns a list of operations that can be applied onto an in-memory CRDT.
|
||||||
pub fn commit<G: Signer>(
|
pub fn commit<R, G: Signer>(
|
||||||
mut self,
|
mut self,
|
||||||
msg: &str,
|
msg: &str,
|
||||||
id: ObjectId,
|
id: ObjectId,
|
||||||
store: &mut Store<T>,
|
store: &mut Store<T, R>,
|
||||||
signer: &G,
|
signer: &G,
|
||||||
) -> Result<(Vec<cob::Op<T::Action>>, Lamport, EntryId), Error>
|
) -> Result<(Vec<cob::Op<T::Action>>, Lamport, EntryId), Error>
|
||||||
where
|
where
|
||||||
|
R: WriteRepository + cob::Store,
|
||||||
T::Action: Serialize + Clone,
|
T::Action: Serialize + Clone,
|
||||||
{
|
{
|
||||||
let actions = NonEmpty::from_vec(self.actions)
|
let actions = NonEmpty::from_vec(self.actions)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use crate::git::{refspec::Refspec, PatternString, Qualified, RefError, RefString
|
||||||
use crate::identity;
|
use crate::identity;
|
||||||
use crate::identity::doc::DocError;
|
use crate::identity::doc::DocError;
|
||||||
use crate::identity::Did;
|
use crate::identity::Did;
|
||||||
use crate::identity::{Id, IdentityError};
|
use crate::identity::{Id, Identity, IdentityError};
|
||||||
use crate::storage::git::NAMESPACES_GLOB;
|
use crate::storage::git::NAMESPACES_GLOB;
|
||||||
use crate::storage::refs::Refs;
|
use crate::storage::refs::Refs;
|
||||||
|
|
||||||
|
|
@ -319,7 +319,7 @@ pub trait WriteStorage: ReadStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows read-only access to a repository.
|
/// Allows read-only access to a repository.
|
||||||
pub trait ReadRepository {
|
pub trait ReadRepository: Sized {
|
||||||
/// Return the repository id.
|
/// Return the repository id.
|
||||||
fn id(&self) -> Id;
|
fn id(&self) -> Id;
|
||||||
|
|
||||||
|
|
@ -368,6 +368,13 @@ pub trait ReadRepository {
|
||||||
/// `rad/id` using [`ReadRepository::canonical_identity_head`].
|
/// `rad/id` using [`ReadRepository::canonical_identity_head`].
|
||||||
fn identity_head(&self) -> Result<Oid, IdentityError>;
|
fn identity_head(&self) -> Result<Oid, IdentityError>;
|
||||||
|
|
||||||
|
/// Load the canonical identity.
|
||||||
|
fn identity(&self) -> Result<Identity<Oid>, IdentityError> {
|
||||||
|
let head = self.identity_head()?;
|
||||||
|
|
||||||
|
Identity::load_at(head, self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute the canonical `rad/id` of this repository.
|
/// Compute the canonical `rad/id` of this repository.
|
||||||
///
|
///
|
||||||
/// Ignores any existing `rad/id` reference.
|
/// Ignores any existing `rad/id` reference.
|
||||||
|
|
|
||||||
|
|
@ -291,12 +291,6 @@ impl Repository {
|
||||||
Identity::load(remote, self)
|
Identity::load(remote, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identity(&self) -> Result<Identity<Oid>, IdentityError> {
|
|
||||||
let head = self.identity_head()?;
|
|
||||||
|
|
||||||
Identity::load_at(head, self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the canonical project information.
|
/// Get the canonical project information.
|
||||||
pub fn project(&self) -> Result<Project, IdentityError> {
|
pub fn project(&self) -> Result<Project, IdentityError> {
|
||||||
let head = self.identity_head()?;
|
let head = self.identity_head()?;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue