feat: public the json to document data pb api (#2694)

* feat: public the json to document data pb api

* test: add test for convert_data_to_document_internal

* chore: apply review suggestion

* chore: update folder path
This commit is contained in:
Lucas.Xu 2023-06-03 20:43:46 +08:00 committed by GitHub
parent ee52bf4b0e
commit 561d0f0808
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 146 additions and 31 deletions

View File

@ -54,11 +54,11 @@ AppFlowyEnv getAppFlowyEnv() {
Future<Directory> appFlowyDocumentDirectory() async {
switch (integrationEnv()) {
case IntegrationMode.develop:
Directory documentsDir = await getApplicationDocumentsDirectory()
Directory documentsDir = await getApplicationSupportDirectory()
..create();
return Directory(path.join(documentsDir.path, 'data_dev')).create();
case IntegrationMode.release:
Directory documentsDir = await getApplicationDocumentsDirectory();
Directory documentsDir = await getApplicationSupportDirectory();
return Directory(path.join(documentsDir.path, 'data')).create();
case IntegrationMode.test:
return Directory(path.join(Directory.current.path, '.sandbox'));

View File

@ -1,5 +1,10 @@
{
"type": "page",
"data": {
"delta": [
{"insert": ""}
]
},
"children": [
{
"type": "heading",

View File

@ -10,7 +10,6 @@ use flowy_database2::entities::DatabaseLayoutPB;
use flowy_database2::services::share::csv::CSVFormat;
use flowy_database2::template::{make_default_board, make_default_calendar, make_default_grid};
use flowy_database2::DatabaseManager2;
use flowy_document2::document_data::default_document_data;
use flowy_document2::entities::DocumentDataPB;
use flowy_document2::manager::DocumentManager;
use flowy_document2::parser::json::parser::JsonToDocumentParser;
@ -105,7 +104,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
let json_str = include_str!("../../assets/read_me.json");
let document_pb = JsonToDocumentParser::json_str_to_document(json_str).unwrap();
manager
.create_document(view.parent_view.id.clone(), document_pb.into())
.create_document(view.parent_view.id.clone(), Some(document_pb.into()))
.unwrap();
view
})
@ -152,7 +151,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
let manager = self.0.clone();
FutureResult::new(async move {
let data = DocumentDataPB::try_from(Bytes::from(data))?;
manager.create_document(view_id, data.into())?;
manager.create_document(view_id, Some(data.into()))?;
Ok(())
})
}
@ -169,7 +168,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
let view_id = view_id.to_string();
let manager = self.0.clone();
FutureResult::new(async move {
manager.create_document(view_id, default_document_data())?;
manager.create_document(view_id, None)?;
Ok(())
})
}
@ -184,7 +183,7 @@ impl FolderOperationHandler for DocumentFolderOperation {
let manager = self.0.clone();
FutureResult::new(async move {
let data = DocumentDataPB::try_from(Bytes::from(bytes))?;
manager.create_document(view_id, data.into())?;
manager.create_document(view_id, Some(data.into()))?;
Ok(())
})
}

View File

@ -0,0 +1,2 @@
pub const PAGE: &str = "page";
pub const PARAGRAPH_BLOCK_TYPE: &str = "paragraph";

View File

@ -3,7 +3,10 @@ use std::{collections::HashMap, vec};
use collab_document::blocks::{Block, DocumentData, DocumentMeta};
use nanoid::nanoid;
use crate::entities::{BlockPB, ChildrenPB, DocumentDataPB, MetaPB};
use crate::{
document_block_keys::{PAGE, PARAGRAPH_BLOCK_TYPE},
entities::{BlockPB, ChildrenPB, DocumentDataPB, MetaPB},
};
impl From<DocumentData> for DocumentDataPB {
fn from(data: DocumentData) -> Self {
@ -58,8 +61,8 @@ impl From<DocumentDataPB> for DocumentData {
/// The default document data.
/// The default document data is a document with a page block and a text block.
pub fn default_document_data() -> DocumentData {
let page_type = "page".to_string();
let text_type = "text".to_string();
let page_type = PAGE.to_string();
let text_type = PARAGRAPH_BLOCK_TYPE.to_string();
let mut blocks: HashMap<String, Block> = HashMap::new();
let mut meta: HashMap<String, Vec<String>> = HashMap::new();

View File

@ -203,3 +203,36 @@ pub struct ExportDataPB {
#[pb(index = 2)]
pub export_type: ExportType,
}
#[derive(PartialEq, Eq, Debug, ProtoBuf_Enum, Clone)]
pub enum ConvertType {
Json = 0,
}
impl Default for ConvertType {
fn default() -> Self {
ConvertType::Json
}
}
impl From<i32> for ConvertType {
fn from(val: i32) -> Self {
match val {
0 => ConvertType::Json,
_ => {
tracing::error!("Invalid export type: {}", val);
ConvertType::Json
},
}
}
}
/// for the json type
/// the data is the json string
#[derive(Default, ProtoBuf, Debug)]
pub struct ConvertDataPayloadPB {
#[pb(index = 1)]
pub convert_type: ConvertType,
#[pb(index = 2)]
pub data: Vec<u8>,
}

View File

@ -8,20 +8,20 @@ use std::sync::Arc;
use collab_document::blocks::{
json_str_to_hashmap, Block, BlockAction, BlockActionPayload, BlockActionType, BlockEvent,
BlockEventPayload, DeltaType, DocumentData,
BlockEventPayload, DeltaType,
};
use flowy_error::{FlowyError, FlowyResult};
use lib_dispatch::prelude::{data_result_ok, AFPluginData, AFPluginState, DataResult};
use crate::document_data::default_document_data;
use crate::{
entities::{
ApplyActionPayloadPB, BlockActionPB, BlockActionPayloadPB, BlockActionTypePB, BlockEventPB,
BlockEventPayloadPB, BlockPB, CloseDocumentPayloadPB, CreateDocumentPayloadPB, DeltaTypePB,
DocEventPB, DocumentDataPB, OpenDocumentPayloadPB,
BlockEventPayloadPB, BlockPB, CloseDocumentPayloadPB, ConvertDataPayloadPB, ConvertType,
CreateDocumentPayloadPB, DeltaTypePB, DocEventPB, DocumentDataPB, OpenDocumentPayloadPB,
},
manager::DocumentManager,
parser::json::parser::JsonToDocumentParser,
};
// Handler for creating a new document
@ -30,10 +30,7 @@ pub(crate) async fn create_document_handler(
manager: AFPluginState<Arc<DocumentManager>>,
) -> FlowyResult<()> {
let data = data.into_inner();
let initial_data = data
.initial_data
.map(|data| DocumentData::from(data))
.unwrap_or_else(default_document_data);
let initial_data = data.initial_data.map(|data| data.into());
manager.create_document(data.document_id, initial_data)?;
Ok(())
}
@ -83,6 +80,29 @@ pub(crate) async fn apply_action_handler(
Ok(())
}
pub(crate) async fn convert_data_to_document(
data: AFPluginData<ConvertDataPayloadPB>,
_manager: AFPluginState<Arc<DocumentManager>>,
) -> DataResult<DocumentDataPB, FlowyError> {
let payload = data.into_inner();
let document = convert_data_to_document_internal(payload)?;
data_result_ok(document)
}
pub fn convert_data_to_document_internal(
payload: ConvertDataPayloadPB,
) -> Result<DocumentDataPB, FlowyError> {
let convert_type = payload.convert_type;
let data = payload.data;
match convert_type {
ConvertType::Json => {
let json_str = String::from_utf8(data).map_err(|_| FlowyError::invalid_data())?;
let document = JsonToDocumentParser::json_str_to_document(&json_str)?;
Ok(document)
},
}
}
impl From<BlockActionPB> for BlockAction {
fn from(pb: BlockActionPB) -> Self {
Self {

View File

@ -6,8 +6,8 @@ use lib_dispatch::prelude::AFPlugin;
use crate::{
event_handler::{
apply_action_handler, close_document_handler, create_document_handler,
get_document_data_handler, open_document_handler,
apply_action_handler, close_document_handler, convert_data_to_document,
create_document_handler, get_document_data_handler, open_document_handler,
},
manager::DocumentManager,
};
@ -22,6 +22,10 @@ pub fn init(document_manager: Arc<DocumentManager>) -> AFPlugin {
plugin = plugin.event(DocumentEvent::CloseDocument, close_document_handler);
plugin = plugin.event(DocumentEvent::ApplyAction, apply_action_handler);
plugin = plugin.event(DocumentEvent::GetDocumentData, get_document_data_handler);
plugin = plugin.event(
DocumentEvent::ConvertDataToDocument,
convert_data_to_document,
);
plugin
}
@ -43,4 +47,7 @@ pub enum DocumentEvent {
#[event(input = "GetDocumentDataPayloadPB")]
GetDocumentData = 4,
#[event(input = "ConvertDataPayloadPB", output = "DocumentDataPB")]
ConvertDataToDocument = 5,
}

View File

@ -1,10 +1,11 @@
pub mod document;
pub mod document_block_keys;
pub mod document_data;
pub mod entities;
pub mod event_handler;
pub mod event_map;
pub mod manager;
pub mod parser;
pub mod protobuf;
mod event_handler;
mod notification;

View File

@ -9,6 +9,7 @@ use flowy_error::{FlowyError, FlowyResult};
use crate::{
document::Document,
document_data::default_document_data,
entities::DocEventPB,
notification::{send_notification, DocumentNotification},
};
@ -34,11 +35,20 @@ impl DocumentManager {
}
}
pub fn create_document(&self, doc_id: String, data: DocumentData) -> FlowyResult<Arc<Document>> {
/// Create a new document.
///
/// if the document already exists, return the existing document.
/// if the data is None, will create a document with default data.
pub fn create_document(
&self,
doc_id: String,
data: Option<DocumentData>,
) -> FlowyResult<Arc<Document>> {
tracing::debug!("create a document: {:?}", &doc_id);
let uid = self.user.user_id()?;
let db = self.user.collab_db()?;
let collab = self.collab_builder.build(uid, &doc_id, "document", db);
let data = data.unwrap_or_else(|| default_document_data());
let document = Arc::new(Document::create_with_data(collab, data)?);
Ok(document)
}

View File

@ -2,6 +2,7 @@ use std::{collections::HashMap, sync::Arc, vec};
use crate::document::util::default_collab_builder;
use collab_document::blocks::{Block, BlockAction, BlockActionPayload, BlockActionType};
use flowy_document2::document_block_keys::PARAGRAPH_BLOCK_TYPE;
use flowy_document2::document_data::default_document_data;
use flowy_document2::{document::Document, manager::DocumentManager};
use nanoid::nanoid;
@ -16,7 +17,7 @@ fn document_apply_insert_block_with_empty_parent_id() {
let text_block_id = nanoid!(10);
let text_block = Block {
id: text_block_id.clone(),
ty: "text".to_string(),
ty: PARAGRAPH_BLOCK_TYPE.to_string(),
parent: "".to_string(),
children: nanoid!(10),
external_id: None,
@ -47,7 +48,7 @@ fn create_and_open_empty_document() -> (DocumentManager, Arc<Document>, String)
// create a document
_ = manager
.create_document(doc_id.clone(), data.clone())
.create_document(doc_id.clone(), Some(data.clone()))
.unwrap();
let document = manager.open_document(doc_id).unwrap();

View File

@ -1,6 +1,7 @@
use std::{collections::HashMap, sync::Arc, vec};
use collab_document::blocks::{Block, BlockAction, BlockActionPayload, BlockActionType};
use flowy_document2::document_block_keys::PARAGRAPH_BLOCK_TYPE;
use nanoid::nanoid;
use serde_json::{json, to_value, Value};
@ -19,7 +20,7 @@ fn restore_document() {
let doc_id: String = nanoid!(10);
let data = default_document_data();
let document_a = manager
.create_document(doc_id.clone(), data.clone())
.create_document(doc_id.clone(), Some(data.clone()))
.unwrap();
let data_a = document_a.lock().get_document().unwrap();
assert_eq!(data_a, data);
@ -36,7 +37,7 @@ fn restore_document() {
assert_eq!(data_b, data);
// restore
_ = manager.create_document(doc_id.clone(), data.clone());
_ = manager.create_document(doc_id.clone(), Some(data.clone()));
// open a document
let data_b = manager
.open_document(doc_id.clone())
@ -59,7 +60,7 @@ fn document_apply_insert_action() {
let data = default_document_data();
// create a document
_ = manager.create_document(doc_id.clone(), data.clone());
_ = manager.create_document(doc_id.clone(), Some(data.clone()));
// open a document
let document = manager.open_document(doc_id.clone()).unwrap();
@ -68,7 +69,7 @@ fn document_apply_insert_action() {
// insert a text block
let text_block = Block {
id: nanoid!(10),
ty: "text".to_string(),
ty: PARAGRAPH_BLOCK_TYPE.to_string(),
parent: page_block.id,
children: nanoid!(10),
external_id: None,
@ -110,7 +111,7 @@ fn document_apply_update_page_action() {
let data = default_document_data();
// create a document
_ = manager.create_document(doc_id.clone(), data.clone());
_ = manager.create_document(doc_id.clone(), Some(data.clone()));
// open a document
let document = manager.open_document(doc_id.clone()).unwrap();
@ -152,7 +153,7 @@ fn document_apply_update_action() {
let data = default_document_data();
// create a document
_ = manager.create_document(doc_id.clone(), data.clone());
_ = manager.create_document(doc_id.clone(), Some(data.clone()));
// open a document
let document = manager.open_document(doc_id.clone()).unwrap();
@ -162,7 +163,7 @@ fn document_apply_update_action() {
let text_block_id = nanoid!(10);
let text_block = Block {
id: text_block_id.clone(),
ty: "text".to_string(),
ty: PARAGRAPH_BLOCK_TYPE.to_string(),
parent: page_block.id,
children: nanoid!(10),
external_id: None,

View File

@ -0,0 +1,32 @@
use flowy_document2::{
entities::{ConvertDataPayloadPB, ConvertType},
event_handler::convert_data_to_document_internal,
};
#[test]
fn convert_json_to_document() {
let json_str = r#"
{
"type": "page",
"children": [
{
"type": "paragraph1"
}
]
}"#;
let payload = ConvertDataPayloadPB {
convert_type: ConvertType::Json,
data: json_str.as_bytes().to_vec(),
};
let document_data = convert_data_to_document_internal(payload).unwrap();
let page_id = document_data.page_id;
let blocks = document_data.blocks;
let children_map = document_data.meta.children_map;
let page_block = blocks.get(&page_id).unwrap();
let page_children = children_map.get(&page_block.children_id).unwrap();
assert_eq!(page_children.children.len(), 1);
let paragraph1 = blocks.get(page_children.children.get(0).unwrap()).unwrap();
assert_eq!(paragraph1.ty, "paragraph1");
assert_eq!(paragraph1.parent_id, page_block.id);
}

View File

@ -1,3 +1,4 @@
mod document_insert_test;
mod document_test;
mod event_handler_test;
mod util;