feat: Data sync on signup (#3283)

* chore: sync all data

* chore: sync database row and document in the row

* chore: sync inline view id

* chore: sync row and document in row

* fix: tests

* fix: migrate document in row

* chore: retry when create collab fail

* fix: invalid secret cause rerun application

* chore: fix clippy warnnings
This commit is contained in:
Nathan.fooo
2023-08-28 13:28:24 +08:00
committed by GitHub
parent 41ec2d992e
commit 4e67282f2b
66 changed files with 1492 additions and 513 deletions

View File

@ -1,6 +1,6 @@
use collab::core::collab_state::SyncState;
use collab_database::rows::RowId;
use collab_database::user::DatabaseRecord;
use collab_database::user::DatabaseWithViews;
use collab_database::views::DatabaseLayout;
use flowy_derive::ProtoBuf;
@ -197,8 +197,8 @@ pub struct DatabaseDescriptionPB {
pub database_id: String,
}
impl From<DatabaseRecord> for DatabaseDescriptionPB {
fn from(data: DatabaseRecord) -> Self {
impl From<DatabaseWithViews> for DatabaseDescriptionPB {
fn from(data: DatabaseWithViews) -> Self {
Self {
name: data.name,
database_id: data.database_id,

View File

@ -94,11 +94,7 @@ impl std::convert::From<GroupData> for GroupPB {
field_id: group_data.field_id,
group_id: group_data.id,
group_name: group_data.name,
rows: group_data
.rows
.into_iter()
.map(|row_detail| RowMetaPB::from(row_detail.meta))
.collect(),
rows: group_data.rows.into_iter().map(RowMetaPB::from).collect(),
is_default: group_data.is_default,
is_visible: group_data.is_visible,
}

View File

@ -1,6 +1,6 @@
use std::collections::HashMap;
use collab_database::rows::{Row, RowId, RowMeta};
use collab_database::rows::{Row, RowDetail, RowId};
use collab_database::views::RowOrder;
use flowy_derive::ProtoBuf;
@ -61,27 +61,27 @@ pub struct RowMetaPB {
pub cover: Option<String>,
}
impl std::convert::From<&RowMeta> for RowMetaPB {
fn from(row_meta: &RowMeta) -> Self {
impl std::convert::From<&RowDetail> for RowMetaPB {
fn from(row_detail: &RowDetail) -> Self {
Self {
id: row_meta.row_id.clone(),
document_id: row_meta.document_id.clone(),
icon: row_meta.icon_url.clone(),
cover: row_meta.cover_url.clone(),
id: row_detail.row.id.to_string(),
document_id: row_detail.document_id.clone(),
icon: row_detail.meta.icon_url.clone(),
cover: row_detail.meta.cover_url.clone(),
}
}
}
impl std::convert::From<RowMeta> for RowMetaPB {
fn from(row_meta: RowMeta) -> Self {
impl std::convert::From<RowDetail> for RowMetaPB {
fn from(row_detail: RowDetail) -> Self {
Self {
id: row_meta.row_id,
document_id: row_meta.document_id,
icon: row_meta.icon_url,
cover: row_meta.cover_url,
id: row_detail.row.id.to_string(),
document_id: row_detail.document_id,
icon: row_detail.meta.icon_url,
cover: row_detail.meta.cover_url,
}
}
}
//
#[derive(Debug, Default, Clone, ProtoBuf)]
pub struct UpdateRowMetaChangesetPB {
@ -251,7 +251,7 @@ impl std::convert::From<RowMetaPB> for InsertedRowPB {
impl From<InsertedRow> for InsertedRowPB {
fn from(data: InsertedRow) -> Self {
Self {
row_meta: data.row_meta.into(),
row_meta: data.row_detail.into(),
index: data.index,
is_new: data.is_new,
}
@ -274,7 +274,7 @@ pub struct UpdatedRowPB {
impl From<UpdatedRow> for UpdatedRowPB {
fn from(data: UpdatedRow) -> Self {
let row_meta = data.row_meta.map(RowMetaPB::from);
let row_meta = data.row_detail.map(RowMetaPB::from);
Self {
row_id: data.row_id,
field_ids: data.field_ids,

View File

@ -88,7 +88,7 @@ impl From<RowDetail> for DidFetchRowPB {
visibility: value.row.visibility,
created_at: value.row.created_at,
modified_at: value.row.modified_at,
meta: RowMetaPB::from(value.meta),
meta: RowMetaPB::from(value),
}
}
}

View File

@ -461,7 +461,7 @@ pub(crate) async fn create_row_handler(
.await?
{
None => Err(FlowyError::internal().with_context("Create row fail")),
Some(row) => data_result_ok(RowMetaPB::from(row.meta)),
Some(row) => data_result_ok(RowMetaPB::from(row)),
}
}

View File

@ -76,7 +76,7 @@ impl DatabaseManager {
&self,
uid: i64,
_workspace_id: String,
database_storage_id: String,
database_views_aggregate_id: String,
) -> FlowyResult<()> {
let collab_db = self.user.collab_db(uid)?;
let collab_builder = UserDatabaseCollabServiceImpl {
@ -87,11 +87,11 @@ impl DatabaseManager {
let mut collab_raw_data = CollabRawData::default();
// If the workspace database not exist in disk, try to fetch from remote.
if !self.is_collab_exist(uid, &collab_db, &database_storage_id) {
if !self.is_collab_exist(uid, &collab_db, &database_views_aggregate_id) {
tracing::trace!("workspace database not exist, try to fetch from remote");
match self
.cloud_service
.get_collab_update(&database_storage_id, CollabType::WorkspaceDatabase)
.get_collab_update(&database_views_aggregate_id, CollabType::WorkspaceDatabase)
.await
{
Ok(updates) => {
@ -100,17 +100,17 @@ impl DatabaseManager {
Err(err) => {
return Err(FlowyError::record_not_found().with_context(format!(
"get workspace database :{} failed: {}",
database_storage_id, err,
database_views_aggregate_id, err,
)));
},
}
}
// Construct the workspace database.
tracing::trace!("open workspace database: {}", &database_storage_id);
tracing::trace!("open workspace database: {}", &database_views_aggregate_id);
let collab = collab_builder.build_collab_with_config(
uid,
&database_storage_id,
&database_views_aggregate_id,
CollabType::WorkspaceDatabase,
collab_db.clone(),
collab_raw_data,
@ -130,10 +130,10 @@ impl DatabaseManager {
&self,
user_id: i64,
workspace_id: String,
database_storage_id: String,
database_views_aggregate_id: String,
) -> FlowyResult<()> {
self
.initialize(user_id, workspace_id, database_storage_id)
.initialize(user_id, workspace_id, database_views_aggregate_id)
.await?;
Ok(())
}

View File

@ -411,8 +411,8 @@ impl DatabaseEditor {
pub async fn move_row(&self, view_id: &str, from: RowId, to: RowId) {
let database = self.database.lock();
if let (Some(row_meta), Some(from_index), Some(to_index)) = (
database.get_row_meta(&from),
if let (Some(row_detail), Some(from_index), Some(to_index)) = (
database.get_row_detail(&from),
database.index_of_row(view_id, &from),
database.index_of_row(view_id, &to),
) {
@ -422,7 +422,7 @@ impl DatabaseEditor {
drop(database);
let delete_row_id = from.into_inner();
let insert_row = InsertedRowPB::new(RowMetaPB::from(&row_meta)).with_index(to_index as i32);
let insert_row = InsertedRowPB::new(RowMetaPB::from(row_detail)).with_index(to_index as i32);
let changes = RowsChangePB::from_move(vec![delete_row_id], vec![insert_row]);
send_notification(view_id, DatabaseNotification::DidUpdateViewRows)
.payload(changes)
@ -442,10 +442,8 @@ impl DatabaseEditor {
let result = self.database.lock().create_row_in_view(view_id, params);
if let Some((index, row_order)) = result {
tracing::trace!("create row: {:?} at {}", row_order, index);
let row = self.database.lock().get_row(&row_order.id);
let row_meta = self.database.lock().get_row_meta(&row_order.id);
if let Some(meta) = row_meta {
let row_detail = RowDetail { row, meta };
let row_detail = self.database.lock().get_row_detail(&row_order.id);
if let Some(row_detail) = row_detail {
for view in self.database_views.editors().await {
view.v_did_create_row(&row_detail, &group_id, index).await;
}
@ -545,9 +543,10 @@ impl DatabaseEditor {
pub fn get_row_meta(&self, view_id: &str, row_id: &RowId) -> Option<RowMetaPB> {
if self.database.lock().views.is_row_exist(view_id, row_id) {
let row_meta = self.database.lock().get_row_meta(row_id)?;
let row_document_id = self.database.lock().get_row_document_id(row_id)?;
Some(RowMetaPB {
id: row_id.clone().into_inner(),
document_id: row_meta.document_id,
document_id: row_document_id,
icon: row_meta.icon_url,
cover: row_meta.cover_url,
})
@ -559,9 +558,7 @@ impl DatabaseEditor {
pub fn get_row_detail(&self, view_id: &str, row_id: &RowId) -> Option<RowDetail> {
if self.database.lock().views.is_row_exist(view_id, row_id) {
let meta = self.database.lock().get_row_meta(row_id)?;
let row = self.database.lock().get_row(row_id);
Some(RowDetail { row, meta })
self.database.lock().get_row_detail(row_id)
} else {
tracing::warn!("the row:{} is exist in view:{}", row_id.as_str(), view_id);
None
@ -587,15 +584,15 @@ impl DatabaseEditor {
});
// Use the temporary row meta to get rid of the lock that not implement the `Send` or 'Sync' trait.
let row_meta = self.database.lock().get_row_meta(row_id);
if let Some(row_meta) = row_meta {
let row_detail = self.database.lock().get_row_detail(row_id);
if let Some(row_detail) = row_detail {
for view in self.database_views.editors().await {
view.v_did_update_row_meta(row_id, &row_meta).await;
view.v_did_update_row_meta(row_id, &row_detail).await;
}
// Notifies the client that the row meta has been updated.
send_notification(row_id.as_str(), DatabaseNotification::DidUpdateRowMeta)
.payload(RowMetaPB::from(&row_meta))
.payload(RowMetaPB::from(&row_detail))
.send();
}
}
@ -1084,7 +1081,7 @@ impl DatabaseEditor {
let rows = rows
.into_iter()
.map(|row_detail| RowMetaPB::from(&row_detail.meta))
.map(|row_detail| RowMetaPB::from(row_detail.as_ref()))
.collect::<Vec<RowMetaPB>>();
Ok(DatabasePB {
id: database_id,
@ -1245,17 +1242,10 @@ impl DatabaseViewData for DatabaseViewDataImpl {
fn get_row(&self, view_id: &str, row_id: &RowId) -> Fut<Option<(usize, Arc<RowDetail>)>> {
let index = self.database.lock().index_of_row(view_id, row_id);
let row = self.database.lock().get_row(row_id);
let row_meta = self.database.lock().get_row_meta(row_id);
let row_detail = self.database.lock().get_row_detail(row_id);
to_fut(async move {
match (index, row_meta) {
(Some(index), Some(row_meta)) => {
let row_detail = RowDetail {
row,
meta: row_meta,
};
Some((index, Arc::new(row_detail)))
},
match (index, row_detail) {
(Some(index), Some(row_detail)) => Some((index, Arc::new(row_detail))),
_ => None,
}
})
@ -1266,11 +1256,7 @@ impl DatabaseViewData for DatabaseViewDataImpl {
let rows = database.get_rows_for_view(view_id);
let row_details = rows
.into_iter()
.flat_map(|row| {
database
.get_row_meta(&row.id)
.map(|meta| RowDetail { row, meta })
})
.flat_map(|row| database.get_row_detail(&row.id))
.collect::<Vec<RowDetail>>();
to_fut(async move { row_details.into_iter().map(Arc::new).collect() })

View File

@ -1,4 +1,4 @@
use collab_database::rows::{RowId, RowMeta};
use collab_database::rows::{RowDetail, RowId};
use collab_database::views::DatabaseLayout;
#[derive(Debug, Clone)]
@ -14,7 +14,7 @@ pub enum DatabaseRowEvent {
#[derive(Debug, Clone)]
pub struct InsertedRow {
pub row_meta: RowMeta,
pub row_detail: RowDetail,
pub index: Option<i32>,
pub is_new: bool,
}
@ -29,7 +29,7 @@ pub struct UpdatedRow {
pub field_ids: Vec<String>,
/// The meta of row was updated if this is Some.
pub row_meta: Option<RowMeta>,
pub row_detail: Option<RowDetail>,
}
impl UpdatedRow {
@ -38,7 +38,7 @@ impl UpdatedRow {
row_id: row_id.to_string(),
height: None,
field_ids: vec![],
row_meta: None,
row_detail: None,
}
}
@ -52,8 +52,8 @@ impl UpdatedRow {
self
}
pub fn with_row_meta(mut self, row_meta: RowMeta) -> Self {
self.row_meta = Some(row_meta);
pub fn with_row_meta(mut self, row_detail: RowDetail) -> Self {
self.row_detail = Some(row_detail);
self
}
}

View File

@ -4,7 +4,7 @@ use std::sync::Arc;
use collab_database::database::{gen_database_filter_id, gen_database_sort_id, MutexDatabase};
use collab_database::fields::{Field, TypeOptionData};
use collab_database::rows::{Cells, Row, RowCell, RowDetail, RowId, RowMeta};
use collab_database::rows::{Cells, Row, RowCell, RowDetail, RowId};
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
use tokio::sync::{broadcast, RwLock};
@ -216,8 +216,8 @@ impl DatabaseViewEditor {
.await;
}
pub async fn v_did_update_row_meta(&self, row_id: &RowId, row_meta: &RowMeta) {
let update_row = UpdatedRow::new(row_id.as_str()).with_row_meta(row_meta.clone());
pub async fn v_did_update_row_meta(&self, row_id: &RowId, row_detail: &RowDetail) {
let update_row = UpdatedRow::new(row_id.as_str()).with_row_meta(row_detail.clone());
let changeset = RowsChangePB::from_update(update_row.into());
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
.payload(changeset)
@ -234,7 +234,7 @@ impl DatabaseViewEditor {
// Send the group notification if the current view has groups
match group_id.as_ref() {
None => {
let row = InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)).with_index(index as i32);
let row = InsertedRowPB::new(RowMetaPB::from(row_detail)).with_index(index as i32);
changes = RowsChangePB::from_insert(row);
},
Some(group_id) => {
@ -246,7 +246,7 @@ impl DatabaseViewEditor {
.await;
let inserted_row = InsertedRowPB {
row_meta: RowMetaPB::from(&row_detail.meta),
row_meta: RowMetaPB::from(row_detail),
index: Some(index as i32),
is_new: true,
};
@ -790,7 +790,7 @@ impl DatabaseViewEditor {
let (_, row_detail) = self.delegate.get_row(&self.view_id, &row_id).await?;
Some(CalendarEventPB {
row_meta: RowMetaPB::from(&row_detail.meta),
row_meta: RowMetaPB::from(row_detail.as_ref()),
date_field_id: date_field.id.clone(),
title,
timestamp,
@ -853,7 +853,7 @@ impl DatabaseViewEditor {
let (_, row_detail) = self.delegate.get_row(&self.view_id, &row_id).await?;
let event = CalendarEventPB {
row_meta: RowMetaPB::from(&row_detail.meta),
row_meta: RowMetaPB::from(row_detail.as_ref()),
date_field_id: calendar_setting.field_id.clone(),
title,
timestamp,

View File

@ -1,7 +1,8 @@
mod entities;
mod field_settings;
mod field_settings_builder;
pub use entities::*;
pub use field_settings::*;
pub use field_settings_builder::*;
mod entities;
#[allow(clippy::module_inception)]
mod field_settings;
mod field_settings_builder;

View File

@ -161,9 +161,9 @@ impl FilterController {
) {
if is_visible {
if let Some((index, _row)) = self.delegate.get_row(&self.view_id, &row_id).await {
notification
.visible_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)).with_index(index as i32))
notification.visible_rows.push(
InsertedRowPB::new(RowMetaPB::from(row_detail.as_ref())).with_index(index as i32),
)
}
} else {
notification.invisible_rows.push(row_id);
@ -197,7 +197,7 @@ impl FilterController {
&self.cell_filter_cache,
) {
if is_visible {
let row_meta = RowMetaPB::from(&row_detail.meta);
let row_meta = RowMetaPB::from(row_detail.as_ref());
visible_rows.push(InsertedRowPB::new(row_meta).with_index(index as i32))
} else {
invisible_rows.push(row_id);

View File

@ -165,7 +165,7 @@ where
if !no_status_group_rows.is_empty() {
changeset
.inserted_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
no_status_group.add_row(row_detail.clone());
}
@ -190,7 +190,7 @@ where
let mut deleted_row_ids = vec![];
for row_detail in &no_status_group.rows {
let row_id = row_detail.meta.row_id.clone();
let row_id = row_detail.row.id.to_string();
if default_group_deleted_rows
.iter()
.any(|deleted_row| deleted_row.row_meta.id == row_id)
@ -200,7 +200,7 @@ where
}
no_status_group
.rows
.retain(|row_detail| !deleted_row_ids.contains(&row_detail.meta.row_id));
.retain(|row_detail| !deleted_row_ids.contains(&row_detail.row.id));
changeset.deleted_rows.extend(deleted_row_ids);
Some(changeset)
}

View File

@ -69,7 +69,7 @@ impl GroupCustomize for CheckboxGroupController {
if is_not_contained {
changeset
.inserted_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
group.add_row(row_detail.clone());
}
}
@ -87,7 +87,7 @@ impl GroupCustomize for CheckboxGroupController {
if is_not_contained {
changeset
.inserted_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
group.add_row(row_detail.clone());
}
}

View File

@ -112,7 +112,7 @@ impl GroupCustomize for DateGroupController {
&setting_content,
);
let mut new_group = self.context.add_new_group(group)?;
new_group.group.rows.push(RowMetaPB::from(&row_detail.meta));
new_group.group.rows.push(RowMetaPB::from(row_detail));
inserted_group = Some(new_group);
}
@ -164,7 +164,7 @@ impl GroupCustomize for DateGroupController {
if !group.contains_row(&row_detail.row.id) {
changeset
.inserted_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
group.add_row(row_detail.clone());
}
} else if group.contains_row(&row_detail.row.id) {

View File

@ -31,7 +31,7 @@ pub fn add_or_remove_select_option_row(
if !group.contains_row(&row_detail.row.id) {
changeset
.inserted_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
group.add_row(row_detail.clone());
}
} else if group.contains_row(&row_detail.row.id) {
@ -104,7 +104,7 @@ pub fn move_group_row(
}
if group.id == *to_group_id {
let mut inserted_row = InsertedRowPB::new(RowMetaPB::from(&row_detail.meta));
let mut inserted_row = InsertedRowPB::new(RowMetaPB::from((*row_detail).clone()));
match to_index {
None => {
changeset.inserted_rows.push(inserted_row);

View File

@ -58,7 +58,7 @@ impl GroupCustomize for URLGroupController {
let cell_data: URLCellData = _cell_data.clone().into();
let group = make_group_from_url_cell(&cell_data);
let mut new_group = self.context.add_new_group(group)?;
new_group.group.rows.push(RowMetaPB::from(&row_detail.meta));
new_group.group.rows.push(RowMetaPB::from(row_detail));
inserted_group = Some(new_group);
}
@ -99,7 +99,7 @@ impl GroupCustomize for URLGroupController {
if !group.contains_row(&row_detail.row.id) {
changeset
.inserted_rows
.push(InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)));
.push(InsertedRowPB::new(RowMetaPB::from(row_detail)));
group.add_row(row_detail.clone());
}
} else if group.contains_row(&row_detail.row.id) {

View File

@ -43,7 +43,7 @@ impl DatabaseRowTest {
.unwrap();
self
.row_by_row_id
.insert(row_detail.row.id.to_string(), row_detail.meta.into());
.insert(row_detail.row.id.to_string(), row_detail.into());
self.row_details = self.get_rows().await;
},
RowScript::UpdateTextCell { row_id, content } => {

View File

@ -3,6 +3,7 @@ use flowy_database2::services::field_settings::FieldSettingsChangesetParams;
use crate::database::database_editor::DatabaseEditorTest;
#[allow(clippy::enum_variant_names)]
pub enum FieldSettingsScript {
AssertFieldSettings {
field_id: String,