2022-07-08 15:06:50 +08:00
|
|
|
use crate::entities::FieldType;
|
2022-07-12 22:24:01 +08:00
|
|
|
use crate::services::cell::{AnyCellData, CellBytes};
|
2022-07-08 15:06:50 +08:00
|
|
|
use crate::services::field::*;
|
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
|
|
|
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
|
|
|
|
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision};
|
|
|
|
|
|
|
|
/// This trait is used when doing filter/search on the grid.
|
2022-07-07 14:56:04 +08:00
|
|
|
pub trait CellFilterOperation<T> {
|
2022-07-08 15:06:50 +08:00
|
|
|
/// Return true if any_cell_data match the filter condition.
|
2022-07-07 14:56:04 +08:00
|
|
|
fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>;
|
2022-07-06 10:38:54 +08:00
|
|
|
}
|
|
|
|
|
2022-08-11 21:18:27 +08:00
|
|
|
pub trait CellGroupOperation {
|
|
|
|
fn apply_group(&self, any_cell_data: AnyCellData, group_content: &str) -> FlowyResult<bool>;
|
|
|
|
}
|
|
|
|
|
2022-07-12 22:24:01 +08:00
|
|
|
/// Return object that describes the cell.
|
2022-07-13 11:09:13 +08:00
|
|
|
pub trait CellDisplayable<CD> {
|
2022-07-12 22:24:01 +08:00
|
|
|
fn display_data(
|
|
|
|
&self,
|
|
|
|
cell_data: CellData<CD>,
|
|
|
|
decoded_field_type: &FieldType,
|
|
|
|
field_rev: &FieldRevision,
|
2022-07-13 11:09:13 +08:00
|
|
|
) -> FlowyResult<CellBytes>;
|
2022-07-12 22:24:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// CD: Short for CellData. This type is the type return by apply_changeset function.
|
|
|
|
// CS: Short for Changeset. Parse the string into specific Changeset type.
|
|
|
|
pub trait CellDataOperation<CD, CS> {
|
|
|
|
/// The cell_data is able to parse into the specific data if CD impl the FromCellData trait.
|
2022-07-08 14:54:11 +08:00
|
|
|
/// For example:
|
|
|
|
/// URLCellData, DateCellData. etc.
|
2022-07-08 13:06:06 +08:00
|
|
|
fn decode_cell_data(
|
2022-04-05 21:25:59 +08:00
|
|
|
&self,
|
2022-07-12 22:24:01 +08:00
|
|
|
cell_data: CellData<CD>,
|
2022-05-23 22:53:13 +08:00
|
|
|
decoded_field_type: &FieldType,
|
2022-06-15 15:13:50 +08:00
|
|
|
field_rev: &FieldRevision,
|
2022-07-12 22:24:01 +08:00
|
|
|
) -> FlowyResult<CellBytes>;
|
2022-06-30 23:00:03 +08:00
|
|
|
|
2022-07-12 22:24:01 +08:00
|
|
|
/// The changeset is able to parse into the specific data if CS impl the FromCellChangeset trait.
|
2022-07-08 14:54:11 +08:00
|
|
|
/// For example:
|
|
|
|
/// SelectOptionCellChangeset,DateCellChangeset. etc.
|
2022-07-12 22:24:01 +08:00
|
|
|
fn apply_changeset(&self, changeset: CellDataChangeset<CS>, 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,
|
2022-06-15 15:13:50 +08:00
|
|
|
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();
|
2022-08-19 11:56:47 +08:00
|
|
|
let field_type = field_rev.ty.into();
|
2022-07-01 20:32:11 +08:00
|
|
|
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)
|
|
|
|
}
|
2022-08-11 13:04:45 +08:00
|
|
|
FieldType::MultiSelect => MultiSelectTypeOptionPB::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
|
|
|
}?;
|
|
|
|
|
2022-07-06 10:38:54 +08:00
|
|
|
Ok(AnyCellData::new(s, field_type).json())
|
2022-03-15 11:07:18 +08:00
|
|
|
}
|
2022-05-09 16:08:27 +08:00
|
|
|
|
2022-09-24 15:57:40 +08:00
|
|
|
pub fn decode_any_cell_data<T: TryInto<AnyCellData, Error = FlowyError> + Debug>(
|
|
|
|
data: T,
|
|
|
|
field_rev: &FieldRevision,
|
|
|
|
) -> CellBytes {
|
|
|
|
match data.try_into() {
|
|
|
|
Ok(any_cell_data) => {
|
|
|
|
let AnyCellData { data, field_type } = any_cell_data;
|
|
|
|
let to_field_type = field_rev.ty.into();
|
|
|
|
match try_decode_cell_data(data.into(), field_rev, &field_type, &to_field_type) {
|
|
|
|
Ok(cell_bytes) => cell_bytes,
|
|
|
|
Err(e) => {
|
|
|
|
tracing::error!("Decode cell data failed, {:?}", e);
|
|
|
|
CellBytes::default()
|
|
|
|
}
|
2022-05-28 15:30:15 +08:00
|
|
|
}
|
|
|
|
}
|
2022-09-24 15:57:40 +08:00
|
|
|
Err(err) => {
|
|
|
|
tracing::error!(
|
|
|
|
"Decode type option data to type: {} failed: {:?}",
|
|
|
|
std::any::type_name::<T>(),
|
|
|
|
err,
|
|
|
|
);
|
|
|
|
CellBytes::default()
|
|
|
|
}
|
2022-05-24 14:56:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 23:00:03 +08:00
|
|
|
pub fn try_decode_cell_data(
|
2022-07-08 13:06:06 +08:00
|
|
|
cell_data: CellData<String>,
|
2022-06-24 18:13:40 +08:00
|
|
|
field_rev: &FieldRevision,
|
2022-05-24 14:56:55 +08:00
|
|
|
s_field_type: &FieldType,
|
|
|
|
t_field_type: &FieldType,
|
2022-07-12 22:24:01 +08:00
|
|
|
) -> FlowyResult<CellBytes> {
|
2022-07-08 13:06:06 +08:00
|
|
|
let cell_data = cell_data.try_into_inner()?;
|
2022-05-24 14:56:55 +08:00
|
|
|
let get_cell_data = || {
|
2022-07-06 10:38:54 +08:00
|
|
|
let field_type: FieldTypeRevision = t_field_type.into();
|
2022-05-24 14:56:55 +08:00
|
|
|
let data = match t_field_type {
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::RichText => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<RichTextTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::Number => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<NumberTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::DateTime => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<DateTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::SingleSelect => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<SingleSelectTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::MultiSelect => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<MultiSelectTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::Checkbox => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<CheckboxTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-06-15 15:13:50 +08:00
|
|
|
FieldType::URL => field_rev
|
2022-09-02 09:49:26 +08:00
|
|
|
.get_type_option::<URLTypeOptionPB>(field_type)?
|
2022-07-08 13:06:06 +08:00
|
|
|
.decode_cell_data(cell_data.into(), s_field_type, field_rev),
|
2022-05-22 23:33:08 +08:00
|
|
|
};
|
2022-05-24 14:56:55 +08:00
|
|
|
Some(data)
|
|
|
|
};
|
|
|
|
|
|
|
|
match get_cell_data() {
|
2022-05-28 15:30:15 +08:00
|
|
|
Some(Ok(data)) => Ok(data),
|
2022-05-24 14:56:55 +08:00
|
|
|
Some(Err(err)) => {
|
|
|
|
tracing::error!("{:?}", err);
|
2022-07-12 22:24:01 +08:00
|
|
|
Ok(CellBytes::default())
|
2022-05-24 14:56:55 +08:00
|
|
|
}
|
2022-07-12 22:24:01 +08:00
|
|
|
None => Ok(CellBytes::default()),
|
2022-05-24 14:56:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-14 11:05: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 {
|
|
|
|
let cell_data = serde_json::to_string(&DateCellChangesetPB {
|
|
|
|
date: Some(timestamp.to_string()),
|
|
|
|
time: None,
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
|
|
|
|
CellRevision::new(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn insert_select_option_cell(option_id: String, field_rev: &FieldRevision) -> CellRevision {
|
|
|
|
let cell_data = SelectOptionCellChangeset::from_insert(&option_id).to_str();
|
|
|
|
let data = apply_cell_data_changeset(cell_data, None, field_rev).unwrap();
|
|
|
|
CellRevision::new(data)
|
|
|
|
}
|
|
|
|
|
2022-08-30 15:21:53 +08:00
|
|
|
pub fn delete_select_option_cell(option_id: String, field_rev: &FieldRevision) -> CellRevision {
|
|
|
|
let cell_data = SelectOptionCellChangeset::from_delete(&option_id).to_str();
|
|
|
|
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-07-12 15:49:14 +08:00
|
|
|
/// CellData is a helper struct. String will be parser into Option<T> only if the T impl the FromCellString trait.
|
2022-07-08 13:06:06 +08:00
|
|
|
pub struct CellData<T>(pub Option<T>);
|
|
|
|
impl<T> CellData<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-07-08 13:06:06 +08:00
|
|
|
impl<T> std::convert::From<String> for CellData<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) {
|
|
|
|
Ok(inner) => CellData(Some(inner)),
|
2022-05-24 14:56:55 +08:00
|
|
|
Err(e) => {
|
|
|
|
tracing::error!("Deserialize Cell Data failed: {}", e);
|
2022-07-08 13:06:06 +08:00
|
|
|
CellData(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-07-13 17:25:03 +08:00
|
|
|
impl<T> std::convert::From<T> for CellData<T> {
|
|
|
|
fn from(val: T) -> Self {
|
|
|
|
CellData(Some(val))
|
2022-07-08 13:06:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::convert::From<CellData<String>> for String {
|
|
|
|
fn from(p: CellData<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;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CellDataChangeset<T>(pub Option<T>);
|
|
|
|
|
|
|
|
impl<T> CellDataChangeset<T> {
|
|
|
|
pub fn try_into_inner(self) -> FlowyResult<T> {
|
|
|
|
match self.0 {
|
|
|
|
None => Err(ErrorCode::InvalidData.into()),
|
|
|
|
Some(data) => Ok(data),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, C: ToString> std::convert::From<C> for CellDataChangeset<T>
|
|
|
|
where
|
|
|
|
T: FromCellChangeset,
|
|
|
|
{
|
|
|
|
fn from(changeset: C) -> Self {
|
|
|
|
match T::from_changeset(changeset.to_string()) {
|
|
|
|
Ok(data) => CellDataChangeset(Some(data)),
|
|
|
|
Err(e) => {
|
|
|
|
tracing::error!("Deserialize CellDataChangeset failed: {}", e);
|
|
|
|
CellDataChangeset(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl std::convert::From<String> for CellDataChangeset<String> {
|
|
|
|
fn from(s: String) -> Self {
|
|
|
|
CellDataChangeset(Some(s))
|
2022-07-08 13:06:06 +08:00
|
|
|
}
|
|
|
|
}
|