From 4ec1e4024e2b6ad7bd5b4a506e70a435013eb497 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 8 Jul 2022 13:06:06 +0800 Subject: [PATCH] refactor: cell data parser --- .../src/services/field/select_option.rs | 11 +++- .../type_options/checkbox_type_option.rs | 17 +++--- .../field/type_options/date_type_option.rs | 30 ++++++---- .../type_options/multi_select_type_option.rs | 16 ++--- .../number_type_option/number_type_option.rs | 13 ++-- .../type_options/single_select_type_option.rs | 17 ++---- .../field/type_options/text_type_option.rs | 14 ++--- .../field/type_options/url_type_option.rs | 27 ++++----- .../src/services/row/cell_data_operation.rs | 59 ++++++++++++------- 9 files changed, 108 insertions(+), 96 deletions(-) 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..57f130cc47 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,6 +1,6 @@ use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; -use crate::services::row::AnyCellData; +use crate::services::row::{AnyCellData, FromCellString}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::parser::NotEmptyStr; @@ -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 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..36d8a95082 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,7 @@ 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, + AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -53,22 +53,19 @@ impl CellFilterOperation for CheckboxTypeOption { } impl CellDataOperation for CheckboxTypeOption { - fn decode_cell_data( + 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()) 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..4623633ed8 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,7 +3,8 @@ 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, + AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, + FromCellString, }; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; @@ -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,9 +141,8 @@ 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) } @@ -170,6 +167,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); 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..6c12ce8ea0 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 @@ -8,7 +8,7 @@ use crate::services::field::select_option::{ 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, + AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -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()) 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..5bcc0a0dc6 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, CellDataOperation, CellFilterOperation, DecodedCellData, + AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -119,20 +119,17 @@ impl CellFilterOperation for NumberTypeOption { } impl CellDataOperation for NumberTypeOption { - fn decode_cell_data( + 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()), 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..e8ecf98d52 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 @@ -6,7 +6,7 @@ use crate::services::field::select_option::{ }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - AnyCellData, CellContentChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, + AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -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()); 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..83401314fe 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,8 @@ 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, + try_decode_cell_data, AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, + DecodedCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -44,15 +45,12 @@ impl CellFilterOperation for RichTextTypeOption { } impl CellDataOperation for RichTextTypeOption { - fn decode_cell_data( + 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() @@ -60,7 +58,7 @@ impl CellDataOperation for RichTextTypeOption { { try_decode_cell_data(cell_data.into(), 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)) } } 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 b87e20e666..b41631c649 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,7 +2,8 @@ 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, Parser, + AnyCellData, CellContentChangeset, CellData, CellDataOperation, CellFilterOperation, DecodedCellData, + FromCellString, }; use bytes::Bytes; use fancy_regex::Regex; @@ -11,7 +12,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,20 +46,17 @@ 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) } @@ -118,10 +115,8 @@ 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) } } @@ -152,7 +147,7 @@ mod tests { use crate::entities::FieldType; use crate::services::field::FieldBuilder; use crate::services::field::{URLCellData, URLTypeOption}; - use crate::services::row::{CellDataOperation, Parser}; + use crate::services::row::{CellData, CellDataOperation}; use flowy_grid_data_model::revision::FieldRevision; #[test] @@ -201,7 +196,7 @@ mod tests { 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, 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 5ec0efb906..f9b5f461fa 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 @@ -14,14 +14,12 @@ pub trait CellFilterOperation { 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. - fn decode_cell_data( + fn decode_cell_data( &self, - cell_data: T, + cell_data: CellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, - ) -> FlowyResult - where - T: Into; + ) -> FlowyResult; fn apply_changeset>( &self, @@ -178,7 +176,7 @@ pub fn decode_any_cell_data>(data: T, field_rev: &FieldR 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) { + 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); @@ -192,35 +190,36 @@ pub fn decode_any_cell_data>(data: T, field_rev: &FieldR } pub fn try_decode_cell_data( - cell_data: String, + 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, s_field_type, field_rev), + .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, s_field_type, field_rev), + .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, s_field_type, field_rev), + .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, s_field_type, field_rev), + .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, s_field_type, field_rev), + .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, s_field_type, field_rev), + .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, s_field_type, field_rev), + .decode_cell_data(cell_data.into(), s_field_type, field_rev), }; Some(data) }; @@ -235,9 +234,15 @@ pub fn try_decode_cell_data( } } -pub(crate) struct Parser(pub Option); +pub trait FromCellString { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized; +} -impl Parser { +pub struct CellData(pub Option); + +impl CellData { pub fn try_into_inner(self) -> FlowyResult { match self.0 { None => Err(ErrorCode::InvalidData.into()), @@ -246,21 +251,33 @@ impl Parser { } } -impl std::convert::From for Parser +impl std::convert::From for CellData where - T: FromStr, + T: FromCellString, { fn from(s: String) -> Self { - match T::from_str(&s) { - Ok(inner) => Parser(Some(inner)), + match T::from_cell_str(&s) { + Ok(inner) => CellData(Some(inner)), Err(e) => { tracing::error!("Deserialize Cell Data failed: {}", e); - Parser(None) + 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("".to_owned()) + } +} + /// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it. /// /// For example: