chore: generic GroupGenerator

This commit is contained in:
appflowy 2022-08-12 09:49:07 +08:00
parent 461751cf59
commit 707ddb4e73
23 changed files with 267 additions and 107 deletions

View File

@ -66,7 +66,7 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev) SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
} }
FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::Checkbox => CheckboxTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
}?; }?;
@ -116,7 +116,7 @@ pub fn try_decode_cell_data(
.get_type_option_entry::<MultiSelectTypeOptionPB>(field_type)? .get_type_option_entry::<MultiSelectTypeOptionPB>(field_type)?
.decode_cell_data(cell_data.into(), s_field_type, field_rev), .decode_cell_data(cell_data.into(), s_field_type, field_rev),
FieldType::Checkbox => field_rev FieldType::Checkbox => field_rev
.get_type_option_entry::<CheckboxTypeOption>(field_type)? .get_type_option_entry::<CheckboxTypeOptionPB>(field_type)?
.decode_cell_data(cell_data.into(), s_field_type, field_rev), .decode_cell_data(cell_data.into(), s_field_type, field_rev),
FieldType::URL => field_rev FieldType::URL => field_rev
.get_type_option_entry::<URLTypeOptionPB>(field_type)? .get_type_option_entry::<URLTypeOptionPB>(field_type)?

View File

@ -95,7 +95,7 @@ pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn
FieldType::DateTime => DateTypeOptionPB::default().into(), FieldType::DateTime => DateTypeOptionPB::default().into(),
FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(), FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(),
FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(), FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
FieldType::Checkbox => CheckboxTypeOption::default().into(), FieldType::Checkbox => CheckboxTypeOptionPB::default().into(),
FieldType::URL => URLTypeOptionPB::default().into(), FieldType::URL => URLTypeOptionPB::default().into(),
}; };

View File

@ -8,7 +8,7 @@ mod tests {
#[test] #[test]
fn checkout_box_description_test() { fn checkout_box_description_test() {
let type_option = CheckboxTypeOption::default(); let type_option = CheckboxTypeOptionPB::default();
let field_type = FieldType::Checkbox; let field_type = FieldType::Checkbox;
let field_rev = FieldBuilder::from_field_type(&field_type).build(); let field_rev = FieldBuilder::from_field_type(&field_type).build();
@ -27,7 +27,7 @@ mod tests {
} }
fn assert_checkbox( fn assert_checkbox(
type_option: &CheckboxTypeOption, type_option: &CheckboxTypeOptionPB,
input_str: &str, input_str: &str,
expected_str: &str, expected_str: &str,
field_type: &FieldType, field_type: &FieldType,

View File

@ -10,9 +10,9 @@ use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
#[derive(Default)] #[derive(Default)]
pub struct CheckboxTypeOptionBuilder(CheckboxTypeOption); pub struct CheckboxTypeOptionBuilder(CheckboxTypeOptionPB);
impl_into_box_type_option_builder!(CheckboxTypeOptionBuilder); impl_into_box_type_option_builder!(CheckboxTypeOptionBuilder);
impl_builder_from_json_str_and_from_bytes!(CheckboxTypeOptionBuilder, CheckboxTypeOption); impl_builder_from_json_str_and_from_bytes!(CheckboxTypeOptionBuilder, CheckboxTypeOptionPB);
impl CheckboxTypeOptionBuilder { impl CheckboxTypeOptionBuilder {
pub fn set_selected(mut self, is_selected: bool) -> Self { pub fn set_selected(mut self, is_selected: bool) -> Self {
@ -32,13 +32,13 @@ impl TypeOptionBuilder for CheckboxTypeOptionBuilder {
} }
#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] #[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
pub struct CheckboxTypeOption { pub struct CheckboxTypeOptionPB {
#[pb(index = 1)] #[pb(index = 1)]
pub is_selected: bool, pub is_selected: bool,
} }
impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); impl_type_option!(CheckboxTypeOptionPB, FieldType::Checkbox);
impl CellDisplayable<CheckboxCellData> for CheckboxTypeOption { impl CellDisplayable<CheckboxCellData> for CheckboxTypeOptionPB {
fn display_data( fn display_data(
&self, &self,
cell_data: CellData<CheckboxCellData>, cell_data: CellData<CheckboxCellData>,
@ -50,7 +50,7 @@ impl CellDisplayable<CheckboxCellData> for CheckboxTypeOption {
} }
} }
impl CellDataOperation<CheckboxCellData, String> for CheckboxTypeOption { impl CellDataOperation<CheckboxCellData, String> for CheckboxTypeOptionPB {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<CheckboxCellData>, cell_data: CellData<CheckboxCellData>,

View File

@ -3,7 +3,7 @@ use crate::entities::{FieldType, GridBlockChangesetPB};
use crate::services::block_manager::GridBlockManager; use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{AnyCellData, CellFilterOperation}; use crate::services::cell::{AnyCellData, CellFilterOperation};
use crate::services::field::{ use crate::services::field::{
CheckboxTypeOption, DateTypeOptionPB, MultiSelectTypeOptionPB, NumberTypeOptionPB, RichTextTypeOptionPB, CheckboxTypeOptionPB, DateTypeOptionPB, MultiSelectTypeOptionPB, NumberTypeOptionPB, RichTextTypeOptionPB,
SingleSelectTypeOptionPB, URLTypeOptionPB, SingleSelectTypeOptionPB, URLTypeOptionPB,
}; };
use crate::services::filter::filter_cache::{ use crate::services::filter::filter_cache::{
@ -222,7 +222,7 @@ fn filter_cell(
FieldType::Checkbox => filter_cache.checkbox_filter.get(&filter_id).and_then(|filter| { FieldType::Checkbox => filter_cache.checkbox_filter.get(&filter_id).and_then(|filter| {
Some( Some(
field_rev field_rev
.get_type_option_entry::<CheckboxTypeOption>(field_type_rev)? .get_type_option_entry::<CheckboxTypeOptionPB>(field_type_rev)?
.apply_filter(any_cell_data, filter.value()) .apply_filter(any_cell_data, filter.value())
.ok(), .ok(),
) )

View File

@ -1,6 +1,6 @@
use crate::entities::{CheckboxCondition, CheckboxFilterConfigurationPB}; use crate::entities::{CheckboxCondition, CheckboxFilterConfigurationPB};
use crate::services::cell::{AnyCellData, CellData, CellFilterOperation}; use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
use crate::services::field::{CheckboxCellData, CheckboxTypeOption}; use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB};
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
impl CheckboxFilterConfigurationPB { impl CheckboxFilterConfigurationPB {
@ -13,7 +13,7 @@ impl CheckboxFilterConfigurationPB {
} }
} }
impl CellFilterOperation<CheckboxFilterConfigurationPB> for CheckboxTypeOption { impl CellFilterOperation<CheckboxFilterConfigurationPB> for CheckboxTypeOptionPB {
fn apply_filter(&self, any_cell_data: AnyCellData, filter: &CheckboxFilterConfigurationPB) -> FlowyResult<bool> { fn apply_filter(&self, any_cell_data: AnyCellData, filter: &CheckboxFilterConfigurationPB) -> FlowyResult<bool> {
if !any_cell_data.is_checkbox() { if !any_cell_data.is_checkbox() {
return Ok(true); return Ok(true);

View File

@ -0,0 +1,70 @@
use crate::entities::{
CheckboxGroupConfigurationPB, DateGroupConfigurationPB, NumberGroupConfigurationPB,
SelectOptionGroupConfigurationPB, TextGroupConfigurationPB, UrlGroupConfigurationPB,
};
use crate::services::cell::CellBytes;
use crate::services::field::{
CheckboxCellDataParser, DateCellDataParser, NumberCellDataParser, NumberFormat, SelectOptionCellDataParser,
TextCellDataParser, URLCellDataParser,
};
use crate::services::group::GroupAction;
// impl GroupAction for TextGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(TextCellDataParser()) {
// cell_data.as_ref() == content
// } else {
// false
// }
// }
// }
//
// impl GroupAction for NumberGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(NumberCellDataParser(NumberFormat::Num)) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for DateGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(DateCellDataParser()) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for SelectOptionGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(SelectOptionCellDataParser()) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for UrlGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(URLCellDataParser()) {
// false
// } else {
// false
// }
// }
// }
//
// impl GroupAction for CheckboxGroupConfigurationPB {
// fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool {
// if let Ok(cell_data) = cell_bytes.with_parser(CheckboxCellDataParser()) {
// false
// } else {
// false
// }
// }
// }

View File

@ -0,0 +1,7 @@
use crate::entities::CheckboxGroupConfigurationPB;
use crate::services::cell::{AnyCellData, CellData, CellGroupOperation};
use crate::services::field::{CheckboxCellData, CheckboxTypeOptionPB};
use crate::services::group::GroupController;
use flowy_error::FlowyResult;
// pub type CheckboxGroupGenerator = GroupGenerator<CheckboxGroupConfigurationPB, CheckboxTypeOptionPB>;

View File

@ -0,0 +1,5 @@
use crate::entities::CheckboxGroupConfigurationPB;
use crate::services::field::DateTypeOptionPB;
use crate::services::group::GroupController;
// pub type CheckboxGroupGenerator = GroupGenerator<CheckboxGroupConfigurationPB, DateTypeOptionPB>;

View File

@ -0,0 +1,88 @@
use crate::services::cell::{decode_any_cell_data, CellBytes};
use bytes::Bytes;
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{
CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision, TypeOptionDataDeserializer,
};
use std::marker::PhantomData;
use std::sync::Arc;
pub trait GroupAction {
fn should_group(&mut self, content: &str, cell_bytes: CellBytes) -> bool;
}
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<C, T> {
fn gen_groups(
configuration: &Option<C>,
type_option: &Option<T>,
cell_content_provider: &dyn GroupCellContentProvider,
) -> Vec<Group>;
}
pub struct GroupController<C, T, G> {
field_rev: Arc<FieldRevision>,
groups: Vec<Group>,
type_option: Option<T>,
configuration: Option<C>,
phantom: PhantomData<G>,
}
pub struct Group {
row_ids: Vec<String>,
content: String,
}
impl<C, T, G> GroupController<C, T, G>
where
C: TryFrom<Bytes, Error = protobuf::ProtobufError>,
T: TypeOptionDataDeserializer,
G: GroupGenerator<C, T>,
{
pub fn new(
field_rev: Arc<FieldRevision>,
configuration: GroupConfigurationRevision,
cell_content_provider: &dyn GroupCellContentProvider,
) -> 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.clone();
let type_option = field_rev.get_type_option_entry::<T>(field_type_rev);
Ok(Self {
field_rev,
groups: G::gen_groups(&configuration, &type_option, cell_content_provider),
type_option,
configuration,
phantom: PhantomData,
})
}
}
impl<C, T, G> GroupController<C, T, G>
where
Self: GroupAction,
{
pub fn group_row(&mut self, row: &RowRevision) {
if self.configuration.is_none() {
return;
}
if let Some(cell_rev) = row.cells.get(&self.field_rev.id) {
for group in self.groups.iter_mut() {
let cell_rev: CellRevision = cell_rev.clone();
let cell_bytes = decode_any_cell_data(cell_rev.data, &self.field_rev);
// if self.should_group(&group.content, cell_bytes) {
// group.row_ids.push(row.id.clone());
// }
}
}
}
}

View File

@ -1,11 +1,15 @@
mod checkbox_group; mod checkbox_group;
mod date_group; mod date_group;
mod generator;
mod number_group; mod number_group;
mod select_option_group; mod select_option_group;
mod text_group; mod text_group;
mod url_group;
pub use checkbox_group::*; pub use checkbox_group::*;
pub use date_group::*; pub use date_group::*;
pub use generator::*;
pub use number_group::*; pub use number_group::*;
pub use select_option_group::*; pub use select_option_group::*;
pub use text_group::*; pub use text_group::*;
pub use url_group::*;

View File

@ -0,0 +1,5 @@
use crate::entities::NumberGroupConfigurationPB;
use crate::services::field::NumberTypeOptionPB;
use crate::services::group::GroupController;
// pub type NumberGroupGenerator = GroupGenerator<NumberGroupConfigurationPB, NumberTypeOptionPB>;

View File

@ -0,0 +1,44 @@
use crate::entities::SelectOptionGroupConfigurationPB;
use crate::services::cell::CellBytes;
use crate::services::field::{MultiSelectTypeOptionPB, SelectedSelectOptions, SingleSelectTypeOptionPB};
use crate::services::group::{Group, GroupAction, GroupCellContentProvider, GroupController, GroupGenerator};
pub type SingleSelectGroupController =
GroupController<SelectOptionGroupConfigurationPB, SingleSelectTypeOptionPB, SingleSelectGroupGen>;
pub struct SingleSelectGroupGen();
impl GroupGenerator<SelectOptionGroupConfigurationPB, SingleSelectTypeOptionPB> for SingleSelectGroupGen {
fn gen_groups(
configuration: &Option<SelectOptionGroupConfigurationPB>,
type_option: &Option<SingleSelectTypeOptionPB>,
cell_content_provider: &dyn GroupCellContentProvider,
) -> Vec<Group> {
todo!()
}
}
impl GroupAction for SingleSelectGroupController {
fn should_group(&mut self, content: &str, cell_bytes: CellBytes) -> bool {
todo!()
}
}
pub type MultiSelectGroupController =
GroupController<SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB, MultiSelectGroupGen>;
pub struct MultiSelectGroupGen();
impl GroupGenerator<SelectOptionGroupConfigurationPB, MultiSelectTypeOptionPB> for MultiSelectGroupGen {
fn gen_groups(
configuration: &Option<SelectOptionGroupConfigurationPB>,
type_option: &Option<MultiSelectTypeOptionPB>,
cell_content_provider: &dyn GroupCellContentProvider,
) -> Vec<Group> {
todo!()
}
}
impl GroupAction for MultiSelectGroupController {
fn should_group(&mut self, content: &str, cell_bytes: CellBytes) -> bool {
todo!()
}
}

View File

@ -0,0 +1,5 @@
use crate::entities::TextGroupConfigurationPB;
use crate::services::field::RichTextTypeOptionPB;
use crate::services::group::GroupController;
// pub type TextGroupGenerator = GroupGenerator<TextGroupConfigurationPB, RichTextTypeOptionPB>;

View File

@ -0,0 +1,5 @@
use crate::entities::UrlGroupConfigurationPB;
use crate::services::field::URLTypeOptionPB;
use crate::services::group::GroupController;
// pub type UrlGroupGenerator = GroupGenerator<UrlGroupConfigurationPB, URLTypeOptionPB>;

View File

@ -4,7 +4,9 @@ use crate::entities::{
}; };
use crate::services::block_manager::GridBlockManager; use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{decode_any_cell_data, CellBytes}; use crate::services::cell::{decode_any_cell_data, CellBytes};
use crate::services::field::TextCellDataParser;
use crate::services::grid_editor_task::GridServiceTaskScheduler; use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::group::{GroupAction, GroupCellContentProvider, SingleSelectGroupController};
use bytes::Bytes; use bytes::Bytes;
use flowy_error::FlowyResult; use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, GroupConfigurationRevision, RowRevision};
@ -56,94 +58,42 @@ impl GridGroupService {
.flatten() .flatten()
.collect::<Vec<Arc<RowRevision>>>(); .collect::<Vec<Arc<RowRevision>>>();
// let a = SingleSelectGroupController::new;
// let b = a(field_rev.clone(), configuration, &self.grid_pad);
let groups = match field_type { let groups = match field_type {
FieldType::RichText => { FieldType::RichText => {
let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<TextGroupConfigurationPB>::from_configuration(configuration);
} }
FieldType::Number => { FieldType::Number => {
let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<NumberGroupConfigurationPB>::from_configuration(configuration);
} }
FieldType::DateTime => { FieldType::DateTime => {
let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<DateGroupConfigurationPB>::from_configuration(configuration);
} }
FieldType::SingleSelect => { FieldType::SingleSelect => {
let generator = GroupGenerator::<SelectOptionGroupConfigurationPB>::from_configuration(configuration); let group_controller =
SingleSelectGroupController::new(field_rev.clone(), configuration, &self.grid_pad);
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let generator = GroupGenerator::<SelectOptionGroupConfigurationPB>::from_configuration(configuration); // let group_generator = MultiSelectGroupControllern(configuration);
} }
FieldType::Checkbox => { FieldType::Checkbox => {
let generator = GroupGenerator::<CheckboxGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<CheckboxGroupConfigurationPB>::from_configuration(configuration);
} }
FieldType::URL => { FieldType::URL => {
let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration); // let generator = GroupGenerator::<UrlGroupConfigurationPB>::from_configuration(configuration);
} }
}; };
None None
} }
} }
pub struct GroupGenerator<T> {
field_id: String,
groups: Vec<Group>,
configuration: Option<T>,
}
pub struct Group {
row_ids: Vec<String>,
content: String,
}
impl<T> GroupGenerator<T>
where
T: TryFrom<Bytes, Error = protobuf::ProtobufError>,
{
pub fn from_configuration(configuration: GroupConfigurationRevision) -> FlowyResult<Self> {
let bytes = Bytes::from(configuration.content.unwrap_or(vec![]));
Self::from_bytes(&configuration.field_id, bytes)
}
pub fn from_bytes(field_id: &str, bytes: Bytes) -> FlowyResult<Self> {
let configuration = if bytes.is_empty() {
None
} else {
Some(T::try_from(bytes)?)
};
Ok(Self {
field_id: field_id.to_owned(),
groups: vec![],
configuration,
})
}
}
pub trait GroupConfiguration {
fn should_group(&self, content: &str, cell_bytes: CellBytes) -> bool;
}
impl<T> GroupGenerator<T>
where
T: GroupConfiguration,
{
pub fn group_row(&mut self, field_rev: &Arc<FieldRevision>, row: &RowRevision) {
if self.configuration.is_none() {
return;
}
let configuration = self.configuration.as_ref().unwrap();
if let Some(cell_rev) = row.cells.get(&self.field_id) {
for group in self.groups.iter_mut() {
let cell_rev: CellRevision = cell_rev.clone();
let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev);
if configuration.should_group(&group.content, cell_bytes) {
group.row_ids.push(row.id.clone());
}
}
}
}
}
fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<&Arc<FieldRevision>> { fn find_group_field(field_revs: &[Arc<FieldRevision>]) -> Option<&Arc<FieldRevision>> {
field_revs.iter().find(|field_rev| { field_revs.iter().find(|field_rev| {
let field_type: FieldType = field_rev.field_type_rev.into(); let field_type: FieldType = field_rev.field_type_rev.into();
field_type.can_be_group() field_type.can_be_group()
}) })
} }
impl GroupCellContentProvider for Arc<RwLock<GridRevisionPad>> {}

View File

@ -1,17 +0,0 @@
use crate::entities::CheckboxGroupConfigurationPB;
use crate::services::cell::{AnyCellData, CellData, CellGroupOperation};
use crate::services::field::{CheckboxCellData, CheckboxTypeOption};
use flowy_error::FlowyResult;
impl CellGroupOperation for CheckboxTypeOption {
fn apply_group(&self, any_cell_data: AnyCellData, content: &str) -> FlowyResult<bool> {
if !any_cell_data.is_checkbox() {
return Ok(true);
}
let cell_data: CellData<CheckboxCellData> = any_cell_data.into();
let checkbox_cell_data = cell_data.try_into_inner()?;
// Ok(checkbox_cell_data.as_ref() == content)
todo!()
}
}

View File

@ -1,8 +0,0 @@
use crate::entities::SelectOptionGroupConfigurationPB;
use crate::services::field::SelectedSelectOptions;
impl SelectOptionGroupConfigurationPB {
pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
return true;
}
}

View File

@ -1,5 +1,7 @@
mod group_configuration;
mod group_generator;
mod group_service; mod group_service;
mod impls;
pub(crate) use group_configuration::*;
pub(crate) use group_generator::*;
pub(crate) use group_service::*; pub(crate) use group_service::*;
pub(crate) use impls::*;