mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: reload UI (#2999)
* chore: reload folder * chore: reload folder * chore: init sync * chore: update tables * chore: update database * chore: load row * chore: update * chore: reload row * test: fit test * chore: retry * chore: support batch fetch * chore: enable sync * chore: sync switch * chore: sync switch * chore: migration user data * chore: migrate data * chore: migrate folder * chore: save user email * chore: refresh user profile * chore: fix test * chore: delete translation files * test: clippy format
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::RocksCollabDB;
|
||||
pub use collab_database::user::CollabObjectUpdate;
|
||||
pub use collab_database::user::CollabObjectUpdateByOid;
|
||||
|
||||
use flowy_error::FlowyError;
|
||||
use lib_infra::future::FutureResult;
|
||||
@ -8,18 +10,23 @@ use lib_infra::future::FutureResult;
|
||||
pub trait DatabaseUser2: Send + Sync {
|
||||
fn user_id(&self) -> Result<i64, FlowyError>;
|
||||
fn token(&self) -> Result<Option<String>, FlowyError>;
|
||||
fn collab_db(&self) -> Result<Arc<RocksCollabDB>, FlowyError>;
|
||||
fn collab_db(&self, uid: i64) -> Result<Arc<RocksCollabDB>, FlowyError>;
|
||||
}
|
||||
|
||||
/// A trait for database cloud service.
|
||||
/// Each kind of server should implement this trait. Check out the [AppFlowyServerProvider] of
|
||||
/// [flowy-server] crate for more information.
|
||||
pub trait DatabaseCloudService: Send + Sync {
|
||||
fn get_database_updates(&self, database_id: &str) -> FutureResult<Vec<Vec<u8>>, FlowyError>;
|
||||
fn get_collab_update(&self, object_id: &str) -> FutureResult<CollabObjectUpdate, FlowyError>;
|
||||
|
||||
fn get_database_latest_snapshot(
|
||||
fn batch_get_collab_updates(
|
||||
&self,
|
||||
database_id: &str,
|
||||
object_ids: Vec<String>,
|
||||
) -> FutureResult<CollabObjectUpdateByOid, FlowyError>;
|
||||
|
||||
fn get_collab_latest_snapshot(
|
||||
&self,
|
||||
object_id: &str,
|
||||
) -> FutureResult<Option<DatabaseSnapshot>, FlowyError>;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ macro_rules! impl_into_field_type {
|
||||
8 => FieldType::LastEditedTime,
|
||||
9 => FieldType::CreatedTime,
|
||||
_ => {
|
||||
tracing::error!("Can't parser FieldType from value: {}", ty);
|
||||
tracing::error!("🔴Can't parser FieldType from value: {}", ty);
|
||||
FieldType::RichText
|
||||
},
|
||||
}
|
||||
|
@ -324,15 +324,6 @@ impl TryInto<RowIdParams> for RowIdPB {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct BlockRowIdPB {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_id: String,
|
||||
}
|
||||
|
||||
#[derive(ProtoBuf, Default)]
|
||||
pub struct CreateRowPayloadPB {
|
||||
#[pb(index = 1)]
|
||||
|
@ -1,6 +1,8 @@
|
||||
use collab_database::rows::RowDetail;
|
||||
|
||||
use flowy_derive::ProtoBuf;
|
||||
|
||||
use crate::entities::{InsertedRowPB, UpdatedRowPB};
|
||||
use crate::entities::{InsertedRowPB, RowMetaPB, UpdatedRowPB};
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct RowsVisibilityChangePB {
|
||||
@ -17,53 +19,76 @@ pub struct RowsVisibilityChangePB {
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct RowsChangePB {
|
||||
#[pb(index = 1)]
|
||||
pub view_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub inserted_rows: Vec<InsertedRowPB>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
#[pb(index = 2)]
|
||||
pub deleted_rows: Vec<String>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
#[pb(index = 3)]
|
||||
pub updated_rows: Vec<UpdatedRowPB>,
|
||||
}
|
||||
|
||||
impl RowsChangePB {
|
||||
pub fn from_insert(view_id: String, inserted_row: InsertedRowPB) -> Self {
|
||||
pub fn from_insert(inserted_row: InsertedRowPB) -> Self {
|
||||
Self {
|
||||
view_id,
|
||||
inserted_rows: vec![inserted_row],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_delete(view_id: String, deleted_row: String) -> Self {
|
||||
pub fn from_delete(deleted_row: String) -> Self {
|
||||
Self {
|
||||
view_id,
|
||||
deleted_rows: vec![deleted_row],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_update(view_id: String, updated_row: UpdatedRowPB) -> Self {
|
||||
pub fn from_update(updated_row: UpdatedRowPB) -> Self {
|
||||
Self {
|
||||
view_id,
|
||||
updated_rows: vec![updated_row],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_move(
|
||||
view_id: String,
|
||||
deleted_rows: Vec<String>,
|
||||
inserted_rows: Vec<InsertedRowPB>,
|
||||
) -> Self {
|
||||
pub fn from_move(deleted_rows: Vec<String>, inserted_rows: Vec<InsertedRowPB>) -> Self {
|
||||
Self {
|
||||
view_id,
|
||||
inserted_rows,
|
||||
deleted_rows,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, ProtoBuf)]
|
||||
pub struct DidFetchRowPB {
|
||||
#[pb(index = 1)]
|
||||
pub row_id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub height: i32,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub visibility: bool,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub created_at: i64,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub modified_at: i64,
|
||||
|
||||
#[pb(index = 6)]
|
||||
pub meta: RowMetaPB,
|
||||
}
|
||||
|
||||
impl From<RowDetail> for DidFetchRowPB {
|
||||
fn from(value: RowDetail) -> Self {
|
||||
Self {
|
||||
row_id: value.row.id.to_string(),
|
||||
height: value.row.height,
|
||||
visibility: value.row.visibility,
|
||||
created_at: value.row.created_at,
|
||||
modified_at: value.row.modified_at,
|
||||
meta: RowMetaPB::from(value.meta),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use appflowy_integrate::collab_builder::AppFlowyCollabBuilder;
|
||||
use appflowy_integrate::{CollabPersistenceConfig, RocksCollabDB};
|
||||
use collab::core::collab::MutexCollab;
|
||||
use collab_database::database::DatabaseData;
|
||||
use collab_database::user::{DatabaseCollabBuilder, UserDatabase as InnerUserDatabase};
|
||||
use collab::core::collab::{CollabRawData, MutexCollab};
|
||||
use collab_database::blocks::BlockEvent;
|
||||
use collab_database::database::{DatabaseData, YrsDocAction};
|
||||
use collab_database::error::DatabaseError;
|
||||
use collab_database::user::{
|
||||
make_workspace_database_id, CollabFuture, CollabObjectUpdate, CollabObjectUpdateByOid,
|
||||
DatabaseCollabService, WorkspaceDatabase,
|
||||
};
|
||||
use collab_database::views::{CreateDatabaseParams, CreateViewParams, DatabaseLayout};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||
@ -16,15 +19,17 @@ use flowy_task::TaskDispatcher;
|
||||
|
||||
use crate::deps::{DatabaseCloudService, DatabaseUser2};
|
||||
use crate::entities::{
|
||||
DatabaseDescriptionPB, DatabaseLayoutPB, DatabaseSnapshotPB, RepeatedDatabaseDescriptionPB,
|
||||
DatabaseDescriptionPB, DatabaseLayoutPB, DatabaseSnapshotPB, DidFetchRowPB,
|
||||
RepeatedDatabaseDescriptionPB,
|
||||
};
|
||||
use crate::services::database::{DatabaseEditor, MutexDatabase};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::database::DatabaseEditor;
|
||||
use crate::services::database_view::DatabaseLayoutDepsResolver;
|
||||
use crate::services::share::csv::{CSVFormat, CSVImporter, ImportResult};
|
||||
|
||||
pub struct DatabaseManager2 {
|
||||
user: Arc<dyn DatabaseUser2>,
|
||||
user_database: UserDatabase,
|
||||
workspace_database: Arc<RwLock<Option<Arc<WorkspaceDatabase>>>>,
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
editors: RwLock<HashMap<String, Arc<DatabaseEditor>>>,
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
@ -40,7 +45,7 @@ impl DatabaseManager2 {
|
||||
) -> Self {
|
||||
Self {
|
||||
user: database_user,
|
||||
user_database: UserDatabase::default(),
|
||||
workspace_database: Default::default(),
|
||||
task_scheduler,
|
||||
editors: Default::default(),
|
||||
collab_builder,
|
||||
@ -48,16 +53,53 @@ impl DatabaseManager2 {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn initialize(&self, user_id: i64) -> FlowyResult<()> {
|
||||
fn is_collab_exist(&self, uid: i64, collab_db: &Arc<RocksCollabDB>, object_id: &str) -> bool {
|
||||
let read_txn = collab_db.read_txn();
|
||||
read_txn.is_exist(uid, object_id)
|
||||
}
|
||||
|
||||
pub async fn initialize(&self, uid: i64) -> FlowyResult<()> {
|
||||
let collab_db = self.user.collab_db(uid)?;
|
||||
let workspace_database_id = make_workspace_database_id(uid);
|
||||
let collab_builder = UserDatabaseCollabServiceImpl {
|
||||
collab_builder: self.collab_builder.clone(),
|
||||
cloud_service: self.cloud_service.clone(),
|
||||
};
|
||||
let config = CollabPersistenceConfig::new().snapshot_per_update(10);
|
||||
let db = self.user.collab_db()?;
|
||||
*self.user_database.lock() = Some(InnerUserDatabase::new(
|
||||
user_id,
|
||||
db,
|
||||
config,
|
||||
UserDatabaseCollabBuilderImpl(self.collab_builder.clone()),
|
||||
));
|
||||
// do nothing
|
||||
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, &workspace_database_id) {
|
||||
tracing::trace!("workspace database not exist, try to fetch from remote");
|
||||
match self
|
||||
.cloud_service
|
||||
.get_collab_update(&workspace_database_id)
|
||||
.await
|
||||
{
|
||||
Ok(updates) => collab_raw_data = updates,
|
||||
Err(err) => {
|
||||
return Err(FlowyError::record_not_found().context(format!(
|
||||
"get workspace database :{} failed: {}",
|
||||
workspace_database_id, err,
|
||||
)));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the workspace database.
|
||||
tracing::trace!("open workspace database: {}", &workspace_database_id);
|
||||
let collab = collab_builder.build_collab_with_config(
|
||||
uid,
|
||||
&workspace_database_id,
|
||||
"databases",
|
||||
collab_db.clone(),
|
||||
collab_raw_data,
|
||||
&config,
|
||||
);
|
||||
let workspace_database =
|
||||
WorkspaceDatabase::open(uid, collab, collab_db, config, collab_builder);
|
||||
subscribe_block_event(&workspace_database);
|
||||
*self.workspace_database.write().await = Some(Arc::new(workspace_database));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -67,17 +109,15 @@ impl DatabaseManager2 {
|
||||
}
|
||||
|
||||
pub async fn get_all_databases_description(&self) -> RepeatedDatabaseDescriptionPB {
|
||||
let databases_description = self.with_user_database(vec![], |database| {
|
||||
database
|
||||
let mut items = vec![];
|
||||
if let Ok(wdb) = self.get_workspace_database().await {
|
||||
items = wdb
|
||||
.get_all_databases()
|
||||
.into_iter()
|
||||
.map(DatabaseDescriptionPB::from)
|
||||
.collect()
|
||||
});
|
||||
|
||||
RepeatedDatabaseDescriptionPB {
|
||||
items: databases_description,
|
||||
.collect();
|
||||
}
|
||||
RepeatedDatabaseDescriptionPB { items }
|
||||
}
|
||||
|
||||
pub async fn get_database_with_view_id(&self, view_id: &str) -> FlowyResult<Arc<DatabaseEditor>> {
|
||||
@ -86,12 +126,11 @@ impl DatabaseManager2 {
|
||||
}
|
||||
|
||||
pub async fn get_database_id_with_view_id(&self, view_id: &str) -> FlowyResult<String> {
|
||||
let database_id = self.with_user_database(Err(FlowyError::internal()), |database| {
|
||||
database
|
||||
.get_database_id_with_view_id(view_id)
|
||||
.ok_or_else(FlowyError::record_not_found)
|
||||
})?;
|
||||
Ok(database_id)
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
wdb.get_database_id_with_view_id(view_id).ok_or_else(|| {
|
||||
FlowyError::record_not_found()
|
||||
.context(format!("The database for view id: {} not found", view_id))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_database(&self, database_id: &str) -> FlowyResult<Arc<DatabaseEditor>> {
|
||||
@ -104,14 +143,12 @@ impl DatabaseManager2 {
|
||||
pub async fn open_database(&self, database_id: &str) -> FlowyResult<Arc<DatabaseEditor>> {
|
||||
tracing::trace!("create new editor for database {}", database_id);
|
||||
let mut editors = self.editors.write().await;
|
||||
let database = MutexDatabase::new(self.with_user_database(
|
||||
Err(FlowyError::record_not_found()),
|
||||
|database| {
|
||||
database
|
||||
.get_database(database_id)
|
||||
.ok_or_else(FlowyError::record_not_found)
|
||||
},
|
||||
)?);
|
||||
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
let database = wdb
|
||||
.get_database(database_id)
|
||||
.await
|
||||
.ok_or_else(FlowyError::record_not_found)?;
|
||||
|
||||
let editor = Arc::new(DatabaseEditor::new(database, self.task_scheduler.clone()).await?);
|
||||
editors.insert(database_id.to_string(), editor.clone());
|
||||
@ -122,13 +159,11 @@ impl DatabaseManager2 {
|
||||
pub async fn close_database_view<T: AsRef<str>>(&self, view_id: T) -> FlowyResult<()> {
|
||||
// TODO(natan): defer closing the database if the sync is not finished
|
||||
let view_id = view_id.as_ref();
|
||||
let database_id = self.with_user_database(None, |databases| {
|
||||
let database_id = databases.get_database_id_with_view_id(view_id);
|
||||
if database_id.is_some() {
|
||||
databases.close_database(database_id.as_ref().unwrap());
|
||||
}
|
||||
database_id
|
||||
});
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
let database_id = wdb.get_database_id_with_view_id(view_id);
|
||||
if database_id.is_some() {
|
||||
wdb.close_database(database_id.as_ref().unwrap());
|
||||
}
|
||||
|
||||
if let Some(database_id) = database_id {
|
||||
let mut editors = self.editors.write().await;
|
||||
@ -150,13 +185,10 @@ impl DatabaseManager2 {
|
||||
}
|
||||
|
||||
pub async fn duplicate_database(&self, view_id: &str) -> FlowyResult<Vec<u8>> {
|
||||
let database_data = self.with_user_database(Err(FlowyError::internal()), |database| {
|
||||
let data = database.get_database_duplicated_data(view_id)?;
|
||||
let json_bytes = data.to_json_bytes()?;
|
||||
Ok(json_bytes)
|
||||
})?;
|
||||
|
||||
Ok(database_data)
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
let data = wdb.get_database_duplicated_data(view_id).await?;
|
||||
let json_bytes = data.to_json_bytes()?;
|
||||
Ok(json_bytes)
|
||||
}
|
||||
|
||||
/// Create a new database with the given data that can be deserialized to [DatabaseData].
|
||||
@ -168,24 +200,15 @@ impl DatabaseManager2 {
|
||||
) -> FlowyResult<()> {
|
||||
let mut database_data = DatabaseData::from_json_bytes(data)?;
|
||||
database_data.view.id = view_id.to_string();
|
||||
self.with_user_database(
|
||||
Err(FlowyError::internal().context("Create database with data failed")),
|
||||
|database| {
|
||||
let database = database.create_database_with_data(database_data)?;
|
||||
Ok(database)
|
||||
},
|
||||
)?;
|
||||
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
let _ = wdb.create_database_with_data(database_data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_database_with_params(&self, params: CreateDatabaseParams) -> FlowyResult<()> {
|
||||
let _ = self.with_user_database(
|
||||
Err(FlowyError::internal().context("Create database with params failed")),
|
||||
|user_database| {
|
||||
let database = user_database.create_database(params)?;
|
||||
Ok(database)
|
||||
},
|
||||
)?;
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
let _ = wdb.create_database(params)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -198,23 +221,18 @@ impl DatabaseManager2 {
|
||||
database_id: String,
|
||||
database_view_id: String,
|
||||
) -> FlowyResult<()> {
|
||||
self.with_user_database(
|
||||
Err(FlowyError::internal().context("Create database view failed")),
|
||||
|user_database| {
|
||||
let mut params = CreateViewParams::new(database_id.clone(), database_view_id, name, layout);
|
||||
if let Some(database) = user_database.get_database(&database_id) {
|
||||
if let Some((field, layout_setting)) = DatabaseLayoutDepsResolver::new(database, layout)
|
||||
.resolve_deps_when_create_database_linked_view()
|
||||
{
|
||||
params = params
|
||||
.with_deps_fields(vec![field])
|
||||
.with_layout_setting(layout_setting);
|
||||
}
|
||||
};
|
||||
user_database.create_database_linked_view(params)?;
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
let wdb = self.get_workspace_database().await?;
|
||||
let mut params = CreateViewParams::new(database_id.clone(), database_view_id, name, layout);
|
||||
if let Some(database) = wdb.get_database(&database_id).await {
|
||||
if let Some((field, layout_setting)) = DatabaseLayoutDepsResolver::new(database, layout)
|
||||
.resolve_deps_when_create_database_linked_view()
|
||||
{
|
||||
params = params
|
||||
.with_deps_fields(vec![field])
|
||||
.with_layout_setting(layout_setting);
|
||||
}
|
||||
};
|
||||
wdb.create_database_linked_view(params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -268,7 +286,7 @@ impl DatabaseManager2 {
|
||||
let mut snapshots = vec![];
|
||||
if let Some(snapshot) = self
|
||||
.cloud_service
|
||||
.get_database_latest_snapshot(&database_id)
|
||||
.get_collab_latest_snapshot(&database_id)
|
||||
.await?
|
||||
.map(|snapshot| DatabaseSnapshotPB {
|
||||
snapshot_id: snapshot.snapshot_id,
|
||||
@ -283,14 +301,11 @@ impl DatabaseManager2 {
|
||||
Ok(snapshots)
|
||||
}
|
||||
|
||||
fn with_user_database<F, Output>(&self, default_value: Output, f: F) -> Output
|
||||
where
|
||||
F: FnOnce(&InnerUserDatabase) -> Output,
|
||||
{
|
||||
let database = self.user_database.lock();
|
||||
async fn get_workspace_database(&self) -> FlowyResult<Arc<WorkspaceDatabase>> {
|
||||
let database = self.workspace_database.read().await;
|
||||
match &*database {
|
||||
None => default_value,
|
||||
Some(folder) => f(folder),
|
||||
None => Err(FlowyError::internal().context("Workspace database not initialized")),
|
||||
Some(user_database) => Ok(user_database.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,33 +316,97 @@ impl DatabaseManager2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct UserDatabase(Arc<Mutex<Option<InnerUserDatabase>>>);
|
||||
|
||||
impl Deref for UserDatabase {
|
||||
type Target = Arc<Mutex<Option<InnerUserDatabase>>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
/// Send notification to all clients that are listening to the given object.
|
||||
fn subscribe_block_event(workspace_database: &WorkspaceDatabase) {
|
||||
let mut block_event_rx = workspace_database.subscribe_block_event();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(event) = block_event_rx.recv().await {
|
||||
match event {
|
||||
BlockEvent::DidFetchRow(row_details) => {
|
||||
for row_detail in row_details {
|
||||
tracing::trace!("Did fetch row: {:?}", row_detail.row.id);
|
||||
let row_id = row_detail.row.id.clone();
|
||||
let pb = DidFetchRowPB::from(row_detail);
|
||||
send_notification(&row_id, DatabaseNotification::DidFetchRow)
|
||||
.payload(pb)
|
||||
.send();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unsafe impl Sync for UserDatabase {}
|
||||
struct UserDatabaseCollabServiceImpl {
|
||||
collab_builder: Arc<AppFlowyCollabBuilder>,
|
||||
cloud_service: Arc<dyn DatabaseCloudService>,
|
||||
}
|
||||
|
||||
unsafe impl Send for UserDatabase {}
|
||||
impl DatabaseCollabService for UserDatabaseCollabServiceImpl {
|
||||
fn get_collab_update(
|
||||
&self,
|
||||
object_id: &str,
|
||||
) -> CollabFuture<Result<CollabObjectUpdate, DatabaseError>> {
|
||||
let object_id = object_id.to_string();
|
||||
let weak_cloud_service = Arc::downgrade(&self.cloud_service);
|
||||
Box::pin(async move {
|
||||
match weak_cloud_service.upgrade() {
|
||||
None => {
|
||||
tracing::warn!("Cloud service is dropped");
|
||||
Ok(vec![])
|
||||
},
|
||||
Some(cloud_service) => {
|
||||
let updates = cloud_service
|
||||
.get_collab_update(&object_id)
|
||||
.await
|
||||
.map_err(|e| DatabaseError::Internal(Box::new(e)))?;
|
||||
Ok(updates)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
struct UserDatabaseCollabBuilderImpl(Arc<AppFlowyCollabBuilder>);
|
||||
fn batch_get_collab_update(
|
||||
&self,
|
||||
object_ids: Vec<String>,
|
||||
) -> CollabFuture<Result<CollabObjectUpdateByOid, DatabaseError>> {
|
||||
let weak_cloud_service = Arc::downgrade(&self.cloud_service);
|
||||
Box::pin(async move {
|
||||
match weak_cloud_service.upgrade() {
|
||||
None => {
|
||||
tracing::warn!("Cloud service is dropped");
|
||||
Ok(CollabObjectUpdateByOid::default())
|
||||
},
|
||||
Some(cloud_service) => {
|
||||
let updates = cloud_service
|
||||
.batch_get_collab_updates(object_ids)
|
||||
.await
|
||||
.map_err(|e| DatabaseError::Internal(Box::new(e)))?;
|
||||
Ok(updates)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl DatabaseCollabBuilder for UserDatabaseCollabBuilderImpl {
|
||||
fn build_with_config(
|
||||
fn build_collab_with_config(
|
||||
&self,
|
||||
uid: i64,
|
||||
object_id: &str,
|
||||
object_name: &str,
|
||||
db: Arc<RocksCollabDB>,
|
||||
collab_db: Arc<RocksCollabDB>,
|
||||
collab_raw_data: CollabRawData,
|
||||
config: &CollabPersistenceConfig,
|
||||
) -> Arc<MutexCollab> {
|
||||
self
|
||||
.0
|
||||
.build_with_config(uid, object_id, object_name, db, config)
|
||||
.collab_builder
|
||||
.build_with_config(
|
||||
uid,
|
||||
object_id,
|
||||
object_name,
|
||||
collab_db,
|
||||
collab_raw_data,
|
||||
config,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ const DATABASE_OBSERVABLE_SOURCE: &str = "Database";
|
||||
pub enum DatabaseNotification {
|
||||
#[default]
|
||||
Unknown = 0,
|
||||
/// Fetch row data from the remote server. It will be triggered if the backend support remote
|
||||
/// storage.
|
||||
DidFetchRow = 19,
|
||||
/// Trigger after inserting/deleting/updating a row
|
||||
DidUpdateViewRows = 20,
|
||||
/// Trigger when the visibility of the row was changed. For example, updating the filter will trigger the notification
|
||||
@ -58,6 +61,7 @@ impl std::convert::From<DatabaseNotification> for i32 {
|
||||
impl std::convert::From<i32> for DatabaseNotification {
|
||||
fn from(notification: i32) -> Self {
|
||||
match notification {
|
||||
19 => DatabaseNotification::DidFetchRow,
|
||||
20 => DatabaseNotification::DidUpdateViewRows,
|
||||
21 => DatabaseNotification::DidUpdateViewRowsVisibility,
|
||||
22 => DatabaseNotification::DidUpdateFields,
|
||||
|
@ -1,14 +1,12 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bytes::Bytes;
|
||||
use collab_database::database::Database as InnerDatabase;
|
||||
use collab_database::database::MutexDatabase;
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{Cell, Cells, CreateRowParams, Row, RowCell, RowId};
|
||||
use collab_database::rows::{Cell, Cells, CreateRowParams, Row, RowCell, RowDetail, RowId};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
|
||||
use futures::StreamExt;
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
|
||||
@ -21,7 +19,7 @@ use crate::services::cell::{
|
||||
apply_cell_changeset, get_cell_protobuf, AnyTypeCache, CellCache, ToCellChangeset,
|
||||
};
|
||||
use crate::services::database::util::database_view_setting_pb_from_view;
|
||||
use crate::services::database::{RowDetail, UpdatedRow};
|
||||
use crate::services::database::UpdatedRow;
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewData, DatabaseViews};
|
||||
use crate::services::field::checklist_type_option::{ChecklistCellChangeset, ChecklistCellData};
|
||||
use crate::services::field::{
|
||||
@ -38,14 +36,14 @@ use crate::services::sort::Sort;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DatabaseEditor {
|
||||
database: MutexDatabase,
|
||||
database: Arc<MutexDatabase>,
|
||||
pub cell_cache: CellCache,
|
||||
database_views: Arc<DatabaseViews>,
|
||||
}
|
||||
|
||||
impl DatabaseEditor {
|
||||
pub async fn new(
|
||||
database: MutexDatabase,
|
||||
database: Arc<MutexDatabase>,
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
) -> FlowyResult<Self> {
|
||||
let cell_cache = AnyTypeCache::<u64>::new();
|
||||
@ -76,7 +74,7 @@ impl DatabaseEditor {
|
||||
tokio::spawn(async move {
|
||||
while let Some(snapshot_state) = snapshot_state.next().await {
|
||||
if let Some(new_snapshot_id) = snapshot_state.snapshot_id() {
|
||||
tracing::debug!("Did create database snapshot: {}", new_snapshot_id);
|
||||
tracing::debug!("Did create database remote snapshot: {}", new_snapshot_id);
|
||||
send_notification(
|
||||
&database_id,
|
||||
DatabaseNotification::DidUpdateDatabaseSnapshotState,
|
||||
@ -415,8 +413,7 @@ impl DatabaseEditor {
|
||||
|
||||
let delete_row_id = from.into_inner();
|
||||
let insert_row = InsertedRowPB::new(RowMetaPB::from(&row_meta)).with_index(to_index as i32);
|
||||
let changes =
|
||||
RowsChangePB::from_move(view_id.to_string(), vec![delete_row_id], vec![insert_row]);
|
||||
let changes = RowsChangePB::from_move(vec![delete_row_id], vec![insert_row]);
|
||||
send_notification(view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changes)
|
||||
.send();
|
||||
@ -437,7 +434,7 @@ impl DatabaseEditor {
|
||||
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(row), Some(meta)) = (row, row_meta) {
|
||||
if let Some(meta) = row_meta {
|
||||
let row_detail = RowDetail { row, meta };
|
||||
for view in self.database_views.editors().await {
|
||||
view.v_did_create_row(&row_detail, &group_id, index).await;
|
||||
@ -527,7 +524,7 @@ impl DatabaseEditor {
|
||||
|
||||
pub fn get_row(&self, view_id: &str, row_id: &RowId) -> Option<Row> {
|
||||
if self.database.lock().views.is_row_exist(view_id, row_id) {
|
||||
self.database.lock().get_row(row_id)
|
||||
Some(self.database.lock().get_row(row_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -551,7 +548,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)?;
|
||||
let row = self.database.lock().get_row(row_id);
|
||||
Some(RowDetail { row, meta })
|
||||
} else {
|
||||
tracing::warn!("the row:{} is exist in view:{}", row_id.as_str(), view_id);
|
||||
@ -597,40 +594,23 @@ impl DatabaseEditor {
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
// If the cell data is referenced, return the reference data. Otherwise, return an empty cell.
|
||||
match field_type {
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => database
|
||||
.get_row(row_id)
|
||||
.map(|row| {
|
||||
if field_type.is_created_time() {
|
||||
DateCellData::new(row.created_at, true)
|
||||
} else {
|
||||
DateCellData::new(row.modified_at, true)
|
||||
}
|
||||
})
|
||||
.map(Cell::from),
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => {
|
||||
let row = database.get_row(row_id);
|
||||
let cell_data = if field_type.is_created_time() {
|
||||
DateCellData::new(row.created_at, true)
|
||||
} else {
|
||||
DateCellData::new(row.modified_at, true)
|
||||
};
|
||||
Some(Cell::from(cell_data))
|
||||
},
|
||||
_ => database.get_cell(field_id, row_id).cell,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_cell_pb(&self, field_id: &str, row_id: &RowId) -> Option<CellPB> {
|
||||
let (field, cell) = {
|
||||
let database = self.database.lock();
|
||||
let field = database.fields.get_field(field_id)?;
|
||||
let field_type = FieldType::from(field.field_type);
|
||||
// If the cell data is referenced, return the reference data. Otherwise, return an empty cell.
|
||||
let cell = match field_type {
|
||||
FieldType::LastEditedTime | FieldType::CreatedTime => database
|
||||
.get_row(row_id)
|
||||
.map(|row| {
|
||||
if field_type.is_created_time() {
|
||||
DateCellData::new(row.created_at, true)
|
||||
} else {
|
||||
DateCellData::new(row.modified_at, true)
|
||||
}
|
||||
})
|
||||
.map(Cell::from),
|
||||
_ => database.get_cell(field_id, row_id).cell,
|
||||
}?;
|
||||
|
||||
let cell = self.get_cell(field_id, row_id).await?;
|
||||
let field = self.database.lock().fields.get_field(field_id)?;
|
||||
(field, cell)
|
||||
};
|
||||
|
||||
@ -723,7 +703,7 @@ impl DatabaseEditor {
|
||||
if let Some(new_row_detail) = option_row {
|
||||
let updated_row =
|
||||
UpdatedRow::new(&new_row_detail.row.id).with_field_ids(vec![field_id.to_string()]);
|
||||
let changes = RowsChangePB::from_update(view_id.to_string(), updated_row.into());
|
||||
let changes = RowsChangePB::from_update(updated_row.into());
|
||||
send_notification(view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changes)
|
||||
.send();
|
||||
@ -1154,35 +1134,15 @@ fn cell_changesets_from_cell_by_field_id(
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MutexDatabase(Arc<Mutex<Arc<InnerDatabase>>>);
|
||||
|
||||
impl MutexDatabase {
|
||||
pub(crate) fn new(database: Arc<InnerDatabase>) -> Self {
|
||||
Self(Arc::new(Mutex::new(database)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MutexDatabase {
|
||||
type Target = Arc<Mutex<Arc<InnerDatabase>>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Sync for MutexDatabase {}
|
||||
|
||||
unsafe impl Send for MutexDatabase {}
|
||||
|
||||
struct DatabaseViewDataImpl {
|
||||
database: MutexDatabase,
|
||||
database: Arc<MutexDatabase>,
|
||||
task_scheduler: Arc<RwLock<TaskDispatcher>>,
|
||||
cell_cache: CellCache,
|
||||
}
|
||||
|
||||
impl DatabaseViewData for DatabaseViewDataImpl {
|
||||
fn get_database(&self) -> Arc<InnerDatabase> {
|
||||
self.database.lock().clone()
|
||||
fn get_database(&self) -> Arc<MutexDatabase> {
|
||||
self.database.clone()
|
||||
}
|
||||
|
||||
fn get_view(&self, view_id: &str) -> Fut<Option<DatabaseView>> {
|
||||
@ -1245,8 +1205,8 @@ impl DatabaseViewData for DatabaseViewDataImpl {
|
||||
let row = self.database.lock().get_row(row_id);
|
||||
let row_meta = self.database.lock().get_row_meta(row_id);
|
||||
to_fut(async move {
|
||||
match (index, row, row_meta) {
|
||||
(Some(index), Some(row), Some(row_meta)) => {
|
||||
match (index, row_meta) {
|
||||
(Some(index), Some(row_meta)) => {
|
||||
let row_detail = RowDetail {
|
||||
row,
|
||||
meta: row_meta,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use collab_database::rows::{Row, RowId, RowMeta};
|
||||
use collab_database::rows::{RowId, RowMeta};
|
||||
use collab_database::views::DatabaseLayout;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -64,9 +64,3 @@ pub struct CreateDatabaseViewParams {
|
||||
pub view_id: String,
|
||||
pub layout_type: DatabaseLayout,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RowDetail {
|
||||
pub row: Row,
|
||||
pub meta: RowMeta,
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::database::{gen_field_id, Database};
|
||||
use collab_database::database::{gen_field_id, MutexDatabase};
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::views::{DatabaseLayout, LayoutSetting};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::field::DateTypeOption;
|
||||
@ -11,13 +10,13 @@ use crate::services::setting::CalendarLayoutSetting;
|
||||
/// When creating a database, we need to resolve the dependencies of the views. Different database
|
||||
/// view has different dependencies. For example, a calendar view depends on a date field.
|
||||
pub struct DatabaseLayoutDepsResolver {
|
||||
pub database: Arc<Database>,
|
||||
pub database: Arc<MutexDatabase>,
|
||||
/// The new database layout.
|
||||
pub database_layout: DatabaseLayout,
|
||||
}
|
||||
|
||||
impl DatabaseLayoutDepsResolver {
|
||||
pub fn new(database: Arc<Database>, database_layout: DatabaseLayout) -> Self {
|
||||
pub fn new(database: Arc<MutexDatabase>, database_layout: DatabaseLayout) -> Self {
|
||||
Self {
|
||||
database,
|
||||
database_layout,
|
||||
@ -39,7 +38,7 @@ impl DatabaseLayoutDepsResolver {
|
||||
/// If the new layout type is a calendar and there is not date field in the database, it will add
|
||||
/// a new date field to the database and create the corresponding layout setting.
|
||||
pub fn resolve_deps_when_update_layout_type(&self, view_id: &str) {
|
||||
let fields = self.database.get_fields(None);
|
||||
let fields = self.database.lock().get_fields(None);
|
||||
// Insert the layout setting if it's not exist
|
||||
match &self.database_layout {
|
||||
DatabaseLayout::Grid => {},
|
||||
@ -53,7 +52,7 @@ impl DatabaseLayoutDepsResolver {
|
||||
tracing::trace!("Create a new date field after layout type change");
|
||||
let field = self.create_date_field();
|
||||
let field_id = field.id.clone();
|
||||
self.database.create_field(field);
|
||||
self.database.lock().create_field(field);
|
||||
field_id
|
||||
},
|
||||
Some(date_field) => date_field.id,
|
||||
@ -66,12 +65,14 @@ impl DatabaseLayoutDepsResolver {
|
||||
fn create_calendar_layout_setting_if_need(&self, view_id: &str, field_id: &str) {
|
||||
if self
|
||||
.database
|
||||
.lock()
|
||||
.get_layout_setting::<CalendarLayoutSetting>(view_id, &self.database_layout)
|
||||
.is_none()
|
||||
{
|
||||
let layout_setting = CalendarLayoutSetting::new(field_id.to_string());
|
||||
self
|
||||
.database
|
||||
.lock()
|
||||
.insert_layout_setting(view_id, &self.database_layout, layout_setting);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::database::{gen_database_filter_id, gen_database_sort_id, Database};
|
||||
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, RowId, RowMeta};
|
||||
use collab_database::rows::{Cells, Row, RowCell, RowDetail, RowId, RowMeta};
|
||||
use collab_database::views::{DatabaseLayout, DatabaseView, LayoutSetting};
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
@ -20,9 +20,7 @@ use crate::entities::{
|
||||
};
|
||||
use crate::notification::{send_notification, DatabaseNotification};
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::{
|
||||
database_view_setting_pb_from_view, DatabaseRowEvent, RowDetail, UpdatedRow,
|
||||
};
|
||||
use crate::services::database::{database_view_setting_pb_from_view, DatabaseRowEvent, UpdatedRow};
|
||||
use crate::services::database_view::view_filter::make_filter_controller;
|
||||
use crate::services::database_view::view_group::{
|
||||
get_cell_for_row, get_cells_for_field, new_group_controller, new_group_controller_with_field,
|
||||
@ -44,7 +42,7 @@ use crate::services::setting::CalendarLayoutSetting;
|
||||
use crate::services::sort::{DeletedSortType, Sort, SortChangeset, SortController, SortType};
|
||||
|
||||
pub trait DatabaseViewData: Send + Sync + 'static {
|
||||
fn get_database(&self) -> Arc<Database>;
|
||||
fn get_database(&self) -> Arc<MutexDatabase>;
|
||||
|
||||
fn get_view(&self, view_id: &str) -> Fut<Option<DatabaseView>>;
|
||||
/// If the field_ids is None, then it will return all the field revisions
|
||||
@ -204,7 +202,7 @@ impl DatabaseViewEditor {
|
||||
|
||||
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());
|
||||
let changeset = RowsChangePB::from_update(self.view_id.clone(), update_row.into());
|
||||
let changeset = RowsChangePB::from_update(update_row.into());
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
.send();
|
||||
@ -221,7 +219,7 @@ impl DatabaseViewEditor {
|
||||
match group_id.as_ref() {
|
||||
None => {
|
||||
let row = InsertedRowPB::new(RowMetaPB::from(&row_detail.meta)).with_index(index as i32);
|
||||
changes = RowsChangePB::from_insert(self.view_id.clone(), row);
|
||||
changes = RowsChangePB::from_insert(row);
|
||||
},
|
||||
Some(group_id) => {
|
||||
self
|
||||
@ -239,7 +237,7 @@ impl DatabaseViewEditor {
|
||||
let changeset =
|
||||
GroupRowsNotificationPB::insert(group_id.clone(), vec![inserted_row.clone()]);
|
||||
notify_did_update_group_rows(changeset).await;
|
||||
changes = RowsChangePB::from_insert(self.view_id.clone(), inserted_row);
|
||||
changes = RowsChangePB::from_insert(inserted_row);
|
||||
},
|
||||
}
|
||||
|
||||
@ -263,7 +261,7 @@ impl DatabaseViewEditor {
|
||||
notify_did_update_group_rows(changeset).await;
|
||||
}
|
||||
}
|
||||
let changes = RowsChangePB::from_delete(self.view_id.clone(), row.id.clone().into_inner());
|
||||
let changes = RowsChangePB::from_delete(row.id.clone().into_inner());
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changes)
|
||||
.send();
|
||||
@ -311,7 +309,7 @@ impl DatabaseViewEditor {
|
||||
} else {
|
||||
let update_row =
|
||||
UpdatedRow::new(&row_detail.row.id).with_field_ids(vec![field_id.to_string()]);
|
||||
let changeset = RowsChangePB::from_update(self.view_id.clone(), update_row.into());
|
||||
let changeset = RowsChangePB::from_update(update_row.into());
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
.payload(changeset)
|
||||
.send();
|
||||
@ -880,23 +878,13 @@ impl DatabaseViewEditor {
|
||||
|
||||
pub async fn handle_row_event(&self, event: Cow<'_, DatabaseRowEvent>) {
|
||||
let changeset = match event.into_owned() {
|
||||
DatabaseRowEvent::InsertRow(row) => {
|
||||
RowsChangePB::from_insert(self.view_id.clone(), row.into())
|
||||
},
|
||||
DatabaseRowEvent::UpdateRow(row) => {
|
||||
RowsChangePB::from_update(self.view_id.clone(), row.into())
|
||||
},
|
||||
DatabaseRowEvent::DeleteRow(row_id) => {
|
||||
RowsChangePB::from_delete(self.view_id.clone(), row_id.into_inner())
|
||||
},
|
||||
DatabaseRowEvent::InsertRow(row) => RowsChangePB::from_insert(row.into()),
|
||||
DatabaseRowEvent::UpdateRow(row) => RowsChangePB::from_update(row.into()),
|
||||
DatabaseRowEvent::DeleteRow(row_id) => RowsChangePB::from_delete(row_id.into_inner()),
|
||||
DatabaseRowEvent::Move {
|
||||
deleted_row_id,
|
||||
inserted_row,
|
||||
} => RowsChangePB::from_move(
|
||||
self.view_id.clone(),
|
||||
vec![deleted_row_id.into_inner()],
|
||||
vec![inserted_row.into()],
|
||||
),
|
||||
} => RowsChangePB::from_move(vec![deleted_row_id.into_inner()], vec![inserted_row.into()]),
|
||||
};
|
||||
|
||||
send_notification(&self.view_id, DatabaseNotification::DidUpdateViewRows)
|
||||
|
@ -1,12 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::RowId;
|
||||
use collab_database::rows::{RowDetail, RowId};
|
||||
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{
|
||||
gen_handler_id, DatabaseViewChangedNotifier, DatabaseViewData,
|
||||
};
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::RowDetail;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use lib_infra::future::{to_fut, Fut};
|
||||
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{
|
||||
gen_handler_id, DatabaseViewChangedNotifier, DatabaseViewData,
|
||||
};
|
||||
|
@ -1,8 +1,9 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::database::MutexDatabase;
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::RowId;
|
||||
use collab_database::rows::{RowDetail, RowId};
|
||||
use nanoid::nanoid;
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
@ -10,7 +11,7 @@ use flowy_error::FlowyResult;
|
||||
use lib_infra::future::Fut;
|
||||
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::{DatabaseRowEvent, MutexDatabase, RowDetail};
|
||||
use crate::services::database::DatabaseRowEvent;
|
||||
use crate::services::database_view::{DatabaseViewData, DatabaseViewEditor};
|
||||
use crate::services::group::RowChangeset;
|
||||
|
||||
@ -19,7 +20,7 @@ pub type RowEventReceiver = broadcast::Receiver<DatabaseRowEvent>;
|
||||
|
||||
pub struct DatabaseViews {
|
||||
#[allow(dead_code)]
|
||||
database: MutexDatabase,
|
||||
database: Arc<MutexDatabase>,
|
||||
cell_cache: CellCache,
|
||||
database_view_data: Arc<dyn DatabaseViewData>,
|
||||
editor_map: Arc<RwLock<HashMap<String, Arc<DatabaseViewEditor>>>>,
|
||||
@ -27,7 +28,7 @@ pub struct DatabaseViews {
|
||||
|
||||
impl DatabaseViews {
|
||||
pub async fn new(
|
||||
database: MutexDatabase,
|
||||
database: Arc<MutexDatabase>,
|
||||
cell_cache: CellCache,
|
||||
database_view_data: Arc<dyn DatabaseViewData>,
|
||||
) -> FlowyResult<Self> {
|
||||
|
@ -9,7 +9,6 @@ use crate::entities::{FieldType, SelectOptionCellDataPB};
|
||||
use crate::services::cell::{
|
||||
CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangeset, ToCellChangeset,
|
||||
};
|
||||
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
|
||||
use crate::services::field::{
|
||||
make_selected_options, CheckboxCellData, MultiSelectTypeOption, SelectOption,
|
||||
@ -168,7 +167,7 @@ pub fn select_type_option_from_field(
|
||||
Ok(Box::new(type_option))
|
||||
},
|
||||
ty => {
|
||||
tracing::error!("Unsupported field type: {:?} for this handler", ty);
|
||||
tracing::error!("🔴Unsupported field type: {:?} for this handler", ty);
|
||||
Err(ErrorCode::FieldInvalidOperation.into())
|
||||
},
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row, RowId};
|
||||
use collab_database::rows::{Cell, Row, RowDetail, RowId};
|
||||
use dashmap::DashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
@ -15,7 +15,6 @@ use lib_infra::future::Fut;
|
||||
use crate::entities::filter_entities::*;
|
||||
use crate::entities::{FieldType, InsertedRowPB, RowMetaPB};
|
||||
use crate::services::cell::{AnyTypeCache, CellCache, CellFilterCache};
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewChangedNotifier};
|
||||
use crate::services::field::*;
|
||||
use crate::services::filter::{Filter, FilterChangeset, FilterResult, FilterResultNotification};
|
||||
|
@ -1,11 +1,10 @@
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row};
|
||||
use collab_database::rows::{Cell, Row, RowDetail};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::{GroupChangesPB, GroupPB, GroupRowsNotificationPB, InsertedGroupPB};
|
||||
use crate::services::cell::DecodedCellData;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::controller::MoveGroupRowContext;
|
||||
use crate::services::group::{GroupData, GroupSettingChangeset};
|
||||
|
||||
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::{Field, TypeOptionData};
|
||||
use collab_database::rows::{Cell, Cells, Row, RowId};
|
||||
use collab_database::rows::{Cell, Cells, Row, RowDetail, RowId};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
@ -13,7 +13,6 @@ use crate::entities::{
|
||||
FieldType, GroupChangesPB, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB,
|
||||
};
|
||||
use crate::services::cell::{get_cell_protobuf, CellProtobufBlobParser, DecodedCellData};
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::action::{
|
||||
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation, GroupCustomize,
|
||||
};
|
||||
|
@ -1,12 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB};
|
||||
use crate::services::cell::insert_checkbox_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{
|
||||
CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOption, CHECK, UNCHECK,
|
||||
};
|
||||
|
@ -1,12 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cells, Row};
|
||||
use collab_database::rows::{Cells, Row, RowDetail};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::GroupChangesPB;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::action::{
|
||||
DidMoveGroupRowResult, DidUpdateGroupRowResult, GroupControllerOperation,
|
||||
};
|
||||
|
@ -1,12 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, SelectOptionCellDataPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{MultiSelectTypeOption, SelectOptionCellDataParser};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::{
|
||||
|
@ -1,12 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::entities::{FieldType, GroupRowsNotificationPB, SelectOptionCellDataPB};
|
||||
use crate::services::cell::insert_select_option_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{SelectOptionCellDataParser, SingleSelectTypeOption};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::controller::{
|
||||
|
@ -1,11 +1,10 @@
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row};
|
||||
use collab_database::rows::{Cell, Row, RowDetail};
|
||||
|
||||
use crate::entities::{
|
||||
FieldType, GroupRowsNotificationPB, InsertedRowPB, RowMetaPB, SelectOptionCellDataPB,
|
||||
};
|
||||
use crate::services::cell::{insert_checkbox_cell, insert_select_option_cell, insert_url_cell};
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{SelectOption, CHECK};
|
||||
use crate::services::group::controller::MoveGroupRowContext;
|
||||
use crate::services::group::{GeneratedGroupConfig, Group, GroupData};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row};
|
||||
use collab_database::rows::{new_cell_builder, Cell, Cells, Row, RowDetail};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
@ -11,7 +11,6 @@ use crate::entities::{
|
||||
URLCellDataPB,
|
||||
};
|
||||
use crate::services::cell::insert_url_cell;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::field::{URLCellData, URLCellDataParser, URLTypeOption};
|
||||
use crate::services::group::action::GroupCustomize;
|
||||
use crate::services::group::configuration::GroupContext;
|
||||
|
@ -1,12 +1,10 @@
|
||||
use anyhow::bail;
|
||||
use collab::core::any_map::AnyMapExtension;
|
||||
use collab_database::database::gen_database_group_id;
|
||||
use collab_database::rows::RowId;
|
||||
use collab_database::rows::{RowDetail, RowId};
|
||||
use collab_database::views::{GroupMap, GroupMapBuilder, GroupSettingBuilder, GroupSettingMap};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::services::database::RowDetail;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct GroupSetting {
|
||||
pub id: String,
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::RowDetail;
|
||||
use collab_database::views::DatabaseLayout;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::group::configuration::GroupSettingReader;
|
||||
use crate::services::group::controller::GroupController;
|
||||
use crate::services::group::{
|
||||
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use collab_database::fields::Field;
|
||||
use collab_database::rows::{Cell, Row, RowId};
|
||||
use collab_database::rows::{Cell, Row, RowDetail, RowId};
|
||||
use rayon::prelude::ParallelSliceMut;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
@ -16,7 +16,6 @@ use lib_infra::future::Fut;
|
||||
use crate::entities::FieldType;
|
||||
use crate::entities::SortChangesetNotificationPB;
|
||||
use crate::services::cell::CellCache;
|
||||
use crate::services::database::RowDetail;
|
||||
use crate::services::database_view::{DatabaseViewChanged, DatabaseViewChangedNotifier};
|
||||
use crate::services::field::{default_order, TypeOptionCellExt};
|
||||
use crate::services::sort::{
|
||||
|
Reference in New Issue
Block a user