296 lines
11 KiB
Rust
Raw Normal View History

use crate::entities::FieldType;
2022-12-17 10:15:13 +08:00
use crate::services::cell::{CellProtobufBlob, TypeCellData};
use crate::services::field::*;
2022-12-17 10:15:13 +08:00
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use grid_rev_model::{CellRevision, FieldRevision};
2022-12-12 19:49:20 +08:00
use std::cmp::Ordering;
2022-09-24 15:57:40 +08:00
use std::fmt::Debug;
2022-03-15 11:07:18 +08:00
2022-07-12 22:24:01 +08:00
/// This trait is used when doing filter/search on the grid.
2022-12-17 10:15:13 +08:00
pub trait CellFilterable: TypeOptionConfiguration {
2022-12-12 17:36:36 +08:00
/// Return true if type_cell_data match the filter condition.
2022-12-17 10:15:13 +08:00
fn apply_filter(
&self,
type_cell_data: TypeCellData,
filter: &<Self as TypeOptionConfiguration>::CellFilterConfiguration,
) -> FlowyResult<bool>;
2022-07-06 10:38:54 +08:00
}
2022-12-12 17:36:36 +08:00
pub trait CellComparable {
2022-12-17 10:15:13 +08:00
type CellData;
fn apply_cmp(&self, cell_data: &Self::CellData, other_cell_data: &Self::CellData) -> Ordering;
2022-08-11 21:18:27 +08:00
}
2022-12-17 10:15:13 +08:00
/// Decode the opaque cell data into readable format content
pub trait CellDataDecoder: TypeOption {
2022-10-12 21:52:02 +08:00
///
2022-12-17 10:15:13 +08:00
/// Tries to decode the opaque cell data to `decoded_field_type`. Sometimes, the `field_type`
/// of the `FieldRevision` is not equal to the `decoded_field_type`(This happened When switching
/// the field type of the `FieldRevision` to another field type). So the cell data is need to do
/// some transformation.
2022-10-12 21:52:02 +08:00
///
/// For example, the current field type of the `FieldRevision` is a checkbox. When switching the field
2022-12-17 10:15:13 +08:00
/// type from the checkbox to single select, it will create two new options,`Yes` and `No`, if they don't exist.
/// But the data of the cell doesn't change. We can't iterate all the rows to transform the cell
/// data that can be parsed by the current field type. One approach is to transform the cell data
/// when it get read. For the moment, the cell data is a string, `Yes` or `No`. It needs to compare
/// with the option's name, if match return the id of the option.
fn try_decode_cell_data(
2022-07-12 22:24:01 +08:00
&self,
2022-12-17 10:15:13 +08:00
cell_data: String,
2022-07-12 22:24:01 +08:00
decoded_field_type: &FieldType,
field_rev: &FieldRevision,
2022-12-17 10:15:13 +08:00
) -> FlowyResult<<Self as TypeOption>::CellData>;
2022-12-17 10:15:13 +08:00
/// Same as `decode_cell_data` does but Decode the cell data to readable `String`
fn decode_cell_data_to_str(
&self,
2022-12-17 10:15:13 +08:00
cell_data: String,
decoded_field_type: &FieldType,
field_rev: &FieldRevision,
) -> FlowyResult<String>;
2022-07-12 22:24:01 +08:00
}
2022-12-17 10:15:13 +08:00
pub trait CellDataChangeset: TypeOption {
/// The changeset is able to parse into the concrete data struct if `TypeOption::CellChangeset`
/// implements the `FromCellChangeset` trait.
/// For example,the SelectOptionCellChangeset,DateCellChangeset. etc.
2022-10-12 21:52:02 +08:00
///
2022-12-17 10:15:13 +08:00
fn apply_changeset(
&self,
changeset: AnyCellChangeset<<Self as TypeOption>::CellChangeset>,
cell_rev: Option<CellRevision>,
) -> FlowyResult<String>;
2022-03-15 11:07:18 +08:00
}
2022-07-12 22:24:01 +08:00
2022-07-12 15:49:14 +08:00
/// changeset: It will be deserialized into specific data base on the FieldType.
/// For example,
/// FieldType::RichText => String
/// FieldType::SingleSelect => SelectOptionChangeset
///
/// cell_rev: It will be None if the cell does not contain any data.
2022-07-08 14:54:11 +08:00
pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
2022-07-01 10:36:07 +08:00
changeset: C,
cell_rev: Option<CellRevision>,
2022-07-01 10:36:07 +08:00
field_rev: T,
2022-04-05 21:25:59 +08:00
) -> Result<String, FlowyError> {
2022-07-01 10:36:07 +08:00
let field_rev = field_rev.as_ref();
2022-07-08 14:54:11 +08:00
let changeset = changeset.to_string();
let field_type = field_rev.ty.into();
let s = match field_type {
2022-08-11 21:18:27 +08:00
FieldType::RichText => RichTextTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::Number => NumberTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
FieldType::DateTime => DateTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
2022-07-17 13:38:53 +08:00
FieldType::SingleSelect => {
SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
}
FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
2022-11-29 22:40:49 +08:00
FieldType::Checklist => ChecklistTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
2022-08-12 09:49:07 +08:00
FieldType::Checkbox => CheckboxTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
2022-08-11 21:18:27 +08:00
FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
2022-05-22 23:33:08 +08:00
}?;
Ok(TypeCellData::new(s, field_type).to_json())
2022-03-15 11:07:18 +08:00
}
2022-05-09 16:08:27 +08:00
2022-12-12 17:36:36 +08:00
pub fn decode_type_cell_data<T: TryInto<TypeCellData, Error = FlowyError> + Debug>(
2022-09-24 15:57:40 +08:00
data: T,
field_rev: &FieldRevision,
2022-12-17 10:15:13 +08:00
) -> (FieldType, CellProtobufBlob) {
let to_field_type = field_rev.ty.into();
2022-09-24 15:57:40 +08:00
match data.try_into() {
2022-12-12 17:36:36 +08:00
Ok(type_cell_data) => {
let TypeCellData { data, field_type } = type_cell_data;
2022-12-17 10:15:13 +08:00
match try_decode_cell_data(data, &field_type, &to_field_type, field_rev) {
Ok(cell_bytes) => (field_type, cell_bytes),
2022-09-24 15:57:40 +08:00
Err(e) => {
tracing::error!("Decode cell data failed, {:?}", e);
2022-12-17 10:15:13 +08:00
(field_type, CellProtobufBlob::default())
2022-09-24 15:57:40 +08:00
}
}
}
2022-09-24 21:48:48 +08:00
Err(_err) => {
// It's okay to ignore this error, because it's okay that the current cell can't
// display the existing cell data. For example, the UI of the text cell will be blank if
// the type of the data of cell is Number.
2022-12-17 10:15:13 +08:00
(to_field_type, CellProtobufBlob::default())
2022-09-24 15:57:40 +08:00
}
2022-05-24 14:56:55 +08:00
}
}
2022-12-17 10:15:13 +08:00
/// Decode the opaque cell data from one field type to another using the corresponding type option builder
///
/// The cell data might become an empty string depends on these two fields' `TypeOptionBuilder`
/// support transform or not.
///
/// # Arguments
///
/// * `cell_data`: the opaque cell data
/// * `from_field_type`: the original field type of the passed-in cell data. Check the `TypeCellData`
/// that is used to save the origin field type of the cell data.
/// * `to_field_type`: decode the passed-in cell data to this field type. It will use the to_field_type's
/// TypeOption to decode this cell data.
/// * `field_rev`: used to get the corresponding TypeOption for the specified field type.
2022-09-27 14:20:18 +08:00
///
2022-12-17 10:15:13 +08:00
/// returns: CellBytes
2022-09-27 14:20:18 +08:00
///
2022-06-30 23:00:03 +08:00
pub fn try_decode_cell_data(
2022-12-17 10:15:13 +08:00
cell_data: String,
2022-09-27 14:20:18 +08:00
from_field_type: &FieldType,
to_field_type: &FieldType,
2022-06-24 18:13:40 +08:00
field_rev: &FieldRevision,
2022-12-17 10:15:13 +08:00
) -> FlowyResult<CellProtobufBlob> {
match FieldRevisionExt::new(field_rev).get_type_option_handler(to_field_type) {
None => Ok(CellProtobufBlob::default()),
Some(handler) => handler.handle_cell_data(cell_data, from_field_type, field_rev),
}
}
2022-05-24 14:56:55 +08:00
2022-12-17 10:15:13 +08:00
pub fn stringify_cell_data(cell_data: String, field_type: &FieldType, field_rev: &FieldRevision) -> String {
match FieldRevisionExt::new(field_rev).get_type_option_handler(field_type) {
None => "".to_string(),
Some(handler) => handler.stringify_cell_data(cell_data, field_type, field_rev),
2022-05-24 14:56:55 +08:00
}
}
pub fn insert_text_cell(s: String, field_rev: &FieldRevision) -> CellRevision {
let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
CellRevision::new(data)
}
pub fn insert_number_cell(num: i64, field_rev: &FieldRevision) -> CellRevision {
let data = apply_cell_data_changeset(num, None, field_rev).unwrap();
CellRevision::new(data)
}
pub fn insert_url_cell(url: String, field_rev: &FieldRevision) -> CellRevision {
let data = apply_cell_data_changeset(url, None, field_rev).unwrap();
CellRevision::new(data)
}
pub fn insert_checkbox_cell(is_check: bool, field_rev: &FieldRevision) -> CellRevision {
let s = if is_check {
CHECK.to_string()
} else {
UNCHECK.to_string()
};
let data = apply_cell_data_changeset(s, None, field_rev).unwrap();
CellRevision::new(data)
}
pub fn insert_date_cell(timestamp: i64, field_rev: &FieldRevision) -> CellRevision {
2022-11-14 12:03:22 +08:00
let cell_data = serde_json::to_string(&DateCellChangeset {
date: Some(timestamp.to_string()),
time: None,
2022-11-14 12:03:22 +08:00
is_utc: true,
})
.unwrap();
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
CellRevision::new(data)
}
pub fn insert_select_option_cell(option_ids: Vec<String>, field_rev: &FieldRevision) -> CellRevision {
let cell_data = SelectOptionCellChangeset::from_insert_options(option_ids).to_str();
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
CellRevision::new(data)
}
pub fn delete_select_option_cell(option_ids: Vec<String>, field_rev: &FieldRevision) -> CellRevision {
let cell_data = SelectOptionCellChangeset::from_delete_options(option_ids).to_str();
2022-08-30 15:21:53 +08:00
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
CellRevision::new(data)
}
2022-07-12 15:49:14 +08:00
/// Deserialize the String into cell specific data type.
2022-07-08 13:06:06 +08:00
pub trait FromCellString {
fn from_cell_str(s: &str) -> FlowyResult<Self>
where
Self: Sized;
}
2022-12-17 10:15:13 +08:00
/// IntoCellData is a helper struct used to deserialize string into a specific data type that implements
/// the `FromCellString` trait.
2022-12-12 17:36:36 +08:00
///
pub struct IntoCellData<T>(pub Option<T>);
impl<T> IntoCellData<T> {
2022-05-24 14:56:55 +08:00
pub fn try_into_inner(self) -> FlowyResult<T> {
match self.0 {
None => Err(ErrorCode::InvalidData.into()),
Some(data) => Ok(data),
}
}
}
2022-12-12 17:36:36 +08:00
impl<T> std::convert::From<String> for IntoCellData<T>
2022-05-24 14:56:55 +08:00
where
2022-07-08 13:06:06 +08:00
T: FromCellString,
2022-05-24 14:56:55 +08:00
{
fn from(s: String) -> Self {
2022-07-08 13:06:06 +08:00
match T::from_cell_str(&s) {
2022-12-12 17:36:36 +08:00
Ok(inner) => IntoCellData(Some(inner)),
2022-05-24 14:56:55 +08:00
Err(e) => {
tracing::error!("Deserialize Cell Data failed: {}", e);
2022-12-12 17:36:36 +08:00
IntoCellData(None)
2022-05-24 14:56:55 +08:00
}
}
2022-05-22 23:33:08 +08:00
}
2022-03-15 11:07:18 +08:00
}
2022-05-11 11:34:13 +08:00
2022-12-12 17:36:36 +08:00
impl<T> std::convert::From<T> for IntoCellData<T> {
2022-07-13 17:25:03 +08:00
fn from(val: T) -> Self {
2022-12-12 17:36:36 +08:00
IntoCellData(Some(val))
2022-07-08 13:06:06 +08:00
}
}
2022-12-17 10:15:13 +08:00
impl std::convert::From<usize> for IntoCellData<String> {
fn from(n: usize) -> Self {
IntoCellData(Some(n.to_string()))
}
}
2022-12-12 17:36:36 +08:00
impl std::convert::From<IntoCellData<String>> for String {
fn from(p: IntoCellData<String>) -> Self {
2022-07-08 14:54:11 +08:00
p.try_into_inner().unwrap_or_else(|_| String::new())
}
}
2022-07-12 15:49:14 +08:00
/// If the changeset applying to the cell is not String type, it should impl this trait.
/// Deserialize the string into cell specific changeset.
2022-07-08 14:54:11 +08:00
pub trait FromCellChangeset {
fn from_changeset(changeset: String) -> FlowyResult<Self>
where
Self: Sized;
}
2022-11-14 12:03:22 +08:00
pub struct AnyCellChangeset<T>(pub Option<T>);
2022-07-08 14:54:11 +08:00
2022-11-14 12:03:22 +08:00
impl<T> AnyCellChangeset<T> {
2022-07-08 14:54:11 +08:00
pub fn try_into_inner(self) -> FlowyResult<T> {
match self.0 {
None => Err(ErrorCode::InvalidData.into()),
Some(data) => Ok(data),
}
}
}
2022-11-14 12:03:22 +08:00
impl<T, C: ToString> std::convert::From<C> for AnyCellChangeset<T>
2022-07-08 14:54:11 +08:00
where
T: FromCellChangeset,
{
fn from(changeset: C) -> Self {
match T::from_changeset(changeset.to_string()) {
2022-11-14 12:03:22 +08:00
Ok(data) => AnyCellChangeset(Some(data)),
2022-07-08 14:54:11 +08:00
Err(e) => {
tracing::error!("Deserialize CellDataChangeset failed: {}", e);
2022-11-14 12:03:22 +08:00
AnyCellChangeset(None)
2022-07-08 14:54:11 +08:00
}
}
}
}
2022-11-14 12:03:22 +08:00
impl std::convert::From<String> for AnyCellChangeset<String> {
2022-07-08 14:54:11 +08:00
fn from(s: String) -> Self {
2022-11-14 12:03:22 +08:00
AnyCellChangeset(Some(s))
2022-07-08 13:06:06 +08:00
}
}