Browse Source

chore: implement folder

nathan 2 years ago
parent
commit
aca9b81c79

+ 2 - 0
shared-lib/flowy-ast/src/ast.rs

@@ -123,7 +123,9 @@ pub struct ASTField<'a> {
     pub node_attrs: NodeStructAttrs,
     pub ty: &'a syn::Type,
     pub original: &'a syn::Field,
+    // If the field is Vec<String>, then the bracket_ty will be Vec
     pub bracket_ty: Option<syn::Ident>,
+    // If the field is Vec<String>, then the bracket_inner_ty will be String
     pub bracket_inner_ty: Option<syn::Ident>,
     pub bracket_category: Option<BracketCategory>,
 }

+ 24 - 20
shared-lib/flowy-ast/src/node_attrs.rs

@@ -11,8 +11,9 @@ use syn::{
 
 pub struct NodeStructAttrs {
     pub rename: Option<LitStr>,
-    pub is_children: bool,
-    node_index: Option<syn::LitInt>,
+    pub has_child: bool,
+    pub child_name: Option<LitStr>,
+    pub child_index: Option<syn::LitInt>,
     get_node_value_with: Option<syn::ExprPath>,
     set_node_value_with: Option<syn::ExprPath>,
 }
@@ -20,9 +21,9 @@ pub struct NodeStructAttrs {
 impl NodeStructAttrs {
     /// Extract out the `#[node(...)]` attributes from a struct field.
     pub fn from_ast(ast_result: &ASTResult, index: usize, field: &syn::Field) -> Self {
-        let mut node_index = ASTAttr::none(ast_result, NODE_INDEX);
-        let mut rename = ASTAttr::none(ast_result, NODE_RENAME);
-        let mut is_children = ASTAttr::none(ast_result, NODE_CHILDREN);
+        let mut rename = ASTAttr::none(ast_result, RENAME_NODE);
+        let mut child_name = ASTAttr::none(ast_result, CHILD_NODE_NAME);
+        let mut child_index = ASTAttr::none(ast_result, CHILD_NODE_INDEX);
         let mut get_node_value_with = ASTAttr::none(ast_result, GET_NODE_VALUE_WITH);
         let mut set_node_value_with = ASTAttr::none(ast_result, SET_NODE_VALUE_WITH);
 
@@ -33,25 +34,27 @@ impl NodeStructAttrs {
             .flatten()
         {
             match &meta_item {
-                // Parse '#[node(index = x)]'
-                Meta(NameValue(m)) if m.path == NODE_INDEX => {
-                    if let syn::Lit::Int(lit) = &m.lit {
-                        node_index.set(&m.path, lit.clone());
+                // Parse '#[node(rename = x)]'
+                Meta(NameValue(m)) if m.path == RENAME_NODE => {
+                    if let syn::Lit::Str(lit) = &m.lit {
+                        rename.set(&m.path, lit.clone());
                     }
                 }
 
-                // Parse '#[node(children)]'
-                Meta(Path(path)) if path == NODE_CHILDREN => {
-                    eprintln!("😄 {:?}", path);
-                    is_children.set(path, true);
+                // Parse '#[node(child_name = x)]'
+                Meta(NameValue(m)) if m.path == CHILD_NODE_NAME => {
+                    if let syn::Lit::Str(lit) = &m.lit {
+                        child_name.set(&m.path, lit.clone());
+                    }
                 }
 
-                // Parse '#[node(rename = x)]'
-                Meta(NameValue(m)) if m.path == NODE_RENAME => {
-                    if let syn::Lit::Str(lit) = &m.lit {
-                        rename.set(&m.path, lit.clone());
+                // Parse '#[node(child_index = x)]'
+                Meta(NameValue(m)) if m.path == CHILD_NODE_INDEX => {
+                    if let syn::Lit::Int(lit) = &m.lit {
+                        child_index.set(&m.path, lit.clone());
                     }
                 }
+
                 // Parse `#[node(get_node_value_with = "...")]`
                 Meta(NameValue(m)) if m.path == GET_NODE_VALUE_WITH => {
                     if let Ok(path) = parse_lit_into_expr_path(ast_result, GET_NODE_VALUE_WITH, &m.lit) {
@@ -76,11 +79,12 @@ impl NodeStructAttrs {
                 }
             }
         }
-
+        let child_name = child_name.get();
         NodeStructAttrs {
             rename: rename.get(),
-            node_index: node_index.get(),
-            is_children: is_children.get().unwrap_or(false),
+            child_index: child_index.get(),
+            has_child: child_name.is_some(),
+            child_name,
             get_node_value_with: get_node_value_with.get(),
             set_node_value_with: set_node_value_with.get(),
         }

+ 3 - 2
shared-lib/flowy-ast/src/symbol.rs

@@ -37,8 +37,9 @@ pub const NODE_ATTRS: Symbol = Symbol("node");
 pub const NODES_ATTRS: Symbol = Symbol("nodes");
 pub const NODE_TYPE: Symbol = Symbol("node_type");
 pub const NODE_INDEX: Symbol = Symbol("index");
-pub const NODE_RENAME: Symbol = Symbol("rename");
-pub const NODE_CHILDREN: Symbol = Symbol("children");
+pub const RENAME_NODE: Symbol = Symbol("rename");
+pub const CHILD_NODE_NAME: Symbol = Symbol("child_name");
+pub const CHILD_NODE_INDEX: Symbol = Symbol("child_index");
 pub const SKIP_NODE_ATTRS: Symbol = Symbol("skip_node_attribute");
 pub const GET_NODE_VALUE_WITH: Symbol = Symbol("get_value_with");
 pub const SET_NODE_VALUE_WITH: Symbol = Symbol("set_value_with");

+ 88 - 9
shared-lib/flowy-derive/src/node/mod.rs

@@ -9,18 +9,98 @@ pub fn expand_derive(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::E
     };
 
     let mut token_stream: TokenStream = TokenStream::default();
+    token_stream.extend(make_helper_funcs_token_stream(&cont));
     token_stream.extend(make_to_node_data_token_stream(&cont));
 
     if let Some(get_value_token_stream) = make_get_set_value_token_steam(&cont) {
         token_stream.extend(get_value_token_stream);
     }
 
+    token_stream.extend(make_alter_children_token_stream(&ast_result, &cont));
     ast_result.check()?;
     Ok(token_stream)
 }
 
-pub fn make_alter_children_token_stream(ast: &ASTContainer) -> TokenStream {
+pub fn make_helper_funcs_token_stream(ast: &ASTContainer) -> TokenStream {
     let mut token_streams = TokenStream::default();
+    let struct_ident = &ast.ident;
+    token_streams.extend(quote! {
+      impl #struct_ident {
+            pub fn get_path(&self) -> Path {
+                self.tree.read().path_from_node_id(self.node_id.clone())
+            }
+        }
+    });
+    token_streams
+}
+
+pub fn make_alter_children_token_stream(ast_result: &ASTResult, ast: &ASTContainer) -> TokenStream {
+    let mut token_streams = TokenStream::default();
+    let children_fields = ast
+        .data
+        .all_fields()
+        .filter(|field| field.node_attrs.has_child)
+        .collect::<Vec<&ASTField>>();
+
+    if !children_fields.is_empty() {
+        let struct_ident = &ast.ident;
+        if children_fields.len() > 1 {
+            ast_result.error_spanned_by(struct_ident, "Only one children property");
+            return token_streams;
+        }
+        let children_field = children_fields.first().unwrap();
+        let field_name = children_field.name().unwrap();
+        eprintln!("😄 {:?} {:?}", struct_ident, field_name);
+        let child_name = children_field.node_attrs.child_name.as_ref().unwrap();
+        let get_func_name = format_ident!("get_{}", child_name.value());
+        let get_mut_func_name = format_ident!("get_mut_{}", child_name.value());
+        let add_func_name = format_ident!("add_{}", child_name.value());
+        let remove_func_name = format_ident!("remove_{}", child_name.value());
+        let ty = children_field.bracket_inner_ty.as_ref().unwrap().clone();
+
+        token_streams.extend(quote! {
+             impl #struct_ident {
+                pub fn #get_func_name(&self, id: &str) -> Option<&#ty> {
+                     self.#field_name.iter().find(|element| element.id == id)
+                }
+
+                pub fn #get_mut_func_name(&mut self, id: &str) -> Option<&mut #ty> {
+                     self.#field_name.iter_mut().find(|element| element.id == id)
+                }
+
+                pub fn #remove_func_name(&mut self, id: &str) {
+                     if let Some(index) = self.#field_name.iter().position(|element| element.id == id) {
+                        let element = self.#field_name.remove(index);
+                        let element_path = element.get_path();
+
+                        let mut write_guard = self.tree.write();
+                        let mut nodes = vec![];
+                        if let Some(node_data) = write_guard.get_node_data(element.node_id.clone()) {
+                            nodes.push(node_data);
+                        }
+                        let _ = write_guard.apply_op(NodeOperation::Delete {
+                            path: element_path,
+                            nodes,
+                        });
+                    }
+                }
+
+                pub fn #add_func_name(&mut self, value: #ty) {
+                    let mut transaction = Transaction::new();
+                    let parent_path = self.get_path();
+                    let path = parent_path.clone_with(self.#field_name.len());
+                    let node_data = value.to_node_data();
+                    transaction.push_operation(NodeOperation::Insert {
+                        path,
+                        nodes: vec![node_data],
+                     });
+
+                    let _ = self.tree.write().apply_transaction(transaction);
+                    self.#field_name.push(value);
+                }
+             }
+        });
+    }
 
     token_streams
 }
@@ -35,7 +115,7 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream {
     let set_key_values = ast
         .data
         .all_fields()
-        .filter(|field| !field.node_attrs.is_children)
+        .filter(|field| !field.node_attrs.has_child)
         .flat_map(|field| {
             let mut field_name = field.name().expect("the name of the field should not be empty");
             let original_field_name = field.name().expect("the name of the field should not be empty");
@@ -51,7 +131,7 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream {
     let children_fields = ast
         .data
         .all_fields()
-        .filter(|field| field.node_attrs.is_children)
+        .filter(|field| field.node_attrs.has_child)
         .collect::<Vec<&ASTField>>();
 
     let childrens_token_streams = match children_fields.is_empty() {
@@ -72,8 +152,8 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream {
     };
 
     token_streams.extend(quote! {
-      impl #struct_ident {
-            pub fn to_node_data(&self) -> NodeData {
+      impl ToNodeData for #struct_ident {
+            fn to_node_data(&self) -> NodeData {
                 #childrens_token_streams
 
                 let builder = NodeDataBuilder::new(#node_type)
@@ -94,7 +174,7 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option<TokenStream>
 
     let tree = format_ident!("tree");
     for field in ast.data.all_fields() {
-        if field.node_attrs.is_children {
+        if field.node_attrs.has_child {
             continue;
         }
 
@@ -113,7 +193,7 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option<TokenStream>
             token_streams.extend(quote! {
               impl #struct_ident {
                     pub fn #get_func_name(&self) -> Option<#get_value_return_ty> {
-                        #get_value_with_fn(self.#tree.clone(), &self.path, #field_name_str)
+                        #get_value_with_fn(self.#tree.clone(), &self.node_id, #field_name_str)
                     }
                 }
             });
@@ -123,12 +203,11 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option<TokenStream>
             token_streams.extend(quote! {
               impl #struct_ident {
                     pub fn #set_func_name(&self, value: #set_value_input_ty) {
-                        let _ = #set_value_with_fn(self.#tree.clone(), &self.path, #field_name_str, value);
+                        let _ = #set_value_with_fn(self.#tree.clone(), &self.node_id, #field_name_str, value);
                     }
                 }
             });
         }
     }
-    ast.data.all_fields().for_each(|field| {});
     Some(token_streams)
 }

+ 6 - 44
shared-lib/flowy-sync/src/client_folder/folder_node.rs

@@ -11,42 +11,6 @@ use std::sync::Arc;
 
 pub type AtomicNodeTree = RwLock<NodeTree>;
 
-// pub struct FolderNodePad2 {
-//     tree: Arc<AtomicNodeTree>,
-//
-//     #[node(rename = "workspaces", revision = "WorkspaceRevision")]
-//     workspaces: Vec<Arc<WorkspaceNode>>,
-// }
-//
-// impl FolderNodePad2 {
-//     pub fn get_workspace() {}
-//     pub fn get_mut_workspace() {}
-//     pub fn add_workspace() {}
-//     pub fn remove_workspace() {}
-//     pub fn to_json() {}
-// }
-//
-// #[derive(Debug, Clone)]
-// pub struct WorkspaceNode2 {
-//     tree: Arc<AtomicNodeTree>,
-//     pub id: String,
-//     pub name: String,
-//     pub path: Path,
-// }
-//
-// impl WorkspaceNode2 {
-//     pub fn get_id() {}
-//     pub fn set_id() {}
-//     pub fn get_name() {}
-//     pub fn set_name() {}
-//     pub fn get_apps() {}
-//
-//     pub fn get_app() {}
-//     pub fn get_mut_app() {}
-//     pub fn add_app() {}
-//     pub fn remove_app() {}
-// }
-
 pub struct FolderNodePad {
     tree: Arc<AtomicNodeTree>,
     // name: workspaces, index of the node,
@@ -71,31 +35,29 @@ impl FolderNodePad {
 
     pub fn remove_workspace(&mut self, workspace_id: &str) {
         if let Some(workspace) = self.workspaces.iter().find(|workspace| workspace.id == workspace_id) {
+            let mut write_guard = self.tree.write();
             let mut nodes = vec![];
-            let workspace_node = self.tree.read().get_node_data_at_path(&workspace.path);
-            debug_assert!(workspace_node.is_some());
 
-            if let Some(node_data) = workspace_node {
+            if let Some(node_data) = write_guard.get_node_data_at_path(&workspace.path) {
                 nodes.push(node_data);
             }
-            let delete_operation = NodeOperation::Delete {
+            let _ = write_guard.apply_op(NodeOperation::Delete {
                 path: workspace.path.clone(),
                 nodes,
-            };
-            let _ = self.tree.write().apply_op(delete_operation);
+            });
         }
     }
 
     pub fn add_workspace(&mut self, revision: WorkspaceRevision) -> CollaborateResult<()> {
         let mut transaction = Transaction::new();
-        let workspace_node = WorkspaceNode::from_workspace_revision(
+        let node = WorkspaceNode::from_workspace_revision(
             &mut transaction,
             revision,
             self.tree.clone(),
             workspaces_path().clone_with(self.workspaces.len()),
         )?;
         let _ = self.tree.write().apply_transaction(transaction)?;
-        self.workspaces.push(Arc::new(workspace_node));
+        self.workspaces.push(Arc::new(node));
         Ok(())
     }
 

+ 51 - 0
shared-lib/flowy-sync/src/client_folder/folder_node_2.rs

@@ -0,0 +1,51 @@
+use crate::client_folder::workspace_node_2::WorkspaceNode2;
+use crate::errors::{CollaborateError, CollaborateResult};
+use flowy_derive::Node;
+use lib_ot::core::NodeTree;
+use lib_ot::core::*;
+use parking_lot::RwLock;
+use std::sync::Arc;
+
+pub type AtomicNodeTree = RwLock<NodeTree>;
+
+#[derive(Node)]
+#[node_type = "folder"]
+pub struct FolderNodePad2 {
+    tree: Arc<AtomicNodeTree>,
+    node_id: NodeId,
+    // name: workspaces, index of the node,
+    #[node(child_name = "child")]
+    children: Vec<Box<dyn ToNodeData>>,
+}
+
+impl FolderNodePad2 {
+    pub fn new() -> Self {
+        // let workspace_node = NodeDataBuilder::new("workspaces").build();
+        // let trash_node = NodeDataBuilder::new("trash").build();
+        // let folder_node = NodeDataBuilder::new("folder")
+        //     .add_node_data(workspace_node)
+        //     .add_node_data(trash_node)
+        //     .build();
+        //
+        // let operation = NodeOperation::Insert {
+        //     path: folder_path(),
+        //     nodes: vec![folder_node],
+        // };
+        // let mut tree = NodeTree::default();
+        // let _ = tree.apply_op(operation).unwrap();
+        //
+        // Self {
+        //     tree: Arc::new(RwLock::new(tree)),
+        //     workspaces: vec![],
+        //     trash: vec![],
+        // }
+        todo!()
+    }
+
+    pub fn to_json(&self, pretty: bool) -> CollaborateResult<String> {
+        self.tree
+            .read()
+            .to_json(pretty)
+            .map_err(|e| CollaborateError::serde().context(e))
+    }
+}

+ 2 - 0
shared-lib/flowy-sync/src/client_folder/mod.rs

@@ -1,7 +1,9 @@
 mod app_node;
 mod builder;
 mod folder_node;
+mod folder_node_2;
 mod folder_pad;
+mod util;
 mod view_node;
 mod workspace_node;
 mod workspace_node_2;

+ 54 - 0
shared-lib/flowy-sync/src/client_folder/util.rs

@@ -0,0 +1,54 @@
+use crate::client_folder::AtomicNodeTree;
+use crate::errors::CollaborateResult;
+use lib_ot::core::{AttributeHashMap, AttributeValue, Changeset, NodeId, NodeOperation};
+use std::sync::Arc;
+
+pub fn get_attributes_str_value(tree: Arc<AtomicNodeTree>, node_id: &NodeId, key: &str) -> Option<String> {
+    tree.read()
+        .get_node(node_id.clone())
+        .and_then(|node| node.attributes.get(key).cloned())
+        .and_then(|value| value.str_value())
+}
+
+pub fn set_attributes_str_value(
+    tree: Arc<AtomicNodeTree>,
+    node_id: &NodeId,
+    key: &str,
+    value: String,
+) -> CollaborateResult<()> {
+    let old_attributes = match get_attributes(tree.clone(), node_id) {
+        None => AttributeHashMap::new(),
+        Some(attributes) => attributes,
+    };
+    let mut new_attributes = old_attributes.clone();
+    new_attributes.insert(key, value);
+    let path = tree.read().path_from_node_id(node_id.clone());
+    let update_operation = NodeOperation::Update {
+        path,
+        changeset: Changeset::Attributes {
+            new: new_attributes,
+            old: old_attributes,
+        },
+    };
+    let _ = tree.write().apply_op(update_operation)?;
+    Ok(())
+}
+
+pub fn get_attributes_int_value(tree: Arc<AtomicNodeTree>, node_id: &NodeId, key: &str) -> Option<i64> {
+    tree.read()
+        .get_node(node_id.clone())
+        .and_then(|node| node.attributes.get(key).cloned())
+        .and_then(|value| value.int_value())
+}
+
+pub fn get_attributes(tree: Arc<AtomicNodeTree>, node_id: &NodeId) -> Option<AttributeHashMap> {
+    tree.read()
+        .get_node(node_id.clone())
+        .and_then(|node| Some(node.attributes.clone()))
+}
+
+pub fn get_attributes_value(tree: Arc<AtomicNodeTree>, node_id: &NodeId, key: &str) -> Option<AttributeValue> {
+    tree.read()
+        .get_node(node_id.clone())
+        .and_then(|node| node.attributes.get(key).cloned())
+}

+ 4 - 53
shared-lib/flowy-sync/src/client_folder/workspace_node_2.rs

@@ -1,3 +1,4 @@
+use crate::client_folder::util::*;
 use crate::client_folder::AtomicNodeTree;
 use crate::errors::CollaborateResult;
 use flowy_derive::Node;
@@ -8,7 +9,7 @@ use std::sync::Arc;
 #[node_type = "workspace"]
 pub struct WorkspaceNode2 {
     tree: Arc<AtomicNodeTree>,
-    path: Path,
+    node_id: NodeId,
 
     #[node(get_value_with = "get_attributes_str_value")]
     #[node(set_value_with = "set_attributes_str_value")]
@@ -22,7 +23,7 @@ pub struct WorkspaceNode2 {
     #[node(get_value_with = "get_attributes_int_value")]
     pub time: i64,
 
-    #[node(children)]
+    #[node(child_name = "app")]
     pub apps: Vec<AppNode2>,
 }
 
@@ -30,7 +31,7 @@ pub struct WorkspaceNode2 {
 #[node_type = "app"]
 pub struct AppNode2 {
     tree: Arc<AtomicNodeTree>,
-    path: Path,
+    node_id: NodeId,
 
     #[node(get_value_with = "get_attributes_str_value")]
     #[node(set_value_with = "set_attributes_str_value")]
@@ -40,53 +41,3 @@ pub struct AppNode2 {
     #[node(set_value_with = "set_attributes_str_value")]
     pub name: String,
 }
-
-pub fn get_attributes_str_value(tree: Arc<AtomicNodeTree>, path: &Path, key: &str) -> Option<String> {
-    tree.read()
-        .get_node_at_path(&path)
-        .and_then(|node| node.attributes.get(key).cloned())
-        .and_then(|value| value.str_value())
-}
-
-pub fn set_attributes_str_value(
-    tree: Arc<AtomicNodeTree>,
-    path: &Path,
-    key: &str,
-    value: String,
-) -> CollaborateResult<()> {
-    let old_attributes = match get_attributes(tree.clone(), path) {
-        None => AttributeHashMap::new(),
-        Some(attributes) => attributes,
-    };
-    let mut new_attributes = old_attributes.clone();
-    new_attributes.insert(key, value);
-
-    let update_operation = NodeOperation::Update {
-        path: path.clone(),
-        changeset: Changeset::Attributes {
-            new: new_attributes,
-            old: old_attributes,
-        },
-    };
-    let _ = tree.write().apply_op(update_operation)?;
-    Ok(())
-}
-
-pub fn get_attributes_int_value(tree: Arc<AtomicNodeTree>, path: &Path, key: &str) -> Option<i64> {
-    tree.read()
-        .get_node_at_path(&path)
-        .and_then(|node| node.attributes.get(key).cloned())
-        .and_then(|value| value.int_value())
-}
-
-pub fn get_attributes(tree: Arc<AtomicNodeTree>, path: &Path) -> Option<AttributeHashMap> {
-    tree.read()
-        .get_node_at_path(&path)
-        .and_then(|node| Some(node.attributes.clone()))
-}
-
-pub fn get_attributes_value(tree: Arc<AtomicNodeTree>, path: &Path, key: &str) -> Option<AttributeValue> {
-    tree.read()
-        .get_node_at_path(&path)
-        .and_then(|node| node.attributes.get(key).cloned())
-}

+ 9 - 0
shared-lib/lib-ot/src/core/node_tree/node.rs

@@ -10,6 +10,15 @@ pub trait ToNodeData: Send + Sync {
     fn to_node_data(&self) -> NodeData;
 }
 
+impl<T> ToNodeData for Box<T>
+where
+    T: ToNodeData,
+{
+    fn to_node_data(&self) -> NodeData {
+        (**self).to_node_data()
+    }
+}
+
 #[derive(Default, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
 pub struct NodeData {
     #[serde(rename = "type")]