chore: add grid unit test

This commit is contained in:
appflowy 2022-03-12 22:52:24 +08:00
parent 1e6d82c0ec
commit baa70f2ee6
18 changed files with 252 additions and 169 deletions

View File

@ -215,7 +215,7 @@ class Field extends $pb.GeneratedMessage {
..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'frozen')
..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'visibility')
..a<$core.int>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'width', $pb.PbFieldType.O3)
..aOM<AnyData>(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptions', subBuilder: AnyData.create)
..aOS(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptions')
..hasRequiredFields = false
;
@ -228,7 +228,7 @@ class Field extends $pb.GeneratedMessage {
$core.bool? frozen,
$core.bool? visibility,
$core.int? width,
AnyData? typeOptions,
$core.String? typeOptions,
}) {
final _result = create();
if (id != null) {
@ -342,15 +342,13 @@ class Field extends $pb.GeneratedMessage {
void clearWidth() => clearField(7);
@$pb.TagNumber(8)
AnyData get typeOptions => $_getN(7);
$core.String get typeOptions => $_getSZ(7);
@$pb.TagNumber(8)
set typeOptions(AnyData v) { setField(8, v); }
set typeOptions($core.String v) { $_setString(7, v); }
@$pb.TagNumber(8)
$core.bool hasTypeOptions() => $_has(7);
@$pb.TagNumber(8)
void clearTypeOptions() => clearField(8);
@$pb.TagNumber(8)
AnyData ensureTypeOptions() => $_ensure(7);
}
enum FieldChangeset_OneOfName {
@ -432,7 +430,7 @@ class FieldChangeset extends $pb.GeneratedMessage {
..aOB(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'frozen')
..aOB(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'visibility')
..a<$core.int>(7, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'width', $pb.PbFieldType.O3)
..aOM<AnyData>(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptions', subBuilder: AnyData.create)
..aOS(8, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptions')
..hasRequiredFields = false
;
@ -445,7 +443,7 @@ class FieldChangeset extends $pb.GeneratedMessage {
$core.bool? frozen,
$core.bool? visibility,
$core.int? width,
AnyData? typeOptions,
$core.String? typeOptions,
}) {
final _result = create();
if (fieldId != null) {
@ -580,15 +578,13 @@ class FieldChangeset extends $pb.GeneratedMessage {
void clearWidth() => clearField(7);
@$pb.TagNumber(8)
AnyData get typeOptions => $_getN(7);
$core.String get typeOptions => $_getSZ(7);
@$pb.TagNumber(8)
set typeOptions(AnyData v) { setField(8, v); }
set typeOptions($core.String v) { $_setString(7, v); }
@$pb.TagNumber(8)
$core.bool hasTypeOptions() => $_has(7);
@$pb.TagNumber(8)
void clearTypeOptions() => clearField(8);
@$pb.TagNumber(8)
AnyData ensureTypeOptions() => $_ensure(7);
}
class RepeatedField extends $pb.GeneratedMessage {

View File

@ -69,12 +69,12 @@ const Field$json = const {
const {'1': 'frozen', '3': 5, '4': 1, '5': 8, '10': 'frozen'},
const {'1': 'visibility', '3': 6, '4': 1, '5': 8, '10': 'visibility'},
const {'1': 'width', '3': 7, '4': 1, '5': 5, '10': 'width'},
const {'1': 'type_options', '3': 8, '4': 1, '5': 11, '6': '.AnyData', '10': 'typeOptions'},
const {'1': 'type_options', '3': 8, '4': 1, '5': 9, '10': 'typeOptions'},
],
};
/// Descriptor for `Field`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List fieldDescriptor = $convert.base64Decode('CgVGaWVsZBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEikKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZRIWCgZmcm96ZW4YBSABKAhSBmZyb3plbhIeCgp2aXNpYmlsaXR5GAYgASgIUgp2aXNpYmlsaXR5EhQKBXdpZHRoGAcgASgFUgV3aWR0aBIrCgx0eXBlX29wdGlvbnMYCCABKAsyCC5BbnlEYXRhUgt0eXBlT3B0aW9ucw==');
final $typed_data.Uint8List fieldDescriptor = $convert.base64Decode('CgVGaWVsZBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRISCgRkZXNjGAMgASgJUgRkZXNjEikKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZRIWCgZmcm96ZW4YBSABKAhSBmZyb3plbhIeCgp2aXNpYmlsaXR5GAYgASgIUgp2aXNpYmlsaXR5EhQKBXdpZHRoGAcgASgFUgV3aWR0aBIhCgx0eXBlX29wdGlvbnMYCCABKAlSC3R5cGVPcHRpb25z');
@$core.Deprecated('Use fieldChangesetDescriptor instead')
const FieldChangeset$json = const {
'1': 'FieldChangeset',
@ -86,7 +86,7 @@ const FieldChangeset$json = const {
const {'1': 'frozen', '3': 5, '4': 1, '5': 8, '9': 3, '10': 'frozen'},
const {'1': 'visibility', '3': 6, '4': 1, '5': 8, '9': 4, '10': 'visibility'},
const {'1': 'width', '3': 7, '4': 1, '5': 5, '9': 5, '10': 'width'},
const {'1': 'type_options', '3': 8, '4': 1, '5': 11, '6': '.AnyData', '9': 6, '10': 'typeOptions'},
const {'1': 'type_options', '3': 8, '4': 1, '5': 9, '9': 6, '10': 'typeOptions'},
],
'8': const [
const {'1': 'one_of_name'},
@ -100,7 +100,7 @@ const FieldChangeset$json = const {
};
/// Descriptor for `FieldChangeset`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List fieldChangesetDescriptor = $convert.base64Decode('Cg5GaWVsZENoYW5nZXNldBIZCghmaWVsZF9pZBgBIAEoCVIHZmllbGRJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEisKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVIAlIJZmllbGRUeXBlEhgKBmZyb3plbhgFIAEoCEgDUgZmcm96ZW4SIAoKdmlzaWJpbGl0eRgGIAEoCEgEUgp2aXNpYmlsaXR5EhYKBXdpZHRoGAcgASgFSAVSBXdpZHRoEi0KDHR5cGVfb3B0aW9ucxgIIAEoCzIILkFueURhdGFIBlILdHlwZU9wdGlvbnNCDQoLb25lX29mX25hbWVCDQoLb25lX29mX2Rlc2NCEwoRb25lX29mX2ZpZWxkX3R5cGVCDwoNb25lX29mX2Zyb3plbkITChFvbmVfb2ZfdmlzaWJpbGl0eUIOCgxvbmVfb2Zfd2lkdGhCFQoTb25lX29mX3R5cGVfb3B0aW9ucw==');
final $typed_data.Uint8List fieldChangesetDescriptor = $convert.base64Decode('Cg5GaWVsZENoYW5nZXNldBIZCghmaWVsZF9pZBgBIAEoCVIHZmllbGRJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEisKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVIAlIJZmllbGRUeXBlEhgKBmZyb3plbhgFIAEoCEgDUgZmcm96ZW4SIAoKdmlzaWJpbGl0eRgGIAEoCEgEUgp2aXNpYmlsaXR5EhYKBXdpZHRoGAcgASgFSAVSBXdpZHRoEiMKDHR5cGVfb3B0aW9ucxgIIAEoCUgGUgt0eXBlT3B0aW9uc0INCgtvbmVfb2ZfbmFtZUINCgtvbmVfb2ZfZGVzY0ITChFvbmVfb2ZfZmllbGRfdHlwZUIPCg1vbmVfb2ZfZnJvemVuQhMKEW9uZV9vZl92aXNpYmlsaXR5Qg4KDG9uZV9vZl93aWR0aEIVChNvbmVfb2ZfdHlwZV9vcHRpb25z');
@$core.Deprecated('Use repeatedFieldDescriptor instead')
const RepeatedField$json = const {
'1': 'RepeatedField',

View File

@ -1073,6 +1073,8 @@ dependencies = [
"rayon",
"rust_decimal",
"rusty-money",
"serde",
"serde_json",
"strum",
"strum_macros",
"tokio",

View File

@ -12,7 +12,7 @@ pub mod errors {
pub use flowy_error::{internal_error, ErrorCode, FlowyError};
}
pub const DOCUMENT_SYNC_INTERVAL_IN_MILLIS: u64 = 1000;
pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000;
use crate::errors::FlowyError;
use flowy_collaboration::entities::text_block_info::{

View File

@ -1,4 +1,4 @@
use crate::{queue::EditorCommand, DOCUMENT_SYNC_INTERVAL_IN_MILLIS};
use crate::{queue::EditorCommand, TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS};
use bytes::Bytes;
use flowy_collaboration::{
entities::{
@ -36,7 +36,7 @@ pub(crate) async fn make_block_ws_manager(
RichTextConflictController::new(&user_id, resolver, Arc::new(ws_data_provider.clone()), rev_manager);
let ws_data_stream = Arc::new(TextBlockRevisionWSDataStream::new(conflict_controller));
let ws_data_sink = Arc::new(TextBlockWSDataSink(ws_data_provider));
let ping_duration = Duration::from_millis(DOCUMENT_SYNC_INTERVAL_IN_MILLIS);
let ping_duration = Duration::from_millis(TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS);
let ws_manager = Arc::new(RevisionWebSocketManager::new(
"Block",
&doc_id,

View File

@ -1,5 +1,5 @@
use flowy_block::editor::ClientTextBlockEditor;
use flowy_block::DOCUMENT_SYNC_INTERVAL_IN_MILLIS;
use flowy_block::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS;
use flowy_sync::disk::RevisionState;
use flowy_test::{helper::ViewTest, FlowySDKTest};
use lib_ot::{core::Interval, rich_text::RichTextDelta};
@ -80,6 +80,6 @@ impl TextBlockEditorTest {
assert_eq!(expected_delta, delta);
}
}
sleep(Duration::from_millis(DOCUMENT_SYNC_INTERVAL_IN_MILLIS)).await;
sleep(Duration::from_millis(TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS)).await;
}
}

View File

@ -33,6 +33,8 @@ dashmap = "4.0"
tokio = {version = "1", features = ["sync"]}
rayon = "1.5"
parking_lot = "0.11"
serde = { version = "1.0", features = ["derive"] }
serde_json = {version = "1.0"}
[dev-dependencies]
flowy-test = { path = "../flowy-test" }

View File

@ -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(payload.field_orders).await?;
let repeated_field = editor.get_fields(Some(payload.field_orders)).await?;
data_result(repeated_field)
}

View File

@ -11,7 +11,7 @@ macro_rules! impl_from_field_type_option {
($target: ident) => {
impl std::convert::From<&Field> for $target {
fn from(field: &Field) -> $target {
match $target::try_from(Bytes::from(field.type_options.value.clone())) {
match serde_json::from_str(&field.type_options) {
Ok(obj) => obj,
Err(err) => {
tracing::error!("{} convert from any data failed, {:?}", stringify!($target), err);
@ -32,19 +32,13 @@ macro_rules! impl_to_field_type_option {
}
}
impl std::convert::From<$target> for AnyData {
impl std::convert::From<$target> for String {
fn from(field_description: $target) -> Self {
let field_type = field_description.field_type();
match field_description.try_into() {
Ok(bytes) => {
let bytes: Bytes = bytes;
AnyData::from_bytes(field_type, bytes)
}
match serde_json::to_string(&field_description) {
Ok(s) => s,
Err(e) => {
tracing::error!("Field type data convert to AnyData fail, error: {:?}", e);
// it's impossible to fail when unwrapping the default field type data
let default_bytes: Bytes = $target::default().try_into().unwrap();
AnyData::from_bytes(field_type, default_bytes)
serde_json::to_string(&$target::default()).unwrap()
}
}
}

View File

@ -59,7 +59,7 @@ impl FieldBuilder {
pub trait TypeOptionsBuilder {
fn field_type(&self) -> FieldType;
fn build(&self) -> AnyData;
fn build(&self) -> String;
}
// Text
@ -76,7 +76,7 @@ impl TypeOptionsBuilder for RichTextTypeOptionsBuilder {
self.0.field_type()
}
fn build(&self) -> AnyData {
fn build(&self) -> String {
self.0.clone().into()
}
}
@ -115,7 +115,7 @@ impl TypeOptionsBuilder for NumberTypeOptionsBuilder {
self.0.field_type()
}
fn build(&self) -> AnyData {
fn build(&self) -> String {
self.0.clone().into()
}
}
@ -142,7 +142,7 @@ impl TypeOptionsBuilder for DateTypeOptionsBuilder {
self.0.field_type()
}
fn build(&self) -> AnyData {
fn build(&self) -> String {
self.0.clone().into()
}
}
@ -165,7 +165,7 @@ impl TypeOptionsBuilder for SingleSelectTypeOptionsBuilder {
self.0.field_type()
}
fn build(&self) -> AnyData {
fn build(&self) -> String {
self.0.clone().into()
}
}
@ -189,7 +189,7 @@ impl TypeOptionsBuilder for MultiSelectTypeOptionsBuilder {
self.0.field_type()
}
fn build(&self) -> AnyData {
fn build(&self) -> String {
self.0.clone().into()
}
}
@ -211,7 +211,7 @@ impl TypeOptionsBuilder for CheckboxTypeOptionsBuilder {
self.0.field_type()
}
fn build(&self) -> AnyData {
fn build(&self) -> String {
self.0.clone().into()
}
}

View File

@ -13,10 +13,11 @@ use rusty_money::{
iso::{Currency, CNY, EUR, USD},
Money,
};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use strum_macros::EnumIter;
#[derive(Debug, Clone, ProtoBuf, Default)]
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct RichTextDescription {
#[pb(index = 1)]
pub format: String,
@ -34,7 +35,7 @@ impl StringifyCellData for RichTextDescription {
}
// Checkbox
#[derive(Debug, Clone, ProtoBuf, Default)]
#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)]
pub struct CheckboxDescription {
#[pb(index = 1)]
pub is_selected: bool,
@ -56,7 +57,7 @@ impl StringifyCellData for CheckboxDescription {
}
// Date
#[derive(Clone, Debug, ProtoBuf, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
pub struct DateDescription {
#[pb(index = 1)]
pub date_format: DateFormat,
@ -115,7 +116,7 @@ impl StringifyCellData for DateDescription {
}
}
#[derive(Clone, Debug, Copy, ProtoBuf_Enum)]
#[derive(Clone, Debug, Copy, Serialize, Deserialize, ProtoBuf_Enum)]
pub enum DateFormat {
Local = 0,
US = 1,
@ -158,7 +159,7 @@ impl DateFormat {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, ProtoBuf_Enum)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)]
pub enum TimeFormat {
TwelveHour = 0,
TwentyFourHour = 1,
@ -198,7 +199,7 @@ impl std::default::Default for TimeFormat {
}
// Single select
#[derive(Clone, Debug, ProtoBuf, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
pub struct SingleSelectDescription {
#[pb(index = 1)]
pub options: Vec<SelectOption>,
@ -219,7 +220,7 @@ impl StringifyCellData for SingleSelectDescription {
}
// Multiple select
#[derive(Clone, Debug, ProtoBuf, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
pub struct MultiSelectDescription {
#[pb(index = 1)]
pub options: Vec<SelectOption>,
@ -238,7 +239,7 @@ impl StringifyCellData for MultiSelectDescription {
}
}
#[derive(Clone, Debug, ProtoBuf, Default)]
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
pub struct SelectOption {
#[pb(index = 1)]
pub id: String,
@ -261,7 +262,7 @@ impl SelectOption {
}
// Number
#[derive(Clone, Debug, ProtoBuf)]
#[derive(Clone, Debug, Serialize, Deserialize, ProtoBuf)]
pub struct NumberDescription {
#[pb(index = 1)]
pub money: MoneySymbol,
@ -342,7 +343,7 @@ impl StringifyCellData for NumberDescription {
}
}
#[derive(Clone, Copy, Debug, EnumIter, ProtoBuf_Enum)]
#[derive(Clone, Copy, Debug, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)]
pub enum MoneySymbol {
CNY = 0,
EUR = 1,

View File

@ -9,7 +9,7 @@ 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, Grid, GridBlock, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
Field, FieldChangeset, Grid, GridBlock, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder,
};
use flowy_sync::disk::SQLiteGridBlockMetaRevisionPersistence;
use flowy_sync::{
@ -60,6 +60,11 @@ impl ClientGridEditor {
Ok(())
}
pub async fn update_field(&self, change: FieldChangeset) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.update_field(change)?)).await?;
Ok(())
}
pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.delete_field(field_id)?)).await?;
Ok(())
@ -81,7 +86,7 @@ impl ClientGridEditor {
todo!()
}
pub async fn get_fields(&self, field_orders: RepeatedFieldOrder) -> FlowyResult<RepeatedField> {
pub async fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> FlowyResult<RepeatedField> {
let fields = self.grid_meta_pad.read().await.get_fields(field_orders)?;
Ok(fields)
}

View File

@ -1,14 +1,98 @@
use crate::grid::script::EditorScript::*;
use crate::grid::script::*;
use flowy_grid::services::field::{SelectOption, SingleSelectDescription};
use flowy_grid_data_model::entities::FieldChangeset;
#[tokio::test]
async fn grid_creat_field_test() {
async fn default_grid_test() {
let scripts = vec![AssertFieldCount(2), AssertGridMetaPad];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_create_field() {
let text_field = create_text_field();
let single_select_field = create_single_select_field();
let scripts = vec![
AssertFieldCount(2),
CreateField {
field: text_field.clone(),
},
AssertFieldEqual {
field_index: 2,
field: text_field,
},
AssertFieldCount(3),
CreateField {
field: single_select_field.clone(),
},
AssertFieldEqual {
field_index: 3,
field: single_select_field,
},
AssertFieldCount(4),
];
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();
let change = FieldChangeset {
field_id: single_select_field.id.clone(),
name: None,
desc: None,
field_type: None,
frozen: None,
visibility: None,
width: None,
type_options: None,
};
let scripts = vec![
CreateField {
field: create_text_field(),
field: single_select_field.clone(),
},
UpdateField { change },
AssertFieldEqual {
field_index: 2,
field: single_select_field,
},
];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
async fn grid_update_field() {
let single_select_field = create_single_select_field();
let mut cloned_field = single_select_field.clone();
let mut single_select_type_options = SingleSelectDescription::from(&single_select_field);
single_select_type_options.options.push(SelectOption::new("Unknown"));
let change = FieldChangeset {
field_id: single_select_field.id.clone(),
name: None,
desc: None,
field_type: None,
frozen: Some(true),
visibility: None,
width: Some(1000),
type_options: Some(single_select_type_options.clone().into()),
};
cloned_field.frozen = true;
cloned_field.width = 1000;
cloned_field.type_options = single_select_type_options.into();
let scripts = vec![
CreateField {
field: create_single_select_field(),
field: single_select_field.clone(),
},
UpdateField { change },
AssertFieldEqual {
field_index: 2,
field: cloned_field,
},
AssertGridMetaPad,
];

View File

@ -1,15 +1,21 @@
use flowy_grid::services::field::*;
use flowy_grid::services::grid_editor::{ClientGridEditor, GridPadBuilder};
use flowy_grid_data_model::entities::{AnyData, Field, FieldType};
use flowy_grid_data_model::entities::{AnyData, Field, FieldChangeset, FieldType};
use flowy_sync::REVISION_WRITE_INTERVAL_IN_MILLIS;
use flowy_test::event_builder::FolderEventBuilder;
use flowy_test::helper::ViewTest;
use flowy_test::FlowySDKTest;
use std::sync::Arc;
use std::time::Duration;
use tokio::time::sleep;
pub enum EditorScript {
CreateField { field: Field },
CreateRow,
UpdateField { change: FieldChangeset },
AssertFieldCount(usize),
AssertFieldEqual { field_index: usize, field: Field },
AssertGridMetaPad,
CreateRow,
}
pub struct GridEditorTest {
@ -44,12 +50,24 @@ impl GridEditorTest {
EditorScript::CreateField { field } => {
self.editor.create_field(field).await.unwrap();
}
EditorScript::CreateRow => {}
EditorScript::UpdateField { change } => {
self.editor.update_field(change).await.unwrap();
}
EditorScript::AssertFieldCount(count) => {
assert_eq!(self.editor.get_fields(None).await.unwrap().len(), count);
}
EditorScript::AssertFieldEqual { field_index, field } => {
let repeated_fields = self.editor.get_fields(None).await.unwrap();
let compared_field = repeated_fields[field_index].clone();
assert_eq!(compared_field, field);
}
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

@ -51,25 +51,30 @@ impl GridMetaPad {
})
}
pub fn get_fields(&self, field_orders: RepeatedFieldOrder) -> CollaborateResult<RepeatedField> {
let field_by_field_id = self
.grid_meta
.fields
.iter()
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &Field>>();
pub fn get_fields(&self, field_orders: Option<RepeatedFieldOrder>) -> CollaborateResult<RepeatedField> {
match field_orders {
None => Ok(self.grid_meta.fields.clone().into()),
Some(field_orders) => {
let field_by_field_id = self
.grid_meta
.fields
.iter()
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &Field>>();
let fields = field_orders
.iter()
.flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) {
None => {
tracing::error!("Can't find the field with id: {}", field_order.field_id);
None
}
Some(field) => Some((*field).clone()),
})
.collect::<Vec<Field>>();
Ok(fields.into())
let fields = field_orders
.iter()
.flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) {
None => {
tracing::error!("Can't find the field with id: {}", field_order.field_id);
None
}
Some(field) => Some((*field).clone()),
})
.collect::<Vec<Field>>();
Ok(fields.into())
}
}
}
pub fn update_field(&mut self, change: FieldChangeset) -> CollaborateResult<Option<GridChange>> {

View File

@ -54,7 +54,7 @@ pub struct GridBlockMeta {
pub rows: Vec<RowMeta>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf, PartialEq, Eq)]
pub struct Field {
#[pb(index = 1)]
pub id: String,
@ -78,7 +78,7 @@ pub struct Field {
pub width: i32,
#[pb(index = 8)]
pub type_options: AnyData,
pub type_options: String,
}
impl Field {
@ -120,7 +120,7 @@ pub struct FieldChangeset {
pub width: Option<i32>,
#[pb(index = 8, one_of)]
pub type_options: Option<AnyData>,
pub type_options: Option<String>,
}
#[derive(Debug, Default, ProtoBuf)]

View File

@ -727,7 +727,7 @@ pub struct Field {
pub frozen: bool,
pub visibility: bool,
pub width: i32,
pub type_options: ::protobuf::SingularPtrField<AnyData>,
pub type_options: ::std::string::String,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -882,47 +882,35 @@ impl Field {
self.width = v;
}
// .AnyData type_options = 8;
// string type_options = 8;
pub fn get_type_options(&self) -> &AnyData {
self.type_options.as_ref().unwrap_or_else(|| <AnyData as ::protobuf::Message>::default_instance())
pub fn get_type_options(&self) -> &str {
&self.type_options
}
pub fn clear_type_options(&mut self) {
self.type_options.clear();
}
pub fn has_type_options(&self) -> bool {
self.type_options.is_some()
}
// Param is passed by value, moved
pub fn set_type_options(&mut self, v: AnyData) {
self.type_options = ::protobuf::SingularPtrField::some(v);
pub fn set_type_options(&mut self, v: ::std::string::String) {
self.type_options = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_type_options(&mut self) -> &mut AnyData {
if self.type_options.is_none() {
self.type_options.set_default();
}
self.type_options.as_mut().unwrap()
pub fn mut_type_options(&mut self) -> &mut ::std::string::String {
&mut self.type_options
}
// Take field
pub fn take_type_options(&mut self) -> AnyData {
self.type_options.take().unwrap_or_else(|| AnyData::new())
pub fn take_type_options(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.type_options, ::std::string::String::new())
}
}
impl ::protobuf::Message for Field {
fn is_initialized(&self) -> bool {
for v in &self.type_options {
if !v.is_initialized() {
return false;
}
};
true
}
@ -964,7 +952,7 @@ impl ::protobuf::Message for Field {
self.width = tmp;
},
8 => {
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.type_options)?;
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.type_options)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -999,9 +987,8 @@ impl ::protobuf::Message for Field {
if self.width != 0 {
my_size += ::protobuf::rt::value_size(7, self.width, ::protobuf::wire_format::WireTypeVarint);
}
if let Some(ref v) = self.type_options.as_ref() {
let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
if !self.type_options.is_empty() {
my_size += ::protobuf::rt::string_size(8, &self.type_options);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
@ -1030,10 +1017,8 @@ impl ::protobuf::Message for Field {
if self.width != 0 {
os.write_int32(7, self.width)?;
}
if let Some(ref v) = self.type_options.as_ref() {
os.write_tag(8, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
if !self.type_options.is_empty() {
os.write_string(8, &self.type_options)?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
@ -1108,7 +1093,7 @@ impl ::protobuf::Message for Field {
|m: &Field| { &m.width },
|m: &mut Field| { &mut m.width },
));
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>(
"type_options",
|m: &Field| { &m.type_options },
|m: &mut Field| { &mut m.type_options },
@ -1208,7 +1193,7 @@ pub enum FieldChangeset_oneof_one_of_width {
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_type_options {
type_options(AnyData),
type_options(::std::string::String),
}
impl FieldChangeset {
@ -1440,13 +1425,13 @@ impl FieldChangeset {
self.one_of_width = ::std::option::Option::Some(FieldChangeset_oneof_one_of_width::width(v))
}
// .AnyData type_options = 8;
// string type_options = 8;
pub fn get_type_options(&self) -> &AnyData {
pub fn get_type_options(&self) -> &str {
match self.one_of_type_options {
::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(ref v)) => v,
_ => <AnyData as ::protobuf::Message>::default_instance(),
_ => "",
}
}
pub fn clear_type_options(&mut self) {
@ -1461,15 +1446,15 @@ impl FieldChangeset {
}
// Param is passed by value, moved
pub fn set_type_options(&mut self, v: AnyData) {
pub fn set_type_options(&mut self, v: ::std::string::String) {
self.one_of_type_options = ::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(v))
}
// Mutable pointer to the field.
pub fn mut_type_options(&mut self) -> &mut AnyData {
pub fn mut_type_options(&mut self) -> &mut ::std::string::String {
if let ::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(_)) = self.one_of_type_options {
} else {
self.one_of_type_options = ::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(AnyData::new()));
self.one_of_type_options = ::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(::std::string::String::new()));
}
match self.one_of_type_options {
::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(ref mut v)) => v,
@ -1478,25 +1463,20 @@ impl FieldChangeset {
}
// Take field
pub fn take_type_options(&mut self) -> AnyData {
pub fn take_type_options(&mut self) -> ::std::string::String {
if self.has_type_options() {
match self.one_of_type_options.take() {
::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(v)) => v,
_ => panic!(),
}
} else {
AnyData::new()
::std::string::String::new()
}
}
}
impl ::protobuf::Message for FieldChangeset {
fn is_initialized(&self) -> bool {
if let Some(FieldChangeset_oneof_one_of_type_options::type_options(ref v)) = self.one_of_type_options {
if !v.is_initialized() {
return false;
}
}
true
}
@ -1547,7 +1527,7 @@ impl ::protobuf::Message for FieldChangeset {
if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_type_options = ::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(is.read_message()?));
self.one_of_type_options = ::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(is.read_string()?));
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -1609,8 +1589,7 @@ impl ::protobuf::Message for FieldChangeset {
if let ::std::option::Option::Some(ref v) = self.one_of_type_options {
match v {
&FieldChangeset_oneof_one_of_type_options::type_options(ref v) => {
let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
my_size += ::protobuf::rt::string_size(8, &v);
},
};
}
@ -1668,9 +1647,7 @@ impl ::protobuf::Message for FieldChangeset {
if let ::std::option::Option::Some(ref v) = self.one_of_type_options {
match v {
&FieldChangeset_oneof_one_of_type_options::type_options(ref v) => {
os.write_tag(8, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
os.write_string(8, v)?;
},
};
}
@ -1747,7 +1724,7 @@ impl ::protobuf::Message for FieldChangeset {
FieldChangeset::has_width,
FieldChangeset::get_width,
));
fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, AnyData>(
fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
"type_options",
FieldChangeset::has_type_options,
FieldChangeset::get_type_options,
@ -3183,46 +3160,45 @@ static file_descriptor_proto_data: &'static [u8] = b"\
ndex\x18\x02\x20\x01(\x05R\rstartRowIndex\x12\x1b\n\trow_count\x18\x03\
\x20\x01(\x05R\x08rowCount\"H\n\rGridBlockMeta\x12\x19\n\x08block_id\x18\
\x01\x20\x01(\tR\x07blockId\x12\x1c\n\x04rows\x18\x02\x20\x03(\x0b2\x08.\
RowMetaR\x04rows\"\xe5\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
RowMetaR\x04rows\"\xdb\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
R\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\
\x18\x03\x20\x01(\tR\x04desc\x12)\n\nfield_type\x18\x04\x20\x01(\x0e2\n.\
FieldTypeR\tfieldType\x12\x16\n\x06frozen\x18\x05\x20\x01(\x08R\x06froze\
n\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\nvisibility\x12\x14\n\x05w\
idth\x18\x07\x20\x01(\x05R\x05width\x12+\n\x0ctype_options\x18\x08\x20\
\x01(\x0b2\x08.AnyDataR\x0btypeOptions\"\x87\x03\n\x0eFieldChangeset\x12\
\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x14\n\x04name\x18\
\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\
\x04desc\x12+\n\nfield_type\x18\x04\x20\x01(\x0e2\n.FieldTypeH\x02R\tfie\
ldType\x12\x18\n\x06frozen\x18\x05\x20\x01(\x08H\x03R\x06frozen\x12\x20\
\n\nvisibility\x18\x06\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\
\x18\x07\x20\x01(\x05H\x05R\x05width\x12-\n\x0ctype_options\x18\x08\x20\
\x01(\x0b2\x08.AnyDataH\x06R\x0btypeOptionsB\r\n\x0bone_of_nameB\r\n\x0b\
one_of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11\
one_of_visibilityB\x0e\n\x0cone_of_widthB\x15\n\x13one_of_type_options\"\
-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\
\x05items\"8\n\x07AnyData\x12\x17\n\x07type_id\x18\x01\x20\x01(\tR\x06ty\
peId\x12\x14\n\x05value\x18\x02\x20\x01(\x0cR\x05value\"\xff\x01\n\x07Ro\
wMeta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x19\n\x08block_id\
\x18\x02\x20\x01(\tR\x07blockId\x12D\n\x10cell_by_field_id\x18\x03\x20\
\x03(\x0b2\x1b.RowMeta.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06h\
eight\x18\x04\x20\x01(\x05R\x06height\x12\x1e\n\nvisibility\x18\x05\x20\
\x01(\x08R\nvisibility\x1aK\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\
\x01\x20\x01(\tR\x03key\x12\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellM\
etaR\x05value:\x028\x01\"\xa7\x02\n\x10RowMetaChangeset\x12\x15\n\x06row\
_id\x18\x01\x20\x01(\tR\x05rowId\x12\x18\n\x06height\x18\x02\x20\x01(\
\x05H\0R\x06height\x12\x20\n\nvisibility\x18\x03\x20\x01(\x08H\x01R\nvis\
ibility\x12M\n\x10cell_by_field_id\x18\x04\x20\x03(\x0b2$.RowMetaChanges\
et.CellByFieldIdEntryR\rcellByFieldId\x1aK\n\x12CellByFieldIdEntry\x12\
\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1f\n\x05value\x18\x02\x20\
\x01(\x0b2\t.CellMetaR\x05value:\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.AnyDataR\x04data\x12\x16\n\x06height\x18\x05\x20\
\x01(\x05R\x06height*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\
\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSele\
ct\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\
\x05b\x06proto3\
idth\x18\x07\x20\x01(\x05R\x05width\x12!\n\x0ctype_options\x18\x08\x20\
\x01(\tR\x0btypeOptions\"\xfd\x02\n\x0eFieldChangeset\x12\x19\n\x08field\
_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x14\n\x04name\x18\x02\x20\x01(\tH\
\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\tH\x01R\x04desc\x12+\n\nf\
ield_type\x18\x04\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\
\x06frozen\x18\x05\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\
\x18\x06\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x07\x20\
\x01(\x05H\x05R\x05width\x12#\n\x0ctype_options\x18\x08\x20\x01(\tH\x06R\
\x0btypeOptionsB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one_of\
_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\x0c\
one_of_widthB\x15\n\x13one_of_type_options\"-\n\rRepeatedField\x12\x1c\n\
\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"8\n\x07AnyData\x12\
\x17\n\x07type_id\x18\x01\x20\x01(\tR\x06typeId\x12\x14\n\x05value\x18\
\x02\x20\x01(\x0cR\x05value\"\xff\x01\n\x07RowMeta\x12\x0e\n\x02id\x18\
\x01\x20\x01(\tR\x02id\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07bloc\
kId\x12D\n\x10cell_by_field_id\x18\x03\x20\x03(\x0b2\x1b.RowMeta.CellByF\
ieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x04\x20\x01(\x05R\
\x06height\x12\x1e\n\nvisibility\x18\x05\x20\x01(\x08R\nvisibility\x1aK\
\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\
\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05value:\x028\x01\"\
\xa7\x02\n\x10RowMetaChangeset\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\
\x05rowId\x12\x18\n\x06height\x18\x02\x20\x01(\x05H\0R\x06height\x12\x20\
\n\nvisibility\x18\x03\x20\x01(\x08H\x01R\nvisibility\x12M\n\x10cell_by_\
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\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -22,7 +22,7 @@ message Field {
bool frozen = 5;
bool visibility = 6;
int32 width = 7;
AnyData type_options = 8;
string type_options = 8;
}
message FieldChangeset {
string field_id = 1;
@ -32,7 +32,7 @@ message FieldChangeset {
oneof one_of_frozen { bool frozen = 5; };
oneof one_of_visibility { bool visibility = 6; };
oneof one_of_width { int32 width = 7; };
oneof one_of_type_options { AnyData type_options = 8; };
oneof one_of_type_options { string type_options = 8; };
}
message RepeatedField {
repeated Field items = 1;