refactor: cell data operation

This commit is contained in:
appflowy 2022-07-08 14:54:11 +08:00
parent 4ec1e4024e
commit 5177884b26
17 changed files with 222 additions and 200 deletions

View File

@ -38,7 +38,7 @@ class CellService {
..gridId = gridId ..gridId = gridId
..fieldId = fieldId ..fieldId = fieldId
..rowId = rowId ..rowId = rowId
..cellContentChangeset = data; ..content = data;
return GridEventUpdateCell(payload).send(); return GridEventUpdateCell(payload).send();
} }

View File

@ -134,7 +134,7 @@ pub struct CellChangeset {
pub field_id: String, pub field_id: String,
#[pb(index = 4, one_of)] #[pb(index = 4, one_of)]
pub cell_content_changeset: Option<String>, pub content: Option<String>,
} }
impl std::convert::From<CellChangeset> for RowMetaChangeset { impl std::convert::From<CellChangeset> for RowMetaChangeset {
@ -142,7 +142,7 @@ impl std::convert::From<CellChangeset> for RowMetaChangeset {
let mut cell_by_field_id = HashMap::with_capacity(1); let mut cell_by_field_id = HashMap::with_capacity(1);
let field_id = changeset.field_id; let field_id = changeset.field_id;
let cell_rev = CellRevision { let cell_rev = CellRevision {
data: changeset.cell_content_changeset.unwrap_or_else(|| "".to_owned()), data: changeset.content.unwrap_or_else(|| "".to_owned()),
}; };
cell_by_field_id.insert(field_id, cell_rev); cell_by_field_id.insert(field_id, cell_rev);

View File

@ -323,7 +323,7 @@ pub(crate) async fn update_select_option_handler(
let mut cell_content_changeset = None; let mut cell_content_changeset = None;
if let Some(option) = changeset.insert_option { if let Some(option) = changeset.insert_option {
cell_content_changeset = Some(SelectOptionCellContentChangeset::from_insert(&option.id).to_str()); cell_content_changeset = Some(SelectOptionCellChangeset::from_insert(&option.id).to_str());
type_option.insert_option(option); type_option.insert_option(option);
} }
@ -332,7 +332,7 @@ pub(crate) async fn update_select_option_handler(
} }
if let Some(option) = changeset.delete_option { if let Some(option) = changeset.delete_option {
cell_content_changeset = Some(SelectOptionCellContentChangeset::from_delete(&option.id).to_str()); cell_content_changeset = Some(SelectOptionCellChangeset::from_delete(&option.id).to_str());
type_option.delete_option(option); type_option.delete_option(option);
} }
@ -343,7 +343,7 @@ pub(crate) async fn update_select_option_handler(
grid_id: changeset.cell_identifier.grid_id, grid_id: changeset.cell_identifier.grid_id,
row_id: changeset.cell_identifier.row_id, row_id: changeset.cell_identifier.row_id,
field_id: changeset.cell_identifier.field_id, field_id: changeset.cell_identifier.field_id,
cell_content_changeset, content: cell_content_changeset,
}; };
let _ = editor.update_cell(changeset).await?; let _ = editor.update_cell(changeset).await?;
} }

View File

@ -1,8 +1,8 @@
use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType};
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
use crate::services::row::{AnyCellData, FromCellString}; use crate::services::row::{AnyCellData, FromCellChangeset, FromCellString};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::parser::NotEmptyStr;
use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry};
use nanoid::nanoid; use nanoid::nanoid;
@ -217,7 +217,7 @@ pub struct SelectOptionCellChangesetParams {
impl std::convert::From<SelectOptionCellChangesetParams> for CellChangeset { impl std::convert::From<SelectOptionCellChangesetParams> for CellChangeset {
fn from(params: SelectOptionCellChangesetParams) -> Self { fn from(params: SelectOptionCellChangesetParams) -> Self {
let changeset = SelectOptionCellContentChangeset { let changeset = SelectOptionCellChangeset {
insert_option_id: params.insert_option_id, insert_option_id: params.insert_option_id,
delete_option_id: params.delete_option_id, delete_option_id: params.delete_option_id,
}; };
@ -226,7 +226,7 @@ impl std::convert::From<SelectOptionCellChangesetParams> for CellChangeset {
grid_id: params.cell_identifier.grid_id, grid_id: params.cell_identifier.grid_id,
row_id: params.cell_identifier.row_id, row_id: params.cell_identifier.row_id,
field_id: params.cell_identifier.field_id, field_id: params.cell_identifier.field_id,
cell_content_changeset: Some(s), content: Some(s),
} }
} }
} }
@ -263,21 +263,30 @@ impl TryInto<SelectOptionCellChangesetParams> for SelectOptionCellChangesetPaylo
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct SelectOptionCellContentChangeset { pub struct SelectOptionCellChangeset {
pub insert_option_id: Option<String>, pub insert_option_id: Option<String>,
pub delete_option_id: Option<String>, pub delete_option_id: Option<String>,
} }
impl SelectOptionCellContentChangeset { impl FromCellChangeset for SelectOptionCellChangeset {
fn from_changeset(changeset: String) -> FlowyResult<Self>
where
Self: Sized,
{
serde_json::from_str::<SelectOptionCellChangeset>(&changeset).map_err(internal_error)
}
}
impl SelectOptionCellChangeset {
pub fn from_insert(option_id: &str) -> Self { pub fn from_insert(option_id: &str) -> Self {
SelectOptionCellContentChangeset { SelectOptionCellChangeset {
insert_option_id: Some(option_id.to_string()), insert_option_id: Some(option_id.to_string()),
delete_option_id: None, delete_option_id: None,
} }
} }
pub fn from_delete(option_id: &str) -> Self { pub fn from_delete(option_id: &str) -> Self {
SelectOptionCellContentChangeset { SelectOptionCellChangeset {
insert_option_id: None, insert_option_id: None,
delete_option_id: Some(option_id.to_string()), delete_option_id: Some(option_id.to_string()),
} }

View File

@ -2,7 +2,8 @@ use crate::entities::{FieldType, GridCheckboxFilter};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation,
DecodedCellData,
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
@ -52,7 +53,7 @@ impl CellFilterOperation<GridCheckboxFilter> for CheckboxTypeOption {
} }
} }
impl CellDataOperation<String> for CheckboxTypeOption { impl CellDataOperation<String, String> for CheckboxTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<String>, cell_data: CellData<String>,
@ -71,11 +72,12 @@ impl CellDataOperation<String> for CheckboxTypeOption {
Ok(DecodedCellData::default()) Ok(DecodedCellData::default())
} }
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(
where &self,
C: Into<CellContentChangeset>, changeset: CellDataChangeset<String>,
{ _cell_rev: Option<CellRevision>,
let changeset = changeset.into(); ) -> Result<String, FlowyError> {
let changeset = changeset.try_into_inner()?;
let s = match string_to_bool(&changeset) { let s = match string_to_bool(&changeset) {
true => YES, true => YES,
false => NO, false => NO,

View File

@ -3,14 +3,14 @@ use crate::entities::{CellIdentifier, CellIdentifierPayload};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
FromCellString, FromCellChangeset, FromCellString,
}; };
use bytes::Bytes; use bytes::Bytes;
use chrono::format::strftime::StrftimeItems; use chrono::format::strftime::StrftimeItems;
use chrono::{NaiveDateTime, Timelike}; use chrono::{NaiveDateTime, Timelike};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum_macros::EnumIter; use strum_macros::EnumIter;
@ -127,7 +127,7 @@ impl CellFilterOperation<GridDateFilter> for DateTypeOption {
} }
} }
impl CellDataOperation<TimestampParser> for DateTypeOption { impl CellDataOperation<TimestampParser, DateCellChangeset> for DateTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<TimestampParser>, cell_data: CellData<TimestampParser>,
@ -146,14 +146,15 @@ impl CellDataOperation<TimestampParser> for DateTypeOption {
DecodedCellData::try_from_bytes(date) DecodedCellData::try_from_bytes(date)
} }
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(
where &self,
C: Into<CellContentChangeset>, changeset: CellDataChangeset<DateCellChangeset>,
{ _cell_rev: Option<CellRevision>,
let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?; ) -> Result<String, FlowyError> {
let cell_data = match content_changeset.date_timestamp() { let changeset = changeset.try_into_inner()?;
let cell_data = match changeset.date_timestamp() {
None => 0, None => 0,
Some(date_timestamp) => match (self.include_time, content_changeset.time) { Some(date_timestamp) => match (self.include_time, changeset.time) {
(true, Some(time)) => { (true, Some(time)) => {
let time = Some(time.trim().to_uppercase()); let time = Some(time.trim().to_uppercase());
let utc = self.utc_date_time_from_timestamp(date_timestamp); let utc = self.utc_date_time_from_timestamp(date_timestamp);
@ -331,7 +332,7 @@ impl TryInto<DateChangesetParams> for DateChangesetPayload {
impl std::convert::From<DateChangesetParams> for CellChangeset { impl std::convert::From<DateChangesetParams> for CellChangeset {
fn from(params: DateChangesetParams) -> Self { fn from(params: DateChangesetParams) -> Self {
let changeset = DateCellContentChangeset { let changeset = DateCellChangeset {
date: params.date, date: params.date,
time: params.time, time: params.time,
}; };
@ -340,18 +341,18 @@ impl std::convert::From<DateChangesetParams> for CellChangeset {
grid_id: params.cell_identifier.grid_id, grid_id: params.cell_identifier.grid_id,
row_id: params.cell_identifier.row_id, row_id: params.cell_identifier.row_id,
field_id: params.cell_identifier.field_id, field_id: params.cell_identifier.field_id,
cell_content_changeset: Some(s), content: Some(s),
} }
} }
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct DateCellContentChangeset { pub struct DateCellChangeset {
pub date: Option<String>, pub date: Option<String>,
pub time: Option<String>, pub time: Option<String>,
} }
impl DateCellContentChangeset { impl DateCellChangeset {
pub fn date_timestamp(&self) -> Option<i64> { pub fn date_timestamp(&self) -> Option<i64> {
if let Some(date) = &self.date { if let Some(date) = &self.date {
match date.parse::<i64>() { match date.parse::<i64>() {
@ -364,10 +365,12 @@ impl DateCellContentChangeset {
} }
} }
impl std::convert::From<DateCellContentChangeset> for CellContentChangeset { impl FromCellChangeset for DateCellChangeset {
fn from(changeset: DateCellContentChangeset) -> Self { fn from_changeset(changeset: String) -> FlowyResult<Self>
let s = serde_json::to_string(&changeset).unwrap(); where
CellContentChangeset::from(s) Self: Sized,
{
serde_json::from_str::<DateCellChangeset>(&changeset).map_err(internal_error)
} }
} }
@ -375,8 +378,8 @@ impl std::convert::From<DateCellContentChangeset> for CellContentChangeset {
mod tests { mod tests {
use crate::entities::FieldType; use crate::entities::FieldType;
use crate::services::field::FieldBuilder; use crate::services::field::FieldBuilder;
use crate::services::field::{DateCellContentChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
use crate::services::row::CellDataOperation; use crate::services::row::{CellDataChangeset, CellDataOperation};
use flowy_grid_data_model::revision::FieldRevision; use flowy_grid_data_model::revision::FieldRevision;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -387,7 +390,7 @@ mod tests {
let field_rev = FieldBuilder::from_field_type(&field_type).build(); let field_rev = FieldBuilder::from_field_type(&field_type).build();
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some("1e".to_string()), date: Some("1e".to_string()),
time: Some("23:00".to_owned()), time: Some("23:00".to_owned()),
}, },
@ -433,7 +436,7 @@ mod tests {
TimeFormat::TwentyFourHour => { TimeFormat::TwentyFourHour => {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
time: None, time: None,
}, },
@ -443,7 +446,7 @@ mod tests {
); );
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
time: Some("23:00".to_owned()), time: Some("23:00".to_owned()),
}, },
@ -455,7 +458,7 @@ mod tests {
TimeFormat::TwelveHour => { TimeFormat::TwelveHour => {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
time: None, time: None,
}, },
@ -466,7 +469,7 @@ mod tests {
// //
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
time: Some("".to_owned()), time: Some("".to_owned()),
}, },
@ -477,7 +480,7 @@ mod tests {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(1653609600.to_string()), date: Some(1653609600.to_string()),
time: Some("11:23 pm".to_owned()), time: Some("11:23 pm".to_owned()),
}, },
@ -499,7 +502,7 @@ mod tests {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
time: None, time: None,
}, },
@ -511,7 +514,7 @@ mod tests {
type_option.include_time = true; type_option.include_time = true;
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
time: None, time: None,
}, },
@ -522,7 +525,7 @@ mod tests {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
time: Some("1:00".to_owned()), time: Some("1:00".to_owned()),
}, },
@ -534,7 +537,7 @@ mod tests {
type_option.time_format = TimeFormat::TwelveHour; type_option.time_format = TimeFormat::TwelveHour;
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp), date: Some(date_timestamp),
time: Some("1:00 am".to_owned()), time: Some("1:00 am".to_owned()),
}, },
@ -554,7 +557,7 @@ mod tests {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp.clone()), date: Some(date_timestamp.clone()),
time: Some("1:".to_owned()), time: Some("1:".to_owned()),
}, },
@ -565,7 +568,7 @@ mod tests {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp), date: Some(date_timestamp),
time: Some("1:00".to_owned()), time: Some("1:00".to_owned()),
}, },
@ -585,7 +588,7 @@ mod tests {
assert_changeset_result( assert_changeset_result(
&type_option, &type_option,
DateCellContentChangeset { DateCellChangeset {
date: Some(date_timestamp), date: Some(date_timestamp),
time: Some("1:00 am".to_owned()), time: Some("1:00 am".to_owned()),
}, },
@ -597,11 +600,12 @@ mod tests {
fn assert_changeset_result( fn assert_changeset_result(
type_option: &DateTypeOption, type_option: &DateTypeOption,
changeset: DateCellContentChangeset, changeset: DateCellChangeset,
_field_type: &FieldType, _field_type: &FieldType,
field_rev: &FieldRevision, field_rev: &FieldRevision,
expected: &str, expected: &str,
) { ) {
let changeset = CellDataChangeset(Some(changeset));
let encoded_data = type_option.apply_changeset(changeset, None).unwrap(); let encoded_data = type_option.apply_changeset(changeset, None).unwrap();
assert_eq!( assert_eq!(
expected.to_owned(), expected.to_owned(),
@ -615,15 +619,12 @@ mod tests {
field_rev: &FieldRevision, field_rev: &FieldRevision,
expected: &str, expected: &str,
) { ) {
let encoded_data = type_option let s = serde_json::to_string(&DateCellChangeset {
.apply_changeset( date: Some(timestamp.to_string()),
DateCellContentChangeset { time: None,
date: Some(timestamp.to_string()), })
time: None, .unwrap();
}, let encoded_data = type_option.apply_changeset(s.into(), None).unwrap();
None,
)
.unwrap();
assert_eq!( assert_eq!(
expected.to_owned(), expected.to_owned(),
@ -631,13 +632,9 @@ mod tests {
); );
} }
fn decode_cell_data<T: Into<String>>( fn decode_cell_data(encoded_data: String, type_option: &DateTypeOption, field_rev: &FieldRevision) -> String {
encoded_data: T,
type_option: &DateTypeOption,
field_rev: &FieldRevision,
) -> String {
let decoded_data = type_option let decoded_data = type_option
.decode_cell_data(encoded_data, &FieldType::DateTime, field_rev) .decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev)
.unwrap() .unwrap()
.parse::<DateCellData>() .parse::<DateCellData>()
.unwrap(); .unwrap();

View File

@ -2,13 +2,13 @@ use crate::entities::{FieldType, GridSelectOptionFilter};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::select_option::{ use crate::services::field::select_option::{
make_selected_select_options, SelectOption, SelectOptionCellContentChangeset, SelectOptionCellData, make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds,
SelectOptionIds, SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR, SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR,
}; };
use crate::services::field::type_options::util::get_cell_data; use crate::services::field::type_options::util::get_cell_data;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
@ -56,7 +56,7 @@ impl CellFilterOperation<GridSelectOptionFilter> for MultiSelectTypeOption {
Ok(filter.apply(&selected_options)) Ok(filter.apply(&selected_options))
} }
} }
impl CellDataOperation<SelectOptionIds> for MultiSelectTypeOption { impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for MultiSelectTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<SelectOptionIds>, cell_data: CellData<SelectOptionIds>,
@ -81,11 +81,12 @@ impl CellDataOperation<SelectOptionIds> for MultiSelectTypeOption {
DecodedCellData::try_from_bytes(cell_data) DecodedCellData::try_from_bytes(cell_data)
} }
fn apply_changeset<T>(&self, changeset: T, cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(
where &self,
T: Into<CellContentChangeset>, changeset: CellDataChangeset<SelectOptionCellChangeset>,
{ cell_rev: Option<CellRevision>,
let content_changeset: SelectOptionCellContentChangeset = serde_json::from_str(&changeset.into())?; ) -> Result<String, FlowyError> {
let content_changeset = changeset.try_into_inner()?;
let new_cell_data: String; let new_cell_data: String;
match cell_rev { match cell_rev {
None => { None => {
@ -164,8 +165,8 @@ mod tests {
let type_option = MultiSelectTypeOption::from(&field_rev); let type_option = MultiSelectTypeOption::from(&field_rev);
let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data.into(), None).unwrap();
assert_multi_select_options( assert_multi_select_options(
cell_data, cell_data,
&type_option, &type_option,
@ -173,24 +174,24 @@ mod tests {
vec![google_option.clone(), facebook_option], vec![google_option.clone(), facebook_option],
); );
let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); let data = SelectOptionCellChangeset::from_insert(&google_option.id).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data.into(), None).unwrap();
assert_multi_select_options(cell_data, &type_option, &field_rev, vec![google_option]); assert_multi_select_options(cell_data, &type_option, &field_rev, vec![google_option]);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) .apply_changeset(SelectOptionCellChangeset::from_insert("").to_str().into(), None)
.unwrap(); .unwrap();
assert_multi_select_options(cell_data, &type_option, &field_rev, vec![]); assert_multi_select_options(cell_data, &type_option, &field_rev, vec![]);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("123,456").to_str(), None) .apply_changeset(SelectOptionCellChangeset::from_insert("123,456").to_str().into(), None)
.unwrap(); .unwrap();
assert_multi_select_options(cell_data, &type_option, &field_rev, vec![]); assert_multi_select_options(cell_data, &type_option, &field_rev, vec![]);
// Invalid changeset // Invalid changeset
assert!(type_option.apply_changeset("123", None).is_err()); assert!(type_option.apply_changeset("123".to_owned().into(), None).is_err());
} }
fn assert_multi_select_options( fn assert_multi_select_options(
@ -203,7 +204,7 @@ mod tests {
assert_eq!( assert_eq!(
expected, expected,
type_option type_option
.decode_cell_data(cell_data, &field_type, field_rev) .decode_cell_data(cell_data.into(), &field_type, field_rev)
.unwrap() .unwrap()
.parse::<SelectOptionCellData>() .parse::<SelectOptionCellData>()
.unwrap() .unwrap()

View File

@ -5,7 +5,7 @@ use crate::services::field::number_currency::Currency;
use crate::services::field::type_options::number_type_option::format::*; use crate::services::field::type_options::number_type_option::format::*;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
@ -118,7 +118,7 @@ impl CellFilterOperation<GridNumberFilter> for NumberTypeOption {
} }
} }
impl CellDataOperation<String> for NumberTypeOption { impl CellDataOperation<String, String> for NumberTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<String>, cell_data: CellData<String>,
@ -136,11 +136,9 @@ impl CellDataOperation<String> for NumberTypeOption {
} }
} }
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(&self, changeset: CellDataChangeset<String>, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
where
C: Into<CellContentChangeset>,
{ {
let changeset = changeset.into(); let changeset = changeset.try_into_inner()?;
let data = changeset.trim().to_string(); let data = changeset.trim().to_string();
let _ = self.format_cell_data(&data)?; let _ = self.format_cell_data(&data)?;
Ok(data) Ok(data)
@ -380,7 +378,7 @@ mod tests {
) { ) {
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_data(cell_data, field_type, field_rev) .decode_cell_data(cell_data.to_owned().into(), field_type, field_rev)
.unwrap() .unwrap()
.to_string(), .to_string(),
expected_str.to_owned() expected_str.to_owned()

View File

@ -1,12 +1,12 @@
use crate::entities::{FieldType, GridSelectOptionFilter}; use crate::entities::{FieldType, GridSelectOptionFilter};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::select_option::{ use crate::services::field::select_option::{
make_selected_select_options, SelectOption, SelectOptionCellContentChangeset, SelectOptionCellData, make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds,
SelectOptionIds, SelectOptionOperation, SelectOptionOperation,
}; };
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
@ -53,7 +53,7 @@ impl CellFilterOperation<GridSelectOptionFilter> for SingleSelectTypeOption {
} }
} }
impl CellDataOperation<SelectOptionIds> for SingleSelectTypeOption { impl CellDataOperation<SelectOptionIds, SelectOptionCellChangeset> for SingleSelectTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<SelectOptionIds>, cell_data: CellData<SelectOptionIds>,
@ -78,12 +78,12 @@ impl CellDataOperation<SelectOptionIds> for SingleSelectTypeOption {
DecodedCellData::try_from_bytes(cell_data) DecodedCellData::try_from_bytes(cell_data)
} }
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(
where &self,
C: Into<CellContentChangeset>, changeset: CellDataChangeset<SelectOptionCellChangeset>,
{ _cell_rev: Option<CellRevision>,
let changeset = changeset.into(); ) -> Result<String, FlowyError> {
let select_option_changeset: SelectOptionCellContentChangeset = serde_json::from_str(&changeset)?; let select_option_changeset = changeset.try_into_inner()?;
let new_cell_data: String; let new_cell_data: String;
if let Some(insert_option_id) = select_option_changeset.insert_option_id { if let Some(insert_option_id) = select_option_changeset.insert_option_id {
tracing::trace!("Insert single select option: {}", &insert_option_id); tracing::trace!("Insert single select option: {}", &insert_option_id);
@ -146,29 +146,29 @@ mod tests {
let type_option = SingleSelectTypeOption::from(&field_rev); let type_option = SingleSelectTypeOption::from(&field_rev);
let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR); let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR);
let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data.into(), None).unwrap();
assert_single_select_options(cell_data, &type_option, &field_rev, vec![google_option.clone()]); assert_single_select_options(cell_data, &type_option, &field_rev, vec![google_option.clone()]);
let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); let data = SelectOptionCellChangeset::from_insert(&google_option.id).to_str();
let cell_data = type_option.apply_changeset(data, None).unwrap(); let cell_data = type_option.apply_changeset(data.into(), None).unwrap();
assert_single_select_options(cell_data, &type_option, &field_rev, vec![google_option]); assert_single_select_options(cell_data, &type_option, &field_rev, vec![google_option]);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) .apply_changeset(SelectOptionCellChangeset::from_insert("").to_str().into(), None)
.unwrap(); .unwrap();
assert_single_select_options(cell_data, &type_option, &field_rev, vec![]); assert_single_select_options(cell_data, &type_option, &field_rev, vec![]);
// Invalid option id // Invalid option id
let cell_data = type_option let cell_data = type_option
.apply_changeset(SelectOptionCellContentChangeset::from_insert("123").to_str(), None) .apply_changeset(SelectOptionCellChangeset::from_insert("123").to_str().into(), None)
.unwrap(); .unwrap();
assert_single_select_options(cell_data, &type_option, &field_rev, vec![]); assert_single_select_options(cell_data, &type_option, &field_rev, vec![]);
// Invalid changeset // Invalid changeset
assert!(type_option.apply_changeset("123", None).is_err()); assert!(type_option.apply_changeset("123".to_owned().into(), None).is_err());
} }
fn assert_single_select_options( fn assert_single_select_options(
@ -181,7 +181,7 @@ mod tests {
assert_eq!( assert_eq!(
expected, expected,
type_option type_option
.decode_cell_data(cell_data, &field_type, field_rev) .decode_cell_data(cell_data.into(), &field_type, field_rev)
.unwrap() .unwrap()
.parse::<SelectOptionCellData>() .parse::<SelectOptionCellData>()
.unwrap() .unwrap()

View File

@ -2,7 +2,7 @@ use crate::entities::{FieldType, GridTextFilter};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
try_decode_cell_data, AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation,
DecodedCellData, DecodedCellData,
}; };
use bytes::Bytes; use bytes::Bytes;
@ -44,7 +44,7 @@ impl CellFilterOperation<GridTextFilter> for RichTextTypeOption {
} }
} }
impl CellDataOperation<String> for RichTextTypeOption { impl CellDataOperation<String, String> for RichTextTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<String>, cell_data: CellData<String>,
@ -56,22 +56,23 @@ impl CellDataOperation<String> for RichTextTypeOption {
|| decoded_field_type.is_multi_select() || decoded_field_type.is_multi_select()
|| decoded_field_type.is_number() || decoded_field_type.is_number()
{ {
try_decode_cell_data(cell_data.into(), field_rev, decoded_field_type, decoded_field_type) try_decode_cell_data(cell_data, field_rev, decoded_field_type, decoded_field_type)
} else { } else {
let cell_data: String = cell_data.try_into_inner()?; let cell_data: String = cell_data.try_into_inner()?;
Ok(DecodedCellData::new(cell_data)) Ok(DecodedCellData::new(cell_data))
} }
} }
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(
where &self,
C: Into<CellContentChangeset>, changeset: CellDataChangeset<String>,
{ _cell_rev: Option<CellRevision>,
let data = changeset.into(); ) -> Result<String, FlowyError> {
let data = changeset.try_into_inner()?;
if data.len() > 10000 { if data.len() > 10000 {
Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000")) Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000"))
} else { } else {
Ok(data.0) Ok(data)
} }
} }
} }
@ -109,7 +110,7 @@ mod tests {
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_data(1647251762.to_string(), &field_type, &date_time_field_rev) .decode_cell_data(1647251762.to_string().into(), &field_type, &date_time_field_rev)
.unwrap() .unwrap()
.parse::<DateCellData>() .parse::<DateCellData>()
.unwrap() .unwrap()
@ -125,7 +126,11 @@ mod tests {
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_data(done_option_id, &FieldType::SingleSelect, &single_select_field_rev) .decode_cell_data(
done_option_id.into(),
&FieldType::SingleSelect,
&single_select_field_rev
)
.unwrap() .unwrap()
.parse::<SelectOptionCellData>() .parse::<SelectOptionCellData>()
.unwrap() .unwrap()
@ -137,16 +142,18 @@ mod tests {
let google_option = SelectOption::new("Google"); let google_option = SelectOption::new("Google");
let facebook_option = SelectOption::new("Facebook"); let facebook_option = SelectOption::new("Facebook");
let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
let cell_data_changeset = SelectOptionCellContentChangeset::from_insert(&ids).to_str(); let cell_data_changeset = SelectOptionCellChangeset::from_insert(&ids).to_str();
let multi_select = MultiSelectTypeOptionBuilder::default() let multi_select = MultiSelectTypeOptionBuilder::default()
.option(google_option.clone()) .option(google_option.clone())
.option(facebook_option.clone()); .option(facebook_option.clone());
let multi_select_field_rev = FieldBuilder::new(multi_select).build(); let multi_select_field_rev = FieldBuilder::new(multi_select).build();
let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_rev); let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_rev);
let cell_data = multi_type_option.apply_changeset(cell_data_changeset, None).unwrap(); let cell_data = multi_type_option
.apply_changeset(cell_data_changeset.into(), None)
.unwrap();
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_data(cell_data, &FieldType::MultiSelect, &multi_select_field_rev) .decode_cell_data(cell_data.into(), &FieldType::MultiSelect, &multi_select_field_rev)
.unwrap() .unwrap()
.parse::<SelectOptionCellData>() .parse::<SelectOptionCellData>()
.unwrap() .unwrap()
@ -159,7 +166,7 @@ mod tests {
let number_field_rev = FieldBuilder::new(number).build(); let number_field_rev = FieldBuilder::new(number).build();
assert_eq!( assert_eq!(
type_option type_option
.decode_cell_data("18443".to_owned(), &FieldType::Number, &number_field_rev) .decode_cell_data("18443".to_owned().into(), &FieldType::Number, &number_field_rev)
.unwrap() .unwrap()
.to_string(), .to_string(),
"$18,443".to_owned() "$18,443".to_owned()

View File

@ -2,8 +2,7 @@ use crate::entities::{FieldType, GridTextFilter};
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder};
use crate::services::row::{ use crate::services::row::{
AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, FromCellString,
FromCellString,
}; };
use bytes::Bytes; use bytes::Bytes;
use fancy_regex::Regex; use fancy_regex::Regex;
@ -46,7 +45,7 @@ impl CellFilterOperation<GridTextFilter> for URLTypeOption {
} }
} }
impl CellDataOperation<URLCellData> for URLTypeOption { impl CellDataOperation<URLCellData, String> for URLTypeOption {
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<URLCellData>, cell_data: CellData<URLCellData>,
@ -60,18 +59,16 @@ impl CellDataOperation<URLCellData> for URLTypeOption {
DecodedCellData::try_from_bytes(cell_data) DecodedCellData::try_from_bytes(cell_data)
} }
fn apply_changeset<C>(&self, changeset: C, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError> fn apply_changeset(&self, changeset: CellDataChangeset<String>, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
where
C: Into<CellContentChangeset>,
{ {
let changeset = changeset.into(); let changeset = changeset.try_into_inner()?;
let mut url = "".to_string(); let mut url = "".to_string();
if let Ok(Some(m)) = URL_REGEX.find(&changeset) { if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
url = auto_append_scheme(m.as_str()); url = auto_append_scheme(m.as_str());
} }
URLCellData { URLCellData {
url, url,
content: changeset.to_string(), content: changeset,
} }
.to_json() .to_json()
} }
@ -190,7 +187,7 @@ mod tests {
expected: &str, expected: &str,
expected_url: &str, expected_url: &str,
) { ) {
let encoded_data = type_option.apply_changeset(cell_data, None).unwrap(); let encoded_data = type_option.apply_changeset(cell_data.to_owned().into(), None).unwrap();
let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type); let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type);
assert_eq!(expected.to_owned(), decode_cell_data.content); assert_eq!(expected.to_owned(), decode_cell_data.content);
assert_eq!(expected_url.to_owned(), decode_cell_data.url); assert_eq!(expected_url.to_owned(), decode_cell_data.url);
@ -203,7 +200,7 @@ mod tests {
field_type: &FieldType, field_type: &FieldType,
) -> URLCellData { ) -> URLCellData {
type_option type_option
.decode_cell_data(encoded_data, field_type, field_rev) .decode_cell_data(encoded_data.into(), field_type, field_rev)
.unwrap() .unwrap()
.parse::<URLCellData>() .parse::<URLCellData>()
.unwrap() .unwrap()

View File

@ -369,7 +369,7 @@ impl GridRevisionEditor {
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
pub async fn update_cell(&self, cell_changeset: CellChangeset) -> FlowyResult<()> { pub async fn update_cell(&self, cell_changeset: CellChangeset) -> FlowyResult<()> {
if cell_changeset.cell_content_changeset.as_ref().is_none() { if cell_changeset.content.as_ref().is_none() {
return Ok(()); return Ok(());
} }
@ -377,7 +377,7 @@ impl GridRevisionEditor {
grid_id, grid_id,
row_id, row_id,
field_id, field_id,
mut cell_content_changeset, mut content,
} = cell_changeset; } = cell_changeset;
match self.grid_pad.read().await.get_field_rev(&field_id) { match self.grid_pad.read().await.get_field_rev(&field_id) {
@ -386,21 +386,17 @@ impl GridRevisionEditor {
Err(FlowyError::internal().context(msg)) Err(FlowyError::internal().context(msg))
} }
Some((_, field_rev)) => { Some((_, field_rev)) => {
tracing::trace!("field changeset: id:{} / value:{:?}", &field_id, cell_content_changeset); tracing::trace!("field changeset: id:{} / value:{:?}", &field_id, content);
let cell_rev = self.get_cell_rev(&row_id, &field_id).await?; let cell_rev = self.get_cell_rev(&row_id, &field_id).await?;
// Update the changeset.data property with the return value. // Update the changeset.data property with the return value.
cell_content_changeset = Some(apply_cell_data_changeset( content = Some(apply_cell_data_changeset(content.unwrap(), cell_rev, field_rev)?);
cell_content_changeset.unwrap(),
cell_rev,
field_rev,
)?);
let field_revs = self.get_field_revs(None).await?; let field_revs = self.get_field_revs(None).await?;
let cell_changeset = CellChangeset { let cell_changeset = CellChangeset {
grid_id, grid_id,
row_id, row_id,
field_id, field_id,
cell_content_changeset, content,
}; };
let _ = self let _ = self
.block_manager .block_manager

View File

@ -4,16 +4,17 @@ use bytes::Bytes;
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Formatter;
use std::str::FromStr; use std::str::FromStr;
pub trait CellFilterOperation<T> { pub trait CellFilterOperation<T> {
fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>; fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>;
} }
pub trait CellDataOperation<D> { pub trait CellDataOperation<D, C> {
/// The cell_data is able to parse into the specific data that was impl the From<String> trait. /// The cell_data is able to parse into the specific data that was impl the FromCellData trait.
/// D will be URLCellData, DateCellData. etc. /// For example:
/// URLCellData, DateCellData. etc.
fn decode_cell_data( fn decode_cell_data(
&self, &self,
cell_data: CellData<D>, cell_data: CellData<D>,
@ -21,35 +22,10 @@ pub trait CellDataOperation<D> {
field_rev: &FieldRevision, field_rev: &FieldRevision,
) -> FlowyResult<DecodedCellData>; ) -> FlowyResult<DecodedCellData>;
fn apply_changeset<C: Into<CellContentChangeset>>( /// The changeset is able to parse into the specific data that was impl the FromCellChangeset trait.
&self, /// For example:
changeset: C, /// SelectOptionCellChangeset,DateCellChangeset. etc.
cell_rev: Option<CellRevision>, fn apply_changeset(&self, changeset: CellDataChangeset<C>, cell_rev: Option<CellRevision>) -> FlowyResult<String>;
) -> FlowyResult<String>;
}
#[derive(Debug)]
pub struct CellContentChangeset(pub String);
impl std::fmt::Display for CellContentChangeset {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0)
}
}
impl<T: AsRef<str>> std::convert::From<T> for CellContentChangeset {
fn from(s: T) -> Self {
let s = s.as_ref().to_owned();
CellContentChangeset(s)
}
}
impl std::ops::Deref for CellContentChangeset {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.0
}
} }
/// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type. /// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type.
@ -152,21 +128,22 @@ impl AnyCellData {
/// The changeset will be deserialized into specific data base on the FieldType. /// The changeset will be deserialized into specific data base on the FieldType.
/// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect /// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect
pub fn apply_cell_data_changeset<C: Into<CellContentChangeset>, T: AsRef<FieldRevision>>( pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
changeset: C, changeset: C,
cell_rev: Option<CellRevision>, cell_rev: Option<CellRevision>,
field_rev: T, field_rev: T,
) -> Result<String, FlowyError> { ) -> Result<String, FlowyError> {
let field_rev = field_rev.as_ref(); let field_rev = field_rev.as_ref();
let changeset = changeset.to_string();
let field_type = field_rev.field_type_rev.into(); let field_type = field_rev.field_type_rev.into();
let s = match field_type { let s = match field_type {
FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::SingleSelect => SingleSelectTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::SingleSelect => SingleSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev),
}?; }?;
Ok(AnyCellData::new(s, field_type).json()) Ok(AnyCellData::new(s, field_type).json())
@ -274,7 +251,45 @@ impl std::convert::From<String> for CellData<String> {
impl std::convert::From<CellData<String>> for String { impl std::convert::From<CellData<String>> for String {
fn from(p: CellData<String>) -> Self { fn from(p: CellData<String>) -> Self {
p.try_into_inner().unwrap_or("".to_owned()) p.try_into_inner().unwrap_or_else(|_| String::new())
}
}
// CellChangeset
pub trait FromCellChangeset {
fn from_changeset(changeset: String) -> FlowyResult<Self>
where
Self: Sized;
}
pub struct CellDataChangeset<T>(pub Option<T>);
impl<T> CellDataChangeset<T> {
pub fn try_into_inner(self) -> FlowyResult<T> {
match self.0 {
None => Err(ErrorCode::InvalidData.into()),
Some(data) => Ok(data),
}
}
}
impl<T, C: ToString> std::convert::From<C> for CellDataChangeset<T>
where
T: FromCellChangeset,
{
fn from(changeset: C) -> Self {
match T::from_changeset(changeset.to_string()) {
Ok(data) => CellDataChangeset(Some(data)),
Err(e) => {
tracing::error!("Deserialize CellDataChangeset failed: {}", e);
CellDataChangeset(None)
}
}
}
}
impl std::convert::From<String> for CellDataChangeset<String> {
fn from(s: String) -> Self {
CellDataChangeset(Some(s))
} }
} }

View File

@ -1,4 +1,4 @@
use crate::services::field::select_option::SelectOptionCellContentChangeset; use crate::services::field::select_option::SelectOptionCellChangeset;
use crate::services::row::apply_cell_data_changeset; use crate::services::row::apply_cell_data_changeset;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT}; use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
@ -35,7 +35,7 @@ impl<'a> CreateRowRevisionBuilder<'a> {
Err(FlowyError::internal().context(msg)) Err(FlowyError::internal().context(msg))
} }
Some(field_rev) => { Some(field_rev) => {
let data = apply_cell_data_changeset(&data, None, field_rev)?; let data = apply_cell_data_changeset(data, None, field_rev)?;
let cell = CellRevision::new(data); let cell = CellRevision::new(data);
self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
Ok(()) Ok(())
@ -50,8 +50,8 @@ impl<'a> CreateRowRevisionBuilder<'a> {
Err(FlowyError::internal().context(msg)) Err(FlowyError::internal().context(msg))
} }
Some(field_rev) => { Some(field_rev) => {
let cell_data = SelectOptionCellContentChangeset::from_insert(&data).to_str(); let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str();
let data = apply_cell_data_changeset(&cell_data, None, field_rev)?; let data = apply_cell_data_changeset(cell_data, None, field_rev)?;
let cell = CellRevision::new(data); let cell = CellRevision::new(data);
self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); self.payload.cell_by_field_id.insert(field_id.to_owned(), cell);
Ok(()) Ok(())

View File

@ -2,7 +2,7 @@ use crate::grid::field_util::make_date_cell_string;
use crate::grid::script::EditorScript::*; use crate::grid::script::EditorScript::*;
use crate::grid::script::*; use crate::grid::script::*;
use flowy_grid::entities::{CellChangeset, FieldType}; use flowy_grid::entities::{CellChangeset, FieldType};
use flowy_grid::services::field::select_option::SelectOptionCellContentChangeset; use flowy_grid::services::field::select_option::SelectOptionCellChangeset;
use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
#[tokio::test] #[tokio::test]
@ -25,11 +25,11 @@ async fn grid_cell_update() {
FieldType::DateTime => make_date_cell_string("123"), FieldType::DateTime => make_date_cell_string("123"),
FieldType::SingleSelect => { FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field_rev); let type_option = SingleSelectTypeOption::from(field_rev);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
} }
FieldType::MultiSelect => { FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_rev); let type_option = MultiSelectTypeOption::from(field_rev);
SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str()
} }
FieldType::Checkbox => "1".to_string(), FieldType::Checkbox => "1".to_string(),
FieldType::URL => "1".to_string(), FieldType::URL => "1".to_string(),
@ -40,7 +40,7 @@ async fn grid_cell_update() {
grid_id: block_id.to_string(), grid_id: block_id.to_string(),
row_id: row_rev.id.clone(), row_id: row_rev.id.clone(),
field_id: field_rev.id.clone(), field_id: field_rev.id.clone(),
cell_content_changeset: Some(data), content: Some(data),
}, },
is_err: false, is_err: false,
}); });

View File

@ -73,7 +73,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev
// The grid will contains all existing field types and there are three empty rows in this grid. // The grid will contains all existing field types and there are three empty rows in this grid.
pub fn make_date_cell_string(s: &str) -> String { pub fn make_date_cell_string(s: &str) -> String {
serde_json::to_string(&DateCellContentChangeset { serde_json::to_string(&DateCellChangeset {
date: Some(s.to_string()), date: Some(s.to_string()),
time: None, time: None,
}) })

View File

@ -1,6 +1,6 @@
use crate::grid::script::GridEditorTest; use crate::grid::script::GridEditorTest;
use flowy_grid::entities::FieldType; use flowy_grid::entities::FieldType;
use flowy_grid::services::field::DateCellContentChangeset; use flowy_grid::services::field::DateCellChangeset;
use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload};
use flowy_grid_data_model::revision::FieldRevision; use flowy_grid_data_model::revision::FieldRevision;
use strum::EnumCount; use strum::EnumCount;
@ -33,7 +33,7 @@ impl<'a> GridRowTestBuilder<'a> {
#[allow(dead_code)] #[allow(dead_code)]
pub fn update_date_cell(mut self, value: i64) -> Self { pub fn update_date_cell(mut self, value: i64) -> Self {
let value = serde_json::to_string(&DateCellContentChangeset { let value = serde_json::to_string(&DateCellChangeset {
date: Some(value.to_string()), date: Some(value.to_string()),
time: None, time: None,
}) })