mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: add row test
This commit is contained in:
parent
572e38ec1c
commit
d101509b32
@ -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())?;
|
||||||
|
@ -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,
|
||||||
|
@ -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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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<()>
|
||||||
|
@ -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),
|
||||||
|
@ -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::*;
|
||||||
|
@ -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!()
|
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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 {
|
||||||
|
@ -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)]
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user