mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-28 08:10:38 +00:00
chore: implement folder
This commit is contained in:
parent
81dd353d12
commit
aca9b81c79
@ -123,7 +123,9 @@ pub struct ASTField<'a> {
|
|||||||
pub node_attrs: NodeStructAttrs,
|
pub node_attrs: NodeStructAttrs,
|
||||||
pub ty: &'a syn::Type,
|
pub ty: &'a syn::Type,
|
||||||
pub original: &'a syn::Field,
|
pub original: &'a syn::Field,
|
||||||
|
// If the field is Vec<String>, then the bracket_ty will be Vec
|
||||||
pub bracket_ty: Option<syn::Ident>,
|
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_inner_ty: Option<syn::Ident>,
|
||||||
pub bracket_category: Option<BracketCategory>,
|
pub bracket_category: Option<BracketCategory>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,8 +11,9 @@ use syn::{
|
|||||||
|
|
||||||
pub struct NodeStructAttrs {
|
pub struct NodeStructAttrs {
|
||||||
pub rename: Option<LitStr>,
|
pub rename: Option<LitStr>,
|
||||||
pub is_children: bool,
|
pub has_child: bool,
|
||||||
node_index: Option<syn::LitInt>,
|
pub child_name: Option<LitStr>,
|
||||||
|
pub child_index: Option<syn::LitInt>,
|
||||||
get_node_value_with: Option<syn::ExprPath>,
|
get_node_value_with: Option<syn::ExprPath>,
|
||||||
set_node_value_with: Option<syn::ExprPath>,
|
set_node_value_with: Option<syn::ExprPath>,
|
||||||
}
|
}
|
||||||
@ -20,9 +21,9 @@ pub struct NodeStructAttrs {
|
|||||||
impl NodeStructAttrs {
|
impl NodeStructAttrs {
|
||||||
/// Extract out the `#[node(...)]` attributes from a struct field.
|
/// Extract out the `#[node(...)]` attributes from a struct field.
|
||||||
pub fn from_ast(ast_result: &ASTResult, index: usize, field: &syn::Field) -> Self {
|
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, RENAME_NODE);
|
||||||
let mut rename = ASTAttr::none(ast_result, NODE_RENAME);
|
let mut child_name = ASTAttr::none(ast_result, CHILD_NODE_NAME);
|
||||||
let mut is_children = ASTAttr::none(ast_result, NODE_CHILDREN);
|
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 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);
|
let mut set_node_value_with = ASTAttr::none(ast_result, SET_NODE_VALUE_WITH);
|
||||||
|
|
||||||
@ -33,25 +34,27 @@ impl NodeStructAttrs {
|
|||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
match &meta_item {
|
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(children)]'
|
|
||||||
Meta(Path(path)) if path == NODE_CHILDREN => {
|
|
||||||
eprintln!("😄 {:?}", path);
|
|
||||||
is_children.set(path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse '#[node(rename = x)]'
|
// Parse '#[node(rename = x)]'
|
||||||
Meta(NameValue(m)) if m.path == NODE_RENAME => {
|
Meta(NameValue(m)) if m.path == RENAME_NODE => {
|
||||||
if let syn::Lit::Str(lit) = &m.lit {
|
if let syn::Lit::Str(lit) = &m.lit {
|
||||||
rename.set(&m.path, lit.clone());
|
rename.set(&m.path, lit.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(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 = "...")]`
|
// Parse `#[node(get_node_value_with = "...")]`
|
||||||
Meta(NameValue(m)) if m.path == 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) {
|
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 {
|
NodeStructAttrs {
|
||||||
rename: rename.get(),
|
rename: rename.get(),
|
||||||
node_index: node_index.get(),
|
child_index: child_index.get(),
|
||||||
is_children: is_children.get().unwrap_or(false),
|
has_child: child_name.is_some(),
|
||||||
|
child_name,
|
||||||
get_node_value_with: get_node_value_with.get(),
|
get_node_value_with: get_node_value_with.get(),
|
||||||
set_node_value_with: set_node_value_with.get(),
|
set_node_value_with: set_node_value_with.get(),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,8 +37,9 @@ pub const NODE_ATTRS: Symbol = Symbol("node");
|
|||||||
pub const NODES_ATTRS: Symbol = Symbol("nodes");
|
pub const NODES_ATTRS: Symbol = Symbol("nodes");
|
||||||
pub const NODE_TYPE: Symbol = Symbol("node_type");
|
pub const NODE_TYPE: Symbol = Symbol("node_type");
|
||||||
pub const NODE_INDEX: Symbol = Symbol("index");
|
pub const NODE_INDEX: Symbol = Symbol("index");
|
||||||
pub const NODE_RENAME: Symbol = Symbol("rename");
|
pub const RENAME_NODE: Symbol = Symbol("rename");
|
||||||
pub const NODE_CHILDREN: Symbol = Symbol("children");
|
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 SKIP_NODE_ATTRS: Symbol = Symbol("skip_node_attribute");
|
||||||
pub const GET_NODE_VALUE_WITH: Symbol = Symbol("get_value_with");
|
pub const GET_NODE_VALUE_WITH: Symbol = Symbol("get_value_with");
|
||||||
pub const SET_NODE_VALUE_WITH: Symbol = Symbol("set_value_with");
|
pub const SET_NODE_VALUE_WITH: Symbol = Symbol("set_value_with");
|
||||||
|
|||||||
@ -9,18 +9,98 @@ pub fn expand_derive(input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::E
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut token_stream: TokenStream = TokenStream::default();
|
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));
|
token_stream.extend(make_to_node_data_token_stream(&cont));
|
||||||
|
|
||||||
if let Some(get_value_token_stream) = make_get_set_value_token_steam(&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(get_value_token_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token_stream.extend(make_alter_children_token_stream(&ast_result, &cont));
|
||||||
ast_result.check()?;
|
ast_result.check()?;
|
||||||
Ok(token_stream)
|
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 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
|
token_streams
|
||||||
}
|
}
|
||||||
@ -35,7 +115,7 @@ pub fn make_to_node_data_token_stream(ast: &ASTContainer) -> TokenStream {
|
|||||||
let set_key_values = ast
|
let set_key_values = ast
|
||||||
.data
|
.data
|
||||||
.all_fields()
|
.all_fields()
|
||||||
.filter(|field| !field.node_attrs.is_children)
|
.filter(|field| !field.node_attrs.has_child)
|
||||||
.flat_map(|field| {
|
.flat_map(|field| {
|
||||||
let mut field_name = field.name().expect("the name of the field should not be empty");
|
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");
|
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
|
let children_fields = ast
|
||||||
.data
|
.data
|
||||||
.all_fields()
|
.all_fields()
|
||||||
.filter(|field| field.node_attrs.is_children)
|
.filter(|field| field.node_attrs.has_child)
|
||||||
.collect::<Vec<&ASTField>>();
|
.collect::<Vec<&ASTField>>();
|
||||||
|
|
||||||
let childrens_token_streams = match children_fields.is_empty() {
|
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! {
|
token_streams.extend(quote! {
|
||||||
impl #struct_ident {
|
impl ToNodeData for #struct_ident {
|
||||||
pub fn to_node_data(&self) -> NodeData {
|
fn to_node_data(&self) -> NodeData {
|
||||||
#childrens_token_streams
|
#childrens_token_streams
|
||||||
|
|
||||||
let builder = NodeDataBuilder::new(#node_type)
|
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");
|
let tree = format_ident!("tree");
|
||||||
for field in ast.data.all_fields() {
|
for field in ast.data.all_fields() {
|
||||||
if field.node_attrs.is_children {
|
if field.node_attrs.has_child {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +193,7 @@ pub fn make_get_set_value_token_steam(ast: &ASTContainer) -> Option<TokenStream>
|
|||||||
token_streams.extend(quote! {
|
token_streams.extend(quote! {
|
||||||
impl #struct_ident {
|
impl #struct_ident {
|
||||||
pub fn #get_func_name(&self) -> Option<#get_value_return_ty> {
|
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! {
|
token_streams.extend(quote! {
|
||||||
impl #struct_ident {
|
impl #struct_ident {
|
||||||
pub fn #set_func_name(&self, value: #set_value_input_ty) {
|
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)
|
Some(token_streams)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,42 +11,6 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
pub type AtomicNodeTree = RwLock<NodeTree>;
|
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 {
|
pub struct FolderNodePad {
|
||||||
tree: Arc<AtomicNodeTree>,
|
tree: Arc<AtomicNodeTree>,
|
||||||
// name: workspaces, index of the node,
|
// name: workspaces, index of the node,
|
||||||
@ -71,31 +35,29 @@ impl FolderNodePad {
|
|||||||
|
|
||||||
pub fn remove_workspace(&mut self, workspace_id: &str) {
|
pub fn remove_workspace(&mut self, workspace_id: &str) {
|
||||||
if let Some(workspace) = self.workspaces.iter().find(|workspace| workspace.id == workspace_id) {
|
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 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);
|
nodes.push(node_data);
|
||||||
}
|
}
|
||||||
let delete_operation = NodeOperation::Delete {
|
let _ = write_guard.apply_op(NodeOperation::Delete {
|
||||||
path: workspace.path.clone(),
|
path: workspace.path.clone(),
|
||||||
nodes,
|
nodes,
|
||||||
};
|
});
|
||||||
let _ = self.tree.write().apply_op(delete_operation);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_workspace(&mut self, revision: WorkspaceRevision) -> CollaborateResult<()> {
|
pub fn add_workspace(&mut self, revision: WorkspaceRevision) -> CollaborateResult<()> {
|
||||||
let mut transaction = Transaction::new();
|
let mut transaction = Transaction::new();
|
||||||
let workspace_node = WorkspaceNode::from_workspace_revision(
|
let node = WorkspaceNode::from_workspace_revision(
|
||||||
&mut transaction,
|
&mut transaction,
|
||||||
revision,
|
revision,
|
||||||
self.tree.clone(),
|
self.tree.clone(),
|
||||||
workspaces_path().clone_with(self.workspaces.len()),
|
workspaces_path().clone_with(self.workspaces.len()),
|
||||||
)?;
|
)?;
|
||||||
let _ = self.tree.write().apply_transaction(transaction)?;
|
let _ = self.tree.write().apply_transaction(transaction)?;
|
||||||
self.workspaces.push(Arc::new(workspace_node));
|
self.workspaces.push(Arc::new(node));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
shared-lib/flowy-sync/src/client_folder/folder_node_2.rs
Normal file
51
shared-lib/flowy-sync/src/client_folder/folder_node_2.rs
Normal file
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
mod app_node;
|
mod app_node;
|
||||||
mod builder;
|
mod builder;
|
||||||
mod folder_node;
|
mod folder_node;
|
||||||
|
mod folder_node_2;
|
||||||
mod folder_pad;
|
mod folder_pad;
|
||||||
|
mod util;
|
||||||
mod view_node;
|
mod view_node;
|
||||||
mod workspace_node;
|
mod workspace_node;
|
||||||
mod workspace_node_2;
|
mod workspace_node_2;
|
||||||
|
|||||||
54
shared-lib/flowy-sync/src/client_folder/util.rs
Normal file
54
shared-lib/flowy-sync/src/client_folder/util.rs
Normal file
@ -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())
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::client_folder::util::*;
|
||||||
use crate::client_folder::AtomicNodeTree;
|
use crate::client_folder::AtomicNodeTree;
|
||||||
use crate::errors::CollaborateResult;
|
use crate::errors::CollaborateResult;
|
||||||
use flowy_derive::Node;
|
use flowy_derive::Node;
|
||||||
@ -8,7 +9,7 @@ use std::sync::Arc;
|
|||||||
#[node_type = "workspace"]
|
#[node_type = "workspace"]
|
||||||
pub struct WorkspaceNode2 {
|
pub struct WorkspaceNode2 {
|
||||||
tree: Arc<AtomicNodeTree>,
|
tree: Arc<AtomicNodeTree>,
|
||||||
path: Path,
|
node_id: NodeId,
|
||||||
|
|
||||||
#[node(get_value_with = "get_attributes_str_value")]
|
#[node(get_value_with = "get_attributes_str_value")]
|
||||||
#[node(set_value_with = "set_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")]
|
#[node(get_value_with = "get_attributes_int_value")]
|
||||||
pub time: i64,
|
pub time: i64,
|
||||||
|
|
||||||
#[node(children)]
|
#[node(child_name = "app")]
|
||||||
pub apps: Vec<AppNode2>,
|
pub apps: Vec<AppNode2>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ pub struct WorkspaceNode2 {
|
|||||||
#[node_type = "app"]
|
#[node_type = "app"]
|
||||||
pub struct AppNode2 {
|
pub struct AppNode2 {
|
||||||
tree: Arc<AtomicNodeTree>,
|
tree: Arc<AtomicNodeTree>,
|
||||||
path: Path,
|
node_id: NodeId,
|
||||||
|
|
||||||
#[node(get_value_with = "get_attributes_str_value")]
|
#[node(get_value_with = "get_attributes_str_value")]
|
||||||
#[node(set_value_with = "set_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")]
|
#[node(set_value_with = "set_attributes_str_value")]
|
||||||
pub name: String,
|
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())
|
|
||||||
}
|
|
||||||
|
|||||||
@ -10,6 +10,15 @@ pub trait ToNodeData: Send + Sync {
|
|||||||
fn to_node_data(&self) -> NodeData;
|
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)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
pub struct NodeData {
|
pub struct NodeData {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user