diff --git a/sn_registers/src/reg_crdt.rs b/sn_registers/src/reg_crdt.rs index 254c156b59..844b3bfce3 100644 --- a/sn_registers/src/reg_crdt.rs +++ b/sn_registers/src/reg_crdt.rs @@ -113,6 +113,15 @@ impl RegisterCrdt { .collect() } + /// Returns the children of an entry, along with their corresponding entry hashes + pub fn children(&self, hash: &EntryHash) -> BTreeSet<(EntryHash, Entry)> { + self.data + .children(hash.0) + .hashes_and_nodes() + .map(|(hash, node)| (EntryHash(hash), node.value.clone())) + .collect() + } + /// Access the underlying MerkleReg (e.g. for access to history) /// NOTE: This API is unstable and may be removed in the future pub(crate) fn merkle_reg(&self) -> &MerkleReg { @@ -163,4 +172,58 @@ mod tests { Ok(()) } + + #[test] + fn entry_children() -> Result<()> { + let mut rng = rand::thread_rng(); + let address = RegisterAddress { + meta: XorName::random(&mut rng), + owner: SecretKey::random().public_key(), + }; + let mut crdt = RegisterCrdt::new(address); + + // let's build the following entries hierarchy to test: + // - entry_1 has no child + // - entry_2_1, entry_2_2, and entry_2_3, all have entry_1 as child + // - entry_3 has both entry_2_1 and entry_2_2 as children + let entry_1 = vec![0x0, 0x1]; + let entry_2_1 = vec![0x2, 0x1]; + let entry_2_2 = vec![0x2, 0x2]; + let entry_2_3 = vec![0x2, 0x3]; + let entry_3 = vec![0x0, 0x3]; + let (entry_hash_1, _, _) = crdt.write(entry_1.clone(), &BTreeSet::new())?; + let (entry_hash_2_1, _, _) = + crdt.write(entry_2_1.clone(), &[entry_hash_1].into_iter().collect())?; + let (entry_hash_2_2, _, _) = + crdt.write(entry_2_2.clone(), &[entry_hash_1].into_iter().collect())?; + let (entry_hash_2_3, _, _) = + crdt.write(entry_2_3.clone(), &[entry_hash_1].into_iter().collect())?; + let (entry_hash_3, _, _) = crdt.write( + entry_3, + &[entry_hash_2_1, entry_hash_2_2].into_iter().collect(), + )?; + + let children_entry_1 = crdt.children(&entry_hash_1); + assert_eq!(children_entry_1, BTreeSet::new()); + + let children_entry_2_1 = crdt.children(&entry_hash_2_1); + let children_entry_2_2 = crdt.children(&entry_hash_2_2); + let children_entry_2_3 = crdt.children(&entry_hash_2_3); + assert_eq!( + children_entry_2_1, + [(entry_hash_1, entry_1)].into_iter().collect() + ); + assert_eq!(children_entry_2_1, children_entry_2_2); + assert_eq!(children_entry_2_1, children_entry_2_3); + + let children_entry_3 = crdt.children(&entry_hash_3); + assert_eq!( + children_entry_3, + [(entry_hash_2_1, entry_2_1), (entry_hash_2_2, entry_2_2)] + .into_iter() + .collect() + ); + + Ok(()) + } } diff --git a/sn_registers/src/register.rs b/sn_registers/src/register.rs index 02bb61758d..7e590a3972 100644 --- a/sn_registers/src/register.rs +++ b/sn_registers/src/register.rs @@ -193,6 +193,11 @@ impl Register { self.crdt.read() } + /// Returns the children of an entry, along with their corresponding entry hashes + pub fn children(&self, hash: &EntryHash) -> BTreeSet<(EntryHash, Entry)> { + self.crdt.children(hash) + } + /// Return the permission. pub fn permissions(&self) -> &Permissions { &self.permissions