chore: separate cell operation from row mod

This commit is contained in:
appflowy 2022-07-08 15:06:50 +08:00
parent 5177884b26
commit 45774093e1
19 changed files with 214 additions and 206 deletions

View File

@ -1,10 +1,10 @@
use crate::entities::*;
use crate::manager::GridManager;
use crate::services::cell::AnyCellData;
use crate::services::field::select_option::*;
use crate::services::field::{
default_type_option_builder_from_type, type_option_builder_from_json_str, DateChangesetParams, DateChangesetPayload,
};
use crate::services::row::AnyCellData;
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::FieldRevision;
use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams};

View File

@ -0,0 +1,151 @@
use crate::entities::FieldType;
use bytes::Bytes;
use flowy_error::{internal_error, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::CellRevision;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
/// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type.
/// When the type of field is changed, it's different from the field_type of AnyCellData.
/// So it will return an empty data. You could check the CellDataOperation trait for more information.
#[derive(Debug, Serialize, Deserialize)]
pub struct AnyCellData {
pub cell_data: String,
pub field_type: FieldType,
}
impl std::str::FromStr for AnyCellData {
type Err = FlowyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let type_option_cell_data: AnyCellData = serde_json::from_str(s)?;
Ok(type_option_cell_data)
}
}
impl std::convert::TryInto<AnyCellData> for String {
type Error = FlowyError;
fn try_into(self) -> Result<AnyCellData, Self::Error> {
AnyCellData::from_str(&self)
}
}
impl std::convert::TryFrom<&CellRevision> for AnyCellData {
type Error = FlowyError;
fn try_from(value: &CellRevision) -> Result<Self, Self::Error> {
Self::from_str(&value.data)
}
}
impl std::convert::TryFrom<&Option<CellRevision>> for AnyCellData {
type Error = FlowyError;
fn try_from(value: &Option<CellRevision>) -> Result<Self, Self::Error> {
match value {
None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")),
Some(cell_rev) => AnyCellData::try_from(cell_rev),
}
}
}
impl std::convert::TryFrom<Option<CellRevision>> for AnyCellData {
type Error = FlowyError;
fn try_from(value: Option<CellRevision>) -> Result<Self, Self::Error> {
Self::try_from(&value)
}
}
impl AnyCellData {
pub fn new(content: String, field_type: FieldType) -> Self {
AnyCellData {
cell_data: content,
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_url(&self) -> bool {
self.field_type == FieldType::URL
}
pub fn is_select_option(&self) -> bool {
self.field_type == FieldType::MultiSelect || self.field_type == FieldType::SingleSelect
}
}
/// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it.
///
/// For example:
///
/// * Use DateCellData to parse the data when the FieldType is Date.
/// * Use URLCellData to parse the data when the FieldType is URL.
/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox.
/// * Check out the implementation of CellDataOperation trait for more information.
#[derive(Default)]
pub struct DecodedCellData {
pub data: Vec<u8>,
}
impl DecodedCellData {
pub fn new<T: AsRef<[u8]>>(data: T) -> Self {
Self {
data: data.as_ref().to_vec(),
}
}
pub fn try_from_bytes<T: TryInto<Bytes>>(bytes: T) -> FlowyResult<Self>
where
<T as TryInto<Bytes>>::Error: std::fmt::Debug,
{
let bytes = bytes.try_into().map_err(internal_error)?;
Ok(Self { data: bytes.to_vec() })
}
pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>
where
<T as TryFrom<&'a [u8]>>::Error: std::fmt::Debug,
{
T::try_from(self.data.as_ref()).map_err(internal_error)
}
}
impl ToString for DecodedCellData {
fn to_string(&self) -> String {
match String::from_utf8(self.data.clone()) {
Ok(s) => s,
Err(e) => {
tracing::error!("DecodedCellData to string failed: {:?}", e);
"".to_string()
}
}
}
}

View File

@ -1,13 +1,12 @@
use crate::entities::FieldType;
use crate::services::field::*;
use bytes::Bytes;
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use crate::entities::FieldType;
use crate::services::cell::{AnyCellData, DecodedCellData};
use crate::services::field::*;
pub trait CellFilterOperation<T> {
/// Return true if any_cell_data match the filter condition.
fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult<bool>;
}
@ -27,105 +26,6 @@ pub trait CellDataOperation<D, C> {
/// SelectOptionCellChangeset,DateCellChangeset. etc.
fn apply_changeset(&self, changeset: CellDataChangeset<C>, cell_rev: Option<CellRevision>) -> FlowyResult<String>;
}
/// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type.
/// When the type of field is changed, it's different from the field_type of AnyCellData.
/// So it will return an empty data. You could check the CellDataOperation trait for more information.
#[derive(Debug, Serialize, Deserialize)]
pub struct AnyCellData {
pub cell_data: String,
pub field_type: FieldType,
}
impl std::str::FromStr for AnyCellData {
type Err = FlowyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let type_option_cell_data: AnyCellData = serde_json::from_str(s)?;
Ok(type_option_cell_data)
}
}
impl std::convert::TryInto<AnyCellData> for String {
type Error = FlowyError;
fn try_into(self) -> Result<AnyCellData, Self::Error> {
AnyCellData::from_str(&self)
}
}
impl std::convert::TryFrom<&CellRevision> for AnyCellData {
type Error = FlowyError;
fn try_from(value: &CellRevision) -> Result<Self, Self::Error> {
Self::from_str(&value.data)
}
}
impl std::convert::TryFrom<&Option<CellRevision>> for AnyCellData {
type Error = FlowyError;
fn try_from(value: &Option<CellRevision>) -> Result<Self, Self::Error> {
match value {
None => Err(FlowyError::invalid_data().context("Expected CellRevision, but receive None")),
Some(cell_rev) => AnyCellData::try_from(cell_rev),
}
}
}
impl std::convert::TryFrom<Option<CellRevision>> for AnyCellData {
type Error = FlowyError;
fn try_from(value: Option<CellRevision>) -> Result<Self, Self::Error> {
Self::try_from(&value)
}
}
impl AnyCellData {
pub fn new(content: String, field_type: FieldType) -> Self {
AnyCellData {
cell_data: content,
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_url(&self) -> bool {
self.field_type == FieldType::URL
}
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<C: ToString, T: AsRef<FieldRevision>>(
@ -292,51 +192,3 @@ impl std::convert::From<String> for CellDataChangeset<String> {
CellDataChangeset(Some(s))
}
}
/// The data is encoded by protobuf or utf8. You should choose the corresponding decode struct to parse it.
///
/// For example:
///
/// * Use DateCellData to parse the data when the FieldType is Date.
/// * Use URLCellData to parse the data when the FieldType is URL.
/// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox.
/// * Check out the implementation of CellDataOperation trait for more information.
#[derive(Default)]
pub struct DecodedCellData {
pub data: Vec<u8>,
}
impl DecodedCellData {
pub fn new<T: AsRef<[u8]>>(data: T) -> Self {
Self {
data: data.as_ref().to_vec(),
}
}
pub fn try_from_bytes<T: TryInto<Bytes>>(bytes: T) -> FlowyResult<Self>
where
<T as TryInto<Bytes>>::Error: std::fmt::Debug,
{
let bytes = bytes.try_into().map_err(internal_error)?;
Ok(Self { data: bytes.to_vec() })
}
pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult<T>
where
<T as TryFrom<&'a [u8]>>::Error: std::fmt::Debug,
{
T::try_from(self.data.as_ref()).map_err(internal_error)
}
}
impl ToString for DecodedCellData {
fn to_string(&self) -> String {
match String::from_utf8(self.data.clone()) {
Ok(s) => s,
Err(e) => {
tracing::error!("DecodedCellData to string failed: {:?}", e);
"".to_string()
}
}
}
}

View File

@ -0,0 +1,5 @@
mod any_cell_data;
mod cell_operation;
pub use any_cell_data::*;
pub use cell_operation::*;

View File

@ -1,6 +1,6 @@
use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType};
use crate::services::cell::{AnyCellData, FromCellChangeset, FromCellString};
use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption};
use crate::services::row::{AnyCellData, FromCellChangeset, FromCellString};
use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::parser::NotEmptyStr;

View File

@ -1,10 +1,9 @@
use crate::entities::{FieldType, GridCheckboxFilter};
use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation,
DecodedCellData,
use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
@ -116,10 +115,9 @@ impl std::convert::TryFrom<AnyCellData> for CheckboxCellData {
#[cfg(test)]
mod tests {
use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data};
use crate::services::field::type_options::checkbox_type_option::{NO, YES};
use crate::services::field::FieldBuilder;
use crate::services::row::{apply_cell_data_changeset, decode_any_cell_data};
use crate::entities::FieldType;

View File

@ -1,11 +1,11 @@
use crate::entities::{CellChangeset, FieldType, GridDateFilter};
use crate::entities::{CellIdentifier, CellIdentifierPayload};
use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{
use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
FromCellChangeset, FromCellString,
};
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use bytes::Bytes;
use chrono::format::strftime::StrftimeItems;
use chrono::{NaiveDateTime, Timelike};
@ -377,9 +377,9 @@ impl FromCellChangeset for DateCellChangeset {
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::{CellDataChangeset, CellDataOperation};
use crate::services::field::FieldBuilder;
use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat};
use crate::services::row::{CellDataChangeset, CellDataOperation};
use flowy_grid_data_model::revision::FieldRevision;
use strum::IntoEnumIterator;

View File

@ -1,15 +1,15 @@
use crate::entities::{FieldType, GridSelectOptionFilter};
use crate::impl_type_option;
use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
use crate::services::field::select_option::{
make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds,
SelectOptionOperation, SelectedSelectOptions, SELECTION_IDS_SEPARATOR,
};
use crate::services::field::type_options::util::get_cell_data;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
@ -141,10 +141,10 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder {
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::CellDataOperation;
use crate::services::field::select_option::*;
use crate::services::field::FieldBuilder;
use crate::services::field::{MultiSelectTypeOption, MultiSelectTypeOptionBuilder};
use crate::services::row::CellDataOperation;
use flowy_grid_data_model::revision::FieldRevision;
#[test]

View File

@ -1,12 +1,12 @@
use crate::impl_type_option;
use crate::entities::{FieldType, GridNumberFilter};
use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
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, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
@ -136,8 +136,11 @@ impl CellDataOperation<String, String> for NumberTypeOption {
}
}
fn apply_changeset(&self, changeset: CellDataChangeset<String>, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
{
fn apply_changeset(
&self,
changeset: CellDataChangeset<String>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let changeset = changeset.try_into_inner()?;
let data = changeset.trim().to_string();
let _ = self.format_cell_data(&data)?;
@ -249,9 +252,9 @@ impl ToString for NumberCellData {
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::CellDataOperation;
use crate::services::field::FieldBuilder;
use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption};
use crate::services::row::CellDataOperation;
use flowy_grid_data_model::revision::FieldRevision;
use strum::IntoEnumIterator;

View File

@ -1,13 +1,13 @@
use crate::entities::{FieldType, GridSelectOptionFilter};
use crate::impl_type_option;
use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
use crate::services::field::select_option::{
make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds,
SelectOptionOperation,
};
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData,
};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
@ -122,10 +122,10 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder {
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::CellDataOperation;
use crate::services::field::select_option::*;
use crate::services::field::type_options::*;
use crate::services::field::FieldBuilder;
use crate::services::row::CellDataOperation;
use flowy_grid_data_model::revision::FieldRevision;
#[test]

View File

@ -1,10 +1,10 @@
use crate::entities::{FieldType, GridTextFilter};
use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{
use crate::services::cell::{
try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation,
DecodedCellData,
};
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use bytes::Bytes;
use flowy_derive::ProtoBuf;
use flowy_error::{FlowyError, FlowyResult};
@ -95,10 +95,10 @@ impl std::convert::TryFrom<AnyCellData> for TextCellData {
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::CellDataOperation;
use crate::services::field::select_option::*;
use crate::services::field::FieldBuilder;
use crate::services::field::*;
use crate::services::row::CellDataOperation;
#[test]
fn text_description_test() {

View File

@ -1,9 +1,9 @@
use crate::entities::{FieldType, GridTextFilter};
use crate::impl_type_option;
use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder};
use crate::services::row::{
use crate::services::cell::{
AnyCellData, CellData, CellDataChangeset, CellDataOperation, CellFilterOperation, DecodedCellData, FromCellString,
};
use crate::services::field::{BoxTypeOptionBuilder, TextCellData, TypeOptionBuilder};
use bytes::Bytes;
use fancy_regex::Regex;
use flowy_derive::ProtoBuf;
@ -59,8 +59,11 @@ impl CellDataOperation<URLCellData, String> for URLTypeOption {
DecodedCellData::try_from_bytes(cell_data)
}
fn apply_changeset(&self, changeset: CellDataChangeset<String>, _cell_rev: Option<CellRevision>) -> Result<String, FlowyError>
{
fn apply_changeset(
&self,
changeset: CellDataChangeset<String>,
_cell_rev: Option<CellRevision>,
) -> Result<String, FlowyError> {
let changeset = changeset.try_into_inner()?;
let mut url = "".to_string();
if let Ok(Some(m)) = URL_REGEX.find(&changeset) {
@ -118,17 +121,11 @@ impl FromCellString for URLCellData {
}
}
// impl std::convert::From<AnyCellData> for URLCellData {
// fn from(any_cell_data: AnyCellData) -> Self {
// URLCellData::from_str(&any_cell_data.cell_data).unwrap_or_default()
// }
// }
impl std::convert::TryFrom<AnyCellData> for URLCellData {
type Error = ();
type Error = FlowyError;
fn try_from(_value: AnyCellData) -> Result<Self, Self::Error> {
todo!()
fn try_from(data: AnyCellData) -> Result<Self, Self::Error> {
serde_json::from_str::<URLCellData>(&data.cell_data).map_err(internal_error)
}
}
@ -142,9 +139,9 @@ lazy_static! {
#[cfg(test)]
mod tests {
use crate::entities::FieldType;
use crate::services::cell::{CellData, CellDataOperation};
use crate::services::field::FieldBuilder;
use crate::services::field::{URLCellData, URLTypeOption};
use crate::services::row::{CellData, CellDataOperation};
use flowy_grid_data_model::revision::FieldRevision;
#[test]

View File

@ -1,4 +1,4 @@
use crate::services::row::AnyCellData;
use crate::services::cell::AnyCellData;
use flowy_grid_data_model::revision::CellRevision;
use std::str::FromStr;

View File

@ -1,6 +1,7 @@
use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::{FieldType, GridBlockChangeset};
use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{AnyCellData, CellFilterOperation};
use crate::services::field::{
CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption,
SingleSelectTypeOption, URLTypeOption,
@ -9,15 +10,13 @@ use crate::services::filter::filter_cache::{
reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
};
use crate::services::grid_editor_task::GridServiceTaskScheduler;
use crate::services::row::{AnyCellData, CellFilterOperation, GridBlockSnapshot};
use crate::services::row::GridBlockSnapshot;
use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
use flowy_sync::client_grid::GridRevisionPad;
use flowy_sync::entities::grid::GridSettingChangesetParams;
use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

View File

@ -1,13 +1,16 @@
use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::CellIdentifier;
use crate::entities::*;
use crate::manager::{GridTaskSchedulerRwLock, GridUser};
use crate::services::block_manager::GridBlockManager;
use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data};
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder};
use crate::services::filter::{GridFilterChangeset, GridFilterService};
use crate::services::persistence::block_index::BlockIndexCache;
use crate::services::row::*;
use crate::entities::*;
use crate::services::row::{
make_grid_blocks, make_row_from_row_rev, make_row_rev_from_context, make_rows_from_row_revs,
CreateRowRevisionBuilder, CreateRowRevisionPayload, GridBlockSnapshot,
};
use bytes::Bytes;
use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::revision::*;

View File

@ -2,6 +2,7 @@ mod util;
mod block_manager;
pub mod block_revision_editor;
pub mod cell;
pub mod field;
mod filter;
pub mod grid_editor;

View File

@ -1,7 +1,5 @@
mod cell_data_operation;
mod row_builder;
mod row_loader;
pub use cell_data_operation::*;
pub use row_builder::*;
pub(crate) use row_loader::*;

View File

@ -1,5 +1,5 @@
use crate::services::cell::apply_cell_data_changeset;
use crate::services::field::select_option::SelectOptionCellChangeset;
use crate::services::row::apply_cell_data_changeset;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT};
use indexmap::IndexMap;

View File

@ -4,9 +4,10 @@ use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use chrono::NaiveDateTime;
use flowy_grid::entities::FieldType;
use flowy_grid::services::cell::decode_any_cell_data;
use flowy_grid::services::field::select_option::SELECTION_IDS_SEPARATOR;
use flowy_grid::services::field::{DateCellData, MultiSelectTypeOption, SingleSelectTypeOption};
use flowy_grid::services::row::{decode_any_cell_data, CreateRowRevisionBuilder};
use flowy_grid::services::row::CreateRowRevisionBuilder;
use flowy_grid_data_model::revision::RowMetaChangeset;
#[tokio::test]