diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart index 5d508cdef5..5e406c0c26 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart @@ -38,7 +38,7 @@ class CellService { ..gridId = gridId ..fieldId = fieldId ..rowId = rowId - ..cellContentChangeset = data; + ..content = data; return GridEventUpdateCell(payload).send(); } diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index 391a63fa3f..f7daa84147 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -134,7 +134,7 @@ pub struct CellChangeset { pub field_id: String, #[pb(index = 4, one_of)] - pub cell_content_changeset: Option, + pub content: Option, } impl std::convert::From for RowMetaChangeset { @@ -142,7 +142,7 @@ impl std::convert::From for RowMetaChangeset { let mut cell_by_field_id = HashMap::with_capacity(1); let field_id = changeset.field_id; 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); diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 6c86c30381..f00edcd124 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -323,7 +323,7 @@ pub(crate) async fn update_select_option_handler( let mut cell_content_changeset = None; 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); } @@ -332,7 +332,7 @@ pub(crate) async fn update_select_option_handler( } 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); } @@ -343,7 +343,7 @@ pub(crate) async fn update_select_option_handler( grid_id: changeset.cell_identifier.grid_id, row_id: changeset.cell_identifier.row_id, field_id: changeset.cell_identifier.field_id, - cell_content_changeset, + content: cell_content_changeset, }; let _ = editor.update_cell(changeset).await?; } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs index 57f130cc47..9e8d9b4a3f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs @@ -1,8 +1,8 @@ use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; 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_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; use nanoid::nanoid; @@ -217,7 +217,7 @@ pub struct SelectOptionCellChangesetParams { impl std::convert::From for CellChangeset { fn from(params: SelectOptionCellChangesetParams) -> Self { - let changeset = SelectOptionCellContentChangeset { + let changeset = SelectOptionCellChangeset { insert_option_id: params.insert_option_id, delete_option_id: params.delete_option_id, }; @@ -226,7 +226,7 @@ impl std::convert::From for CellChangeset { grid_id: params.cell_identifier.grid_id, row_id: params.cell_identifier.row_id, field_id: params.cell_identifier.field_id, - cell_content_changeset: Some(s), + content: Some(s), } } } @@ -263,21 +263,30 @@ impl TryInto for SelectOptionCellChangesetPaylo } #[derive(Clone, Serialize, Deserialize)] -pub struct SelectOptionCellContentChangeset { +pub struct SelectOptionCellChangeset { pub insert_option_id: Option, pub delete_option_id: Option, } -impl SelectOptionCellContentChangeset { +impl FromCellChangeset for SelectOptionCellChangeset { + fn from_changeset(changeset: String) -> FlowyResult + where + Self: Sized, + { + serde_json::from_str::(&changeset).map_err(internal_error) + } +} + +impl SelectOptionCellChangeset { pub fn from_insert(option_id: &str) -> Self { - SelectOptionCellContentChangeset { + SelectOptionCellChangeset { insert_option_id: Some(option_id.to_string()), delete_option_id: None, } } pub fn from_delete(option_id: &str) -> Self { - SelectOptionCellContentChangeset { + SelectOptionCellChangeset { insert_option_id: None, delete_option_id: Some(option_id.to_string()), } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs index 36d8a95082..03667b6917 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -2,7 +2,8 @@ use crate::entities::{FieldType, GridCheckboxFilter}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, + DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -52,7 +53,7 @@ impl CellFilterOperation for CheckboxTypeOption { } } -impl CellDataOperation for CheckboxTypeOption { +impl CellDataOperation for CheckboxTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -71,11 +72,12 @@ impl CellDataOperation for CheckboxTypeOption { Ok(DecodedCellData::default()) } - fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result - where - C: Into, - { - let changeset = changeset.into(); + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let changeset = changeset.try_into_inner()?; let s = match string_to_bool(&changeset) { true => YES, false => NO, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 4623633ed8..289c273f4f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -3,14 +3,14 @@ use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, - FromCellString, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, + FromCellChangeset, FromCellString, }; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; use chrono::{NaiveDateTime, Timelike}; 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 serde::{Deserialize, Serialize}; use strum_macros::EnumIter; @@ -127,7 +127,7 @@ impl CellFilterOperation for DateTypeOption { } } -impl CellDataOperation for DateTypeOption { +impl CellDataOperation for DateTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -146,14 +146,15 @@ impl CellDataOperation for DateTypeOption { DecodedCellData::try_from_bytes(date) } - fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result - where - C: Into, - { - let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?; - let cell_data = match content_changeset.date_timestamp() { + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let changeset = changeset.try_into_inner()?; + let cell_data = match changeset.date_timestamp() { None => 0, - Some(date_timestamp) => match (self.include_time, content_changeset.time) { + Some(date_timestamp) => match (self.include_time, changeset.time) { (true, Some(time)) => { let time = Some(time.trim().to_uppercase()); let utc = self.utc_date_time_from_timestamp(date_timestamp); @@ -331,7 +332,7 @@ impl TryInto for DateChangesetPayload { impl std::convert::From for CellChangeset { fn from(params: DateChangesetParams) -> Self { - let changeset = DateCellContentChangeset { + let changeset = DateCellChangeset { date: params.date, time: params.time, }; @@ -340,18 +341,18 @@ impl std::convert::From for CellChangeset { grid_id: params.cell_identifier.grid_id, row_id: params.cell_identifier.row_id, field_id: params.cell_identifier.field_id, - cell_content_changeset: Some(s), + content: Some(s), } } } #[derive(Clone, Serialize, Deserialize)] -pub struct DateCellContentChangeset { +pub struct DateCellChangeset { pub date: Option, pub time: Option, } -impl DateCellContentChangeset { +impl DateCellChangeset { pub fn date_timestamp(&self) -> Option { if let Some(date) = &self.date { match date.parse::() { @@ -364,10 +365,12 @@ impl DateCellContentChangeset { } } -impl std::convert::From for CellContentChangeset { - fn from(changeset: DateCellContentChangeset) -> Self { - let s = serde_json::to_string(&changeset).unwrap(); - CellContentChangeset::from(s) +impl FromCellChangeset for DateCellChangeset { + fn from_changeset(changeset: String) -> FlowyResult + where + Self: Sized, + { + serde_json::from_str::(&changeset).map_err(internal_error) } } @@ -375,8 +378,8 @@ impl std::convert::From for CellContentChangeset { mod tests { use crate::entities::FieldType; use crate::services::field::FieldBuilder; - use crate::services::field::{DateCellContentChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; - use crate::services::row::CellDataOperation; + use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; + use crate::services::row::{CellDataChangeset, CellDataOperation}; use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; @@ -387,7 +390,7 @@ mod tests { let field_rev = FieldBuilder::from_field_type(&field_type).build(); assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some("1e".to_string()), time: Some("23:00".to_owned()), }, @@ -433,7 +436,7 @@ mod tests { TimeFormat::TwentyFourHour => { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: None, }, @@ -443,7 +446,7 @@ mod tests { ); assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: Some("23:00".to_owned()), }, @@ -455,7 +458,7 @@ mod tests { TimeFormat::TwelveHour => { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: None, }, @@ -466,7 +469,7 @@ mod tests { // assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: Some("".to_owned()), }, @@ -477,7 +480,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: Some("11:23 pm".to_owned()), }, @@ -499,7 +502,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: None, }, @@ -511,7 +514,7 @@ mod tests { type_option.include_time = true; assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: None, }, @@ -522,7 +525,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: Some("1:00".to_owned()), }, @@ -534,7 +537,7 @@ mod tests { type_option.time_format = TimeFormat::TwelveHour; assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, @@ -554,7 +557,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: Some("1:".to_owned()), }, @@ -565,7 +568,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp), time: Some("1:00".to_owned()), }, @@ -585,7 +588,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, @@ -597,11 +600,12 @@ mod tests { fn assert_changeset_result( type_option: &DateTypeOption, - changeset: DateCellContentChangeset, + changeset: DateCellChangeset, _field_type: &FieldType, field_rev: &FieldRevision, expected: &str, ) { + let changeset = CellDataChangeset(Some(changeset)); let encoded_data = type_option.apply_changeset(changeset, None).unwrap(); assert_eq!( expected.to_owned(), @@ -615,15 +619,12 @@ mod tests { field_rev: &FieldRevision, expected: &str, ) { - let encoded_data = type_option - .apply_changeset( - DateCellContentChangeset { - date: Some(timestamp.to_string()), - time: None, - }, - None, - ) - .unwrap(); + let s = serde_json::to_string(&DateCellChangeset { + date: Some(timestamp.to_string()), + time: None, + }) + .unwrap(); + let encoded_data = type_option.apply_changeset(s.into(), None).unwrap(); assert_eq!( expected.to_owned(), @@ -631,13 +632,9 @@ mod tests { ); } - fn decode_cell_data>( - encoded_data: T, - type_option: &DateTypeOption, - field_rev: &FieldRevision, - ) -> String { + fn decode_cell_data(encoded_data: String, type_option: &DateTypeOption, field_rev: &FieldRevision) -> String { 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() .parse::() .unwrap(); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs index 6c12ce8ea0..417f44142a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs @@ -2,13 +2,13 @@ use crate::entities::{FieldType, GridSelectOptionFilter}; use crate::impl_type_option; use crate::services::field::select_option::{ - make_selected_select_options, SelectOption, SelectOptionCellContentChangeset, SelectOptionCellData, - SelectOptionIds, SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR, + make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, + SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR, }; use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -56,7 +56,7 @@ impl CellFilterOperation for MultiSelectTypeOption { Ok(filter.apply(&selected_options)) } } -impl CellDataOperation for MultiSelectTypeOption { +impl CellDataOperation for MultiSelectTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -81,11 +81,12 @@ impl CellDataOperation for MultiSelectTypeOption { DecodedCellData::try_from_bytes(cell_data) } - fn apply_changeset(&self, changeset: T, cell_rev: Option) -> Result - where - T: Into, - { - let content_changeset: SelectOptionCellContentChangeset = serde_json::from_str(&changeset.into())?; + fn apply_changeset( + &self, + changeset: CellDataChangeset, + cell_rev: Option, + ) -> Result { + let content_changeset = changeset.try_into_inner()?; let new_cell_data: String; match cell_rev { None => { @@ -164,8 +165,8 @@ mod tests { let type_option = MultiSelectTypeOption::from(&field_rev); 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 cell_data = type_option.apply_changeset(data, None).unwrap(); + let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str(); + let cell_data = type_option.apply_changeset(data.into(), None).unwrap(); assert_multi_select_options( cell_data, &type_option, @@ -173,24 +174,24 @@ mod tests { vec![google_option.clone(), facebook_option], ); - let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); - let cell_data = type_option.apply_changeset(data, None).unwrap(); + let data = SelectOptionCellChangeset::from_insert(&google_option.id).to_str(); + let cell_data = type_option.apply_changeset(data.into(), None).unwrap(); assert_multi_select_options(cell_data, &type_option, &field_rev, vec![google_option]); // Invalid option id let cell_data = type_option - .apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) + .apply_changeset(SelectOptionCellChangeset::from_insert("").to_str().into(), None) .unwrap(); assert_multi_select_options(cell_data, &type_option, &field_rev, vec![]); // Invalid option id 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(); assert_multi_select_options(cell_data, &type_option, &field_rev, vec![]); // 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( @@ -203,7 +204,7 @@ mod tests { assert_eq!( expected, type_option - .decode_cell_data(cell_data, &field_type, field_rev) + .decode_cell_data(cell_data.into(), &field_type, field_rev) .unwrap() .parse::() .unwrap() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index 5bcc0a0dc6..16896f3d5e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -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::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -118,7 +118,7 @@ impl CellFilterOperation for NumberTypeOption { } } -impl CellDataOperation for NumberTypeOption { +impl CellDataOperation for NumberTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -136,11 +136,9 @@ impl CellDataOperation for NumberTypeOption { } } - fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result - where - C: Into, + fn apply_changeset(&self, changeset: CellDataChangeset, _cell_rev: Option) -> Result { - let changeset = changeset.into(); + let changeset = changeset.try_into_inner()?; let data = changeset.trim().to_string(); let _ = self.format_cell_data(&data)?; Ok(data) @@ -380,7 +378,7 @@ mod tests { ) { assert_eq!( type_option - .decode_cell_data(cell_data, field_type, field_rev) + .decode_cell_data(cell_data.to_owned().into(), field_type, field_rev) .unwrap() .to_string(), expected_str.to_owned() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs index e8ecf98d52..94d7af18cf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs @@ -1,12 +1,12 @@ use crate::entities::{FieldType, GridSelectOptionFilter}; use crate::impl_type_option; use crate::services::field::select_option::{ - make_selected_select_options, SelectOption, SelectOptionCellContentChangeset, SelectOptionCellData, - SelectOptionIds, SelectOptionOperation, + make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, + SelectOptionOperation, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -53,7 +53,7 @@ impl CellFilterOperation for SingleSelectTypeOption { } } -impl CellDataOperation for SingleSelectTypeOption { +impl CellDataOperation for SingleSelectTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -78,12 +78,12 @@ impl CellDataOperation for SingleSelectTypeOption { DecodedCellData::try_from_bytes(cell_data) } - fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result - where - C: Into, - { - let changeset = changeset.into(); - let select_option_changeset: SelectOptionCellContentChangeset = serde_json::from_str(&changeset)?; + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let select_option_changeset = changeset.try_into_inner()?; let new_cell_data: String; if let Some(insert_option_id) = select_option_changeset.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 option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR); - let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); - let cell_data = type_option.apply_changeset(data, None).unwrap(); + let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str(); + 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()]); - let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); - let cell_data = type_option.apply_changeset(data, None).unwrap(); + let data = SelectOptionCellChangeset::from_insert(&google_option.id).to_str(); + let cell_data = type_option.apply_changeset(data.into(), None).unwrap(); assert_single_select_options(cell_data, &type_option, &field_rev, vec![google_option]); // Invalid option id let cell_data = type_option - .apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) + .apply_changeset(SelectOptionCellChangeset::from_insert("").to_str().into(), None) .unwrap(); assert_single_select_options(cell_data, &type_option, &field_rev, vec![]); // Invalid option id 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(); assert_single_select_options(cell_data, &type_option, &field_rev, vec![]); // 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( @@ -181,7 +181,7 @@ mod tests { assert_eq!( expected, type_option - .decode_cell_data(cell_data, &field_type, field_rev) + .decode_cell_data(cell_data.into(), &field_type, field_rev) .unwrap() .parse::() .unwrap() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index 83401314fe..a496a57c8d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -2,7 +2,7 @@ use crate::entities::{FieldType, GridTextFilter}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - try_decode_cell_data, AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, + try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; @@ -44,7 +44,7 @@ impl CellFilterOperation for RichTextTypeOption { } } -impl CellDataOperation for RichTextTypeOption { +impl CellDataOperation for RichTextTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -56,22 +56,23 @@ impl CellDataOperation for RichTextTypeOption { || decoded_field_type.is_multi_select() || 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 { let cell_data: String = cell_data.try_into_inner()?; Ok(DecodedCellData::new(cell_data)) } } - fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result - where - C: Into, - { - let data = changeset.into(); + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let data = changeset.try_into_inner()?; if data.len() > 10000 { Err(FlowyError::text_too_long().context("The len of the text should not be more than 10000")) } else { - Ok(data.0) + Ok(data) } } } @@ -109,7 +110,7 @@ mod tests { assert_eq!( 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() .parse::() .unwrap() @@ -125,7 +126,11 @@ mod tests { assert_eq!( 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() .parse::() .unwrap() @@ -137,16 +142,18 @@ mod tests { let google_option = SelectOption::new("Google"); let facebook_option = SelectOption::new("Facebook"); 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() .option(google_option.clone()) .option(facebook_option.clone()); let multi_select_field_rev = FieldBuilder::new(multi_select).build(); 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!( 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() .parse::() .unwrap() @@ -159,7 +166,7 @@ mod tests { let number_field_rev = FieldBuilder::new(number).build(); assert_eq!( 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() .to_string(), "$18,443".to_owned() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs index b41631c649..db24442b9b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs @@ -2,8 +2,7 @@ use crate::entities::{FieldType, GridTextFilter}; use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, - FromCellString, + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, FromCellString, }; use bytes::Bytes; use fancy_regex::Regex; @@ -46,7 +45,7 @@ impl CellFilterOperation for URLTypeOption { } } -impl CellDataOperation for URLTypeOption { +impl CellDataOperation for URLTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -60,18 +59,16 @@ impl CellDataOperation for URLTypeOption { DecodedCellData::try_from_bytes(cell_data) } - fn apply_changeset(&self, changeset: C, _cell_rev: Option) -> Result - where - C: Into, + fn apply_changeset(&self, changeset: CellDataChangeset, _cell_rev: Option) -> Result { - let changeset = changeset.into(); + let changeset = changeset.try_into_inner()?; let mut url = "".to_string(); if let Ok(Some(m)) = URL_REGEX.find(&changeset) { url = auto_append_scheme(m.as_str()); } URLCellData { url, - content: changeset.to_string(), + content: changeset, } .to_json() } @@ -190,7 +187,7 @@ mod tests { expected: &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); assert_eq!(expected.to_owned(), decode_cell_data.content); assert_eq!(expected_url.to_owned(), decode_cell_data.url); @@ -203,7 +200,7 @@ mod tests { field_type: &FieldType, ) -> URLCellData { type_option - .decode_cell_data(encoded_data, field_type, field_rev) + .decode_cell_data(encoded_data.into(), field_type, field_rev) .unwrap() .parse::() .unwrap() diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 7bac1ee51f..2b7a854a7d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -369,7 +369,7 @@ impl GridRevisionEditor { #[tracing::instrument(level = "trace", skip_all, err)] 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(()); } @@ -377,7 +377,7 @@ impl GridRevisionEditor { grid_id, row_id, field_id, - mut cell_content_changeset, + mut content, } = cell_changeset; match self.grid_pad.read().await.get_field_rev(&field_id) { @@ -386,21 +386,17 @@ impl GridRevisionEditor { Err(FlowyError::internal().context(msg)) } 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?; // Update the changeset.data property with the return value. - cell_content_changeset = Some(apply_cell_data_changeset( - cell_content_changeset.unwrap(), - cell_rev, - field_rev, - )?); + content = Some(apply_cell_data_changeset(content.unwrap(), cell_rev, field_rev)?); let field_revs = self.get_field_revs(None).await?; let cell_changeset = CellChangeset { grid_id, row_id, field_id, - cell_content_changeset, + content, }; let _ = self .block_manager diff --git a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs index f9b5f461fa..d312543a6f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs @@ -4,16 +4,17 @@ use bytes::Bytes; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision}; use serde::{Deserialize, Serialize}; -use std::fmt::Formatter; + use std::str::FromStr; pub trait CellFilterOperation { fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult; } -pub trait CellDataOperation { - /// The cell_data is able to parse into the specific data that was impl the From trait. - /// D will be URLCellData, DateCellData. etc. +pub trait CellDataOperation { + /// The cell_data is able to parse into the specific data that was impl the FromCellData trait. + /// For example: + /// URLCellData, DateCellData. etc. fn decode_cell_data( &self, cell_data: CellData, @@ -21,35 +22,10 @@ pub trait CellDataOperation { field_rev: &FieldRevision, ) -> FlowyResult; - fn apply_changeset>( - &self, - changeset: C, - cell_rev: Option, - ) -> FlowyResult; -} - -#[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> std::convert::From 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 - } + /// The changeset is able to parse into the specific data that was impl the FromCellChangeset trait. + /// For example: + /// SelectOptionCellChangeset,DateCellChangeset. etc. + fn apply_changeset(&self, changeset: CellDataChangeset, cell_rev: Option) -> FlowyResult; } /// 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. /// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect -pub fn apply_cell_data_changeset, T: AsRef>( +pub fn apply_cell_data_changeset>( changeset: C, cell_rev: Option, field_rev: T, ) -> Result { let field_rev = field_rev.as_ref(); + let changeset = changeset.to_string(); let field_type = field_rev.field_type_rev.into(); let s = match field_type { - FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), - FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), - FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), - FieldType::SingleSelect => SingleSelectTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), - FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), - FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset, cell_rev), - FieldType::URL => URLTypeOption::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.into(), cell_rev), + FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), + FieldType::SingleSelect => SingleSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), + FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), + FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), + FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), }?; Ok(AnyCellData::new(s, field_type).json()) @@ -274,7 +251,45 @@ impl std::convert::From for CellData { impl std::convert::From> for String { fn from(p: CellData) -> 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 + where + Self: Sized; +} + +pub struct CellDataChangeset(pub Option); + +impl CellDataChangeset { + pub fn try_into_inner(self) -> FlowyResult { + match self.0 { + None => Err(ErrorCode::InvalidData.into()), + Some(data) => Ok(data), + } + } +} + +impl std::convert::From for CellDataChangeset +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 for CellDataChangeset { + fn from(s: String) -> Self { + CellDataChangeset(Some(s)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index 99c6617c7e..d13154ebcc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -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 flowy_error::{FlowyError, FlowyResult}; 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)) } 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); self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); Ok(()) @@ -50,8 +50,8 @@ impl<'a> CreateRowRevisionBuilder<'a> { Err(FlowyError::internal().context(msg)) } Some(field_rev) => { - let cell_data = SelectOptionCellContentChangeset::from_insert(&data).to_str(); - let data = apply_cell_data_changeset(&cell_data, None, field_rev)?; + let cell_data = SelectOptionCellChangeset::from_insert(&data).to_str(); + let data = apply_cell_data_changeset(cell_data, None, field_rev)?; let cell = CellRevision::new(data); self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); Ok(()) diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs index 803e17e2b5..01d2310278 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs @@ -2,7 +2,7 @@ use crate::grid::field_util::make_date_cell_string; use crate::grid::script::EditorScript::*; use crate::grid::script::*; 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}; #[tokio::test] @@ -25,11 +25,11 @@ async fn grid_cell_update() { FieldType::DateTime => make_date_cell_string("123"), FieldType::SingleSelect => { 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 => { 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::URL => "1".to_string(), @@ -40,7 +40,7 @@ async fn grid_cell_update() { grid_id: block_id.to_string(), row_id: row_rev.id.clone(), field_id: field_rev.id.clone(), - cell_content_changeset: Some(data), + content: Some(data), }, is_err: false, }); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs index ca094651f5..d9055f93ea 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs @@ -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. pub fn make_date_cell_string(s: &str) -> String { - serde_json::to_string(&DateCellContentChangeset { + serde_json::to_string(&DateCellChangeset { date: Some(s.to_string()), time: None, }) diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs index ee4750bd19..bdd6dd86dc 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs @@ -1,6 +1,6 @@ use crate::grid::script::GridEditorTest; 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_data_model::revision::FieldRevision; use strum::EnumCount; @@ -33,7 +33,7 @@ impl<'a> GridRowTestBuilder<'a> { #[allow(dead_code)] 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()), time: None, })