mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
5d7008edd7
commit
4643851b3f
@ -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))
|
||||
// }
|
||||
// }
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user