ipld_block_builder/
builder.rs1use crate::batch::Batch;
2use crate::codec::{Decoder, Encoder, Encrypted, IpldDecoder};
3use crate::path::DagPath;
4use libipld::cid::Cid;
5use libipld::codec::{Decode, Encode};
6use libipld::error::Result;
7use libipld::ipld::Ipld;
8use libipld::store::{AliasStore, MultiUserStore, ReadonlyStore, Store, Visibility};
9use std::path::Path;
10
11pub struct BlockBuilder<S, C> {
13 store: S,
14 codec: C,
15 visibility: Visibility,
16}
17
18impl<S, C> BlockBuilder<S, C> {
19 pub fn new(store: S, codec: C) -> Self {
21 Self {
22 store,
23 codec,
24 visibility: Visibility::Public,
25 }
26 }
27
28 pub fn visibility(&self) -> Visibility {
30 self.visibility
31 }
32
33 pub fn store(&self) -> &S {
35 &self.store
36 }
37
38 pub fn codec(&self) -> &C {
40 &self.codec
41 }
42}
43
44impl<S, C: Encrypted> BlockBuilder<S, C> {
45 pub fn new_private(store: S, codec: C) -> Self {
47 Self {
48 store,
49 codec,
50 visibility: Visibility::Private,
51 }
52 }
53}
54
55impl<S: ReadonlyStore, C: Decoder> BlockBuilder<S, C> {
56 pub async fn get<D: Decode<C::Codec>>(&self, cid: &Cid) -> Result<D> {
58 let data = self.store.get(cid).await?;
59 self.codec.decode(cid, &data)
60 }
61}
62
63impl<S: ReadonlyStore, C: IpldDecoder> BlockBuilder<S, C> {
64 pub async fn get_ipld(&self, cid: &Cid) -> Result<Ipld> {
66 let data = self.store.get(cid).await?;
67 self.codec.decode_ipld(cid, &data)
68 }
69
70 pub async fn get_path(&self, path: &DagPath<'_>) -> Result<Ipld> {
72 let mut root = self.get_ipld(path.root()).await?;
73 let mut ipld = &root;
74 for segment in path.path().iter() {
75 ipld = ipld.get(segment)?;
76 if let Ipld::Link(cid) = ipld {
77 root = self.get_ipld(cid).await?;
78 ipld = &root;
79 }
80 }
81 Ok(ipld.clone())
82 }
83}
84
85impl<S: Store, C: Encoder + Clone> BlockBuilder<S, C> {
86 pub fn create_batch(&self) -> Batch<C> {
88 Batch::new(self.codec.clone())
89 }
90
91 pub fn create_batch_with_capacity(&self, capacity: usize) -> Batch<C> {
93 Batch::with_capacity(self.codec.clone(), capacity)
94 }
95
96 pub async fn insert<E: Encode<C::Codec>>(&self, e: &E) -> Result<Cid> {
98 let mut batch = self.create_batch();
99 batch.insert(e)?;
100 self.insert_batch(batch).await
101 }
102
103 pub async fn insert_batch<T>(&self, batch: Batch<T>) -> Result<Cid> {
105 Ok(self
106 .store
107 .insert_batch(batch.into_vec(), self.visibility)
108 .await?)
109 }
110}
111
112impl<S: Store, C> BlockBuilder<S, C> {
113 pub async fn flush(&self) -> Result<()> {
115 Ok(self.store.flush().await?)
116 }
117
118 pub async fn unpin(&self, cid: &Cid) -> Result<()> {
120 Ok(self.store.unpin(cid).await?)
121 }
122}
123
124impl<S: MultiUserStore, C> BlockBuilder<S, C> {
125 pub async fn pin(&self, cid: &Cid, path: &Path) -> Result<()> {
127 Ok(self.store.pin(cid, path).await?)
128 }
129}
130
131impl<S: AliasStore, C> BlockBuilder<S, C> {
132 pub async fn alias(&self, alias: &[u8], cid: &Cid) -> Result<()> {
134 Ok(self.store.alias(alias, cid, self.visibility).await?)
135 }
136
137 pub async fn unalias(&self, alias: &[u8]) -> Result<()> {
139 Ok(self.store.unalias(alias).await?)
140 }
141
142 pub async fn resolve(&self, alias: &[u8]) -> Result<Option<Cid>> {
144 Ok(self.store.resolve(alias).await?)
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 #[cfg(feature = "crypto")]
152 use crate::crypto::Key;
153 use crate::Codec;
154 #[cfg(feature = "crypto")]
155 use crate::StrobeCodec;
156 use libipld::mem::MemStore;
157 use libipld::{ipld, DagCbor};
158
159 #[async_std::test]
160 async fn test_block_builder() {
161 let store = MemStore::default();
162 let codec = Codec::new();
163 let builder = BlockBuilder::new(store, codec);
164
165 let block1 = ipld!({
166 "value": 42,
167 });
168 let cid1 = builder.insert(&block1).await.unwrap();
169 let block1_2: Ipld = builder.get(&cid1).await.unwrap();
170 assert_eq!(block1, block1_2);
171
172 let block2 = ipld!({
173 "name": cid1,
174 });
175 let cid2 = builder.insert(&block2).await.unwrap();
176 let block2_2: Ipld = builder.get(&cid2).await.unwrap();
177 assert_eq!(block2, block2_2);
178 }
179
180 #[async_std::test]
181 async fn test_dag() {
182 let store = MemStore::default();
183 let codec = Codec::new();
184 let builder = BlockBuilder::new(store, codec);
185 let ipld1 = ipld!({"a": 3});
186 let cid = builder.insert(&ipld1).await.unwrap();
187 let ipld2 = ipld!({"root": [{"child": &cid}]});
188 let root = builder.insert(&ipld2).await.unwrap();
189 let path = DagPath::new(&root, "root/0/child/a");
190 assert_eq!(builder.get_path(&path).await.unwrap(), Ipld::Integer(3));
191 }
192
193 #[derive(Clone, DagCbor, Debug, Eq, PartialEq)]
194 struct Identity {
195 id: u64,
196 name: String,
197 age: u8,
198 }
199
200 #[async_std::test]
201 #[cfg(feature = "crypto")]
202 async fn test_block_builder_private() {
203 let key = Key::from(b"private encryption key".to_vec());
204 let store = MemStore::default();
205 let codec = StrobeCodec::new(key);
206 let builder = BlockBuilder::new_private(store, codec);
207
208 let identity = Identity {
209 id: 0,
210 name: "David Craven".into(),
211 age: 26,
212 };
213 let cid = builder.insert(&identity).await.unwrap();
214 let identity2 = builder.get(&cid).await.unwrap();
215 assert_eq!(identity, identity2);
216 }
217
218 #[async_std::test]
219 #[cfg(feature = "crypto")]
220 async fn test_dag_private() {
221 let key = Key::from(b"private encryption key".to_vec());
222 let store = MemStore::default();
223 let codec = StrobeCodec::new(key);
224 let builder = BlockBuilder::new_private(store, codec);
225 let ipld1 = ipld!({"a": 3});
226 let cid = builder.insert(&ipld1).await.unwrap();
227 let ipld2 = ipld!({"root": [{"child": &cid}]});
228 let root = builder.insert(&ipld2).await.unwrap();
229 let path = DagPath::new(&root, "root/0/child/a");
230 assert_eq!(builder.get_path(&path).await.unwrap(), Ipld::Integer(3));
231 }
232}