mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
ee52bf4b0e
commit
561d0f0808
@ -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'));
|
||||
|
@ -1,5 +1,10 @@
|
||||
{
|
||||
"type": "page",
|
||||
"data": {
|
||||
"delta": [
|
||||
{"insert": ""}
|
||||
]
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "heading",
|
||||
|
@ -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(())
|
||||
})
|
||||
}
|
||||
|
@ -0,0 +1,2 @@
|
||||
pub const PAGE: &str = "page";
|
||||
pub const PARAGRAPH_BLOCK_TYPE: &str = "paragraph";
|
@ -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();
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
mod document_insert_test;
|
||||
mod document_test;
|
||||
mod event_handler_test;
|
||||
mod util;
|
||||
|
Loading…
Reference in New Issue
Block a user