chore: grid block meta editor

This commit is contained in:
appflowy 2022-03-11 21:36:00 +08:00
parent 9a791974b4
commit e11176436d
32 changed files with 1887 additions and 529 deletions

View File

@ -17,7 +17,7 @@ class GridMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridMeta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
..pc<Field>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fields', $pb.PbFieldType.PM, subBuilder: Field.create)
..pc<Block>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blocks', $pb.PbFieldType.PM, subBuilder: Block.create)
..pc<GridBlock>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blocks', $pb.PbFieldType.PM, subBuilder: GridBlock.create)
..hasRequiredFields = false
;
@ -25,7 +25,7 @@ class GridMeta extends $pb.GeneratedMessage {
factory GridMeta({
$core.String? gridId,
$core.Iterable<Field>? fields,
$core.Iterable<Block>? blocks,
$core.Iterable<GridBlock>? blocks,
}) {
final _result = create();
if (gridId != null) {
@ -73,19 +73,19 @@ class GridMeta extends $pb.GeneratedMessage {
$core.List<Field> get fields => $_getList(1);
@$pb.TagNumber(3)
$core.List<Block> get blocks => $_getList(2);
$core.List<GridBlock> get blocks => $_getList(2);
}
class Block extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Block', createEmptyInstance: create)
class GridBlock extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlock', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'startRowIndex', $pb.PbFieldType.O3)
..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowCount', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
Block._() : super();
factory Block({
GridBlock._() : super();
factory GridBlock({
$core.String? id,
$core.int? startRowIndex,
$core.int? rowCount,
@ -102,26 +102,26 @@ class Block extends $pb.GeneratedMessage {
}
return _result;
}
factory Block.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory Block.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
factory GridBlock.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory GridBlock.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
Block clone() => Block()..mergeFromMessage(this);
GridBlock clone() => GridBlock()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
Block copyWith(void Function(Block) updates) => super.copyWith((message) => updates(message as Block)) as Block; // ignore: deprecated_member_use
GridBlock copyWith(void Function(GridBlock) updates) => super.copyWith((message) => updates(message as GridBlock)) as GridBlock; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static Block create() => Block._();
Block createEmptyInstance() => create();
static $pb.PbList<Block> createRepeated() => $pb.PbList<Block>();
static GridBlock create() => GridBlock._();
GridBlock createEmptyInstance() => create();
static $pb.PbList<GridBlock> createRepeated() => $pb.PbList<GridBlock>();
@$core.pragma('dart2js:noInline')
static Block getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Block>(create);
static Block? _defaultInstance;
static GridBlock getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlock>(create);
static GridBlock? _defaultInstance;
@$pb.TagNumber(1)
$core.String get id => $_getSZ(0);
@ -151,15 +151,15 @@ class Block extends $pb.GeneratedMessage {
void clearRowCount() => clearField(3);
}
class BlockMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockMeta', createEmptyInstance: create)
class GridBlockMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockMeta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..pc<RowMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rows', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..hasRequiredFields = false
;
BlockMeta._() : super();
factory BlockMeta({
GridBlockMeta._() : super();
factory GridBlockMeta({
$core.String? blockId,
$core.Iterable<RowMeta>? rows,
}) {
@ -172,26 +172,26 @@ class BlockMeta extends $pb.GeneratedMessage {
}
return _result;
}
factory BlockMeta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory BlockMeta.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
factory GridBlockMeta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory GridBlockMeta.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
BlockMeta clone() => BlockMeta()..mergeFromMessage(this);
GridBlockMeta clone() => GridBlockMeta()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
BlockMeta copyWith(void Function(BlockMeta) updates) => super.copyWith((message) => updates(message as BlockMeta)) as BlockMeta; // ignore: deprecated_member_use
GridBlockMeta copyWith(void Function(GridBlockMeta) updates) => super.copyWith((message) => updates(message as GridBlockMeta)) as GridBlockMeta; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static BlockMeta create() => BlockMeta._();
BlockMeta createEmptyInstance() => create();
static $pb.PbList<BlockMeta> createRepeated() => $pb.PbList<BlockMeta>();
static GridBlockMeta create() => GridBlockMeta._();
GridBlockMeta createEmptyInstance() => create();
static $pb.PbList<GridBlockMeta> createRepeated() => $pb.PbList<GridBlockMeta>();
@$core.pragma('dart2js:noInline')
static BlockMeta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockMeta>(create);
static BlockMeta? _defaultInstance;
static GridBlockMeta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlockMeta>(create);
static GridBlockMeta? _defaultInstance;
@$pb.TagNumber(1)
$core.String get blockId => $_getSZ(0);
@ -394,6 +394,244 @@ class RepeatedField extends $pb.GeneratedMessage {
$core.List<Field> get items => $_getList(0);
}
enum FieldChangeset_OneOfName {
name,
notSet
}
enum FieldChangeset_OneOfDesc {
desc,
notSet
}
enum FieldChangeset_OneOfFieldType {
fieldType,
notSet
}
enum FieldChangeset_OneOfFrozen {
frozen,
notSet
}
enum FieldChangeset_OneOfVisibility {
visibility,
notSet
}
enum FieldChangeset_OneOfWidth {
width,
notSet
}
enum FieldChangeset_OneOfTypeOptions {
typeOptions,
notSet
}
class FieldChangeset extends $pb.GeneratedMessage {
static const $core.Map<$core.int, FieldChangeset_OneOfName> _FieldChangeset_OneOfNameByTag = {
2 : FieldChangeset_OneOfName.name,
0 : FieldChangeset_OneOfName.notSet
};
static const $core.Map<$core.int, FieldChangeset_OneOfDesc> _FieldChangeset_OneOfDescByTag = {
3 : FieldChangeset_OneOfDesc.desc,
0 : FieldChangeset_OneOfDesc.notSet
};
static const $core.Map<$core.int, FieldChangeset_OneOfFieldType> _FieldChangeset_OneOfFieldTypeByTag = {
4 : FieldChangeset_OneOfFieldType.fieldType,
0 : FieldChangeset_OneOfFieldType.notSet
};
static const $core.Map<$core.int, FieldChangeset_OneOfFrozen> _FieldChangeset_OneOfFrozenByTag = {
5 : FieldChangeset_OneOfFrozen.frozen,
0 : FieldChangeset_OneOfFrozen.notSet
};
static const $core.Map<$core.int, FieldChangeset_OneOfVisibility> _FieldChangeset_OneOfVisibilityByTag = {
6 : FieldChangeset_OneOfVisibility.visibility,
0 : FieldChangeset_OneOfVisibility.notSet
};
static const $core.Map<$core.int, FieldChangeset_OneOfWidth> _FieldChangeset_OneOfWidthByTag = {
7 : FieldChangeset_OneOfWidth.width,
0 : FieldChangeset_OneOfWidth.notSet
};
static const $core.Map<$core.int, FieldChangeset_OneOfTypeOptions> _FieldChangeset_OneOfTypeOptionsByTag = {
8 : FieldChangeset_OneOfTypeOptions.typeOptions,
0 : FieldChangeset_OneOfTypeOptions.notSet
};
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldChangeset', createEmptyInstance: create)
..oo(0, [2])
..oo(1, [3])
..oo(2, [4])
..oo(3, [5])
..oo(4, [6])
..oo(5, [7])
..oo(6, [8])
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId')
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
..e<FieldType>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values)
..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)
..hasRequiredFields = false
;
FieldChangeset._() : super();
factory FieldChangeset({
$core.String? fieldId,
$core.String? name,
$core.String? desc,
FieldType? fieldType,
$core.bool? frozen,
$core.bool? visibility,
$core.int? width,
AnyData? typeOptions,
}) {
final _result = create();
if (fieldId != null) {
_result.fieldId = fieldId;
}
if (name != null) {
_result.name = name;
}
if (desc != null) {
_result.desc = desc;
}
if (fieldType != null) {
_result.fieldType = fieldType;
}
if (frozen != null) {
_result.frozen = frozen;
}
if (visibility != null) {
_result.visibility = visibility;
}
if (width != null) {
_result.width = width;
}
if (typeOptions != null) {
_result.typeOptions = typeOptions;
}
return _result;
}
factory FieldChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory FieldChangeset.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
FieldChangeset clone() => FieldChangeset()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
FieldChangeset copyWith(void Function(FieldChangeset) updates) => super.copyWith((message) => updates(message as FieldChangeset)) as FieldChangeset; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static FieldChangeset create() => FieldChangeset._();
FieldChangeset createEmptyInstance() => create();
static $pb.PbList<FieldChangeset> createRepeated() => $pb.PbList<FieldChangeset>();
@$core.pragma('dart2js:noInline')
static FieldChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<FieldChangeset>(create);
static FieldChangeset? _defaultInstance;
FieldChangeset_OneOfName whichOneOfName() => _FieldChangeset_OneOfNameByTag[$_whichOneof(0)]!;
void clearOneOfName() => clearField($_whichOneof(0));
FieldChangeset_OneOfDesc whichOneOfDesc() => _FieldChangeset_OneOfDescByTag[$_whichOneof(1)]!;
void clearOneOfDesc() => clearField($_whichOneof(1));
FieldChangeset_OneOfFieldType whichOneOfFieldType() => _FieldChangeset_OneOfFieldTypeByTag[$_whichOneof(2)]!;
void clearOneOfFieldType() => clearField($_whichOneof(2));
FieldChangeset_OneOfFrozen whichOneOfFrozen() => _FieldChangeset_OneOfFrozenByTag[$_whichOneof(3)]!;
void clearOneOfFrozen() => clearField($_whichOneof(3));
FieldChangeset_OneOfVisibility whichOneOfVisibility() => _FieldChangeset_OneOfVisibilityByTag[$_whichOneof(4)]!;
void clearOneOfVisibility() => clearField($_whichOneof(4));
FieldChangeset_OneOfWidth whichOneOfWidth() => _FieldChangeset_OneOfWidthByTag[$_whichOneof(5)]!;
void clearOneOfWidth() => clearField($_whichOneof(5));
FieldChangeset_OneOfTypeOptions whichOneOfTypeOptions() => _FieldChangeset_OneOfTypeOptionsByTag[$_whichOneof(6)]!;
void clearOneOfTypeOptions() => clearField($_whichOneof(6));
@$pb.TagNumber(1)
$core.String get fieldId => $_getSZ(0);
@$pb.TagNumber(1)
set fieldId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasFieldId() => $_has(0);
@$pb.TagNumber(1)
void clearFieldId() => clearField(1);
@$pb.TagNumber(2)
$core.String get name => $_getSZ(1);
@$pb.TagNumber(2)
set name($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2)
$core.bool hasName() => $_has(1);
@$pb.TagNumber(2)
void clearName() => clearField(2);
@$pb.TagNumber(3)
$core.String get desc => $_getSZ(2);
@$pb.TagNumber(3)
set desc($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3)
$core.bool hasDesc() => $_has(2);
@$pb.TagNumber(3)
void clearDesc() => clearField(3);
@$pb.TagNumber(4)
FieldType get fieldType => $_getN(3);
@$pb.TagNumber(4)
set fieldType(FieldType v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasFieldType() => $_has(3);
@$pb.TagNumber(4)
void clearFieldType() => clearField(4);
@$pb.TagNumber(5)
$core.bool get frozen => $_getBF(4);
@$pb.TagNumber(5)
set frozen($core.bool v) { $_setBool(4, v); }
@$pb.TagNumber(5)
$core.bool hasFrozen() => $_has(4);
@$pb.TagNumber(5)
void clearFrozen() => clearField(5);
@$pb.TagNumber(6)
$core.bool get visibility => $_getBF(5);
@$pb.TagNumber(6)
set visibility($core.bool v) { $_setBool(5, v); }
@$pb.TagNumber(6)
$core.bool hasVisibility() => $_has(5);
@$pb.TagNumber(6)
void clearVisibility() => clearField(6);
@$pb.TagNumber(7)
$core.int get width => $_getIZ(6);
@$pb.TagNumber(7)
set width($core.int v) { $_setSignedInt32(6, v); }
@$pb.TagNumber(7)
$core.bool hasWidth() => $_has(6);
@$pb.TagNumber(7)
void clearWidth() => clearField(7);
@$pb.TagNumber(8)
AnyData get typeOptions => $_getN(7);
@$pb.TagNumber(8)
set typeOptions(AnyData v) { setField(8, v); }
@$pb.TagNumber(8)
$core.bool hasTypeOptions() => $_has(7);
@$pb.TagNumber(8)
void clearTypeOptions() => clearField(8);
@$pb.TagNumber(8)
AnyData ensureTypeOptions() => $_ensure(7);
}
class AnyData extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'AnyData', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeId')

View File

@ -29,15 +29,15 @@ const GridMeta$json = const {
'2': const [
const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
const {'1': 'fields', '3': 2, '4': 3, '5': 11, '6': '.Field', '10': 'fields'},
const {'1': 'blocks', '3': 3, '4': 3, '5': 11, '6': '.Block', '10': 'blocks'},
const {'1': 'blocks', '3': 3, '4': 3, '5': 11, '6': '.GridBlock', '10': 'blocks'},
],
};
/// Descriptor for `GridMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSHgoGZmllbGRzGAIgAygLMgYuRmllbGRSBmZpZWxkcxIeCgZibG9ja3MYAyADKAsyBi5CbG9ja1IGYmxvY2tz');
@$core.Deprecated('Use blockDescriptor instead')
const Block$json = const {
'1': 'Block',
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSHgoGZmllbGRzGAIgAygLMgYuRmllbGRSBmZpZWxkcxIiCgZibG9ja3MYAyADKAsyCi5HcmlkQmxvY2tSBmJsb2Nrcw==');
@$core.Deprecated('Use gridBlockDescriptor instead')
const GridBlock$json = const {
'1': 'GridBlock',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {'1': 'start_row_index', '3': 2, '4': 1, '5': 5, '10': 'startRowIndex'},
@ -45,19 +45,19 @@ const Block$json = const {
],
};
/// Descriptor for `Block`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List blockDescriptor = $convert.base64Decode('CgVCbG9jaxIOCgJpZBgBIAEoCVICaWQSJgoPc3RhcnRfcm93X2luZGV4GAIgASgFUg1zdGFydFJvd0luZGV4EhsKCXJvd19jb3VudBgDIAEoBVIIcm93Q291bnQ=');
@$core.Deprecated('Use blockMetaDescriptor instead')
const BlockMeta$json = const {
'1': 'BlockMeta',
/// Descriptor for `GridBlock`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSDgoCaWQYASABKAlSAmlkEiYKD3N0YXJ0X3Jvd19pbmRleBgCIAEoBVINc3RhcnRSb3dJbmRleBIbCglyb3dfY291bnQYAyABKAVSCHJvd0NvdW50');
@$core.Deprecated('Use gridBlockMetaDescriptor instead')
const GridBlockMeta$json = const {
'1': 'GridBlockMeta',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'rows', '3': 2, '4': 3, '5': 11, '6': '.RowMeta', '10': 'rows'},
],
};
/// Descriptor for `BlockMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List blockMetaDescriptor = $convert.base64Decode('CglCbG9ja01ldGESGQoIYmxvY2tfaWQYASABKAlSB2Jsb2NrSWQSHAoEcm93cxgCIAMoCzIILlJvd01ldGFSBHJvd3M=');
/// Descriptor for `GridBlockMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridBlockMetaDescriptor = $convert.base64Decode('Cg1HcmlkQmxvY2tNZXRhEhkKCGJsb2NrX2lkGAEgASgJUgdibG9ja0lkEhwKBHJvd3MYAiADKAsyCC5Sb3dNZXRhUgRyb3dz');
@$core.Deprecated('Use fieldDescriptor instead')
const Field$json = const {
'1': 'Field',
@ -85,6 +85,32 @@ const RepeatedField$json = const {
/// Descriptor for `RepeatedField`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List repeatedFieldDescriptor = $convert.base64Decode('Cg1SZXBlYXRlZEZpZWxkEhwKBWl0ZW1zGAEgAygLMgYuRmllbGRSBWl0ZW1z');
@$core.Deprecated('Use fieldChangesetDescriptor instead')
const FieldChangeset$json = const {
'1': 'FieldChangeset',
'2': const [
const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'},
const {'1': 'name', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'name'},
const {'1': 'desc', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'desc'},
const {'1': 'field_type', '3': 4, '4': 1, '5': 14, '6': '.FieldType', '9': 2, '10': 'fieldType'},
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'},
],
'8': const [
const {'1': 'one_of_name'},
const {'1': 'one_of_desc'},
const {'1': 'one_of_field_type'},
const {'1': 'one_of_frozen'},
const {'1': 'one_of_visibility'},
const {'1': 'one_of_width'},
const {'1': 'one_of_type_options'},
],
};
/// Descriptor for `FieldChangeset`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List fieldChangesetDescriptor = $convert.base64Decode('Cg5GaWVsZENoYW5nZXNldBIZCghmaWVsZF9pZBgBIAEoCVIHZmllbGRJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEisKCmZpZWxkX3R5cGUYBCABKA4yCi5GaWVsZFR5cGVIAlIJZmllbGRUeXBlEhgKBmZyb3plbhgFIAEoCEgDUgZmcm96ZW4SIAoKdmlzaWJpbGl0eRgGIAEoCEgEUgp2aXNpYmlsaXR5EhYKBXdpZHRoGAcgASgFSAVSBXdpZHRoEi0KDHR5cGVfb3B0aW9ucxgIIAEoCzIILkFueURhdGFIBlILdHlwZU9wdGlvbnNCDQoLb25lX29mX25hbWVCDQoLb25lX29mX2Rlc2NCEwoRb25lX29mX2ZpZWxkX3R5cGVCDwoNb25lX29mX2Zyb3plbkITChFvbmVfb2ZfdmlzaWJpbGl0eUIOCgxvbmVfb2Zfd2lkdGhCFQoTb25lX29mX3R5cGVfb3B0aW9ucw==');
@$core.Deprecated('Use anyDataDescriptor instead')
const AnyData$json = const {
'1': 'AnyData',

View File

@ -7,8 +7,8 @@ edition = "2018"
[lib]
name = "dart_ffi"
# this value will change depending on the target os
# default staticlib
crate-type = ["staticlib"]
# default cdylib
crate-type = ["cdylib"]
[dependencies]

View File

@ -1,4 +1,4 @@
use crate::queue::BlockRevisionCompact;
use crate::queue::TextBlockRevisionCompactor;
use crate::web_socket::{make_block_ws_manager, EditorCommandSender};
use crate::{
errors::FlowyError,
@ -40,9 +40,7 @@ impl ClientTextBlockEditor {
rev_web_socket: Arc<dyn RevisionWebSocket>,
cloud_service: Arc<dyn RevisionCloudService>,
) -> FlowyResult<Arc<Self>> {
let document_info = rev_manager
.load::<BlockInfoBuilder, BlockRevisionCompact>(cloud_service)
.await?;
let document_info = rev_manager.load::<BlockInfoBuilder>(cloud_service).await?;
let delta = document_info.delta()?;
let rev_manager = Arc::new(rev_manager);
let doc_id = doc_id.to_string();

View File

@ -8,6 +8,7 @@ use flowy_collaboration::entities::{
};
use flowy_database::ConnectionPool;
use flowy_error::FlowyResult;
use flowy_sync::disk::SQLiteTextBlockRevisionPersistence;
use flowy_sync::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket};
use lib_infra::future::FutureResult;
use std::{convert::TryInto, sync::Arc};
@ -84,7 +85,7 @@ impl TextBlockManager {
let doc_id = doc_id.as_ref().to_owned();
let db_pool = self.user.db_pool()?;
// Maybe we could save the block to disk without creating the RevisionManager
let rev_manager = self.make_block_rev_manager(&doc_id, db_pool)?;
let rev_manager = self.make_rev_manager(&doc_id, db_pool)?;
let _ = rev_manager.reset_object(revisions).await?;
Ok(())
}
@ -111,20 +112,20 @@ impl TextBlockManager {
match self.editor_map.get(block_id) {
None => {
let db_pool = self.user.db_pool()?;
self.make_block_editor(block_id, db_pool).await
self.make_text_block_editor(block_id, db_pool).await
}
Some(editor) => Ok(editor),
}
}
async fn make_block_editor(
async fn make_text_block_editor(
&self,
block_id: &str,
pool: Arc<ConnectionPool>,
) -> Result<Arc<ClientTextBlockEditor>, FlowyError> {
let user = self.user.clone();
let token = self.user.token()?;
let rev_manager = self.make_block_rev_manager(block_id, pool.clone())?;
let rev_manager = self.make_rev_manager(block_id, pool.clone())?;
let cloud_service = Arc::new(TextBlockRevisionCloudService {
token,
server: self.cloud_service.clone(),
@ -135,9 +136,10 @@ impl TextBlockManager {
Ok(doc_editor)
}
fn make_block_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<RevisionManager, FlowyError> {
fn make_rev_manager(&self, doc_id: &str, pool: Arc<ConnectionPool>) -> Result<RevisionManager, FlowyError> {
let user_id = self.user.user_id()?;
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, pool));
let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool));
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, disk_cache));
Ok(RevisionManager::new(&user_id, doc_id, rev_persistence))
}
}

View File

@ -1,6 +1,7 @@
use crate::web_socket::EditorCommandReceiver;
use crate::TextBlockUser;
use async_stream::stream;
use bytes::Bytes;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_collaboration::{
client_document::{history::UndoResult, ClientDocument},
@ -8,8 +9,9 @@ use flowy_collaboration::{
errors::CollaborateError,
};
use flowy_error::{FlowyError, FlowyResult};
use flowy_sync::{DeltaMD5, RevisionCompact, RevisionManager, RichTextTransformDeltas, TransformDeltas};
use flowy_sync::{DeltaMD5, RevisionCompactor, RevisionManager, RichTextTransformDeltas, TransformDeltas};
use futures::stream::StreamExt;
use lib_ot::core::{Attributes, Delta};
use lib_ot::{
core::{Interval, OperationTransformable},
rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta},
@ -187,31 +189,17 @@ impl EditBlockQueue {
);
let _ = self
.rev_manager
.add_local_revision::<BlockRevisionCompact>(&revision)
.add_local_revision(&revision, Box::new(TextBlockRevisionCompactor()))
.await?;
Ok(rev_id.into())
}
}
pub(crate) struct BlockRevisionCompact();
impl RevisionCompact for BlockRevisionCompact {
fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> {
if revisions.is_empty() {
return Err(FlowyError::internal().context("Can't compact the empty block's revisions"));
}
if revisions.len() == 1 {
return Ok(revisions.pop().unwrap());
}
let first_revision = revisions.first().unwrap();
let last_revision = revisions.last().unwrap();
let (base_rev_id, rev_id) = first_revision.pair_rev_id();
let md5 = last_revision.md5.clone();
pub(crate) struct TextBlockRevisionCompactor();
impl RevisionCompactor for TextBlockRevisionCompactor {
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
let delta = make_delta_from_revisions::<RichTextAttributes>(revisions)?;
let delta_data = delta.to_bytes();
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5))
Ok(delta.to_bytes())
}
}

View File

@ -1,3 +1,2 @@
-- This file should undo anything in `up.sql`
DROP TABLE kv_table;
DROP TABLE grid_rev_table;
DROP TABLE kv_table;

View File

@ -2,13 +2,4 @@
CREATE TABLE kv_table (
key TEXT NOT NULL PRIMARY KEY,
value BLOB NOT NULL DEFAULT (x'')
);
CREATE TABLE grid_rev_table (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
object_id TEXT NOT NULL DEFAULT '',
base_rev_id BIGINT NOT NULL DEFAULT 0,
rev_id BIGINT NOT NULL DEFAULT 0,
data BLOB NOT NULL DEFAULT (x''),
state INTEGER NOT NULL DEFAULT 0
);

View File

@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
DROP TABLE grid_rev_table;
DROP TABLE grid_meta_rev_table;

View File

@ -0,0 +1,18 @@
-- Your SQL goes here
CREATE TABLE grid_rev_table (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
object_id TEXT NOT NULL DEFAULT '',
base_rev_id BIGINT NOT NULL DEFAULT 0,
rev_id BIGINT NOT NULL DEFAULT 0,
data BLOB NOT NULL DEFAULT (x''),
state INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE grid_meta_rev_table (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
object_id TEXT NOT NULL DEFAULT '',
base_rev_id BIGINT NOT NULL DEFAULT 0,
rev_id BIGINT NOT NULL DEFAULT 0,
data BLOB NOT NULL DEFAULT (x''),
state INTEGER NOT NULL DEFAULT 0
);

View File

@ -160,3 +160,39 @@ macro_rules! impl_sql_integer_expression {
}
};
}
#[macro_export]
macro_rules! impl_rev_state_map {
($target:ident) => {
impl std::convert::From<i32> for $target {
fn from(value: i32) -> Self {
match value {
0 => $target::Sync,
1 => $target::Ack,
o => {
tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o);
$target::Sync
}
}
}
}
impl std::convert::From<$target> for RevisionState {
fn from(s: $target) -> Self {
match s {
$target::Sync => RevisionState::Sync,
$target::Ack => RevisionState::Ack,
}
}
}
impl std::convert::From<RevisionState> for $target {
fn from(s: RevisionState) -> Self {
match s {
RevisionState::Sync => $target::Sync,
RevisionState::Ack => $target::Ack,
}
}
}
};
}

View File

@ -21,6 +21,17 @@ table! {
}
}
table! {
grid_meta_rev_table (id) {
id -> Integer,
object_id -> Text,
base_rev_id -> BigInt,
rev_id -> BigInt,
data -> Binary,
state -> Integer,
}
}
table! {
grid_rev_table (id) {
id -> Integer,
@ -102,6 +113,7 @@ table! {
allow_tables_to_appear_in_same_query!(
app_table,
doc_table,
grid_meta_rev_table,
grid_rev_table,
kv_table,
rev_table,

View File

@ -17,7 +17,8 @@ use flowy_collaboration::{client_folder::FolderPad, entities::ws_data::ServerRev
use flowy_error::FlowyError;
use flowy_folder_data_model::entities::view::ViewDataType;
use flowy_folder_data_model::user_default;
use flowy_sync::RevisionWebSocket;
use flowy_sync::disk::SQLiteTextBlockRevisionPersistence;
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
use lazy_static::lazy_static;
use lib_infra::future::FutureResult;
use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc};
@ -163,7 +164,12 @@ impl FolderManager {
let _ = self.persistence.initialize(user_id, &folder_id).await?;
let pool = self.persistence.db_pool()?;
let folder_editor = ClientFolderEditor::new(user_id, &folder_id, token, pool, self.web_socket.clone()).await?;
let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool));
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
let rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence);
let folder_editor =
ClientFolderEditor::new(user_id, &folder_id, token, rev_manager, self.web_socket.clone()).await?;
*self.folder_editor.write().await = Some(Arc::new(folder_editor));
let _ = self.app_controller.initialize()?;

View File

@ -5,14 +5,16 @@ use flowy_collaboration::{
};
use crate::manager::FolderId;
use bytes::Bytes;
use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult};
use flowy_sync::disk::RevisionDiskCache;
use flowy_sync::{
RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
RevisionWebSocket, RevisionWebSocketManager,
};
use lib_infra::future::FutureResult;
use lib_ot::core::PlainTextAttributes;
use lib_ot::core::{Delta, PlainTextAttributes};
use lib_sqlite::ConnectionPool;
use parking_lot::RwLock;
use std::sync::Arc;
@ -30,19 +32,13 @@ impl ClientFolderEditor {
user_id: &str,
folder_id: &FolderId,
token: &str,
pool: Arc<ConnectionPool>,
mut rev_manager: RevisionManager,
web_socket: Arc<dyn RevisionWebSocket>,
) -> FlowyResult<Self> {
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), pool));
let mut rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence);
let cloud = Arc::new(FolderRevisionCloudService {
token: token.to_string(),
});
let folder = Arc::new(RwLock::new(
rev_manager
.load::<FolderPadBuilder, FolderRevisionCompact>(cloud)
.await?,
));
let folder = Arc::new(RwLock::new(rev_manager.load::<FolderPadBuilder>(cloud).await?));
let rev_manager = Arc::new(rev_manager);
let ws_manager = make_folder_ws_manager(
user_id,
@ -86,7 +82,7 @@ impl ClientFolderEditor {
);
let _ = futures::executor::block_on(async {
self.rev_manager
.add_local_revision::<FolderRevisionCompact>(&revision)
.add_local_revision(&revision, Box::new(FolderRevisionCompactor()))
.await
})?;
Ok(())
@ -128,24 +124,10 @@ impl ClientFolderEditor {
}
}
struct FolderRevisionCompact();
impl RevisionCompact for FolderRevisionCompact {
fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> {
if revisions.is_empty() {
return Err(FlowyError::internal().context("Can't compact the empty folder's revisions"));
}
if revisions.len() == 1 {
return Ok(revisions.pop().unwrap());
}
let first_revision = revisions.first().unwrap();
let last_revision = revisions.last().unwrap();
let (base_rev_id, rev_id) = first_revision.pair_rev_id();
let md5 = last_revision.md5.clone();
struct FolderRevisionCompactor();
impl RevisionCompactor for FolderRevisionCompactor {
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
let delta_data = delta.to_bytes();
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5))
Ok(delta.to_bytes())
}
}

View File

@ -11,6 +11,7 @@ use flowy_folder_data_model::entities::{
view::{RepeatedView, View},
workspace::Workspace,
};
use flowy_sync::disk::SQLiteTextBlockRevisionPersistence;
use flowy_sync::{RevisionLoader, RevisionPersistence};
use std::sync::Arc;
@ -87,7 +88,8 @@ impl FolderMigration {
return Ok(None);
}
let pool = self.database.db_pool()?;
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), pool.clone()));
let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool));
let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache));
let (revisions, _) = RevisionLoader {
object_id: folder_id.as_ref().to_owned(),
user_id: self.user_id.clone(),

View File

@ -7,6 +7,7 @@ use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{Field, RowMeta};
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
use flowy_sync::disk::SQLiteGridRevisionPersistence;
use lib_sqlite::ConnectionPool;
use parking_lot::RwLock;
use std::sync::Arc;
@ -104,7 +105,9 @@ impl GridManager {
fn make_grid_rev_manager(&self, grid_id: &str, pool: Arc<ConnectionPool>) -> FlowyResult<RevisionManager> {
let user_id = self.grid_user.user_id()?;
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, pool));
let disk_cache = Arc::new(SQLiteGridRevisionPersistence::new(&user_id, pool));
let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, disk_cache));
let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence);
Ok(rev_manager)
}

View File

@ -2,6 +2,8 @@ use crate::manager::GridUser;
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
use crate::services::stringify::stringify_deserialize;
use crate::services::grid_meta_editor::ClientGridBlockMetaEditor;
use bytes::Bytes;
use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridChange, GridMetaPad};
use flowy_collaboration::entities::revision::Revision;
@ -10,10 +12,10 @@ use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{
Cell, CellMeta, Field, Grid, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row, RowMeta,
};
use flowy_sync::{RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder};
use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
use lib_infra::future::FutureResult;
use lib_infra::uuid;
use lib_ot::core::PlainTextAttributes;
use lib_ot::core::{Delta, PlainTextAttributes};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::collections::HashMap;
use std::sync::Arc;
@ -24,10 +26,8 @@ pub struct ClientGridEditor {
user: Arc<dyn GridUser>,
grid_meta_pad: Arc<RwLock<GridMetaPad>>,
rev_manager: Arc<RevisionManager>,
block_meta_manager: Arc<GridBlockMetaEditorManager>,
kv_persistence: Arc<GridKVPersistence>,
field_map: DashMap<String, Field>,
cell_map: DashMap<String, CellMeta>,
}
impl ClientGridEditor {
@ -39,50 +39,22 @@ impl ClientGridEditor {
) -> FlowyResult<Arc<Self>> {
let token = user.token()?;
let cloud = Arc::new(GridRevisionCloudService { token });
let grid_pad = rev_manager.load::<GridPadBuilder, GridRevisionCompact>(cloud).await?;
let grid_pad = rev_manager.load::<GridPadBuilder>(cloud).await?;
let rev_manager = Arc::new(rev_manager);
let field_map = load_all_fields(&grid_pad, &kv_persistence).await?;
let grid_meta_pad = Arc::new(RwLock::new(grid_pad));
let cell_map = DashMap::new();
let block_meta_manager = Arc::new(GridBlockMetaEditorManager::new());
Ok(Arc::new(Self {
grid_id: grid_id.to_owned(),
user,
grid_meta_pad,
rev_manager,
block_meta_manager,
kv_persistence,
field_map,
cell_map,
}))
}
pub async fn create_empty_row(&self) -> FlowyResult<()> {
let row = RowMeta::new(&uuid(), &self.grid_id, vec![]);
self.create_row(row).await?;
Ok(())
}
async fn create_row(&self, row: RowMeta) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.create_row(row)?)).await?;
// self.cell_map.insert(row.id.clone(), row.clone());
// let _ = self.kv_persistence.set(row)?;
Ok(())
}
pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.delete_rows(&ids)?)).await?;
// let _ = self.kv.batch_delete(ids)?;
Ok(())
}
// pub async fn update_row(&self, cell: Cell) -> FlowyResult<()> {
// match self.cell_map.get(&cell.id) {
// None => Err(FlowyError::internal().context(format!("Can't find cell with id: {}", cell.id))),
// Some(raw_cell) => {}
// }
// }
pub async fn create_field(&mut self, field: Field) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.create_field(field)?)).await?;
Ok(())
@ -90,76 +62,38 @@ impl ClientGridEditor {
pub async fn delete_field(&mut self, field_id: &str) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.delete_field(field_id)?)).await?;
// let _ = self.kv.remove(field_id)?;
Ok(())
}
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())
pub async fn create_empty_row(&self) -> FlowyResult<()> {
// let _ = self.modify(|grid| {
//
//
// grid.blocks
//
// }).await?;
todo!()
}
pub async fn get_fields(&self, field_orders: RepeatedFieldOrder) -> FlowyResult<RepeatedField> {
let fields = field_orders
.iter()
.flat_map(|field_order| match self.field_map.get(&field_order.field_id) {
None => {
tracing::error!("Can't find the field with {}", field_order.field_id);
None
}
Some(field) => Some(field.value().clone()),
})
.collect::<Vec<Field>>();
Ok(fields.into())
async fn create_row(&self, row: RowMeta) -> FlowyResult<()> {
todo!()
}
pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
todo!()
}
pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
todo!()
}
pub async fn grid_data(&self) -> Grid {
self.grid_meta_pad.read().await.grid_data()
todo!()
}
pub async fn get_fields(&self, field_orders: RepeatedFieldOrder) -> FlowyResult<RepeatedField> {
let fields = self.grid_meta_pad.read().await.get_fields(field_orders)?;
Ok(fields)
}
pub async fn delta_str(&self) -> String {
@ -195,7 +129,7 @@ impl ClientGridEditor {
);
let _ = self
.rev_manager
.add_local_revision::<GridRevisionCompact>(&revision)
.add_local_revision(&revision, Box::new(GridRevisionCompactor()))
.await?;
Ok(())
}
@ -241,24 +175,73 @@ impl RevisionCloudService for GridRevisionCloudService {
}
}
struct GridRevisionCompact();
impl RevisionCompact for GridRevisionCompact {
fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> {
if revisions.is_empty() {
return Err(FlowyError::internal().context("Can't compact the empty folder's revisions"));
}
if revisions.len() == 1 {
return Ok(revisions.pop().unwrap());
}
let first_revision = revisions.first().unwrap();
let last_revision = revisions.last().unwrap();
let (base_rev_id, rev_id) = first_revision.pair_rev_id();
let md5 = last_revision.md5.clone();
struct GridRevisionCompactor();
impl RevisionCompactor for GridRevisionCompactor {
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
let delta_data = delta.to_bytes();
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5))
Ok(delta.to_bytes())
}
}
struct GridBlockMetaEditorManager {
editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
}
impl GridBlockMetaEditorManager {
fn new() -> Self {
Self {
editor_map: DashMap::new(),
}
}
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!()
}
}

View File

@ -0,0 +1,125 @@
use bytes::Bytes;
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;
use flowy_sync::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder};
use lib_infra::future::FutureResult;
use lib_infra::uuid;
use lib_ot::core::PlainTextAttributes;
use std::sync::Arc;
use tokio::sync::RwLock;
pub struct ClientGridBlockMetaEditor {
user_id: String,
block_id: String,
meta_pad: Arc<RwLock<GridBlockMetaPad>>,
rev_manager: Arc<RevisionManager>,
}
impl ClientGridBlockMetaEditor {
pub async fn new(
user_id: &str,
token: &str,
block_id: String,
mut rev_manager: RevisionManager,
) -> FlowyResult<Self> {
let cloud = Arc::new(GridBlockMetaRevisionCloudService {
token: token.to_owned(),
});
let block_meta_pad = rev_manager.load::<GridBlockMetaPadBuilder>(cloud).await?;
let meta_pad = Arc::new(RwLock::new(block_meta_pad));
let rev_manager = Arc::new(rev_manager);
let user_id = user_id.to_owned();
Ok(Self {
user_id,
block_id,
meta_pad,
rev_manager,
})
}
pub async fn create_empty_row(&self) -> FlowyResult<()> {
let row = RowMeta::new(&uuid(), &self.block_id, vec![]);
self.create_row(row).await?;
Ok(())
}
async fn create_row(&self, row: RowMeta) -> FlowyResult<()> {
// let _ = self.modify(|grid| Ok(grid.create_row(row)?)).await?;
// self.cell_map.insert(row.id.clone(), row.clone());
// let _ = self.kv_persistence.set(row)?;
Ok(())
}
pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
// let _ = self.modify(|grid| Ok(grid.delete_rows(&ids)?)).await?;
// let _ = self.kv.batch_delete(ids)?;
Ok(())
}
async fn modify<F>(&self, f: F) -> FlowyResult<()>
where
F: for<'a> FnOnce(&'a mut GridBlockMetaPad) -> FlowyResult<Option<GridBlockMetaChange>>,
{
let mut write_guard = self.meta_pad.write().await;
match f(&mut *write_guard)? {
None => {}
Some(change) => {
let _ = self.apply_change(change).await?;
}
}
Ok(())
}
async fn apply_change(&self, change: GridBlockMetaChange) -> FlowyResult<()> {
let GridBlockMetaChange { delta, md5 } = change;
let user_id = self.user_id.clone();
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
let delta_data = delta.to_bytes();
let revision = Revision::new(
&self.rev_manager.object_id,
base_rev_id,
rev_id,
delta_data,
&user_id,
md5,
);
let _ = self
.rev_manager
.add_local_revision(&revision, Box::new(GridBlockMetaRevisionCompactor()))
.await?;
Ok(())
}
}
struct GridBlockMetaRevisionCloudService {
#[allow(dead_code)]
token: String,
}
impl RevisionCloudService for GridBlockMetaRevisionCloudService {
#[tracing::instrument(level = "trace", skip(self))]
fn fetch_object(&self, _user_id: &str, _object_id: &str) -> FutureResult<Vec<Revision>, FlowyError> {
FutureResult::new(async move { Ok(vec![]) })
}
}
struct GridBlockMetaPadBuilder();
impl RevisionObjectBuilder for GridBlockMetaPadBuilder {
type Output = GridBlockMetaPad;
fn build_object(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output> {
let pad = GridBlockMetaPad::from_revisions(object_id, revisions)?;
Ok(pad)
}
}
struct GridBlockMetaRevisionCompactor();
impl RevisionCompactor for GridBlockMetaRevisionCompactor {
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
Ok(delta.to_bytes())
}
}

View File

@ -3,5 +3,6 @@ mod util;
pub mod cell_data;
pub mod grid_builder;
pub mod grid_editor;
pub mod grid_meta_editor;
pub mod kv_persistence;
pub mod stringify;

View File

@ -66,10 +66,10 @@ fn make_view_data_processor(
) -> ViewDataProcessorMap {
let mut map: HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new();
let block_data_impl = BlockManagerViewDataImpl(text_block_manager);
let block_data_impl = TextBlockViewDataProcessor(text_block_manager);
map.insert(block_data_impl.data_type(), Arc::new(block_data_impl));
let grid_data_impl = GridManagerViewDataImpl(grid_manager);
let grid_data_impl = GridViewDataProcessor(grid_manager);
map.insert(grid_data_impl.data_type(), Arc::new(grid_data_impl));
Arc::new(map)
@ -133,8 +133,8 @@ impl WSMessageReceiver for FolderWSMessageReceiverImpl {
}
}
struct BlockManagerViewDataImpl(Arc<TextBlockManager>);
impl ViewDataProcessor for BlockManagerViewDataImpl {
struct TextBlockViewDataProcessor(Arc<TextBlockManager>);
impl ViewDataProcessor for TextBlockViewDataProcessor {
fn initialize(&self) -> FutureResult<(), FlowyError> {
let manager = self.0.clone();
FutureResult::new(async move { manager.init() })
@ -186,8 +186,8 @@ impl ViewDataProcessor for BlockManagerViewDataImpl {
}
}
struct GridManagerViewDataImpl(Arc<GridManager>);
impl ViewDataProcessor for GridManagerViewDataImpl {
struct GridViewDataProcessor(Arc<GridManager>);
impl ViewDataProcessor for GridViewDataProcessor {
fn initialize(&self) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) })
}

View File

@ -0,0 +1,235 @@
use crate::cache::disk::RevisionDiskCache;
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
use crate::memory::RevisionMemoryCacheDelegate;
use bytes::Bytes;
use diesel::{sql_types::Integer, update, SqliteConnection};
use flowy_collaboration::{
entities::revision::{RevId, RevType, Revision, RevisionRange},
util::md5,
};
use flowy_database::{
impl_sql_integer_expression, insert_or_ignore_into,
prelude::*,
schema::{grid_meta_rev_table, grid_meta_rev_table::dsl},
ConnectionPool,
};
use flowy_error::{internal_error, FlowyError, FlowyResult};
use std::sync::Arc;
pub struct SQLiteGridBlockMetaRevisionPersistence {
user_id: String,
pub(crate) pool: Arc<ConnectionPool>,
}
impl RevisionDiskCache for SQLiteGridBlockMetaRevisionPersistence {
type Error = FlowyError;
fn create_revision_records(&self, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
let _ = GridMetaRevisionSql::create(revision_records, &*conn)?;
Ok(())
}
fn read_revision_records(
&self,
object_id: &str,
rev_ids: Option<Vec<i64>>,
) -> Result<Vec<RevisionRecord>, Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
let records = GridMetaRevisionSql::read(&self.user_id, object_id, rev_ids, &*conn)?;
Ok(records)
}
fn read_revision_records_with_range(
&self,
object_id: &str,
range: &RevisionRange,
) -> Result<Vec<RevisionRecord>, Self::Error> {
let conn = &*self.pool.get().map_err(internal_error)?;
let revisions = GridMetaRevisionSql::read_with_range(&self.user_id, object_id, range.clone(), conn)?;
Ok(revisions)
}
fn update_revision_record(&self, changesets: Vec<RevisionChangeset>) -> FlowyResult<()> {
let conn = &*self.pool.get().map_err(internal_error)?;
let _ = conn.immediate_transaction::<_, FlowyError, _>(|| {
for changeset in changesets {
let _ = GridMetaRevisionSql::update(changeset, conn)?;
}
Ok(())
})?;
Ok(())
}
fn delete_revision_records(&self, object_id: &str, rev_ids: Option<Vec<i64>>) -> Result<(), Self::Error> {
let conn = &*self.pool.get().map_err(internal_error)?;
let _ = GridMetaRevisionSql::delete(object_id, rev_ids, conn)?;
Ok(())
}
fn delete_and_insert_records(
&self,
object_id: &str,
deleted_rev_ids: Option<Vec<i64>>,
inserted_records: Vec<RevisionRecord>,
) -> Result<(), Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
conn.immediate_transaction::<_, FlowyError, _>(|| {
let _ = GridMetaRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?;
let _ = GridMetaRevisionSql::create(inserted_records, &*conn)?;
Ok(())
})
}
}
impl SQLiteGridBlockMetaRevisionPersistence {
pub fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
Self {
user_id: user_id.to_owned(),
pool,
}
}
}
struct GridMetaRevisionSql();
impl GridMetaRevisionSql {
fn create(revision_records: Vec<RevisionRecord>, conn: &SqliteConnection) -> Result<(), FlowyError> {
// Batch insert: https://diesel.rs/guides/all-about-inserts.html
let records = revision_records
.into_iter()
.map(|record| {
tracing::trace!(
"[GridMetaRevisionSql] create revision: {}:{:?}",
record.revision.object_id,
record.revision.rev_id
);
let rev_state: GridMetaRevisionState = record.state.into();
(
dsl::object_id.eq(record.revision.object_id),
dsl::base_rev_id.eq(record.revision.base_rev_id),
dsl::rev_id.eq(record.revision.rev_id),
dsl::data.eq(record.revision.delta_data),
dsl::state.eq(rev_state),
)
})
.collect::<Vec<_>>();
let _ = insert_or_ignore_into(dsl::grid_meta_rev_table)
.values(&records)
.execute(conn)?;
Ok(())
}
fn update(changeset: RevisionChangeset, conn: &SqliteConnection) -> Result<(), FlowyError> {
let state: GridMetaRevisionState = changeset.state.clone().into();
let filter = dsl::grid_meta_rev_table
.filter(dsl::rev_id.eq(changeset.rev_id.as_ref()))
.filter(dsl::object_id.eq(changeset.object_id));
let _ = update(filter).set(dsl::state.eq(state)).execute(conn)?;
tracing::debug!(
"[GridMetaRevisionSql] update revision:{} state:to {:?}",
changeset.rev_id,
changeset.state
);
Ok(())
}
fn read(
user_id: &str,
object_id: &str,
rev_ids: Option<Vec<i64>>,
conn: &SqliteConnection,
) -> Result<Vec<RevisionRecord>, FlowyError> {
let mut sql = dsl::grid_meta_rev_table
.filter(dsl::object_id.eq(object_id))
.into_boxed();
if let Some(rev_ids) = rev_ids {
sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
}
let rows = sql.order(dsl::rev_id.asc()).load::<GridMetaRevisionTable>(conn)?;
let records = rows
.into_iter()
.map(|row| mk_revision_record_from_table(user_id, row))
.collect::<Vec<_>>();
Ok(records)
}
fn read_with_range(
user_id: &str,
object_id: &str,
range: RevisionRange,
conn: &SqliteConnection,
) -> Result<Vec<RevisionRecord>, FlowyError> {
let rev_tables = dsl::grid_meta_rev_table
.filter(dsl::rev_id.ge(range.start))
.filter(dsl::rev_id.le(range.end))
.filter(dsl::object_id.eq(object_id))
.order(dsl::rev_id.asc())
.load::<GridMetaRevisionTable>(conn)?;
let revisions = rev_tables
.into_iter()
.map(|table| mk_revision_record_from_table(user_id, table))
.collect::<Vec<_>>();
Ok(revisions)
}
fn delete(object_id: &str, rev_ids: Option<Vec<i64>>, conn: &SqliteConnection) -> Result<(), FlowyError> {
let mut sql = diesel::delete(dsl::grid_meta_rev_table).into_boxed();
sql = sql.filter(dsl::object_id.eq(object_id));
if let Some(rev_ids) = rev_ids {
tracing::trace!("[GridMetaRevisionSql] Delete revision: {}:{:?}", object_id, rev_ids);
sql = sql.filter(dsl::rev_id.eq_any(rev_ids));
}
let affected_row = sql.execute(conn)?;
tracing::trace!("[GridMetaRevisionSql] Delete {} rows", affected_row);
Ok(())
}
}
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "grid_meta_rev_table"]
struct GridMetaRevisionTable {
id: i32,
object_id: String,
base_rev_id: i64,
rev_id: i64,
data: Vec<u8>,
state: GridMetaRevisionState,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
#[repr(i32)]
#[sql_type = "Integer"]
pub enum GridMetaRevisionState {
Sync = 0,
Ack = 1,
}
impl_sql_integer_expression!(GridMetaRevisionState);
impl_rev_state_map!(GridMetaRevisionState);
impl std::default::Default for GridMetaRevisionState {
fn default() -> Self {
GridMetaRevisionState::Sync
}
}
fn mk_revision_record_from_table(user_id: &str, table: GridMetaRevisionTable) -> RevisionRecord {
let md5 = md5(&table.data);
let revision = Revision::new(
&table.object_id,
table.base_rev_id,
table.rev_id,
Bytes::from(table.data),
user_id,
md5,
);
RevisionRecord {
revision,
state: table.state.into(),
write_to_disk: false,
}
}

View File

@ -1,5 +1,6 @@
use crate::cache::disk::RevisionDiskCache;
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
use crate::memory::RevisionMemoryCacheDelegate;
use bytes::Bytes;
use diesel::{sql_types::Integer, update, SqliteConnection};
use flowy_collaboration::{
@ -23,12 +24,9 @@ pub struct SQLiteGridRevisionPersistence {
impl RevisionDiskCache for SQLiteGridRevisionPersistence {
type Error = FlowyError;
fn create_revision_records(
&self,
revision_records: Vec<RevisionRecord>,
conn: &SqliteConnection,
) -> Result<(), Self::Error> {
let _ = GridRevisionSql::create(revision_records, conn)?;
fn create_revision_records(&self, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
let _ = GridRevisionSql::create(revision_records, &*conn)?;
Ok(())
}
@ -78,14 +76,14 @@ impl RevisionDiskCache for SQLiteGridRevisionPersistence {
let conn = self.pool.get().map_err(internal_error)?;
conn.immediate_transaction::<_, FlowyError, _>(|| {
let _ = GridRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?;
let _ = self.create_revision_records(inserted_records, &*conn)?;
let _ = GridRevisionSql::create(inserted_records, &*conn)?;
Ok(())
})
}
}
impl SQLiteGridRevisionPersistence {
pub(crate) fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
pub fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
Self {
user_id: user_id.to_owned(),
pool,
@ -193,13 +191,13 @@ impl GridRevisionSql {
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "grid_rev_table"]
pub(crate) struct GridRevisionTable {
struct GridRevisionTable {
id: i32,
pub(crate) object_id: String,
pub(crate) base_rev_id: i64,
pub(crate) rev_id: i64,
pub(crate) data: Vec<u8>,
pub(crate) state: GridRevisionState,
object_id: String,
base_rev_id: i64,
rev_id: i64,
data: Vec<u8>,
state: GridRevisionState,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
@ -209,6 +207,8 @@ pub enum GridRevisionState {
Sync = 0,
Ack = 1,
}
impl_sql_integer_expression!(GridRevisionState);
impl_rev_state_map!(GridRevisionState);
impl std::default::Default for GridRevisionState {
fn default() -> Self {
@ -216,44 +216,6 @@ impl std::default::Default for GridRevisionState {
}
}
impl std::convert::From<i32> for GridRevisionState {
fn from(value: i32) -> Self {
match value {
0 => GridRevisionState::Sync,
1 => GridRevisionState::Ack,
o => {
tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o);
GridRevisionState::Sync
}
}
}
}
impl GridRevisionState {
pub fn value(&self) -> i32 {
*self as i32
}
}
impl_sql_integer_expression!(GridRevisionState);
impl std::convert::From<GridRevisionState> for RevisionState {
fn from(s: GridRevisionState) -> Self {
match s {
GridRevisionState::Sync => RevisionState::Sync,
GridRevisionState::Ack => RevisionState::Ack,
}
}
}
impl std::convert::From<RevisionState> for GridRevisionState {
fn from(s: RevisionState) -> Self {
match s {
RevisionState::Sync => GridRevisionState::Sync,
RevisionState::Ack => GridRevisionState::Ack,
}
}
}
fn mk_revision_record_from_table(user_id: &str, table: GridRevisionTable) -> RevisionRecord {
let md5 = md5(&table.data);
let revision = Revision::new(

View File

@ -1,11 +1,14 @@
mod folder_rev_impl;
mod grid_meta_rev_impl;
mod grid_rev_impl;
mod text_rev_impl;
pub use folder_rev_impl::*;
pub use grid_meta_rev_impl::*;
pub use grid_rev_impl::*;
pub use text_rev_impl::*;
use crate::memory::RevisionMemoryCacheDelegate;
use diesel::SqliteConnection;
use flowy_collaboration::entities::revision::{RevId, Revision, RevisionRange};
use flowy_error::FlowyResult;
@ -13,11 +16,7 @@ use std::fmt::Debug;
pub trait RevisionDiskCache: Sync + Send {
type Error: Debug;
fn create_revision_records(
&self,
revision_records: Vec<RevisionRecord>,
conn: &SqliteConnection,
) -> Result<(), Self::Error>;
fn create_revision_records(&self, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error>;
// Read all the records if the rev_ids is None
fn read_revision_records(

View File

@ -1,5 +1,6 @@
use crate::cache::disk::RevisionDiskCache;
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
use crate::memory::RevisionMemoryCacheDelegate;
use bytes::Bytes;
use diesel::{sql_types::Integer, update, SqliteConnection};
use flowy_collaboration::{
@ -23,12 +24,9 @@ pub struct SQLiteTextBlockRevisionPersistence {
impl RevisionDiskCache for SQLiteTextBlockRevisionPersistence {
type Error = FlowyError;
fn create_revision_records(
&self,
revision_records: Vec<RevisionRecord>,
conn: &SqliteConnection,
) -> Result<(), Self::Error> {
let _ = TextRevisionSql::create(revision_records, conn)?;
fn create_revision_records(&self, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
let conn = self.pool.get().map_err(internal_error)?;
let _ = TextRevisionSql::create(revision_records, &*conn)?;
Ok(())
}
@ -78,14 +76,14 @@ impl RevisionDiskCache for SQLiteTextBlockRevisionPersistence {
let conn = self.pool.get().map_err(internal_error)?;
conn.immediate_transaction::<_, FlowyError, _>(|| {
let _ = TextRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?;
let _ = self.create_revision_records(inserted_records, &*conn)?;
let _ = TextRevisionSql::create(inserted_records, &*conn)?;
Ok(())
})
}
}
impl SQLiteTextBlockRevisionPersistence {
pub(crate) fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
pub fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
Self {
user_id: user_id.to_owned(),
pool,
@ -210,6 +208,8 @@ enum TextRevisionState {
Sync = 0,
Ack = 1,
}
impl_sql_integer_expression!(TextRevisionState);
impl_rev_state_map!(TextRevisionState);
impl std::default::Default for TextRevisionState {
fn default() -> Self {
@ -217,44 +217,6 @@ impl std::default::Default for TextRevisionState {
}
}
impl std::convert::From<i32> for TextRevisionState {
fn from(value: i32) -> Self {
match value {
0 => TextRevisionState::Sync,
1 => TextRevisionState::Ack,
o => {
tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o);
TextRevisionState::Sync
}
}
}
}
impl TextRevisionState {
pub fn value(&self) -> i32 {
*self as i32
}
}
impl_sql_integer_expression!(TextRevisionState);
impl std::convert::From<TextRevisionState> for RevisionState {
fn from(s: TextRevisionState) -> Self {
match s {
TextRevisionState::Sync => RevisionState::Sync,
TextRevisionState::Ack => RevisionState::Ack,
}
}
}
impl std::convert::From<RevisionState> for TextRevisionState {
fn from(s: RevisionState) -> Self {
match s {
RevisionState::Sync => TextRevisionState::Sync,
RevisionState::Ack => TextRevisionState::Ack,
}
}
}
fn mk_revision_record_from_table(user_id: &str, table: RevisionTable) -> RevisionRecord {
let md5 = md5(&table.data);
let revision = Revision::new(
@ -279,6 +241,7 @@ pub enum RevTableType {
Local = 0,
Remote = 1,
}
impl_sql_integer_expression!(RevTableType);
impl std::default::Default for RevTableType {
fn default() -> Self {
@ -298,12 +261,6 @@ impl std::convert::From<i32> for RevTableType {
}
}
}
impl RevTableType {
pub fn value(&self) -> i32 {
*self as i32
}
}
impl_sql_integer_expression!(RevTableType);
impl std::convert::From<RevType> for RevTableType {
fn from(ty: RevType) -> Self {

View File

@ -1,11 +1,13 @@
use crate::disk::RevisionState;
use crate::{RevisionPersistence, WSDataProviderDataSource};
use bytes::Bytes;
use flowy_collaboration::{
entities::revision::{RepeatedRevision, Revision, RevisionRange},
util::{pair_rev_id_from_revisions, RevIdCounter},
};
use flowy_error::{FlowyError, FlowyResult};
use lib_infra::future::FutureResult;
use lib_ot::core::{Attributes, Delta};
use std::sync::Arc;
pub trait RevisionCloudService: Send + Sync {
@ -17,8 +19,26 @@ pub trait RevisionObjectBuilder: Send + Sync {
fn build_object(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output>;
}
pub trait RevisionCompact: Send + Sync {
fn compact_revisions(user_id: &str, object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Revision>;
pub trait RevisionCompactor: Send + Sync {
fn compact(&self, user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> {
if revisions.is_empty() {
return Err(FlowyError::internal().context("Can't compact the empty folder's revisions"));
}
if revisions.len() == 1 {
return Ok(revisions.pop().unwrap());
}
let first_revision = revisions.first().unwrap();
let last_revision = revisions.last().unwrap();
let (base_rev_id, rev_id) = first_revision.pair_rev_id();
let md5 = last_revision.md5.clone();
let delta_data = self.bytes_from_revisions(revisions)?;
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5))
}
fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes>;
}
pub struct RevisionManager {
@ -48,10 +68,9 @@ impl RevisionManager {
}
}
pub async fn load<B, C>(&mut self, cloud: Arc<dyn RevisionCloudService>) -> FlowyResult<B::Output>
pub async fn load<B>(&mut self, cloud: Arc<dyn RevisionCloudService>) -> FlowyResult<B::Output>
where
B: RevisionObjectBuilder,
C: RevisionCompact,
{
let (revisions, rev_id) = RevisionLoader {
object_id: self.object_id.clone(),
@ -84,15 +103,16 @@ impl RevisionManager {
Ok(())
}
#[tracing::instrument(level = "debug", skip(self, revision))]
pub async fn add_local_revision<C>(&self, revision: &Revision) -> Result<(), FlowyError>
where
C: RevisionCompact,
{
#[tracing::instrument(level = "debug", skip_all, err)]
pub async fn add_local_revision<'a>(
&'a self,
revision: &Revision,
compactor: Box<dyn RevisionCompactor + 'a>,
) -> Result<(), FlowyError> {
if revision.delta_data.is_empty() {
return Err(FlowyError::internal().context("Delta data should be empty"));
}
let rev_id = self.rev_persistence.add_sync_revision::<C>(revision).await?;
let rev_id = self.rev_persistence.add_sync_revision(revision, compactor).await?;
self.rev_id_counter.set(rev_id);
Ok(())
}

View File

@ -1,9 +1,10 @@
use crate::cache::{
disk::{RevisionChangeset, RevisionDiskCache, SQLiteTextBlockRevisionPersistence},
memory::{RevisionMemoryCache, RevisionMemoryCacheDelegate},
memory::RevisionMemoryCacheDelegate,
};
use crate::disk::{RevisionRecord, RevisionState};
use crate::RevisionCompact;
use crate::memory::RevisionMemoryCache;
use crate::RevisionCompactor;
use flowy_collaboration::entities::revision::{Revision, RevisionRange};
use flowy_database::ConnectionPool;
use flowy_error::{internal_error, FlowyError, FlowyResult};
@ -21,13 +22,17 @@ pub struct RevisionPersistence {
memory_cache: Arc<RevisionMemoryCache>,
sync_seq: RwLock<RevisionSyncSequence>,
}
impl RevisionPersistence {
pub fn new(user_id: &str, object_id: &str, pool: Arc<ConnectionPool>) -> RevisionPersistence {
let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool));
let memory_cache = Arc::new(RevisionMemoryCache::new(object_id, Arc::new(disk_cache.clone())));
pub fn new(
user_id: &str,
object_id: &str,
disk_cache: Arc<dyn RevisionDiskCache<Error = FlowyError>>,
) -> RevisionPersistence {
let object_id = object_id.to_owned();
let user_id = user_id.to_owned();
let sync_seq = RwLock::new(RevisionSyncSequence::new());
let memory_cache = Arc::new(RevisionMemoryCache::new(&object_id, Arc::new(disk_cache.clone())));
Self {
user_id,
object_id,
@ -54,11 +59,12 @@ impl RevisionPersistence {
}
/// Save the revision to disk and append it to the end of the sync sequence.
#[tracing::instrument(level = "trace", skip(self, revision), fields(rev_id, compact_range, object_id=%self.object_id), err)]
pub(crate) async fn add_sync_revision<C>(&self, revision: &Revision) -> FlowyResult<i64>
where
C: RevisionCompact,
{
#[tracing::instrument(level = "trace", skip_all, fields(rev_id, compact_range, object_id=%self.object_id), err)]
pub(crate) async fn add_sync_revision<'a>(
&'a self,
revision: &'a Revision,
compactor: Box<dyn RevisionCompactor + 'a>,
) -> FlowyResult<i64> {
let result = self.sync_seq.read().await.compact();
match result {
None => {
@ -78,7 +84,7 @@ impl RevisionPersistence {
revisions.push(revision.clone());
// compact multiple revisions into one
let compact_revision = C::compact_revisions(&self.user_id, &self.object_id, revisions)?;
let compact_revision = compactor.compact(&self.user_id, &self.object_id, revisions)?;
let rev_id = compact_revision.rev_id;
tracing::Span::current().record("rev_id", &rev_id);
@ -215,17 +221,15 @@ pub fn mk_revision_disk_cache(
Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool))
}
impl RevisionMemoryCacheDelegate for Arc<SQLiteTextBlockRevisionPersistence> {
#[tracing::instrument(level = "trace", skip(self, records), fields(checkpoint_result), err)]
impl RevisionMemoryCacheDelegate for Arc<dyn RevisionDiskCache<Error = FlowyError>> {
fn checkpoint_tick(&self, mut records: Vec<RevisionRecord>) -> FlowyResult<()> {
let conn = &*self.pool.get().map_err(internal_error)?;
records.retain(|record| record.write_to_disk);
if !records.is_empty() {
tracing::Span::current().record(
"checkpoint_result",
&format!("{} records were saved", records.len()).as_str(),
);
let _ = self.create_revision_records(records, conn)?;
let _ = self.create_revision_records(records)?;
}
Ok(())
}

View File

@ -1,28 +1,28 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{BlockMeta, RowMeta, RowMetaChangeset, RowOrder};
use flowy_grid_data_model::entities::{GridBlockMeta, RowMeta, RowMetaChangeset, RowOrder};
use lib_infra::uuid;
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
pub type BlockMetaDelta = PlainTextDelta;
pub type BlockDeltaBuilder = PlainTextDeltaBuilder;
pub type GridBlockMetaDelta = PlainTextDelta;
pub type GridBlockMetaDeltaBuilder = PlainTextDeltaBuilder;
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct BlockMetaPad {
pub struct GridBlockMetaPad {
block_id: String,
rows: Vec<Arc<RowMeta>>,
#[serde(skip)]
pub(crate) delta: BlockMetaDelta,
pub(crate) delta: GridBlockMetaDelta,
}
impl BlockMetaPad {
pub fn from_delta(delta: BlockMetaDelta) -> CollaborateResult<Self> {
impl GridBlockMetaPad {
pub fn from_delta(delta: GridBlockMetaDelta) -> CollaborateResult<Self> {
let s = delta.to_str()?;
let block_meta: BlockMeta = serde_json::from_str(&s).map_err(|e| {
let block_meta: GridBlockMeta = serde_json::from_str(&s).map_err(|e| {
CollaborateError::internal().context(format!("Deserialize delta to block meta failed: {}", e))
})?;
let block_id = block_meta.block_id;
@ -31,25 +31,25 @@ impl BlockMetaPad {
}
pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
let block_delta: BlockMetaDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
let block_delta: GridBlockMetaDelta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
Self::from_delta(block_delta)
}
pub fn add_row(&mut self, row: RowMeta) -> CollaborateResult<Option<BlockMetaChange>> {
pub fn add_row(&mut self, row: RowMeta) -> CollaborateResult<Option<GridBlockMetaChange>> {
self.modify(|rows| {
rows.push(Arc::new(row));
Ok(Some(()))
})
}
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<BlockMetaChange>> {
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<GridBlockMetaChange>> {
self.modify(|rows| {
rows.retain(|row| !row_ids.contains(&row.id));
Ok(Some(()))
})
}
pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<BlockMetaChange>> {
pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
let row_id = changeset.row_id.clone();
self.modify_row(&row_id, |row| {
let mut is_changed = None;
@ -74,7 +74,7 @@ impl BlockMetaPad {
})
}
pub fn modify<F>(&mut self, f: F) -> CollaborateResult<Option<BlockMetaChange>>
pub fn modify<F>(&mut self, f: F) -> CollaborateResult<Option<GridBlockMetaChange>>
where
F: for<'a> FnOnce(&'a mut Vec<Arc<RowMeta>>) -> CollaborateResult<Option<()>>,
{
@ -88,14 +88,14 @@ impl BlockMetaPad {
None => Ok(None),
Some(delta) => {
self.delta = self.delta.compose(&delta)?;
Ok(Some(BlockMetaChange { delta, md5: self.md5() }))
Ok(Some(GridBlockMetaChange { delta, md5: self.md5() }))
}
}
}
}
}
fn modify_row<F>(&mut self, row_id: &str, f: F) -> CollaborateResult<Option<BlockMetaChange>>
fn modify_row<F>(&mut self, row_id: &str, f: F) -> CollaborateResult<Option<GridBlockMetaChange>>
where
F: FnOnce(&mut RowMeta) -> CollaborateResult<Option<()>>,
{
@ -123,39 +123,39 @@ impl BlockMetaPad {
}
}
fn json_from_grid(block_meta: &Arc<BlockMeta>) -> CollaborateResult<String> {
fn json_from_grid(block_meta: &Arc<GridBlockMeta>) -> CollaborateResult<String> {
let json = serde_json::to_string(block_meta)
.map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?;
Ok(json)
}
pub struct BlockMetaChange {
pub delta: BlockMetaDelta,
pub struct GridBlockMetaChange {
pub delta: GridBlockMetaDelta,
/// md5: the md5 of the grid after applying the change.
pub md5: String,
}
pub fn make_block_meta_delta(block_meta: &BlockMeta) -> BlockMetaDelta {
pub fn make_block_meta_delta(block_meta: &GridBlockMeta) -> GridBlockMetaDelta {
let json = serde_json::to_string(&block_meta).unwrap();
PlainTextDeltaBuilder::new().insert(&json).build()
}
pub fn make_block_meta_revisions(user_id: &str, block_meta: &BlockMeta) -> RepeatedRevision {
pub fn make_block_meta_revisions(user_id: &str, block_meta: &GridBlockMeta) -> RepeatedRevision {
let delta = make_block_meta_delta(block_meta);
let bytes = delta.to_bytes();
let revision = Revision::initial_revision(user_id, &block_meta.block_id, bytes);
revision.into()
}
impl std::default::Default for BlockMetaPad {
impl std::default::Default for GridBlockMetaPad {
fn default() -> Self {
let block_meta = BlockMeta {
let block_meta = GridBlockMeta {
block_id: uuid(),
rows: vec![],
};
let delta = make_block_meta_delta(&block_meta);
BlockMetaPad {
GridBlockMetaPad {
block_id: block_meta.block_id,
rows: block_meta.rows.into_iter().map(Arc::new).collect::<Vec<_>>(),
delta,
@ -165,7 +165,7 @@ impl std::default::Default for BlockMetaPad {
#[cfg(test)]
mod tests {
use crate::client_grid::{BlockMetaDelta, BlockMetaPad};
use crate::client_grid::{GridBlockMetaDelta, GridMetaPad};
use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset};
use std::str::FromStr;
@ -241,8 +241,8 @@ mod tests {
);
}
fn test_pad() -> BlockMetaPad {
let delta = BlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap();
BlockMetaPad::from_delta(delta).unwrap()
fn test_pad() -> GridMetaPad {
let delta = GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap();
GridMetaPad::from_delta(delta).unwrap()
}
}

View File

@ -1,9 +1,13 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{Field, FieldOrder, Grid, GridMeta, RowMeta, RowOrder};
use flowy_grid_data_model::entities::{
Field, FieldChangeset, FieldOrder, Grid, GridBlock, GridBlockChangeset, GridMeta, RepeatedField,
RepeatedFieldOrder, RowMeta, RowOrder,
};
use lib_infra::uuid;
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use std::collections::HashMap;
use std::sync::Arc;
pub type GridDelta = PlainTextDelta;
@ -31,13 +35,6 @@ impl GridMetaPad {
Self::from_delta(grid_delta)
}
pub fn create_row(&mut self, row: RowMeta) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
// grid.rows.push(row);
Ok(Some(()))
})
}
pub fn create_field(&mut self, field: Field) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.fields.push(field);
@ -45,13 +42,6 @@ impl GridMetaPad {
})
}
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
// grid.rows.retain(|row| !row_ids.contains(&row.id));
Ok(Some(()))
})
}
pub fn delete_field(&mut self, field_id: &str) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| match grid.fields.iter().position(|field| field.id == field_id) {
None => Ok(None),
@ -62,30 +52,93 @@ impl GridMetaPad {
})
}
pub fn md5(&self) -> String {
md5(&self.delta.to_bytes())
}
pub fn grid_data(&self) -> Grid {
let field_orders = self
pub fn get_fields(&self, field_orders: RepeatedFieldOrder) -> CollaborateResult<RepeatedField> {
let field_by_field_id = self
.grid_meta
.fields
.iter()
.map(FieldOrder::from)
.collect::<Vec<FieldOrder>>();
.map(|field| (&field.id, field))
.collect::<HashMap<&String, &Field>>();
// let row_orders = self
// .grid_meta
// .rows
// .iter()
// .map(RowOrder::from)
// .collect::<Vec<RowOrder>>();
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 {}", field_order.field_id);
None
}
Some(field) => Some((*field).clone()),
})
.collect::<Vec<Field>>();
Ok(fields.into())
}
Grid {
id: "".to_string(),
field_orders,
row_orders: vec![],
}
pub fn update_field(&mut self, change: FieldChangeset) -> CollaborateResult<Option<GridChange>> {
let field_id = change.field_id.clone();
self.modify_field(&field_id, |field| {
let mut is_changed = None;
if let Some(name) = change.name {
field.name = name;
is_changed = Some(())
}
if let Some(desc) = change.desc {
field.desc = desc;
is_changed = Some(())
}
if let Some(field_type) = change.field_type {
field.field_type = field_type;
is_changed = Some(())
}
if let Some(frozen) = change.frozen {
field.frozen = frozen;
is_changed = Some(())
}
if let Some(visibility) = change.visibility {
field.visibility = visibility;
is_changed = Some(())
}
if let Some(width) = change.width {
field.width = width;
is_changed = Some(())
}
if let Some(type_options) = change.type_options {
field.type_options = type_options;
is_changed = Some(())
}
Ok(is_changed)
})
}
pub fn create_block(&mut self, block: GridBlock) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| {
grid.blocks.push(block);
Ok(Some(()))
})
}
pub fn update_block(&mut self, change: GridBlockChangeset) -> CollaborateResult<Option<GridChange>> {
let block_id = change.block_id.clone();
self.modify_block(&block_id, |block| {
let mut is_changed = None;
if let Some(row_count) = change.row_count {
block.row_count = row_count;
is_changed = Some(());
}
Ok(is_changed)
})
}
pub fn md5(&self) -> String {
md5(&self.delta.to_bytes())
}
pub fn delta_str(&self) -> String {
@ -96,7 +149,7 @@ impl GridMetaPad {
&self.grid_meta.fields
}
pub fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChange>>
fn modify_grid<F>(&mut self, f: F) -> CollaborateResult<Option<GridChange>>
where
F: FnOnce(&mut GridMeta) -> CollaborateResult<Option<()>>,
{
@ -116,6 +169,32 @@ impl GridMetaPad {
}
}
}
pub fn modify_block<F>(&mut self, block_id: &str, f: F) -> CollaborateResult<Option<GridChange>>
where
F: FnOnce(&mut GridBlock) -> CollaborateResult<Option<()>>,
{
self.modify_grid(|grid| match grid.blocks.iter().position(|block| block.id == block_id) {
None => {
tracing::warn!("[GridMetaPad]: Can't find any block with id: {}", block_id);
Ok(None)
}
Some(index) => f(&mut grid.blocks[index]),
})
}
pub fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChange>>
where
F: FnOnce(&mut Field) -> CollaborateResult<Option<()>>,
{
self.modify_grid(|grid| match grid.fields.iter().position(|field| field.id == field_id) {
None => {
tracing::warn!("[GridMetaPad]: Can't find any field with id: {}", field_id);
Ok(None)
}
Some(index) => f(&mut grid.fields[index]),
})
}
}
fn json_from_grid(grid: &Arc<GridMeta>) -> CollaborateResult<String> {

View File

@ -2,9 +2,6 @@ use crate::entities::{Field, RowMeta};
use flowy_derive::ProtoBuf;
use std::collections::HashMap;
pub const DEFAULT_ROW_HEIGHT: i32 = 36;
pub const DEFAULT_FIELD_WIDTH: i32 = 150;
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct Grid {
#[pb(index = 1)]

View File

@ -15,11 +15,11 @@ pub struct GridMeta {
pub fields: Vec<Field>,
#[pb(index = 3)]
pub blocks: Vec<Block>,
pub blocks: Vec<GridBlock>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct Block {
pub struct GridBlock {
#[pb(index = 1)]
pub id: String,
@ -30,8 +30,14 @@ pub struct Block {
pub row_count: i32,
}
pub struct GridBlockChangeset {
pub block_id: String,
pub start_row_index: Option<i32>,
pub row_count: Option<i32>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct BlockMeta {
pub struct GridBlockMeta {
#[pb(index = 1)]
pub block_id: String,
@ -81,6 +87,33 @@ impl Field {
}
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct FieldChangeset {
#[pb(index = 1)]
pub field_id: String,
#[pb(index = 2, one_of)]
pub name: Option<String>,
#[pb(index = 3, one_of)]
pub desc: Option<String>,
#[pb(index = 4, one_of)]
pub field_type: Option<FieldType>,
#[pb(index = 5, one_of)]
pub frozen: Option<bool>,
#[pb(index = 6, one_of)]
pub visibility: Option<bool>,
#[pb(index = 7, one_of)]
pub width: Option<i32>,
#[pb(index = 8, one_of)]
pub type_options: Option<AnyData>,
}
#[derive(Debug, Default, ProtoBuf)]
pub struct RepeatedField {
#[pb(index = 1)]
@ -191,7 +224,7 @@ pub struct RowMeta {
}
impl RowMeta {
pub fn new(id: &str, grid_id: &str, cells: Vec<CellMeta>) -> Self {
pub fn new(id: &str, block_id: &str, cells: Vec<CellMeta>) -> Self {
let cell_by_field_id = cells
.into_iter()
.map(|cell| (cell.id.clone(), cell))
@ -199,7 +232,7 @@ impl RowMeta {
Self {
id: id.to_owned(),
block_id: grid_id.to_owned(),
block_id: block_id.to_owned(),
cell_by_field_id,
height: DEFAULT_ROW_HEIGHT,
visibility: true,

View File

@ -28,7 +28,7 @@ pub struct GridMeta {
// message fields
pub grid_id: ::std::string::String,
pub fields: ::protobuf::RepeatedField<Field>,
pub blocks: ::protobuf::RepeatedField<Block>,
pub blocks: ::protobuf::RepeatedField<GridBlock>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -96,10 +96,10 @@ impl GridMeta {
::std::mem::replace(&mut self.fields, ::protobuf::RepeatedField::new())
}
// repeated .Block blocks = 3;
// repeated .GridBlock blocks = 3;
pub fn get_blocks(&self) -> &[Block] {
pub fn get_blocks(&self) -> &[GridBlock] {
&self.blocks
}
pub fn clear_blocks(&mut self) {
@ -107,17 +107,17 @@ impl GridMeta {
}
// Param is passed by value, moved
pub fn set_blocks(&mut self, v: ::protobuf::RepeatedField<Block>) {
pub fn set_blocks(&mut self, v: ::protobuf::RepeatedField<GridBlock>) {
self.blocks = v;
}
// Mutable pointer to the field.
pub fn mut_blocks(&mut self) -> &mut ::protobuf::RepeatedField<Block> {
pub fn mut_blocks(&mut self) -> &mut ::protobuf::RepeatedField<GridBlock> {
&mut self.blocks
}
// Take field
pub fn take_blocks(&mut self) -> ::protobuf::RepeatedField<Block> {
pub fn take_blocks(&mut self) -> ::protobuf::RepeatedField<GridBlock> {
::std::mem::replace(&mut self.blocks, ::protobuf::RepeatedField::new())
}
}
@ -240,7 +240,7 @@ impl ::protobuf::Message for GridMeta {
|m: &GridMeta| { &m.fields },
|m: &mut GridMeta| { &mut m.fields },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<Block>>(
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<GridBlock>>(
"blocks",
|m: &GridMeta| { &m.blocks },
|m: &mut GridMeta| { &mut m.blocks },
@ -281,7 +281,7 @@ impl ::protobuf::reflect::ProtobufValue for GridMeta {
}
#[derive(PartialEq,Clone,Default)]
pub struct Block {
pub struct GridBlock {
// message fields
pub id: ::std::string::String,
pub start_row_index: i32,
@ -291,14 +291,14 @@ pub struct Block {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a Block {
fn default() -> &'a Block {
<Block as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a GridBlock {
fn default() -> &'a GridBlock {
<GridBlock as ::protobuf::Message>::default_instance()
}
}
impl Block {
pub fn new() -> Block {
impl GridBlock {
pub fn new() -> GridBlock {
::std::default::Default::default()
}
@ -359,7 +359,7 @@ impl Block {
}
}
impl ::protobuf::Message for Block {
impl ::protobuf::Message for GridBlock {
fn is_initialized(&self) -> bool {
true
}
@ -451,8 +451,8 @@ impl ::protobuf::Message for Block {
Self::descriptor_static()
}
fn new() -> Block {
Block::new()
fn new() -> GridBlock {
GridBlock::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -461,34 +461,34 @@ impl ::protobuf::Message for Block {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id",
|m: &Block| { &m.id },
|m: &mut Block| { &mut m.id },
|m: &GridBlock| { &m.id },
|m: &mut GridBlock| { &mut m.id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"start_row_index",
|m: &Block| { &m.start_row_index },
|m: &mut Block| { &mut m.start_row_index },
|m: &GridBlock| { &m.start_row_index },
|m: &mut GridBlock| { &mut m.start_row_index },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"row_count",
|m: &Block| { &m.row_count },
|m: &mut Block| { &mut m.row_count },
|m: &GridBlock| { &m.row_count },
|m: &mut GridBlock| { &mut m.row_count },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<Block>(
"Block",
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlock>(
"GridBlock",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static Block {
static instance: ::protobuf::rt::LazyV2<Block> = ::protobuf::rt::LazyV2::INIT;
instance.get(Block::new)
fn default_instance() -> &'static GridBlock {
static instance: ::protobuf::rt::LazyV2<GridBlock> = ::protobuf::rt::LazyV2::INIT;
instance.get(GridBlock::new)
}
}
impl ::protobuf::Clear for Block {
impl ::protobuf::Clear for GridBlock {
fn clear(&mut self) {
self.id.clear();
self.start_row_index = 0;
@ -497,20 +497,20 @@ impl ::protobuf::Clear for Block {
}
}
impl ::std::fmt::Debug for Block {
impl ::std::fmt::Debug for GridBlock {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for Block {
impl ::protobuf::reflect::ProtobufValue for GridBlock {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct BlockMeta {
pub struct GridBlockMeta {
// message fields
pub block_id: ::std::string::String,
pub rows: ::protobuf::RepeatedField<RowMeta>,
@ -519,14 +519,14 @@ pub struct BlockMeta {
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a BlockMeta {
fn default() -> &'a BlockMeta {
<BlockMeta as ::protobuf::Message>::default_instance()
impl<'a> ::std::default::Default for &'a GridBlockMeta {
fn default() -> &'a GridBlockMeta {
<GridBlockMeta as ::protobuf::Message>::default_instance()
}
}
impl BlockMeta {
pub fn new() -> BlockMeta {
impl GridBlockMeta {
pub fn new() -> GridBlockMeta {
::std::default::Default::default()
}
@ -582,7 +582,7 @@ impl BlockMeta {
}
}
impl ::protobuf::Message for BlockMeta {
impl ::protobuf::Message for GridBlockMeta {
fn is_initialized(&self) -> bool {
for v in &self.rows {
if !v.is_initialized() {
@ -665,8 +665,8 @@ impl ::protobuf::Message for BlockMeta {
Self::descriptor_static()
}
fn new() -> BlockMeta {
BlockMeta::new()
fn new() -> GridBlockMeta {
GridBlockMeta::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -675,29 +675,29 @@ impl ::protobuf::Message for BlockMeta {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"block_id",
|m: &BlockMeta| { &m.block_id },
|m: &mut BlockMeta| { &mut m.block_id },
|m: &GridBlockMeta| { &m.block_id },
|m: &mut GridBlockMeta| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowMeta>>(
"rows",
|m: &BlockMeta| { &m.rows },
|m: &mut BlockMeta| { &mut m.rows },
|m: &GridBlockMeta| { &m.rows },
|m: &mut GridBlockMeta| { &mut m.rows },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<BlockMeta>(
"BlockMeta",
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlockMeta>(
"GridBlockMeta",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static BlockMeta {
static instance: ::protobuf::rt::LazyV2<BlockMeta> = ::protobuf::rt::LazyV2::INIT;
instance.get(BlockMeta::new)
fn default_instance() -> &'static GridBlockMeta {
static instance: ::protobuf::rt::LazyV2<GridBlockMeta> = ::protobuf::rt::LazyV2::INIT;
instance.get(GridBlockMeta::new)
}
}
impl ::protobuf::Clear for BlockMeta {
impl ::protobuf::Clear for GridBlockMeta {
fn clear(&mut self) {
self.block_id.clear();
self.rows.clear();
@ -705,13 +705,13 @@ impl ::protobuf::Clear for BlockMeta {
}
}
impl ::std::fmt::Debug for BlockMeta {
impl ::std::fmt::Debug for GridBlockMeta {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for BlockMeta {
impl ::protobuf::reflect::ProtobufValue for GridBlockMeta {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
@ -1319,6 +1319,645 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedField {
}
}
#[derive(PartialEq,Clone,Default)]
pub struct FieldChangeset {
// message fields
pub field_id: ::std::string::String,
// message oneof groups
pub one_of_name: ::std::option::Option<FieldChangeset_oneof_one_of_name>,
pub one_of_desc: ::std::option::Option<FieldChangeset_oneof_one_of_desc>,
pub one_of_field_type: ::std::option::Option<FieldChangeset_oneof_one_of_field_type>,
pub one_of_frozen: ::std::option::Option<FieldChangeset_oneof_one_of_frozen>,
pub one_of_visibility: ::std::option::Option<FieldChangeset_oneof_one_of_visibility>,
pub one_of_width: ::std::option::Option<FieldChangeset_oneof_one_of_width>,
pub one_of_type_options: ::std::option::Option<FieldChangeset_oneof_one_of_type_options>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a FieldChangeset {
fn default() -> &'a FieldChangeset {
<FieldChangeset as ::protobuf::Message>::default_instance()
}
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_name {
name(::std::string::String),
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_desc {
desc(::std::string::String),
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_field_type {
field_type(FieldType),
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_frozen {
frozen(bool),
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_visibility {
visibility(bool),
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_width {
width(i32),
}
#[derive(Clone,PartialEq,Debug)]
pub enum FieldChangeset_oneof_one_of_type_options {
type_options(AnyData),
}
impl FieldChangeset {
pub fn new() -> FieldChangeset {
::std::default::Default::default()
}
// string field_id = 1;
pub fn get_field_id(&self) -> &str {
&self.field_id
}
pub fn clear_field_id(&mut self) {
self.field_id.clear();
}
// Param is passed by value, moved
pub fn set_field_id(&mut self, v: ::std::string::String) {
self.field_id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_field_id(&mut self) -> &mut ::std::string::String {
&mut self.field_id
}
// Take field
pub fn take_field_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.field_id, ::std::string::String::new())
}
// string name = 2;
pub fn get_name(&self) -> &str {
match self.one_of_name {
::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(ref v)) => v,
_ => "",
}
}
pub fn clear_name(&mut self) {
self.one_of_name = ::std::option::Option::None;
}
pub fn has_name(&self) -> bool {
match self.one_of_name {
::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_name(&mut self, v: ::std::string::String) {
self.one_of_name = ::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(v))
}
// Mutable pointer to the field.
pub fn mut_name(&mut self) -> &mut ::std::string::String {
if let ::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(_)) = self.one_of_name {
} else {
self.one_of_name = ::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(::std::string::String::new()));
}
match self.one_of_name {
::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(ref mut v)) => v,
_ => panic!(),
}
}
// Take field
pub fn take_name(&mut self) -> ::std::string::String {
if self.has_name() {
match self.one_of_name.take() {
::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(v)) => v,
_ => panic!(),
}
} else {
::std::string::String::new()
}
}
// string desc = 3;
pub fn get_desc(&self) -> &str {
match self.one_of_desc {
::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(ref v)) => v,
_ => "",
}
}
pub fn clear_desc(&mut self) {
self.one_of_desc = ::std::option::Option::None;
}
pub fn has_desc(&self) -> bool {
match self.one_of_desc {
::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_desc(&mut self, v: ::std::string::String) {
self.one_of_desc = ::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(v))
}
// Mutable pointer to the field.
pub fn mut_desc(&mut self) -> &mut ::std::string::String {
if let ::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(_)) = self.one_of_desc {
} else {
self.one_of_desc = ::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(::std::string::String::new()));
}
match self.one_of_desc {
::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(ref mut v)) => v,
_ => panic!(),
}
}
// Take field
pub fn take_desc(&mut self) -> ::std::string::String {
if self.has_desc() {
match self.one_of_desc.take() {
::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(v)) => v,
_ => panic!(),
}
} else {
::std::string::String::new()
}
}
// .FieldType field_type = 4;
pub fn get_field_type(&self) -> FieldType {
match self.one_of_field_type {
::std::option::Option::Some(FieldChangeset_oneof_one_of_field_type::field_type(v)) => v,
_ => FieldType::RichText,
}
}
pub fn clear_field_type(&mut self) {
self.one_of_field_type = ::std::option::Option::None;
}
pub fn has_field_type(&self) -> bool {
match self.one_of_field_type {
::std::option::Option::Some(FieldChangeset_oneof_one_of_field_type::field_type(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_field_type(&mut self, v: FieldType) {
self.one_of_field_type = ::std::option::Option::Some(FieldChangeset_oneof_one_of_field_type::field_type(v))
}
// bool frozen = 5;
pub fn get_frozen(&self) -> bool {
match self.one_of_frozen {
::std::option::Option::Some(FieldChangeset_oneof_one_of_frozen::frozen(v)) => v,
_ => false,
}
}
pub fn clear_frozen(&mut self) {
self.one_of_frozen = ::std::option::Option::None;
}
pub fn has_frozen(&self) -> bool {
match self.one_of_frozen {
::std::option::Option::Some(FieldChangeset_oneof_one_of_frozen::frozen(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_frozen(&mut self, v: bool) {
self.one_of_frozen = ::std::option::Option::Some(FieldChangeset_oneof_one_of_frozen::frozen(v))
}
// bool visibility = 6;
pub fn get_visibility(&self) -> bool {
match self.one_of_visibility {
::std::option::Option::Some(FieldChangeset_oneof_one_of_visibility::visibility(v)) => v,
_ => false,
}
}
pub fn clear_visibility(&mut self) {
self.one_of_visibility = ::std::option::Option::None;
}
pub fn has_visibility(&self) -> bool {
match self.one_of_visibility {
::std::option::Option::Some(FieldChangeset_oneof_one_of_visibility::visibility(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_visibility(&mut self, v: bool) {
self.one_of_visibility = ::std::option::Option::Some(FieldChangeset_oneof_one_of_visibility::visibility(v))
}
// int32 width = 7;
pub fn get_width(&self) -> i32 {
match self.one_of_width {
::std::option::Option::Some(FieldChangeset_oneof_one_of_width::width(v)) => v,
_ => 0,
}
}
pub fn clear_width(&mut self) {
self.one_of_width = ::std::option::Option::None;
}
pub fn has_width(&self) -> bool {
match self.one_of_width {
::std::option::Option::Some(FieldChangeset_oneof_one_of_width::width(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_width(&mut self, v: i32) {
self.one_of_width = ::std::option::Option::Some(FieldChangeset_oneof_one_of_width::width(v))
}
// .AnyData type_options = 8;
pub fn get_type_options(&self) -> &AnyData {
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) {
self.one_of_type_options = ::std::option::Option::None;
}
pub fn has_type_options(&self) -> bool {
match self.one_of_type_options {
::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_type_options(&mut self, v: AnyData) {
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 {
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()));
}
match self.one_of_type_options {
::std::option::Option::Some(FieldChangeset_oneof_one_of_type_options::type_options(ref mut v)) => v,
_ => panic!(),
}
}
// Take field
pub fn take_type_options(&mut self) -> AnyData {
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()
}
}
}
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
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
while !is.eof()? {
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.field_id)?;
},
2 => {
if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_name = ::std::option::Option::Some(FieldChangeset_oneof_one_of_name::name(is.read_string()?));
},
3 => {
if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_desc = ::std::option::Option::Some(FieldChangeset_oneof_one_of_desc::desc(is.read_string()?));
},
4 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_field_type = ::std::option::Option::Some(FieldChangeset_oneof_one_of_field_type::field_type(is.read_enum()?));
},
5 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_frozen = ::std::option::Option::Some(FieldChangeset_oneof_one_of_frozen::frozen(is.read_bool()?));
},
6 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_visibility = ::std::option::Option::Some(FieldChangeset_oneof_one_of_visibility::visibility(is.read_bool()?));
},
7 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_width = ::std::option::Option::Some(FieldChangeset_oneof_one_of_width::width(is.read_int32()?));
},
8 => {
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()?));
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.field_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.field_id);
}
if let ::std::option::Option::Some(ref v) = self.one_of_name {
match v {
&FieldChangeset_oneof_one_of_name::name(ref v) => {
my_size += ::protobuf::rt::string_size(2, &v);
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_desc {
match v {
&FieldChangeset_oneof_one_of_desc::desc(ref v) => {
my_size += ::protobuf::rt::string_size(3, &v);
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_field_type {
match v {
&FieldChangeset_oneof_one_of_field_type::field_type(v) => {
my_size += ::protobuf::rt::enum_size(4, v);
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_frozen {
match v {
&FieldChangeset_oneof_one_of_frozen::frozen(v) => {
my_size += 2;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_visibility {
match v {
&FieldChangeset_oneof_one_of_visibility::visibility(v) => {
my_size += 2;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_width {
match v {
&FieldChangeset_oneof_one_of_width::width(v) => {
my_size += ::protobuf::rt::value_size(7, v, ::protobuf::wire_format::WireTypeVarint);
},
};
}
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::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.field_id.is_empty() {
os.write_string(1, &self.field_id)?;
}
if let ::std::option::Option::Some(ref v) = self.one_of_name {
match v {
&FieldChangeset_oneof_one_of_name::name(ref v) => {
os.write_string(2, v)?;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_desc {
match v {
&FieldChangeset_oneof_one_of_desc::desc(ref v) => {
os.write_string(3, v)?;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_field_type {
match v {
&FieldChangeset_oneof_one_of_field_type::field_type(v) => {
os.write_enum(4, ::protobuf::ProtobufEnum::value(&v))?;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_frozen {
match v {
&FieldChangeset_oneof_one_of_frozen::frozen(v) => {
os.write_bool(5, v)?;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_visibility {
match v {
&FieldChangeset_oneof_one_of_visibility::visibility(v) => {
os.write_bool(6, v)?;
},
};
}
if let ::std::option::Option::Some(ref v) = self.one_of_width {
match v {
&FieldChangeset_oneof_one_of_width::width(v) => {
os.write_int32(7, v)?;
},
};
}
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_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
fn get_cached_size(&self) -> u32 {
self.cached_size.get()
}
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
&self.unknown_fields
}
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
&mut self.unknown_fields
}
fn as_any(&self) -> &dyn (::std::any::Any) {
self as &dyn (::std::any::Any)
}
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
self as &mut dyn (::std::any::Any)
}
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
self
}
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
Self::descriptor_static()
}
fn new() -> FieldChangeset {
FieldChangeset::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
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>(
"field_id",
|m: &FieldChangeset| { &m.field_id },
|m: &mut FieldChangeset| { &mut m.field_id },
));
fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
"name",
FieldChangeset::has_name,
FieldChangeset::get_name,
));
fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>(
"desc",
FieldChangeset::has_desc,
FieldChangeset::get_desc,
));
fields.push(::protobuf::reflect::accessor::make_singular_enum_accessor::<_, FieldType>(
"field_type",
FieldChangeset::has_field_type,
FieldChangeset::get_field_type,
));
fields.push(::protobuf::reflect::accessor::make_singular_bool_accessor::<_>(
"frozen",
FieldChangeset::has_frozen,
FieldChangeset::get_frozen,
));
fields.push(::protobuf::reflect::accessor::make_singular_bool_accessor::<_>(
"visibility",
FieldChangeset::has_visibility,
FieldChangeset::get_visibility,
));
fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>(
"width",
FieldChangeset::has_width,
FieldChangeset::get_width,
));
fields.push(::protobuf::reflect::accessor::make_singular_message_accessor::<_, AnyData>(
"type_options",
FieldChangeset::has_type_options,
FieldChangeset::get_type_options,
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<FieldChangeset>(
"FieldChangeset",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static FieldChangeset {
static instance: ::protobuf::rt::LazyV2<FieldChangeset> = ::protobuf::rt::LazyV2::INIT;
instance.get(FieldChangeset::new)
}
}
impl ::protobuf::Clear for FieldChangeset {
fn clear(&mut self) {
self.field_id.clear();
self.one_of_name = ::std::option::Option::None;
self.one_of_desc = ::std::option::Option::None;
self.one_of_field_type = ::std::option::Option::None;
self.one_of_frozen = ::std::option::Option::None;
self.one_of_visibility = ::std::option::Option::None;
self.one_of_width = ::std::option::Option::None;
self.one_of_type_options = ::std::option::Option::None;
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for FieldChangeset {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for FieldChangeset {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct AnyData {
// message fields
@ -2537,43 +3176,53 @@ impl ::protobuf::reflect::ProtobufValue for FieldType {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\nmeta.proto\"c\n\x08GridMeta\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
\n\nmeta.proto\"g\n\x08GridMeta\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
\x06gridId\x12\x1e\n\x06fields\x18\x02\x20\x03(\x0b2\x06.FieldR\x06field\
s\x12\x1e\n\x06blocks\x18\x03\x20\x03(\x0b2\x06.BlockR\x06blocks\"\\\n\
\x05Block\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12&\n\x0fstart_row_\
index\x18\x02\x20\x01(\x05R\rstartRowIndex\x12\x1b\n\trow_count\x18\x03\
\x20\x01(\x05R\x08rowCount\"D\n\tBlockMeta\x12\x19\n\x08block_id\x18\x01\
\x20\x01(\tR\x07blockId\x12\x1c\n\x04rows\x18\x02\x20\x03(\x0b2\x08.RowM\
etaR\x04rows\"\xe5\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\
\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\
s\x12\"\n\x06blocks\x18\x03\x20\x03(\x0b2\n.GridBlockR\x06blocks\"`\n\tG\
ridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12&\n\x0fstart_row_i\
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\
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\"-\n\rRepeatedField\x12\x1c\n\x05\
items\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\x07blockId\
\x12D\n\x10cell_by_field_id\x18\x03\x20\x03(\x0b2\x1b.RowMeta.CellByFiel\
dIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x04\x20\x01(\x05R\x06he\
ight\x12\x1e\n\nvisibility\x18\x05\x20\x01(\x08R\nvisibility\x1aK\n\x12C\
ellByFieldIdEntry\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\nvisib\
ility\x18\x03\x20\x01(\x08H\x01R\nvisibility\x12M\n\x10cell_by_field_id\
\x18\x04\x20\x03(\x0b2$.RowMetaChangeset.CellByFieldIdEntryR\rcellByFiel\
dId\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(\t\
R\x07fieldId\x12\x1c\n\x04data\x18\x04\x20\x01(\x0b2\x08.AnyDataR\x04dat\
a\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\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\
\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\
items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"\x87\x03\n\x0eFieldChan\
geset\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x14\n\x04\
name\x18\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\t\
H\x01R\x04desc\x12+\n\nfield_type\x18\x04\x20\x01(\x0e2\n.FieldTypeH\x02\
R\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(\x0b2\x08.AnyDataH\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\x0cone_of_widthB\x15\n\x13one_of_type\
_options\"8\n\x07AnyData\x12\x17\n\x07type_id\x18\x01\x20\x01(\tR\x06typ\
eId\x12\x14\n\x05value\x18\x02\x20\x01(\x0cR\x05value\"\xff\x01\n\x07Row\
Meta\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\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\nvisibili\
ty\x12M\n\x10cell_by_field_id\x18\x04\x20\x03(\x0b2$.RowMetaChangeset.Ce\
llByFieldIdEntryR\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\x08\
field_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(\x05\
R\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\x0cSingleSelect\x10\x03\
\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06prot\
o3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -3,14 +3,14 @@ syntax = "proto3";
message GridMeta {
string grid_id = 1;
repeated Field fields = 2;
repeated Block blocks = 3;
repeated GridBlock blocks = 3;
}
message Block {
message GridBlock {
string id = 1;
int32 start_row_index = 2;
int32 row_count = 3;
}
message BlockMeta {
message GridBlockMeta {
string block_id = 1;
repeated RowMeta rows = 2;
}
@ -27,6 +27,16 @@ message Field {
message RepeatedField {
repeated Field items = 1;
}
message FieldChangeset {
string field_id = 1;
oneof one_of_name { string name = 2; };
oneof one_of_desc { string desc = 3; };
oneof one_of_field_type { FieldType field_type = 4; };
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; };
}
message AnyData {
string type_id = 1;
bytes value = 2;