radicle_cob/object/collaboration/
create.rs

1// Copyright © 2022 The Radicle Link Contributors
2
3use nonempty::NonEmpty;
4
5use crate::Embed;
6use crate::Evaluate;
7use crate::Store;
8
9use super::*;
10
11/// The metadata required for creating a new [`CollaborativeObject`].
12pub struct Create {
13    /// The CRDT history to initialize this object with.
14    pub contents: NonEmpty<Vec<u8>>,
15    /// The typename for this object.
16    pub type_name: TypeName,
17    /// The message to add when creating this object.
18    pub message: String,
19    /// Embedded content.
20    pub embeds: Vec<Embed<Oid>>,
21    /// COB version.
22    pub version: Version,
23}
24
25impl Create {
26    fn template(self) -> change::Template<git_ext::Oid> {
27        change::Template {
28            type_name: self.type_name,
29            tips: Vec::new(),
30            message: self.message,
31            embeds: self.embeds,
32            contents: self.contents,
33        }
34    }
35}
36
37/// Create a new [`CollaborativeObject`].
38///
39/// The `storage` is the backing storage for storing
40/// [`crate::Entry`]s at content-addressable locations. Please see
41/// [`Store`] for further information.
42///
43/// The `signer` is expected to be a cryptographic signing key. This
44/// ensures that the objects origin is cryptographically verifiable.
45///
46/// The `resource` is the parent of this object, for example a
47/// software project. Its content-address is stored in the object's
48/// history.
49///
50/// The `identifier` is a unqiue id that is passed through to the
51/// [`crate::object::Storage`].
52///
53/// The `args` are the metadata for this [`CollaborativeObject`]. See
54/// [`Create`] for further information.
55pub fn create<T, S, G>(
56    storage: &S,
57    signer: &G,
58    resource: Option<Oid>,
59    related: Vec<Oid>,
60    identifier: &S::Namespace,
61    args: Create,
62) -> Result<CollaborativeObject<T>, error::Create>
63where
64    T: Evaluate<S>,
65    S: Store,
66    G: signature::Signer<crate::ExtendedSignature>,
67{
68    let type_name = args.type_name.clone();
69    let version = args.version;
70    let init_change = storage
71        .store(resource, related, signer, args.template())
72        .map_err(error::Create::from)?;
73    let object_id = init_change.id().into();
74    let object = T::init(&init_change, storage).map_err(error::Create::evaluate)?;
75
76    storage
77        .update(identifier, &type_name, &object_id, &object_id)
78        .map_err(|err| error::Create::Refs { err: Box::new(err) })?;
79
80    let history = History::new_from_root(init_change);
81
82    Ok(CollaborativeObject {
83        manifest: Manifest::new(type_name, version),
84        history,
85        object,
86        id: object_id,
87    })
88}