chore: config grid row changeset

This commit is contained in:
appflowy 2022-03-13 11:06:28 +08:00
parent baa70f2ee6
commit 572e38ec1c
25 changed files with 555 additions and 464 deletions

View File

@ -163,17 +163,22 @@ class RepeatedFieldOrder extends $pb.GeneratedMessage {
class RowOrder extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RowOrder', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..hasRequiredFields = false
;
RowOrder._() : super();
factory RowOrder({
$core.String? rowId,
$core.String? blockId,
}) {
final _result = create();
if (rowId != null) {
_result.rowId = rowId;
}
if (blockId != null) {
_result.blockId = blockId;
}
return _result;
}
factory RowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@ -205,6 +210,15 @@ class RowOrder extends $pb.GeneratedMessage {
$core.bool hasRowId() => $_has(0);
@$pb.TagNumber(1)
void clearRowId() => clearField(1);
@$pb.TagNumber(2)
$core.String get blockId => $_getSZ(1);
@$pb.TagNumber(2)
set blockId($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasBlockId() => $_has(1);
@$pb.TagNumber(2)
void clearBlockId() => clearField(2);
}
class RepeatedRowOrder extends $pb.GeneratedMessage {
@ -360,22 +374,17 @@ class RepeatedRow extends $pb.GeneratedMessage {
class Cell extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Cell', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content')
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content')
..hasRequiredFields = false
;
Cell._() : super();
factory Cell({
$core.String? id,
$core.String? fieldId,
$core.String? content,
}) {
final _result = create();
if (id != null) {
_result.id = id;
}
if (fieldId != null) {
_result.fieldId = fieldId;
}
@ -406,31 +415,22 @@ class Cell extends $pb.GeneratedMessage {
static Cell? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
$core.String get fieldId => $_getSZ(0);
@$pb.TagNumber(1)
set id($core.String v) { $_setString(0, v); }
set fieldId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasId() => $_has(0);
$core.bool hasFieldId() => $_has(0);
@$pb.TagNumber(1)
void clearId() => clearField(1);
void clearFieldId() => clearField(1);
@$pb.TagNumber(2)
$core.String get fieldId => $_getSZ(1);
$core.String get content => $_getSZ(1);
@$pb.TagNumber(2)
set fieldId($core.String v) { $_setString(1, v); }
set content($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasFieldId() => $_has(1);
$core.bool hasContent() => $_has(1);
@$pb.TagNumber(2)
void clearFieldId() => clearField(2);
@$pb.TagNumber(3)
$core.String get content => $_getSZ(2);
@$pb.TagNumber(3)
set content($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasContent() => $_has(2);
@$pb.TagNumber(3)
void clearContent() => clearField(3);
void clearContent() => clearField(2);
}
class CreateGridPayload extends $pb.GeneratedMessage {

View File

@ -45,11 +45,12 @@ const RowOrder$json = const {
'1': 'RowOrder',
'2': const [
const {'1': 'row_id', '3': 1, '4': 1, '5': 9, '10': 'rowId'},
const {'1': 'block_id', '3': 2, '4': 1, '5': 9, '10': 'blockId'},
],
};
/// Descriptor for `RowOrder`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lk');
final $typed_data.Uint8List rowOrderDescriptor = $convert.base64Decode('CghSb3dPcmRlchIVCgZyb3dfaWQYASABKAlSBXJvd0lkEhkKCGJsb2NrX2lkGAIgASgJUgdibG9ja0lk');
@$core.Deprecated('Use repeatedRowOrderDescriptor instead')
const RepeatedRowOrder$json = const {
'1': 'RepeatedRowOrder',
@ -97,14 +98,13 @@ final $typed_data.Uint8List repeatedRowDescriptor = $convert.base64Decode('CgtSZ
const Cell$json = const {
'1': 'Cell',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'},
const {'1': 'content', '3': 3, '4': 1, '5': 9, '10': 'content'},
const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
const {'1': 'content', '3': 2, '4': 1, '5': 9, '10': 'content'},
],
};
/// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEg4KAmlkGAEgASgJUgJpZBIZCghmaWVsZF9pZBgCIAEoCVIHZmllbGRJZBIYCgdjb250ZW50GAMgASgJUgdjb250ZW50');
final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ=');
@$core.Deprecated('Use createGridPayloadDescriptor instead')
const CreateGridPayload$json = const {
'1': 'CreateGridPayload',

View File

@ -897,38 +897,23 @@ class RowMetaChangeset extends $pb.GeneratedMessage {
class CellMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellMeta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId')
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
..aOM<AnyData>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', subBuilder: AnyData.create)
..a<$core.int>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'height', $pb.PbFieldType.O3)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..hasRequiredFields = false
;
CellMeta._() : super();
factory CellMeta({
$core.String? id,
$core.String? rowId,
$core.String? fieldId,
AnyData? data,
$core.int? height,
$core.String? data,
}) {
final _result = create();
if (id != null) {
_result.id = id;
}
if (rowId != null) {
_result.rowId = rowId;
}
if (fieldId != null) {
_result.fieldId = fieldId;
}
if (data != null) {
_result.data = data;
}
if (height != null) {
_result.height = height;
}
return _result;
}
factory CellMeta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@ -953,50 +938,21 @@ class CellMeta extends $pb.GeneratedMessage {
static CellMeta? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
$core.String get fieldId => $_getSZ(0);
@$pb.TagNumber(1)
set id($core.String v) { $_setString(0, v); }
set fieldId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasId() => $_has(0);
$core.bool hasFieldId() => $_has(0);
@$pb.TagNumber(1)
void clearId() => clearField(1);
void clearFieldId() => clearField(1);
@$pb.TagNumber(2)
$core.String get rowId => $_getSZ(1);
$core.String get data => $_getSZ(1);
@$pb.TagNumber(2)
set rowId($core.String v) { $_setString(1, v); }
set data($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasRowId() => $_has(1);
$core.bool hasData() => $_has(1);
@$pb.TagNumber(2)
void clearRowId() => clearField(2);
@$pb.TagNumber(3)
$core.String get fieldId => $_getSZ(2);
@$pb.TagNumber(3)
set fieldId($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasFieldId() => $_has(2);
@$pb.TagNumber(3)
void clearFieldId() => clearField(3);
@$pb.TagNumber(4)
AnyData get data => $_getN(3);
@$pb.TagNumber(4)
set data(AnyData v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasData() => $_has(3);
@$pb.TagNumber(4)
void clearData() => clearField(4);
@$pb.TagNumber(4)
AnyData ensureData() => $_ensure(3);
@$pb.TagNumber(5)
$core.int get height => $_getIZ(4);
@$pb.TagNumber(5)
set height($core.int v) { $_setSignedInt32(4, v); }
@$pb.TagNumber(5)
$core.bool hasHeight() => $_has(4);
@$pb.TagNumber(5)
void clearHeight() => clearField(5);
void clearData() => clearField(2);
}

View File

@ -179,13 +179,10 @@ final $typed_data.Uint8List rowMetaChangesetDescriptor = $convert.base64Decode('
const CellMeta$json = const {
'1': 'CellMeta',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {'1': 'row_id', '3': 2, '4': 1, '5': 9, '10': 'rowId'},
const {'1': 'field_id', '3': 3, '4': 1, '5': 9, '10': 'fieldId'},
const {'1': 'data', '3': 4, '4': 1, '5': 11, '6': '.AnyData', '10': 'data'},
const {'1': 'height', '3': 5, '4': 1, '5': 5, '10': 'height'},
const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
],
};
/// Descriptor for `CellMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List cellMetaDescriptor = $convert.base64Decode('CghDZWxsTWV0YRIOCgJpZBgBIAEoCVICaWQSFQoGcm93X2lkGAIgASgJUgVyb3dJZBIZCghmaWVsZF9pZBgDIAEoCVIHZmllbGRJZBIcCgRkYXRhGAQgASgLMgguQW55RGF0YVIEZGF0YRIWCgZoZWlnaHQYBSABKAVSBmhlaWdodA==');
final $typed_data.Uint8List cellMetaDescriptor = $convert.base64Decode('CghDZWxsTWV0YRIZCghmaWVsZF9pZBgBIAEoCVIHZmllbGRJZBISCgRkYXRhGAIgASgJUgRkYXRh');

View File

@ -24,7 +24,7 @@ pub(crate) async fn get_rows_handler(
) -> DataResult<RepeatedRow, FlowyError> {
let payload: QueryRowPayload = data.into_inner();
let editor = manager.get_grid_editor(&payload.grid_id)?;
let repeated_row = editor.get_rows(payload.row_orders).await?;
let repeated_row: RepeatedRow = editor.get_rows(Some(payload.row_orders)).await?.into();
data_result(repeated_row)
}
@ -35,7 +35,7 @@ pub(crate) async fn get_fields_handler(
) -> DataResult<RepeatedField, FlowyError> {
let payload: QueryFieldPayload = data.into_inner();
let editor = manager.get_grid_editor(&payload.grid_id)?;
let repeated_field = editor.get_fields(Some(payload.field_orders)).await?;
let repeated_field: RepeatedField = editor.get_fields(Some(payload.field_orders)).await?.into();
data_result(repeated_field)
}

View File

@ -1,7 +1,5 @@
mod cell_stringify;
mod field_builder;
mod type_options;
pub use cell_stringify::*;
pub use field_builder::*;
pub use type_options::*;

View File

@ -1,6 +1,6 @@
#![allow(clippy::upper_case_acronyms)]
use crate::impl_from_and_to_type_option;
use crate::services::field::StringifyCellData;
use crate::services::row::StringifyCellData;
use crate::services::util::*;
use bytes::Bytes;
use chrono::format::strftime::StrftimeItems;

View File

@ -1,7 +1,7 @@
use crate::manager::GridUser;
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
use crate::services::grid_meta_editor::ClientGridBlockMetaEditor;
use crate::services::grid_meta_editor::{ClientGridBlockMetaEditor, GridBlockMetaEditorManager};
use bytes::Bytes;
use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridChange, GridMetaPad};
@ -9,7 +9,8 @@ use flowy_collaboration::entities::revision::Revision;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{
Field, FieldChangeset, Grid, GridBlock, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
Field, FieldChangeset, Grid, GridBlock, GridBlockChangeset, RepeatedField, RepeatedFieldOrder, RepeatedRow,
RepeatedRowOrder, Row,
};
use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
use flowy_sync::{
@ -43,7 +44,7 @@ impl ClientGridEditor {
let grid_meta_pad = Arc::new(RwLock::new(grid_pad));
let block_meta_manager =
Arc::new(GridBlockMetaEditorManager::new(&user, grid_meta_pad.read().await.get_blocks()).await?);
Arc::new(GridBlockMetaEditorManager::new(&user, grid_meta_pad.read().await.get_blocks().clone()).await?);
Ok(Arc::new(Self {
grid_id: grid_id.to_owned(),
@ -70,27 +71,60 @@ impl ClientGridEditor {
Ok(())
}
pub async fn create_block(&self, grid_block: GridBlock) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.create_block(grid_block)?)).await?;
Ok(())
}
pub async fn update_block(&self, change: GridBlockChangeset) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.update_block(change)?)).await?;
Ok(())
}
pub async fn create_row(&self) -> FlowyResult<()> {
todo!()
let fields = self.grid_meta_pad.read().await.get_fields(None)?;
match self.grid_meta_pad.read().await.get_blocks().last() {
None => Err(FlowyError::internal().context("There is no grid block in this grid")),
Some(grid_block) => {
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?;
Ok(())
}
}
}
pub async fn get_rows(&self, _row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
todo!()
pub async fn get_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<Row>> {
let fields = self.grid_meta_pad.read().await.get_fields(None)?;
let rows = self.block_meta_manager.get_rows(fields, row_orders).await?;
Ok(rows)
}
pub async fn delete_rows(&self, _ids: Vec<String>) -> FlowyResult<()> {
todo!()
pub async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<()> {
let row_counts = self.block_meta_manager.delete_rows(row_orders).await?;
for (block_id, row_count) in row_counts {
let _ = self
.update_block(GridBlockChangeset::from_row_count(&block_id, row_count))
.await?;
}
Ok(())
}
pub async fn grid_data(&self) -> Grid {
todo!()
}
pub async fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<RepeatedField> {
pub async fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<Vec<Field>> {
let fields = self.grid_meta_pad.read().await.get_fields(field_orders)?;
Ok(fields)
}
pub async fn get_blocks(&self) -> FlowyResult<Vec<GridBlock>> {
let grid_blocks = self.grid_meta_pad.read().await.get_blocks();
Ok(grid_blocks)
}
pub async fn delta_str(&self) -> String {
self.grid_meta_pad.read().await.delta_str()
}
@ -184,90 +218,3 @@ impl RevisionCompactor for GridRevisionCompactor {
Ok(delta.to_bytes())
}
}
struct GridBlockMetaEditorManager {
editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
}
impl GridBlockMetaEditorManager {
async fn new(user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
let editor_map = make_block_meta_editor_map(user, blocks).await?;
let manager = Self { editor_map };
Ok(manager)
}
async fn get_editor(&self, _block_id: &str) -> Arc<ClientGridBlockMetaEditor> {
todo!()
}
pub async fn get_rows(&self, _row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
// let ids = row_orders
// .items
// .into_iter()
// .map(|row_order| row_order.row_id)
// .collect::<Vec<_>>();
// let row_metas: Vec<RowMeta> = self.kv_persistence.batch_get(ids)?;
//
// let make_cell = |field_id: String, raw_cell: CellMeta| {
// let some_field = self.field_map.get(&field_id);
// if some_field.is_none() {
// tracing::error!("Can't find the field with {}", field_id);
// return None;
// }
// self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone());
//
// let field = some_field.unwrap();
// match stringify_deserialize(raw_cell.data, field.value()) {
// Ok(content) => {
// let cell = Cell {
// id: raw_cell.id,
// field_id: field_id.clone(),
// content,
// };
// Some((field_id, cell))
// }
// Err(_) => None,
// }
// };
//
// let rows = row_metas
// .into_par_iter()
// .map(|row_meta| {
// let mut row = Row {
// id: row_meta.id.clone(),
// cell_by_field_id: Default::default(),
// height: row_meta.height,
// };
// row.cell_by_field_id = row_meta
// .cell_by_field_id
// .into_par_iter()
// .flat_map(|(field_id, raw_cell)| make_cell(field_id, raw_cell))
// .collect::<HashMap<String, Cell>>();
// row
// })
// .collect::<Vec<Row>>();
//
// Ok(rows.into())
todo!()
}
}
async fn make_block_meta_editor_map(
user: &Arc<dyn GridUser>,
blocks: Vec<GridBlock>,
) -> FlowyResult<DashMap<String, Arc<ClientGridBlockMetaEditor>>> {
let token = user.token()?;
let user_id = user.user_id()?;
let pool = user.db_pool()?;
let editor_map = DashMap::new();
for block in blocks {
let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool.clone()));
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, &block.id, disk_cache));
let rev_manager = RevisionManager::new(&user_id, &block.id, rev_persistence);
let editor = ClientGridBlockMetaEditor::new(&user_id, &token, &block.id, rev_manager).await?;
editor_map.insert(block.id, Arc::new(editor));
}
Ok(editor_map)
}

View File

@ -1,15 +1,110 @@
use crate::manager::GridUser;
use crate::services::row::{make_row_ids_per_block, make_rows, sort_rows, RowBuilder};
use bytes::Bytes;
use dashmap::mapref::one::Ref;
use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridBlockMetaChange, GridBlockMetaPad};
use flowy_collaboration::entities::revision::Revision;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset};
use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
use flowy_grid_data_model::entities::{
Field, GridBlock, RepeatedRow, RepeatedRowOrder, Row, RowMeta, RowMetaChangeset,
};
use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
use flowy_sync::{
RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
};
use lib_infra::future::FutureResult;
use lib_ot::core::PlainTextAttributes;
use lib_sqlite::ConnectionPool;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
pub(crate) struct GridBlockMetaEditorManager {
user: Arc<dyn GridUser>,
editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
}
impl GridBlockMetaEditorManager {
pub(crate) async fn new(user: &Arc<dyn GridUser>, blocks: Vec<GridBlock>) -> FlowyResult<Self> {
let editor_map = make_block_meta_editor_map(user, blocks).await?;
let user = user.clone();
let manager = Self { user, editor_map };
Ok(manager)
}
pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult<Arc<ClientGridBlockMetaEditor>> {
match self.editor_map.get(block_id) {
None => {
tracing::error!("The is a fatal error, block is not exist");
let editor = Arc::new(make_block_meta_editor(&self.user, block_id).await?);
self.editor_map.insert(block_id.to_owned(), editor.clone());
Ok(editor)
}
Some(editor) => Ok(editor.clone()),
}
}
pub(crate) async fn create_row(&self, fields: Vec<Field>, grid_block: &GridBlock) -> FlowyResult<i32> {
let row = RowBuilder::new(&fields, &grid_block.id).build();
let editor = self.get_editor(&grid_block.id).await?;
editor.create_row(row).await
}
pub(crate) async fn delete_rows(&self, row_orders: Option<RepeatedRowOrder>) -> FlowyResult<Vec<(String, i32)>> {
Ok(vec![("".to_owned(), 2)])
}
pub(crate) async fn get_rows(
&self,
fields: Vec<Field>,
row_orders: Option<RepeatedRowOrder>,
) -> FlowyResult<Vec<Row>> {
match row_orders {
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)
}
}
}
}
async fn make_block_meta_editor_map(
user: &Arc<dyn GridUser>,
blocks: Vec<GridBlock>,
) -> FlowyResult<DashMap<String, Arc<ClientGridBlockMetaEditor>>> {
let editor_map = DashMap::new();
for block in blocks {
let editor = make_block_meta_editor(user, &block.id).await?;
editor_map.insert(block.id, Arc::new(editor));
}
Ok(editor_map)
}
async fn make_block_meta_editor(user: &Arc<dyn GridUser>, block_id: &str) -> FlowyResult<ClientGridBlockMetaEditor> {
let token = user.token()?;
let user_id = user.user_id()?;
let pool = user.db_pool()?;
let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool));
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache));
let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence);
ClientGridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await
}
pub struct ClientGridBlockMetaEditor {
user_id: String,
pub block_id: String,
@ -40,10 +135,17 @@ impl ClientGridBlockMetaEditor {
})
}
async fn create_row(&self) -> FlowyResult<()> {
let row = RowMeta::new(&self.block_id, vec![]);
let _ = self.modify(|pad| Ok(pad.add_row(row)?)).await?;
Ok(())
async fn create_row(&self, row: RowMeta) -> FlowyResult<i32> {
let mut row_count = 0;
let _ = self
.modify(|pad| {
let change = pad.add_row(row)?;
row_count = pad.number_of_rows();
Ok(change)
})
.await?;
Ok(row_count)
}
pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {

View File

@ -4,3 +4,4 @@ pub mod field;
pub mod grid_editor;
pub mod grid_meta_editor;
pub mod kv_persistence;
pub mod row;

View File

@ -0,0 +1,7 @@
mod cell_stringify;
mod row_builder;
mod row_loader;
pub use cell_stringify::*;
pub use row_builder::*;
pub use row_loader::*;

View File

@ -0,0 +1,24 @@
use flowy_grid_data_model::entities::{CellMeta, Field, RowMeta};
pub struct RowBuilder<'a> {
fields: &'a Vec<Field>,
row: RowMeta,
}
impl<'a> RowBuilder<'a> {
pub fn new(fields: &'a Vec<Field>, block_id: &'a String) -> Self {
let row = RowMeta::new(block_id);
Self { fields, row }
}
#[allow(dead_code)]
pub fn add_cell(mut self, field_id: &str, data: String) -> Self {
let cell = CellMeta::new(field_id, data);
self.row.cell_by_field_id.insert(field_id.to_owned(), cell);
self
}
pub fn build(self) -> RowMeta {
self.row
}
}

View File

@ -0,0 +1,68 @@
use flowy_grid_data_model::entities::{Field, RepeatedRowOrder, Row, RowMeta};
use std::collections::HashMap;
pub(crate) struct RowIdsPerBlock {
pub(crate) block_id: String,
pub(crate) row_ids: Vec<String>,
}
pub(crate) fn make_row_ids_per_block(row_orders: &RepeatedRowOrder) -> Vec<RowIdsPerBlock> {
let mut map: HashMap<String, RowIdsPerBlock> = HashMap::new();
row_orders.iter().for_each(|row_order| {
let block_id = row_order.block_id.clone();
let entry = map.entry(block_id.clone()).or_insert(RowIdsPerBlock {
block_id,
row_ids: vec![],
});
entry.row_ids.push(row_order.row_id.clone());
});
map.into_values().collect::<Vec<_>>()
}
pub(crate) fn sort_rows(rows: &mut Vec<Row>, row_orders: RepeatedRowOrder) {
todo!()
}
pub(crate) fn make_rows(fields: &Vec<Field>, rows: Vec<RowMeta>) -> Vec<Row> {
// let make_cell = |field_id: String, raw_cell: CellMeta| {
// let some_field = self.field_map.get(&field_id);
// if some_field.is_none() {
// tracing::error!("Can't find the field with {}", field_id);
// return None;
// }
// self.cell_map.insert(raw_cell.id.clone(), raw_cell.clone());
//
// let field = some_field.unwrap();
// match stringify_deserialize(raw_cell.data, field.value()) {
// Ok(content) => {
// let cell = Cell {
// id: raw_cell.id,
// field_id: field_id.clone(),
// content,
// };
// Some((field_id, cell))
// }
// Err(_) => None,
// }
// };
//
// let rows = row_metas
// .into_par_iter()
// .map(|row_meta| {
// let mut row = Row {
// id: row_meta.id.clone(),
// cell_by_field_id: Default::default(),
// height: row_meta.height,
// };
// row.cell_by_field_id = row_meta
// .cell_by_field_id
// .into_par_iter()
// .flat_map(|(field_id, raw_cell)| make_cell(field_id, raw_cell))
// .collect::<HashMap<String, Cell>>();
// row
// })
// .collect::<Vec<Row>>();
//
// Ok(rows.into())
todo!()
}

View File

@ -1,7 +1,7 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use flowy_grid::services::field::{SelectOption, SingleSelectDescription};
use flowy_grid_data_model::entities::FieldChangeset;
use flowy_grid_data_model::entities::{FieldChangeset, GridBlock, GridBlockChangeset};
#[tokio::test]
async fn default_grid_test() {
@ -35,6 +35,23 @@ async fn grid_create_field() {
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_duplicate_field() {
let text_field = create_text_field();
let scripts = vec![
AssertFieldCount(2),
CreateField {
field: text_field.clone(),
},
AssertFieldCount(3),
CreateField {
field: text_field.clone(),
},
AssertFieldCount(3),
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_field_with_empty_change() {
let single_select_field = create_single_select_field();
@ -98,3 +115,60 @@ async fn grid_update_field() {
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_delete_field() {
let text_field = create_text_field();
let scripts = vec![
CreateField {
field: text_field.clone(),
},
AssertFieldCount(3),
DeleteField { field: text_field },
AssertFieldCount(2),
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_block() {
let grid_block = GridBlock::new();
let scripts = vec![
AssertBlockCount(1),
CreateBlock { block: grid_block },
AssertBlockCount(2),
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_block() {
let grid_block = GridBlock::new();
let mut cloned_grid_block = grid_block.clone();
let change = GridBlockChangeset {
block_id: grid_block.id.clone(),
start_row_index: Some(2),
row_count: Some(10),
};
cloned_grid_block.start_row_index = 2;
cloned_grid_block.row_count = 10;
let scripts = vec![
AssertBlockCount(1),
CreateBlock { block: grid_block },
UpdateBlock { change },
AssertBlockCount(2),
AssertBlockEqual {
block_index: 1,
block: cloned_grid_block,
},
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_row() {
let scripts = vec![AssertRowCount(2), CreateRow, CreateRow, CreateRow, AssertRowCount(5)];
GridEditorTest::new().await.run_scripts(scripts).await;
}

View File

@ -1,6 +1,6 @@
use flowy_grid::services::field::*;
use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
use flowy_grid_data_model::entities::{AnyData, Field, FieldChangeset, FieldType};
use flowy_grid_data_model::entities::{AnyData, Field, FieldChangeset, FieldType, GridBlock, GridBlockChangeset};
use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
use flowy_test::event_builder::FolderEventBuilder;
use flowy_test::helper::ViewTest;
@ -12,10 +12,17 @@ use tokio::time::sleep;
pub enum EditorScript {
CreateField { field: Field },
UpdateField { change: FieldChangeset },
DeleteField { field: Field },
AssertFieldCount(usize),
AssertFieldEqual { field_index: usize, field: Field },
AssertGridMetaPad,
CreateBlock { block: GridBlock },
UpdateBlock { change: GridBlockChangeset },
AssertBlockCount(usize),
AssertBlockEqual { block_index: usize, block: GridBlock },
CreateRow,
AssertRowCount(usize),
// AssertRowEqual{ row_index: usize, row: RowMeta},
AssertGridMetaPad,
}
pub struct GridEditorTest {
@ -53,6 +60,9 @@ impl GridEditorTest {
EditorScript::UpdateField { change } => {
self.editor.update_field(change).await.unwrap();
}
EditorScript::DeleteField { field } => {
self.editor.delete_field(&field.id).await.unwrap();
}
EditorScript::AssertFieldCount(count) => {
assert_eq!(self.editor.get_fields(None).await.unwrap().len(), count);
}
@ -61,13 +71,32 @@ impl GridEditorTest {
let compared_field = repeated_fields[field_index].clone();
assert_eq!(compared_field, field);
}
EditorScript::CreateBlock { block } => {
self.editor.create_block(block).await.unwrap();
}
EditorScript::UpdateBlock { change } => {
self.editor.update_block(change).await.unwrap();
}
EditorScript::AssertBlockCount(count) => {
assert_eq!(self.editor.get_blocks().await.unwrap().len(), count);
}
EditorScript::AssertBlockEqual { block_index, block } => {
let blocks = self.editor.get_blocks().await.unwrap();
let compared_block = blocks[block_index].clone();
assert_eq!(compared_block, block);
}
EditorScript::CreateRow => {
self.editor.create_row().await.unwrap();
}
EditorScript::AssertRowCount(count) => {
assert_eq!(self.editor.get_rows(None).await.unwrap().len(), count);
}
EditorScript::AssertGridMetaPad => {
sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await;
let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap();
let grid_pad = grid_rev_manager.load::<GridPadBuilder>(None).await.unwrap();
println!("{}", grid_pad.delta_str());
}
EditorScript::CreateRow => {}
}
}
}

View File

@ -69,6 +69,10 @@ impl GridBlockMetaPad {
.collect::<Vec<RowMeta>>())
}
pub fn number_of_rows(&self) -> i32 {
self.rows.len() as i32
}
pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
let row_id = changeset.row_id.clone();
self.modify_row(&row_id, |row| {

View File

@ -31,7 +31,7 @@ impl GridBuilder {
}
pub fn add_empty_row(mut self) -> Self {
let row = RowMeta::new(&self.grid_block.id, vec![]);
let row = RowMeta::new(&self.grid_block.id);
self.grid_block_meta.rows.push(row);
self
}

View File

@ -36,8 +36,13 @@ impl GridMetaPad {
pub fn create_field(&mut self, field: Field) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.fields.push(field);
Ok(Some(()))
if grid.fields.contains(&field) {
tracing::warn!("Duplicate grid field");
Ok(None)
} else {
grid.fields.push(field);
Ok(Some(()))
}
})
}
@ -51,7 +56,7 @@ impl GridMetaPad {
})
}
pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<RepeatedField> {
pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<Vec<Field>> {
match field_orders {
None => Ok(self.grid_meta.fields.clone().into()),
Some(field_orders) => {
@ -72,7 +77,7 @@ impl GridMetaPad {
Some(field) => Some((*field).clone()),
})
.collect::<Vec<Field>>();
Ok(fields.into())
Ok(fields)
}
}
}
@ -122,8 +127,13 @@ impl GridMetaPad {
pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.blocks.push(block);
Ok(Some(()))
if grid.blocks.iter().find(|b| b.id == block.id).is_some() {
tracing::warn!("Duplicate grid block");
Ok(None)
} else {
grid.blocks.push(block);
Ok(Some(()))
}
})
}
@ -141,6 +151,11 @@ impl GridMetaPad {
is_changed = Some(());
}
if let Some(start_row_index) = change.start_row_index {
block.start_row_index = start_row_index;
is_changed = Some(());
}
Ok(is_changed)
})
}

View File

@ -45,11 +45,17 @@ impl std::ops::Deref for RepeatedFieldOrder {
pub struct RowOrder {
#[pb(index = 1)]
pub row_id: String,
#[pb(index = 2)]
pub block_id: String,
}
impl std::convert::From<&RowMeta> for RowOrder {
fn from(row: &RowMeta) -> Self {
Self { row_id: row.id.clone() }
Self {
row_id: row.id.clone(),
block_id: row.block_id.clone(),
}
}
}
@ -111,12 +117,9 @@ impl std::convert::From<Vec<Row>> for RepeatedRow {
#[derive(Debug, Default, ProtoBuf)]
pub struct Cell {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2)]
pub field_id: String,
#[pb(index = 3)]
#[pb(index = 2)]
pub content: String,
}

View File

@ -18,7 +18,7 @@ pub struct GridMeta {
pub blocks: Vec<GridBlock>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
pub struct GridBlock {
#[pb(index = 1)]
pub id: String,
@ -45,6 +45,16 @@ pub struct GridBlockChangeset {
pub row_count: Option<i32>,
}
impl GridBlockChangeset {
pub fn from_row_count(block_id: &str, row_count: i32) -> Self {
Self {
block_id: block_id.to_string(),
start_row_index: None,
row_count: Some(row_count),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct GridBlockMeta {
#[pb(index = 1)]
@ -225,7 +235,7 @@ impl ToString for AnyData {
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
pub struct RowMeta {
#[pb(index = 1)]
pub id: String,
@ -244,16 +254,11 @@ pub struct RowMeta {
}
impl RowMeta {
pub fn new(block_id: &str, cells: Vec<CellMeta>) -> Self {
let cell_by_field_id = cells
.into_iter()
.map(|cell| (cell.id.clone(), cell))
.collect::<HashMap<String, CellMeta>>();
pub fn new(block_id: &str) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string(),
block_id: block_id.to_owned(),
cell_by_field_id,
cell_by_field_id: Default::default(),
height: DEFAULT_ROW_HEIGHT,
visibility: true,
}
@ -275,20 +280,20 @@ pub struct RowMetaChangeset {
pub cell_by_field_id: HashMap<String, CellMeta>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, ProtoBuf)]
pub struct CellMeta {
#[pb(index = 1)]
pub id: String,
#[pb(index = 2)]
pub row_id: String,
#[pb(index = 3)]
pub field_id: String,
#[pb(index = 4)]
pub data: AnyData,
#[pb(index = 5)]
pub height: i32,
#[pb(index = 2)]
pub data: String,
}
impl CellMeta {
pub fn new(field_id: &str, data: String) -> Self {
Self {
field_id: field_id.to_string(),
data,
}
}
}

View File

@ -609,6 +609,7 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedFieldOrder {
pub struct RowOrder {
// message fields
pub row_id: ::std::string::String,
pub block_id: ::std::string::String,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -650,6 +651,32 @@ impl RowOrder {
pub fn take_row_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.row_id, ::std::string::String::new())
}
// string block_id = 2;
pub fn get_block_id(&self) -> &str {
&self.block_id
}
pub fn clear_block_id(&mut self) {
self.block_id.clear();
}
// Param is passed by value, moved
pub fn set_block_id(&mut self, v: ::std::string::String) {
self.block_id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_block_id(&mut self) -> &mut ::std::string::String {
&mut self.block_id
}
// Take field
pub fn take_block_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.block_id, ::std::string::String::new())
}
}
impl ::protobuf::Message for RowOrder {
@ -664,6 +691,9 @@ impl ::protobuf::Message for RowOrder {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?;
},
2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
@ -679,6 +709,9 @@ impl ::protobuf::Message for RowOrder {
if !self.row_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.row_id);
}
if !self.block_id.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.block_id);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
my_size
@ -688,6 +721,9 @@ impl ::protobuf::Message for RowOrder {
if !self.row_id.is_empty() {
os.write_string(1, &self.row_id)?;
}
if !self.block_id.is_empty() {
os.write_string(2, &self.block_id)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
@ -731,6 +767,11 @@ impl ::protobuf::Message for RowOrder {
|m: &RowOrder| { &m.row_id },
|m: &mut RowOrder| { &mut m.row_id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"block_id",
|m: &RowOrder| { &m.block_id },
|m: &mut RowOrder| { &mut m.block_id },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<RowOrder>(
"RowOrder",
fields,
@ -748,6 +789,7 @@ impl ::protobuf::Message for RowOrder {
impl ::protobuf::Clear for RowOrder {
fn clear(&mut self) {
self.row_id.clear();
self.block_id.clear();
self.unknown_fields.clear();
}
}
@ -1330,7 +1372,6 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedRow {
#[derive(PartialEq,Clone,Default)]
pub struct Cell {
// message fields
pub id: ::std::string::String,
pub field_id: ::std::string::String,
pub content: ::std::string::String,
// special fields
@ -1349,33 +1390,7 @@ impl Cell {
::std::default::Default::default()
}
// string id = 1;
pub fn get_id(&self) -> &str {
&self.id
}
pub fn clear_id(&mut self) {
self.id.clear();
}
// Param is passed by value, moved
pub fn set_id(&mut self, v: ::std::string::String) {
self.id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_id(&mut self) -> &mut ::std::string::String {
&mut self.id
}
// Take field
pub fn take_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.id, ::std::string::String::new())
}
// string field_id = 2;
// string field_id = 1;
pub fn get_field_id(&self) -> &str {
@ -1401,7 +1416,7 @@ impl Cell {
::std::mem::replace(&mut self.field_id, ::std::string::String::new())
}
// string content = 3;
// string content = 2;
pub fn get_content(&self) -> &str {
@ -1438,12 +1453,9 @@ impl ::protobuf::Message for Cell {
let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
},
2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
},
3 => {
2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.content)?;
},
_ => {
@ -1458,14 +1470,11 @@ impl ::protobuf::Message for Cell {
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.id);
}
if !self.field_id.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.field_id);
my_size += ::protobuf::rt::string_size(1, &self.field_id);
}
if !self.content.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.content);
my_size += ::protobuf::rt::string_size(2, &self.content);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
@ -1473,14 +1482,11 @@ impl ::protobuf::Message for Cell {
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.id.is_empty() {
os.write_string(1, &self.id)?;
}
if !self.field_id.is_empty() {
os.write_string(2, &self.field_id)?;
os.write_string(1, &self.field_id)?;
}
if !self.content.is_empty() {
os.write_string(3, &self.content)?;
os.write_string(2, &self.content)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
@ -1520,11 +1526,6 @@ impl ::protobuf::Message for Cell {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id",
|m: &Cell| { &m.id },
|m: &mut Cell| { &mut m.id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"field_id",
|m: &Cell| { &m.field_id },
@ -1551,7 +1552,6 @@ impl ::protobuf::Message for Cell {
impl ::protobuf::Clear for Cell {
fn clear(&mut self) {
self.id.clear();
self.field_id.clear();
self.content.clear();
self.unknown_fields.clear();
@ -2326,17 +2326,17 @@ static file_descriptor_proto_data: &'static [u8] = b"\
ders\x12(\n\nrow_orders\x18\x03\x20\x03(\x0b2\t.RowOrderR\trowOrders\"'\
\n\nFieldOrder\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\"7\n\
\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOr\
derR\x05items\"!\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\
\x05rowId\"3\n\x10RepeatedRowOrder\x12\x1f\n\x05items\x18\x01\x20\x03(\
\x0b2\t.RowOrderR\x05items\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\
\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.\
Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\x20\
\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\
\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.Cel\
lR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\
\x03(\x0b2\x04.RowR\x05items\"K\n\x04Cell\x12\x0e\n\x02id\x18\x01\x20\
\x01(\tR\x02id\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12\
\x18\n\x07content\x18\x03\x20\x01(\tR\x07content\"'\n\x11CreateGridPaylo\
derR\x05items\"<\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\
\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\"3\n\x10R\
epeatedRowOrder\x12\x1f\n\x05items\x18\x01\x20\x03(\x0b2\t.RowOrderR\x05\
items\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\
\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\
\rcellByFieldId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\
\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\
\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\
\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05ite\
ms\";\n\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\
\x18\n\x07content\x18\x02\x20\x01(\tR\x07content\"'\n\x11CreateGridPaylo\
ad\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\
\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"d\n\x11QueryFieldPayload\
\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orde\

View File

@ -2758,11 +2758,8 @@ impl ::protobuf::reflect::ProtobufValue for RowMetaChangeset {
#[derive(PartialEq,Clone,Default)]
pub struct CellMeta {
// message fields
pub id: ::std::string::String,
pub row_id: ::std::string::String,
pub field_id: ::std::string::String,
pub data: ::protobuf::SingularPtrField<AnyData>,
pub height: i32,
pub data: ::std::string::String,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -2779,59 +2776,7 @@ impl CellMeta {
::std::default::Default::default()
}
// string id = 1;
pub fn get_id(&self) -> &str {
&self.id
}
pub fn clear_id(&mut self) {
self.id.clear();
}
// Param is passed by value, moved
pub fn set_id(&mut self, v: ::std::string::String) {
self.id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_id(&mut self) -> &mut ::std::string::String {
&mut self.id
}
// Take field
pub fn take_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.id, ::std::string::String::new())
}
// string row_id = 2;
pub fn get_row_id(&self) -> &str {
&self.row_id
}
pub fn clear_row_id(&mut self) {
self.row_id.clear();
}
// Param is passed by value, moved
pub fn set_row_id(&mut self, v: ::std::string::String) {
self.row_id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_row_id(&mut self) -> &mut ::std::string::String {
&mut self.row_id
}
// Take field
pub fn take_row_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.row_id, ::std::string::String::new())
}
// string field_id = 3;
// string field_id = 1;
pub fn get_field_id(&self) -> &str {
@ -2857,62 +2802,35 @@ impl CellMeta {
::std::mem::replace(&mut self.field_id, ::std::string::String::new())
}
// .AnyData data = 4;
// string data = 2;
pub fn get_data(&self) -> &AnyData {
self.data.as_ref().unwrap_or_else(|| <AnyData as ::protobuf::Message>::default_instance())
pub fn get_data(&self) -> &str {
&self.data
}
pub fn clear_data(&mut self) {
self.data.clear();
}
pub fn has_data(&self) -> bool {
self.data.is_some()
}
// Param is passed by value, moved
pub fn set_data(&mut self, v: AnyData) {
self.data = ::protobuf::SingularPtrField::some(v);
pub fn set_data(&mut self, v: ::std::string::String) {
self.data = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut AnyData {
if self.data.is_none() {
self.data.set_default();
}
self.data.as_mut().unwrap()
pub fn mut_data(&mut self) -> &mut ::std::string::String {
&mut self.data
}
// Take field
pub fn take_data(&mut self) -> AnyData {
self.data.take().unwrap_or_else(|| AnyData::new())
}
// int32 height = 5;
pub fn get_height(&self) -> i32 {
self.height
}
pub fn clear_height(&mut self) {
self.height = 0;
}
// Param is passed by value, moved
pub fn set_height(&mut self, v: i32) {
self.height = v;
pub fn take_data(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.data, ::std::string::String::new())
}
}
impl ::protobuf::Message for CellMeta {
fn is_initialized(&self) -> bool {
for v in &self.data {
if !v.is_initialized() {
return false;
}
};
true
}
@ -2921,23 +2839,10 @@ impl ::protobuf::Message for CellMeta {
let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
},
2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?;
},
3 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?;
},
4 => {
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.data)?;
},
5 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_int32()?;
self.height = tmp;
2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -2951,21 +2856,11 @@ impl ::protobuf::Message for CellMeta {
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.id);
}
if !self.row_id.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.row_id);
}
if !self.field_id.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.field_id);
my_size += ::protobuf::rt::string_size(1, &self.field_id);
}
if let Some(ref v) = self.data.as_ref() {
let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
}
if self.height != 0 {
my_size += ::protobuf::rt::value_size(5, self.height, ::protobuf::wire_format::WireTypeVarint);
if !self.data.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.data);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
@ -2973,22 +2868,11 @@ impl ::protobuf::Message for CellMeta {
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.id.is_empty() {
os.write_string(1, &self.id)?;
}
if !self.row_id.is_empty() {
os.write_string(2, &self.row_id)?;
}
if !self.field_id.is_empty() {
os.write_string(3, &self.field_id)?;
os.write_string(1, &self.field_id)?;
}
if let Some(ref v) = self.data.as_ref() {
os.write_tag(4, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
}
if self.height != 0 {
os.write_int32(5, self.height)?;
if !self.data.is_empty() {
os.write_string(2, &self.data)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
@ -3028,31 +2912,16 @@ impl ::protobuf::Message for CellMeta {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id",
|m: &CellMeta| { &m.id },
|m: &mut CellMeta| { &mut m.id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"row_id",
|m: &CellMeta| { &m.row_id },
|m: &mut CellMeta| { &mut m.row_id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"field_id",
|m: &CellMeta| { &m.field_id },
|m: &mut CellMeta| { &mut m.field_id },
));
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<AnyData>>(
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data",
|m: &CellMeta| { &m.data },
|m: &mut CellMeta| { &mut m.data },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"height",
|m: &CellMeta| { &m.height },
|m: &mut CellMeta| { &mut m.height },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<CellMeta>(
"CellMeta",
fields,
@ -3069,11 +2938,8 @@ impl ::protobuf::Message for CellMeta {
impl ::protobuf::Clear for CellMeta {
fn clear(&mut self) {
self.id.clear();
self.row_id.clear();
self.field_id.clear();
self.data.clear();
self.height = 0;
self.unknown_fields.clear();
}
}
@ -3191,14 +3057,12 @@ static file_descriptor_proto_data: &'static [u8] = b"\
field_id\x18\x04\x20\x03(\x0b2$.RowMetaChangeset.CellByFieldIdEntryR\rce\
llByFieldId\x1aK\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\
\x01(\tR\x03key\x12\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05\
value:\x028\x01B\x0f\n\rone_of_heightB\x13\n\x11one_of_visibility\"\x82\
\x01\n\x08CellMeta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x15\n\
\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\
\x20\x01(\tR\x07fieldId\x12\x1c\n\x04data\x18\x04\x20\x01(\x0b2\x08.AnyD\
ataR\x04data\x12\x16\n\x06height\x18\x05\x20\x01(\x05R\x06height*d\n\tFi\
eldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\
\x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMult\
iSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\
value:\x028\x01B\x0f\n\rone_of_heightB\x13\n\x11one_of_visibility\"9\n\
\x08CellMeta\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\
\x12\n\x04data\x18\x02\x20\x01(\tR\x04data*d\n\tFieldType\x12\x0c\n\x08R\
ichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\
\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\
\x0c\n\x08Checkbox\x10\x05b\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -13,6 +13,7 @@ message RepeatedFieldOrder {
}
message RowOrder {
string row_id = 1;
string block_id = 2;
}
message RepeatedRowOrder {
repeated RowOrder items = 1;
@ -26,9 +27,8 @@ message RepeatedRow {
repeated Row items = 1;
}
message Cell {
string id = 1;
string field_id = 2;
string content = 3;
string field_id = 1;
string content = 2;
}
message CreateGridPayload {
string name = 1;

View File

@ -55,11 +55,8 @@ message RowMetaChangeset {
map<string, CellMeta> cell_by_field_id = 4;
}
message CellMeta {
string id = 1;
string row_id = 2;
string field_id = 3;
AnyData data = 4;
int32 height = 5;
string field_id = 1;
string data = 2;
}
enum FieldType {
RichText = 0;