Merge pull request #830 from AppFlowy-IO/fix/dup-self-ref
fix: self referencing database
This commit is contained in:
commit
4908ceae8b
|
|
@ -693,6 +693,44 @@ impl PublishCollabDuplicator {
|
||||||
.duplicated_refs
|
.duplicated_refs
|
||||||
.insert(pub_db_id.clone(), Some(new_db_id.clone()));
|
.insert(pub_db_id.clone(), Some(new_db_id.clone()));
|
||||||
|
|
||||||
|
{
|
||||||
|
// assign new id to all views of database.
|
||||||
|
// this will mark the database as duplicated
|
||||||
|
let txn = db_collab.context.transact();
|
||||||
|
let mut db_views = db_body.views.get_all_views(&txn);
|
||||||
|
let mut new_db_view_ids: Vec<String> = Vec::with_capacity(db_views.len());
|
||||||
|
for db_view in db_views.iter_mut() {
|
||||||
|
let new_db_view_id = if db_view.id == publish_view_id {
|
||||||
|
self
|
||||||
|
.duplicated_db_main_view
|
||||||
|
.insert(pub_db_id.clone(), new_view_id.clone());
|
||||||
|
new_view_id.clone()
|
||||||
|
} else {
|
||||||
|
gen_view_id()
|
||||||
|
};
|
||||||
|
self
|
||||||
|
.duplicated_db_view
|
||||||
|
.insert(db_view.id.clone(), new_db_view_id.clone());
|
||||||
|
|
||||||
|
new_db_view_ids.push(new_db_view_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this database as linked view
|
||||||
|
self
|
||||||
|
.workspace_databases
|
||||||
|
.insert(new_db_id.clone(), new_db_view_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign new id to all rows of database.
|
||||||
|
// this will mark the rows as duplicated
|
||||||
|
for pub_row_id in published_db.database_row_collabs.keys() {
|
||||||
|
// assign a new id for the row
|
||||||
|
let dup_row_id = gen_row_id();
|
||||||
|
self
|
||||||
|
.duplicated_db_row
|
||||||
|
.insert(pub_row_id.clone(), dup_row_id.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// handle row relations
|
// handle row relations
|
||||||
let mut txn = db_collab.context.transact_mut();
|
let mut txn = db_collab.context.transact_mut();
|
||||||
|
|
@ -734,8 +772,12 @@ impl PublishCollabDuplicator {
|
||||||
|
|
||||||
// duplicate db collab rows
|
// duplicate db collab rows
|
||||||
for (pub_row_id, row_bin_data) in &published_db.database_row_collabs {
|
for (pub_row_id, row_bin_data) in &published_db.database_row_collabs {
|
||||||
// assign a new id for the row
|
let dup_row_id = self
|
||||||
let dup_row_id = gen_row_id();
|
.duplicated_db_row
|
||||||
|
.get(pub_row_id)
|
||||||
|
.ok_or_else(|| AppError::RecordNotFound(format!("row not found: {}", pub_row_id)))?
|
||||||
|
.clone();
|
||||||
|
|
||||||
let mut db_row_collab = collab_from_doc_state(row_bin_data.clone(), &dup_row_id)?;
|
let mut db_row_collab = collab_from_doc_state(row_bin_data.clone(), &dup_row_id)?;
|
||||||
let mut db_row_body = DatabaseRowBody::open(pub_row_id.clone().into(), &mut db_row_collab)
|
let mut db_row_body = DatabaseRowBody::open(pub_row_id.clone().into(), &mut db_row_collab)
|
||||||
.map_err(|e| AppError::Unhandled(e.to_string()))?;
|
.map_err(|e| AppError::Unhandled(e.to_string()))?;
|
||||||
|
|
@ -754,7 +796,7 @@ impl PublishCollabDuplicator {
|
||||||
|
|
||||||
// updates row id along with meta keys
|
// updates row id along with meta keys
|
||||||
db_row_body
|
db_row_body
|
||||||
.update_id(&mut txn, dup_row_id.clone())
|
.update_id(&mut txn, dup_row_id.clone().into())
|
||||||
.map_err(|e| AppError::Unhandled(format!("failed to update row id: {:?}", e)))?;
|
.map_err(|e| AppError::Unhandled(format!("failed to update row id: {:?}", e)))?;
|
||||||
|
|
||||||
// duplicate row document if exists
|
// duplicate row document if exists
|
||||||
|
|
@ -860,34 +902,24 @@ impl PublishCollabDuplicator {
|
||||||
dup_row_id.to_string(),
|
dup_row_id.to_string(),
|
||||||
(CollabType::DatabaseRow, db_row_ec_bytes),
|
(CollabType::DatabaseRow, db_row_ec_bytes),
|
||||||
);
|
);
|
||||||
self
|
|
||||||
.duplicated_db_row
|
|
||||||
.insert(pub_row_id.clone(), dup_row_id.to_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// accumulate list of database views (Board, Cal, ...) to be linked to the database
|
// accumulate list of database views (Board, Cal, ...) to be linked to the database
|
||||||
let mut new_db_view_ids: Vec<String> = vec![];
|
|
||||||
{
|
{
|
||||||
let mut txn = db_collab.context.transact_mut();
|
let mut txn = db_collab.context.transact_mut();
|
||||||
db_body.root.insert(&mut txn, "id", new_db_id.clone());
|
db_body.root.insert(&mut txn, "id", new_db_id.clone());
|
||||||
|
|
||||||
let mut db_views = db_body.views.get_all_views(&txn);
|
let mut db_views = db_body.views.get_all_views(&txn);
|
||||||
for db_view in db_views.iter_mut() {
|
for db_view in db_views.iter_mut() {
|
||||||
let new_db_view_id = if db_view.id == publish_view_id {
|
let new_db_view_id = self.duplicated_db_view.get(&db_view.id).ok_or_else(|| {
|
||||||
self
|
AppError::Unhandled(format!(
|
||||||
.duplicated_db_main_view
|
"view not found in duplicated_db_view: {}",
|
||||||
.insert(pub_db_id.clone(), new_view_id.clone());
|
db_view.id
|
||||||
new_view_id.clone()
|
))
|
||||||
} else {
|
})?;
|
||||||
gen_view_id()
|
|
||||||
};
|
|
||||||
self
|
|
||||||
.duplicated_db_view
|
|
||||||
.insert(db_view.id.clone(), new_db_view_id.clone());
|
|
||||||
|
|
||||||
db_view.id.clone_from(&new_db_view_id);
|
db_view.id.clone_from(new_db_view_id);
|
||||||
db_view.database_id.clone_from(&new_db_id);
|
db_view.database_id.clone_from(&new_db_id);
|
||||||
new_db_view_ids.push(db_view.id.clone());
|
|
||||||
|
|
||||||
// update all views's row's id
|
// update all views's row's id
|
||||||
for row_order in db_view.row_orders.iter_mut() {
|
for row_order in db_view.row_orders.iter_mut() {
|
||||||
|
|
@ -917,11 +949,6 @@ impl PublishCollabDuplicator {
|
||||||
.collabs_to_insert
|
.collabs_to_insert
|
||||||
.insert(new_db_id.clone(), (CollabType::Database, db_encoded_collab));
|
.insert(new_db_id.clone(), (CollabType::Database, db_encoded_collab));
|
||||||
|
|
||||||
// Add this database as linked view
|
|
||||||
self
|
|
||||||
.workspace_databases
|
|
||||||
.insert(new_db_id.clone(), new_db_view_ids);
|
|
||||||
|
|
||||||
Ok((pub_db_id, new_db_id, false))
|
Ok((pub_db_id, new_db_id, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1304,6 +1304,88 @@ async fn duplicate_to_workspace_db_row_with_doc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn duplicate_to_workspace_db_rel_self() {
|
||||||
|
let client_1 = TestClient::new_user().await;
|
||||||
|
let workspace_id = client_1.workspace_id().await;
|
||||||
|
|
||||||
|
// database with a row referencing itself
|
||||||
|
// uuid must be fixed because the collab contains row data which reference itself
|
||||||
|
let db_rel_self_view_id: uuid::Uuid = "18d72589-80d7-4041-9342-5d572facb7c9".parse().unwrap();
|
||||||
|
let db_rel_self_metadata: PublishViewMetaData =
|
||||||
|
serde_json::from_str(published_data::DB_REL_SELF_META).unwrap();
|
||||||
|
let db_rel_self_blob = hex::decode(published_data::DB_REL_SELF_HEX).unwrap();
|
||||||
|
|
||||||
|
client_1
|
||||||
|
.api_client
|
||||||
|
.publish_collabs(
|
||||||
|
&workspace_id,
|
||||||
|
vec![PublishCollabItem {
|
||||||
|
meta: PublishCollabMetadata {
|
||||||
|
view_id: db_rel_self_view_id,
|
||||||
|
publish_name: "db-rel-self".to_string(),
|
||||||
|
metadata: db_rel_self_metadata.clone(),
|
||||||
|
},
|
||||||
|
data: db_rel_self_blob,
|
||||||
|
}],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut client_2 = TestClient::new_user().await;
|
||||||
|
let workspace_id_2 = client_2.workspace_id().await;
|
||||||
|
let fv = client_2
|
||||||
|
.api_client
|
||||||
|
.get_workspace_folder(&workspace_id_2, Some(5), None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
client_2
|
||||||
|
.api_client
|
||||||
|
.duplicate_published_to_workspace(
|
||||||
|
&workspace_id_2,
|
||||||
|
&PublishedDuplicate {
|
||||||
|
published_view_id: db_rel_self_view_id.to_string(),
|
||||||
|
dest_view_id: fv.view_id, // use the root view
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let fv = client_2
|
||||||
|
.api_client
|
||||||
|
.get_workspace_folder(&workspace_id_2, Some(5), None)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
println!("{:#?}", fv);
|
||||||
|
|
||||||
|
let db_rel_self = fv
|
||||||
|
.children
|
||||||
|
.iter()
|
||||||
|
.find(|v| v.name == "self_ref_db")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let db_rel_self_collab = client_2
|
||||||
|
.get_db_collab_from_view(&workspace_id_2, &db_rel_self.view_id)
|
||||||
|
.await;
|
||||||
|
let txn = db_rel_self_collab.transact();
|
||||||
|
let db_rel_self_body = DatabaseBody::from_collab(&db_rel_self_collab).unwrap();
|
||||||
|
let database_id = db_rel_self_body.get_database_id(&txn);
|
||||||
|
let all_fields = db_rel_self_body.fields.get_all_fields(&txn);
|
||||||
|
let rel_fields = all_fields
|
||||||
|
.iter()
|
||||||
|
.map(|f| &f.type_options)
|
||||||
|
.flat_map(|t| t.iter())
|
||||||
|
.filter(|(k, _v)| **k == FieldType::Relation.type_id())
|
||||||
|
.map(|(_k, v)| v)
|
||||||
|
.flat_map(|v| v.iter())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
assert_eq!(rel_fields.len(), 1);
|
||||||
|
assert_eq!(rel_fields[0].1.to_string(), database_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_database_id_and_row_ids(published_db_blob: &[u8]) -> (String, HashSet<String>) {
|
fn get_database_id_and_row_ids(published_db_blob: &[u8]) -> (String, HashSet<String>) {
|
||||||
let pub_db_data = serde_json::from_slice::<PublishDatabaseData>(published_db_blob).unwrap();
|
let pub_db_data = serde_json::from_slice::<PublishDatabaseData>(published_db_blob).unwrap();
|
||||||
let db_collab = collab_from_doc_state(pub_db_data.database_collab, "").unwrap();
|
let db_collab = collab_from_doc_state(pub_db_data.database_collab, "").unwrap();
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue