chore: refactor grid setting

This commit is contained in:
appflowy 2022-08-11 10:08:42 +08:00
parent 1bdd863b75
commit 29ea3c83c8
19 changed files with 252 additions and 222 deletions

View File

@ -1,8 +1,9 @@
use crate::entities::FieldType;
use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::GridGroupRevision;
use flowy_sync::entities::grid::CreateGridGroupParams;
use flowy_sync::entities::grid::{CreateGridGroupParams, DeleteGroupParams};
use std::convert::TryInto;
use std::sync::Arc;
@ -11,8 +12,8 @@ pub struct GridGroupPB {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2, one_of)]
pub group_field_id: Option<String>,
#[pb(index = 2)]
pub group_field_id: String,
#[pb(index = 3, one_of)]
pub sub_group_field_id: Option<String>,
@ -50,27 +51,64 @@ impl std::convert::From<Vec<Arc<GridGroupRevision>>> for RepeatedGridGroupPB {
#[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)]
pub struct CreateGridGroupPayloadPB {
#[pb(index = 1, one_of)]
pub field_id: Option<String>,
#[pb(index = 1)]
pub field_id: String,
#[pb(index = 2, one_of)]
pub sub_field_id: Option<String>,
#[pb(index = 3)]
pub field_type: FieldType,
}
impl TryInto<CreateGridGroupParams> for CreateGridGroupPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<CreateGridGroupParams, Self::Error> {
let field_id = match self.field_id {
None => None,
Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
};
let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let sub_field_id = match self.sub_field_id {
None => None,
Some(field_id) => Some(NotEmptyStr::parse(field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
};
Ok(CreateGridGroupParams { field_id, sub_field_id })
Ok(CreateGridGroupParams {
field_id,
sub_field_id,
field_type_rev: self.field_type.into(),
})
}
}
#[derive(ProtoBuf, Debug, Default, Clone)]
pub struct DeleteGroupPayloadPB {
#[pb(index = 1)]
pub field_id: String,
#[pb(index = 2)]
pub group_id: String,
#[pb(index = 3)]
pub field_type: FieldType,
}
impl TryInto<DeleteGroupParams> for DeleteGroupPayloadPB {
type Error = ErrorCode;
fn try_into(self) -> Result<DeleteGroupParams, Self::Error> {
let field_id = NotEmptyStr::parse(self.field_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
let group_id = NotEmptyStr::parse(self.group_id)
.map_err(|_| ErrorCode::FieldIdIsEmpty)?
.0;
Ok(DeleteGroupParams {
field_id,
field_type_rev: self.field_type.into(),
group_id,
})
}
}

View File

@ -0,0 +1,3 @@
mod group;
pub use group::*;

View File

@ -1,12 +1,12 @@
use crate::entities::{
CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, DeleteFilterPayloadPB,
RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB,
DeleteGroupPayloadPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB,
};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::GridLayoutRevision;
use flowy_sync::entities::grid::GridSettingChangesetParams;
use flowy_sync::entities::grid::{DeleteGroupParams, GridSettingChangesetParams};
use std::collections::HashMap;
use std::convert::TryInto;
use strum::IntoEnumIterator;
@ -97,7 +97,7 @@ pub struct GridSettingChangesetPayloadPB {
pub insert_group: Option<CreateGridGroupPayloadPB>,
#[pb(index = 6, one_of)]
pub delete_group: Option<String>,
pub delete_group: Option<DeleteGroupPayloadPB>,
#[pb(index = 7, one_of)]
pub insert_sort: Option<CreateGridSortPayloadPB>,
@ -130,8 +130,8 @@ impl TryInto<GridSettingChangesetParams> for GridSettingChangesetPayloadPB {
};
let delete_group = match self.delete_group {
Some(payload) => Some(payload.try_into()?),
None => None,
Some(filter_id) => Some(NotEmptyStr::parse(filter_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?.0),
};
let insert_sort = match self.insert_sort {

View File

@ -6,6 +6,7 @@ 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::persistence::block_index::BlockIndexCache;
use crate::services::row::{
make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder,
@ -34,6 +35,7 @@ pub struct GridRevisionEditor {
block_manager: Arc<GridBlockManager>,
#[allow(dead_code)]
pub(crate) filter_service: Arc<GridFilterService>,
pub(crate) group_service: Arc<GridGroupService>,
}
impl Drop for GridRevisionEditor {
@ -59,6 +61,7 @@ impl GridRevisionEditor {
let block_manager = Arc::new(GridBlockManager::new(grid_id, &user, block_meta_revs, persistence).await?);
let filter_service =
Arc::new(GridFilterService::new(grid_pad.clone(), block_manager.clone(), task_scheduler.clone()).await);
let group_service = Arc::new(GridGroupService::new());
let editor = Arc::new(Self {
grid_id: grid_id.to_owned(),
user,
@ -66,6 +69,7 @@ impl GridRevisionEditor {
rev_manager,
block_manager,
filter_service,
group_service,
});
Ok(editor)

View File

@ -19,6 +19,7 @@ impl GridTaskHandler for GridRevisionEditor {
Box::pin(async move {
match content {
TaskContent::Snapshot => {}
TaskContent::Group => {}
TaskContent::Filter(context) => self.filter_service.process(context).await?,
}
Ok(())

View File

@ -0,0 +1,7 @@
pub struct GridGroupService {}
impl GridGroupService {
pub fn new() -> Self {
Self {}
}
}

View File

@ -0,0 +1,3 @@
mod group_service;
pub use group_service::*;

View File

@ -7,6 +7,7 @@ pub mod field;
mod filter;
pub mod grid_editor;
mod grid_editor_task;
pub mod group;
pub mod persistence;
pub mod row;
pub mod setting;

View File

@ -27,6 +27,7 @@ impl GridTaskQueue {
let task_type = match task.content.as_ref().unwrap() {
TaskContent::Snapshot => TaskType::Snapshot,
TaskContent::Group => TaskType::Group,
TaskContent::Filter { .. } => TaskType::Filter,
};
let pending_task = PendingTask {

View File

@ -10,6 +10,8 @@ pub enum TaskType {
Filter,
/// Generate snapshot for grid, unused by now.
Snapshot,
Group,
}
impl PartialEq for TaskType {
@ -44,9 +46,15 @@ impl PartialOrd for PendingTask {
impl Ord for PendingTask {
fn cmp(&self, other: &Self) -> Ordering {
match (self.ty, other.ty) {
// Snapshot
(TaskType::Snapshot, TaskType::Snapshot) => Ordering::Equal,
(TaskType::Snapshot, _) => Ordering::Greater,
(_, TaskType::Snapshot) => Ordering::Less,
// Group
(TaskType::Group, TaskType::Group) => self.id.cmp(&other.id).reverse(),
(TaskType::Group, _) => Ordering::Greater,
(_, TaskType::Group) => Ordering::Greater,
// Filter
(TaskType::Filter, TaskType::Filter) => self.id.cmp(&other.id).reverse(),
}
}
@ -59,6 +67,7 @@ pub(crate) struct FilterTaskContext {
pub(crate) enum TaskContent {
#[allow(dead_code)]
Snapshot,
Group,
Filter(FilterTaskContext),
}

View File

@ -54,24 +54,14 @@ pub fn make_default_board() -> BuildGridContext {
let single_select_field_id = single_select_field.id.clone();
grid_builder.add_field(single_select_field);
let field_revs = grid_builder.field_revs();
let block_id = grid_builder.block_id();
// rows
let row_1 = RowRevisionBuilder::new(block_id, field_revs)
.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
.build();
grid_builder.add_row(row_1);
let row_2 = RowRevisionBuilder::new(block_id, field_revs)
.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
.build();
grid_builder.add_row(row_2);
let row_3 = RowRevisionBuilder::new(block_id, field_revs)
.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
.build();
grid_builder.add_row(row_3);
for _ in 0..3 {
grid_builder.add_row(
RowRevisionBuilder::new(grid_builder.block_id(), grid_builder.field_revs())
.insert_select_option_cell(&single_select_field_id, not_started_option.id.clone())
.build(),
);
}
grid_builder.build()
}

View File

@ -97,6 +97,7 @@ async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataTypePB
desc: "".to_string(),
thumbnail: Some("http://1.png".to_string()),
data_type,
sub_data_type: None,
plugin_type: 0,
data,
};

View File

@ -0,0 +1,12 @@
use crate::revision::FieldTypeRevision;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
pub struct GridFilterRevision {
pub id: String,
pub field_id: String,
pub condition: u8,
pub content: Option<String>,
}

View File

@ -1,94 +0,0 @@
use crate::entities::NumberFilterCondition;
use indexmap::IndexMap;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use serde_repr::*;
use std::str::FromStr;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridFilterRevision {
pub id: String,
pub field_id: String,
pub condition: u8,
pub content: Option<String>,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum TextFilterConditionRevision {
Is = 0,
IsNot = 1,
Contains = 2,
DoesNotContain = 3,
StartsWith = 4,
EndsWith = 5,
IsEmpty = 6,
IsNotEmpty = 7,
}
impl ToString for TextFilterConditionRevision {
fn to_string(&self) -> String {
(self.clone() as u8).to_string()
}
}
impl FromStr for TextFilterConditionRevision {
type Err = serde_json::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let rev = serde_json::from_str(s)?;
Ok(rev)
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum NumberFilterConditionRevision {
Equal = 0,
NotEqual = 1,
GreaterThan = 2,
LessThan = 3,
GreaterThanOrEqualTo = 4,
LessThanOrEqualTo = 5,
IsEmpty = 6,
IsNotEmpty = 7,
}
impl ToString for NumberFilterConditionRevision {
fn to_string(&self) -> String {
(self.clone() as u8).to_string()
}
}
impl FromStr for NumberFilterConditionRevision {
type Err = serde_json::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let rev = serde_json::from_str(s)?;
Ok(rev)
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum SelectOptionConditionRevision {
OptionIs = 0,
OptionIsNot = 1,
OptionIsEmpty = 2,
OptionIsNotEmpty = 3,
}
impl ToString for SelectOptionConditionRevision {
fn to_string(&self) -> String {
(self.clone() as u8).to_string()
}
}
impl FromStr for SelectOptionConditionRevision {
type Err = serde_json::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let rev = serde_json::from_str(s)?;
Ok(rev)
}
}

View File

@ -1,9 +1,12 @@
use crate::revision::filter_rev::GridFilterRevision;
use crate::revision::group_rev::GridGroupRevision;
use crate::revision::{FieldRevision, FieldTypeRevision};
use indexmap::IndexMap;
use nanoid::nanoid;
use serde::{Deserialize, Serialize};
use serde_repr::*;
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Arc;
pub fn gen_grid_filter_id() -> String {
@ -18,41 +21,50 @@ pub fn gen_grid_sort_id() -> String {
nanoid!(6)
}
/// Each layout contains multiple key/value.
/// Key: field_id
/// Value: this value also contains key/value.
/// Key: FieldType,
/// Value: the corresponding filter.
///
/// This overall struct is described below:
/// GridSettingRevision
/// layout:
/// field_id:
/// FieldType: GridFilterRevision
/// FieldType: GridFilterRevision
/// field_id:
/// FieldType: GridFilterRevision
/// FieldType: GridFilterRevision
/// layout:
/// field_id:
/// FieldType: GridFilterRevision
/// FieldType: GridFilterRevision
///
/// Group and sorts will be the same structure as filters.
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
pub struct GridSettingRevision {
pub layout: GridLayoutRevision,
/// Each layout contains multiple key/value.
/// Key: field_id
/// Value: this value contains key/value.
/// Key: FieldType,
/// Value: the corresponding filters.
#[serde(with = "indexmap::serde_seq")]
filters: IndexMap<GridLayoutRevision, IndexMap<String, GridFilterRevisionMap>>,
/// Each layout contains multiple key/value.
/// Key: field_id
/// Value: this value contains key/value.
/// Key: FieldType,
/// Value: the corresponding groups.
#[serde(skip, with = "indexmap::serde_seq")]
pub groups: IndexMap<GridLayoutRevision, Vec<GridGroupRevision>>,
pub groups: IndexMap<GridLayoutRevision, IndexMap<String, GridGroupRevisionMap>>,
#[serde(skip, with = "indexmap::serde_seq")]
pub sorts: IndexMap<GridLayoutRevision, Vec<GridSortRevision>>,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum GridLayoutRevision {
Table = 0,
Board = 1,
}
impl ToString for GridLayoutRevision {
fn to_string(&self) -> String {
let layout_rev = self.clone() as u8;
layout_rev.to_string()
}
}
impl std::default::Default for GridLayoutRevision {
fn default() -> Self {
GridLayoutRevision::Table
}
}
pub type FiltersByFieldId = HashMap<String, Vec<Arc<GridFilterRevision>>>;
pub type GroupsByFieldId = HashMap<String, Vec<Arc<GridGroupRevision>>>;
pub type SortsByFieldId = HashMap<String, Vec<Arc<GridSortRevision>>>;
@ -61,6 +73,36 @@ impl GridSettingRevision {
None
}
pub fn get_mut_groups(
&mut self,
layout: &GridLayoutRevision,
field_id: &str,
field_type: &FieldTypeRevision,
) -> Option<&mut Vec<Arc<GridGroupRevision>>> {
self.groups
.get_mut(layout)
.and_then(|group_rev_map_by_field_id| group_rev_map_by_field_id.get_mut(field_id))
.and_then(|group_rev_map| group_rev_map.get_mut(field_type))
}
pub fn insert_group(
&mut self,
layout: &GridLayoutRevision,
field_id: &str,
field_type: &FieldTypeRevision,
filter_rev: GridGroupRevision,
) {
let filter_rev_map_by_field_id = self.groups.entry(layout.clone()).or_insert_with(IndexMap::new);
let filter_rev_map = filter_rev_map_by_field_id
.entry(field_id.to_string())
.or_insert_with(GridGroupRevisionMap::new);
filter_rev_map
.entry(field_type.to_owned())
.or_insert_with(Vec::new)
.push(Arc::new(filter_rev))
}
pub fn get_all_sort(&self) -> Option<SortsByFieldId> {
None
}
@ -135,70 +177,50 @@ impl GridSettingRevision {
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
#[serde(transparent)]
pub struct GridFilterRevisionMap {
#[serde(with = "indexmap::serde_seq")]
pub filter_by_field_type: IndexMap<FieldTypeRevision, Vec<Arc<GridFilterRevision>>>,
}
impl GridFilterRevisionMap {
pub fn new() -> Self {
GridFilterRevisionMap::default()
}
}
impl std::ops::Deref for GridFilterRevisionMap {
type Target = IndexMap<FieldTypeRevision, Vec<Arc<GridFilterRevision>>>;
fn deref(&self) -> &Self::Target {
&self.filter_by_field_type
}
}
impl std::ops::DerefMut for GridFilterRevisionMap {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.filter_by_field_type
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize_repr, Deserialize_repr)]
#[repr(u8)]
pub enum GridLayoutRevision {
Table = 0,
Board = 1,
}
impl ToString for GridLayoutRevision {
fn to_string(&self) -> String {
let layout_rev = self.clone() as u8;
layout_rev.to_string()
}
}
impl std::default::Default for GridLayoutRevision {
fn default() -> Self {
GridLayoutRevision::Table
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, Hash)]
pub struct GridFilterRevision {
pub id: String,
pub field_id: String,
pub condition: u8,
pub content: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridGroupRevision {
pub id: String,
pub field_id: Option<String>,
pub sub_field_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridSortRevision {
pub id: String,
pub field_id: Option<String>,
}
pub type GridFilterRevisionMap = GridObjectRevisionMap<GridFilterRevision>;
pub type GridGroupRevisionMap = GridObjectRevisionMap<GridGroupRevision>;
#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq, PartialEq)]
#[serde(transparent)]
pub struct GridObjectRevisionMap<T>
where
T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
#[serde(with = "indexmap::serde_seq")]
pub object_by_field_type: IndexMap<FieldTypeRevision, Vec<Arc<T>>>,
}
impl<T> GridObjectRevisionMap<T>
where
T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
pub fn new() -> Self {
GridObjectRevisionMap::default()
}
}
impl<T> std::ops::Deref for GridObjectRevisionMap<T>
where
T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
type Target = IndexMap<FieldTypeRevision, Vec<Arc<T>>>;
fn deref(&self) -> &Self::Target {
&self.object_by_field_type
}
}
impl<T> std::ops::DerefMut for GridObjectRevisionMap<T>
where
T: Debug + Clone + Default + Eq + PartialEq + serde::Serialize + serde::de::DeserializeOwned + 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.object_by_field_type
}
}

View File

@ -0,0 +1,11 @@
use crate::revision::FieldTypeRevision;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct GridGroupRevision {
pub id: String,
pub field_id: String,
pub sub_field_id: Option<String>,
}

View File

@ -1,5 +1,9 @@
mod filter_rev;
mod grid_rev;
mod grid_setting_rev;
mod group_rev;
pub use filter_rev::*;
pub use grid_rev::*;
pub use grid_setting_rev::*;
pub use group_rev::*;

View File

@ -409,24 +409,32 @@ impl GridRevisionPad {
}
}
if let Some(params) = changeset.insert_group {
let rev = GridGroupRevision {
let group_rev = GridGroupRevision {
id: gen_grid_group_id(),
field_id: params.field_id,
field_id: params.field_id.clone(),
sub_field_id: params.sub_field_id,
};
grid_rev
.setting
.groups
.entry(layout_rev.clone())
.or_insert_with(std::vec::Vec::new)
.push(rev);
is_changed = Some(())
.insert_group(&layout_rev, &params.field_id, &params.field_type_rev, group_rev);
is_changed = Some(());
}
if let Some(delete_group_id) = changeset.delete_group {
match grid_rev.setting.groups.get_mut(&layout_rev) {
Some(groups) => groups.retain(|group| group.id != delete_group_id),
if let Some(params) = changeset.delete_group {
// match grid_rev.setting.groups.get_mut(&layout_rev) {
// Some(groups) => groups.retain(|group| group.id != delete_group_id),
// None => {
// tracing::warn!("Can't find the group with {:?}", layout_rev);
// }
// }
match grid_rev
.setting
.get_mut_groups(&layout_rev, &params.field_id, &params.field_type_rev)
{
Some(groups) => {
groups.retain(|filter| filter.id != params.group_id);
}
None => {
tracing::warn!("Can't find the group with {:?}", layout_rev);
}

View File

@ -6,7 +6,7 @@ pub struct GridSettingChangesetParams {
pub insert_filter: Option<CreateGridFilterParams>,
pub delete_filter: Option<DeleteFilterParams>,
pub insert_group: Option<CreateGridGroupParams>,
pub delete_group: Option<String>,
pub delete_group: Option<DeleteGroupParams>,
pub insert_sort: Option<CreateGridSortParams>,
pub delete_sort: Option<String>,
}
@ -28,10 +28,19 @@ pub struct DeleteFilterParams {
pub filter_id: String,
pub field_type_rev: FieldTypeRevision,
}
pub struct CreateGridGroupParams {
pub field_id: Option<String>,
pub field_id: String,
pub sub_field_id: Option<String>,
pub field_type_rev: FieldTypeRevision,
}
pub struct DeleteGroupParams {
pub field_id: String,
pub group_id: String,
pub field_type_rev: FieldTypeRevision,
}
pub struct CreateGridSortParams {
pub field_id: Option<String>,
}