use crate::services::field::*; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{CellMeta, FieldMeta, FieldType}; use serde::{Deserialize, Serialize}; use std::fmt::Formatter; use std::str::FromStr; pub trait CellDataOperation { fn decode_cell_data( &self, encoded_data: T, decoded_field_type: &FieldType, field_meta: &FieldMeta, ) -> FlowyResult where T: Into; // fn apply_changeset>( &self, changeset: C, cell_meta: 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 TypeOptionCellData { pub data: String, pub field_type: FieldType, } impl TypeOptionCellData { pub fn split(self) -> (String, FieldType) { (self.data, self.field_type) } } impl std::str::FromStr for TypeOptionCellData { type Err = FlowyError; fn from_str(s: &str) -> Result { let type_option_cell_data: TypeOptionCellData = serde_json::from_str(s)?; Ok(type_option_cell_data) } } impl std::convert::TryInto for String { type Error = FlowyError; fn try_into(self) -> Result { TypeOptionCellData::from_str(&self) } } impl TypeOptionCellData { pub fn new(data: T, field_type: FieldType) -> Self { TypeOptionCellData { data: data.to_string(), 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_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>( changeset: T, cell_meta: Option, field_meta: &FieldMeta, ) -> Result { let s = match field_meta.field_type { FieldType::RichText => RichTextTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), FieldType::Number => NumberTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), FieldType::DateTime => DateTypeOption::from(field_meta) .apply_changeset(changeset, cell_meta) .map(|data| data.to_string()), FieldType::SingleSelect => SingleSelectTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), FieldType::MultiSelect => MultiSelectTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), FieldType::Checkbox => CheckboxTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), }?; Ok(TypeOptionCellData::new(s, field_meta.field_type.clone()).json()) } pub fn decode_cell_data_from_type_option_cell_data>( data: T, field_meta: &FieldMeta, field_type: &FieldType, ) -> DecodedCellData { if let Ok(type_option_cell_data) = data.try_into() { let (encoded_data, s_field_type) = type_option_cell_data.split(); decode_cell_data(encoded_data, &s_field_type, field_type, field_meta).unwrap_or_default() } else { DecodedCellData::default() } } pub fn decode_cell_data>( encoded_data: T, s_field_type: &FieldType, t_field_type: &FieldType, field_meta: &FieldMeta, ) -> FlowyResult { let encoded_data = encoded_data.into(); let get_cell_data = || { let data = match t_field_type { FieldType::RichText => field_meta .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_meta), FieldType::Number => field_meta .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_meta), FieldType::DateTime => field_meta .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_meta), FieldType::SingleSelect => field_meta .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_meta), FieldType::MultiSelect => field_meta .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_meta), FieldType::Checkbox => field_meta .get_type_option_entry::(t_field_type)? .decode_cell_data(encoded_data, s_field_type, field_meta), }; Some(data) }; match get_cell_data() { Some(Ok(data)) => { tracing::Span::current().record( "content", &format!("{:?}: {}", field_meta.field_type, data.content).as_str(), ); 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) } } } } #[derive(Default)] pub struct DecodedCellData { raw: String, pub content: String, } impl DecodedCellData { pub fn from_content(content: String) -> Self { Self { raw: content.clone(), content, } } pub fn new(raw: String, content: String) -> Self { Self { raw, content } } pub fn split(self) -> (String, String) { (self.raw, self.content) } }