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) 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') ..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<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 ..hasRequiredFields = false
; ;
@ -25,7 +25,7 @@ class GridMeta extends $pb.GeneratedMessage {
factory GridMeta({ factory GridMeta({
$core.String? gridId, $core.String? gridId,
$core.Iterable<Field>? fields, $core.Iterable<Field>? fields,
$core.Iterable<Block>? blocks, $core.Iterable<GridBlock>? blocks,
}) { }) {
final _result = create(); final _result = create();
if (gridId != null) { if (gridId != null) {
@ -73,19 +73,19 @@ class GridMeta extends $pb.GeneratedMessage {
$core.List<Field> get fields => $_getList(1); $core.List<Field> get fields => $_getList(1);
@$pb.TagNumber(3) @$pb.TagNumber(3)
$core.List<Block> get blocks => $_getList(2); $core.List<GridBlock> get blocks => $_getList(2);
} }
class Block extends $pb.GeneratedMessage { class GridBlock extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Block', createEmptyInstance: create) 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') ..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>(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) ..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowCount', $pb.PbFieldType.O3)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
Block._() : super(); GridBlock._() : super();
factory Block({ factory GridBlock({
$core.String? id, $core.String? id,
$core.int? startRowIndex, $core.int? startRowIndex,
$core.int? rowCount, $core.int? rowCount,
@ -102,26 +102,26 @@ class Block extends $pb.GeneratedMessage {
} }
return _result; return _result;
} }
factory Block.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory GridBlock.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.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated( @$core.Deprecated(
'Using this can add significant overhead to your binary. ' 'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version') 'Will be removed in next major version')
Block clone() => Block()..mergeFromMessage(this); GridBlock clone() => GridBlock()..mergeFromMessage(this);
@$core.Deprecated( @$core.Deprecated(
'Using this can add significant overhead to your binary. ' 'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version') '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; $pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline') @$core.pragma('dart2js:noInline')
static Block create() => Block._(); static GridBlock create() => GridBlock._();
Block createEmptyInstance() => create(); GridBlock createEmptyInstance() => create();
static $pb.PbList<Block> createRepeated() => $pb.PbList<Block>(); static $pb.PbList<GridBlock> createRepeated() => $pb.PbList<GridBlock>();
@$core.pragma('dart2js:noInline') @$core.pragma('dart2js:noInline')
static Block getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Block>(create); static GridBlock getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlock>(create);
static Block? _defaultInstance; static GridBlock? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.String get id => $_getSZ(0); $core.String get id => $_getSZ(0);
@ -151,15 +151,15 @@ class Block extends $pb.GeneratedMessage {
void clearRowCount() => clearField(3); void clearRowCount() => clearField(3);
} }
class BlockMeta extends $pb.GeneratedMessage { class GridBlockMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BlockMeta', createEmptyInstance: create) 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') ..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) ..pc<RowMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rows', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
BlockMeta._() : super(); GridBlockMeta._() : super();
factory BlockMeta({ factory GridBlockMeta({
$core.String? blockId, $core.String? blockId,
$core.Iterable<RowMeta>? rows, $core.Iterable<RowMeta>? rows,
}) { }) {
@ -172,26 +172,26 @@ class BlockMeta extends $pb.GeneratedMessage {
} }
return _result; return _result;
} }
factory BlockMeta.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory GridBlockMeta.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.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated( @$core.Deprecated(
'Using this can add significant overhead to your binary. ' 'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version') 'Will be removed in next major version')
BlockMeta clone() => BlockMeta()..mergeFromMessage(this); GridBlockMeta clone() => GridBlockMeta()..mergeFromMessage(this);
@$core.Deprecated( @$core.Deprecated(
'Using this can add significant overhead to your binary. ' 'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version') '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; $pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline') @$core.pragma('dart2js:noInline')
static BlockMeta create() => BlockMeta._(); static GridBlockMeta create() => GridBlockMeta._();
BlockMeta createEmptyInstance() => create(); GridBlockMeta createEmptyInstance() => create();
static $pb.PbList<BlockMeta> createRepeated() => $pb.PbList<BlockMeta>(); static $pb.PbList<GridBlockMeta> createRepeated() => $pb.PbList<GridBlockMeta>();
@$core.pragma('dart2js:noInline') @$core.pragma('dart2js:noInline')
static BlockMeta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockMeta>(create); static GridBlockMeta getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlockMeta>(create);
static BlockMeta? _defaultInstance; static GridBlockMeta? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.String get blockId => $_getSZ(0); $core.String get blockId => $_getSZ(0);
@ -394,6 +394,244 @@ class RepeatedField extends $pb.GeneratedMessage {
$core.List<Field> get items => $_getList(0); $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 { class AnyData extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'AnyData', createEmptyInstance: create) 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') ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeId')

View File

@ -29,15 +29,15 @@ const GridMeta$json = const {
'2': const [ '2': const [
const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, 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': '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`. /// Descriptor for `GridMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSHgoGZmllbGRzGAIgAygLMgYuRmllbGRSBmZpZWxkcxIeCgZibG9ja3MYAyADKAsyBi5CbG9ja1IGYmxvY2tz'); final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSHgoGZmllbGRzGAIgAygLMgYuRmllbGRSBmZpZWxkcxIiCgZibG9ja3MYAyADKAsyCi5HcmlkQmxvY2tSBmJsb2Nrcw==');
@$core.Deprecated('Use blockDescriptor instead') @$core.Deprecated('Use gridBlockDescriptor instead')
const Block$json = const { const GridBlock$json = const {
'1': 'Block', '1': 'GridBlock',
'2': const [ '2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {'1': 'start_row_index', '3': 2, '4': 1, '5': 5, '10': 'startRowIndex'}, 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`. /// Descriptor for `GridBlock`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List blockDescriptor = $convert.base64Decode('CgVCbG9jaxIOCgJpZBgBIAEoCVICaWQSJgoPc3RhcnRfcm93X2luZGV4GAIgASgFUg1zdGFydFJvd0luZGV4EhsKCXJvd19jb3VudBgDIAEoBVIIcm93Q291bnQ='); final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSDgoCaWQYASABKAlSAmlkEiYKD3N0YXJ0X3Jvd19pbmRleBgCIAEoBVINc3RhcnRSb3dJbmRleBIbCglyb3dfY291bnQYAyABKAVSCHJvd0NvdW50');
@$core.Deprecated('Use blockMetaDescriptor instead') @$core.Deprecated('Use gridBlockMetaDescriptor instead')
const BlockMeta$json = const { const GridBlockMeta$json = const {
'1': 'BlockMeta', '1': 'GridBlockMeta',
'2': const [ '2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, 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'}, const {'1': 'rows', '3': 2, '4': 3, '5': 11, '6': '.RowMeta', '10': 'rows'},
], ],
}; };
/// Descriptor for `BlockMeta`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `GridBlockMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List blockMetaDescriptor = $convert.base64Decode('CglCbG9ja01ldGESGQoIYmxvY2tfaWQYASABKAlSB2Jsb2NrSWQSHAoEcm93cxgCIAMoCzIILlJvd01ldGFSBHJvd3M='); final $typed_data.Uint8List gridBlockMetaDescriptor = $convert.base64Decode('Cg1HcmlkQmxvY2tNZXRhEhkKCGJsb2NrX2lkGAEgASgJUgdibG9ja0lkEhwKBHJvd3MYAiADKAsyCC5Sb3dNZXRhUgRyb3dz');
@$core.Deprecated('Use fieldDescriptor instead') @$core.Deprecated('Use fieldDescriptor instead')
const Field$json = const { const Field$json = const {
'1': 'Field', '1': 'Field',
@ -85,6 +85,32 @@ const RepeatedField$json = const {
/// Descriptor for `RepeatedField`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `RepeatedField`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List repeatedFieldDescriptor = $convert.base64Decode('Cg1SZXBlYXRlZEZpZWxkEhwKBWl0ZW1zGAEgAygLMgYuRmllbGRSBWl0ZW1z'); 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') @$core.Deprecated('Use anyDataDescriptor instead')
const AnyData$json = const { const AnyData$json = const {
'1': 'AnyData', '1': 'AnyData',

View File

@ -7,8 +7,8 @@ edition = "2018"
[lib] [lib]
name = "dart_ffi" name = "dart_ffi"
# this value will change depending on the target os # this value will change depending on the target os
# default staticlib # default cdylib
crate-type = ["staticlib"] crate-type = ["cdylib"]
[dependencies] [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::web_socket::{make_block_ws_manager, EditorCommandSender};
use crate::{ use crate::{
errors::FlowyError, errors::FlowyError,
@ -40,9 +40,7 @@ impl ClientTextBlockEditor {
rev_web_socket: Arc<dyn RevisionWebSocket>, rev_web_socket: Arc<dyn RevisionWebSocket>,
cloud_service: Arc<dyn RevisionCloudService>, cloud_service: Arc<dyn RevisionCloudService>,
) -> FlowyResult<Arc<Self>> { ) -> FlowyResult<Arc<Self>> {
let document_info = rev_manager let document_info = rev_manager.load::<BlockInfoBuilder>(cloud_service).await?;
.load::<BlockInfoBuilder, BlockRevisionCompact>(cloud_service)
.await?;
let delta = document_info.delta()?; let delta = document_info.delta()?;
let rev_manager = Arc::new(rev_manager); let rev_manager = Arc::new(rev_manager);
let doc_id = doc_id.to_string(); let doc_id = doc_id.to_string();

View File

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

View File

@ -1,6 +1,7 @@
use crate::web_socket::EditorCommandReceiver; use crate::web_socket::EditorCommandReceiver;
use crate::TextBlockUser; use crate::TextBlockUser;
use async_stream::stream; use async_stream::stream;
use bytes::Bytes;
use flowy_collaboration::util::make_delta_from_revisions; use flowy_collaboration::util::make_delta_from_revisions;
use flowy_collaboration::{ use flowy_collaboration::{
client_document::{history::UndoResult, ClientDocument}, client_document::{history::UndoResult, ClientDocument},
@ -8,8 +9,9 @@ use flowy_collaboration::{
errors::CollaborateError, errors::CollaborateError,
}; };
use flowy_error::{FlowyError, FlowyResult}; 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 futures::stream::StreamExt;
use lib_ot::core::{Attributes, Delta};
use lib_ot::{ use lib_ot::{
core::{Interval, OperationTransformable}, core::{Interval, OperationTransformable},
rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta}, rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta},
@ -187,31 +189,17 @@ impl EditBlockQueue {
); );
let _ = self let _ = self
.rev_manager .rev_manager
.add_local_revision::<BlockRevisionCompact>(&revision) .add_local_revision(&revision, Box::new(TextBlockRevisionCompactor()))
.await?; .await?;
Ok(rev_id.into()) Ok(rev_id.into())
} }
} }
pub(crate) struct BlockRevisionCompact(); pub(crate) struct TextBlockRevisionCompactor();
impl RevisionCompact for BlockRevisionCompact { impl RevisionCompactor for TextBlockRevisionCompactor {
fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
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();
let delta = make_delta_from_revisions::<RichTextAttributes>(revisions)?; let delta = make_delta_from_revisions::<RichTextAttributes>(revisions)?;
let delta_data = delta.to_bytes(); Ok(delta.to_bytes())
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5))
} }
} }

View File

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

View File

@ -3,12 +3,3 @@ CREATE TABLE kv_table (
key TEXT NOT NULL PRIMARY KEY, key TEXT NOT NULL PRIMARY KEY,
value BLOB NOT NULL DEFAULT (x'') 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! { table! {
grid_rev_table (id) { grid_rev_table (id) {
id -> Integer, id -> Integer,
@ -102,6 +113,7 @@ table! {
allow_tables_to_appear_in_same_query!( allow_tables_to_appear_in_same_query!(
app_table, app_table,
doc_table, doc_table,
grid_meta_rev_table,
grid_rev_table, grid_rev_table,
kv_table, kv_table,
rev_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_error::FlowyError;
use flowy_folder_data_model::entities::view::ViewDataType; use flowy_folder_data_model::entities::view::ViewDataType;
use flowy_folder_data_model::user_default; 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 lazy_static::lazy_static;
use lib_infra::future::FutureResult; use lib_infra::future::FutureResult;
use std::{collections::HashMap, convert::TryInto, fmt::Formatter, sync::Arc}; 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 _ = self.persistence.initialize(user_id, &folder_id).await?;
let pool = self.persistence.db_pool()?; 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)); *self.folder_editor.write().await = Some(Arc::new(folder_editor));
let _ = self.app_controller.initialize()?; let _ = self.app_controller.initialize()?;

View File

@ -5,14 +5,16 @@ use flowy_collaboration::{
}; };
use crate::manager::FolderId; use crate::manager::FolderId;
use bytes::Bytes;
use flowy_collaboration::util::make_delta_from_revisions; use flowy_collaboration::util::make_delta_from_revisions;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_sync::disk::RevisionDiskCache;
use flowy_sync::{ use flowy_sync::{
RevisionCloudService, RevisionCompact, RevisionManager, RevisionObjectBuilder, RevisionPersistence, RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionPersistence,
RevisionWebSocket, RevisionWebSocketManager, RevisionWebSocket, RevisionWebSocketManager,
}; };
use lib_infra::future::FutureResult; use lib_infra::future::FutureResult;
use lib_ot::core::PlainTextAttributes; use lib_ot::core::{Delta, PlainTextAttributes};
use lib_sqlite::ConnectionPool; use lib_sqlite::ConnectionPool;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
@ -30,19 +32,13 @@ impl ClientFolderEditor {
user_id: &str, user_id: &str,
folder_id: &FolderId, folder_id: &FolderId,
token: &str, token: &str,
pool: Arc<ConnectionPool>, mut rev_manager: RevisionManager,
web_socket: Arc<dyn RevisionWebSocket>, web_socket: Arc<dyn RevisionWebSocket>,
) -> FlowyResult<Self> { ) -> 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 { let cloud = Arc::new(FolderRevisionCloudService {
token: token.to_string(), token: token.to_string(),
}); });
let folder = Arc::new(RwLock::new( let folder = Arc::new(RwLock::new(rev_manager.load::<FolderPadBuilder>(cloud).await?));
rev_manager
.load::<FolderPadBuilder, FolderRevisionCompact>(cloud)
.await?,
));
let rev_manager = Arc::new(rev_manager); let rev_manager = Arc::new(rev_manager);
let ws_manager = make_folder_ws_manager( let ws_manager = make_folder_ws_manager(
user_id, user_id,
@ -86,7 +82,7 @@ impl ClientFolderEditor {
); );
let _ = futures::executor::block_on(async { let _ = futures::executor::block_on(async {
self.rev_manager self.rev_manager
.add_local_revision::<FolderRevisionCompact>(&revision) .add_local_revision(&revision, Box::new(FolderRevisionCompactor()))
.await .await
})?; })?;
Ok(()) Ok(())
@ -128,24 +124,10 @@ impl ClientFolderEditor {
} }
} }
struct FolderRevisionCompact(); struct FolderRevisionCompactor();
impl RevisionCompact for FolderRevisionCompact { impl RevisionCompactor for FolderRevisionCompactor {
fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
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 = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
let delta_data = delta.to_bytes(); Ok(delta.to_bytes())
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5))
} }
} }

View File

@ -11,6 +11,7 @@ use flowy_folder_data_model::entities::{
view::{RepeatedView, View}, view::{RepeatedView, View},
workspace::Workspace, workspace::Workspace,
}; };
use flowy_sync::disk::SQLiteTextBlockRevisionPersistence;
use flowy_sync::{RevisionLoader, RevisionPersistence}; use flowy_sync::{RevisionLoader, RevisionPersistence};
use std::sync::Arc; use std::sync::Arc;
@ -87,7 +88,8 @@ impl FolderMigration {
return Ok(None); return Ok(None);
} }
let pool = self.database.db_pool()?; 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 { let (revisions, _) = RevisionLoader {
object_id: folder_id.as_ref().to_owned(), object_id: folder_id.as_ref().to_owned(),
user_id: self.user_id.clone(), 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_grid_data_model::entities::{Field, RowMeta};
use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket}; use flowy_sync::{RevisionManager, RevisionPersistence, RevisionWebSocket};
use flowy_sync::disk::SQLiteGridRevisionPersistence;
use lib_sqlite::ConnectionPool; use lib_sqlite::ConnectionPool;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
@ -104,7 +105,9 @@ impl GridManager {
fn make_grid_rev_manager(&self, grid_id: &str, pool: Arc<ConnectionPool>) -> FlowyResult<RevisionManager> { fn make_grid_rev_manager(&self, grid_id: &str, pool: Arc<ConnectionPool>) -> FlowyResult<RevisionManager> {
let user_id = self.grid_user.user_id()?; 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); let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence);
Ok(rev_manager) Ok(rev_manager)
} }

View File

@ -2,6 +2,8 @@ use crate::manager::GridUser;
use crate::services::kv_persistence::{GridKVPersistence, KVTransaction}; use crate::services::kv_persistence::{GridKVPersistence, KVTransaction};
use crate::services::stringify::stringify_deserialize; use crate::services::stringify::stringify_deserialize;
use crate::services::grid_meta_editor::ClientGridBlockMetaEditor;
use bytes::Bytes;
use dashmap::DashMap; use dashmap::DashMap;
use flowy_collaboration::client_grid::{GridChange, GridMetaPad}; use flowy_collaboration::client_grid::{GridChange, GridMetaPad};
use flowy_collaboration::entities::revision::Revision; use flowy_collaboration::entities::revision::Revision;
@ -10,10 +12,10 @@ use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{ use flowy_grid_data_model::entities::{
Cell, CellMeta, Field, Grid, RepeatedField, RepeatedFieldOrder, RepeatedRow, RepeatedRowOrder, Row, RowMeta, 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::future::FutureResult;
use lib_infra::uuid; use lib_infra::uuid;
use lib_ot::core::PlainTextAttributes; use lib_ot::core::{Delta, PlainTextAttributes};
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
@ -24,10 +26,8 @@ pub struct ClientGridEditor {
user: Arc<dyn GridUser>, user: Arc<dyn GridUser>,
grid_meta_pad: Arc<RwLock<GridMetaPad>>, grid_meta_pad: Arc<RwLock<GridMetaPad>>,
rev_manager: Arc<RevisionManager>, rev_manager: Arc<RevisionManager>,
block_meta_manager: Arc<GridBlockMetaEditorManager>,
kv_persistence: Arc<GridKVPersistence>, kv_persistence: Arc<GridKVPersistence>,
field_map: DashMap<String, Field>,
cell_map: DashMap<String, CellMeta>,
} }
impl ClientGridEditor { impl ClientGridEditor {
@ -39,50 +39,22 @@ impl ClientGridEditor {
) -> FlowyResult<Arc<Self>> { ) -> FlowyResult<Arc<Self>> {
let token = user.token()?; let token = user.token()?;
let cloud = Arc::new(GridRevisionCloudService { 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 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 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 { Ok(Arc::new(Self {
grid_id: grid_id.to_owned(), grid_id: grid_id.to_owned(),
user, user,
grid_meta_pad, grid_meta_pad,
rev_manager, rev_manager,
block_meta_manager,
kv_persistence, 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<()> { pub async fn create_field(&mut self, field: Field) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.create_field(field)?)).await?; let _ = self.modify(|grid| Ok(grid.create_field(field)?)).await?;
Ok(()) Ok(())
@ -90,76 +62,38 @@ impl ClientGridEditor {
pub async fn delete_field(&mut self, field_id: &str) -> FlowyResult<()> { pub async fn delete_field(&mut self, field_id: &str) -> FlowyResult<()> {
let _ = self.modify(|grid| Ok(grid.delete_field(field_id)?)).await?; let _ = self.modify(|grid| Ok(grid.delete_field(field_id)?)).await?;
// let _ = self.kv.remove(field_id)?;
Ok(()) Ok(())
} }
pub async fn create_empty_row(&self) -> FlowyResult<()> {
// let _ = self.modify(|grid| {
//
//
// grid.blocks
//
// }).await?;
todo!()
}
async fn create_row(&self, row: RowMeta) -> FlowyResult<()> {
todo!()
}
pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> { pub async fn get_rows(&self, row_orders: RepeatedRowOrder) -> FlowyResult<RepeatedRow> {
let ids = row_orders todo!()
.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 get_fields(&self, field_orders: RepeatedFieldOrder) -> FlowyResult<RepeatedField> { pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<()> {
let fields = field_orders todo!()
.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())
} }
pub async fn grid_data(&self) -> Grid { 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 { pub async fn delta_str(&self) -> String {
@ -195,7 +129,7 @@ impl ClientGridEditor {
); );
let _ = self let _ = self
.rev_manager .rev_manager
.add_local_revision::<GridRevisionCompact>(&revision) .add_local_revision(&revision, Box::new(GridRevisionCompactor()))
.await?; .await?;
Ok(()) Ok(())
} }
@ -241,24 +175,73 @@ impl RevisionCloudService for GridRevisionCloudService {
} }
} }
struct GridRevisionCompact(); struct GridRevisionCompactor();
impl RevisionCompact for GridRevisionCompact { impl RevisionCompactor for GridRevisionCompactor {
fn compact_revisions(user_id: &str, object_id: &str, mut revisions: Vec<Revision>) -> FlowyResult<Revision> { fn bytes_from_revisions(&self, revisions: Vec<Revision>) -> FlowyResult<Bytes> {
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 = make_delta_from_revisions::<PlainTextAttributes>(revisions)?; let delta = make_delta_from_revisions::<PlainTextAttributes>(revisions)?;
let delta_data = delta.to_bytes(); Ok(delta.to_bytes())
Ok(Revision::new(object_id, base_rev_id, rev_id, delta_data, user_id, md5)) }
}
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 cell_data;
pub mod grid_builder; pub mod grid_builder;
pub mod grid_editor; pub mod grid_editor;
pub mod grid_meta_editor;
pub mod kv_persistence; pub mod kv_persistence;
pub mod stringify; pub mod stringify;

View File

@ -66,10 +66,10 @@ fn make_view_data_processor(
) -> ViewDataProcessorMap { ) -> ViewDataProcessorMap {
let mut map: HashMap<ViewDataType, Arc<dyn ViewDataProcessor + Send + Sync>> = HashMap::new(); 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)); 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)); map.insert(grid_data_impl.data_type(), Arc::new(grid_data_impl));
Arc::new(map) Arc::new(map)
@ -133,8 +133,8 @@ impl WSMessageReceiver for FolderWSMessageReceiverImpl {
} }
} }
struct BlockManagerViewDataImpl(Arc<TextBlockManager>); struct TextBlockViewDataProcessor(Arc<TextBlockManager>);
impl ViewDataProcessor for BlockManagerViewDataImpl { impl ViewDataProcessor for TextBlockViewDataProcessor {
fn initialize(&self) -> FutureResult<(), FlowyError> { fn initialize(&self) -> FutureResult<(), FlowyError> {
let manager = self.0.clone(); let manager = self.0.clone();
FutureResult::new(async move { manager.init() }) FutureResult::new(async move { manager.init() })
@ -186,8 +186,8 @@ impl ViewDataProcessor for BlockManagerViewDataImpl {
} }
} }
struct GridManagerViewDataImpl(Arc<GridManager>); struct GridViewDataProcessor(Arc<GridManager>);
impl ViewDataProcessor for GridManagerViewDataImpl { impl ViewDataProcessor for GridViewDataProcessor {
fn initialize(&self) -> FutureResult<(), FlowyError> { fn initialize(&self) -> FutureResult<(), FlowyError> {
FutureResult::new(async { Ok(()) }) 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::cache::disk::RevisionDiskCache;
use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState}; use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState};
use crate::memory::RevisionMemoryCacheDelegate;
use bytes::Bytes; use bytes::Bytes;
use diesel::{sql_types::Integer, update, SqliteConnection}; use diesel::{sql_types::Integer, update, SqliteConnection};
use flowy_collaboration::{ use flowy_collaboration::{
@ -23,12 +24,9 @@ pub struct SQLiteGridRevisionPersistence {
impl RevisionDiskCache for SQLiteGridRevisionPersistence { impl RevisionDiskCache for SQLiteGridRevisionPersistence {
type Error = FlowyError; type Error = FlowyError;
fn create_revision_records( fn create_revision_records(&self, revision_records: Vec<RevisionRecord>) -> Result<(), Self::Error> {
&self, let conn = self.pool.get().map_err(internal_error)?;
revision_records: Vec<RevisionRecord>, let _ = GridRevisionSql::create(revision_records, &*conn)?;
conn: &SqliteConnection,
) -> Result<(), Self::Error> {
let _ = GridRevisionSql::create(revision_records, conn)?;
Ok(()) Ok(())
} }
@ -78,14 +76,14 @@ impl RevisionDiskCache for SQLiteGridRevisionPersistence {
let conn = self.pool.get().map_err(internal_error)?; let conn = self.pool.get().map_err(internal_error)?;
conn.immediate_transaction::<_, FlowyError, _>(|| { conn.immediate_transaction::<_, FlowyError, _>(|| {
let _ = GridRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?; let _ = GridRevisionSql::delete(object_id, deleted_rev_ids, &*conn)?;
let _ = self.create_revision_records(inserted_records, &*conn)?; let _ = GridRevisionSql::create(inserted_records, &*conn)?;
Ok(()) Ok(())
}) })
} }
} }
impl SQLiteGridRevisionPersistence { impl SQLiteGridRevisionPersistence {
pub(crate) fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self { pub fn new(user_id: &str, pool: Arc<ConnectionPool>) -> Self {
Self { Self {
user_id: user_id.to_owned(), user_id: user_id.to_owned(),
pool, pool,
@ -193,13 +191,13 @@ impl GridRevisionSql {
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "grid_rev_table"] #[table_name = "grid_rev_table"]
pub(crate) struct GridRevisionTable { struct GridRevisionTable {
id: i32, id: i32,
pub(crate) object_id: String, object_id: String,
pub(crate) base_rev_id: i64, base_rev_id: i64,
pub(crate) rev_id: i64, rev_id: i64,
pub(crate) data: Vec<u8>, data: Vec<u8>,
pub(crate) state: GridRevisionState, state: GridRevisionState,
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
@ -209,6 +207,8 @@ pub enum GridRevisionState {
Sync = 0, Sync = 0,
Ack = 1, Ack = 1,
} }
impl_sql_integer_expression!(GridRevisionState);
impl_rev_state_map!(GridRevisionState);
impl std::default::Default for GridRevisionState { impl std::default::Default for GridRevisionState {
fn default() -> Self { 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 { fn mk_revision_record_from_table(user_id: &str, table: GridRevisionTable) -> RevisionRecord {
let md5 = md5(&table.data); let md5 = md5(&table.data);
let revision = Revision::new( let revision = Revision::new(

View File

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

View File

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

View File

@ -1,11 +1,13 @@
use crate::disk::RevisionState; use crate::disk::RevisionState;
use crate::{RevisionPersistence, WSDataProviderDataSource}; use crate::{RevisionPersistence, WSDataProviderDataSource};
use bytes::Bytes;
use flowy_collaboration::{ use flowy_collaboration::{
entities::revision::{RepeatedRevision, Revision, RevisionRange}, entities::revision::{RepeatedRevision, Revision, RevisionRange},
util::{pair_rev_id_from_revisions, RevIdCounter}, util::{pair_rev_id_from_revisions, RevIdCounter},
}; };
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use lib_infra::future::FutureResult; use lib_infra::future::FutureResult;
use lib_ot::core::{Attributes, Delta};
use std::sync::Arc; use std::sync::Arc;
pub trait RevisionCloudService: Send + Sync { 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>; fn build_object(object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Self::Output>;
} }
pub trait RevisionCompact: Send + Sync { pub trait RevisionCompactor: Send + Sync {
fn compact_revisions(user_id: &str, object_id: &str, revisions: Vec<Revision>) -> FlowyResult<Revision>; 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 { 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 where
B: RevisionObjectBuilder, B: RevisionObjectBuilder,
C: RevisionCompact,
{ {
let (revisions, rev_id) = RevisionLoader { let (revisions, rev_id) = RevisionLoader {
object_id: self.object_id.clone(), object_id: self.object_id.clone(),
@ -84,15 +103,16 @@ impl RevisionManager {
Ok(()) Ok(())
} }
#[tracing::instrument(level = "debug", skip(self, revision))] #[tracing::instrument(level = "debug", skip_all, err)]
pub async fn add_local_revision<C>(&self, revision: &Revision) -> Result<(), FlowyError> pub async fn add_local_revision<'a>(
where &'a self,
C: RevisionCompact, revision: &Revision,
{ compactor: Box<dyn RevisionCompactor + 'a>,
) -> Result<(), FlowyError> {
if revision.delta_data.is_empty() { if revision.delta_data.is_empty() {
return Err(FlowyError::internal().context("Delta data should be 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); self.rev_id_counter.set(rev_id);
Ok(()) Ok(())
} }

View File

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

View File

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

View File

@ -1,9 +1,13 @@
use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::entities::revision::{md5, RepeatedRevision, Revision};
use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::errors::{internal_error, CollaborateError, CollaborateResult};
use crate::util::{cal_diff, make_delta_from_revisions}; use crate::util::{cal_diff, make_delta_from_revisions};
use flowy_grid_data_model::entities::{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_infra::uuid;
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
pub type GridDelta = PlainTextDelta; pub type GridDelta = PlainTextDelta;
@ -31,13 +35,6 @@ impl GridMetaPad {
Self::from_delta(grid_delta) 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>> { pub fn create_field(&mut self, field: Field) -> CollaborateResult<Option<GridChange>> {
self.modify_grid(|grid| { self.modify_grid(|grid| {
grid.fields.push(field); 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>> { 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) { self.modify_grid(|grid| match grid.fields.iter().position(|field| field.id == field_id) {
None => Ok(None), None => Ok(None),
@ -62,30 +52,93 @@ impl GridMetaPad {
}) })
} }
pub fn md5(&self) -> String { pub fn get_fields(&self, field_orders: RepeatedFieldOrder) -> CollaborateResult<RepeatedField> {
md5(&self.delta.to_bytes()) let field_by_field_id = self
}
pub fn grid_data(&self) -> Grid {
let field_orders = self
.grid_meta .grid_meta
.fields .fields
.iter() .iter()
.map(FieldOrder::from) .map(|field| (&field.id, field))
.collect::<Vec<FieldOrder>>(); .collect::<HashMap<&String, &Field>>();
// let row_orders = self let fields = field_orders
// .grid_meta .iter()
// .rows .flat_map(|field_order| match field_by_field_id.get(&field_order.field_id) {
// .iter() None => {
// .map(RowOrder::from) tracing::error!("Can't find the field with {}", field_order.field_id);
// .collect::<Vec<RowOrder>>(); None
Grid {
id: "".to_string(),
field_orders,
row_orders: vec![],
} }
Some(field) => Some((*field).clone()),
})
.collect::<Vec<Field>>();
Ok(fields.into())
}
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 { pub fn delta_str(&self) -> String {
@ -96,7 +149,7 @@ impl GridMetaPad {
&self.grid_meta.fields &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 where
F: FnOnce(&mut GridMeta) -> CollaborateResult<Option<()>>, 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> { 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 flowy_derive::ProtoBuf;
use std::collections::HashMap; use std::collections::HashMap;
pub const DEFAULT_ROW_HEIGHT: i32 = 36;
pub const DEFAULT_FIELD_WIDTH: i32 = 150;
#[derive(Debug, Clone, Default, ProtoBuf)] #[derive(Debug, Clone, Default, ProtoBuf)]
pub struct Grid { pub struct Grid {
#[pb(index = 1)] #[pb(index = 1)]

View File

@ -15,11 +15,11 @@ pub struct GridMeta {
pub fields: Vec<Field>, pub fields: Vec<Field>,
#[pb(index = 3)] #[pb(index = 3)]
pub blocks: Vec<Block>, pub blocks: Vec<GridBlock>,
} }
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)] #[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct Block { pub struct GridBlock {
#[pb(index = 1)] #[pb(index = 1)]
pub id: String, pub id: String,
@ -30,8 +30,14 @@ pub struct Block {
pub row_count: i32, 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)] #[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf)]
pub struct BlockMeta { pub struct GridBlockMeta {
#[pb(index = 1)] #[pb(index = 1)]
pub block_id: String, 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)] #[derive(Debug, Default, ProtoBuf)]
pub struct RepeatedField { pub struct RepeatedField {
#[pb(index = 1)] #[pb(index = 1)]
@ -191,7 +224,7 @@ pub struct RowMeta {
} }
impl 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 let cell_by_field_id = cells
.into_iter() .into_iter()
.map(|cell| (cell.id.clone(), cell)) .map(|cell| (cell.id.clone(), cell))
@ -199,7 +232,7 @@ impl RowMeta {
Self { Self {
id: id.to_owned(), id: id.to_owned(),
block_id: grid_id.to_owned(), block_id: block_id.to_owned(),
cell_by_field_id, cell_by_field_id,
height: DEFAULT_ROW_HEIGHT, height: DEFAULT_ROW_HEIGHT,
visibility: true, visibility: true,

View File

@ -28,7 +28,7 @@ pub struct GridMeta {
// message fields // message fields
pub grid_id: ::std::string::String, pub grid_id: ::std::string::String,
pub fields: ::protobuf::RepeatedField<Field>, pub fields: ::protobuf::RepeatedField<Field>,
pub blocks: ::protobuf::RepeatedField<Block>, pub blocks: ::protobuf::RepeatedField<GridBlock>,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -96,10 +96,10 @@ impl GridMeta {
::std::mem::replace(&mut self.fields, ::protobuf::RepeatedField::new()) ::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 &self.blocks
} }
pub fn clear_blocks(&mut self) { pub fn clear_blocks(&mut self) {
@ -107,17 +107,17 @@ impl GridMeta {
} }
// Param is passed by value, moved // 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; self.blocks = v;
} }
// Mutable pointer to the field. // 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 &mut self.blocks
} }
// Take field // 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()) ::std::mem::replace(&mut self.blocks, ::protobuf::RepeatedField::new())
} }
} }
@ -240,7 +240,7 @@ impl ::protobuf::Message for GridMeta {
|m: &GridMeta| { &m.fields }, |m: &GridMeta| { &m.fields },
|m: &mut GridMeta| { &mut 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", "blocks",
|m: &GridMeta| { &m.blocks }, |m: &GridMeta| { &m.blocks },
|m: &mut GridMeta| { &mut m.blocks }, |m: &mut GridMeta| { &mut m.blocks },
@ -281,7 +281,7 @@ impl ::protobuf::reflect::ProtobufValue for GridMeta {
} }
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct Block { pub struct GridBlock {
// message fields // message fields
pub id: ::std::string::String, pub id: ::std::string::String,
pub start_row_index: i32, pub start_row_index: i32,
@ -291,14 +291,14 @@ pub struct Block {
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
} }
impl<'a> ::std::default::Default for &'a Block { impl<'a> ::std::default::Default for &'a GridBlock {
fn default() -> &'a Block { fn default() -> &'a GridBlock {
<Block as ::protobuf::Message>::default_instance() <GridBlock as ::protobuf::Message>::default_instance()
} }
} }
impl Block { impl GridBlock {
pub fn new() -> Block { pub fn new() -> GridBlock {
::std::default::Default::default() ::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 { fn is_initialized(&self) -> bool {
true true
} }
@ -451,8 +451,8 @@ impl ::protobuf::Message for Block {
Self::descriptor_static() Self::descriptor_static()
} }
fn new() -> Block { fn new() -> GridBlock {
Block::new() GridBlock::new()
} }
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -461,34 +461,34 @@ impl ::protobuf::Message for Block {
let mut fields = ::std::vec::Vec::new(); let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"id", "id",
|m: &Block| { &m.id }, |m: &GridBlock| { &m.id },
|m: &mut Block| { &mut m.id }, |m: &mut GridBlock| { &mut m.id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"start_row_index", "start_row_index",
|m: &Block| { &m.start_row_index }, |m: &GridBlock| { &m.start_row_index },
|m: &mut Block| { &mut m.start_row_index }, |m: &mut GridBlock| { &mut m.start_row_index },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"row_count", "row_count",
|m: &Block| { &m.row_count }, |m: &GridBlock| { &m.row_count },
|m: &mut Block| { &mut m.row_count }, |m: &mut GridBlock| { &mut m.row_count },
)); ));
::protobuf::reflect::MessageDescriptor::new_pb_name::<Block>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlock>(
"Block", "GridBlock",
fields, fields,
file_descriptor_proto() file_descriptor_proto()
) )
}) })
} }
fn default_instance() -> &'static Block { fn default_instance() -> &'static GridBlock {
static instance: ::protobuf::rt::LazyV2<Block> = ::protobuf::rt::LazyV2::INIT; static instance: ::protobuf::rt::LazyV2<GridBlock> = ::protobuf::rt::LazyV2::INIT;
instance.get(Block::new) instance.get(GridBlock::new)
} }
} }
impl ::protobuf::Clear for Block { impl ::protobuf::Clear for GridBlock {
fn clear(&mut self) { fn clear(&mut self) {
self.id.clear(); self.id.clear();
self.start_row_index = 0; 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 { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f) ::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 { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self) ::protobuf::reflect::ReflectValueRef::Message(self)
} }
} }
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct BlockMeta { pub struct GridBlockMeta {
// message fields // message fields
pub block_id: ::std::string::String, pub block_id: ::std::string::String,
pub rows: ::protobuf::RepeatedField<RowMeta>, pub rows: ::protobuf::RepeatedField<RowMeta>,
@ -519,14 +519,14 @@ pub struct BlockMeta {
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
} }
impl<'a> ::std::default::Default for &'a BlockMeta { impl<'a> ::std::default::Default for &'a GridBlockMeta {
fn default() -> &'a BlockMeta { fn default() -> &'a GridBlockMeta {
<BlockMeta as ::protobuf::Message>::default_instance() <GridBlockMeta as ::protobuf::Message>::default_instance()
} }
} }
impl BlockMeta { impl GridBlockMeta {
pub fn new() -> BlockMeta { pub fn new() -> GridBlockMeta {
::std::default::Default::default() ::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 { fn is_initialized(&self) -> bool {
for v in &self.rows { for v in &self.rows {
if !v.is_initialized() { if !v.is_initialized() {
@ -665,8 +665,8 @@ impl ::protobuf::Message for BlockMeta {
Self::descriptor_static() Self::descriptor_static()
} }
fn new() -> BlockMeta { fn new() -> GridBlockMeta {
BlockMeta::new() GridBlockMeta::new()
} }
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -675,29 +675,29 @@ impl ::protobuf::Message for BlockMeta {
let mut fields = ::std::vec::Vec::new(); let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"block_id", "block_id",
|m: &BlockMeta| { &m.block_id }, |m: &GridBlockMeta| { &m.block_id },
|m: &mut BlockMeta| { &mut m.block_id }, |m: &mut GridBlockMeta| { &mut m.block_id },
)); ));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowMeta>>( fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowMeta>>(
"rows", "rows",
|m: &BlockMeta| { &m.rows }, |m: &GridBlockMeta| { &m.rows },
|m: &mut BlockMeta| { &mut m.rows }, |m: &mut GridBlockMeta| { &mut m.rows },
)); ));
::protobuf::reflect::MessageDescriptor::new_pb_name::<BlockMeta>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlockMeta>(
"BlockMeta", "GridBlockMeta",
fields, fields,
file_descriptor_proto() file_descriptor_proto()
) )
}) })
} }
fn default_instance() -> &'static BlockMeta { fn default_instance() -> &'static GridBlockMeta {
static instance: ::protobuf::rt::LazyV2<BlockMeta> = ::protobuf::rt::LazyV2::INIT; static instance: ::protobuf::rt::LazyV2<GridBlockMeta> = ::protobuf::rt::LazyV2::INIT;
instance.get(BlockMeta::new) instance.get(GridBlockMeta::new)
} }
} }
impl ::protobuf::Clear for BlockMeta { impl ::protobuf::Clear for GridBlockMeta {
fn clear(&mut self) { fn clear(&mut self) {
self.block_id.clear(); self.block_id.clear();
self.rows.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 { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f) ::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 { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self) ::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)] #[derive(PartialEq,Clone,Default)]
pub struct AnyData { pub struct AnyData {
// message fields // message fields
@ -2537,43 +3176,53 @@ impl ::protobuf::reflect::ProtobufValue for FieldType {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ 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\ \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\ s\x12\"\n\x06blocks\x18\x03\x20\x03(\x0b2\n.GridBlockR\x06blocks\"`\n\tG\
\x05Block\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12&\n\x0fstart_row_\ ridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12&\n\x0fstart_row_i\
index\x18\x02\x20\x01(\x05R\rstartRowIndex\x12\x1b\n\trow_count\x18\x03\ ndex\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(\x05R\x08rowCount\"H\n\rGridBlockMeta\x12\x19\n\x08block_id\x18\
\x20\x01(\tR\x07blockId\x12\x1c\n\x04rows\x18\x02\x20\x03(\x0b2\x08.RowM\ \x01\x20\x01(\tR\x07blockId\x12\x1c\n\x04rows\x18\x02\x20\x03(\x0b2\x08.\
etaR\x04rows\"\xe5\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\ RowMetaR\x04rows\"\xe5\x01\n\x05Field\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04desc\ 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.\ \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\ 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\ 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\ 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\ \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\ items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"\x87\x03\n\x0eFieldChan\
\n\x07type_id\x18\x01\x20\x01(\tR\x06typeId\x12\x14\n\x05value\x18\x02\ geset\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x14\n\x04\
\x20\x01(\x0cR\x05value\"\xff\x01\n\x07RowMeta\x12\x0e\n\x02id\x18\x01\ name\x18\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\x01(\t\
\x20\x01(\tR\x02id\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\ H\x01R\x04desc\x12+\n\nfield_type\x18\x04\x20\x01(\x0e2\n.FieldTypeH\x02\
\x12D\n\x10cell_by_field_id\x18\x03\x20\x03(\x0b2\x1b.RowMeta.CellByFiel\ R\tfieldType\x12\x18\n\x06frozen\x18\x05\x20\x01(\x08H\x03R\x06frozen\
dIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x04\x20\x01(\x05R\x06he\ \x12\x20\n\nvisibility\x18\x06\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\
ight\x12\x1e\n\nvisibility\x18\x05\x20\x01(\x08R\nvisibility\x1aK\n\x12C\ \x05width\x18\x07\x20\x01(\x05H\x05R\x05width\x12-\n\x0ctype_options\x18\
ellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1f\n\ \x08\x20\x01(\x0b2\x08.AnyDataH\x06R\x0btypeOptionsB\r\n\x0bone_of_nameB\
\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05value:\x028\x01\"\xa7\x02\ \r\n\x0bone_of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\
\n\x10RowMetaChangeset\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\ \x13\n\x11one_of_visibilityB\x0e\n\x0cone_of_widthB\x15\n\x13one_of_type\
\x12\x18\n\x06height\x18\x02\x20\x01(\x05H\0R\x06height\x12\x20\n\nvisib\ _options\"8\n\x07AnyData\x12\x17\n\x07type_id\x18\x01\x20\x01(\tR\x06typ\
ility\x18\x03\x20\x01(\x08H\x01R\nvisibility\x12M\n\x10cell_by_field_id\ eId\x12\x14\n\x05value\x18\x02\x20\x01(\x0cR\x05value\"\xff\x01\n\x07Row\
\x18\x04\x20\x03(\x0b2$.RowMetaChangeset.CellByFieldIdEntryR\rcellByFiel\ Meta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x19\n\x08block_id\x18\
dId\x1aK\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\ \x02\x20\x01(\tR\x07blockId\x12D\n\x10cell_by_field_id\x18\x03\x20\x03(\
\x03key\x12\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\x05value:\ \x0b2\x1b.RowMeta.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\
\x028\x01B\x0f\n\rone_of_heightB\x13\n\x11one_of_visibility\"\x82\x01\n\ \x18\x04\x20\x01(\x05R\x06height\x12\x1e\n\nvisibility\x18\x05\x20\x01(\
\x08CellMeta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x15\n\x06row_\ \x08R\nvisibility\x1aK\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\
id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\t\ \x20\x01(\tR\x03key\x12\x1f\n\x05value\x18\x02\x20\x01(\x0b2\t.CellMetaR\
R\x07fieldId\x12\x1c\n\x04data\x18\x04\x20\x01(\x0b2\x08.AnyDataR\x04dat\ \x05value:\x028\x01\"\xa7\x02\n\x10RowMetaChangeset\x12\x15\n\x06row_id\
a\x12\x16\n\x06height\x18\x05\x20\x01(\x05R\x06height*d\n\tFieldType\x12\ \x18\x01\x20\x01(\tR\x05rowId\x12\x18\n\x06height\x18\x02\x20\x01(\x05H\
\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\ \0R\x06height\x12\x20\n\nvisibility\x18\x03\x20\x01(\x08H\x01R\nvisibili\
\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\ ty\x12M\n\x10cell_by_field_id\x18\x04\x20\x03(\x0b2$.RowMetaChangeset.Ce\
\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ 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; 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 { message GridMeta {
string grid_id = 1; string grid_id = 1;
repeated Field fields = 2; repeated Field fields = 2;
repeated Block blocks = 3; repeated GridBlock blocks = 3;
} }
message Block { message GridBlock {
string id = 1; string id = 1;
int32 start_row_index = 2; int32 start_row_index = 2;
int32 row_count = 3; int32 row_count = 3;
} }
message BlockMeta { message GridBlockMeta {
string block_id = 1; string block_id = 1;
repeated RowMeta rows = 2; repeated RowMeta rows = 2;
} }
@ -27,6 +27,16 @@ message Field {
message RepeatedField { message RepeatedField {
repeated Field items = 1; 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 { message AnyData {
string type_id = 1; string type_id = 1;
bytes value = 2; bytes value = 2;