chore: add row test

This commit is contained in:
appflowy 2022-03-13 23:16:52 +08:00
parent 572e38ec1c
commit d101509b32
16 changed files with 191 additions and 164 deletions

View File

@ -24,7 +24,7 @@ pub(crate) async fn get_rows_handler(
) -> DataResult<RepeatedRow, FlowyError> { ) -> DataResult<RepeatedRow, FlowyError> {
let payload: QueryRowPayload = data.into_inner(); let payload: QueryRowPayload = data.into_inner();
let editor = manager.get_grid_editor(&payload.grid_id)?; let editor = manager.get_grid_editor(&payload.grid_id)?;
let repeated_row: RepeatedRow = editor.get_rows(Some(payload.row_orders)).await?.into(); let repeated_row: RepeatedRow = editor.get_rows(payload.row_orders).await?.into();
data_result(repeated_row) data_result(repeated_row)
} }
@ -50,10 +50,10 @@ pub(crate) async fn create_row_handler(
Ok(()) Ok(())
} }
#[tracing::instrument(level = "debug", skip(data, manager), err)] #[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn update_cell_handler( pub(crate) async fn update_cell_handler(
data: Data<Cell>, data: Data<Cell>,
manager: AppData<Arc<GridManager>>, _manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> { ) -> Result<(), FlowyError> {
let _cell: Cell = data.into_inner(); let _cell: Cell = data.into_inner();
// let editor = manager.get_grid_editor(id.as_ref())?; // let editor = manager.get_grid_editor(id.as_ref())?;

View File

@ -2,7 +2,7 @@ use crate::services::field::{
CheckboxDescription, DateDescription, DateFormat, MoneySymbol, MultiSelectDescription, NumberDescription, CheckboxDescription, DateDescription, DateFormat, MoneySymbol, MultiSelectDescription, NumberDescription,
RichTextDescription, SelectOption, SingleSelectDescription, TimeFormat, RichTextDescription, SelectOption, SingleSelectDescription, TimeFormat,
}; };
use flowy_grid_data_model::entities::{AnyData, Field, FieldType}; use flowy_grid_data_model::entities::{Field, FieldType};
pub struct FieldBuilder { pub struct FieldBuilder {
field: Field, field: Field,

View File

@ -2,12 +2,12 @@
use crate::impl_from_and_to_type_option; use crate::impl_from_and_to_type_option;
use crate::services::row::StringifyCellData; use crate::services::row::StringifyCellData;
use crate::services::util::*; use crate::services::util::*;
use bytes::Bytes;
use chrono::format::strftime::StrftimeItems; use chrono::format::strftime::StrftimeItems;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::FlowyError; use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{AnyData, Field, FieldType}; use flowy_grid_data_model::entities::{Field, FieldType};
use rust_decimal::Decimal; use rust_decimal::Decimal;
use rusty_money::{ use rusty_money::{
iso::{Currency, CNY, EUR, USD}, iso::{Currency, CNY, EUR, USD},
@ -25,12 +25,12 @@ pub struct RichTextDescription {
impl_from_and_to_type_option!(RichTextDescription, FieldType::RichText); impl_from_and_to_type_option!(RichTextDescription, FieldType::RichText);
impl StringifyCellData for RichTextDescription { impl StringifyCellData for RichTextDescription {
fn str_from_cell_data(&self, data: AnyData) -> String { fn str_from_cell_data(&self, data: String) -> String {
data.to_string() data
} }
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError> { fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(AnyData::from_str(self.field_type(), s)) Ok(s.to_owned())
} }
} }
@ -43,16 +43,16 @@ pub struct CheckboxDescription {
impl_from_and_to_type_option!(CheckboxDescription, FieldType::Checkbox); impl_from_and_to_type_option!(CheckboxDescription, FieldType::Checkbox);
impl StringifyCellData for CheckboxDescription { impl StringifyCellData for CheckboxDescription {
fn str_from_cell_data(&self, data: AnyData) -> String { fn str_from_cell_data(&self, data: String) -> String {
data.to_string() data
} }
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError> { fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
let s = match string_to_bool(s) { let s = match string_to_bool(s) {
true => "1", true => "1",
false => "0", false => "0",
}; };
Ok(AnyData::from_str(self.field_type(), s)) Ok(s.to_owned())
} }
} }
@ -89,30 +89,24 @@ impl DateDescription {
} }
impl StringifyCellData for DateDescription { impl StringifyCellData for DateDescription {
fn str_from_cell_data(&self, data: AnyData) -> String { fn str_from_cell_data(&self, data: String) -> String {
match String::from_utf8(data.value) { match data.parse::<i64>() {
Ok(s) => match s.parse::<i64>() { Ok(timestamp) => {
Ok(timestamp) => { let native = NaiveDateTime::from_timestamp(timestamp, 0);
let native = NaiveDateTime::from_timestamp(timestamp, 0); self.today_from_native(native)
self.today_from_native(native) }
}
Err(e) => {
tracing::debug!("DateDescription format {} fail. error: {:?}", s, e);
String::new()
}
},
Err(e) => { Err(e) => {
tracing::error!("DateDescription stringify any_data failed. {:?}", e); tracing::debug!("DateDescription format {} fail. error: {:?}", data, e);
String::new() String::new()
} }
} }
} }
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError> { fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
let timestamp = s let timestamp = s
.parse::<i64>() .parse::<i64>()
.map_err(|e| FlowyError::internal().context(format!("Parse {} to i64 failed: {}", s, e)))?; .map_err(|e| FlowyError::internal().context(format!("Parse {} to i64 failed: {}", s, e)))?;
Ok(AnyData::from_str(self.field_type(), &format!("{}", timestamp))) Ok(format!("{}", timestamp))
} }
} }
@ -210,12 +204,12 @@ pub struct SingleSelectDescription {
impl_from_and_to_type_option!(SingleSelectDescription, FieldType::SingleSelect); impl_from_and_to_type_option!(SingleSelectDescription, FieldType::SingleSelect);
impl StringifyCellData for SingleSelectDescription { impl StringifyCellData for SingleSelectDescription {
fn str_from_cell_data(&self, data: AnyData) -> String { fn str_from_cell_data(&self, data: String) -> String {
data.to_string() data
} }
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError> { fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(AnyData::from_str(self.field_type(), s)) Ok(s.to_owned())
} }
} }
@ -230,12 +224,12 @@ pub struct MultiSelectDescription {
} }
impl_from_and_to_type_option!(MultiSelectDescription, FieldType::MultiSelect); impl_from_and_to_type_option!(MultiSelectDescription, FieldType::MultiSelect);
impl StringifyCellData for MultiSelectDescription { impl StringifyCellData for MultiSelectDescription {
fn str_from_cell_data(&self, data: AnyData) -> String { fn str_from_cell_data(&self, data: String) -> String {
data.to_string() data
} }
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError> { fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
Ok(AnyData::from_str(self.field_type(), s)) Ok(s.to_owned())
} }
} }
@ -322,24 +316,17 @@ impl NumberDescription {
} }
impl StringifyCellData for NumberDescription { impl StringifyCellData for NumberDescription {
fn str_from_cell_data(&self, data: AnyData) -> String { fn str_from_cell_data(&self, data: String) -> String {
match String::from_utf8(data.value) { match self.money_from_str(&data) {
Ok(s) => match self.money_from_str(&s) { Some(money_str) => money_str,
Some(money_str) => money_str, None => String::default(),
None => String::default(),
},
Err(e) => {
tracing::error!("NumberDescription stringify any_data failed. {:?}", e);
String::new()
}
} }
} }
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError> { fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError> {
let strip_symbol_money = strip_money_symbol(s); let strip_symbol_money = strip_money_symbol(s);
let decimal = Decimal::from_str(&strip_symbol_money).map_err(|err| FlowyError::internal().context(err))?; let decimal = Decimal::from_str(&strip_symbol_money).map_err(|err| FlowyError::internal().context(err))?;
let money_str = decimal.to_string(); Ok(decimal.to_string())
Ok(AnyData::from_str(self.field_type(), &money_str))
} }
} }

View File

@ -1,7 +1,7 @@
use crate::manager::GridUser; use crate::manager::GridUser;
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction}; use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
use crate::services::grid_meta_editor::{ClientGridBlockMetaEditor, GridBlockMetaEditorManager}; use crate::services::grid_meta_editor::GridBlockMetaEditorManager;
use bytes::Bytes; use bytes::Bytes;
use dashmap::DashMap; use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridChange, GridMetaPad}; use flowy_collaboration::client_grid::{GridChange, GridMetaPad};
@ -9,13 +9,10 @@ use flowy_collaboration::entities::revision::Revision;
use flowy_collaboration::util::make_delta_from_revisions; use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{ use flowy_grid_data_model::entities::{
Field, FieldChangeset, Grid, GridBlock, GridBlockChangeset, RepeatedField, RepeatedFieldOrder, RepeatedRow, Field, FieldChangeset, Grid, GridBlock, GridBlockChangeset, RepeatedFieldOrder, RepeatedRowOrder, Row,
RepeatedRowOrder, Row,
};
use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
use flowy_sync::{
RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
}; };
use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
use lib_infra::future::FutureResult; use lib_infra::future::FutureResult;
use lib_ot::core::PlainTextAttributes; use lib_ot::core::PlainTextAttributes;
use std::sync::Arc; use std::sync::Arc;
@ -83,23 +80,29 @@ impl ClientGridEditor {
pub async fn create_row(&self) -> FlowyResult<()> { pub async fn create_row(&self) -> FlowyResult<()> {
let fields = self.grid_meta_pad.read().await.get_fields(None)?; let fields = self.grid_meta_pad.read().await.get_fields(None)?;
match self.grid_meta_pad.read().await.get_blocks().last() { let grid_block = match self.grid_meta_pad.read().await.get_blocks().last() {
None => Err(FlowyError::internal().context("There is no grid block in this grid")), None => Err(FlowyError::internal().context("There is no grid block in this grid")),
Some(grid_block) => { Some(grid_block) => Ok(grid_block.clone()),
let row_count = self.block_meta_manager.create_row(fields, grid_block).await?; }?;
let change = GridBlockChangeset::from_row_count(&grid_block.id, row_count);
let _ = self.update_block(change).await?; let row_count = self.block_meta_manager.create_row(fields, &grid_block).await?;
Ok(()) let change = GridBlockChangeset::from_row_count(&grid_block.id, row_count);
} let _ = self.update_block(change).await?;
} Ok(())
} }
pub async fn get_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<Row>> { pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> FlowyResult<Vec<Row>> {
let fields = self.grid_meta_pad.read().await.get_fields(None)?; let fields = self.grid_meta_pad.read().await.get_fields(None)?;
let rows = self.block_meta_manager.get_rows(fields, row_orders).await?; let rows = self.block_meta_manager.get_rows(fields, row_orders).await?;
Ok(rows) Ok(rows)
} }
pub async fn get_all_rows(&self) -> FlowyResult<Vec<Row>> {
let fields = self.grid_meta_pad.read().await.get_fields(None)?;
let grid_blocks = self.grid_meta_pad.read().await.get_blocks();
self.block_meta_manager.get_all_rows(grid_blocks, fields).await
}
pub async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<()> { pub async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<()> {
let row_counts = self.block_meta_manager.delete_rows(row_orders).await?; let row_counts = self.block_meta_manager.delete_rows(row_orders).await?;
for (block_id, row_count) in row_counts { for (block_id, row_count) in row_counts {

View File

@ -1,22 +1,20 @@
use crate::manager::GridUser; use crate::manager::GridUser;
use crate::services::row::{make_row_ids_per_block, make_rows, sort_rows, RowBuilder}; use crate::services::row::{make_row_by_row_id, make_row_ids_per_block, make_rows, RowBuilder};
use bytes::Bytes; use bytes::Bytes;
use dashmap::mapref::one::Ref;
use dashmap::DashMap; use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridBlockMetaChange, GridBlockMetaPad}; use flowy_collaboration::client_grid::{GridBlockMetaChange, GridBlockMetaPad};
use flowy_collaboration::entities::revision::Revision; use flowy_collaboration::entities::revision::Revision;
use flowy_collaboration::util::make_delta_from_revisions; use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{ use flowy_grid_data_model::entities::{Field, GridBlock, RepeatedRowOrder, Row, RowMeta, RowMetaChangeset};
Field, GridBlock, RepeatedRow, RepeatedRowOrder, Row, RowMeta, RowMetaChangeset,
};
use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence; use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
use flowy_sync::{ use flowy_sync::{
RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence, RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
}; };
use lib_infra::future::FutureResult; use lib_infra::future::FutureResult;
use lib_ot::core::PlainTextAttributes; use lib_ot::core::PlainTextAttributes;
use lib_sqlite::ConnectionPool;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
@ -52,32 +50,34 @@ impl GridBlockMetaEditorManager {
editor.create_row(row).await editor.create_row(row).await
} }
pub(crate) async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<(String, i32)>> { pub(crate) async fn delete_rows(&self, _row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<(String, i32)>> {
Ok(vec![("".to_owned(), 2)]) Ok(vec![("".to_owned(), 2)])
} }
pub(crate) async fn get_rows( pub(crate) async fn get_all_rows(&self, grid_blocks: Vec<GridBlock>, fields: Vec<Field>) -> FlowyResult<Vec<Row>> {
&self, let mut rows = vec![];
fields: Vec<Field>, for grid_block in grid_blocks {
row_orders: Option<RepeatedRowOrder>, let editor = self.get_editor(&grid_block.id).await?;
) -> FlowyResult<Vec<Row>> { let row_metas = editor.get_rows(None).await?;
match row_orders { rows.extend(make_rows(&fields, row_metas));
None => {
let rows = vec![];
Ok(rows)
}
Some(row_orders) => {
let row_ids_per_blocks = make_row_ids_per_block(&row_orders);
let mut rows = vec![];
for row_ids_per_block in row_ids_per_blocks {
let editor = self.get_editor(&row_ids_per_block.block_id).await?;
let row_metas = editor.get_rows(row_ids_per_block.row_ids).await?;
rows.extend(make_rows(&fields, row_metas));
}
sort_rows(&mut rows, row_orders);
Ok(rows)
}
} }
Ok(rows)
}
pub(crate) async fn get_rows(&self, fields: Vec<Field>, row_orders: RepeatedRowOrder) -> FlowyResult<Vec<Row>> {
let row_ids_per_blocks = make_row_ids_per_block(&row_orders);
let mut row_map: HashMap<String, Row> = HashMap::new();
for row_ids_per_block in row_ids_per_blocks {
let editor = self.get_editor(&row_ids_per_block.block_id).await?;
let row_metas = editor.get_rows(Some(row_ids_per_block.row_ids)).await?;
row_map.extend(make_row_by_row_id(&fields, row_metas));
}
let rows = row_orders
.iter()
.flat_map(|row_order| row_map.remove(&row_order.row_id))
.collect::<Vec<_>>();
Ok(rows)
} }
} }
@ -158,9 +158,14 @@ impl ClientGridBlockMetaEditor {
Ok(()) Ok(())
} }
pub async fn get_rows(&self, row_ids: Vec<String>) -> FlowyResult<Vec<RowMeta>> { pub async fn get_rows(&self, row_ids: Option<Vec<String>>) -> FlowyResult<Vec<RowMeta>> {
let rows = self.meta_pad.read().await.get_rows(row_ids)?; match row_ids {
Ok(rows) None => Ok(self.meta_pad.read().await.all_rows()),
Some(row_ids) => {
let rows = self.meta_pad.read().await.get_rows(row_ids)?;
Ok(rows)
}
}
} }
async fn modify<F>(&self, f: F) -> FlowyResult<()> async fn modify<F>(&self, f: F) -> FlowyResult<()>

View File

@ -1,15 +1,15 @@
use crate::services::field::*; use crate::services::field::*;
use crate::services::util::*;
use flowy_error::FlowyError; use flowy_error::FlowyError;
use flowy_grid_data_model::entities::{AnyData, Field, FieldType}; use flowy_grid_data_model::entities::{Field, FieldType};
pub trait StringifyCellData { pub trait StringifyCellData {
fn str_from_cell_data(&self, data: AnyData) -> String; fn str_from_cell_data(&self, data: String) -> String;
fn str_to_cell_data(&self, s: &str) -> Result<AnyData, FlowyError>; fn str_to_cell_data(&self, s: &str) -> Result<String, FlowyError>;
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn stringify_serialize(field: &Field, s: &str) -> Result<AnyData, FlowyError> { pub fn stringify_serialize(field: &Field, s: &str) -> Result<String, FlowyError> {
match field.field_type { match field.field_type {
FieldType::RichText => RichTextDescription::from(field).str_to_cell_data(s), FieldType::RichText => RichTextDescription::from(field).str_to_cell_data(s),
FieldType::Number => NumberDescription::from(field).str_to_cell_data(s), FieldType::Number => NumberDescription::from(field).str_to_cell_data(s),
@ -20,8 +20,8 @@ pub fn stringify_serialize(field: &Field, s: &str) -> Result<AnyData, FlowyError
} }
} }
pub(crate) fn stringify_deserialize(data: AnyData, field: &Field) -> Result<String, FlowyError> { pub(crate) fn stringify_deserialize(data: String, field: &Field) -> Result<String, FlowyError> {
let _ = check_type_id(&data, field)?; // let _ = check_type_id(&data, field)?;
let s = match field.field_type { let s = match field.field_type {
FieldType::RichText => RichTextDescription::from(field).str_from_cell_data(data), FieldType::RichText => RichTextDescription::from(field).str_from_cell_data(data),
FieldType::Number => NumberDescription::from(field).str_from_cell_data(data), FieldType::Number => NumberDescription::from(field).str_from_cell_data(data),

View File

@ -4,4 +4,4 @@ mod row_loader;
pub use cell_stringify::*; pub use cell_stringify::*;
pub use row_builder::*; pub use row_builder::*;
pub use row_loader::*; pub(crate) use row_loader::*;

View File

@ -1,4 +1,6 @@
use flowy_grid_data_model::entities::{Field, RepeatedRowOrder, Row, RowMeta}; use crate::services::row::stringify_deserialize;
use flowy_grid_data_model::entities::{Cell, CellMeta, Field, RepeatedRowOrder, Row, RowMeta};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::collections::HashMap; use std::collections::HashMap;
pub(crate) struct RowIdsPerBlock { pub(crate) struct RowIdsPerBlock {
@ -19,50 +21,67 @@ pub(crate) fn make_row_ids_per_block(row_orders: &RepeatedRowOrder) -> Vec<RowId
map.into_values().collect::<Vec<_>>() map.into_values().collect::<Vec<_>>()
} }
pub(crate) fn sort_rows(rows: &mut Vec<Row>, row_orders: RepeatedRowOrder) { pub(crate) fn make_rows(fields: &Vec<Field>, row_metas: Vec<RowMeta>) -> Vec<Row> {
todo!() let field_map = fields
.iter()
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &Field>>();
let make_row = |row_meta: RowMeta| {
let cell_by_field_id = row_meta
.cell_by_field_id
.into_par_iter()
.flat_map(|(field_id, raw_cell)| make_cell(&field_map, field_id, raw_cell))
.collect::<HashMap<String, Cell>>();
Row {
id: row_meta.id.clone(),
cell_by_field_id,
height: row_meta.height,
}
};
row_metas.into_iter().map(make_row).collect::<Vec<Row>>()
} }
pub(crate) fn make_rows(fields: &Vec<Field>, rows: Vec<RowMeta>) -> Vec<Row> { #[inline(always)]
// let make_cell = |field_id: String, raw_cell: CellMeta| { fn make_cell(field_map: &HashMap<&String, &Field>, field_id: String, raw_cell: CellMeta) -> Option<(String, Cell)> {
// let some_field = self.field_map.get(&field_id); let field = field_map.get(&field_id)?;
// if some_field.is_none() { match stringify_deserialize(raw_cell.data, field) {
// tracing::error!("Can't find the field with {}", field_id); Ok(content) => {
// return None; let cell = Cell::new(&field_id, content);
// } Some((field_id, cell))
// self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone()); }
// Err(e) => {
// let field = some_field.unwrap(); tracing::error!("{}", e);
// match stringify_deserialize(raw_cell.data, field.value()) { None
// Ok(content) => { }
// let cell = Cell { }
// id: raw_cell.id, }
// field_id: field_id.clone(),
// content, pub(crate) fn make_row_by_row_id(fields: &Vec<Field>, row_metas: Vec<RowMeta>) -> HashMap<String, Row> {
// }; let field_map = fields
// Some((field_id, cell)) .iter()
// } .map(|field| (&field.id, field))
// Err(_) => None, .collect::<HashMap<&String, &Field>>();
// }
// }; let make_row = |row_meta: RowMeta| {
// let cell_by_field_id = row_meta
// let rows = row_metas .cell_by_field_id
// .into_par_iter() .into_par_iter()
// .map(|row_meta| { .flat_map(|(field_id, raw_cell)| make_cell(&field_map, field_id, raw_cell))
// let mut row = Row { .collect::<HashMap<String, Cell>>();
// id: row_meta.id.clone(),
// cell_by_field_id: Default::default(), let row = Row {
// height: row_meta.height, id: row_meta.id.clone(),
// }; cell_by_field_id,
// row.cell_by_field_id = row_meta height: row_meta.height,
// .cell_by_field_id };
// .into_par_iter() (row.id.clone(), row)
// .flat_map(|(field_id, raw_cell)| make_cell(field_id, raw_cell)) };
// .collect::<HashMap<String, Cell>>();
// row row_metas
// }) .into_par_iter()
// .collect::<Vec<Row>>(); .map(make_row)
// .collect::<HashMap<String, Row>>()
// Ok(rows.into())
todo!()
} }

View File

@ -1,6 +1,6 @@
use crate::services::field::*; use crate::services::field::*;
use flowy_collaboration::client_grid::{BuildGridInfo, GridBuilder}; use flowy_collaboration::client_grid::{BuildGridInfo, GridBuilder};
use flowy_grid_data_model::entities::{Field, FieldType}; use flowy_grid_data_model::entities::FieldType;
pub fn make_default_grid(grid_id: &str) -> BuildGridInfo { pub fn make_default_grid(grid_id: &str) -> BuildGridInfo {
let text_field = FieldBuilder::new(RichTextTypeOptionsBuilder::new()) let text_field = FieldBuilder::new(RichTextTypeOptionsBuilder::new())

View File

@ -169,6 +169,6 @@ async fn grid_update_block() {
#[tokio::test] #[tokio::test]
async fn grid_create_row() { async fn grid_create_row() {
let scripts = vec![AssertRowCount(2), CreateRow, CreateRow, CreateRow, AssertRowCount(5)]; let scripts = vec![AssertRowCount(3), CreateRow, CreateRow, AssertRowCount(5)];
GridEditorTest::new().await.run_scripts(scripts).await; GridEditorTest::new().await.run_scripts(scripts).await;
} }

View File

@ -1,8 +1,8 @@
use flowy_grid::services::field::*; use flowy_grid::services::field::*;
use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder}; use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
use flowy_grid_data_model::entities::{AnyData, Field, FieldChangeset, FieldType, GridBlock, GridBlockChangeset}; use flowy_grid_data_model::entities::{Field, FieldChangeset, FieldType, GridBlock, GridBlockChangeset};
use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS; use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
use flowy_test::event_builder::FolderEventBuilder;
use flowy_test::helper::ViewTest; use flowy_test::helper::ViewTest;
use flowy_test::FlowySDKTest; use flowy_test::FlowySDKTest;
use std::sync::Arc; use std::sync::Arc;
@ -89,7 +89,7 @@ impl GridEditorTest {
self.editor.create_row().await.unwrap(); self.editor.create_row().await.unwrap();
} }
EditorScript::AssertRowCount(count) => { EditorScript::AssertRowCount(count) => {
assert_eq!(self.editor.get_rows(None).await.unwrap().len(), count); assert_eq!(self.editor.get_all_rows().await.unwrap().len(), count);
} }
EditorScript::AssertGridMetaPad => { EditorScript::AssertGridMetaPad => {
sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;

View File

@ -1,5 +1,5 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::errors::{CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions}; use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{GridBlockMeta, RowMeta, RowMetaChangeset}; use flowy_grid_data_model::entities::{GridBlockMeta, RowMeta, RowMetaChangeset};
use lib_infra::uuid; use lib_infra::uuid;
@ -69,6 +69,10 @@ impl GridBlockMetaPad {
.collect::<Vec<RowMeta>>()) .collect::<Vec<RowMeta>>())
} }
pub fn all_rows(&self) -> Vec<RowMeta> {
self.rows.iter().map(|row| (**row).clone()).collect::<Vec<_>>()
}
pub fn number_of_rows(&self) -> i32 { pub fn number_of_rows(&self) -> i32 {
self.rows.len() as i32 self.rows.len() as i32
} }

View File

@ -1,6 +1,6 @@
use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBlockMetaDelta, GridMetaDelta}; use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBlockMetaDelta, GridMetaDelta};
use crate::errors::{CollaborateError, CollaborateResult}; use crate::errors::{CollaborateError, CollaborateResult};
use flowy_grid_data_model::entities::{Field, FieldType, GridBlock, GridBlockMeta, GridMeta, RowMeta}; use flowy_grid_data_model::entities::{Field, GridBlock, GridBlockMeta, GridMeta, RowMeta};
pub struct GridBuilder { pub struct GridBuilder {
grid_id: String, grid_id: String,

View File

@ -2,7 +2,7 @@ use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions}; use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{ use flowy_grid_data_model::entities::{
Field, FieldChangeset, GridBlock, GridBlockChangeset, GridMeta, RepeatedField, RepeatedFieldOrder, Field, FieldChangeset, GridBlock, GridBlockChangeset, GridMeta, RepeatedFieldOrder,
}; };
use lib_infra::uuid; use lib_infra::uuid;
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
@ -58,7 +58,7 @@ impl GridMetaPad {
pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<Vec<Field>> { pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<Vec<Field>> {
match field_orders { match field_orders {
None => Ok(self.grid_meta.fields.clone().into()), None => Ok(self.grid_meta.fields.clone()),
Some(field_orders) => { Some(field_orders) => {
let field_by_field_id = self let field_by_field_id = self
.grid_meta .grid_meta
@ -127,7 +127,7 @@ impl GridMetaPad {
pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChange>> { pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| { self.modify_grid(|grid| {
if grid.blocks.iter().find(|b| b.id == block.id).is_some() { if grid.blocks.iter().any(|b| b.id == block.id) {
tracing::warn!("Duplicate grid block"); tracing::warn!("Duplicate grid block");
Ok(None) Ok(None)
} else { } else {

View File

@ -123,6 +123,15 @@ pub struct Cell {
pub content: String, pub content: String,
} }
impl Cell {
pub fn new(field_id: &str, content: String) -> Self {
Self {
field_id: field_id.to_owned(),
content,
}
}
}
#[derive(ProtoBuf, Default)] #[derive(ProtoBuf, Default)]
pub struct CreateGridPayload { pub struct CreateGridPayload {
#[pb(index = 1)] #[pb(index = 1)]

View File

@ -175,13 +175,13 @@ impl std::default::Default for FieldType {
impl AsRef<FieldType> for FieldType { impl AsRef<FieldType> for FieldType {
fn as_ref(&self) -> &FieldType { fn as_ref(&self) -> &FieldType {
&self self
} }
} }
impl Into<FieldType> for &FieldType { impl From<&FieldType> for FieldType {
fn into(self) -> FieldType { fn from(field: &FieldType) -> Self {
self.clone() field.clone()
} }
} }