mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: provide default type option transform (#1579)
This commit is contained in:
parent
85e489babb
commit
67e350e797
@ -9,24 +9,6 @@ pub trait TypeOptionBuilder {
|
||||
|
||||
/// Returns a serializer that can be used to serialize the type-option data
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer;
|
||||
|
||||
/// Transform the data from passed-in type-option to current type-option
|
||||
///
|
||||
/// The current type-option data may be changed if it supports transform
|
||||
/// the data from the other kind of type-option data.
|
||||
///
|
||||
/// For example, when switching from `checkbox` type-option to `single-select`
|
||||
/// type-option, adding the `Yes` option if the `single-select` type-option doesn't contain it.
|
||||
/// But the cell content is a string, `Yes`, it's need to do the cell content transform.
|
||||
/// The `Yes` string will be transformed to the `Yes` option id.
|
||||
///
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `field_type`: represents as the field type of the passed-in type-option data
|
||||
/// * `type_option_data`: passed-in type-option data
|
||||
//
|
||||
fn transform(&mut self, field_type: &FieldType, type_option_data: String);
|
||||
}
|
||||
|
||||
pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn TypeOptionBuilder> {
|
||||
|
@ -3,6 +3,7 @@ use crate::impl_type_option;
|
||||
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, CheckboxCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
|
||||
TypeOptionTransform,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
@ -31,10 +32,6 @@ impl TypeOptionBuilder for CheckboxTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
|
||||
@ -47,15 +44,17 @@ impl_type_option!(CheckboxTypeOptionPB, FieldType::Checkbox);
|
||||
impl TypeOption for CheckboxTypeOptionPB {
|
||||
type CellData = CheckboxCellData;
|
||||
type CellChangeset = CheckboxCellChangeset;
|
||||
type CellPBType = CheckboxCellData;
|
||||
type CellProtobufType = CheckboxCellData;
|
||||
}
|
||||
|
||||
impl TypeOptionTransform for CheckboxTypeOptionPB {}
|
||||
|
||||
impl TypeOptionConfiguration for CheckboxTypeOptionPB {
|
||||
type CellFilterConfiguration = CheckboxFilterPB;
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for CheckboxTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
cell_data
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ mod tests {
|
||||
let decoded_data = type_option
|
||||
.try_decode_cell_data(encoded_data, &FieldType::DateTime, field_rev)
|
||||
.unwrap();
|
||||
let decoded_data = type_option.convert_into_pb_type(decoded_data);
|
||||
let decoded_data = type_option.convert_to_protobuf(decoded_data);
|
||||
if type_option.include_time {
|
||||
format!("{} {}", decoded_data.date, decoded_data.time)
|
||||
.trim_end()
|
||||
|
@ -3,7 +3,7 @@ use crate::impl_type_option;
|
||||
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateCellDataPB, DateFormat, TimeFormat, TypeOption,
|
||||
TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
|
||||
TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration, TypeOptionTransform,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use chrono::format::strftime::StrftimeItems;
|
||||
@ -30,7 +30,7 @@ impl_type_option!(DateTypeOptionPB, FieldType::DateTime);
|
||||
impl TypeOption for DateTypeOptionPB {
|
||||
type CellData = DateCellData;
|
||||
type CellChangeset = DateCellChangeset;
|
||||
type CellPBType = DateCellDataPB;
|
||||
type CellProtobufType = DateCellDataPB;
|
||||
}
|
||||
|
||||
impl TypeOptionConfiguration for DateTypeOptionPB {
|
||||
@ -38,7 +38,7 @@ impl TypeOptionConfiguration for DateTypeOptionPB {
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for DateTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
self.today_desc_from_timestamp(cell_data)
|
||||
}
|
||||
|
||||
@ -128,6 +128,8 @@ impl DateTypeOptionPB {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeOptionTransform for DateTypeOptionPB {}
|
||||
|
||||
impl CellDataDecoder for DateTypeOptionPB {
|
||||
fn try_decode_cell_data(
|
||||
&self,
|
||||
@ -207,7 +209,4 @@ impl TypeOptionBuilder for DateTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::services::cell::{AnyCellChangeset, CellComparable, CellDataChangeset,
|
||||
use crate::services::field::type_options::number_type_option::format::*;
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, NumberCellData, StrCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData,
|
||||
TypeOptionConfiguration,
|
||||
TypeOptionConfiguration, TypeOptionTransform,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
@ -51,9 +51,6 @@ impl TypeOptionBuilder for NumberTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// Number
|
||||
@ -79,7 +76,7 @@ impl_type_option!(NumberTypeOptionPB, FieldType::Number);
|
||||
impl TypeOption for NumberTypeOptionPB {
|
||||
type CellData = StrCellData;
|
||||
type CellChangeset = NumberCellChangeset;
|
||||
type CellPBType = StrCellData;
|
||||
type CellProtobufType = StrCellData;
|
||||
}
|
||||
|
||||
impl TypeOptionConfiguration for NumberTypeOptionPB {
|
||||
@ -87,7 +84,7 @@ impl TypeOptionConfiguration for NumberTypeOptionPB {
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for NumberTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
cell_data
|
||||
}
|
||||
|
||||
@ -128,6 +125,8 @@ pub(crate) fn strip_currency_symbol<T: ToString>(s: T) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
impl TypeOptionTransform for NumberTypeOptionPB {}
|
||||
|
||||
impl CellDataDecoder for NumberTypeOptionPB {
|
||||
fn try_decode_cell_data(
|
||||
&self,
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::entities::{ChecklistFilterPB, FieldType};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
|
||||
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
|
||||
SelectTypeOptionSharedAction, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
|
||||
@ -26,7 +26,7 @@ impl_type_option!(ChecklistTypeOptionPB, FieldType::Checklist);
|
||||
impl TypeOption for ChecklistTypeOptionPB {
|
||||
type CellData = SelectOptionIds;
|
||||
type CellChangeset = SelectOptionCellChangeset;
|
||||
type CellPBType = SelectOptionCellDataPB;
|
||||
type CellProtobufType = SelectOptionCellDataPB;
|
||||
}
|
||||
|
||||
impl TypeOptionConfiguration for ChecklistTypeOptionPB {
|
||||
@ -34,7 +34,7 @@ impl TypeOptionConfiguration for ChecklistTypeOptionPB {
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for ChecklistTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
self.get_selected_options(cell_data)
|
||||
}
|
||||
|
||||
@ -113,8 +113,4 @@ impl TypeOptionBuilder for ChecklistTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
|
||||
SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::entities::{FieldType, SelectOptionFilterPB};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
|
||||
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
|
||||
SelectTypeOptionSharedAction, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
|
||||
@ -26,7 +26,7 @@ impl_type_option!(MultiSelectTypeOptionPB, FieldType::MultiSelect);
|
||||
impl TypeOption for MultiSelectTypeOptionPB {
|
||||
type CellData = SelectOptionIds;
|
||||
type CellChangeset = SelectOptionCellChangeset;
|
||||
type CellPBType = SelectOptionCellDataPB;
|
||||
type CellProtobufType = SelectOptionCellDataPB;
|
||||
}
|
||||
|
||||
impl TypeOptionConfiguration for MultiSelectTypeOptionPB {
|
||||
@ -34,7 +34,7 @@ impl TypeOptionConfiguration for MultiSelectTypeOptionPB {
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for MultiSelectTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
self.get_selected_options(cell_data)
|
||||
}
|
||||
|
||||
@ -119,17 +119,14 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
|
||||
SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::entities::FieldType;
|
||||
use crate::services::cell::CellDataChangeset;
|
||||
use crate::services::field::type_options::selection_type_option::*;
|
||||
use crate::services::field::{CheckboxTypeOptionBuilder, FieldBuilder, TypeOptionBuilder};
|
||||
use crate::services::field::{CheckboxTypeOptionBuilder, FieldBuilder, TypeOptionBuilder, TypeOptionTransform};
|
||||
use crate::services::field::{MultiSelectTypeOptionBuilder, MultiSelectTypeOptionPB};
|
||||
|
||||
#[test]
|
||||
@ -137,13 +134,13 @@ mod tests {
|
||||
let checkbox_type_option_builder = CheckboxTypeOptionBuilder::default();
|
||||
let checkbox_type_option_data = checkbox_type_option_builder.serializer().json_str();
|
||||
|
||||
let mut multi_select = MultiSelectTypeOptionBuilder::default();
|
||||
multi_select.transform(&FieldType::Checkbox, checkbox_type_option_data.clone());
|
||||
debug_assert_eq!(multi_select.0.options.len(), 2);
|
||||
let mut multi_select = MultiSelectTypeOptionBuilder::default().0;
|
||||
multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data.clone());
|
||||
debug_assert_eq!(multi_select.options.len(), 2);
|
||||
|
||||
// Already contain the yes/no option. It doesn't need to insert new options
|
||||
multi_select.transform(&FieldType::Checkbox, checkbox_type_option_data);
|
||||
debug_assert_eq!(multi_select.0.options.len(), 2);
|
||||
multi_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data);
|
||||
debug_assert_eq!(multi_select.options.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -158,13 +155,13 @@ mod tests {
|
||||
|
||||
let singleselect_type_option_data = singleselect_type_option_builder.serializer().json_str();
|
||||
|
||||
let mut multi_select = MultiSelectTypeOptionBuilder::default();
|
||||
multi_select.transform(&FieldType::MultiSelect, singleselect_type_option_data.clone());
|
||||
debug_assert_eq!(multi_select.0.options.len(), 2);
|
||||
let mut multi_select = MultiSelectTypeOptionBuilder::default().0;
|
||||
multi_select.transform_type_option(FieldType::MultiSelect, singleselect_type_option_data.clone());
|
||||
debug_assert_eq!(multi_select.options.len(), 2);
|
||||
|
||||
// Already contain the yes/no option. It doesn't need to insert new options
|
||||
multi_select.transform(&FieldType::MultiSelect, singleselect_type_option_data);
|
||||
debug_assert_eq!(multi_select.0.options.len(), 2);
|
||||
multi_select.transform_type_option(FieldType::MultiSelect, singleselect_type_option_data);
|
||||
debug_assert_eq!(multi_select.options.len(), 2);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
@ -4,9 +4,10 @@ use crate::services::cell::{
|
||||
CellDataDecoder, CellProtobufBlobParser, DecodedCellData, FromCellChangeset, FromCellString,
|
||||
};
|
||||
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformHelper;
|
||||
use crate::services::field::{
|
||||
ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB, TypeOption, TypeOptionCellData,
|
||||
TypeOptionTransform,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
|
||||
@ -128,6 +129,31 @@ pub trait SelectTypeOptionSharedAction: TypeOptionDataSerializer + Send + Sync {
|
||||
fn mut_options(&mut self) -> &mut Vec<SelectOptionPB>;
|
||||
}
|
||||
|
||||
impl<T> TypeOptionTransform for T
|
||||
where
|
||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + TypeOptionDataSerializer,
|
||||
{
|
||||
fn transformable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn transform_type_option(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String) {
|
||||
SelectOptionTypeOptionTransformHelper::transform_type_option(
|
||||
self,
|
||||
&old_type_option_field_type,
|
||||
old_type_option_data,
|
||||
);
|
||||
}
|
||||
|
||||
fn transform_type_option_cell_data(
|
||||
&self,
|
||||
cell_data: <Self as TypeOption>::CellData,
|
||||
decoded_field_type: &FieldType,
|
||||
) -> <Self as TypeOption>::CellData {
|
||||
SelectOptionTypeOptionTransformHelper::transform_type_option_cell_data(self, cell_data, decoded_field_type)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> CellDataDecoder for T
|
||||
where
|
||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds> + TypeOptionCellData,
|
||||
@ -135,16 +161,10 @@ where
|
||||
fn try_decode_cell_data(
|
||||
&self,
|
||||
cell_data: String,
|
||||
decoded_field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
_decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> FlowyResult<<Self as TypeOption>::CellData> {
|
||||
let cell_data = self.decode_type_option_cell_data(cell_data)?;
|
||||
Ok(SelectOptionTypeOptionTransformer::transform_type_option_cell_data(
|
||||
self,
|
||||
cell_data,
|
||||
decoded_field_type,
|
||||
field_rev,
|
||||
))
|
||||
self.decode_type_option_cell_data(cell_data)
|
||||
}
|
||||
|
||||
fn decode_cell_data_to_str(
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::entities::{FieldType, SelectOptionFilterPB};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString};
|
||||
use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
|
||||
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, SelectOptionCellDataPB, TypeOption, TypeOptionBuilder, TypeOptionCellData,
|
||||
TypeOptionConfiguration,
|
||||
@ -29,7 +29,7 @@ impl_type_option!(SingleSelectTypeOptionPB, FieldType::SingleSelect);
|
||||
impl TypeOption for SingleSelectTypeOptionPB {
|
||||
type CellData = SelectOptionIds;
|
||||
type CellChangeset = SelectOptionCellChangeset;
|
||||
type CellPBType = SelectOptionCellDataPB;
|
||||
type CellProtobufType = SelectOptionCellDataPB;
|
||||
}
|
||||
|
||||
impl TypeOptionConfiguration for SingleSelectTypeOptionPB {
|
||||
@ -37,7 +37,7 @@ impl TypeOptionConfiguration for SingleSelectTypeOptionPB {
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for SingleSelectTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
self.get_selected_options(cell_data)
|
||||
}
|
||||
|
||||
@ -107,10 +107,6 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn transform(&mut self, field_type: &FieldType, type_option_data: String) {
|
||||
SelectOptionTypeOptionTransformer::transform_type_option(&mut self.0, field_type, type_option_data)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -125,13 +121,13 @@ mod tests {
|
||||
let checkbox_type_option_builder = CheckboxTypeOptionBuilder::default();
|
||||
let checkbox_type_option_data = checkbox_type_option_builder.serializer().json_str();
|
||||
|
||||
let mut single_select = SingleSelectTypeOptionBuilder::default();
|
||||
single_select.transform(&FieldType::Checkbox, checkbox_type_option_data.clone());
|
||||
debug_assert_eq!(single_select.0.options.len(), 2);
|
||||
let mut single_select = SingleSelectTypeOptionBuilder::default().0;
|
||||
single_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data.clone());
|
||||
debug_assert_eq!(single_select.options.len(), 2);
|
||||
|
||||
// Already contain the yes/no option. It doesn't need to insert new options
|
||||
single_select.transform(&FieldType::Checkbox, checkbox_type_option_data);
|
||||
debug_assert_eq!(single_select.0.options.len(), 2);
|
||||
single_select.transform_type_option(FieldType::Checkbox, checkbox_type_option_data);
|
||||
debug_assert_eq!(single_select.options.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -146,13 +142,13 @@ mod tests {
|
||||
|
||||
let multiselect_type_option_data = multiselect_type_option_builder.serializer().json_str();
|
||||
|
||||
let mut single_select = SingleSelectTypeOptionBuilder::default();
|
||||
single_select.transform(&FieldType::MultiSelect, multiselect_type_option_data.clone());
|
||||
debug_assert_eq!(single_select.0.options.len(), 2);
|
||||
let mut single_select = SingleSelectTypeOptionBuilder::default().0;
|
||||
single_select.transform_type_option(FieldType::MultiSelect, multiselect_type_option_data.clone());
|
||||
debug_assert_eq!(single_select.options.len(), 2);
|
||||
|
||||
// Already contain the yes/no option. It doesn't need to insert new options
|
||||
single_select.transform(&FieldType::MultiSelect, multiselect_type_option_data);
|
||||
debug_assert_eq!(single_select.0.options.len(), 2);
|
||||
single_select.transform_type_option(FieldType::MultiSelect, multiselect_type_option_data);
|
||||
debug_assert_eq!(single_select.options.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -5,24 +5,22 @@ use crate::services::field::{
|
||||
SingleSelectTypeOptionPB, TypeOption, CHECK, UNCHECK,
|
||||
};
|
||||
|
||||
use grid_rev_model::FieldRevision;
|
||||
use serde_json;
|
||||
use grid_rev_model::TypeOptionDataDeserializer;
|
||||
|
||||
/// Handles how to transform the cell data when switching between different field types
|
||||
pub struct SelectOptionTypeOptionTransformer();
|
||||
impl SelectOptionTypeOptionTransformer {
|
||||
pub(crate) struct SelectOptionTypeOptionTransformHelper();
|
||||
impl SelectOptionTypeOptionTransformHelper {
|
||||
/// Transform the TypeOptionData from 'field_type' to single select option type.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `field_type`: the FieldType of the passed-in TypeOptionData
|
||||
/// * `type_option_data`: the data that can be parsed into corresponding TypeOptionData.
|
||||
/// * `old_field_type`: the FieldType of the passed-in TypeOptionData
|
||||
///
|
||||
pub fn transform_type_option<T>(shared: &mut T, field_type: &FieldType, _type_option_data: String)
|
||||
pub fn transform_type_option<T>(shared: &mut T, old_field_type: &FieldType, old_type_option_data: String)
|
||||
where
|
||||
T: SelectTypeOptionSharedAction,
|
||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
|
||||
{
|
||||
match field_type {
|
||||
match old_field_type {
|
||||
FieldType::Checkbox => {
|
||||
//add Yes and No options if it does not exist.
|
||||
if !shared.options().iter().any(|option| option.name == CHECK) {
|
||||
@ -36,16 +34,16 @@ impl SelectOptionTypeOptionTransformer {
|
||||
}
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let option_pb: MultiSelectTypeOptionPB = serde_json::from_str(_type_option_data.as_str()).unwrap();
|
||||
option_pb.options.iter().for_each(|new_option| {
|
||||
let options = MultiSelectTypeOptionPB::from_json_str(&old_type_option_data).options;
|
||||
options.iter().for_each(|new_option| {
|
||||
if !shared.options().iter().any(|option| option.name == new_option.name) {
|
||||
shared.mut_options().push(new_option.clone());
|
||||
}
|
||||
})
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let option_pb: SingleSelectTypeOptionPB = serde_json::from_str(_type_option_data.as_str()).unwrap();
|
||||
option_pb.options.iter().for_each(|new_option| {
|
||||
let options = SingleSelectTypeOptionPB::from_json_str(&old_type_option_data).options;
|
||||
options.iter().for_each(|new_option| {
|
||||
if !shared.options().iter().any(|option| option.name == new_option.name) {
|
||||
shared.mut_options().push(new_option.clone());
|
||||
}
|
||||
@ -59,7 +57,6 @@ impl SelectOptionTypeOptionTransformer {
|
||||
shared: &T,
|
||||
cell_data: <T as TypeOption>::CellData,
|
||||
decoded_field_type: &FieldType,
|
||||
_field_rev: &FieldRevision,
|
||||
) -> <T as TypeOption>::CellData
|
||||
where
|
||||
T: SelectTypeOptionSharedAction + TypeOption<CellData = SelectOptionIds>,
|
||||
@ -75,7 +72,6 @@ impl SelectOptionTypeOptionTransformer {
|
||||
transformed_ids.push(option.id.clone());
|
||||
}
|
||||
});
|
||||
|
||||
SelectOptionIds::from(transformed_ids)
|
||||
}
|
||||
_ => SelectOptionIds::from(vec![]),
|
||||
|
@ -6,6 +6,7 @@ use crate::services::cell::{
|
||||
};
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
|
||||
TypeOptionTransform,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use flowy_derive::ProtoBuf;
|
||||
@ -28,9 +29,6 @@ impl TypeOptionBuilder for RichTextTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/// For the moment, the `RichTextTypeOptionPB` is empty. The `data` property is not
|
||||
@ -46,15 +44,17 @@ impl_type_option!(RichTextTypeOptionPB, FieldType::RichText);
|
||||
impl TypeOption for RichTextTypeOptionPB {
|
||||
type CellData = StrCellData;
|
||||
type CellChangeset = String;
|
||||
type CellPBType = StrCellData;
|
||||
type CellProtobufType = StrCellData;
|
||||
}
|
||||
|
||||
impl TypeOptionTransform for RichTextTypeOptionPB {}
|
||||
|
||||
impl TypeOptionConfiguration for RichTextTypeOptionPB {
|
||||
type CellFilterConfiguration = TextFilterPB;
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for RichTextTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
cell_data
|
||||
}
|
||||
|
||||
|
@ -6,20 +6,112 @@ use crate::services::field::{
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use flowy_error::FlowyResult;
|
||||
use grid_rev_model::FieldRevision;
|
||||
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
|
||||
use protobuf::ProtobufError;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait TypeOption {
|
||||
/// `CellData` represents as the decoded model for current type option. Each of them impl the
|
||||
/// `FromCellString` and `Default` trait. If the cell string can not be decoded into the specified
|
||||
/// cell data type then the default value will be returned.
|
||||
/// For example:
|
||||
/// FieldType::Checkbox => CheckboxCellData
|
||||
/// FieldType::Date => DateCellData
|
||||
/// FieldType::URL => URLCellData
|
||||
///
|
||||
/// Uses `StrCellData` for any `TypeOption` if their cell data is pure `String`.
|
||||
///
|
||||
type CellData: FromCellString + Default;
|
||||
|
||||
///
|
||||
type CellChangeset;
|
||||
type CellPBType: TryInto<Bytes, Error = ProtobufError> + Debug;
|
||||
|
||||
/// For the moment, the protobuf type only be used in the FFI of `Dart`. If the decoded cell
|
||||
/// struct is just a `String`, then use the `StrCellData` as its `CellProtobufType`.
|
||||
/// Otherwise, providing a custom protobuf type as its `CellProtobufType`.
|
||||
/// For example:
|
||||
/// FieldType::Date => DateCellDataPB
|
||||
/// FieldType::URL => URLCellDataPB
|
||||
///
|
||||
type CellProtobufType: TryInto<Bytes, Error = ProtobufError> + Debug;
|
||||
}
|
||||
|
||||
pub trait TypeOptionCellData: TypeOption {
|
||||
/// Convert the decoded cell data into corresponding `Protobuf struct`.
|
||||
/// For example:
|
||||
/// FieldType::URL => URLCellDataPB
|
||||
/// FieldType::Date=> DateCellDataPB
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType;
|
||||
|
||||
/// Decodes the opaque cell data to corresponding data struct.
|
||||
// For example, the cell data is timestamp if its field type is `FieldType::Date`. This cell
|
||||
// data can not directly show to user. So it needs to be encode as the date string with custom
|
||||
// format setting. Encode `1647251762` to `"Mar 14,2022`
|
||||
fn decode_type_option_cell_data(&self, cell_data: String) -> FlowyResult<<Self as TypeOption>::CellData>;
|
||||
}
|
||||
|
||||
pub trait TypeOptionConfiguration {
|
||||
type CellFilterConfiguration;
|
||||
}
|
||||
|
||||
pub trait TypeOptionTransform: TypeOption {
|
||||
/// Returns true if the current `TypeOption` provides custom type option transformation
|
||||
fn transformable(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Transform the TypeOption from one field type to another
|
||||
/// For example, when switching from `checkbox` type-option to `single-select`
|
||||
/// type-option, adding the `Yes` option if the `single-select` type-option doesn't contain it.
|
||||
/// But the cell content is a string, `Yes`, it's need to do the cell content transform.
|
||||
/// The `Yes` string will be transformed to the `Yes` option id.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `old_type_option_field_type`: the FieldType of the passed-in TypeOption
|
||||
/// * `old_type_option_data`: the data that can be parsed into corresponding `TypeOption`.
|
||||
///
|
||||
///
|
||||
fn transform_type_option(&mut self, _old_type_option_field_type: FieldType, _old_type_option_data: String) {}
|
||||
|
||||
/// Transform the cell data from one field type to another
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `cell_data`: the cell data of the current field type
|
||||
/// * `decoded_field_type`: the field type of the cell data that's going to be transformed into.
|
||||
///
|
||||
fn transform_type_option_cell_data(
|
||||
&self,
|
||||
cell_data: <Self as TypeOption>::CellData,
|
||||
_decoded_field_type: &FieldType,
|
||||
) -> <Self as TypeOption>::CellData {
|
||||
// Do nothing, just return the passed-in cell data
|
||||
cell_data
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeOptionTransformHandler {
|
||||
fn transform(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String);
|
||||
|
||||
fn json_str(&self) -> String;
|
||||
}
|
||||
|
||||
impl<T> TypeOptionTransformHandler for T
|
||||
where
|
||||
T: TypeOptionTransform + TypeOptionDataSerializer,
|
||||
{
|
||||
fn transform(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String) {
|
||||
if self.transformable() {
|
||||
self.transform_type_option(old_type_option_field_type, old_type_option_data)
|
||||
}
|
||||
}
|
||||
|
||||
fn json_str(&self) -> String {
|
||||
self.json_str()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeOptionCellDataHandler {
|
||||
fn handle_cell_data(
|
||||
&self,
|
||||
@ -31,24 +123,9 @@ pub trait TypeOptionCellDataHandler {
|
||||
fn stringify_cell_data(&self, cell_data: String, field_type: &FieldType, field_rev: &FieldRevision) -> String;
|
||||
}
|
||||
|
||||
pub trait TypeOptionCellData: TypeOption {
|
||||
///
|
||||
/// Convert the decoded cell data into corresponding `Protobuf struct`.
|
||||
/// For example:
|
||||
/// FieldType::URL => URLCellDataPB
|
||||
/// FieldType::Date=> DateCellDataPB
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType;
|
||||
|
||||
/// Decodes the opaque cell data to corresponding data struct.
|
||||
// For example, the cell data is timestamp if its field type is `FieldType::Date`. This cell
|
||||
// data can not directly show to user. So it needs to be encode as the date string with custom
|
||||
// format setting. Encode `1647251762` to `"Mar 14,2022`
|
||||
fn decode_type_option_cell_data(&self, cell_data: String) -> FlowyResult<<Self as TypeOption>::CellData>;
|
||||
}
|
||||
|
||||
impl<T> TypeOptionCellDataHandler for T
|
||||
where
|
||||
T: TypeOption + CellDataDecoder + CellDataChangeset + TypeOptionCellData,
|
||||
T: TypeOption + CellDataDecoder + CellDataChangeset + TypeOptionCellData + TypeOptionTransform,
|
||||
{
|
||||
fn handle_cell_data(
|
||||
&self,
|
||||
@ -56,8 +133,11 @@ where
|
||||
field_type: &FieldType,
|
||||
field_rev: &FieldRevision,
|
||||
) -> FlowyResult<CellProtobufBlob> {
|
||||
let cell_data = self.try_decode_cell_data(cell_data, field_type, field_rev)?;
|
||||
CellProtobufBlob::from(self.convert_into_pb_type(cell_data))
|
||||
let mut cell_data = self.try_decode_cell_data(cell_data, field_type, field_rev)?;
|
||||
if self.transformable() {
|
||||
cell_data = self.transform_type_option_cell_data(cell_data, field_type);
|
||||
}
|
||||
CellProtobufBlob::from(self.convert_to_protobuf(cell_data))
|
||||
}
|
||||
|
||||
fn stringify_cell_data(
|
||||
@ -117,3 +197,48 @@ impl<'a> FieldRevisionExt<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_type_option(
|
||||
type_option_data: &str,
|
||||
new_field_type: &FieldType,
|
||||
old_type_option_data: Option<String>,
|
||||
old_field_type: FieldType,
|
||||
) -> String {
|
||||
let mut transform_handler = get_type_option_transform_handler(type_option_data, new_field_type);
|
||||
if let Some(old_type_option_data) = old_type_option_data {
|
||||
transform_handler.transform(old_field_type, old_type_option_data);
|
||||
}
|
||||
transform_handler.json_str()
|
||||
}
|
||||
|
||||
pub fn get_type_option_transform_handler(
|
||||
type_option_data: &str,
|
||||
field_type: &FieldType,
|
||||
) -> Box<dyn TypeOptionTransformHandler> {
|
||||
match field_type {
|
||||
FieldType::RichText => {
|
||||
Box::new(RichTextTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::Number => {
|
||||
Box::new(NumberTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
Box::new(DateTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
Box::new(SingleSelectTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
Box::new(MultiSelectTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
Box::new(CheckboxTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::URL => {
|
||||
Box::new(URLTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
FieldType::Checklist => {
|
||||
Box::new(ChecklistTypeOptionPB::from_json_str(type_option_data)) as Box<dyn TypeOptionTransformHandler>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ use crate::entities::{FieldType, TextFilterPB};
|
||||
use crate::impl_type_option;
|
||||
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
|
||||
use crate::services::field::{
|
||||
BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration, URLCellData,
|
||||
URLCellDataPB,
|
||||
BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
|
||||
TypeOptionTransform, URLCellData, URLCellDataPB,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use fancy_regex::Regex;
|
||||
@ -26,10 +26,6 @@ impl TypeOptionBuilder for URLTypeOptionBuilder {
|
||||
fn serializer(&self) -> &dyn TypeOptionDataSerializer {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn transform(&mut self, _field_type: &FieldType, _type_option_data: String) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
|
||||
@ -42,15 +38,17 @@ impl_type_option!(URLTypeOptionPB, FieldType::URL);
|
||||
impl TypeOption for URLTypeOptionPB {
|
||||
type CellData = URLCellData;
|
||||
type CellChangeset = URLCellChangeset;
|
||||
type CellPBType = URLCellDataPB;
|
||||
type CellProtobufType = URLCellDataPB;
|
||||
}
|
||||
|
||||
impl TypeOptionTransform for URLTypeOptionPB {}
|
||||
|
||||
impl TypeOptionConfiguration for URLTypeOptionPB {
|
||||
type CellFilterConfiguration = TextFilterPB;
|
||||
}
|
||||
|
||||
impl TypeOptionCellData for URLTypeOptionPB {
|
||||
fn convert_into_pb_type(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellPBType {
|
||||
fn convert_to_protobuf(&self, cell_data: <Self as TypeOption>::CellData) -> <Self as TypeOption>::CellProtobufType {
|
||||
cell_data.into()
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,7 @@ use crate::manager::GridUser;
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use crate::services::cell::{apply_cell_data_changeset, decode_type_cell_data, CellProtobufBlob};
|
||||
use crate::services::field::{
|
||||
default_type_option_builder_from_type, type_option_builder_from_bytes, type_option_builder_from_json_str,
|
||||
FieldBuilder,
|
||||
default_type_option_builder_from_type, transform_type_option, type_option_builder_from_bytes, FieldBuilder,
|
||||
};
|
||||
|
||||
use crate::services::filter::FilterType;
|
||||
@ -280,11 +279,13 @@ impl GridRevisionEditor {
|
||||
let type_option_transform =
|
||||
|old_field_type: FieldTypeRevision, old_type_option: Option<String>, new_type_option: String| {
|
||||
let old_field_type: FieldType = old_field_type.into();
|
||||
let mut type_option_builder = type_option_builder_from_json_str(&new_type_option, new_field_type);
|
||||
if let Some(old_type_option) = old_type_option {
|
||||
type_option_builder.transform(&old_field_type, old_type_option)
|
||||
}
|
||||
type_option_builder.serializer().json_str()
|
||||
// let mut type_option_builder = type_option_builder_from_json_str(&new_type_option, new_field_type);
|
||||
// if let Some(old_type_option) = old_type_option {
|
||||
// type_option_builder.transform(&old_field_type, old_type_option)
|
||||
// }
|
||||
// type_option_builder.serializer().json_str()
|
||||
|
||||
transform_type_option(&new_type_option, new_field_type, old_type_option, old_field_type)
|
||||
};
|
||||
|
||||
let _ = self
|
||||
|
@ -3,6 +3,7 @@ use bytes::Bytes;
|
||||
use indexmap::IndexMap;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn gen_grid_id() -> String {
|
||||
|
Loading…
Reference in New Issue
Block a user