mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #854 from AppFlowy-IO/feat/view_lens
This commit is contained in:
commit
6b312b4f8f
1
frontend/rust-lib/Cargo.lock
generated
1
frontend/rust-lib/Cargo.lock
generated
@ -935,6 +935,7 @@ dependencies = [
|
||||
"atomic_refcell",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"crossbeam-utils",
|
||||
"dart-notify",
|
||||
"dashmap",
|
||||
"diesel",
|
||||
|
@ -1,2 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE user_table;
|
||||
ALTER TABLE user_table DROP COLUMN workspace;
|
@ -1 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE view_table DROP COLUMN ext_data;
|
@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TABLE grid_view_rev_table;
|
@ -0,0 +1,11 @@
|
||||
-- Your SQL goes here
|
||||
|
||||
|
||||
CREATE TABLE grid_view_rev_table (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
object_id TEXT NOT NULL DEFAULT '',
|
||||
base_rev_id BIGINT NOT NULL DEFAULT 0,
|
||||
rev_id BIGINT NOT NULL DEFAULT 0,
|
||||
data BLOB NOT NULL DEFAULT (x''),
|
||||
state INTEGER NOT NULL DEFAULT 0
|
||||
);
|
@ -177,20 +177,20 @@ macro_rules! impl_rev_state_map {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<$target> for RevisionState {
|
||||
impl std::convert::From<$target> for crate::disk::RevisionState {
|
||||
fn from(s: $target) -> Self {
|
||||
match s {
|
||||
$target::Sync => RevisionState::Sync,
|
||||
$target::Ack => RevisionState::Ack,
|
||||
$target::Sync => crate::disk::RevisionState::Sync,
|
||||
$target::Ack => crate::disk::RevisionState::Ack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<RevisionState> for $target {
|
||||
fn from(s: RevisionState) -> Self {
|
||||
impl std::convert::From<crate::disk::RevisionState> for $target {
|
||||
fn from(s: crate::disk::RevisionState) -> Self {
|
||||
match s {
|
||||
RevisionState::Sync => $target::Sync,
|
||||
RevisionState::Ack => $target::Ack,
|
||||
crate::disk::RevisionState::Sync => $target::Sync,
|
||||
crate::disk::RevisionState::Ack => $target::Ack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,17 @@ table! {
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
grid_view_rev_table (id) {
|
||||
id -> Integer,
|
||||
object_id -> Text,
|
||||
base_rev_id -> BigInt,
|
||||
rev_id -> BigInt,
|
||||
data -> Binary,
|
||||
state -> Integer,
|
||||
}
|
||||
}
|
||||
|
||||
table! {
|
||||
kv_table (key) {
|
||||
key -> Text,
|
||||
@ -125,6 +136,7 @@ allow_tables_to_appear_in_same_query!(
|
||||
grid_block_index_table,
|
||||
grid_meta_rev_table,
|
||||
grid_rev_table,
|
||||
grid_view_rev_table,
|
||||
kv_table,
|
||||
rev_snapshot,
|
||||
rev_table,
|
||||
|
@ -4,13 +4,12 @@ use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_revision::{
|
||||
RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionWebSocket,
|
||||
};
|
||||
use flowy_sync::util::make_delta_from_revisions;
|
||||
use flowy_sync::util::make_text_delta_from_revisions;
|
||||
use flowy_sync::{
|
||||
client_folder::{FolderChangeset, FolderPad},
|
||||
entities::{revision::Revision, ws_data::ServerRevisionWSData},
|
||||
};
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ot::core::PhantomAttributes;
|
||||
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
@ -132,7 +131,7 @@ impl FolderEditor {
|
||||
pub struct FolderRevisionCompactor();
|
||||
impl RevisionCompactor for FolderRevisionCompactor {
|
||||
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
|
||||
let delta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
|
||||
let delta = make_text_delta_from_revisions(revisions)?;
|
||||
Ok(delta.json_bytes())
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ regex = "1.5.6"
|
||||
url = { version = "2"}
|
||||
futures = "0.3.15"
|
||||
atomic_refcell = "0.1.8"
|
||||
crossbeam-utils = "0.8.7"
|
||||
|
||||
[dev-dependencies]
|
||||
flowy-test = { path = "../flowy-test" }
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::entities::RowPB;
|
||||
use crate::entities::{CreateRowParams, RowPB};
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
@ -11,20 +11,17 @@ pub struct CreateBoardCardPayloadPB {
|
||||
#[pb(index = 2)]
|
||||
pub group_id: String,
|
||||
}
|
||||
pub struct CreateBoardCardParams {
|
||||
pub grid_id: String,
|
||||
pub group_id: String,
|
||||
}
|
||||
|
||||
impl TryInto<CreateBoardCardParams> for CreateBoardCardPayloadPB {
|
||||
impl TryInto<CreateRowParams> for CreateBoardCardPayloadPB {
|
||||
type Error = ErrorCode;
|
||||
|
||||
fn try_into(self) -> Result<CreateBoardCardParams, Self::Error> {
|
||||
fn try_into(self) -> Result<CreateRowParams, Self::Error> {
|
||||
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
|
||||
let group_id = NotEmptyStr::parse(self.group_id).map_err(|_| ErrorCode::GroupIdIsEmpty)?;
|
||||
Ok(CreateBoardCardParams {
|
||||
Ok(CreateRowParams {
|
||||
grid_id: grid_id.0,
|
||||
group_id: group_id.0,
|
||||
start_row_id: None,
|
||||
group_id: Some(group_id.0),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ pub struct CreateRowPayloadPB {
|
||||
pub struct CreateRowParams {
|
||||
pub grid_id: String,
|
||||
pub start_row_id: Option<String>,
|
||||
pub group_id: Option<String>,
|
||||
}
|
||||
|
||||
impl TryInto<CreateRowParams> for CreateRowPayloadPB {
|
||||
@ -68,6 +69,7 @@ impl TryInto<CreateRowParams> for CreateRowPayloadPB {
|
||||
Ok(CreateRowParams {
|
||||
grid_id: grid_id.0,
|
||||
start_row_id: self.start_row_id,
|
||||
group_id: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ pub(crate) async fn create_row_handler(
|
||||
) -> DataResult<RowPB, FlowyError> {
|
||||
let params: CreateRowParams = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(params.grid_id.as_ref())?;
|
||||
let row = editor.create_row(params.start_row_id).await?;
|
||||
let row = editor.create_row(params).await?;
|
||||
data_result(row)
|
||||
}
|
||||
|
||||
@ -419,8 +419,8 @@ pub(crate) async fn create_board_card_handler(
|
||||
data: Data<CreateBoardCardPayloadPB>,
|
||||
manager: AppData<Arc<GridManager>>,
|
||||
) -> DataResult<RowPB, FlowyError> {
|
||||
let params: CreateBoardCardParams = data.into_inner().try_into()?;
|
||||
let params: CreateRowParams = data.into_inner().try_into()?;
|
||||
let editor = manager.get_grid_editor(params.grid_id.as_ref())?;
|
||||
let row = editor.create_board_card(¶ms.group_id).await?;
|
||||
let row = editor.create_row(params).await?;
|
||||
data_result(row)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::services::block_revision_editor::GridBlockRevisionCompactor;
|
||||
use crate::services::block_editor::GridBlockRevisionCompactor;
|
||||
use crate::services::grid_editor::{GridRevisionCompactor, GridRevisionEditor};
|
||||
use crate::services::grid_view_manager::make_grid_view_rev_manager;
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
use crate::services::persistence::kv::GridKVPersistence;
|
||||
use crate::services::persistence::migration::GridMigration;
|
||||
@ -9,10 +10,10 @@ use bytes::Bytes;
|
||||
use dashmap::DashMap;
|
||||
use flowy_database::ConnectionPool;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::revision::{BuildGridContext, GridRevision};
|
||||
use flowy_grid_data_model::revision::{BuildGridContext, GridRevision, GridViewRevision};
|
||||
use flowy_revision::disk::{SQLiteGridBlockRevisionPersistence, SQLiteGridRevisionPersistence};
|
||||
use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionSnapshotPersistence};
|
||||
use flowy_sync::client_grid::{make_grid_block_delta, make_grid_delta};
|
||||
use flowy_sync::client_grid::{make_grid_block_delta, make_grid_delta, make_grid_view_delta};
|
||||
use flowy_sync::entities::revision::{RepeatedRevision, Revision};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
@ -70,6 +71,15 @@ impl GridManager {
|
||||
let db_pool = self.grid_user.db_pool()?;
|
||||
let rev_manager = self.make_grid_rev_manager(grid_id, db_pool)?;
|
||||
let _ = rev_manager.reset_object(revisions).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, err)]
|
||||
async fn create_grid_view<T: AsRef<str>>(&self, view_id: T, revisions: RepeatedRevision) -> FlowyResult<()> {
|
||||
let view_id = view_id.as_ref();
|
||||
let rev_manager = make_grid_view_rev_manager(&self.grid_user, view_id).await?;
|
||||
let _ = rev_manager.reset_object(revisions).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -198,14 +208,23 @@ pub async fn make_grid_view_data(
|
||||
let _ = grid_manager.create_grid_block(&block_id, repeated_revision).await?;
|
||||
}
|
||||
|
||||
let grid_rev = GridRevision::from_build_context(view_id, build_context);
|
||||
let grid_id = view_id.to_owned();
|
||||
let grid_rev = GridRevision::from_build_context(&grid_id, build_context);
|
||||
|
||||
// Create grid
|
||||
let grid_meta_delta = make_grid_delta(&grid_rev);
|
||||
let grid_delta_data = grid_meta_delta.json_bytes();
|
||||
let grid_rev_delta = make_grid_delta(&grid_rev);
|
||||
let grid_rev_delta_bytes = grid_rev_delta.json_bytes();
|
||||
let repeated_revision: RepeatedRevision =
|
||||
Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into();
|
||||
let _ = grid_manager.create_grid(view_id, repeated_revision).await?;
|
||||
Revision::initial_revision(user_id, &grid_id, grid_rev_delta_bytes.clone()).into();
|
||||
let _ = grid_manager.create_grid(&grid_id, repeated_revision).await?;
|
||||
|
||||
Ok(grid_delta_data)
|
||||
// Create grid view
|
||||
let grid_view = GridViewRevision::new(view_id.to_owned(), view_id.to_owned());
|
||||
let grid_view_delta = make_grid_view_delta(&grid_view);
|
||||
let grid_view_delta_bytes = grid_view_delta.json_bytes();
|
||||
let repeated_revision: RepeatedRevision =
|
||||
Revision::initial_revision(user_id, view_id, grid_view_delta_bytes).into();
|
||||
let _ = grid_manager.create_grid_view(view_id, repeated_revision).await?;
|
||||
|
||||
Ok(grid_rev_delta_bytes)
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaCh
|
||||
use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
|
||||
use flowy_sync::client_grid::{GridBlockRevisionChangeset, GridBlockRevisionPad};
|
||||
use flowy_sync::entities::revision::Revision;
|
||||
use flowy_sync::util::make_delta_from_revisions;
|
||||
use flowy_sync::util::make_text_delta_from_revisions;
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ot::core::PhantomAttributes;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
@ -200,7 +200,7 @@ impl RevisionObjectBuilder for GridBlockRevisionPadBuilder {
|
||||
pub struct GridBlockRevisionCompactor();
|
||||
impl RevisionCompactor for GridBlockRevisionCompactor {
|
||||
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
|
||||
let delta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
|
||||
let delta = make_text_delta_from_revisions(revisions)?;
|
||||
Ok(delta.json_bytes())
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::entities::{CellChangesetPB, GridBlockChangesetPB, InsertedRowPB, RowPB};
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::block_revision_editor::{GridBlockRevisionCompactor, GridBlockRevisionEditor};
|
||||
use crate::services::block_editor::{GridBlockRevisionCompactor, GridBlockRevisionEditor};
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
use crate::services::row::{block_from_row_orders, make_row_from_row_rev, GridBlockSnapshot};
|
||||
use dashmap::DashMap;
|
||||
@ -17,8 +17,6 @@ use std::sync::Arc;
|
||||
|
||||
type BlockId = String;
|
||||
pub(crate) struct GridBlockManager {
|
||||
#[allow(dead_code)]
|
||||
grid_id: String,
|
||||
user: Arc<dyn GridUser>,
|
||||
persistence: Arc<BlockIndexCache>,
|
||||
block_editors: DashMap<BlockId, Arc<GridBlockRevisionEditor>>,
|
||||
@ -26,16 +24,13 @@ pub(crate) struct GridBlockManager {
|
||||
|
||||
impl GridBlockManager {
|
||||
pub(crate) async fn new(
|
||||
grid_id: &str,
|
||||
user: &Arc<dyn GridUser>,
|
||||
block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
|
||||
persistence: Arc<BlockIndexCache>,
|
||||
) -> FlowyResult<Self> {
|
||||
let block_editors = make_block_editors(user, block_meta_revs).await?;
|
||||
let user = user.clone();
|
||||
let grid_id = grid_id.to_owned();
|
||||
let manager = Self {
|
||||
grid_id,
|
||||
user,
|
||||
block_editors,
|
||||
persistence,
|
||||
@ -44,7 +39,7 @@ impl GridBlockManager {
|
||||
}
|
||||
|
||||
// #[tracing::instrument(level = "trace", skip(self))]
|
||||
pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<GridBlockRevisionEditor>> {
|
||||
pub(crate) async fn get_block_editor(&self, block_id: &str) -> FlowyResult<Arc<GridBlockRevisionEditor>> {
|
||||
debug_assert!(!block_id.is_empty());
|
||||
match self.block_editors.get(block_id) {
|
||||
None => {
|
||||
@ -59,13 +54,13 @@ impl GridBlockManager {
|
||||
|
||||
async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult<Arc<GridBlockRevisionEditor>> {
|
||||
let block_id = self.persistence.get_block_id(row_id)?;
|
||||
Ok(self.get_editor(&block_id).await?)
|
||||
Ok(self.get_block_editor(&block_id).await?)
|
||||
}
|
||||
|
||||
pub(crate) async fn create_row(&self, row_rev: RowRevision, start_row_id: Option<String>) -> FlowyResult<i32> {
|
||||
let block_id = row_rev.block_id.clone();
|
||||
let _ = self.persistence.insert(&row_rev.block_id, &row_rev.id)?;
|
||||
let editor = self.get_editor(&row_rev.block_id).await?;
|
||||
let editor = self.get_block_editor(&row_rev.block_id).await?;
|
||||
|
||||
let mut index_row_order = InsertedRowPB::from(&row_rev);
|
||||
let (row_count, row_index) = editor.create_row(row_rev, start_row_id).await?;
|
||||
@ -82,7 +77,7 @@ impl GridBlockManager {
|
||||
let mut changesets = vec![];
|
||||
for (block_id, row_revs) in rows_by_block_id {
|
||||
let mut inserted_row_orders = vec![];
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let editor = self.get_block_editor(&block_id).await?;
|
||||
let mut row_count = 0;
|
||||
for row in row_revs {
|
||||
let _ = self.persistence.insert(&row.block_id, &row.id)?;
|
||||
@ -130,7 +125,7 @@ impl GridBlockManager {
|
||||
pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> {
|
||||
let row_id = row_id.to_owned();
|
||||
let block_id = self.persistence.get_block_id(&row_id)?;
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let editor = self.get_block_editor(&block_id).await?;
|
||||
match editor.get_row_info(&row_id).await? {
|
||||
None => {}
|
||||
Some(row_info) => {
|
||||
@ -147,7 +142,7 @@ impl GridBlockManager {
|
||||
pub(crate) async fn delete_rows(&self, row_orders: Vec<RowPB>) -> FlowyResult<Vec<GridBlockMetaRevisionChangeset>> {
|
||||
let mut changesets = vec![];
|
||||
for grid_block in block_from_row_orders(row_orders) {
|
||||
let editor = self.get_editor(&grid_block.id).await?;
|
||||
let editor = self.get_block_editor(&grid_block.id).await?;
|
||||
let row_ids = grid_block
|
||||
.rows
|
||||
.into_iter()
|
||||
@ -207,7 +202,7 @@ impl GridBlockManager {
|
||||
}
|
||||
|
||||
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowPB>> {
|
||||
let editor = self.get_editor(block_id).await?;
|
||||
let editor = self.get_block_editor(block_id).await?;
|
||||
editor.get_row_infos::<&str>(None).await
|
||||
}
|
||||
|
||||
@ -227,7 +222,7 @@ impl GridBlockManager {
|
||||
}
|
||||
Some(block_ids) => {
|
||||
for block_id in block_ids {
|
||||
let editor = self.get_editor(&block_id).await?;
|
||||
let editor = self.get_block_editor(&block_id).await?;
|
||||
let row_revs = editor.get_row_revs::<&str>(None).await?;
|
||||
snapshots.push(GridBlockSnapshot { block_id, row_revs });
|
||||
}
|
||||
@ -250,6 +245,7 @@ impl GridBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize each block editor
|
||||
async fn make_block_editors(
|
||||
user: &Arc<dyn GridUser>,
|
||||
block_meta_revs: Vec<Arc<GridBlockMetaRevision>>,
|
||||
@ -264,7 +260,7 @@ async fn make_block_editors(
|
||||
}
|
||||
|
||||
async fn make_block_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<GridBlockRevisionEditor> {
|
||||
tracing::trace!("Open block:{} meta editor", block_id);
|
||||
tracing::trace!("Open block:{} editor", block_id);
|
||||
let token = user.token()?;
|
||||
let user_id = user.user_id()?;
|
||||
let pool = user.db_pool()?;
|
||||
|
@ -3,7 +3,7 @@ use crate::entities::{
|
||||
SelectOptionFilterConfigurationPB, TextFilterConfigurationPB,
|
||||
};
|
||||
use dashmap::DashMap;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use flowy_grid_data_model::revision::{FieldRevision, FilterConfigurationRevision, RowRevision};
|
||||
use flowy_sync::client_grid::GridRevisionPad;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
@ -74,6 +74,7 @@ impl FilterCache {
|
||||
this
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn remove(&self, filter_id: &FilterId) {
|
||||
let _ = match filter_id.field_type {
|
||||
FieldType::RichText => {
|
||||
@ -104,13 +105,15 @@ impl FilterCache {
|
||||
/// Refresh the filter according to the field id.
|
||||
pub(crate) async fn refresh_filter_cache(
|
||||
cache: Arc<FilterCache>,
|
||||
field_ids: Option<Vec<String>>,
|
||||
_field_ids: Option<Vec<String>>,
|
||||
grid_pad: &Arc<RwLock<GridRevisionPad>>,
|
||||
) {
|
||||
let grid_pad = grid_pad.read().await;
|
||||
let filters_revs = grid_pad.get_filters(field_ids).unwrap_or_default();
|
||||
// let filters_revs = grid_pad.get_filters(field_ids).unwrap_or_default();
|
||||
// TODO nathan
|
||||
let filter_revs: Vec<Arc<FilterConfigurationRevision>> = vec![];
|
||||
|
||||
for filter_rev in filters_revs {
|
||||
for filter_rev in filter_revs {
|
||||
match grid_pad.get_field_rev(&filter_rev.field_id) {
|
||||
None => {}
|
||||
Some((_, field_rev)) => {
|
||||
|
@ -1,3 +1,8 @@
|
||||
#![allow(clippy::all)]
|
||||
#![allow(unused_attributes)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(unused_results)]
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::entities::{FieldType, GridBlockChangesetPB};
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
@ -22,8 +27,10 @@ use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub(crate) struct GridFilterService {
|
||||
#[allow(dead_code)]
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
#[allow(dead_code)]
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
filter_cache: Arc<FilterCache>,
|
||||
filter_result_cache: Arc<FilterResultCache>,
|
||||
|
@ -5,14 +5,13 @@ use crate::manager::{GridTaskSchedulerRwLock, GridUser};
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes};
|
||||
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
|
||||
use crate::services::filter::{GridFilterChangeset, GridFilterService};
|
||||
|
||||
use crate::services::group::GridGroupService;
|
||||
use crate::services::filter::GridFilterService;
|
||||
use crate::services::grid_view_manager::GridViewManager;
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
use crate::services::row::{
|
||||
make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder,
|
||||
};
|
||||
use crate::services::setting::make_grid_setting;
|
||||
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::revision::*;
|
||||
@ -21,26 +20,23 @@ use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeseri
|
||||
use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};
|
||||
use flowy_sync::entities::revision::Revision;
|
||||
use flowy_sync::errors::CollaborateResult;
|
||||
use flowy_sync::util::make_delta_from_revisions;
|
||||
use flowy_sync::util::make_text_delta_from_revisions;
|
||||
use lib_infra::future::FutureResult;
|
||||
use lib_ot::core::PhantomAttributes;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub struct GridRevisionEditor {
|
||||
pub(crate) grid_id: String,
|
||||
pub grid_id: String,
|
||||
user: Arc<dyn GridUser>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
// view_editor: Arc<GridViewRevisionEditor>,
|
||||
view_manager: Arc<GridViewManager>,
|
||||
rev_manager: Arc<RevisionManager>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) filter_service: Arc<GridFilterService>,
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) group_service: Arc<RwLock<GridGroupService>>,
|
||||
}
|
||||
|
||||
impl Drop for GridRevisionEditor {
|
||||
@ -63,20 +59,30 @@ impl GridRevisionEditor {
|
||||
let rev_manager = Arc::new(rev_manager);
|
||||
let grid_pad = Arc::new(RwLock::new(grid_pad));
|
||||
|
||||
// Block manager
|
||||
let block_meta_revs = grid_pad.read().await.get_block_meta_revs();
|
||||
let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?);
|
||||
let block_manager = Arc::new(GridBlockManager::new(&user, block_meta_revs, persistence).await?);
|
||||
let filter_service =
|
||||
GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await;
|
||||
let group_service =
|
||||
GridGroupService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await;
|
||||
|
||||
// View manager
|
||||
let view_manager = Arc::new(
|
||||
GridViewManager::new(
|
||||
user.clone(),
|
||||
grid_pad.clone(),
|
||||
block_manager.clone(),
|
||||
Arc::new(task_scheduler.clone()),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
let editor = Arc::new(Self {
|
||||
grid_id: grid_id.to_owned(),
|
||||
user,
|
||||
grid_pad,
|
||||
rev_manager,
|
||||
block_manager,
|
||||
view_manager,
|
||||
filter_service: Arc::new(filter_service),
|
||||
group_service: Arc::new(RwLock::new(group_service)),
|
||||
});
|
||||
|
||||
Ok(editor)
|
||||
@ -278,9 +284,15 @@ impl GridRevisionEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowPB> {
|
||||
let row_rev = self.create_row_rev().await?;
|
||||
self.create_row_pb(row_rev, start_row_id).await
|
||||
pub async fn create_row(&self, params: CreateRowParams) -> FlowyResult<RowPB> {
|
||||
let mut row_rev = self.create_row_rev().await?;
|
||||
|
||||
self.view_manager.update_row(&mut row_rev, ¶ms).await;
|
||||
|
||||
let row_pb = self.create_row_pb(row_rev, params.start_row_id.clone()).await?;
|
||||
|
||||
self.view_manager.did_create_row(&row_pb, ¶ms).await;
|
||||
Ok(row_pb)
|
||||
}
|
||||
|
||||
pub async fn insert_rows(&self, row_revs: Vec<RowRevision>) -> FlowyResult<Vec<RowPB>> {
|
||||
@ -330,7 +342,7 @@ impl GridRevisionEditor {
|
||||
|
||||
pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> {
|
||||
let _ = self.block_manager.delete_row(row_id).await?;
|
||||
self.group_service.read().await.did_delete_card(row_id.to_owned()).await;
|
||||
self.view_manager.delete_row(row_id).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -444,34 +456,15 @@ impl GridRevisionEditor {
|
||||
}
|
||||
|
||||
pub async fn get_grid_setting(&self) -> FlowyResult<GridSettingPB> {
|
||||
let read_guard = self.grid_pad.read().await;
|
||||
let grid_setting_rev = read_guard.get_setting_rev();
|
||||
let field_revs = read_guard.get_field_revs(None)?;
|
||||
let grid_setting = make_grid_setting(grid_setting_rev, &field_revs);
|
||||
Ok(grid_setting)
|
||||
self.view_manager.get_setting().await
|
||||
}
|
||||
|
||||
pub async fn get_grid_filter(&self) -> FlowyResult<Vec<GridFilterConfiguration>> {
|
||||
let read_guard = self.grid_pad.read().await;
|
||||
match read_guard.get_filters(None) {
|
||||
Some(filter_revs) => Ok(filter_revs
|
||||
.iter()
|
||||
.map(|filter_rev| filter_rev.as_ref().into())
|
||||
.collect::<Vec<GridFilterConfiguration>>()),
|
||||
None => Ok(vec![]),
|
||||
}
|
||||
self.view_manager.get_filters().await
|
||||
}
|
||||
|
||||
pub async fn update_grid_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> {
|
||||
let filter_changeset = GridFilterChangeset::from(¶ms);
|
||||
let _ = self
|
||||
.modify(|grid_pad| Ok(grid_pad.update_grid_setting_rev(params)?))
|
||||
.await?;
|
||||
|
||||
let filter_service = self.filter_service.clone();
|
||||
tokio::spawn(async move {
|
||||
filter_service.apply_changeset(filter_changeset).await;
|
||||
});
|
||||
let _ = self.view_manager.update_setting(params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -521,22 +514,9 @@ impl GridRevisionEditor {
|
||||
}
|
||||
|
||||
pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> {
|
||||
match self.block_manager.get_row_rev(row_id).await? {
|
||||
None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
|
||||
Some(row_rev) => {
|
||||
let _ = self
|
||||
.block_manager
|
||||
.move_row(row_rev.clone(), from as usize, to as usize)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
self.view_manager.move_row(row_id, from, to).await
|
||||
}
|
||||
|
||||
pub async fn move_board_card(&self, group_id: &str, from: i32, to: i32) -> FlowyResult<()> {
|
||||
self.group_service.write().await.move_card(group_id, from, to).await;
|
||||
Ok(())
|
||||
}
|
||||
pub async fn delta_bytes(&self) -> Bytes {
|
||||
self.grid_pad.read().await.delta_bytes()
|
||||
}
|
||||
@ -549,7 +529,10 @@ impl GridRevisionEditor {
|
||||
let mut blocks_meta_data = vec![];
|
||||
if original_blocks.len() == duplicated_blocks.len() {
|
||||
for (index, original_block_meta) in original_blocks.iter().enumerate() {
|
||||
let grid_block_meta_editor = self.block_manager.get_editor(&original_block_meta.block_id).await?;
|
||||
let grid_block_meta_editor = self
|
||||
.block_manager
|
||||
.get_block_editor(&original_block_meta.block_id)
|
||||
.await?;
|
||||
let duplicated_block_id = &duplicated_blocks[index].block_id;
|
||||
|
||||
tracing::trace!("Duplicate block:{} meta data", duplicated_block_id);
|
||||
@ -568,24 +551,9 @@ impl GridRevisionEditor {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn create_board_card(&self, group_id: &str) -> FlowyResult<RowPB> {
|
||||
let mut row_rev = self.create_row_rev().await?;
|
||||
let _ = self
|
||||
.group_service
|
||||
.write()
|
||||
.await
|
||||
.update_board_card(&mut row_rev, group_id)
|
||||
.await;
|
||||
|
||||
let row_pb = self.create_row_pb(row_rev, None).await?;
|
||||
self.group_service.read().await.did_create_card(group_id, &row_pb).await;
|
||||
Ok(row_pb)
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all, err)]
|
||||
pub async fn load_groups(&self) -> FlowyResult<RepeatedGridGroupPB> {
|
||||
let groups = self.group_service.write().await.load_groups().await.unwrap_or_default();
|
||||
Ok(RepeatedGridGroupPB { items: groups })
|
||||
self.view_manager.load_groups().await
|
||||
}
|
||||
|
||||
async fn create_row_rev(&self) -> FlowyResult<RowRevision> {
|
||||
@ -716,7 +684,7 @@ impl RevisionCloudService for GridRevisionCloudService {
|
||||
pub struct GridRevisionCompactor();
|
||||
impl RevisionCompactor for GridRevisionCompactor {
|
||||
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
|
||||
let delta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
|
||||
let delta = make_text_delta_from_revisions(revisions)?;
|
||||
Ok(delta.json_bytes())
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,163 @@
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
|
||||
use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, GroupPB, RowPB};
|
||||
use crate::services::grid_editor_task::GridServiceTaskScheduler;
|
||||
use crate::services::group::{default_group_configuration, GroupConfigurationDelegate, GroupService};
|
||||
use flowy_grid_data_model::revision::{FieldRevision, GroupConfigurationRevision, RowRevision};
|
||||
use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder};
|
||||
use flowy_sync::client_grid::GridViewRevisionPad;
|
||||
use flowy_sync::client_grid::{GridViewRevisionChangeset, GridViewRevisionPad};
|
||||
use flowy_sync::entities::revision::Revision;
|
||||
use lib_infra::future::FutureResult;
|
||||
|
||||
use crate::services::setting::make_grid_setting;
|
||||
use flowy_sync::entities::grid::GridSettingChangesetParams;
|
||||
use lib_infra::future::{wrap_future, AFFuture, FutureResult};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub trait GridViewRevisionDelegate: Send + Sync + 'static {
|
||||
fn get_field_revs(&self) -> AFFuture<Vec<Arc<FieldRevision>>>;
|
||||
fn get_field_rev(&self, field_id: &str) -> AFFuture<Option<Arc<FieldRevision>>>;
|
||||
}
|
||||
|
||||
pub trait GridViewRevisionDataSource: Send + Sync + 'static {
|
||||
fn row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>>;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct GridViewRevisionEditor {
|
||||
#[allow(dead_code)]
|
||||
user_id: String,
|
||||
view_id: String,
|
||||
pad: Arc<RwLock<GridViewRevisionPad>>,
|
||||
#[allow(dead_code)]
|
||||
rev_manager: Arc<RevisionManager>,
|
||||
delegate: Arc<dyn GridViewRevisionDelegate>,
|
||||
data_source: Arc<dyn GridViewRevisionDataSource>,
|
||||
group_service: Arc<RwLock<GroupService>>,
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
}
|
||||
|
||||
impl GridViewRevisionEditor {
|
||||
#[allow(dead_code)]
|
||||
pub async fn new(token: &str, mut rev_manager: RevisionManager) -> FlowyResult<Self> {
|
||||
pub(crate) async fn new<Delegate, DataSource>(
|
||||
user_id: &str,
|
||||
token: &str,
|
||||
view_id: String,
|
||||
delegate: Delegate,
|
||||
data_source: DataSource,
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
mut rev_manager: RevisionManager,
|
||||
) -> FlowyResult<Self>
|
||||
where
|
||||
Delegate: GridViewRevisionDelegate,
|
||||
DataSource: GridViewRevisionDataSource,
|
||||
{
|
||||
let cloud = Arc::new(GridViewRevisionCloudService {
|
||||
token: token.to_owned(),
|
||||
});
|
||||
let view_revision_pad = rev_manager.load::<GridViewRevisionPadBuilder>(Some(cloud)).await?;
|
||||
let pad = Arc::new(RwLock::new(view_revision_pad));
|
||||
let rev_manager = Arc::new(rev_manager);
|
||||
let group_service = GroupService::new(Box::new(pad.clone())).await;
|
||||
let user_id = user_id.to_owned();
|
||||
Ok(Self {
|
||||
pad,
|
||||
user_id,
|
||||
view_id,
|
||||
rev_manager,
|
||||
scheduler,
|
||||
delegate: Arc::new(delegate),
|
||||
data_source: Arc::new(data_source),
|
||||
group_service: Arc::new(RwLock::new(group_service)),
|
||||
})
|
||||
}
|
||||
|
||||
Ok(Self { pad, rev_manager })
|
||||
pub(crate) async fn create_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
|
||||
match params.group_id.as_ref() {
|
||||
None => {}
|
||||
Some(group_id) => {
|
||||
self.group_service
|
||||
.read()
|
||||
.await
|
||||
.update_row(row_rev, group_id, |field_id| self.delegate.get_field_rev(&field_id))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub(crate) async fn did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
|
||||
match params.group_id.as_ref() {
|
||||
None => {}
|
||||
Some(group_id) => {
|
||||
self.group_service.read().await.did_create_row(group_id, row_pb).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_row(&self, row_id: &str) {
|
||||
self.group_service.read().await.did_delete_card(row_id.to_owned()).await;
|
||||
}
|
||||
|
||||
pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
|
||||
let field_revs = self.delegate.get_field_revs().await;
|
||||
let row_revs = self.data_source.row_revs().await;
|
||||
let mut write_guard = self.group_service.write().await;
|
||||
match write_guard.load_groups(&field_revs, row_revs).await {
|
||||
None => Ok(vec![]),
|
||||
Some(groups) => Ok(groups),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_setting(&self) -> GridSettingPB {
|
||||
let field_revs = self.delegate.get_field_revs().await;
|
||||
let grid_setting = make_grid_setting(self.pad.read().await.get_setting_rev(), &field_revs);
|
||||
grid_setting
|
||||
}
|
||||
|
||||
pub(crate) async fn update_setting(&self, changeset: GridSettingChangesetParams) -> FlowyResult<()> {
|
||||
let _ = self.modify(|pad| Ok(pad.update_setting(changeset)?)).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_filters(&self) -> Vec<GridFilterConfiguration> {
|
||||
let field_revs = self.delegate.get_field_revs().await;
|
||||
match self.pad.read().await.get_setting_rev().get_all_filters(&field_revs) {
|
||||
None => vec![],
|
||||
Some(filters) => filters
|
||||
.into_values()
|
||||
.flatten()
|
||||
.map(|filter| GridFilterConfiguration::from(filter.as_ref()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn modify<F>(&self, f: F) -> FlowyResult<()>
|
||||
where
|
||||
F: for<'a> FnOnce(&'a mut GridViewRevisionPad) -> FlowyResult<Option<GridViewRevisionChangeset>>,
|
||||
{
|
||||
let mut write_guard = self.pad.write().await;
|
||||
match f(&mut *write_guard)? {
|
||||
None => {}
|
||||
Some(change) => {
|
||||
let _ = self.apply_change(change).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_change(&self, change: GridViewRevisionChangeset) -> FlowyResult<()> {
|
||||
let GridViewRevisionChangeset { delta, md5 } = change;
|
||||
let user_id = self.user_id.clone();
|
||||
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
|
||||
let delta_data = delta.json_bytes();
|
||||
let revision = Revision::new(
|
||||
&self.rev_manager.object_id,
|
||||
base_rev_id,
|
||||
rev_id,
|
||||
delta_data,
|
||||
&user_id,
|
||||
md5,
|
||||
);
|
||||
let _ = self.rev_manager.add_local_revision(&revision).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,3 +182,20 @@ impl RevisionObjectBuilder for GridViewRevisionPadBuilder {
|
||||
Ok(pad)
|
||||
}
|
||||
}
|
||||
|
||||
impl GroupConfigurationDelegate for Arc<RwLock<GridViewRevisionPad>> {
|
||||
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision> {
|
||||
let view_pad = self.clone();
|
||||
wrap_future(async move {
|
||||
let grid_pad = view_pad.read().await;
|
||||
let configurations = grid_pad.get_groups(&field_rev.id, &field_rev.field_type_rev);
|
||||
match configurations {
|
||||
None => default_group_configuration(&field_rev),
|
||||
Some(mut configurations) => {
|
||||
assert_eq!(configurations.len(), 1);
|
||||
(&*configurations.pop().unwrap()).clone()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
217
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
Normal file
217
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs
Normal file
@ -0,0 +1,217 @@
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::grid_view_editor::{GridViewRevisionDataSource, GridViewRevisionDelegate, GridViewRevisionEditor};
|
||||
use bytes::Bytes;
|
||||
|
||||
use crate::entities::{CreateRowParams, GridFilterConfiguration, GridSettingPB, RepeatedGridGroupPB, RowPB};
|
||||
use crate::services::grid_editor_task::GridServiceTaskScheduler;
|
||||
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use dashmap::DashMap;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use flowy_revision::disk::SQLiteGridViewRevisionPersistence;
|
||||
use flowy_revision::{RevisionCompactor, RevisionManager, RevisionPersistence, SQLiteRevisionSnapshotPersistence};
|
||||
use flowy_sync::client_grid::GridRevisionPad;
|
||||
use flowy_sync::entities::revision::Revision;
|
||||
|
||||
use flowy_sync::util::make_text_delta_from_revisions;
|
||||
|
||||
use flowy_sync::entities::grid::GridSettingChangesetParams;
|
||||
|
||||
use lib_infra::future::{wrap_future, AFFuture};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
type ViewId = String;
|
||||
|
||||
pub(crate) struct GridViewManager {
|
||||
user: Arc<dyn GridUser>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>,
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
}
|
||||
|
||||
impl GridViewManager {
|
||||
pub(crate) async fn new(
|
||||
user: Arc<dyn GridUser>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
) -> FlowyResult<Self> {
|
||||
Ok(Self {
|
||||
user,
|
||||
grid_pad,
|
||||
scheduler,
|
||||
block_manager,
|
||||
view_editors: DashMap::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn update_row(&self, row_rev: &mut RowRevision, params: &CreateRowParams) {
|
||||
for view_editor in self.view_editors.iter() {
|
||||
view_editor.create_row(row_rev, params).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn did_create_row(&self, row_pb: &RowPB, params: &CreateRowParams) {
|
||||
for view_editor in self.view_editors.iter() {
|
||||
view_editor.did_create_row(row_pb, params).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn delete_row(&self, row_id: &str) {
|
||||
for view_editor in self.view_editors.iter() {
|
||||
view_editor.delete_row(row_id).await;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_setting(&self) -> FlowyResult<GridSettingPB> {
|
||||
let view_editor = self.get_default_view_editor().await?;
|
||||
Ok(view_editor.get_setting().await)
|
||||
}
|
||||
|
||||
pub(crate) async fn update_setting(&self, params: GridSettingChangesetParams) -> FlowyResult<()> {
|
||||
let view_editor = self.get_default_view_editor().await?;
|
||||
let _ = view_editor.update_setting(params).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_filters(&self) -> FlowyResult<Vec<GridFilterConfiguration>> {
|
||||
let view_editor = self.get_default_view_editor().await?;
|
||||
Ok(view_editor.get_filters().await)
|
||||
}
|
||||
|
||||
pub(crate) async fn load_groups(&self) -> FlowyResult<RepeatedGridGroupPB> {
|
||||
let view_editor = self.get_default_view_editor().await?;
|
||||
let groups = view_editor.load_groups().await?;
|
||||
Ok(RepeatedGridGroupPB { items: groups })
|
||||
}
|
||||
|
||||
pub(crate) async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> {
|
||||
match self.block_manager.get_row_rev(row_id).await? {
|
||||
None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
|
||||
Some(row_rev) => {
|
||||
let _ = self
|
||||
.block_manager
|
||||
.move_row(row_rev.clone(), from as usize, to as usize)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_view_editor(&self, view_id: &str) -> FlowyResult<Arc<GridViewRevisionEditor>> {
|
||||
debug_assert!(!view_id.is_empty());
|
||||
match self.view_editors.get(view_id) {
|
||||
None => {
|
||||
let editor = Arc::new(
|
||||
make_view_editor(
|
||||
&self.user,
|
||||
view_id,
|
||||
self.grid_pad.clone(),
|
||||
self.block_manager.clone(),
|
||||
self.scheduler.clone(),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
self.view_editors.insert(view_id.to_owned(), editor.clone());
|
||||
Ok(editor)
|
||||
}
|
||||
Some(view_editor) => Ok(view_editor.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_default_view_editor(&self) -> FlowyResult<Arc<GridViewRevisionEditor>> {
|
||||
let grid_id = self.grid_pad.read().await.grid_id();
|
||||
self.get_view_editor(&grid_id).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn make_view_editor<Delegate, DataSource>(
|
||||
user: &Arc<dyn GridUser>,
|
||||
view_id: &str,
|
||||
delegate: Delegate,
|
||||
data_source: DataSource,
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
) -> FlowyResult<GridViewRevisionEditor>
|
||||
where
|
||||
Delegate: GridViewRevisionDelegate,
|
||||
DataSource: GridViewRevisionDataSource,
|
||||
{
|
||||
tracing::trace!("Open view:{} editor", view_id);
|
||||
|
||||
let rev_manager = make_grid_view_rev_manager(user, view_id).await?;
|
||||
let user_id = user.user_id()?;
|
||||
let token = user.token()?;
|
||||
let view_id = view_id.to_owned();
|
||||
GridViewRevisionEditor::new(&user_id, &token, view_id, delegate, data_source, scheduler, rev_manager).await
|
||||
}
|
||||
|
||||
pub async fn make_grid_view_rev_manager(user: &Arc<dyn GridUser>, view_id: &str) -> FlowyResult<RevisionManager> {
|
||||
tracing::trace!("Open view:{} editor", view_id);
|
||||
let user_id = user.user_id()?;
|
||||
let pool = user.db_pool()?;
|
||||
|
||||
let disk_cache = SQLiteGridViewRevisionPersistence::new(&user_id, pool.clone());
|
||||
let rev_persistence = RevisionPersistence::new(&user_id, view_id, disk_cache);
|
||||
let rev_compactor = GridViewRevisionCompactor();
|
||||
|
||||
let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(view_id, pool);
|
||||
Ok(RevisionManager::new(
|
||||
&user_id,
|
||||
view_id,
|
||||
rev_persistence,
|
||||
rev_compactor,
|
||||
snapshot_persistence,
|
||||
))
|
||||
}
|
||||
|
||||
pub struct GridViewRevisionCompactor();
|
||||
impl RevisionCompactor for GridViewRevisionCompactor {
|
||||
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
|
||||
let delta = make_text_delta_from_revisions(revisions)?;
|
||||
Ok(delta.json_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl GridViewRevisionDataSource for Arc<GridBlockManager> {
|
||||
fn row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>> {
|
||||
let block_manager = self.clone();
|
||||
|
||||
wrap_future(async move {
|
||||
let blocks = block_manager.get_block_snapshots(None).await.unwrap();
|
||||
blocks
|
||||
.into_iter()
|
||||
.map(|block| block.row_revs)
|
||||
.flatten()
|
||||
.collect::<Vec<Arc<RowRevision>>>()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GridViewRevisionDelegate for Arc<RwLock<GridRevisionPad>> {
|
||||
fn get_field_revs(&self) -> AFFuture<Vec<Arc<FieldRevision>>> {
|
||||
let pad = self.clone();
|
||||
wrap_future(async move {
|
||||
match pad.read().await.get_field_revs(None) {
|
||||
Ok(field_revs) => field_revs,
|
||||
Err(e) => {
|
||||
tracing::error!("[GridViewRevisionDelegate] get field revisions failed: {}", e);
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_field_rev(&self, field_id: &str) -> AFFuture<Option<Arc<FieldRevision>>> {
|
||||
let pad = self.clone();
|
||||
let field_id = field_id.to_owned();
|
||||
wrap_future(async move {
|
||||
pad.read()
|
||||
.await
|
||||
.get_field_rev(&field_id)
|
||||
.map(|(_, field_rev)| field_rev.clone())
|
||||
})
|
||||
}
|
||||
}
|
@ -4,9 +4,7 @@ use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
|
||||
use crate::services::group::{
|
||||
Group, GroupActionHandler, GroupCellContentProvider, GroupController, GroupGenerator, Groupable,
|
||||
};
|
||||
use crate::services::group::{Group, GroupActionHandler, GroupController, GroupGenerator, Groupable};
|
||||
|
||||
pub type CheckboxGroupController =
|
||||
GroupController<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB, CheckboxGroupGenerator, CheckboxCellDataParser>;
|
||||
@ -45,7 +43,6 @@ impl GroupGenerator for CheckboxGroupGenerator {
|
||||
fn generate_groups(
|
||||
_configuration: &Option<Self::ConfigurationType>,
|
||||
_type_option: &Option<Self::TypeOptionType>,
|
||||
_cell_content_provider: &dyn GroupCellContentProvider,
|
||||
) -> Vec<Group> {
|
||||
let check_group = Group {
|
||||
id: "true".to_string(),
|
||||
|
@ -11,14 +11,6 @@ use indexmap::IndexMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait GroupCellContentProvider {
|
||||
/// We need to group the rows base on the deduplication cell content when the field type is
|
||||
/// RichText.
|
||||
fn deduplication_cell_content(&self, _field_id: &str) -> Vec<String> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GroupGenerator {
|
||||
type ConfigurationType;
|
||||
type TypeOptionType;
|
||||
@ -26,7 +18,6 @@ pub trait GroupGenerator {
|
||||
fn generate_groups(
|
||||
configuration: &Option<Self::ConfigurationType>,
|
||||
type_option: &Option<Self::TypeOptionType>,
|
||||
cell_content_provider: &dyn GroupCellContentProvider,
|
||||
) -> Vec<Group>;
|
||||
}
|
||||
|
||||
@ -86,18 +77,14 @@ where
|
||||
T: TypeOptionDataDeserializer,
|
||||
G: GroupGenerator<ConfigurationType = C, TypeOptionType = T>,
|
||||
{
|
||||
pub fn new(
|
||||
field_rev: &Arc<FieldRevision>,
|
||||
configuration: GroupConfigurationRevision,
|
||||
cell_content_provider: &dyn GroupCellContentProvider,
|
||||
) -> FlowyResult<Self> {
|
||||
pub fn new(field_rev: &Arc<FieldRevision>, configuration: GroupConfigurationRevision) -> FlowyResult<Self> {
|
||||
let configuration = match configuration.content {
|
||||
None => None,
|
||||
Some(content) => Some(C::try_from(Bytes::from(content))?),
|
||||
};
|
||||
let field_type_rev = field_rev.field_type_rev;
|
||||
let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
|
||||
let groups = G::generate_groups(&configuration, &type_option, cell_content_provider);
|
||||
let groups = G::generate_groups(&configuration, &type_option);
|
||||
|
||||
let default_group = Group {
|
||||
id: DEFAULT_GROUP_ID.to_owned(),
|
||||
|
@ -8,9 +8,7 @@ use std::sync::Arc;
|
||||
use crate::services::field::{
|
||||
MultiSelectTypeOptionPB, SelectOptionCellDataPB, SelectOptionCellDataParser, SingleSelectTypeOptionPB,
|
||||
};
|
||||
use crate::services::group::{
|
||||
Group, GroupActionHandler, GroupCellContentProvider, GroupController, GroupGenerator, Groupable,
|
||||
};
|
||||
use crate::services::group::{Group, GroupActionHandler, GroupController, GroupGenerator, Groupable};
|
||||
|
||||
// SingleSelect
|
||||
pub type SingleSelectGroupController = GroupController<
|
||||
@ -59,7 +57,6 @@ impl GroupGenerator for SingleSelectGroupGenerator {
|
||||
fn generate_groups(
|
||||
_configuration: &Option<Self::ConfigurationType>,
|
||||
type_option: &Option<Self::TypeOptionType>,
|
||||
_cell_content_provider: &dyn GroupCellContentProvider,
|
||||
) -> Vec<Group> {
|
||||
match type_option {
|
||||
None => vec![],
|
||||
@ -125,7 +122,6 @@ impl GroupGenerator for MultiSelectGroupGenerator {
|
||||
fn generate_groups(
|
||||
_configuration: &Option<Self::ConfigurationType>,
|
||||
type_option: &Option<Self::TypeOptionType>,
|
||||
_cell_content_provider: &dyn GroupCellContentProvider,
|
||||
) -> Vec<Group> {
|
||||
match type_option {
|
||||
None => vec![],
|
||||
|
@ -4,55 +4,42 @@ use crate::entities::{
|
||||
NumberGroupConfigurationPB, RowPB, SelectOptionGroupConfigurationPB, TextGroupConfigurationPB,
|
||||
UrlGroupConfigurationPB,
|
||||
};
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use crate::services::grid_editor_task::GridServiceTaskScheduler;
|
||||
use crate::services::group::{
|
||||
CheckboxGroupController, GroupActionHandler, GroupCellContentProvider, MultiSelectGroupController,
|
||||
SingleSelectGroupController,
|
||||
CheckboxGroupController, GroupActionHandler, MultiSelectGroupController, SingleSelectGroupController,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::revision::{gen_grid_group_id, FieldRevision, GroupConfigurationRevision, RowRevision};
|
||||
use flowy_sync::client_grid::GridRevisionPad;
|
||||
|
||||
use lib_infra::future::AFFuture;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub(crate) struct GridGroupService {
|
||||
#[allow(dead_code)]
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
group_action_handler: Option<Arc<RwLock<dyn GroupActionHandler>>>,
|
||||
pub trait GroupConfigurationDelegate: Send + Sync + 'static {
|
||||
fn get_group_configuration(&self, field_rev: Arc<FieldRevision>) -> AFFuture<GroupConfigurationRevision>;
|
||||
}
|
||||
|
||||
impl GridGroupService {
|
||||
pub(crate) async fn new<S: GridServiceTaskScheduler>(
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
scheduler: S,
|
||||
) -> Self {
|
||||
let scheduler = Arc::new(scheduler);
|
||||
pub(crate) struct GroupService {
|
||||
delegate: Box<dyn GroupConfigurationDelegate>,
|
||||
action_handler: Option<Arc<RwLock<dyn GroupActionHandler>>>,
|
||||
}
|
||||
|
||||
impl GroupService {
|
||||
pub(crate) async fn new(delegate: Box<dyn GroupConfigurationDelegate>) -> Self {
|
||||
Self {
|
||||
scheduler,
|
||||
grid_pad,
|
||||
block_manager,
|
||||
group_action_handler: None,
|
||||
delegate,
|
||||
action_handler: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn load_groups(&mut self) -> Option<Vec<GroupPB>> {
|
||||
let field_rev = find_group_field(self.grid_pad.read().await.fields()).unwrap();
|
||||
pub(crate) async fn load_groups(
|
||||
&mut self,
|
||||
field_revs: &[Arc<FieldRevision>],
|
||||
row_revs: Vec<Arc<RowRevision>>,
|
||||
) -> Option<Vec<GroupPB>> {
|
||||
let field_rev = find_group_field(field_revs).unwrap();
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
let configuration = self.get_group_configuration(&field_rev).await;
|
||||
|
||||
let blocks = self.block_manager.get_block_snapshots(None).await.unwrap();
|
||||
let row_revs = blocks
|
||||
.into_iter()
|
||||
.map(|block| block.row_revs)
|
||||
.flatten()
|
||||
.collect::<Vec<Arc<RowRevision>>>();
|
||||
let configuration = self.delegate.get_group_configuration(field_rev.clone()).await;
|
||||
|
||||
match self
|
||||
.build_groups(&field_type, &field_rev, row_revs, configuration)
|
||||
@ -63,36 +50,25 @@ impl GridGroupService {
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, row_rev))]
|
||||
pub(crate) async fn update_board_card(&self, row_rev: &mut RowRevision, group_id: &str) {
|
||||
if let Some(group_action_handler) = self.group_action_handler.as_ref() {
|
||||
pub(crate) async fn update_row<F, O>(&self, row_rev: &mut RowRevision, group_id: &str, f: F)
|
||||
where
|
||||
F: FnOnce(String) -> O,
|
||||
O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
|
||||
{
|
||||
if let Some(group_action_handler) = self.action_handler.as_ref() {
|
||||
let field_id = group_action_handler.read().await.field_id().to_owned();
|
||||
|
||||
match self.grid_pad.read().await.get_field_rev(&field_id) {
|
||||
None => tracing::warn!("Fail to create card because the field does not exist"),
|
||||
Some((_, field_rev)) => {
|
||||
match f(field_id).await {
|
||||
None => {}
|
||||
Some(field_rev) => {
|
||||
group_action_handler
|
||||
.write()
|
||||
.await
|
||||
.update_card(row_rev, field_rev, group_id);
|
||||
.update_card(row_rev, &field_rev, group_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_group_configuration(&self, field_rev: &FieldRevision) -> GroupConfigurationRevision {
|
||||
let grid_pad = self.grid_pad.read().await;
|
||||
let setting = grid_pad.get_setting_rev();
|
||||
let configurations = setting.get_groups(&field_rev.id, &field_rev.field_type_rev);
|
||||
match configurations {
|
||||
None => default_group_configuration(field_rev),
|
||||
Some(mut configurations) => {
|
||||
assert_eq!(configurations.len(), 1);
|
||||
(&*configurations.pop().unwrap()).clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn move_card(&self, _group_id: &str, _from: i32, _to: i32) {
|
||||
// BoardCardChangesetPB {
|
||||
// group_id: "".to_string(),
|
||||
@ -103,20 +79,20 @@ impl GridGroupService {
|
||||
// let row_pb = make_row_from_row_rev(row_rev);
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn did_delete_card(&self, _row_id: String) {
|
||||
// let changeset = BoardCardChangesetPB::delete(group_id.to_owned(), vec![row_id]);
|
||||
// self.notify_did_update_board(changeset).await;
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn did_create_card(&self, group_id: &str, row_pb: &RowPB) {
|
||||
pub async fn did_create_row(&self, group_id: &str, row_pb: &RowPB) {
|
||||
let changeset = BoardCardChangesetPB::insert(group_id.to_owned(), vec![row_pb.clone()]);
|
||||
self.notify_did_update_board(changeset).await;
|
||||
}
|
||||
|
||||
pub async fn notify_did_update_board(&self, changeset: BoardCardChangesetPB) {
|
||||
if self.group_action_handler.is_none() {
|
||||
if self.action_handler.is_none() {
|
||||
return;
|
||||
}
|
||||
send_dart_notification(&changeset.group_id, GridNotification::DidUpdateBoard)
|
||||
@ -143,16 +119,16 @@ impl GridGroupService {
|
||||
// let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let controller = SingleSelectGroupController::new(field_rev, configuration, &self.grid_pad)?;
|
||||
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||
let controller = SingleSelectGroupController::new(field_rev, configuration)?;
|
||||
self.action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let controller = MultiSelectGroupController::new(field_rev, configuration, &self.grid_pad)?;
|
||||
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||
let controller = MultiSelectGroupController::new(field_rev, configuration)?;
|
||||
self.action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let controller = CheckboxGroupController::new(field_rev, configuration, &self.grid_pad)?;
|
||||
self.group_action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||
let controller = CheckboxGroupController::new(field_rev, configuration)?;
|
||||
self.action_handler = Some(Arc::new(RwLock::new(controller)));
|
||||
}
|
||||
FieldType::URL => {
|
||||
// let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
|
||||
@ -160,7 +136,7 @@ impl GridGroupService {
|
||||
};
|
||||
|
||||
let mut groups = vec![];
|
||||
if let Some(group_action_handler) = self.group_action_handler.as_ref() {
|
||||
if let Some(group_action_handler) = self.action_handler.as_ref() {
|
||||
let mut write_guard = group_action_handler.write().await;
|
||||
let _ = write_guard.group_rows(&row_revs, field_rev)?;
|
||||
groups = write_guard.get_groups();
|
||||
@ -182,9 +158,7 @@ fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<Arc<FieldRevisi
|
||||
field_rev
|
||||
}
|
||||
|
||||
impl GroupCellContentProvider for Arc<RwLock<GridRevisionPad>> {}
|
||||
|
||||
fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision {
|
||||
pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurationRevision {
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
let bytes: Bytes = match field_type {
|
||||
FieldType::RichText => TextGroupConfigurationPB::default().try_into().unwrap(),
|
||||
|
@ -1,13 +1,14 @@
|
||||
mod util;
|
||||
|
||||
pub mod block_editor;
|
||||
mod block_manager;
|
||||
pub mod block_revision_editor;
|
||||
pub mod cell;
|
||||
pub mod field;
|
||||
mod filter;
|
||||
pub mod grid_editor;
|
||||
mod grid_editor_task;
|
||||
pub mod grid_view_editor;
|
||||
pub mod grid_view_manager;
|
||||
pub mod group;
|
||||
pub mod persistence;
|
||||
pub mod row;
|
||||
|
@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow};
|
||||
use crate::grid::block_test::util::GridRowTestBuilder;
|
||||
use crate::grid::grid_editor::GridEditorTest;
|
||||
|
||||
use flowy_grid::entities::{FieldType, GridCellIdParams, RowPB};
|
||||
use flowy_grid::entities::{CreateRowParams, FieldType, GridCellIdParams, RowPB};
|
||||
use flowy_grid::services::field::*;
|
||||
use flowy_grid_data_model::revision::{
|
||||
GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision,
|
||||
@ -77,7 +77,12 @@ impl GridRowTest {
|
||||
pub async fn run_script(&mut self, script: RowScript) {
|
||||
match script {
|
||||
RowScript::CreateEmptyRow => {
|
||||
let row_order = self.editor.create_row(None).await.unwrap();
|
||||
let params = CreateRowParams {
|
||||
grid_id: self.editor.grid_id.clone(),
|
||||
start_row_id: None,
|
||||
group_id: None,
|
||||
};
|
||||
let row_order = self.editor.create_row(params).await.unwrap();
|
||||
self.row_order_by_row_id
|
||||
.insert(row_order.row_id().to_owned(), row_order);
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::cache::disk::RevisionDiskCache;
|
||||
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
|
||||
use crate::disk::{RevisionChangeset, RevisionRecord};
|
||||
use bytes::Bytes;
|
||||
use diesel::{sql_types::Integer, update, SqliteConnection};
|
||||
use flowy_database::{
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::cache::disk::RevisionDiskCache;
|
||||
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
|
||||
use crate::disk::{RevisionChangeset, RevisionRecord};
|
||||
use bytes::Bytes;
|
||||
use diesel::{sql_types::Integer, update, SqliteConnection};
|
||||
use flowy_database::{
|
||||
@ -103,7 +103,7 @@ impl GridMetaRevisionSql {
|
||||
record.revision.object_id,
|
||||
record.revision.rev_id
|
||||
);
|
||||
let rev_state: GridMetaRevisionState = record.state.into();
|
||||
let rev_state: GridBlockRevisionState = record.state.into();
|
||||
(
|
||||
dsl::object_id.eq(record.revision.object_id),
|
||||
dsl::base_rev_id.eq(record.revision.base_rev_id),
|
||||
@ -121,7 +121,7 @@ impl GridMetaRevisionSql {
|
||||
}
|
||||
|
||||
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
|
||||
let state: GridMetaRevisionState = changeset.state.clone().into();
|
||||
let state: GridBlockRevisionState = changeset.state.clone().into();
|
||||
let filter = dsl::grid_meta_rev_table
|
||||
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
|
||||
.filter(dsl::object_id.eq(changeset.object_id));
|
||||
@ -146,7 +146,7 @@ impl GridMetaRevisionSql {
|
||||
if let Some(rev_ids) = rev_ids {
|
||||
sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
|
||||
}
|
||||
let rows = sql.order(dsl::rev_id.asc()).load::<GridMetaRevisionTable>(conn)?;
|
||||
let rows = sql.order(dsl::rev_id.asc()).load::<GridBlockRevisionTable>(conn)?;
|
||||
let records = rows
|
||||
.into_iter()
|
||||
.map(|row| mk_revision_record_from_table(user_id, row))
|
||||
@ -166,7 +166,7 @@ impl GridMetaRevisionSql {
|
||||
.filter(dsl::rev_id.le(range.end))
|
||||
.filter(dsl::object_id.eq(object_id))
|
||||
.order(dsl::rev_id.asc())
|
||||
.load::<GridMetaRevisionTable>(conn)?;
|
||||
.load::<GridBlockRevisionTable>(conn)?;
|
||||
|
||||
let revisions = rev_tables
|
||||
.into_iter()
|
||||
@ -192,31 +192,31 @@ impl GridMetaRevisionSql {
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
|
||||
#[table_name = "grid_meta_rev_table"]
|
||||
struct GridMetaRevisionTable {
|
||||
struct GridBlockRevisionTable {
|
||||
id: i32,
|
||||
object_id: String,
|
||||
base_rev_id: i64,
|
||||
rev_id: i64,
|
||||
data: Vec<u8>,
|
||||
state: GridMetaRevisionState,
|
||||
state: GridBlockRevisionState,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
|
||||
#[repr(i32)]
|
||||
#[sql_type = "Integer"]
|
||||
pub enum GridMetaRevisionState {
|
||||
pub enum GridBlockRevisionState {
|
||||
Sync = 0,
|
||||
Ack = 1,
|
||||
}
|
||||
impl_sql_integer_expression!(GridMetaRevisionState);
|
||||
impl_rev_state_map!(GridMetaRevisionState);
|
||||
impl std::default::Default for GridMetaRevisionState {
|
||||
impl_sql_integer_expression!(GridBlockRevisionState);
|
||||
impl_rev_state_map!(GridBlockRevisionState);
|
||||
impl std::default::Default for GridBlockRevisionState {
|
||||
fn default() -> Self {
|
||||
GridMetaRevisionState::Sync
|
||||
GridBlockRevisionState::Sync
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_revision_record_from_table(user_id: &str, table: GridMetaRevisionTable) -> RevisionRecord {
|
||||
fn mk_revision_record_from_table(user_id: &str, table: GridBlockRevisionTable) -> RevisionRecord {
|
||||
let md5 = md5(&table.data);
|
||||
let revision = Revision::new(
|
||||
&table.object_id,
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::cache::disk::RevisionDiskCache;
|
||||
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
|
||||
|
||||
use crate::disk::{RevisionChangeset, RevisionRecord};
|
||||
use bytes::Bytes;
|
||||
use diesel::{sql_types::Integer, update, SqliteConnection};
|
||||
use flowy_database::{
|
||||
|
233
frontend/rust-lib/flowy-revision/src/cache/disk/grid_view_impl.rs
vendored
Normal file
233
frontend/rust-lib/flowy-revision/src/cache/disk/grid_view_impl.rs
vendored
Normal file
@ -0,0 +1,233 @@
|
||||
use crate::disk::{RevisionChangeset, RevisionDiskCache, RevisionRecord};
|
||||
use bytes::Bytes;
|
||||
use diesel::{sql_types::Integer, update, SqliteConnection};
|
||||
use flowy_database::{
|
||||
impl_sql_integer_expression, insert_or_ignore_into,
|
||||
prelude::*,
|
||||
schema::{grid_view_rev_table, grid_view_rev_table::dsl},
|
||||
ConnectionPool,
|
||||
};
|
||||
use flowy_error::{internal_error, FlowyError, FlowyResult};
|
||||
use flowy_sync::{
|
||||
entities::revision::{Revision, RevisionRange},
|
||||
util::md5,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct SQLiteGridViewRevisionPersistence {
|
||||
user_id: String,
|
||||
pub(crate) pool: Arc<ConnectionPool>,
|
||||
}
|
||||
|
||||
impl SQLiteGridViewRevisionPersistence {
|
||||
pub fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
|
||||
Self {
|
||||
user_id: user_id.to_owned(),
|
||||
pool,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RevisionDiskCache for SQLiteGridViewRevisionPersistence {
|
||||
type Error = FlowyError;
|
||||
|
||||
fn create_revision_records(&self, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
|
||||
let conn = self.pool.get().map_err(internal_error)?;
|
||||
let _ = GridViewRevisionSql::create(revision_records, &*conn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_revision_records(
|
||||
&self,
|
||||
object_id: &str,
|
||||
rev_ids: Option<Vec<i64>>,
|
||||
) -> Result<Vec<RevisionRecord>, Self::Error> {
|
||||
let conn = self.pool.get().map_err(internal_error)?;
|
||||
let records = GridViewRevisionSql::read(&self.user_id, object_id, rev_ids, &*conn)?;
|
||||
Ok(records)
|
||||
}
|
||||
|
||||
fn read_revision_records_with_range(
|
||||
&self,
|
||||
object_id: &str,
|
||||
range: &RevisionRange,
|
||||
) -> Result<Vec<RevisionRecord>, Self::Error> {
|
||||
let conn = &*self.pool.get().map_err(internal_error)?;
|
||||
let revisions = GridViewRevisionSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?;
|
||||
Ok(revisions)
|
||||
}
|
||||
|
||||
fn update_revision_record(&self, changesets: Vec<RevisionChangeset>) -> FlowyResult<()> {
|
||||
let conn = &*self.pool.get().map_err(internal_error)?;
|
||||
let _ = conn.immediate_transaction::<_, FlowyError, _>(|| {
|
||||
for changeset in changesets {
|
||||
let _ = GridViewRevisionSql::update(changeset, conn)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_revision_records(&self, object_id: &str, rev_ids: Option<Vec<i64>>) -> Result<(), Self::Error> {
|
||||
let conn = &*self.pool.get().map_err(internal_error)?;
|
||||
let _ = GridViewRevisionSql::delete(object_id, rev_ids, conn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn delete_and_insert_records(
|
||||
&self,
|
||||
object_id: &str,
|
||||
deleted_rev_ids: Option<Vec<i64>>,
|
||||
inserted_records: Vec<RevisionRecord>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let conn = self.pool.get().map_err(internal_error)?;
|
||||
conn.immediate_transaction::<_, FlowyError, _>(|| {
|
||||
let _ = GridViewRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?;
|
||||
let _ = GridViewRevisionSql::create(inserted_records, &*conn)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct GridViewRevisionSql();
|
||||
impl GridViewRevisionSql {
|
||||
fn create(revision_records: Vec<RevisionRecord>, conn: &SqliteConnection) -> Result<(), FlowyError> {
|
||||
// Batch insert: https://diesel.rs/guides/all-about-inserts.html
|
||||
let records = revision_records
|
||||
.into_iter()
|
||||
.map(|record| {
|
||||
tracing::trace!(
|
||||
"[GridViewRevisionSql] create revision: {}:{:?}",
|
||||
record.revision.object_id,
|
||||
record.revision.rev_id
|
||||
);
|
||||
let rev_state: GridViewRevisionState = record.state.into();
|
||||
(
|
||||
dsl::object_id.eq(record.revision.object_id),
|
||||
dsl::base_rev_id.eq(record.revision.base_rev_id),
|
||||
dsl::rev_id.eq(record.revision.rev_id),
|
||||
dsl::data.eq(record.revision.delta_data),
|
||||
dsl::state.eq(rev_state),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let _ = insert_or_ignore_into(dsl::grid_view_rev_table)
|
||||
.values(&records)
|
||||
.execute(conn)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
|
||||
let state: GridViewRevisionState = changeset.state.clone().into();
|
||||
let filter = dsl::grid_view_rev_table
|
||||
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
|
||||
.filter(dsl::object_id.eq(changeset.object_id));
|
||||
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
|
||||
tracing::debug!(
|
||||
"[GridViewRevisionSql] update revision:{} state:to {:?}",
|
||||
changeset.rev_id,
|
||||
changeset.state
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(
|
||||
user_id: &str,
|
||||
object_id: &str,
|
||||
rev_ids: Option<Vec<i64>>,
|
||||
conn: &SqliteConnection,
|
||||
) -> Result<Vec<RevisionRecord>, FlowyError> {
|
||||
let mut sql = dsl::grid_view_rev_table
|
||||
.filter(dsl::object_id.eq(object_id))
|
||||
.into_boxed();
|
||||
if let Some(rev_ids) = rev_ids {
|
||||
sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
|
||||
}
|
||||
let rows = sql.order(dsl::rev_id.asc()).load::<GridViewRevisionTable>(conn)?;
|
||||
let records = rows
|
||||
.into_iter()
|
||||
.map(|row| mk_revision_record_from_table(user_id, row))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(records)
|
||||
}
|
||||
|
||||
fn read_with_range(
|
||||
user_id: &str,
|
||||
object_id: &str,
|
||||
range: RevisionRange,
|
||||
conn: &SqliteConnection,
|
||||
) -> Result<Vec<RevisionRecord>, FlowyError> {
|
||||
let rev_tables = dsl::grid_view_rev_table
|
||||
.filter(dsl::rev_id.ge(range.start))
|
||||
.filter(dsl::rev_id.le(range.end))
|
||||
.filter(dsl::object_id.eq(object_id))
|
||||
.order(dsl::rev_id.asc())
|
||||
.load::<GridViewRevisionTable>(conn)?;
|
||||
|
||||
let revisions = rev_tables
|
||||
.into_iter()
|
||||
.map(|table| mk_revision_record_from_table(user_id, table))
|
||||
.collect::<Vec<_>>();
|
||||
Ok(revisions)
|
||||
}
|
||||
|
||||
fn delete(object_id: &str, rev_ids: Option<Vec<i64>>, conn: &SqliteConnection) -> Result<(), FlowyError> {
|
||||
let mut sql = diesel::delete(dsl::grid_view_rev_table).into_boxed();
|
||||
sql = sql.filter(dsl::object_id.eq(object_id));
|
||||
|
||||
if let Some(rev_ids) = rev_ids {
|
||||
tracing::trace!("[GridViewRevisionSql] Delete revision: {}:{:?}", object_id, rev_ids);
|
||||
sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
|
||||
}
|
||||
|
||||
let affected_row = sql.execute(conn)?;
|
||||
tracing::trace!("[GridViewRevisionSql] Delete {} rows", affected_row);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
|
||||
#[table_name = "grid_view_rev_table"]
|
||||
struct GridViewRevisionTable {
|
||||
id: i32,
|
||||
object_id: String,
|
||||
base_rev_id: i64,
|
||||
rev_id: i64,
|
||||
data: Vec<u8>,
|
||||
state: GridViewRevisionState,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
|
||||
#[repr(i32)]
|
||||
#[sql_type = "Integer"]
|
||||
pub enum GridViewRevisionState {
|
||||
Sync = 0,
|
||||
Ack = 1,
|
||||
}
|
||||
impl_sql_integer_expression!(GridViewRevisionState);
|
||||
impl_rev_state_map!(GridViewRevisionState);
|
||||
|
||||
impl std::default::Default for GridViewRevisionState {
|
||||
fn default() -> Self {
|
||||
GridViewRevisionState::Sync
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_revision_record_from_table(user_id: &str, table: GridViewRevisionTable) -> RevisionRecord {
|
||||
let md5 = md5(&table.data);
|
||||
let revision = Revision::new(
|
||||
&table.object_id,
|
||||
table.base_rev_id,
|
||||
table.rev_id,
|
||||
Bytes::from(table.data),
|
||||
user_id,
|
||||
md5,
|
||||
);
|
||||
RevisionRecord {
|
||||
revision,
|
||||
state: table.state.into(),
|
||||
write_to_disk: false,
|
||||
}
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
mod document_impl;
|
||||
mod grid_block_impl;
|
||||
mod grid_impl;
|
||||
mod grid_view_impl;
|
||||
|
||||
pub use document_impl::*;
|
||||
pub use grid_block_impl::*;
|
||||
pub use grid_impl::*;
|
||||
pub use grid_view_impl::*;
|
||||
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_sync::entities::revision::{RevId, Revision, RevisionRange};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::revision::{GridBlockRevision, SettingRevision};
|
||||
use crate::revision::GridBlockRevision;
|
||||
use bytes::Bytes;
|
||||
use indexmap::IndexMap;
|
||||
use nanoid::nanoid;
|
||||
@ -23,9 +23,6 @@ pub struct GridRevision {
|
||||
pub grid_id: String,
|
||||
pub fields: Vec<Arc<FieldRevision>>,
|
||||
pub blocks: Vec<Arc<GridBlockMetaRevision>>,
|
||||
|
||||
#[serde(default)]
|
||||
pub setting: SettingRevision,
|
||||
}
|
||||
|
||||
impl GridRevision {
|
||||
@ -34,7 +31,6 @@ impl GridRevision {
|
||||
grid_id: grid_id.to_owned(),
|
||||
fields: vec![],
|
||||
blocks: vec![],
|
||||
setting: SettingRevision::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +39,6 @@ impl GridRevision {
|
||||
grid_id: grid_id.to_owned(),
|
||||
fields: context.field_revs,
|
||||
blocks: context.blocks.into_iter().map(Arc::new).collect(),
|
||||
setting: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use crate::revision::SettingRevision;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn gen_grid_view_id() -> String {
|
||||
nanoid!(6)
|
||||
}
|
||||
@ -21,9 +22,9 @@ pub struct GridViewRevision {
|
||||
}
|
||||
|
||||
impl GridViewRevision {
|
||||
pub fn new(grid_id: String) -> Self {
|
||||
pub fn new(grid_id: String, view_id: String) -> Self {
|
||||
GridViewRevision {
|
||||
view_id: gen_grid_view_id(),
|
||||
view_id,
|
||||
grid_id,
|
||||
setting: Default::default(),
|
||||
row_orders: vec![],
|
||||
|
@ -6,8 +6,5 @@ fn grid_default_serde_test() {
|
||||
let grid = GridRevision::new(&grid_id);
|
||||
|
||||
let json = serde_json::to_string(&grid).unwrap();
|
||||
assert_eq!(
|
||||
json,
|
||||
r#"{"grid_id":"1","fields":[],"blocks":[],"setting":{"layout":0,"filters":[],"groups":[]}}"#
|
||||
)
|
||||
assert_eq!(json, r#"{"grid_id":"1","fields":[],"blocks":[]}"#)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::entities::folder::FolderDelta;
|
||||
use crate::util::make_delta_from_revisions;
|
||||
use crate::util::make_text_delta_from_revisions;
|
||||
use crate::{
|
||||
client_folder::{default_folder_delta, FolderPad},
|
||||
entities::revision::Revision,
|
||||
@ -7,7 +7,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use flowy_folder_data_model::revision::{TrashRevision, WorkspaceRevision};
|
||||
use lib_ot::core::PhantomAttributes;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@ -37,7 +37,7 @@ impl FolderPadBuilder {
|
||||
}
|
||||
|
||||
pub(crate) fn build_with_revisions(self, revisions: Vec<Revision>) -> CollaborateResult<FolderPad> {
|
||||
let mut folder_delta: FolderDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
|
||||
let mut folder_delta: FolderDelta = make_text_delta_from_revisions(revisions)?;
|
||||
if folder_delta.is_empty() {
|
||||
folder_delta = default_folder_delta();
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
use crate::entities::grid::{
|
||||
CreateGridFilterParams, CreateGridGroupParams, FieldChangesetParams, GridSettingChangesetParams,
|
||||
};
|
||||
use crate::entities::grid::FieldChangesetParams;
|
||||
use crate::entities::revision::{md5, RepeatedRevision, Revision};
|
||||
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
|
||||
use crate::util::{cal_diff, make_delta_from_revisions};
|
||||
use crate::util::{cal_diff, make_text_delta_from_revisions};
|
||||
use bytes::Bytes;
|
||||
use flowy_grid_data_model::revision::{
|
||||
gen_block_id, gen_grid_filter_id, gen_grid_group_id, gen_grid_id, FieldRevision, FieldTypeRevision,
|
||||
FilterConfigurationRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, GridRevision,
|
||||
GroupConfigurationRevision, SettingRevision,
|
||||
gen_block_id, gen_grid_id, FieldRevision, FieldTypeRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset,
|
||||
GridRevision,
|
||||
};
|
||||
use lib_infra::util::move_vec_element;
|
||||
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder};
|
||||
@ -68,7 +65,7 @@ impl GridRevisionPad {
|
||||
}
|
||||
|
||||
pub fn from_revisions(revisions: Vec<Revision>) -> CollaborateResult<Self> {
|
||||
let grid_delta: GridRevisionDelta = make_delta_from_revisions::<PhantomAttributes>(revisions)?;
|
||||
let grid_delta: GridRevisionDelta = make_text_delta_from_revisions(revisions)?;
|
||||
Self::from_delta(grid_delta)
|
||||
}
|
||||
|
||||
@ -347,95 +344,6 @@ impl GridRevisionPad {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_setting_rev(&self) -> &SettingRevision {
|
||||
&self.grid_rev.setting
|
||||
}
|
||||
|
||||
/// If layout is None, then the default layout will be the read from GridSettingRevision
|
||||
pub fn get_filters(&self, field_ids: Option<Vec<String>>) -> Option<Vec<Arc<FilterConfigurationRevision>>> {
|
||||
let mut filter_revs = vec![];
|
||||
let field_revs = self.get_field_revs(None).ok()?;
|
||||
|
||||
field_revs.iter().for_each(|field_rev| {
|
||||
let mut is_contain = true;
|
||||
if let Some(field_ids) = &field_ids {
|
||||
is_contain = field_ids.contains(&field_rev.id);
|
||||
}
|
||||
|
||||
if is_contain {
|
||||
// Only return the filters for the current fields' type.
|
||||
let field_id = &field_rev.id;
|
||||
let field_type_rev = &field_rev.field_type_rev;
|
||||
if let Some(mut t_filter_revs) = self.grid_rev.setting.get_filters(field_id, field_type_rev) {
|
||||
filter_revs.append(&mut t_filter_revs);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Some(filter_revs)
|
||||
}
|
||||
|
||||
pub fn update_grid_setting_rev(
|
||||
&mut self,
|
||||
changeset: GridSettingChangesetParams,
|
||||
) -> CollaborateResult<Option<GridRevisionChangeset>> {
|
||||
self.modify_grid(|grid_rev| {
|
||||
let mut is_changed = None;
|
||||
if let Some(params) = changeset.insert_filter {
|
||||
grid_rev
|
||||
.setting
|
||||
.insert_filter(¶ms.field_id, ¶ms.field_type_rev, make_filter_revision(¶ms));
|
||||
is_changed = Some(())
|
||||
}
|
||||
if let Some(params) = changeset.delete_filter {
|
||||
if let Some(filters) = grid_rev
|
||||
.setting
|
||||
.get_mut_filters(¶ms.field_id, ¶ms.field_type_rev)
|
||||
{
|
||||
filters.retain(|filter| filter.id != params.filter_id);
|
||||
}
|
||||
}
|
||||
if let Some(params) = changeset.insert_group {
|
||||
grid_rev
|
||||
.setting
|
||||
.insert_group(¶ms.field_id, ¶ms.field_type_rev, make_group_revision(¶ms));
|
||||
is_changed = Some(());
|
||||
}
|
||||
if let Some(params) = changeset.delete_group {
|
||||
if let Some(groups) = grid_rev
|
||||
.setting
|
||||
.get_mut_groups(¶ms.field_id, ¶ms.field_type_rev)
|
||||
{
|
||||
groups.retain(|filter| filter.id != params.group_id);
|
||||
}
|
||||
}
|
||||
if let Some(_sort) = changeset.insert_sort {
|
||||
// let rev = GridSortRevision {
|
||||
// id: gen_grid_sort_id(),
|
||||
// field_id: sort.field_id,
|
||||
// };
|
||||
//
|
||||
// grid_rev
|
||||
// .setting
|
||||
// .sorts
|
||||
// .entry(layout_rev.clone())
|
||||
// .or_insert_with(std::vec::Vec::new)
|
||||
// .push(rev);
|
||||
is_changed = Some(())
|
||||
}
|
||||
|
||||
if let Some(_delete_sort_id) = changeset.delete_sort {
|
||||
// match grid_rev.setting.sorts.get_mut(&layout_rev) {
|
||||
// Some(sorts) => sorts.retain(|sort| sort.id != delete_sort_id),
|
||||
// None => {
|
||||
// tracing::warn!("Can't find the sort with {:?}", layout_rev);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Ok(is_changed)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn md5(&self) -> String {
|
||||
md5(&self.delta.json_bytes())
|
||||
}
|
||||
@ -548,21 +456,3 @@ impl std::default::Default for GridRevisionPad {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_filter_revision(params: &CreateGridFilterParams) -> FilterConfigurationRevision {
|
||||
FilterConfigurationRevision {
|
||||
id: gen_grid_filter_id(),
|
||||
field_id: params.field_id.clone(),
|
||||
condition: params.condition,
|
||||
content: params.content.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_group_revision(params: &CreateGridGroupParams) -> GroupConfigurationRevision {
|
||||
GroupConfigurationRevision {
|
||||
id: gen_grid_group_id(),
|
||||
field_id: params.field_id.clone(),
|
||||
field_type_rev: params.field_type_rev,
|
||||
content: params.content.clone(),
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
use crate::entities::grid::{CreateGridFilterParams, CreateGridGroupParams, GridSettingChangesetParams};
|
||||
use crate::entities::revision::{md5, Revision};
|
||||
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
|
||||
use crate::util::{cal_diff, make_text_delta_from_revisions};
|
||||
use flowy_grid_data_model::revision::{
|
||||
FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision,
|
||||
GroupConfigurationRevision, GroupConfigurationsByFieldId, SortConfigurationsByFieldId,
|
||||
gen_grid_filter_id, gen_grid_group_id, FieldRevision, FieldTypeRevision, FilterConfigurationRevision,
|
||||
FilterConfigurationsByFieldId, GridViewRevision, GroupConfigurationRevision, GroupConfigurationsByFieldId,
|
||||
SettingRevision, SortConfigurationsByFieldId,
|
||||
};
|
||||
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder};
|
||||
use std::sync::Arc;
|
||||
@ -23,8 +25,8 @@ impl std::ops::Deref for GridViewRevisionPad {
|
||||
}
|
||||
|
||||
impl GridViewRevisionPad {
|
||||
pub fn new(grid_id: String) -> Self {
|
||||
let view = Arc::new(GridViewRevision::new(grid_id));
|
||||
pub fn new(grid_id: String, view_id: String) -> Self {
|
||||
let view = Arc::new(GridViewRevision::new(grid_id, view_id));
|
||||
let json = serde_json::to_string(&view).unwrap();
|
||||
let delta = TextDeltaBuilder::new().insert(&json).build();
|
||||
Self { view, delta }
|
||||
@ -48,6 +50,59 @@ impl GridViewRevisionPad {
|
||||
Self::from_delta(delta)
|
||||
}
|
||||
|
||||
pub fn get_setting_rev(&self) -> &SettingRevision {
|
||||
&self.view.setting
|
||||
}
|
||||
|
||||
pub fn update_setting(
|
||||
&mut self,
|
||||
changeset: GridSettingChangesetParams,
|
||||
) -> CollaborateResult<Option<GridViewRevisionChangeset>> {
|
||||
self.modify(|view| {
|
||||
let mut is_changed = None;
|
||||
if let Some(params) = changeset.insert_filter {
|
||||
view.setting.filters.insert_object(
|
||||
¶ms.field_id,
|
||||
¶ms.field_type_rev,
|
||||
make_filter_revision(¶ms),
|
||||
);
|
||||
is_changed = Some(())
|
||||
}
|
||||
if let Some(params) = changeset.delete_filter {
|
||||
if let Some(filters) = view
|
||||
.setting
|
||||
.filters
|
||||
.get_mut_objects(¶ms.field_id, ¶ms.field_type_rev)
|
||||
{
|
||||
filters.retain(|filter| filter.id != params.filter_id);
|
||||
is_changed = Some(())
|
||||
}
|
||||
}
|
||||
if let Some(params) = changeset.insert_group {
|
||||
view.setting.groups.remove_all();
|
||||
view.setting.groups.insert_object(
|
||||
¶ms.field_id,
|
||||
¶ms.field_type_rev,
|
||||
make_group_revision(¶ms),
|
||||
);
|
||||
|
||||
is_changed = Some(());
|
||||
}
|
||||
if let Some(params) = changeset.delete_group {
|
||||
if let Some(groups) = view
|
||||
.setting
|
||||
.groups
|
||||
.get_mut_objects(¶ms.field_id, ¶ms.field_type_rev)
|
||||
{
|
||||
groups.retain(|group| group.id != params.group_id);
|
||||
is_changed = Some(());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(is_changed)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_all_groups(&self, field_revs: &[Arc<FieldRevision>]) -> Option<GroupConfigurationsByFieldId> {
|
||||
self.setting.groups.get_all_objects(field_revs)
|
||||
}
|
||||
@ -161,6 +216,24 @@ impl GridViewRevisionPad {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_filter_revision(params: &CreateGridFilterParams) -> FilterConfigurationRevision {
|
||||
FilterConfigurationRevision {
|
||||
id: gen_grid_filter_id(),
|
||||
field_id: params.field_id.clone(),
|
||||
condition: params.condition,
|
||||
content: params.content.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_group_revision(params: &CreateGridGroupParams) -> GroupConfigurationRevision {
|
||||
GroupConfigurationRevision {
|
||||
id: gen_grid_group_id(),
|
||||
field_id: params.field_id.clone(),
|
||||
field_type_rev: params.field_type_rev,
|
||||
content: params.content.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GridViewRevisionChangeset {
|
||||
pub delta: TextDelta,
|
||||
pub md5: String,
|
||||
@ -171,3 +244,8 @@ pub fn make_grid_view_rev_json_str(grid_revision: &GridViewRevision) -> Collabor
|
||||
.map_err(|err| internal_error(format!("Serialize grid view to json str failed. {:?}", err)))?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
pub fn make_grid_view_delta(grid_view: &GridViewRevision) -> TextDelta {
|
||||
let json = serde_json::to_string(grid_view).unwrap();
|
||||
TextDeltaBuilder::new().insert(&json).build()
|
||||
}
|
||||
|
@ -8,20 +8,20 @@ use std::{
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
pub fn wrap_future<T, O>(f: T) -> FnFuture<O>
|
||||
pub fn wrap_future<T, O>(f: T) -> AFFuture<O>
|
||||
where
|
||||
T: Future<Output = O> + Send + Sync + 'static,
|
||||
{
|
||||
FnFuture { fut: Box::pin(f) }
|
||||
AFFuture { fut: Box::pin(f) }
|
||||
}
|
||||
|
||||
#[pin_project]
|
||||
pub struct FnFuture<T> {
|
||||
pub struct AFFuture<T> {
|
||||
#[pin]
|
||||
pub fut: Pin<Box<dyn Future<Output = T> + Sync + Send>>,
|
||||
}
|
||||
|
||||
impl<T> Future for FnFuture<T>
|
||||
impl<T> Future for AFFuture<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user