Skip to content

Commit c89277d

Browse files
committed
feat: create folder node & add tests
1 parent fa01dbb commit c89277d

File tree

14 files changed

+645
-6
lines changed

14 files changed

+645
-6
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use crate::client_folder::view_node::ViewNode;
2+
use crate::client_folder::{get_attributes_str_value, set_attributes_str_value, AtomicNodeTree};
3+
use crate::errors::CollaborateResult;
4+
use folder_rev_model::{AppRevision, ViewRevision};
5+
use lib_ot::core::{NodeData, NodeDataBuilder, NodeOperation, Path, Transaction};
6+
use std::sync::Arc;
7+
8+
#[derive(Debug, Clone)]
9+
pub struct AppNode {
10+
pub id: String,
11+
tree: Arc<AtomicNodeTree>,
12+
pub(crate) path: Path,
13+
views: Vec<Arc<ViewNode>>,
14+
}
15+
16+
impl AppNode {
17+
pub(crate) fn from_app_revision(
18+
transaction: &mut Transaction,
19+
revision: AppRevision,
20+
tree: Arc<AtomicNodeTree>,
21+
path: Path,
22+
) -> CollaborateResult<Self> {
23+
let app_id = revision.id.clone();
24+
let app_node = NodeDataBuilder::new("app")
25+
.insert_attribute("id", revision.id)
26+
.insert_attribute("name", revision.name)
27+
.insert_attribute("workspace_id", revision.workspace_id)
28+
.build();
29+
30+
transaction.push_operation(NodeOperation::Insert {
31+
path: path.clone(),
32+
nodes: vec![app_node],
33+
});
34+
35+
let views = revision
36+
.belongings
37+
.into_iter()
38+
.enumerate()
39+
.map(|(index, app)| (path.clone_with(index), app))
40+
.flat_map(
41+
|(path, app)| match ViewNode::from_view_revision(transaction, app, tree.clone(), path) {
42+
Ok(view_node) => Some(Arc::new(view_node)),
43+
Err(err) => {
44+
tracing::error!("create view node failed: {:?}", err);
45+
None
46+
}
47+
},
48+
)
49+
.collect::<Vec<Arc<ViewNode>>>();
50+
51+
Ok(Self {
52+
id: app_id,
53+
tree,
54+
path,
55+
views,
56+
})
57+
}
58+
59+
pub fn get_name(&self) -> Option<String> {
60+
get_attributes_str_value(self.tree.clone(), &self.path, "name")
61+
}
62+
63+
pub fn set_name(&self, name: &str) -> CollaborateResult<()> {
64+
set_attributes_str_value(self.tree.clone(), &self.path, "name", name.to_string())
65+
}
66+
67+
fn get_workspace_id(&self) -> Option<String> {
68+
get_attributes_str_value(self.tree.clone(), &self.path, "workspace_id")
69+
}
70+
71+
fn set_workspace_id(&self, workspace_id: String) -> CollaborateResult<()> {
72+
set_attributes_str_value(self.tree.clone(), &self.path, "workspace_id", workspace_id)
73+
}
74+
75+
fn get_view(&self, view_id: &str) -> Option<&Arc<ViewNode>> {
76+
todo!()
77+
}
78+
79+
fn get_mut_view(&mut self, view_id: &str) -> Option<&mut Arc<ViewNode>> {
80+
todo!()
81+
}
82+
83+
fn add_view(&mut self, revision: ViewRevision) -> CollaborateResult<()> {
84+
let mut transaction = Transaction::new();
85+
let path = self.path.clone_with(self.views.len());
86+
let view_node = ViewNode::from_view_revision(&mut transaction, revision, self.tree.clone(), path)?;
87+
let _ = self.tree.write().apply_transaction(transaction)?;
88+
self.views.push(Arc::new(view_node));
89+
todo!()
90+
}
91+
92+
fn remove_view(&mut self, view_id: &str) {
93+
todo!()
94+
}
95+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
use crate::client_folder::workspace_node::WorkspaceNode;
2+
use crate::errors::{CollaborateError, CollaborateResult};
3+
use folder_rev_model::{AppRevision, ViewRevision, WorkspaceRevision};
4+
use lib_ot::core::{
5+
AttributeEntry, AttributeHashMap, AttributeValue, Changeset, Node, NodeDataBuilder, NodeOperation, NodeTree, Path,
6+
Transaction,
7+
};
8+
use parking_lot::RwLock;
9+
use std::string::ToString;
10+
use std::sync::Arc;
11+
12+
pub type AtomicNodeTree = RwLock<NodeTree>;
13+
14+
pub struct FolderNodePad {
15+
tree: Arc<AtomicNodeTree>,
16+
workspaces: Vec<Arc<WorkspaceNode>>,
17+
trash: Vec<Arc<TrashNode>>,
18+
}
19+
20+
impl FolderNodePad {
21+
pub fn new() -> Self {
22+
Self::default()
23+
}
24+
25+
pub fn get_workspace(&self, workspace_id: &str) -> Option<&Arc<WorkspaceNode>> {
26+
self.workspaces.iter().find(|workspace| workspace.id == workspace_id)
27+
}
28+
29+
pub fn get_mut_workspace(&mut self, workspace_id: &str) -> Option<&mut Arc<WorkspaceNode>> {
30+
self.workspaces
31+
.iter_mut()
32+
.find(|workspace| workspace.id == workspace_id)
33+
}
34+
35+
pub fn remove_workspace(&mut self, workspace_id: &str) {
36+
if let Some(workspace) = self.workspaces.iter().find(|workspace| workspace.id == workspace_id) {
37+
let mut nodes = vec![];
38+
let workspace_node = self.tree.read().get_node_data_at_path(&workspace.path);
39+
debug_assert!(workspace_node.is_some());
40+
41+
if let Some(node_data) = workspace_node {
42+
nodes.push(node_data);
43+
}
44+
let delete_operation = NodeOperation::Delete {
45+
path: workspace.path.clone(),
46+
nodes,
47+
};
48+
let _ = self.tree.write().apply_op(delete_operation);
49+
}
50+
}
51+
52+
pub fn add_workspace(&mut self, revision: WorkspaceRevision) -> CollaborateResult<()> {
53+
let mut transaction = Transaction::new();
54+
let workspace_node = WorkspaceNode::from_workspace_revision(
55+
&mut transaction,
56+
revision,
57+
self.tree.clone(),
58+
workspaces_path().clone_with(self.workspaces.len()),
59+
)?;
60+
let _ = self.tree.write().apply_transaction(transaction)?;
61+
self.workspaces.push(Arc::new(workspace_node));
62+
Ok(())
63+
}
64+
65+
pub fn to_json(&self, pretty: bool) -> CollaborateResult<String> {
66+
self.tree
67+
.read()
68+
.to_json(pretty)
69+
.map_err(|e| CollaborateError::serde().context(e))
70+
}
71+
}
72+
73+
fn folder_path() -> Path {
74+
vec![0].into()
75+
}
76+
77+
fn workspaces_path() -> Path {
78+
folder_path().clone_with(0)
79+
}
80+
81+
fn trash_path() -> Path {
82+
folder_path().clone_with(1)
83+
}
84+
85+
pub fn get_attributes(tree: Arc<AtomicNodeTree>, path: &Path) -> Option<AttributeHashMap> {
86+
tree.read()
87+
.get_node_at_path(&path)
88+
.and_then(|node| Some(node.attributes.clone()))
89+
}
90+
91+
pub fn get_attributes_value(tree: Arc<AtomicNodeTree>, path: &Path, key: &str) -> Option<AttributeValue> {
92+
tree.read()
93+
.get_node_at_path(&path)
94+
.and_then(|node| node.attributes.get(key).cloned())
95+
}
96+
97+
pub fn get_attributes_str_value(tree: Arc<AtomicNodeTree>, path: &Path, key: &str) -> Option<String> {
98+
tree.read()
99+
.get_node_at_path(&path)
100+
.and_then(|node| node.attributes.get(key).cloned())
101+
.and_then(|value| value.str_value())
102+
}
103+
104+
pub fn set_attributes_str_value(
105+
tree: Arc<AtomicNodeTree>,
106+
path: &Path,
107+
key: &str,
108+
value: String,
109+
) -> CollaborateResult<()> {
110+
let old_attributes = match get_attributes(tree.clone(), path) {
111+
None => AttributeHashMap::new(),
112+
Some(attributes) => attributes,
113+
};
114+
let mut new_attributes = old_attributes.clone();
115+
new_attributes.insert(key, value);
116+
117+
let update_operation = NodeOperation::Update {
118+
path: path.clone(),
119+
changeset: Changeset::Attributes {
120+
new: new_attributes,
121+
old: old_attributes,
122+
},
123+
};
124+
let _ = tree.write().apply_op(update_operation)?;
125+
Ok(())
126+
}
127+
128+
impl std::default::Default for FolderNodePad {
129+
fn default() -> Self {
130+
let workspace_node = NodeDataBuilder::new("workspaces").build();
131+
let trash_node = NodeDataBuilder::new("trash").build();
132+
let folder_node = NodeDataBuilder::new("folder")
133+
.add_node_data(workspace_node)
134+
.add_node_data(trash_node)
135+
.build();
136+
137+
let operation = NodeOperation::Insert {
138+
path: folder_path(),
139+
nodes: vec![folder_node],
140+
};
141+
let mut tree = NodeTree::default();
142+
let _ = tree.apply_op(operation).unwrap();
143+
144+
Self {
145+
tree: Arc::new(RwLock::new(tree)),
146+
workspaces: vec![],
147+
trash: vec![],
148+
}
149+
}
150+
}
151+
152+
pub struct TrashNode {
153+
tree: Arc<AtomicNodeTree>,
154+
parent_path: Path,
155+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
mod app_node;
12
mod builder;
3+
mod folder_node;
24
mod folder_pad;
5+
mod view_node;
6+
mod workspace_node;
37

8+
pub use folder_node::*;
49
pub use folder_pad::*;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use crate::client_folder::AtomicNodeTree;
2+
use crate::errors::CollaborateResult;
3+
use folder_rev_model::ViewRevision;
4+
use lib_ot::core::{NodeDataBuilder, NodeOperation, Path, Transaction};
5+
use std::sync::Arc;
6+
7+
#[derive(Debug, Clone)]
8+
pub struct ViewNode {
9+
tree: Arc<AtomicNodeTree>,
10+
path: Path,
11+
}
12+
13+
impl ViewNode {
14+
pub(crate) fn from_view_revision(
15+
transaction: &mut Transaction,
16+
revision: ViewRevision,
17+
tree: Arc<AtomicNodeTree>,
18+
path: Path,
19+
) -> CollaborateResult<Self> {
20+
let view_node = NodeDataBuilder::new("view")
21+
.insert_attribute("id", revision.id)
22+
.insert_attribute("name", revision.name)
23+
.build();
24+
25+
transaction.push_operation(NodeOperation::Insert {
26+
path: path.clone(),
27+
nodes: vec![view_node],
28+
});
29+
30+
Ok(Self { tree, path })
31+
}
32+
33+
fn get_id(&self) -> &str {
34+
todo!()
35+
}
36+
37+
fn get_app_id(&self) -> &str {
38+
todo!()
39+
}
40+
41+
fn set_app_id(&self, workspace_id: String) {
42+
todo!()
43+
}
44+
}

0 commit comments

Comments
 (0)