Skip to content

Commit

Permalink
added reparenting of tree elements
Browse files Browse the repository at this point in the history
  • Loading branch information
zippy committed Dec 7, 2023
1 parent 4a5d0a9 commit fcff8d5
Show file tree
Hide file tree
Showing 15 changed files with 304 additions and 94 deletions.
10 changes: 7 additions & 3 deletions dnas/how/zomes/coordinator/how/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,14 @@ pub struct UpdateDocumentInput {
pub fn update_document(input: UpdateDocumentInput) -> ExternResult<EntryHashB64> {
let record = get(EntryHash::from(input.hash), GetOptions::default())?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Document not found"))))?;
let _action_hash = update_entry(record.action_address().clone().into(), &input.document)?;
let hash = hash_entry(&input.document)?;
_update_document(record.action_address().clone().into(),input.path, &input.document)
}

pub fn _update_document(hash: ActionHash, path: String, document: &Document) -> ExternResult<EntryHashB64> {
let _action_hash = update_entry(hash, document)?;
let hash = hash_entry(document)?;
// TODO validate that old doc had the same path, or get the path some other way?
link_document(hash.clone(), input.path)?;
link_document(hash.clone(), path)?;
return Ok(hash.into());
}

Expand Down
84 changes: 70 additions & 14 deletions dnas/how/zomes/coordinator/how/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ pub struct UnitInfo {

#[derive(Clone, Serialize, Deserialize, Debug, Default, PartialEq)]
pub struct Content {
name: String,
units: Vec<UnitInfo>,
documents: Vec<EntryHash>,
pub name: String,
pub units: Vec<UnitInfo>,
pub documents: Vec<EntryHash>,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct PathContent {
pub path: String,
pub units: Vec<UnitInfo>,
pub documents: Vec<EntryHash>,
}


fn get_entry_hashes(path: &Path) -> ExternResult<(Vec<UnitInfo>,Vec<EntryHash>)> {
let mut units = vec![];
let mut documents = vec![];
Expand Down Expand Up @@ -48,13 +56,34 @@ fn build_tree(tree: &mut Tree<Content>, node: usize, path: Path) -> ExternResult
for path in path.into_typed(ScopedLinkType::try_from(LinkTypes::Tree)?).children_paths()? {
let v = path.as_ref();
let (units, documents) = get_entry_hashes(&path)?;
let val = Content {
name: String::try_from(&v[v.len()-1]).map_err(|e| wasm_error!(e))?,
units,
documents,
};
let idx = tree.insert(node, val);
build_tree(tree, idx, path.path)?;
// there may be a path left over from a move that is now empty, so ignore it if there are no units there.
if units.len() > 0 {
let val = Content {
name: String::try_from(&v[v.len()-1]).map_err(|e| wasm_error!(e))?,
units,
documents,
};
let idx = tree.insert(node, val);
build_tree(tree, idx, path.path)?;
}
}
Ok(())
}


fn build_path_tree(tree: &mut Tree<PathContent>, node: usize, path: Path) -> ExternResult<()>{
for path in path.into_typed(ScopedLinkType::try_from(LinkTypes::Tree)?).children_paths()? {
let path_str : String = path.clone().try_into().map_err(|_e| wasm_error!(WasmErrorInner::Guest(String::from("XXX"))))?;
let (units, documents) = get_entry_hashes(&path)?;
if units.len() > 0 {
let val = PathContent {
path: path_str,
units,
documents,
};
let idx = tree.insert(node, val);
build_path_tree(tree, idx, path.path)?;
}
}
Ok(())
}
Expand All @@ -66,9 +95,23 @@ pub fn tree_path(path_str: String) -> Path {
Path::from(path)
}

pub fn tree_path_to_str(path:Path) -> ExternResult<String> {
let mut v = path.as_ref().clone();
v.remove(0);
let mut x:Vec<String> = Vec::new();
for c in v {
x.push(String::try_from(&c).map_err(|e| wasm_error!(e))?);
}
Ok(x.join("."))
}

#[hdk_extern]
pub fn get_tree(_input: ()) -> ExternResult<Tree<Content>> {
let root_path = Path::from(TREE_ROOT);
_get_tree(root_path)
}

pub fn _get_tree(root_path: Path) -> ExternResult<Tree<Content>> {
let (units, documents) = get_entry_hashes(&root_path)?;
let val = Content {
name: String::from(""),
Expand All @@ -80,6 +123,19 @@ pub fn get_tree(_input: ()) -> ExternResult<Tree<Content>> {
Ok(tree)
}

pub fn _get_path_tree(root_path: Path) -> ExternResult<Tree<PathContent>> {
let (units, documents) = get_entry_hashes(&root_path)?;
let val = PathContent {
path: tree_path_to_str(root_path.clone())?,
units,
documents,
};
let mut tree = Tree::new(val);
build_path_tree(&mut tree, 0, root_path)?;
Ok(tree)
}


#[derive(Clone, Serialize, Deserialize, Debug, Default)]
pub struct Tree<T>
where
Expand Down Expand Up @@ -118,10 +174,10 @@ pub struct Node<T>
where
T: PartialEq
{
idx: usize,
val: T,
parent: Option<usize>,
children: Vec<usize>,
pub idx: usize,
pub val: T,
pub parent: Option<usize>,
pub children: Vec<usize>,
}

impl<T> Node<T>
Expand Down
95 changes: 93 additions & 2 deletions dnas/how/zomes/coordinator/how/src/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use holo_hash::{EntryHashB64};
use how_integrity::Document;
use how_integrity::{Unit, EntryTypes, LinkTypes};

use crate::document::{update_document, UpdateDocumentInput};
use crate::document::{update_document, UpdateDocumentInput, _update_document};
use crate::error::*;
//use crate::signals::*;
use crate::tree::UnitInfo;
use crate::tree::{UnitInfo, _get_tree, tree_path, _get_path_tree, tree_path_to_str};

pub fn get_units_path() -> Path {
Path::from("units")
Expand Down Expand Up @@ -181,3 +181,94 @@ pub fn advance_state(input: AdvanceStateInput) -> ExternResult<EntryHashB64> {
create_unit_links(hash,unit.tree_paths(), &input.new_state, &unit.version)?;
return Ok(new_doc_hash);
}


#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ReparentInput {
pub path: String,
pub new_parent: String,
}
#[hdk_extern]
pub fn reparent(input: ReparentInput) -> ExternResult<()> {
// let new_parent_path = Path::from(input.new_parent);
// let link = get
let sub_tree = _get_path_tree(tree_path(input.path.clone()))?;
let mut parent:Vec<_> = input.path.split(".").into_iter().collect();
parent.pop();
let parent = parent.join(".");
for node in sub_tree.tree {
let units = node.val.units.clone();
let current_path = node.val.path;//.clone();
for unit in units {
let documents: Vec<HoloHash<holo_hash::hash_type::Entry>> = node.val.documents.clone();

let (new_unit_hash, new_unit) = reparent_unit(&unit, parent.clone(), input.new_parent.clone())?;
for doc in documents {
reparent_document(unit.hash.clone(), new_unit_hash.clone(), &new_unit, doc, current_path.clone(), input.new_parent.clone())?;
}
}
}
Ok(())
}

pub fn update_unit(hash: ActionHash, unit: &Unit) -> ExternResult<EntryHash> {
let _action_hash = update_entry(hash, unit)?;
let hash = hash_entry(unit)?;
Ok(hash)
}

pub fn reparent_unit(unit_info: &UnitInfo, from: String, to: String) -> ExternResult<(EntryHash, Unit)> {
let record = get(unit_info.hash.clone(), GetOptions::default())?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Unit not found"))))?;
let mut unit: Unit = record
.entry()
.to_app_option().map_err(|err| wasm_error!(err))?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Malformed unit"))))?;
delete_unit_links(unit_info.hash.clone(), unit.tree_paths())?;

if let Some(idx) = unit.parents.clone().into_iter().position(|p| {
p.starts_with(&from)}
) {
unit.parents[idx] = unit.parents[idx].replacen(&from, &to,1);
}

let new_unit_hash = update_unit(record.action_address().clone(), &unit)?;
create_unit_links(new_unit_hash.clone(), unit.tree_paths(), &unit_info.state, &unit_info.version)?;

Ok((new_unit_hash,unit))
}

pub fn reparent_document(old_unit_hash: EntryHash, new_unit_hash: EntryHash, new_unit: &Unit, hash: EntryHash, old_path:String, new_parent: String) -> ExternResult<()> {
let record = get(hash.clone(), GetOptions::default())?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Document not found"))))?;
let mut document: Document = record
.entry()
.to_app_option().map_err(|err| wasm_error!(err))?
.ok_or(wasm_error!(WasmErrorInner::Guest(String::from("Malformed document"))))?;

if document.unit_hash == old_unit_hash {
document.unit_hash = new_unit_hash;
let new_path = format!("{}.{}", new_parent, new_unit.path_abbreviation);
let path = tree_path(old_path);
let links = get_links(path.path_entry_hash()?, LinkTypes::Document, None)?;

// delete all the old links at the old path
let mut delete_link_input: Vec<DeleteLinkInput> = Vec::new();
let any: AnyLinkableHash = hash.into();
for l in links {
if l.target == any {
delete_link_input.push(DeleteLinkInput{
address: l.create_link_hash,
chain_top_ordering: ChainTopOrdering::Relaxed,
});
}
}
for input in delete_link_input {
HDK.with(|hdk| hdk.borrow().delete_link(input))?;
}

_update_document( record.action_address().clone().into(), new_path, &document )?;
}
Ok(())
}
Loading

0 comments on commit fcff8d5

Please sign in to comment.