refactor: apply cell change set (#1589)

* refactor: update cell changeset trait

* refactor: update cell changeset documentation

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Nathan.fooo 2022-12-20 14:40:40 +08:00 committed by GitHub
parent 5d7008edd7
commit 4643851b3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 158 additions and 155 deletions

View File

@ -55,8 +55,8 @@ pub trait CellDataChangeset: TypeOption {
///
fn apply_changeset(
&self,
changeset: AnyCellChangeset<<Self as TypeOption>::CellChangeset>,
cell_rev: Option<CellRevision>,
changeset: <Self as TypeOption>::CellChangeset,
type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String>;
}
@ -73,21 +73,18 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
) -> Result<String, FlowyError> {
let field_rev = field_rev.as_ref();
let changeset = changeset.to_string();
let field_type = field_rev.ty.into();
let s = match field_type {
FieldType::RichText => RichTextTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Number => NumberTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::DateTime => DateTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::SingleSelect => {
SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
}
FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Checklist => ChecklistTypeOptionPB::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),
}?;
let field_type: FieldType = field_rev.ty.into();
Ok(TypeCellData::new(s, field_type).to_json())
let type_cell_data = cell_rev.and_then(|cell_rev| match TypeCellData::try_from(cell_rev) {
Ok(type_cell_data) => Some(type_cell_data),
Err(_) => None,
});
let cell_data = match FieldRevisionExt::new(field_rev).get_type_option_cell_data_handler(&field_type) {
None => "".to_string(),
Some(handler) => handler.handle_cell_changeset(changeset, type_cell_data)?,
};
Ok(TypeCellData::new(cell_data, field_type).to_json())
}
pub fn decode_type_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug>(
@ -138,7 +135,7 @@ pub fn try_decode_cell_data(
to_field_type: &FieldType,
field_rev: &FieldRevision,
) -> FlowyResult<CellProtobufBlob> {
match FieldRevisionExt::new(field_rev).get_type_option_handler(to_field_type) {
match FieldRevisionExt::new(field_rev).get_type_option_cell_data_handler(to_field_type) {
None => Ok(CellProtobufBlob::default()),
Some(handler) => handler.handle_cell_data(cell_data, from_field_type, field_rev),
}
@ -154,7 +151,7 @@ pub fn stringify_cell_data(
to_field_type: &FieldType,
field_rev: &FieldRevision,
) -> String {
match FieldRevisionExt::new(field_rev).get_type_option_handler(to_field_type) {
match FieldRevisionExt::new(field_rev).get_type_option_cell_data_handler(to_field_type) {
None => "".to_string(),
Some(handler) => handler.stringify_cell_data(cell_data, from_field_type, field_rev),
}
@ -269,6 +266,15 @@ pub trait FromCellChangeset {
Self: Sized;
}
impl FromCellChangeset for String {
fn from_changeset(changeset: String) -> FlowyResult<Self>
where
Self: Sized,
{
Ok(changeset)
}
}
pub struct AnyCellChangeset<T>(pub Option<T>);
impl<T> AnyCellChangeset<T> {
@ -294,8 +300,8 @@ where
}
}
}
impl std::convert::From<String> for AnyCellChangeset<String> {
fn from(s: String) -> Self {
AnyCellChangeset(Some(s))
}
}
// impl std::convert::From<String> for AnyCellChangeset<String> {
// fn from(s: String) -> Self {
// AnyCellChangeset(Some(s))
// }
// }

View File

@ -1,14 +1,14 @@
use crate::entities::{CheckboxFilterPB, FieldType};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
use crate::services::cell::{CellDataChangeset, CellDataDecoder, FromCellString, TypeCellData};
use crate::services::field::{
BoxTypeOptionBuilder, CheckboxCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
TypeOptionTransform,
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use flowy_error::FlowyResult;
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
@ -87,10 +87,9 @@ pub type CheckboxCellChangeset = String;
impl CellDataChangeset for CheckboxTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<CheckboxCellChangeset>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let changeset = changeset.try_into_inner()?;
changeset: <Self as TypeOption>::CellChangeset,
_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let cell_data = CheckboxCellData::from_str(&changeset)?;
Ok(cell_data.to_string())
}

View File

@ -147,13 +147,12 @@ mod tests {
expected_str: &str,
field_rev: &FieldRevision,
) {
let s = serde_json::to_string(&DateCellChangeset {
let changeset = DateCellChangeset {
date: Some(timestamp.to_string()),
time: include_time_str,
is_utc: false,
})
.unwrap();
let encoded_data = type_option.apply_changeset(s.into(), None).unwrap();
};
let encoded_data = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!(
decode_cell_data(encoded_data, type_option, field_rev),

View File

@ -1,6 +1,6 @@
use crate::entities::{DateFilterPB, FieldType};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
use crate::services::cell::{CellDataChangeset, CellDataDecoder, FromCellString, TypeCellData};
use crate::services::field::{
BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateCellDataPB, DateFormat, TimeFormat, TypeOption,
TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration, TypeOptionTransform,
@ -10,7 +10,7 @@ use chrono::format::strftime::StrftimeItems;
use chrono::{NaiveDateTime, Timelike};
use flowy_derive::ProtoBuf;
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use serde::{Deserialize, Serialize};
// Date
@ -156,10 +156,9 @@ impl CellDataDecoder for DateTypeOptionPB {
impl CellDataChangeset for DateTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<DateCellChangeset>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let changeset = changeset.try_into_inner()?;
changeset: <Self as TypeOption>::CellChangeset,
_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let cell_data = match changeset.date_timestamp() {
None => 0,
Some(date_timestamp) => match (self.include_time, changeset.time) {

View File

@ -1,6 +1,6 @@
use crate::entities::{FieldType, NumberFilterPB};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellComparable, CellDataChangeset, CellDataDecoder};
use crate::services::cell::{CellComparable, CellDataChangeset, CellDataDecoder, TypeCellData};
use crate::services::field::type_options::number_type_option::format::*;
use crate::services::field::{
BoxTypeOptionBuilder, NumberCellData, StrCellData, TypeOption, TypeOptionBuilder, TypeOptionCellData,
@ -8,8 +8,8 @@ use crate::services::field::{
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use flowy_error::FlowyResult;
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
@ -156,10 +156,9 @@ pub type NumberCellChangeset = String;
impl CellDataChangeset for NumberTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<NumberCellChangeset>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let changeset = changeset.try_into_inner()?;
changeset: <Self as TypeOption>::CellChangeset,
_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let data = changeset.trim().to_string();
let _ = self.format_cell_data(&data)?;
Ok(data)

View File

@ -1,6 +1,6 @@
use crate::entities::{ChecklistFilterPB, FieldType};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
use crate::services::cell::{CellDataChangeset, FromCellString, TypeCellData};
use crate::services::field::{
BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
@ -8,8 +8,8 @@ use crate::services::field::{
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use flowy_error::FlowyResult;
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use serde::{Deserialize, Serialize};
// Multiple select
@ -60,31 +60,26 @@ impl SelectTypeOptionSharedAction for ChecklistTypeOptionPB {
impl CellDataChangeset for ChecklistTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<SelectOptionCellChangeset>,
cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let content_changeset = changeset.try_into_inner()?;
let insert_option_ids = content_changeset
changeset: <Self as TypeOption>::CellChangeset,
type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let insert_option_ids = changeset
.insert_option_ids
.into_iter()
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
.collect::<Vec<String>>();
match cell_rev {
match type_cell_data {
None => Ok(SelectOptionIds::from(insert_option_ids).to_string()),
Some(cell_rev) => {
let cell_data = TypeCellData::try_from(cell_rev)
.map(|data| data.into_inner())
.unwrap_or_default();
let mut select_ids: SelectOptionIds = cell_data.into();
Some(type_cell_data) => {
let mut select_ids: SelectOptionIds = type_cell_data.data.into();
for insert_option_id in insert_option_ids {
if !select_ids.contains(&insert_option_id) {
select_ids.push(insert_option_id);
}
}
for delete_option_id in content_changeset.delete_option_ids {
for delete_option_id in changeset.delete_option_ids {
select_ids.retain(|id| id != &delete_option_id);
}

View File

@ -1,6 +1,6 @@
use crate::entities::{FieldType, SelectOptionFilterPB};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString, TypeCellData};
use crate::services::cell::{CellDataChangeset, FromCellString, TypeCellData};
use crate::services::field::{
BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, SelectOptionPB,
@ -8,8 +8,8 @@ use crate::services::field::{
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use flowy_error::FlowyResult;
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use serde::{Deserialize, Serialize};
// Multiple select
@ -60,34 +60,29 @@ impl SelectTypeOptionSharedAction for MultiSelectTypeOptionPB {
impl CellDataChangeset for MultiSelectTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<SelectOptionCellChangeset>,
cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let content_changeset = changeset.try_into_inner()?;
let insert_option_ids = content_changeset
changeset: <Self as TypeOption>::CellChangeset,
type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let insert_option_ids = changeset
.insert_option_ids
.into_iter()
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
.collect::<Vec<String>>();
let new_cell_data: String;
match cell_rev {
match type_cell_data {
None => {
new_cell_data = SelectOptionIds::from(insert_option_ids).to_string();
}
Some(cell_rev) => {
let cell_data = TypeCellData::try_from(cell_rev)
.map(|data| data.into_inner())
.unwrap_or_default();
let mut select_ids: SelectOptionIds = cell_data.into();
Some(type_cell_data) => {
let mut select_ids: SelectOptionIds = type_cell_data.data.into();
for insert_option_id in insert_option_ids {
if !select_ids.contains(&insert_option_id) {
select_ids.push(insert_option_id);
}
}
for delete_option_id in content_changeset.delete_option_ids {
for delete_option_id in changeset.delete_option_ids {
select_ids.retain(|id| id != &delete_option_id);
}
@ -177,8 +172,8 @@ mod tests {
let field_rev = FieldBuilder::new(multi_select).name("Platform").build();
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
let option_ids = vec![google.id, facebook.id];
let data = SelectOptionCellChangeset::from_insert_options(option_ids.clone()).to_str();
let select_option_ids: SelectOptionIds = type_option.apply_changeset(data.into(), None).unwrap().into();
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().into();
assert_eq!(&*select_option_ids, &option_ids);
}
@ -196,13 +191,13 @@ mod tests {
let option_ids = vec![google.id, facebook.id];
// insert
let data = SelectOptionCellChangeset::from_insert_options(option_ids.clone()).to_str();
let select_option_ids: SelectOptionIds = type_option.apply_changeset(data.into(), None).unwrap().into();
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().into();
assert_eq!(&*select_option_ids, &option_ids);
// delete
let data = SelectOptionCellChangeset::from_delete_options(option_ids).to_str();
let select_option_ids: SelectOptionIds = type_option.apply_changeset(data.into(), None).unwrap().into();
let changeset = SelectOptionCellChangeset::from_delete_options(option_ids);
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().into();
assert!(select_option_ids.is_empty());
}
@ -217,8 +212,8 @@ mod tests {
.build();
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
let data = SelectOptionCellChangeset::from_insert_option_id(&google.id).to_str();
let cell_option_ids = type_option.apply_changeset(data.into(), None).unwrap();
let changeset = SelectOptionCellChangeset::from_insert_option_id(&google.id);
let cell_option_ids = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!(cell_option_ids, google.id);
}
@ -232,8 +227,8 @@ mod tests {
.build();
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
let data = SelectOptionCellChangeset::from_insert_option_id(&google.id).to_str();
let cell_option_ids = type_option.apply_changeset(data.into(), None).unwrap();
let changeset = SelectOptionCellChangeset::from_insert_option_id(&google.id);
let cell_option_ids = type_option.apply_changeset(changeset, None).unwrap();
assert!(cell_option_ids.is_empty());
}
@ -250,22 +245,12 @@ mod tests {
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
// empty option id string
let data = SelectOptionCellChangeset::from_insert_option_id("").to_str();
let cell_option_ids = type_option.apply_changeset(data.into(), None).unwrap();
let changeset = SelectOptionCellChangeset::from_insert_option_id("");
let cell_option_ids = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!(cell_option_ids, "");
let data = SelectOptionCellChangeset::from_insert_option_id("123,456").to_str();
let cell_option_ids = type_option.apply_changeset(data.into(), None).unwrap();
let changeset = SelectOptionCellChangeset::from_insert_option_id("123,456");
let cell_option_ids = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!(cell_option_ids, "");
}
#[test]
fn multi_select_invalid_changeset_data_test() {
let multi_select = MultiSelectTypeOptionBuilder::default();
let field_rev = FieldBuilder::new(multi_select).name("Platform").build();
let type_option = MultiSelectTypeOptionPB::from(&field_rev);
// The type of the changeset should be SelectOptionCellChangeset
assert!(type_option.apply_changeset("123".to_owned().into(), None).is_err());
}
}

View File

@ -1,6 +1,6 @@
use crate::entities::{FieldType, SelectOptionFilterPB};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, FromCellString};
use crate::services::cell::{CellDataChangeset, FromCellString, TypeCellData};
use crate::services::field::{
BoxTypeOptionBuilder, SelectOptionCellDataPB, TypeOption, TypeOptionBuilder, TypeOptionCellData,
@ -11,8 +11,8 @@ use crate::services::field::{
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use flowy_error::FlowyResult;
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use serde::{Deserialize, Serialize};
// Single select
@ -63,12 +63,10 @@ impl SelectTypeOptionSharedAction for SingleSelectTypeOptionPB {
impl CellDataChangeset for SingleSelectTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<SelectOptionCellChangeset>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let content_changeset = changeset.try_into_inner()?;
let mut insert_option_ids = content_changeset
changeset: <Self as TypeOption>::CellChangeset,
_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let mut insert_option_ids = changeset
.insert_option_ids
.into_iter()
.filter(|insert_option_id| self.options.iter().any(|option| &option.id == insert_option_id))
@ -162,8 +160,8 @@ mod tests {
let field_rev = FieldBuilder::new(single_select).name("Platform").build();
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
let option_ids = vec![google.id.clone(), facebook.id];
let data = SelectOptionCellChangeset::from_insert_options(option_ids).to_str();
let select_option_ids: SelectOptionIds = type_option.apply_changeset(data.into(), None).unwrap().into();
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids);
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().into();
assert_eq!(&*select_option_ids, &vec![google.id]);
}
@ -181,13 +179,13 @@ mod tests {
let option_ids = vec![google.id.clone(), facebook.id];
// insert
let data = SelectOptionCellChangeset::from_insert_options(option_ids.clone()).to_str();
let select_option_ids: SelectOptionIds = type_option.apply_changeset(data.into(), None).unwrap().into();
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids.clone());
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().into();
assert_eq!(&*select_option_ids, &vec![google.id]);
// delete
let data = SelectOptionCellChangeset::from_delete_options(option_ids).to_str();
let select_option_ids: SelectOptionIds = type_option.apply_changeset(data.into(), None).unwrap().into();
let changeset = SelectOptionCellChangeset::from_delete_options(option_ids);
let select_option_ids: SelectOptionIds = type_option.apply_changeset(changeset, None).unwrap().into();
assert!(select_option_ids.is_empty());
}
@ -199,8 +197,8 @@ mod tests {
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
let option_ids = vec![google.id];
let data = SelectOptionCellChangeset::from_insert_options(option_ids).to_str();
let cell_option_ids = type_option.apply_changeset(data.into(), None).unwrap();
let changeset = SelectOptionCellChangeset::from_insert_options(option_ids);
let cell_option_ids = type_option.apply_changeset(changeset, None).unwrap();
assert!(cell_option_ids.is_empty());
}
@ -211,18 +209,8 @@ mod tests {
let field_rev = FieldBuilder::new(single_select).name("Platform").build();
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
let data = SelectOptionCellChangeset::from_insert_option_id("").to_str();
let cell_option_ids = type_option.apply_changeset(data.into(), None).unwrap();
let changeset = SelectOptionCellChangeset::from_insert_option_id("");
let cell_option_ids = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!(cell_option_ids, "");
}
#[test]
fn single_select_invalid_changeset_data_test() {
let single_select = SingleSelectTypeOptionBuilder::default();
let field_rev = FieldBuilder::new(single_select).name("Platform").build();
let type_option = SingleSelectTypeOptionPB::from(&field_rev);
// The type of the changeset should be SelectOptionCellChangeset
assert!(type_option.apply_changeset("123".to_owned().into(), None).is_err());
}
}

View File

@ -1,8 +1,8 @@
use crate::entities::{FieldType, TextFilterPB};
use crate::impl_type_option;
use crate::services::cell::{
stringify_cell_data, AnyCellChangeset, CellComparable, CellDataChangeset, CellDataDecoder, CellProtobufBlobParser,
DecodedCellData, FromCellString,
stringify_cell_data, CellComparable, CellDataChangeset, CellDataDecoder, CellProtobufBlobParser, DecodedCellData,
FromCellString, TypeCellData,
};
use crate::services::field::{
BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
@ -11,7 +11,7 @@ use crate::services::field::{
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use protobuf::ProtobufError;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
@ -90,14 +90,13 @@ impl CellDataDecoder for RichTextTypeOptionPB {
impl CellDataChangeset for RichTextTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<String>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let data = changeset.try_into_inner()?;
if data.len() > 10000 {
changeset: <Self as TypeOption>::CellChangeset,
_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
if changeset.len() > 10000 {
Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000"))
} else {
Ok(data)
Ok(changeset)
}
}
}

View File

@ -1,5 +1,7 @@
use crate::entities::FieldType;
use crate::services::cell::{CellDataChangeset, CellDataDecoder, CellProtobufBlob, FromCellString};
use crate::services::cell::{
CellDataChangeset, CellDataDecoder, CellProtobufBlob, FromCellChangeset, FromCellString, TypeCellData,
};
use crate::services::field::{
CheckboxTypeOptionPB, ChecklistTypeOptionPB, DateTypeOptionPB, MultiSelectTypeOptionPB, NumberTypeOptionPB,
RichTextTypeOptionPB, SingleSelectTypeOptionPB, URLTypeOptionPB,
@ -23,8 +25,11 @@ pub trait TypeOption {
///
type CellData: FromCellString + Default;
///
type CellChangeset;
/// Represents as the corresponding field type cell changeset.
/// The changeset must implements the `FromCellChangeset` trait. The `CellChangeset` is implemented
/// for `String`.
///
type CellChangeset: FromCellChangeset;
/// 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`.
@ -92,6 +97,7 @@ pub trait TypeOptionTransform: TypeOption {
}
}
/// A helper trait that used to erase the `Self` of `TypeOption` trait to make it become a Object-safe trait.
pub trait TypeOptionTransformHandler {
fn transform(&mut self, old_type_option_field_type: FieldType, old_type_option_data: String);
@ -113,6 +119,12 @@ where
}
}
/// A helper trait that used to erase the `Self` of `TypeOption` trait to make it become a Object-safe trait
/// Only object-safe traits can be made into trait objects.
/// > Object-safe traits are traits with methods that follow these two rules:
/// 1.the return type is not Self.
/// 2.there are no generic types parameters.
///
pub trait TypeOptionCellDataHandler {
fn handle_cell_data(
&self,
@ -121,6 +133,12 @@ pub trait TypeOptionCellDataHandler {
field_rev: &FieldRevision,
) -> FlowyResult<CellProtobufBlob>;
fn handle_cell_changeset(
&self,
cell_changeset: String,
old_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String>;
fn stringify_cell_data(&self, cell_data: String, field_type: &FieldType, field_rev: &FieldRevision) -> String;
}
@ -145,6 +163,16 @@ where
CellProtobufBlob::from(self.convert_to_protobuf(cell_data))
}
fn handle_cell_changeset(
&self,
cell_changeset: String,
old_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let changeset = <Self as TypeOption>::CellChangeset::from_changeset(cell_changeset)?;
let cell_data = self.apply_changeset(changeset, old_type_cell_data)?;
Ok(cell_data)
}
fn stringify_cell_data(
&self,
cell_data: String,
@ -173,7 +201,10 @@ impl<'a> FieldRevisionExt<'a> {
Self { field_rev }
}
pub fn get_type_option_handler(&self, field_type: &FieldType) -> Option<Box<dyn TypeOptionCellDataHandler>> {
pub fn get_type_option_cell_data_handler(
&self,
field_type: &FieldType,
) -> Option<Box<dyn TypeOptionCellDataHandler>> {
match field_type {
FieldType::RichText => self
.field_rev

View File

@ -170,7 +170,7 @@ mod tests {
field_type: &FieldType,
field_rev: &FieldRevision,
) {
let encoded_data = type_option.apply_changeset(input_str.to_owned().into(), None).unwrap();
let encoded_data = type_option.apply_changeset(input_str.to_owned(), None).unwrap();
let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type);
assert_eq!(expected_str.to_owned(), decode_cell_data.content);
assert_eq!(expected_url.to_owned(), decode_cell_data.url);

View File

@ -1,6 +1,6 @@
use crate::entities::{FieldType, TextFilterPB};
use crate::impl_type_option;
use crate::services::cell::{AnyCellChangeset, CellDataChangeset, CellDataDecoder, FromCellString};
use crate::services::cell::{CellDataChangeset, CellDataDecoder, FromCellString, TypeCellData};
use crate::services::field::{
BoxTypeOptionBuilder, TypeOption, TypeOptionBuilder, TypeOptionCellData, TypeOptionConfiguration,
TypeOptionTransform, URLCellData, URLCellDataPB,
@ -8,8 +8,8 @@ use crate::services::field::{
use bytes::Bytes;
use fancy_regex::Regex;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use flowy_error::FlowyResult;
use grid_rev_model::{FieldRevision, TypeOptionDataDeserializer, TypeOptionDataSerializer};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
@ -81,15 +81,18 @@ pub type URLCellChangeset = String;
impl CellDataChangeset for URLTypeOptionPB {
fn apply_changeset(
&self,
changeset: AnyCellChangeset<URLCellChangeset>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let content = changeset.try_into_inner()?;
changeset: <Self as TypeOption>::CellChangeset,
_type_cell_data: Option<TypeCellData>,
) -> FlowyResult<String> {
let mut url = "".to_string();
if let Ok(Some(m)) = URL_REGEX.find(&content) {
if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
url = auto_append_scheme(m.as_str());
}
URLCellData { url, content }.to_json()
URLCellData {
url,
content: changeset,
}
.to_json()
}
}