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/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index 137693e13a..d43e77e9ae 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -458,6 +458,8 @@ impl TryInto for FieldChangesetPayload { Serialize_repr, Deserialize_repr, )] +/// The order of the enum can't be changed. If you want to add a new type, +/// it would be better to append it to the end of the list. #[repr(u8)] pub enum FieldType { RichText = 0, diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 6c86c30381..d45d5e31c7 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -1,10 +1,10 @@ use crate::entities::*; use crate::manager::GridManager; +use crate::services::cell::AnyCellData; use crate::services::field::select_option::*; use crate::services::field::{ default_type_option_builder_from_type, type_option_builder_from_json_str, DateChangesetParams, DateChangesetPayload, }; -use crate::services::row::AnyCellData; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::FieldRevision; use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; @@ -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/cell/any_cell_data.rs b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs new file mode 100644 index 0000000000..8caeafd1ac --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs @@ -0,0 +1,151 @@ +use crate::entities::FieldType; +use bytes::Bytes; +use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::CellRevision; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; +/// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type. +/// When the type of field is changed, it's different from the field_type of AnyCellData. +/// So it will return an empty data. You could check the CellDataOperation trait for more information. +#[derive(Debug, Serialize, Deserialize)] +pub struct AnyCellData { + pub cell_data: String, + pub field_type: FieldType, +} + +impl std::str::FromStr for AnyCellData { + type Err = FlowyError; + + fn from_str(s: &str) -> Result { + let type_option_cell_data: AnyCellData = serde_json::from_str(s)?; + Ok(type_option_cell_data) + } +} + +impl std::convert::TryInto for String { + type Error = FlowyError; + + fn try_into(self) -> Result { + AnyCellData::from_str(&self) + } +} + +impl std::convert::TryFrom<&CellRevision> for AnyCellData { + type Error = FlowyError; + + fn try_from(value: &CellRevision) -> Result { + Self::from_str(&value.data) + } +} + +impl std::convert::TryFrom<&Option> for AnyCellData { + type Error = FlowyError; + + fn try_from(value: &Option) -> Result { + match value { + None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")), + Some(cell_rev) => AnyCellData::try_from(cell_rev), + } + } +} + +impl std::convert::TryFrom> for AnyCellData { + type Error = FlowyError; + + fn try_from(value: Option) -> Result { + Self::try_from(&value) + } +} + +impl AnyCellData { + pub fn new(content: String, field_type: FieldType) -> Self { + AnyCellData { + cell_data: content, + field_type, + } + } + + pub fn json(&self) -> String { + serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) + } + + pub fn is_number(&self) -> bool { + self.field_type == FieldType::Number + } + + pub fn is_text(&self) -> bool { + self.field_type == FieldType::RichText + } + + pub fn is_checkbox(&self) -> bool { + self.field_type == FieldType::Checkbox + } + + pub fn is_date(&self) -> bool { + self.field_type == FieldType::DateTime + } + + pub fn is_single_select(&self) -> bool { + self.field_type == FieldType::SingleSelect + } + + pub fn is_multi_select(&self) -> bool { + self.field_type == FieldType::MultiSelect + } + + pub fn is_url(&self) -> bool { + self.field_type == FieldType::URL + } + + pub fn is_select_option(&self) -> bool { + self.field_type == FieldType::MultiSelect || self.field_type == FieldType::SingleSelect + } +} + +/// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it. +/// +/// For example: +/// +/// * Use DateCellData to parse the data when the FieldType is Date. +/// * Use URLCellData to parse the data when the FieldType is URL. +/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox. +/// * Check out the implementation of CellDataOperation trait for more information. +#[derive(Default)] +pub struct DecodedCellData { + pub data: Vec, +} + +impl DecodedCellData { + pub fn new>(data: T) -> Self { + Self { + data: data.as_ref().to_vec(), + } + } + + pub fn try_from_bytes>(bytes: T) -> FlowyResult + where + >::Error: std::fmt::Debug, + { + let bytes = bytes.try_into().map_err(internal_error)?; + Ok(Self { data: bytes.to_vec() }) + } + + pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult + where + >::Error: std::fmt::Debug, + { + T::try_from(self.data.as_ref()).map_err(internal_error) + } +} + +impl ToString for DecodedCellData { + fn to_string(&self) -> String { + match String::from_utf8(self.data.clone()) { + Ok(s) => s, + Err(e) => { + tracing::error!("DecodedCellData to string failed: {:?}", e); + "".to_string() + } + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs new file mode 100644 index 0000000000..c866f2a167 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -0,0 +1,194 @@ +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision}; + +use crate::entities::FieldType; +use crate::services::cell::{AnyCellData, DecodedCellData}; +use crate::services::field::*; + +pub trait CellFilterOperation { + /// Return true if any_cell_data match the filter condition. + 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 FromCellData trait. + /// For example: + /// URLCellData, DateCellData. etc. + fn decode_cell_data( + &self, + cell_data: CellData, + decoded_field_type: &FieldType, + field_rev: &FieldRevision, + ) -> FlowyResult; + + /// 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; +} +/// 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>( + 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.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()) +} + +pub fn decode_any_cell_data>(data: T, field_rev: &FieldRevision) -> DecodedCellData { + if let Ok(any_cell_data) = data.try_into() { + let AnyCellData { cell_data, field_type } = any_cell_data; + let to_field_type = field_rev.field_type_rev.into(); + match try_decode_cell_data(CellData(Some(cell_data)), field_rev, &field_type, &to_field_type) { + Ok(cell_data) => cell_data, + Err(e) => { + tracing::error!("Decode cell data failed, {:?}", e); + DecodedCellData::default() + } + } + } else { + tracing::error!("Decode type option data failed"); + DecodedCellData::default() + } +} + +pub fn try_decode_cell_data( + cell_data: CellData, + field_rev: &FieldRevision, + s_field_type: &FieldType, + t_field_type: &FieldType, +) -> FlowyResult { + let cell_data = cell_data.try_into_inner()?; + let get_cell_data = || { + let field_type: FieldTypeRevision = t_field_type.into(); + let data = match t_field_type { + FieldType::RichText => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + FieldType::Number => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + FieldType::DateTime => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + FieldType::SingleSelect => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + FieldType::MultiSelect => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + FieldType::Checkbox => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + FieldType::URL => field_rev + .get_type_option_entry::(field_type)? + .decode_cell_data(cell_data.into(), s_field_type, field_rev), + }; + Some(data) + }; + + match get_cell_data() { + Some(Ok(data)) => Ok(data), + Some(Err(err)) => { + tracing::error!("{:?}", err); + Ok(DecodedCellData::default()) + } + None => Ok(DecodedCellData::default()), + } +} + +pub trait FromCellString { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized; +} + +pub struct CellData(pub Option); + +impl CellData { + pub fn try_into_inner(self) -> FlowyResult { + match self.0 { + None => Err(ErrorCode::InvalidData.into()), + Some(data) => Ok(data), + } + } +} + +impl std::convert::From for CellData +where + T: FromCellString, +{ + fn from(s: String) -> Self { + match T::from_cell_str(&s) { + Ok(inner) => CellData(Some(inner)), + Err(e) => { + tracing::error!("Deserialize Cell Data failed: {}", e); + CellData(None) + } + } + } +} + +impl std::convert::From for CellData { + fn from(s: String) -> Self { + CellData(Some(s)) + } +} + +impl std::convert::From> for String { + fn from(p: CellData) -> Self { + 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/cell/mod.rs b/frontend/rust-lib/flowy-grid/src/services/cell/mod.rs new file mode 100644 index 0000000000..bc8ada929c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/cell/mod.rs @@ -0,0 +1,5 @@ +mod any_cell_data; +mod cell_operation; + +pub use any_cell_data::*; +pub use cell_operation::*; 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 3838405d93..e4b3d0f3d6 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::cell::{AnyCellData, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; -use crate::services::row::AnyCellData; 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; @@ -155,6 +155,15 @@ impl std::convert::TryFrom for SelectOptionIds { } } +impl FromCellString for SelectOptionIds { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized, + { + Ok(Self::from(s.to_owned())) + } +} + impl std::convert::From for SelectOptionIds { fn from(s: String) -> Self { let ids = s @@ -208,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, }; @@ -217,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), } } } @@ -254,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 bb8f43c6fb..12361e3fcb 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 @@ -1,9 +1,9 @@ use crate::entities::{FieldType, GridCheckboxFilter}; use crate::impl_type_option; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{ - AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, +use crate::services::cell::{ + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, }; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; @@ -52,33 +52,31 @@ impl CellFilterOperation for CheckboxTypeOption { } } -impl CellDataOperation for CheckboxTypeOption { - fn decode_cell_data( +impl CellDataOperation for CheckboxTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into, - { + ) -> FlowyResult { if !decoded_field_type.is_checkbox() { return Ok(DecodedCellData::default()); } - let encoded_data = cell_data.into(); - if encoded_data == YES || encoded_data == NO { - return Ok(DecodedCellData::new(encoded_data)); + let s: String = cell_data.try_into_inner()?; + if s == YES || s == NO { + return Ok(DecodedCellData::new(s)); } 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, @@ -117,10 +115,9 @@ impl std::convert::TryFrom for CheckboxCellData { #[cfg(test)] mod tests { + use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data}; use crate::services::field::type_options::checkbox_type_option::{NO, YES}; - use crate::services::field::FieldBuilder; - use crate::services::row::{apply_cell_data_changeset, decode_any_cell_data}; use crate::entities::FieldType; 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 21c608f3b4..34b354b060 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 @@ -1,15 +1,16 @@ use crate::entities::{CellChangeset, FieldType, GridDateFilter}; use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::impl_type_option; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{ - AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, +use crate::services::cell::{ + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, + FromCellChangeset, FromCellString, }; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; 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; @@ -126,16 +127,13 @@ impl CellFilterOperation for DateTypeOption { } } -impl CellDataOperation for DateTypeOption { - fn decode_cell_data( +impl CellDataOperation for DateTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into, - { + ) -> FlowyResult { // Return default data if the type_option_cell_data is not FieldType::DateTime. // It happens when switching from one field to another. // For example: @@ -143,20 +141,20 @@ impl CellDataOperation for DateTypeOption { if !decoded_field_type.is_date() { return Ok(DecodedCellData::default()); } - - let timestamp = cell_data.into().parse::().unwrap_or(0); - let date = self.today_desc_from_timestamp(timestamp); + let timestamp = cell_data.try_into_inner()?; + let date = self.today_desc_from_timestamp(timestamp.0); 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); @@ -170,6 +168,17 @@ impl CellDataOperation for DateTypeOption { } } +pub struct TimestampParser(i64); + +impl FromCellString for TimestampParser { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized, + { + let num = s.parse::().unwrap_or(0); + Ok(TimestampParser(num)) + } +} #[derive(Default)] pub struct DateTypeOptionBuilder(DateTypeOption); impl_into_box_type_option_builder!(DateTypeOptionBuilder); @@ -323,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, }; @@ -332,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::() { @@ -356,19 +365,21 @@ 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) } } #[cfg(test)] mod tests { use crate::entities::FieldType; + use crate::services::cell::{CellDataChangeset, CellDataOperation}; 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 flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; @@ -379,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()), }, @@ -425,7 +436,7 @@ mod tests { TimeFormat::TwentyFourHour => { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: None, }, @@ -435,7 +446,7 @@ mod tests { ); assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: Some("23:00".to_owned()), }, @@ -447,7 +458,7 @@ mod tests { TimeFormat::TwelveHour => { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: None, }, @@ -458,7 +469,7 @@ mod tests { // assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: Some("".to_owned()), }, @@ -469,7 +480,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(1653609600.to_string()), time: Some("11:23 pm".to_owned()), }, @@ -491,7 +502,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: None, }, @@ -503,7 +514,7 @@ mod tests { type_option.include_time = true; assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: None, }, @@ -514,7 +525,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: Some("1:00".to_owned()), }, @@ -526,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()), }, @@ -546,7 +557,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp.clone()), time: Some("1:".to_owned()), }, @@ -557,7 +568,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp), time: Some("1:00".to_owned()), }, @@ -577,7 +588,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellContentChangeset { + DateCellChangeset { date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, @@ -589,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(), @@ -607,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(), @@ -623,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 513d509f9b..9d27b0f468 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 @@ -1,15 +1,15 @@ use crate::entities::{FieldType, GridSelectOptionFilter}; use crate::impl_type_option; +use crate::services::cell::{ + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, +}; 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, CellDataOperation, CellFilterOperation, DecodedCellData, -}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; @@ -56,22 +56,18 @@ impl CellFilterOperation for MultiSelectTypeOption { Ok(filter.apply(&selected_options)) } } -impl CellDataOperation for MultiSelectTypeOption { - fn decode_cell_data( +impl CellDataOperation for MultiSelectTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into, - { + ) -> FlowyResult { if !decoded_field_type.is_select_option() { return Ok(DecodedCellData::default()); } - let encoded_data = cell_data.into(); - let ids: SelectOptionIds = encoded_data.into(); + let ids: SelectOptionIds = cell_data.try_into_inner()?; let select_options = ids .iter() .flat_map(|option_id| self.options.iter().find(|option| &option.id == option_id).cloned()) @@ -85,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 => { @@ -144,10 +141,10 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder { #[cfg(test)] mod tests { use crate::entities::FieldType; + use crate::services::cell::CellDataOperation; use crate::services::field::select_option::*; use crate::services::field::FieldBuilder; use crate::services::field::{MultiSelectTypeOption, MultiSelectTypeOptionBuilder}; - use crate::services::row::CellDataOperation; use flowy_grid_data_model::revision::FieldRevision; #[test] @@ -168,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, @@ -177,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( @@ -207,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 2b9717458b..690fd10841 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 @@ -1,12 +1,12 @@ use crate::impl_type_option; use crate::entities::{FieldType, GridNumberFilter}; +use crate::services::cell::{ + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, +}; 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, CellDataOperation, CellFilterOperation, DecodedCellData, -}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; @@ -118,32 +118,30 @@ impl CellFilterOperation for NumberTypeOption { } } -impl CellDataOperation for NumberTypeOption { - fn decode_cell_data( +impl CellDataOperation for NumberTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into, - { + ) -> FlowyResult { if decoded_field_type.is_date() { return Ok(DecodedCellData::default()); } - let cell_data = cell_data.into(); + let cell_data: String = cell_data.try_into_inner()?; match self.format_cell_data(&cell_data) { Ok(num) => Ok(DecodedCellData::new(num.to_string())), Err(_) => 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 data = changeset.trim().to_string(); let _ = self.format_cell_data(&data)?; Ok(data) @@ -254,9 +252,9 @@ impl ToString for NumberCellData { #[cfg(test)] mod tests { use crate::entities::FieldType; + use crate::services::cell::CellDataOperation; use crate::services::field::FieldBuilder; use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption}; - use crate::services::row::CellDataOperation; use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; @@ -383,7 +381,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 3df9107f6e..b1e72d24a7 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,13 +1,13 @@ use crate::entities::{FieldType, GridSelectOptionFilter}; use crate::impl_type_option; +use crate::services::cell::{ + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, +}; 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, CellDataOperation, CellFilterOperation, DecodedCellData, -}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; @@ -53,27 +53,22 @@ impl CellFilterOperation for SingleSelectTypeOption { } } -impl CellDataOperation for SingleSelectTypeOption { - fn decode_cell_data( +impl CellDataOperation for SingleSelectTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into, - { + ) -> FlowyResult { if !decoded_field_type.is_select_option() { return Ok(DecodedCellData::default()); } - let encoded_data = cell_data.into(); + let ids: SelectOptionIds = cell_data.try_into_inner()?; let mut cell_data = SelectOptionCellData { options: self.options.clone(), select_options: vec![], }; - - let ids: SelectOptionIds = encoded_data.into(); if let Some(option_id) = ids.first() { if let Some(option) = self.options.iter().find(|option| &option.id == option_id) { cell_data.select_options.push(option.clone()); @@ -83,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); @@ -127,10 +122,10 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder { #[cfg(test)] mod tests { use crate::entities::FieldType; + use crate::services::cell::CellDataOperation; use crate::services::field::select_option::*; use crate::services::field::type_options::*; use crate::services::field::FieldBuilder; - use crate::services::row::CellDataOperation; use flowy_grid_data_model::revision::FieldRevision; #[test] @@ -151,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( @@ -186,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 8b0579d6c9..0a727afb56 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 @@ -1,9 +1,10 @@ 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, CellDataOperation, CellFilterOperation, DecodedCellData, +use crate::services::cell::{ + try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, + DecodedCellData, }; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; @@ -43,37 +44,35 @@ impl CellFilterOperation for RichTextTypeOption { } } -impl CellDataOperation for RichTextTypeOption { - fn decode_cell_data( +impl CellDataOperation for RichTextTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into, - { + ) -> FlowyResult { if decoded_field_type.is_date() || decoded_field_type.is_single_select() || 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 = cell_data.into(); + 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) } } } @@ -96,10 +95,10 @@ impl std::convert::TryFrom for TextCellData { #[cfg(test)] mod tests { use crate::entities::FieldType; + use crate::services::cell::CellDataOperation; use crate::services::field::select_option::*; use crate::services::field::FieldBuilder; use crate::services::field::*; - use crate::services::row::CellDataOperation; #[test] fn text_description_test() { @@ -111,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() @@ -127,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() @@ -139,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() @@ -161,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 09af0cda8d..490d9dfaa1 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 @@ -1,9 +1,9 @@ use crate::entities::{FieldType, GridTextFilter}; use crate::impl_type_option; -use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder}; -use crate::services::row::{ - AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, EncodedCellData, +use crate::services::cell::{ + AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, FromCellString, }; +use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder}; use bytes::Bytes; use fancy_regex::Regex; use flowy_derive::ProtoBuf; @@ -11,7 +11,6 @@ use flowy_error::{internal_error, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; -use std::str::FromStr; #[derive(Default)] pub struct URLTypeOptionBuilder(URLTypeOption); @@ -46,35 +45,33 @@ impl CellFilterOperation for URLTypeOption { } } -impl CellDataOperation> for URLTypeOption { - fn decode_cell_data( +impl CellDataOperation for URLTypeOption { + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into>, - { + ) -> FlowyResult { if !decoded_field_type.is_url() { return Ok(DecodedCellData::default()); } - let cell_data = cell_data.into().try_into_inner()?; + let cell_data: URLCellData = cell_data.try_into_inner()?; DecodedCellData::try_from_bytes(cell_data) } - 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 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() } @@ -118,25 +115,17 @@ impl URLCellData { } } -impl FromStr for URLCellData { - type Err = FlowyError; - - fn from_str(s: &str) -> Result { +impl FromCellString for URLCellData { + fn from_cell_str(s: &str) -> FlowyResult { serde_json::from_str::(s).map_err(internal_error) } } -// impl std::convert::From for URLCellData { -// fn from(any_cell_data: AnyCellData) -> Self { -// URLCellData::from_str(&any_cell_data.cell_data).unwrap_or_default() -// } -// } - impl std::convert::TryFrom for URLCellData { - type Error = (); + type Error = FlowyError; - fn try_from(_value: AnyCellData) -> Result { - todo!() + fn try_from(data: AnyCellData) -> Result { + serde_json::from_str::(&data.cell_data).map_err(internal_error) } } @@ -150,9 +139,9 @@ lazy_static! { #[cfg(test)] mod tests { use crate::entities::FieldType; + use crate::services::cell::{CellData, CellDataOperation}; use crate::services::field::FieldBuilder; use crate::services::field::{URLCellData, URLTypeOption}; - use crate::services::row::{CellDataOperation, EncodedCellData}; use flowy_grid_data_model::revision::FieldRevision; #[test] @@ -195,20 +184,20 @@ 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); } - fn decode_cell_data>>( + fn decode_cell_data>>( encoded_data: T, type_option: &URLTypeOption, field_rev: &FieldRevision, 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/field/type_options/util/cell_data_util.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs index a61dd1ccf5..c8170e5fad 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/cell_data_util.rs @@ -1,4 +1,4 @@ -use crate::services::row::AnyCellData; +use crate::services::cell::AnyCellData; use flowy_grid_data_model::revision::CellRevision; use std::str::FromStr; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index 2e37287935..67dac70b6a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -1,6 +1,7 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::entities::{FieldType, GridBlockChangeset}; use crate::services::block_manager::GridBlockManager; +use crate::services::cell::{AnyCellData, CellFilterOperation}; use crate::services::field::{ CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption, SingleSelectTypeOption, URLTypeOption, @@ -9,15 +10,13 @@ use crate::services::filter::filter_cache::{ reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache, }; use crate::services::grid_editor_task::GridServiceTaskScheduler; -use crate::services::row::{AnyCellData, CellFilterOperation, GridBlockSnapshot}; +use crate::services::row::GridBlockSnapshot; use crate::services::tasks::{FilterTaskContext, Task, TaskContent}; - use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision}; use flowy_sync::client_grid::GridRevisionPad; use flowy_sync::entities::grid::GridSettingChangesetParams; use rayon::prelude::*; - use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; 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..152c9a8d2a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -1,13 +1,16 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::entities::CellIdentifier; +use crate::entities::*; use crate::manager::{GridTaskSchedulerRwLock, GridUser}; use crate::services::block_manager::GridBlockManager; +use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data}; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; use crate::services::filter::{GridFilterChangeset, GridFilterService}; use crate::services::persistence::block_index::BlockIndexCache; -use crate::services::row::*; - -use crate::entities::*; +use crate::services::row::{ + make_grid_blocks, make_row_from_row_rev, make_row_rev_from_context, make_rows_from_row_revs, + CreateRowRevisionBuilder, CreateRowRevisionPayload, GridBlockSnapshot, +}; use bytes::Bytes; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::*; @@ -369,7 +372,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 +380,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 +389,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/mod.rs b/frontend/rust-lib/flowy-grid/src/services/mod.rs index e051544839..6e670bae8c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/mod.rs @@ -2,6 +2,7 @@ mod util; mod block_manager; pub mod block_revision_editor; +pub mod cell; pub mod field; mod filter; pub mod grid_editor; 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 deleted file mode 100644 index 15368d42c3..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs +++ /dev/null @@ -1,305 +0,0 @@ -use crate::entities::FieldType; -use crate::services::field::*; -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 { - fn decode_cell_data( - &self, - cell_data: T, - decoded_field_type: &FieldType, - field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into; - - 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 - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct AnyCellData { - pub cell_data: String, - pub field_type: FieldType, -} - -impl std::str::FromStr for AnyCellData { - type Err = FlowyError; - - fn from_str(s: &str) -> Result { - let type_option_cell_data: AnyCellData = serde_json::from_str(s)?; - Ok(type_option_cell_data) - } -} - -impl std::convert::TryInto for String { - type Error = FlowyError; - - fn try_into(self) -> Result { - AnyCellData::from_str(&self) - } -} - -impl std::convert::TryFrom<&CellRevision> for AnyCellData { - type Error = FlowyError; - - fn try_from(value: &CellRevision) -> Result { - Self::from_str(&value.data) - } -} - -impl std::convert::TryFrom<&Option> for AnyCellData { - type Error = FlowyError; - - fn try_from(value: &Option) -> Result { - match value { - None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")), - Some(cell_rev) => AnyCellData::try_from(cell_rev), - } - } -} - -impl std::convert::TryFrom> for AnyCellData { - type Error = FlowyError; - - fn try_from(value: Option) -> Result { - Self::try_from(&value) - } -} - -impl AnyCellData { - pub fn new(content: String, field_type: FieldType) -> Self { - AnyCellData { - cell_data: content, - field_type, - } - } - - pub fn json(&self) -> String { - serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) - } - - pub fn is_number(&self) -> bool { - self.field_type == FieldType::Number - } - - pub fn is_text(&self) -> bool { - self.field_type == FieldType::RichText - } - - pub fn is_checkbox(&self) -> bool { - self.field_type == FieldType::Checkbox - } - - pub fn is_date(&self) -> bool { - self.field_type == FieldType::DateTime - } - - pub fn is_single_select(&self) -> bool { - self.field_type == FieldType::SingleSelect - } - - pub fn is_multi_select(&self) -> bool { - self.field_type == FieldType::MultiSelect - } - - pub fn is_url(&self) -> bool { - self.field_type == FieldType::URL - } - - pub fn is_select_option(&self) -> bool { - self.field_type == FieldType::MultiSelect || self.field_type == FieldType::SingleSelect - } -} - -/// 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>( - changeset: C, - cell_rev: Option, - field_rev: T, -) -> Result { - let field_rev = field_rev.as_ref(); - 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), - }?; - - Ok(AnyCellData::new(s, field_type).json()) -} - -pub fn decode_any_cell_data>(data: T, field_rev: &FieldRevision) -> DecodedCellData { - if let Ok(any_cell_data) = data.try_into() { - let AnyCellData { cell_data, field_type } = any_cell_data; - let to_field_type = field_rev.field_type_rev.into(); - match try_decode_cell_data(cell_data, field_rev, &field_type, &to_field_type) { - Ok(cell_data) => cell_data, - Err(e) => { - tracing::error!("Decode cell data failed, {:?}", e); - DecodedCellData::default() - } - } - } else { - tracing::error!("Decode type option data failed"); - DecodedCellData::default() - } -} - -pub fn try_decode_cell_data( - cell_data: String, - field_rev: &FieldRevision, - s_field_type: &FieldType, - t_field_type: &FieldType, -) -> FlowyResult { - let get_cell_data = || { - let field_type: FieldTypeRevision = t_field_type.into(); - let data = match t_field_type { - FieldType::RichText => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - FieldType::Number => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - FieldType::DateTime => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - FieldType::SingleSelect => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - FieldType::MultiSelect => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - FieldType::Checkbox => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - FieldType::URL => field_rev - .get_type_option_entry::(field_type)? - .decode_cell_data(cell_data, s_field_type, field_rev), - }; - Some(data) - }; - - match get_cell_data() { - Some(Ok(data)) => Ok(data), - Some(Err(err)) => { - tracing::error!("{:?}", err); - Ok(DecodedCellData::default()) - } - None => Ok(DecodedCellData::default()), - } -} - -pub(crate) struct EncodedCellData(pub Option); - -impl EncodedCellData { - pub fn try_into_inner(self) -> FlowyResult { - match self.0 { - None => Err(ErrorCode::InvalidData.into()), - Some(data) => Ok(data), - } - } -} - -impl std::convert::From for EncodedCellData -where - T: FromStr, -{ - fn from(s: String) -> Self { - match T::from_str(&s) { - Ok(inner) => EncodedCellData(Some(inner)), - Err(e) => { - tracing::error!("Deserialize Cell Data failed: {}", e); - EncodedCellData(None) - } - } - } -} - -/// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it. -/// -/// For example: -/// -/// * Use DateCellData to parse the data when the FieldType is Date. -/// * Use URLCellData to parse the data when the FieldType is URL. -/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox. -/// * Check out the implementation of CellDataOperation trait for more information. -#[derive(Default)] -pub struct DecodedCellData { - pub data: Vec, -} - -impl DecodedCellData { - pub fn new>(data: T) -> Self { - Self { - data: data.as_ref().to_vec(), - } - } - - pub fn try_from_bytes>(bytes: T) -> FlowyResult - where - >::Error: std::fmt::Debug, - { - let bytes = bytes.try_into().map_err(internal_error)?; - Ok(Self { data: bytes.to_vec() }) - } - - pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult - where - >::Error: std::fmt::Debug, - { - T::try_from(self.data.as_ref()).map_err(internal_error) - } -} - -impl ToString for DecodedCellData { - fn to_string(&self) -> String { - match String::from_utf8(self.data.clone()) { - Ok(s) => s, - Err(e) => { - tracing::error!("DecodedCellData to string failed: {:?}", e); - "".to_string() - } - } - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs index e2727cdf34..60c8421d15 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/mod.rs @@ -1,7 +1,5 @@ -mod cell_data_operation; mod row_builder; mod row_loader; -pub use cell_data_operation::*; pub use row_builder::*; pub(crate) use row_loader::*; 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..3302276cd8 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,5 +1,5 @@ -use crate::services::field::select_option::SelectOptionCellContentChangeset; -use crate::services::row::apply_cell_data_changeset; +use crate::services::cell::apply_cell_data_changeset; +use crate::services::field::select_option::SelectOptionCellChangeset; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT}; use indexmap::IndexMap; @@ -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_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs index c28c2a7537..73b24f9afd 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs @@ -4,9 +4,10 @@ use crate::grid::script::EditorScript::*; use crate::grid::script::*; use chrono::NaiveDateTime; use flowy_grid::entities::FieldType; +use flowy_grid::services::cell::decode_any_cell_data; use flowy_grid::services::field::select_option::SELECTION_IDS_SEPARATOR; use flowy_grid::services::field::{DateCellData, MultiSelectTypeOption, SingleSelectTypeOption}; -use flowy_grid::services::row::{decode_any_cell_data, CreateRowRevisionBuilder}; +use flowy_grid::services::row::CreateRowRevisionBuilder; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] 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, })