|
@@ -1,25 +1,32 @@
|
|
|
use crate::entities::FieldType;
|
|
|
use crate::services::cell::{CellBytes, TypeCellData};
|
|
|
use crate::services::field::*;
|
|
|
+use std::cmp::Ordering;
|
|
|
use std::fmt::Debug;
|
|
|
|
|
|
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
|
|
use grid_rev_model::{CellRevision, FieldRevision, FieldTypeRevision};
|
|
|
|
|
|
/// This trait is used when doing filter/search on the grid.
|
|
|
-pub trait CellFilterOperation<T> {
|
|
|
- /// Return true if any_cell_data match the filter condition.
|
|
|
- fn apply_filter(&self, any_cell_data: TypeCellData, filter: &T) -> FlowyResult<bool>;
|
|
|
+pub trait CellFilterable<T> {
|
|
|
+ /// Return true if type_cell_data match the filter condition.
|
|
|
+ fn apply_filter(&self, type_cell_data: TypeCellData, filter: &T) -> FlowyResult<bool>;
|
|
|
}
|
|
|
|
|
|
-pub trait CellGroupOperation {
|
|
|
- fn apply_group(&self, any_cell_data: TypeCellData, group_content: &str) -> FlowyResult<bool>;
|
|
|
+pub trait CellComparable {
|
|
|
+ fn apply_cmp(&self, type_cell_data: &TypeCellData, other_type_cell_data: &TypeCellData) -> FlowyResult<Ordering>;
|
|
|
}
|
|
|
|
|
|
-/// Return object that describes the cell.
|
|
|
-pub trait CellDisplayable<CD> {
|
|
|
+/// Serialize the cell data in Protobuf/String format.
|
|
|
+///
|
|
|
+/// Each cell data is a opaque data, it needs to deserialized to a concrete data struct.
|
|
|
+/// Essentially when the field type is SingleSelect/Multi-Select, the cell data contains a
|
|
|
+/// list of option ids. So it need to be decoded including convert the option's id to
|
|
|
+/// option's name
|
|
|
+///
|
|
|
+pub trait CellDataSerialize<CD> {
|
|
|
/// Serialize the cell data into `CellBytes` that will be posted to the `Dart` side. Using the
|
|
|
- /// corresponding protobuf struct implement in `Dart` to deserialize the data.
|
|
|
+ /// corresponding protobuf struct implemented in `Dart` to deserialize the data.
|
|
|
///
|
|
|
/// Using `utf8` to encode the cell data if the cell data use `String` as its data container.
|
|
|
/// Using `protobuf` to encode the cell data if the cell data use `Protobuf struct` as its data container.
|
|
@@ -43,9 +50,9 @@ pub trait CellDisplayable<CD> {
|
|
|
///
|
|
|
/// returns: Result<CellBytes, FlowyError>
|
|
|
///
|
|
|
- fn displayed_cell_bytes(
|
|
|
+ fn serialize_cell_data_to_bytes(
|
|
|
&self,
|
|
|
- cell_data: CellData<CD>,
|
|
|
+ cell_data: IntoCellData<CD>,
|
|
|
decoded_field_type: &FieldType,
|
|
|
field_rev: &FieldRevision,
|
|
|
) -> FlowyResult<CellBytes>;
|
|
@@ -55,14 +62,14 @@ pub trait CellDisplayable<CD> {
|
|
|
/// The cell data is not readable which means it can't display the cell data directly to user.
|
|
|
/// For example,
|
|
|
/// 1. the cell data is timestamp if its field type is FieldType::Date that is not readable.
|
|
|
- /// It needs to be parsed as the date string.
|
|
|
+ /// So it needs to be parsed as the date string with custom format setting.
|
|
|
///
|
|
|
/// 2. the cell data is a commas separated id if its field type if FieldType::MultiSelect that is not readable.
|
|
|
- /// It needs to be parsed as a commas separated option name.
|
|
|
+ /// So it needs to be parsed as a commas separated option name.
|
|
|
///
|
|
|
- fn displayed_cell_string(
|
|
|
+ fn serialize_cell_data_to_str(
|
|
|
&self,
|
|
|
- cell_data: CellData<CD>,
|
|
|
+ cell_data: IntoCellData<CD>,
|
|
|
decoded_field_type: &FieldType,
|
|
|
field_rev: &FieldRevision,
|
|
|
) -> FlowyResult<String>;
|
|
@@ -76,7 +83,10 @@ pub trait CellDataOperation<CD, CS> {
|
|
|
/// FieldType::URL => URLCellData
|
|
|
/// FieldType::Date=> DateCellData
|
|
|
///
|
|
|
- /// Each cell data is a opaque data, it needs to deserialized to a concrete data struct
|
|
|
+ /// Each cell data is a opaque data, it needs to deserialized to a concrete data struct.
|
|
|
+ /// Essentially when the field type is SingleSelect/Multi-Select, the cell data contains a
|
|
|
+ /// list of option ids. So it need to be decoded including convert the option's id to
|
|
|
+ /// option's name
|
|
|
///
|
|
|
/// `cell_data`: the opaque data of the cell.
|
|
|
/// `decoded_field_type`: the field type of the cell data when doing serialization
|
|
@@ -86,7 +96,7 @@ pub trait CellDataOperation<CD, CS> {
|
|
|
///
|
|
|
fn decode_cell_data(
|
|
|
&self,
|
|
|
- cell_data: CellData<CD>,
|
|
|
+ cell_data: IntoCellData<CD>,
|
|
|
decoded_field_type: &FieldType,
|
|
|
field_rev: &FieldRevision,
|
|
|
) -> FlowyResult<CellBytes>;
|
|
@@ -130,14 +140,14 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
|
|
|
Ok(TypeCellData::new(s, field_type).to_json())
|
|
|
}
|
|
|
|
|
|
-pub fn decode_any_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug>(
|
|
|
+pub fn decode_type_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug>(
|
|
|
data: T,
|
|
|
field_rev: &FieldRevision,
|
|
|
) -> (FieldType, CellBytes) {
|
|
|
let to_field_type = field_rev.ty.into();
|
|
|
match data.try_into() {
|
|
|
- Ok(any_cell_data) => {
|
|
|
- let TypeCellData { data, field_type } = any_cell_data;
|
|
|
+ Ok(type_cell_data) => {
|
|
|
+ let TypeCellData { data, field_type } = type_cell_data;
|
|
|
match try_decode_cell_data(data.into(), &field_type, &to_field_type, field_rev) {
|
|
|
Ok(cell_bytes) => (field_type, cell_bytes),
|
|
|
Err(e) => {
|
|
@@ -156,40 +166,40 @@ pub fn decode_any_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub fn decode_cell_data_to_string(
|
|
|
- cell_data: CellData<String>,
|
|
|
+pub fn decode_cell_data_to_string<C: Into<IntoCellData<String>>>(
|
|
|
+ cell_data: C,
|
|
|
from_field_type: &FieldType,
|
|
|
to_field_type: &FieldType,
|
|
|
field_rev: &FieldRevision,
|
|
|
) -> FlowyResult<String> {
|
|
|
- let cell_data = cell_data.try_into_inner()?;
|
|
|
+ let cell_data = cell_data.into().try_into_inner()?;
|
|
|
let get_cell_display_str = || {
|
|
|
let field_type: FieldTypeRevision = to_field_type.into();
|
|
|
let result = match to_field_type {
|
|
|
FieldType::RichText => field_rev
|
|
|
.get_type_option::<RichTextTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::Number => field_rev
|
|
|
.get_type_option::<NumberTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::DateTime => field_rev
|
|
|
.get_type_option::<DateTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::SingleSelect => field_rev
|
|
|
.get_type_option::<SingleSelectTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::MultiSelect => field_rev
|
|
|
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::Checklist => field_rev
|
|
|
.get_type_option::<ChecklistTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::Checkbox => field_rev
|
|
|
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
FieldType::URL => field_rev
|
|
|
.get_type_option::<URLTypeOptionPB>(field_type)?
|
|
|
- .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
|
|
|
+ .serialize_cell_data_to_str(cell_data.into(), from_field_type, field_rev),
|
|
|
};
|
|
|
Some(result)
|
|
|
};
|
|
@@ -210,7 +220,7 @@ pub fn decode_cell_data_to_string(
|
|
|
/// and `CellDataOperation` traits.
|
|
|
///
|
|
|
pub fn try_decode_cell_data(
|
|
|
- cell_data: CellData<String>,
|
|
|
+ cell_data: IntoCellData<String>,
|
|
|
from_field_type: &FieldType,
|
|
|
to_field_type: &FieldType,
|
|
|
field_rev: &FieldRevision,
|
|
@@ -312,9 +322,10 @@ pub trait FromCellString {
|
|
|
Self: Sized;
|
|
|
}
|
|
|
|
|
|
-/// CellData is a helper struct. String will be parser into Option<T> only if the T impl the FromCellString trait.
|
|
|
-pub struct CellData<T>(pub Option<T>);
|
|
|
-impl<T> CellData<T> {
|
|
|
+/// IntoCellData is a helper struct. String will be parser into Option<T> only if the T impl the FromCellString trait.
|
|
|
+///
|
|
|
+pub struct IntoCellData<T>(pub Option<T>);
|
|
|
+impl<T> IntoCellData<T> {
|
|
|
pub fn try_into_inner(self) -> FlowyResult<T> {
|
|
|
match self.0 {
|
|
|
None => Err(ErrorCode::InvalidData.into()),
|
|
@@ -323,35 +334,35 @@ impl<T> CellData<T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T> std::convert::From<String> for CellData<T>
|
|
|
+impl<T> std::convert::From<String> for IntoCellData<T>
|
|
|
where
|
|
|
T: FromCellString,
|
|
|
{
|
|
|
fn from(s: String) -> Self {
|
|
|
match T::from_cell_str(&s) {
|
|
|
- Ok(inner) => CellData(Some(inner)),
|
|
|
+ Ok(inner) => IntoCellData(Some(inner)),
|
|
|
Err(e) => {
|
|
|
tracing::error!("Deserialize Cell Data failed: {}", e);
|
|
|
- CellData(None)
|
|
|
+ IntoCellData(None)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl std::convert::From<usize> for CellData<String> {
|
|
|
+impl std::convert::From<usize> for IntoCellData<String> {
|
|
|
fn from(n: usize) -> Self {
|
|
|
- CellData(Some(n.to_string()))
|
|
|
+ IntoCellData(Some(n.to_string()))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T> std::convert::From<T> for CellData<T> {
|
|
|
+impl<T> std::convert::From<T> for IntoCellData<T> {
|
|
|
fn from(val: T) -> Self {
|
|
|
- CellData(Some(val))
|
|
|
+ IntoCellData(Some(val))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl std::convert::From<CellData<String>> for String {
|
|
|
- fn from(p: CellData<String>) -> Self {
|
|
|
+impl std::convert::From<IntoCellData<String>> for String {
|
|
|
+ fn from(p: IntoCellData<String>) -> Self {
|
|
|
p.try_into_inner().unwrap_or_else(|_| String::new())
|
|
|
}
|
|
|
}
|