瀏覽代碼

refactor: cell data parser

appflowy 3 年之前
父節點
當前提交
4ec1e4024e

+ 10 - 1
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<AnyCellData> for SelectOptionIds {
     }
 }
 
+impl FromCellString for SelectOptionIds {
+    fn from_cell_str(s: &str) -> FlowyResult<Self>
+    where
+        Self: Sized,
+    {
+        Ok(Self::from(s.to_owned()))
+    }
+}
+
 impl std::convert::From<String> for SelectOptionIds {
     fn from(s: String) -> Self {
         let ids = s

+ 7 - 10
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<GridCheckboxFilter> for CheckboxTypeOption {
 }
 
 impl CellDataOperation<String> for CheckboxTypeOption {
-    fn decode_cell_data<T>(
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<String>,
         decoded_field_type: &FieldType,
         _field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<String>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         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())

+ 19 - 11
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<GridDateFilter> for DateTypeOption {
     }
 }
 
-impl CellDataOperation<String> for DateTypeOption {
-    fn decode_cell_data<T>(
+impl CellDataOperation<TimestampParser> for DateTypeOption {
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<TimestampParser>,
         decoded_field_type: &FieldType,
         _field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<String>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         // 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<String> for DateTypeOption {
         if !decoded_field_type.is_date() {
             return Ok(DecodedCellData::default());
         }
-
-        let timestamp = cell_data.into().parse::<i64>().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<String> for DateTypeOption {
     }
 }
 
+pub struct TimestampParser(i64);
+
+impl FromCellString for TimestampParser {
+    fn from_cell_str(s: &str) -> FlowyResult<Self>
+    where
+        Self: Sized,
+    {
+        let num = s.parse::<i64>().unwrap_or(0);
+        Ok(TimestampParser(num))
+    }
+}
 #[derive(Default)]
 pub struct DateTypeOptionBuilder(DateTypeOption);
 impl_into_box_type_option_builder!(DateTypeOptionBuilder);

+ 6 - 10
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<GridSelectOptionFilter> for MultiSelectTypeOption {
         Ok(filter.apply(&selected_options))
     }
 }
-impl CellDataOperation<String> for MultiSelectTypeOption {
-    fn decode_cell_data<T>(
+impl CellDataOperation<SelectOptionIds> for MultiSelectTypeOption {
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<SelectOptionIds>,
         decoded_field_type: &FieldType,
         _field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<String>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         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())

+ 5 - 8
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<GridNumberFilter> for NumberTypeOption {
 }
 
 impl CellDataOperation<String> for NumberTypeOption {
-    fn decode_cell_data<T>(
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<String>,
         decoded_field_type: &FieldType,
         _field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<String>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         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()),

+ 6 - 11
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<GridSelectOptionFilter> for SingleSelectTypeOption {
     }
 }
 
-impl CellDataOperation<String> for SingleSelectTypeOption {
-    fn decode_cell_data<T>(
+impl CellDataOperation<SelectOptionIds> for SingleSelectTypeOption {
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<SelectOptionIds>,
         decoded_field_type: &FieldType,
         _field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<String>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         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());

+ 6 - 8
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<GridTextFilter> for RichTextTypeOption {
 }
 
 impl CellDataOperation<String> for RichTextTypeOption {
-    fn decode_cell_data<T>(
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<String>,
         decoded_field_type: &FieldType,
         field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<String>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         if decoded_field_type.is_date()
             || decoded_field_type.is_single_select()
             || decoded_field_type.is_multi_select()
@@ -60,7 +58,7 @@ impl CellDataOperation<String> 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))
         }
     }

+ 11 - 16
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<GridTextFilter> for URLTypeOption {
     }
 }
 
-impl CellDataOperation<Parser<URLCellData>> for URLTypeOption {
-    fn decode_cell_data<T>(
+impl CellDataOperation<URLCellData> for URLTypeOption {
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<URLCellData>,
         decoded_field_type: &FieldType,
         _field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<Parser<URLCellData>>,
-    {
+    ) -> FlowyResult<DecodedCellData> {
         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<Self, Self::Err> {
+impl FromCellString for URLCellData {
+    fn from_cell_str(s: &str) -> FlowyResult<Self> {
         serde_json::from_str::<URLCellData>(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<T: Into<Parser<URLCellData>>>(
+    fn decode_cell_data<T: Into<CellData<URLCellData>>>(
         encoded_data: T,
         type_option: &URLTypeOption,
         field_rev: &FieldRevision,

+ 38 - 21
frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs

@@ -14,14 +14,12 @@ pub trait CellFilterOperation<T> {
 pub trait CellDataOperation<D> {
     /// The cell_data is able to parse into the specific data that was impl the From<String> trait.
     /// D will be URLCellData, DateCellData. etc.
-    fn decode_cell_data<T>(
+    fn decode_cell_data(
         &self,
-        cell_data: T,
+        cell_data: CellData<D>,
         decoded_field_type: &FieldType,
         field_rev: &FieldRevision,
-    ) -> FlowyResult<DecodedCellData>
-    where
-        T: Into<D>;
+    ) -> FlowyResult<DecodedCellData>;
 
     fn apply_changeset<C: Into<CellContentChangeset>>(
         &self,
@@ -178,7 +176,7 @@ pub fn decode_any_cell_data<T: TryInto<AnyCellData>>(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<T: TryInto<AnyCellData>>(data: T, field_rev: &FieldR
 }
 
 pub fn try_decode_cell_data(
-    cell_data: String,
+    cell_data: CellData<String>,
     field_rev: &FieldRevision,
     s_field_type: &FieldType,
     t_field_type: &FieldType,
 ) -> FlowyResult<DecodedCellData> {
+    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::<RichTextTypeOption>(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::<NumberTypeOption>(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::<DateTypeOption>(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::<SingleSelectTypeOption>(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::<MultiSelectTypeOption>(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::<CheckboxTypeOption>(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::<URLTypeOption>(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<T>(pub Option<T>);
+pub trait FromCellString {
+    fn from_cell_str(s: &str) -> FlowyResult<Self>
+    where
+        Self: Sized;
+}
+
+pub struct CellData<T>(pub Option<T>);
 
-impl<T> Parser<T> {
+impl<T> CellData<T> {
     pub fn try_into_inner(self) -> FlowyResult<T> {
         match self.0 {
             None => Err(ErrorCode::InvalidData.into()),
@@ -246,21 +251,33 @@ impl<T> Parser<T> {
     }
 }
 
-impl<T> std::convert::From<String> for Parser<T>
+impl<T> std::convert::From<String> for CellData<T>
 where
-    T: FromStr<Err = FlowyError>,
+    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<String> for CellData<String> {
+    fn from(s: String) -> Self {
+        CellData(Some(s))
+    }
+}
+
+impl std::convert::From<CellData<String>> for String {
+    fn from(p: CellData<String>) -> 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: