remove notify from edit context

This commit is contained in:
appflowy
2021-09-26 16:39:57 +08:00
parent 9175efa4c6
commit 77313ab431
51 changed files with 1120 additions and 715 deletions

View File

@ -30,8 +30,8 @@ class DocBloc extends Bloc<DocEvent, DocState> {
(doc) { (doc) {
final flowyDoc = FlowyDoc( final flowyDoc = FlowyDoc(
doc: doc, doc: doc,
data: _decodeToDocument( data: _decodeJsonToDocument(
Uint8List.fromList(doc.data), doc.data,
), ),
iDocImpl: iDocImpl); iDocImpl: iDocImpl);
return DocState.loadDoc(flowyDoc); return DocState.loadDoc(flowyDoc);
@ -42,11 +42,17 @@ class DocBloc extends Bloc<DocEvent, DocState> {
); );
} }
Document _decodeToDocument(Uint8List data) { Document _decodeListToDocument(Uint8List data) {
final json = jsonDecode(utf8.decode(data)); final json = jsonDecode(utf8.decode(data));
final document = Document.fromJson(json); final document = Document.fromJson(json);
return document; return document;
} }
Document _decodeJsonToDocument(String data) {
final json = jsonDecode(data);
final document = Document.fromJson(json);
return document;
}
} }
@freezed @freezed

View File

@ -26,7 +26,7 @@ class FlowyDoc implements EditorDeltaSender {
result.fold((rustDoc) { result.fold((rustDoc) {
// final json = utf8.decode(doc.data); // final json = utf8.decode(doc.data);
final rustDelta = Delta.fromJson(jsonDecode(utf8.decode(rustDoc.data))); final rustDelta = Delta.fromJson(jsonDecode(rustDoc.data));
if (delta != rustDelta) { if (delta != rustDelta) {
Log.error("Receive : $rustDelta"); Log.error("Receive : $rustDelta");
@ -41,6 +41,6 @@ class FlowyDoc implements EditorDeltaSender {
abstract class IDoc { abstract class IDoc {
Future<Either<Doc, WorkspaceError>> readDoc(); Future<Either<Doc, WorkspaceError>> readDoc();
Future<Either<Doc, WorkspaceError>> applyChangeset({String? json}); Future<Either<Doc, WorkspaceError>> applyChangeset({required String json});
Future<Either<Unit, WorkspaceError>> closeDoc(); Future<Either<Unit, WorkspaceError>> closeDoc();
} }

View File

@ -24,12 +24,13 @@ class IDocImpl extends IDoc {
} }
@override @override
Future<Either<Doc, WorkspaceError>> applyChangeset({String? json}) { Future<Either<Doc, WorkspaceError>> applyChangeset({required String json}) {
return repo.applyChangeset(data: _encodeText(json)); return repo.applyDelta(data: json);
} }
} }
Uint8List _encodeText(String? json) { // ignore: unused_element
Uint8List _encodeJsonText(String? json) {
final data = utf8.encode(json ?? ""); final data = utf8.encode(json ?? "");
return Uint8List.fromList(data); return Uint8List.fromList(data);
} }

View File

@ -18,8 +18,7 @@ class DocRepository {
return WorkspaceEventOpenView(request).send(); return WorkspaceEventOpenView(request).send();
} }
Future<Either<Doc, WorkspaceError>> applyChangeset( Future<Either<Doc, WorkspaceError>> applyDelta({required String data}) {
{required Uint8List data}) {
final request = DocDelta.create() final request = DocDelta.create()
..docId = docId ..docId = docId
..data = data; ..data = data;

View File

@ -13,14 +13,14 @@ import 'package:protobuf/protobuf.dart' as $pb;
class CreateDocParams extends $pb.GeneratedMessage { class CreateDocParams extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateDocParams', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateDocParams', 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.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
CreateDocParams._() : super(); CreateDocParams._() : super();
factory CreateDocParams({ factory CreateDocParams({
$core.String? id, $core.String? id,
$core.List<$core.int>? data, $core.String? data,
}) { }) {
final _result = create(); final _result = create();
if (id != null) { if (id != null) {
@ -62,9 +62,9 @@ class CreateDocParams extends $pb.GeneratedMessage {
void clearId() => clearField(1); void clearId() => clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.List<$core.int> get data => $_getN(1); $core.String get data => $_getSZ(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set data($core.List<$core.int> v) { $_setBytes(1, v); } set data($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasData() => $_has(1); $core.bool hasData() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
@ -74,7 +74,7 @@ class CreateDocParams extends $pb.GeneratedMessage {
class Doc extends $pb.GeneratedMessage { class Doc extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Doc', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Doc', 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.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId') ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -82,7 +82,7 @@ class Doc extends $pb.GeneratedMessage {
Doc._() : super(); Doc._() : super();
factory Doc({ factory Doc({
$core.String? id, $core.String? id,
$core.List<$core.int>? data, $core.String? data,
$fixnum.Int64? revId, $fixnum.Int64? revId,
}) { }) {
final _result = create(); final _result = create();
@ -128,9 +128,9 @@ class Doc extends $pb.GeneratedMessage {
void clearId() => clearField(1); void clearId() => clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.List<$core.int> get data => $_getN(1); $core.String get data => $_getSZ(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set data($core.List<$core.int> v) { $_setBytes(1, v); } set data($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasData() => $_has(1); $core.bool hasData() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
@ -149,7 +149,7 @@ class Doc extends $pb.GeneratedMessage {
class UpdateDocParams extends $pb.GeneratedMessage { class UpdateDocParams extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateDocParams', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateDocParams', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId') ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId') ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'revId')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -157,7 +157,7 @@ class UpdateDocParams extends $pb.GeneratedMessage {
UpdateDocParams._() : super(); UpdateDocParams._() : super();
factory UpdateDocParams({ factory UpdateDocParams({
$core.String? docId, $core.String? docId,
$core.List<$core.int>? data, $core.String? data,
$fixnum.Int64? revId, $fixnum.Int64? revId,
}) { }) {
final _result = create(); final _result = create();
@ -203,9 +203,9 @@ class UpdateDocParams extends $pb.GeneratedMessage {
void clearDocId() => clearField(1); void clearDocId() => clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.List<$core.int> get data => $_getN(1); $core.String get data => $_getSZ(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set data($core.List<$core.int> v) { $_setBytes(1, v); } set data($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasData() => $_has(1); $core.bool hasData() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
@ -224,14 +224,14 @@ class UpdateDocParams extends $pb.GeneratedMessage {
class DocDelta extends $pb.GeneratedMessage { class DocDelta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocDelta', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocDelta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId') ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
DocDelta._() : super(); DocDelta._() : super();
factory DocDelta({ factory DocDelta({
$core.String? docId, $core.String? docId,
$core.List<$core.int>? data, $core.String? data,
}) { }) {
final _result = create(); final _result = create();
if (docId != null) { if (docId != null) {
@ -273,9 +273,9 @@ class DocDelta extends $pb.GeneratedMessage {
void clearDocId() => clearField(1); void clearDocId() => clearField(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.List<$core.int> get data => $_getN(1); $core.String get data => $_getSZ(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)
set data($core.List<$core.int> v) { $_setBytes(1, v); } set data($core.String v) { $_setString(1, v); }
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.bool hasData() => $_has(1); $core.bool hasData() => $_has(1);
@$pb.TagNumber(2) @$pb.TagNumber(2)

View File

@ -13,47 +13,47 @@ const CreateDocParams$json = const {
'1': 'CreateDocParams', '1': 'CreateDocParams',
'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': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'}, const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
], ],
}; };
/// Descriptor for `CreateDocParams`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `CreateDocParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List createDocParamsDescriptor = $convert.base64Decode('Cg9DcmVhdGVEb2NQYXJhbXMSDgoCaWQYASABKAlSAmlkEhIKBGRhdGEYAiABKAxSBGRhdGE='); final $typed_data.Uint8List createDocParamsDescriptor = $convert.base64Decode('Cg9DcmVhdGVEb2NQYXJhbXMSDgoCaWQYASABKAlSAmlkEhIKBGRhdGEYAiABKAlSBGRhdGE=');
@$core.Deprecated('Use docDescriptor instead') @$core.Deprecated('Use docDescriptor instead')
const Doc$json = const { const Doc$json = const {
'1': 'Doc', '1': 'Doc',
'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': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'}, const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'}, const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'},
], ],
}; };
/// Descriptor for `Doc`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `Doc`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List docDescriptor = $convert.base64Decode('CgNEb2MSDgoCaWQYASABKAlSAmlkEhIKBGRhdGEYAiABKAxSBGRhdGESFQoGcmV2X2lkGAMgASgDUgVyZXZJZA=='); final $typed_data.Uint8List docDescriptor = $convert.base64Decode('CgNEb2MSDgoCaWQYASABKAlSAmlkEhIKBGRhdGEYAiABKAlSBGRhdGESFQoGcmV2X2lkGAMgASgDUgVyZXZJZA==');
@$core.Deprecated('Use updateDocParamsDescriptor instead') @$core.Deprecated('Use updateDocParamsDescriptor instead')
const UpdateDocParams$json = const { const UpdateDocParams$json = const {
'1': 'UpdateDocParams', '1': 'UpdateDocParams',
'2': const [ '2': const [
const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'}, const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'}, const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'}, const {'1': 'rev_id', '3': 3, '4': 1, '5': 3, '10': 'revId'},
], ],
}; };
/// Descriptor for `UpdateDocParams`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `UpdateDocParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List updateDocParamsDescriptor = $convert.base64Decode('Cg9VcGRhdGVEb2NQYXJhbXMSFQoGZG9jX2lkGAEgASgJUgVkb2NJZBISCgRkYXRhGAIgASgMUgRkYXRhEhUKBnJldl9pZBgDIAEoA1IFcmV2SWQ='); final $typed_data.Uint8List updateDocParamsDescriptor = $convert.base64Decode('Cg9VcGRhdGVEb2NQYXJhbXMSFQoGZG9jX2lkGAEgASgJUgVkb2NJZBISCgRkYXRhGAIgASgJUgRkYXRhEhUKBnJldl9pZBgDIAEoA1IFcmV2SWQ=');
@$core.Deprecated('Use docDeltaDescriptor instead') @$core.Deprecated('Use docDeltaDescriptor instead')
const DocDelta$json = const { const DocDelta$json = const {
'1': 'DocDelta', '1': 'DocDelta',
'2': const [ '2': const [
const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'}, const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'}, const {'1': 'data', '3': 2, '4': 1, '5': 9, '10': 'data'},
], ],
}; };
/// Descriptor for `DocDelta`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `DocDelta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List docDeltaDescriptor = $convert.base64Decode('CghEb2NEZWx0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEhIKBGRhdGEYAiABKAxSBGRhdGE='); final $typed_data.Uint8List docDeltaDescriptor = $convert.base64Decode('CghEb2NEZWx0YRIVCgZkb2NfaWQYASABKAlSBWRvY0lkEhIKBGRhdGEYAiABKAlSBGRhdGE=');
@$core.Deprecated('Use queryDocParamsDescriptor instead') @$core.Deprecated('Use queryDocParamsDescriptor instead')
const QueryDocParams$json = const { const QueryDocParams$json = const {
'1': 'QueryDocParams', '1': 'QueryDocParams',

View File

@ -10,6 +10,10 @@ import 'dart:core' as $core;
import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:protobuf/protobuf.dart' as $pb; import 'package:protobuf/protobuf.dart' as $pb;
import 'revision.pbenum.dart';
export 'revision.pbenum.dart';
class Revision extends $pb.GeneratedMessage { class Revision extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Revision', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Revision', createEmptyInstance: create)
..aInt64(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'baseRevId') ..aInt64(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'baseRevId')
@ -17,6 +21,7 @@ class Revision extends $pb.GeneratedMessage {
..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'delta', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'delta', $pb.PbFieldType.OY)
..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'md5') ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'md5')
..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId') ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
..e<RevType>(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: RevType.Local, valueOf: RevType.valueOf, enumValues: RevType.values)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -27,6 +32,7 @@ class Revision extends $pb.GeneratedMessage {
$core.List<$core.int>? delta, $core.List<$core.int>? delta,
$core.String? md5, $core.String? md5,
$core.String? docId, $core.String? docId,
RevType? ty,
}) { }) {
final _result = create(); final _result = create();
if (baseRevId != null) { if (baseRevId != null) {
@ -44,6 +50,9 @@ class Revision extends $pb.GeneratedMessage {
if (docId != null) { if (docId != null) {
_result.docId = docId; _result.docId = docId;
} }
if (ty != null) {
_result.ty = ty;
}
return _result; return _result;
} }
factory Revision.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Revision.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@ -111,5 +120,14 @@ class Revision extends $pb.GeneratedMessage {
$core.bool hasDocId() => $_has(4); $core.bool hasDocId() => $_has(4);
@$pb.TagNumber(5) @$pb.TagNumber(5)
void clearDocId() => clearField(5); void clearDocId() => clearField(5);
@$pb.TagNumber(6)
RevType get ty => $_getN(5);
@$pb.TagNumber(6)
set ty(RevType v) { setField(6, v); }
@$pb.TagNumber(6)
$core.bool hasTy() => $_has(5);
@$pb.TagNumber(6)
void clearTy() => clearField(6);
} }

View File

@ -5,3 +5,22 @@
// @dart = 2.12 // @dart = 2.12
// ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
// ignore_for_file: UNDEFINED_SHOWN_NAME
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class RevType extends $pb.ProtobufEnum {
static const RevType Local = RevType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Local');
static const RevType Remote = RevType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Remote');
static const $core.List<RevType> values = <RevType> [
Local,
Remote,
];
static final $core.Map<$core.int, RevType> _byValue = $pb.ProtobufEnum.initByValue(values);
static RevType? valueOf($core.int value) => _byValue[value];
const RevType._($core.int v, $core.String n) : super(v, n);
}

View File

@ -8,6 +8,17 @@
import 'dart:core' as $core; import 'dart:core' as $core;
import 'dart:convert' as $convert; import 'dart:convert' as $convert;
import 'dart:typed_data' as $typed_data; import 'dart:typed_data' as $typed_data;
@$core.Deprecated('Use revTypeDescriptor instead')
const RevType$json = const {
'1': 'RevType',
'2': const [
const {'1': 'Local', '2': 0},
const {'1': 'Remote', '2': 1},
],
};
/// Descriptor for `RevType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List revTypeDescriptor = $convert.base64Decode('CgdSZXZUeXBlEgkKBUxvY2FsEAASCgoGUmVtb3RlEAE=');
@$core.Deprecated('Use revisionDescriptor instead') @$core.Deprecated('Use revisionDescriptor instead')
const Revision$json = const { const Revision$json = const {
'1': 'Revision', '1': 'Revision',
@ -17,8 +28,9 @@ const Revision$json = const {
const {'1': 'delta', '3': 3, '4': 1, '5': 12, '10': 'delta'}, const {'1': 'delta', '3': 3, '4': 1, '5': 12, '10': 'delta'},
const {'1': 'md5', '3': 4, '4': 1, '5': 9, '10': 'md5'}, const {'1': 'md5', '3': 4, '4': 1, '5': 9, '10': 'md5'},
const {'1': 'doc_id', '3': 5, '4': 1, '5': 9, '10': 'docId'}, const {'1': 'doc_id', '3': 5, '4': 1, '5': 9, '10': 'docId'},
const {'1': 'ty', '3': 6, '4': 1, '5': 14, '6': '.RevType', '10': 'ty'},
], ],
}; };
/// Descriptor for `Revision`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `Revision`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSFAoFZGVsdGEYAyABKAxSBWRlbHRhEhAKA21kNRgEIAEoCVIDbWQ1EhUKBmRvY19pZBgFIAEoCVIFZG9jSWQ='); final $typed_data.Uint8List revisionDescriptor = $convert.base64Decode('CghSZXZpc2lvbhIeCgtiYXNlX3Jldl9pZBgBIAEoA1IJYmFzZVJldklkEhUKBnJldl9pZBgCIAEoA1IFcmV2SWQSFAoFZGVsdGEYAyABKAxSBWRlbHRhEhAKA21kNRgEIAEoCVIDbWQ1EhUKBmRvY19pZBgFIAEoCVIFZG9jSWQSGAoCdHkYBiABKA4yCC5SZXZUeXBlUgJ0eQ==');

View File

@ -137,7 +137,7 @@ class CreateViewParams extends $pb.GeneratedMessage {
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc') ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'desc')
..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail') ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'thumbnail')
..e<ViewType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewType.Blank, valueOf: ViewType.valueOf, enumValues: ViewType.values) ..e<ViewType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewType', $pb.PbFieldType.OE, defaultOrMaker: ViewType.Blank, valueOf: ViewType.valueOf, enumValues: ViewType.values)
..a<$core.List<$core.int>>(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..aOS(6, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -148,7 +148,7 @@ class CreateViewParams extends $pb.GeneratedMessage {
$core.String? desc, $core.String? desc,
$core.String? thumbnail, $core.String? thumbnail,
ViewType? viewType, ViewType? viewType,
$core.List<$core.int>? data, $core.String? data,
}) { }) {
final _result = create(); final _result = create();
if (belongToId != null) { if (belongToId != null) {
@ -238,9 +238,9 @@ class CreateViewParams extends $pb.GeneratedMessage {
void clearViewType() => clearField(5); void clearViewType() => clearField(5);
@$pb.TagNumber(6) @$pb.TagNumber(6)
$core.List<$core.int> get data => $_getN(5); $core.String get data => $_getSZ(5);
@$pb.TagNumber(6) @$pb.TagNumber(6)
set data($core.List<$core.int> v) { $_setBytes(5, v); } set data($core.String v) { $_setString(5, v); }
@$pb.TagNumber(6) @$pb.TagNumber(6)
$core.bool hasData() => $_has(5); $core.bool hasData() => $_has(5);
@$pb.TagNumber(6) @$pb.TagNumber(6)

View File

@ -45,12 +45,12 @@ const CreateViewParams$json = const {
const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'}, const {'1': 'desc', '3': 3, '4': 1, '5': 9, '10': 'desc'},
const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '10': 'thumbnail'}, const {'1': 'thumbnail', '3': 4, '4': 1, '5': 9, '10': 'thumbnail'},
const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewType', '10': 'viewType'}, const {'1': 'view_type', '3': 5, '4': 1, '5': 14, '6': '.ViewType', '10': 'viewType'},
const {'1': 'data', '3': 6, '4': 1, '5': 12, '10': 'data'}, const {'1': 'data', '3': 6, '4': 1, '5': 9, '10': 'data'},
], ],
}; };
/// Descriptor for `CreateViewParams`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `CreateViewParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSJgoJdmlld190eXBlGAUgASgOMgkuVmlld1R5cGVSCHZpZXdUeXBlEhIKBGRhdGEYBiABKAxSBGRhdGE='); final $typed_data.Uint8List createViewParamsDescriptor = $convert.base64Decode('ChBDcmVhdGVWaWV3UGFyYW1zEiAKDGJlbG9uZ190b19pZBgBIAEoCVIKYmVsb25nVG9JZBISCgRuYW1lGAIgASgJUgRuYW1lEhIKBGRlc2MYAyABKAlSBGRlc2MSHAoJdGh1bWJuYWlsGAQgASgJUgl0aHVtYm5haWwSJgoJdmlld190eXBlGAUgASgOMgkuVmlld1R5cGVSCHZpZXdUeXBlEhIKBGRhdGEYBiABKAlSBGRhdGE=');
@$core.Deprecated('Use viewDescriptor instead') @$core.Deprecated('Use viewDescriptor instead')
const View$json = const { const View$json = const {
'1': 'View', '1': 'View',

View File

@ -319,15 +319,15 @@ class UpdateViewParams extends $pb.GeneratedMessage {
void clearIsTrash() => clearField(5); void clearIsTrash() => clearField(5);
} }
class ApplyChangesetRequest extends $pb.GeneratedMessage { class DocDeltaRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ApplyChangesetRequest', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocDeltaRequest', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId') ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data', $pb.PbFieldType.OY)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
ApplyChangesetRequest._() : super(); DocDeltaRequest._() : super();
factory ApplyChangesetRequest({ factory DocDeltaRequest({
$core.String? viewId, $core.String? viewId,
$core.List<$core.int>? data, $core.List<$core.int>? data,
}) { }) {
@ -340,26 +340,26 @@ class ApplyChangesetRequest extends $pb.GeneratedMessage {
} }
return _result; return _result;
} }
factory ApplyChangesetRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory DocDeltaRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory ApplyChangesetRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); factory DocDeltaRequest.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')
ApplyChangesetRequest clone() => ApplyChangesetRequest()..mergeFromMessage(this); DocDeltaRequest clone() => DocDeltaRequest()..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')
ApplyChangesetRequest copyWith(void Function(ApplyChangesetRequest) updates) => super.copyWith((message) => updates(message as ApplyChangesetRequest)) as ApplyChangesetRequest; // ignore: deprecated_member_use DocDeltaRequest copyWith(void Function(DocDeltaRequest) updates) => super.copyWith((message) => updates(message as DocDeltaRequest)) as DocDeltaRequest; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i; $pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline') @$core.pragma('dart2js:noInline')
static ApplyChangesetRequest create() => ApplyChangesetRequest._(); static DocDeltaRequest create() => DocDeltaRequest._();
ApplyChangesetRequest createEmptyInstance() => create(); DocDeltaRequest createEmptyInstance() => create();
static $pb.PbList<ApplyChangesetRequest> createRepeated() => $pb.PbList<ApplyChangesetRequest>(); static $pb.PbList<DocDeltaRequest> createRepeated() => $pb.PbList<DocDeltaRequest>();
@$core.pragma('dart2js:noInline') @$core.pragma('dart2js:noInline')
static ApplyChangesetRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ApplyChangesetRequest>(create); static DocDeltaRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocDeltaRequest>(create);
static ApplyChangesetRequest? _defaultInstance; static DocDeltaRequest? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.String get viewId => $_getSZ(0); $core.String get viewId => $_getSZ(0);

View File

@ -48,14 +48,14 @@ const UpdateViewParams$json = const {
/// Descriptor for `UpdateViewParams`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `UpdateViewParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List updateViewParamsDescriptor = $convert.base64Decode('ChBVcGRhdGVWaWV3UGFyYW1zEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgCUgl0aHVtYm5haWwSGwoIaXNfdHJhc2gYBSABKAhIA1IHaXNUcmFzaEINCgtvbmVfb2ZfbmFtZUINCgtvbmVfb2ZfZGVzY0ISChBvbmVfb2ZfdGh1bWJuYWlsQhEKD29uZV9vZl9pc190cmFzaA=='); final $typed_data.Uint8List updateViewParamsDescriptor = $convert.base64Decode('ChBVcGRhdGVWaWV3UGFyYW1zEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgCUgl0aHVtYm5haWwSGwoIaXNfdHJhc2gYBSABKAhIA1IHaXNUcmFzaEINCgtvbmVfb2ZfbmFtZUINCgtvbmVfb2ZfZGVzY0ISChBvbmVfb2ZfdGh1bWJuYWlsQhEKD29uZV9vZl9pc190cmFzaA==');
@$core.Deprecated('Use applyChangesetRequestDescriptor instead') @$core.Deprecated('Use docDeltaRequestDescriptor instead')
const ApplyChangesetRequest$json = const { const DocDeltaRequest$json = const {
'1': 'ApplyChangesetRequest', '1': 'DocDeltaRequest',
'2': const [ '2': const [
const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'}, const {'1': 'view_id', '3': 1, '4': 1, '5': 9, '10': 'viewId'},
const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'}, const {'1': 'data', '3': 2, '4': 1, '5': 12, '10': 'data'},
], ],
}; };
/// Descriptor for `ApplyChangesetRequest`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `DocDeltaRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List applyChangesetRequestDescriptor = $convert.base64Decode('ChVBcHBseUNoYW5nZXNldFJlcXVlc3QSFwoHdmlld19pZBgBIAEoCVIGdmlld0lkEhIKBGRhdGEYAiABKAxSBGRhdGE='); final $typed_data.Uint8List docDeltaRequestDescriptor = $convert.base64Decode('Cg9Eb2NEZWx0YVJlcXVlc3QSFwoHdmlld19pZBgBIAEoCVIGdmlld0lkEhIKBGRhdGEYAiABKAxSBGRhdGE=');

View File

@ -2,6 +2,7 @@
CREATE TABLE IF NOT EXISTS doc_table( CREATE TABLE IF NOT EXISTS doc_table(
id uuid NOT NULL, id uuid NOT NULL,
PRIMARY KEY (id), PRIMARY KEY (id),
data bytea NOT NULL DEFAULT '', -- data bytea NOT NULL DEFAULT '',
data TEXT NOT NULL DEFAULT '',
rev_id bigint NOT NULL DEFAULT 0 rev_id bigint NOT NULL DEFAULT 0
); );

View File

@ -1,5 +1,5 @@
# https://rust-lang.github.io/rustfmt/?version=master&search= # https://rust-lang.github.io/rustfmt/?version=master&search=
max_width = 100 max_width = 120
tab_spaces = 4 tab_spaces = 4
fn_single_line = true fn_single_line = true
match_block_trailing_comma = true match_block_trailing_comma = true

View File

@ -5,7 +5,7 @@ pub(crate) const DOC_TABLE: &'static str = "doc_table";
#[derive(Debug, Clone, sqlx::FromRow)] #[derive(Debug, Clone, sqlx::FromRow)]
pub struct DocTable { pub struct DocTable {
pub(crate) id: uuid::Uuid, pub(crate) id: uuid::Uuid,
pub(crate) data: Vec<u8>, pub(crate) data: String,
pub(crate) rev_id: i64, pub(crate) rev_id: i64,
} }

View File

@ -4,11 +4,11 @@ use crate::service::{
ws::{entities::Socket, WsMessageAdaptor}, ws::{entities::Socket, WsMessageAdaptor},
}; };
use actix_web::web::Data; use actix_web::web::Data;
use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use byteorder::{BigEndian, WriteBytesExt};
use bytes::Bytes; use bytes::Bytes;
use flowy_document::{ use flowy_document::{
entities::ws::{WsDataType, WsDocumentData}, entities::ws::{WsDataType, WsDocumentData},
protobuf::{Doc, Revision, UpdateDocParams}, protobuf::{Doc, RevType, Revision, UpdateDocParams},
services::doc::Document, services::doc::Document,
}; };
use flowy_net::errors::{internal_error, ServerError}; use flowy_net::errors::{internal_error, ServerError};
@ -31,7 +31,7 @@ pub(crate) struct EditDocContext {
impl EditDocContext { impl EditDocContext {
pub(crate) fn new(doc: Doc, pg_pool: Data<PgPool>) -> Result<Self, ServerError> { pub(crate) fn new(doc: Doc, pg_pool: Data<PgPool>) -> Result<Self, ServerError> {
let delta = Delta::from_bytes(doc.data).map_err(internal_error)?; let delta = Delta::from_bytes(&doc.data).map_err(internal_error)?;
let document = Arc::new(RwLock::new(Document::from_delta(delta))); let document = Arc::new(RwLock::new(Document::from_delta(delta)));
Ok(Self { Ok(Self {
doc_id: doc.id.clone(), doc_id: doc.id.clone(),
@ -42,29 +42,25 @@ impl EditDocContext {
} }
#[tracing::instrument(level = "debug", skip(self, socket, revision))] #[tracing::instrument(level = "debug", skip(self, socket, revision))]
pub(crate) async fn apply_revision( pub(crate) async fn apply_revision(&self, socket: Socket, revision: Revision) -> Result<(), ServerError> {
&self,
socket: Socket,
revision: Revision,
) -> Result<(), ServerError> {
let _ = self.verify_md5(&revision)?; let _ = self.verify_md5(&revision)?;
if self.rev_id > revision.rev_id { if self.rev_id > revision.rev_id {
let (cli_prime, server_prime) = self.compose(revision.delta).map_err(internal_error)?; let (cli_prime, server_prime) = self.compose(&revision.delta).map_err(internal_error)?;
let _ = self.update_document_delta(server_prime)?; let _ = self.update_document_delta(server_prime)?;
log::debug!("{} client delta: {}", self.doc_id, cli_prime.to_json()); log::debug!("{} client delta: {}", self.doc_id, cli_prime.to_json());
let cli_revision = self.mk_revision(revision.rev_id, cli_prime); let cli_revision = self.mk_revision(revision.rev_id, cli_prime);
let ws_cli_revision = mk_ws_rev_message(&self.doc_id, cli_revision); let ws_cli_revision = mk_rev_ws_message(&self.doc_id, cli_revision);
socket.do_send(ws_cli_revision).map_err(internal_error)?; socket.do_send(ws_cli_revision).map_err(internal_error)?;
Ok(()) Ok(())
} else { } else {
let delta = Delta::from_bytes(revision.delta.clone()).map_err(internal_error)?; let delta = Delta::from_bytes(&revision.delta).map_err(internal_error)?;
let _ = self.update_document_delta(delta)?; let _ = self.update_document_delta(delta)?;
socket.do_send(mk_ws_acked_message(&revision)); socket.do_send(mk_acked_ws_message(&revision));
// Opti: save with multiple revisions // Opti: save with multiple revisions
let _ = self.save_doc_to_disk(&revision).await?; let _ = self.save_revision(&revision).await?;
Ok(()) Ok(())
} }
} }
@ -78,23 +74,20 @@ impl EditDocContext {
delta: delta_data, delta: delta_data,
md5, md5,
doc_id: self.doc_id.to_string(), doc_id: self.doc_id.to_string(),
ty: RevType::Remote,
..Default::default() ..Default::default()
}; };
revision revision
} }
#[tracing::instrument(level = "debug", skip(self, delta_data))] #[tracing::instrument(level = "debug", skip(self, delta_data))]
fn compose(&self, delta_data: Vec<u8>) -> Result<(Delta, Delta), OTError> { fn compose(&self, delta_data: &Vec<u8>) -> Result<(Delta, Delta), OTError> {
log::debug!( log::debug!("{} document data: {}", self.doc_id, self.document.read().to_json());
"{} document data: {}",
self.doc_id,
self.document.read().to_json()
);
let doc_delta = self.document.read().delta().clone(); let doc_delta = self.document.read().delta().clone();
let cli_delta = Delta::from_bytes(delta_data)?; let cli_delta = Delta::from_bytes(delta_data)?;
let (a, b) = doc_delta.transform(&cli_delta)?; let (cli_prime, server_prime) = doc_delta.transform(&cli_delta)?;
Ok((a, b)) Ok((cli_prime, server_prime))
} }
#[tracing::instrument(level = "debug", skip(self, delta))] #[tracing::instrument(level = "debug", skip(self, delta))]
@ -105,9 +98,7 @@ impl EditDocContext {
log::error!("Failed to acquire write lock of document"); log::error!("Failed to acquire write lock of document");
}, },
Some(mut write_guard) => { Some(mut write_guard) => {
let _ = write_guard let _ = write_guard.compose_delta(&delta).map_err(internal_error)?;
.apply_delta(delta.clone())
.map_err(internal_error)?;
log::debug!("Document: {}", write_guard.to_plain_string()); log::debug!("Document: {}", write_guard.to_plain_string());
}, },
@ -122,18 +113,20 @@ impl EditDocContext {
Ok(()) Ok(())
} }
async fn save_doc_to_disk(&self, revision: &Revision) -> Result<(), ServerError> { #[tracing::instrument(level = "debug", skip(self, revision))]
async fn save_revision(&self, revision: &Revision) -> Result<(), ServerError> {
let mut params = UpdateDocParams::new(); let mut params = UpdateDocParams::new();
params.set_doc_id(self.doc_id.clone()); params.set_doc_id(self.doc_id.clone());
params.set_data(self.document.read().to_bytes()); params.set_data(self.document.read().to_json());
params.set_rev_id(revision.rev_id); params.set_rev_id(revision.rev_id);
let _ = update_doc(self.pg_pool.get_ref(), params).await?; let _ = update_doc(self.pg_pool.get_ref(), params).await?;
Ok(()) Ok(())
} }
} }
fn mk_ws_rev_message(doc_id: &str, revision: Revision) -> WsMessageAdaptor { fn mk_rev_ws_message(doc_id: &str, revision: Revision) -> WsMessageAdaptor {
let bytes = revision.write_to_bytes().unwrap(); let bytes = revision.write_to_bytes().unwrap();
let data = WsDocumentData { let data = WsDocumentData {
@ -147,7 +140,7 @@ fn mk_ws_rev_message(doc_id: &str, revision: Revision) -> WsMessageAdaptor {
WsMessageAdaptor(bytes) WsMessageAdaptor(bytes)
} }
fn mk_ws_acked_message(revision: &Revision) -> WsMessageAdaptor { fn mk_acked_ws_message(revision: &Revision) -> WsMessageAdaptor {
let mut wtr = vec![]; let mut wtr = vec![];
let _ = wtr.write_i64::<BigEndian>(revision.rev_id); let _ = wtr.write_i64::<BigEndian>(revision.rev_id);

View File

@ -16,13 +16,13 @@ impl NewDocSqlBuilder {
pub fn new(id: Uuid) -> Self { pub fn new(id: Uuid) -> Self {
let table = DocTable { let table = DocTable {
id, id,
data: vec![], data: "".to_owned(),
rev_id: 0, rev_id: 0,
}; };
Self { table } Self { table }
} }
pub fn data(mut self, data: Vec<u8>) -> Self { pub fn data(mut self, data: String) -> Self {
self.table.data = data; self.table.data = data;
self self
} }

View File

@ -1,9 +1,3 @@
use flowy_net::errors::ServerError;
use flowy_workspace::{
entities::view::default_delta,
protobuf::{App, CreateViewParams, View, ViewType, Workspace},
};
use crate::{ use crate::{
service::{ service::{
app::sql_builder::NewAppSqlBuilder as AppBuilder, app::sql_builder::NewAppSqlBuilder as AppBuilder,
@ -12,6 +6,11 @@ use crate::{
}, },
sqlx_ext::{map_sqlx_error, DBTransaction}, sqlx_ext::{map_sqlx_error, DBTransaction},
}; };
use flowy_net::errors::ServerError;
use flowy_workspace::{
entities::view::VIEW_DEFAULT_DATA,
protobuf::{App, CreateViewParams, View, ViewType, Workspace},
};
pub async fn create_default_workspace( pub async fn create_default_workspace(
transaction: &mut DBTransaction<'_>, transaction: &mut DBTransaction<'_>,
@ -24,10 +23,7 @@ pub async fn create_default_workspace(
Ok(workspace) Ok(workspace)
} }
async fn create_workspace( async fn create_workspace(transaction: &mut DBTransaction<'_>, user_id: &str) -> Result<Workspace, ServerError> {
transaction: &mut DBTransaction<'_>,
user_id: &str,
) -> Result<Workspace, ServerError> {
let (sql, args, workspace) = WorkspaceBuilder::new(user_id.as_ref()) let (sql, args, workspace) = WorkspaceBuilder::new(user_id.as_ref())
.name("DefaultWorkspace") .name("DefaultWorkspace")
.desc("Workspace created by AppFlowy") .desc("Workspace created by AppFlowy")
@ -66,7 +62,7 @@ async fn create_view(transaction: &mut DBTransaction<'_>, app: &App) -> Result<V
desc: "View created by AppFlowy".to_string(), desc: "View created by AppFlowy".to_string(),
thumbnail: "123.png".to_string(), thumbnail: "123.png".to_string(),
view_type: ViewType::Doc, view_type: ViewType::Doc,
data: default_delta(), data: VIEW_DEFAULT_DATA.to_string(),
unknown_fields: Default::default(), unknown_fields: Default::default(),
cached_size: Default::default(), cached_size: Default::default(),
}; };

View File

@ -1,6 +1,7 @@
-- Your SQL goes here -- Your SQL goes here
CREATE TABLE doc_table ( CREATE TABLE doc_table (
id TEXT NOT NULL PRIMARY KEY, id TEXT NOT NULL PRIMARY KEY,
data BLOB NOT NULL DEFAULT (x''), -- data BLOB NOT NULL DEFAULT (x''),
data TEXT NOT NULL DEFAULT '',
revision BIGINT NOT NULL DEFAULT 0 revision BIGINT NOT NULL DEFAULT 0
); );

View File

@ -1,9 +1,10 @@
-- Your SQL goes here -- Your SQL goes here
CREATE TABLE op_table ( CREATE TABLE rev_table (
doc_id TEXT NOT NULL PRIMARY KEY, doc_id TEXT NOT NULL PRIMARY KEY,
base_rev_id BIGINT NOT NULL DEFAULT 0, base_rev_id BIGINT NOT NULL DEFAULT 0,
rev_id BIGINT NOT NULL DEFAULT 0, rev_id BIGINT NOT NULL DEFAULT 0,
data BLOB NOT NULL DEFAULT (x''), data BLOB NOT NULL DEFAULT (x''),
md5 TEXT NOT NULL DEFAULT '', md5 TEXT NOT NULL DEFAULT '',
state INTEGER NOT NULL DEFAULT 0 state INTEGER NOT NULL DEFAULT 0,
ty INTEGER NOT NULL DEFAULT 0
); );

View File

@ -112,13 +112,18 @@ macro_rules! impl_sql_binary_expression {
*const [u8]: diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>, *const [u8]: diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>,
{ {
fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> { fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
let slice_ptr = <*const [u8] as diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>>::from_sql(bytes)?; let slice_ptr =
<*const [u8] as diesel::deserialize::FromSql<diesel::sql_types::Binary, DB>>::from_sql(bytes)?;
let bytes = unsafe { &*slice_ptr }; let bytes = unsafe { &*slice_ptr };
match $target::try_from(bytes) { match $target::try_from(bytes) {
Ok(object) => Ok(object), Ok(object) => Ok(object),
Err(e) => { Err(e) => {
log::error!("{:?} deserialize from bytes fail. {:?}", std::any::type_name::<$target>(), e); log::error!(
"{:?} deserialize from bytes fail. {:?}",
std::any::type_name::<$target>(),
e
);
panic!(); panic!();
}, },
} }
@ -130,28 +135,25 @@ macro_rules! impl_sql_binary_expression {
#[macro_export] #[macro_export]
macro_rules! impl_sql_integer_expression { macro_rules! impl_sql_integer_expression {
($target:ident) => { ($target:ident) => {
use diesel::{ impl<DB> diesel::serialize::ToSql<Integer, DB> for $target
deserialize,
deserialize::FromSql,
serialize,
serialize::{Output, ToSql},
};
use std::io::Write;
impl<DB> ToSql<Integer, DB> for $target
where where
DB: diesel::backend::Backend, DB: diesel::backend::Backend,
i32: ToSql<Integer, DB>, i32: diesel::serialize::ToSql<Integer, DB>,
{ {
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result { (*self as i32).to_sql(out) } fn to_sql<W: std::io::Write>(
&self,
out: &mut diesel::serialize::Output<W, DB>,
) -> diesel::serialize::Result {
(*self as i32).to_sql(out)
}
} }
impl<DB> FromSql<Integer, DB> for $target impl<DB> diesel::deserialize::FromSql<Integer, DB> for $target
where where
DB: diesel::backend::Backend, DB: diesel::backend::Backend,
i32: FromSql<Integer, DB>, i32: diesel::deserialize::FromSql<Integer, DB>,
{ {
fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> { fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
let smaill_int = i32::from_sql(bytes)?; let smaill_int = i32::from_sql(bytes)?;
Ok($target::from(smaill_int)) Ok($target::from(smaill_int))
} }

View File

@ -16,19 +16,20 @@ table! {
table! { table! {
doc_table (id) { doc_table (id) {
id -> Text, id -> Text,
data -> Binary, data -> Text,
revision -> BigInt, revision -> BigInt,
} }
} }
table! { table! {
op_table (doc_id) { rev_table (doc_id) {
doc_id -> Text, doc_id -> Text,
base_rev_id -> BigInt, base_rev_id -> BigInt,
rev_id -> BigInt, rev_id -> BigInt,
data -> Binary, data -> Binary,
md5 -> Text, md5 -> Text,
state -> Integer, state -> Integer,
ty -> Integer,
} }
} }
@ -72,7 +73,7 @@ table! {
allow_tables_to_appear_in_same_query!( allow_tables_to_appear_in_same_query!(
app_table, app_table,
doc_table, doc_table,
op_table, rev_table,
user_table, user_table,
view_table, view_table,
workspace_table, workspace_table,

View File

@ -41,7 +41,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "CurrentWorkspace" | "CurrentWorkspace"
| "UpdateViewRequest" | "UpdateViewRequest"
| "UpdateViewParams" | "UpdateViewParams"
| "ApplyChangesetRequest" | "DocDeltaRequest"
| "DeleteViewRequest" | "DeleteViewRequest"
| "DeleteViewParams" | "DeleteViewParams"
| "QueryViewRequest" | "QueryViewRequest"
@ -81,6 +81,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "ErrorCode" | "ErrorCode"
| "WorkspaceObservable" | "WorkspaceObservable"
| "WsModule" | "WsModule"
| "RevType"
| "WsDataType" | "WsDataType"
| "DocObservable" | "DocObservable"
| "FFIStatusCode" | "FFIStatusCode"

View File

@ -6,11 +6,16 @@ pub struct CreateDocParams {
pub id: String, pub id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub data: Vec<u8>, pub data: String,
} }
impl CreateDocParams { impl CreateDocParams {
pub fn new(id: &str, data: Vec<u8>) -> Self { Self { id: id.to_owned(), data } } pub fn new(id: &str, data: String) -> Self {
Self {
id: id.to_owned(),
data,
}
}
} }
#[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)] #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)]
@ -19,7 +24,7 @@ pub struct Doc {
pub id: String, pub id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub data: Vec<u8>, pub data: String,
#[pb(index = 3)] #[pb(index = 3)]
pub rev_id: i64, pub rev_id: i64,
@ -31,7 +36,7 @@ pub struct UpdateDocParams {
pub doc_id: String, pub doc_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub data: Vec<u8>, pub data: String,
#[pb(index = 3)] #[pb(index = 3)]
pub rev_id: i64, pub rev_id: i64,
@ -43,7 +48,7 @@ pub struct DocDelta {
pub doc_id: String, pub doc_id: String,
#[pb(index = 2)] #[pb(index = 2)]
pub data: Vec<u8>, // Delta pub data: String, // Delta
} }
#[derive(ProtoBuf, Default, Debug, Clone)] #[derive(ProtoBuf, Default, Debug, Clone)]

View File

@ -1,4 +1,14 @@
use flowy_derive::ProtoBuf; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
#[derive(Debug, ProtoBuf_Enum, Clone, Eq, PartialEq)]
pub enum RevType {
Local = 0,
Remote = 1,
}
impl std::default::Default for RevType {
fn default() -> Self { RevType::Local }
}
#[derive(Debug, Clone, Default, ProtoBuf)] #[derive(Debug, Clone, Default, ProtoBuf)]
pub struct Revision { pub struct Revision {
@ -16,16 +26,20 @@ pub struct Revision {
#[pb(index = 5)] #[pb(index = 5)]
pub doc_id: String, pub doc_id: String,
#[pb(index = 6)]
pub ty: RevType,
} }
impl Revision { impl Revision {
pub fn new(base_rev_id: i64, rev_id: i64, delta: Vec<u8>, md5: String, doc_id: String) -> Revision { pub fn new(base_rev_id: i64, rev_id: i64, delta: Vec<u8>, md5: String, doc_id: String, ty: RevType) -> Revision {
Self { Self {
base_rev_id, base_rev_id,
rev_id, rev_id,
delta, delta,
md5, md5,
doc_id, doc_id,
ty,
} }
} }
} }

View File

@ -27,7 +27,7 @@
pub struct CreateDocParams { pub struct CreateDocParams {
// message fields // message fields
pub id: ::std::string::String, pub id: ::std::string::String,
pub data: ::std::vec::Vec<u8>, pub data: ::std::string::String,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -70,10 +70,10 @@ impl CreateDocParams {
::std::mem::replace(&mut self.id, ::std::string::String::new()) ::std::mem::replace(&mut self.id, ::std::string::String::new())
} }
// bytes data = 2; // string data = 2;
pub fn get_data(&self) -> &[u8] { pub fn get_data(&self) -> &str {
&self.data &self.data
} }
pub fn clear_data(&mut self) { pub fn clear_data(&mut self) {
@ -81,19 +81,19 @@ impl CreateDocParams {
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) { pub fn set_data(&mut self, v: ::std::string::String) {
self.data = v; self.data = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> { pub fn mut_data(&mut self) -> &mut ::std::string::String {
&mut self.data &mut self.data
} }
// Take field // Take field
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> { pub fn take_data(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) ::std::mem::replace(&mut self.data, ::std::string::String::new())
} }
} }
@ -110,7 +110,7 @@ impl ::protobuf::Message for CreateDocParams {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
}, },
2 => { 2 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
}, },
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -128,7 +128,7 @@ impl ::protobuf::Message for CreateDocParams {
my_size += ::protobuf::rt::string_size(1, &self.id); my_size += ::protobuf::rt::string_size(1, &self.id);
} }
if !self.data.is_empty() { if !self.data.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.data); my_size += ::protobuf::rt::string_size(2, &self.data);
} }
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
@ -140,7 +140,7 @@ impl ::protobuf::Message for CreateDocParams {
os.write_string(1, &self.id)?; os.write_string(1, &self.id)?;
} }
if !self.data.is_empty() { if !self.data.is_empty() {
os.write_bytes(2, &self.data)?; os.write_string(2, &self.data)?;
} }
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
@ -185,7 +185,7 @@ impl ::protobuf::Message for CreateDocParams {
|m: &CreateDocParams| { &m.id }, |m: &CreateDocParams| { &m.id },
|m: &mut CreateDocParams| { &mut m.id }, |m: &mut CreateDocParams| { &mut m.id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data", "data",
|m: &CreateDocParams| { &m.data }, |m: &CreateDocParams| { &m.data },
|m: &mut CreateDocParams| { &mut m.data }, |m: &mut CreateDocParams| { &mut m.data },
@ -228,7 +228,7 @@ impl ::protobuf::reflect::ProtobufValue for CreateDocParams {
pub struct Doc { pub struct Doc {
// message fields // message fields
pub id: ::std::string::String, pub id: ::std::string::String,
pub data: ::std::vec::Vec<u8>, pub data: ::std::string::String,
pub rev_id: i64, pub rev_id: i64,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
@ -272,10 +272,10 @@ impl Doc {
::std::mem::replace(&mut self.id, ::std::string::String::new()) ::std::mem::replace(&mut self.id, ::std::string::String::new())
} }
// bytes data = 2; // string data = 2;
pub fn get_data(&self) -> &[u8] { pub fn get_data(&self) -> &str {
&self.data &self.data
} }
pub fn clear_data(&mut self) { pub fn clear_data(&mut self) {
@ -283,19 +283,19 @@ impl Doc {
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) { pub fn set_data(&mut self, v: ::std::string::String) {
self.data = v; self.data = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> { pub fn mut_data(&mut self) -> &mut ::std::string::String {
&mut self.data &mut self.data
} }
// Take field // Take field
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> { pub fn take_data(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) ::std::mem::replace(&mut self.data, ::std::string::String::new())
} }
// int64 rev_id = 3; // int64 rev_id = 3;
@ -327,7 +327,7 @@ impl ::protobuf::Message for Doc {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
}, },
2 => { 2 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
}, },
3 => { 3 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint { if wire_type != ::protobuf::wire_format::WireTypeVarint {
@ -352,7 +352,7 @@ impl ::protobuf::Message for Doc {
my_size += ::protobuf::rt::string_size(1, &self.id); my_size += ::protobuf::rt::string_size(1, &self.id);
} }
if !self.data.is_empty() { if !self.data.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.data); my_size += ::protobuf::rt::string_size(2, &self.data);
} }
if self.rev_id != 0 { if self.rev_id != 0 {
my_size += ::protobuf::rt::value_size(3, self.rev_id, ::protobuf::wire_format::WireTypeVarint); my_size += ::protobuf::rt::value_size(3, self.rev_id, ::protobuf::wire_format::WireTypeVarint);
@ -367,7 +367,7 @@ impl ::protobuf::Message for Doc {
os.write_string(1, &self.id)?; os.write_string(1, &self.id)?;
} }
if !self.data.is_empty() { if !self.data.is_empty() {
os.write_bytes(2, &self.data)?; os.write_string(2, &self.data)?;
} }
if self.rev_id != 0 { if self.rev_id != 0 {
os.write_int64(3, self.rev_id)?; os.write_int64(3, self.rev_id)?;
@ -415,7 +415,7 @@ impl ::protobuf::Message for Doc {
|m: &Doc| { &m.id }, |m: &Doc| { &m.id },
|m: &mut Doc| { &mut m.id }, |m: &mut Doc| { &mut m.id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data", "data",
|m: &Doc| { &m.data }, |m: &Doc| { &m.data },
|m: &mut Doc| { &mut m.data }, |m: &mut Doc| { &mut m.data },
@ -464,7 +464,7 @@ impl ::protobuf::reflect::ProtobufValue for Doc {
pub struct UpdateDocParams { pub struct UpdateDocParams {
// message fields // message fields
pub doc_id: ::std::string::String, pub doc_id: ::std::string::String,
pub data: ::std::vec::Vec<u8>, pub data: ::std::string::String,
pub rev_id: i64, pub rev_id: i64,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
@ -508,10 +508,10 @@ impl UpdateDocParams {
::std::mem::replace(&mut self.doc_id, ::std::string::String::new()) ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
} }
// bytes data = 2; // string data = 2;
pub fn get_data(&self) -> &[u8] { pub fn get_data(&self) -> &str {
&self.data &self.data
} }
pub fn clear_data(&mut self) { pub fn clear_data(&mut self) {
@ -519,19 +519,19 @@ impl UpdateDocParams {
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) { pub fn set_data(&mut self, v: ::std::string::String) {
self.data = v; self.data = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> { pub fn mut_data(&mut self) -> &mut ::std::string::String {
&mut self.data &mut self.data
} }
// Take field // Take field
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> { pub fn take_data(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) ::std::mem::replace(&mut self.data, ::std::string::String::new())
} }
// int64 rev_id = 3; // int64 rev_id = 3;
@ -563,7 +563,7 @@ impl ::protobuf::Message for UpdateDocParams {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
}, },
2 => { 2 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
}, },
3 => { 3 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint { if wire_type != ::protobuf::wire_format::WireTypeVarint {
@ -588,7 +588,7 @@ impl ::protobuf::Message for UpdateDocParams {
my_size += ::protobuf::rt::string_size(1, &self.doc_id); my_size += ::protobuf::rt::string_size(1, &self.doc_id);
} }
if !self.data.is_empty() { if !self.data.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.data); my_size += ::protobuf::rt::string_size(2, &self.data);
} }
if self.rev_id != 0 { if self.rev_id != 0 {
my_size += ::protobuf::rt::value_size(3, self.rev_id, ::protobuf::wire_format::WireTypeVarint); my_size += ::protobuf::rt::value_size(3, self.rev_id, ::protobuf::wire_format::WireTypeVarint);
@ -603,7 +603,7 @@ impl ::protobuf::Message for UpdateDocParams {
os.write_string(1, &self.doc_id)?; os.write_string(1, &self.doc_id)?;
} }
if !self.data.is_empty() { if !self.data.is_empty() {
os.write_bytes(2, &self.data)?; os.write_string(2, &self.data)?;
} }
if self.rev_id != 0 { if self.rev_id != 0 {
os.write_int64(3, self.rev_id)?; os.write_int64(3, self.rev_id)?;
@ -651,7 +651,7 @@ impl ::protobuf::Message for UpdateDocParams {
|m: &UpdateDocParams| { &m.doc_id }, |m: &UpdateDocParams| { &m.doc_id },
|m: &mut UpdateDocParams| { &mut m.doc_id }, |m: &mut UpdateDocParams| { &mut m.doc_id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data", "data",
|m: &UpdateDocParams| { &m.data }, |m: &UpdateDocParams| { &m.data },
|m: &mut UpdateDocParams| { &mut m.data }, |m: &mut UpdateDocParams| { &mut m.data },
@ -700,7 +700,7 @@ impl ::protobuf::reflect::ProtobufValue for UpdateDocParams {
pub struct DocDelta { pub struct DocDelta {
// message fields // message fields
pub doc_id: ::std::string::String, pub doc_id: ::std::string::String,
pub data: ::std::vec::Vec<u8>, pub data: ::std::string::String,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -743,10 +743,10 @@ impl DocDelta {
::std::mem::replace(&mut self.doc_id, ::std::string::String::new()) ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
} }
// bytes data = 2; // string data = 2;
pub fn get_data(&self) -> &[u8] { pub fn get_data(&self) -> &str {
&self.data &self.data
} }
pub fn clear_data(&mut self) { pub fn clear_data(&mut self) {
@ -754,19 +754,19 @@ impl DocDelta {
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) { pub fn set_data(&mut self, v: ::std::string::String) {
self.data = v; self.data = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> { pub fn mut_data(&mut self) -> &mut ::std::string::String {
&mut self.data &mut self.data
} }
// Take field // Take field
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> { pub fn take_data(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) ::std::mem::replace(&mut self.data, ::std::string::String::new())
} }
} }
@ -783,7 +783,7 @@ impl ::protobuf::Message for DocDelta {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
}, },
2 => { 2 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
}, },
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -801,7 +801,7 @@ impl ::protobuf::Message for DocDelta {
my_size += ::protobuf::rt::string_size(1, &self.doc_id); my_size += ::protobuf::rt::string_size(1, &self.doc_id);
} }
if !self.data.is_empty() { if !self.data.is_empty() {
my_size += ::protobuf::rt::bytes_size(2, &self.data); my_size += ::protobuf::rt::string_size(2, &self.data);
} }
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
@ -813,7 +813,7 @@ impl ::protobuf::Message for DocDelta {
os.write_string(1, &self.doc_id)?; os.write_string(1, &self.doc_id)?;
} }
if !self.data.is_empty() { if !self.data.is_empty() {
os.write_bytes(2, &self.data)?; os.write_string(2, &self.data)?;
} }
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
@ -858,7 +858,7 @@ impl ::protobuf::Message for DocDelta {
|m: &DocDelta| { &m.doc_id }, |m: &DocDelta| { &m.doc_id },
|m: &mut DocDelta| { &mut m.doc_id }, |m: &mut DocDelta| { &mut m.doc_id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data", "data",
|m: &DocDelta| { &m.data }, |m: &DocDelta| { &m.data },
|m: &mut DocDelta| { &mut m.data }, |m: &mut DocDelta| { &mut m.data },
@ -1058,47 +1058,47 @@ impl ::protobuf::reflect::ProtobufValue for QueryDocParams {
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\tdoc.proto\"5\n\x0fCreateDocParams\x12\x0e\n\x02id\x18\x01\x20\x01(\t\ \n\tdoc.proto\"5\n\x0fCreateDocParams\x12\x0e\n\x02id\x18\x01\x20\x01(\t\
R\x02id\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data\"@\n\x03Doc\x12\ R\x02id\x12\x12\n\x04data\x18\x02\x20\x01(\tR\x04data\"@\n\x03Doc\x12\
\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04data\x18\x02\x20\x01\ \x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04data\x18\x02\x20\x01\
(\x0cR\x04data\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\x05revId\"S\n\ (\tR\x04data\x12\x15\n\x06rev_id\x18\x03\x20\x01(\x03R\x05revId\"S\n\x0f\
\x0fUpdateDocParams\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\ UpdateDocParams\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docId\x12\x12\
\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data\x12\x15\n\x06rev_id\x18\x03\ \n\x04data\x18\x02\x20\x01(\tR\x04data\x12\x15\n\x06rev_id\x18\x03\x20\
\x20\x01(\x03R\x05revId\"5\n\x08DocDelta\x12\x15\n\x06doc_id\x18\x01\x20\ \x01(\x03R\x05revId\"5\n\x08DocDelta\x12\x15\n\x06doc_id\x18\x01\x20\x01\
\x01(\tR\x05docId\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\x04data\"'\n\ (\tR\x05docId\x12\x12\n\x04data\x18\x02\x20\x01(\tR\x04data\"'\n\x0eQuer\
\x0eQueryDocParams\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docIdJ\xe7\ yDocParams\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docIdJ\xe7\x05\n\
\x05\n\x06\x12\x04\0\0\x16\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\ \x06\x12\x04\0\0\x16\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\
\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x17\n\ \x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x17\n\x0b\n\
\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x04\0\x02\0\x05\ \x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\
\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\r\n\x0c\n\ \x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\r\n\x0c\n\x05\x04\
\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\x04\x04\0\x02\x01\x12\ \0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\
\x03\x04\x04\x13\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\ \x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\
\x05\x04\0\x02\x01\x01\x12\x03\x04\n\x0e\n\x0c\n\x05\x04\0\x02\x01\x03\ \0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\
\x12\x03\x04\x11\x12\n\n\n\x02\x04\x01\x12\x04\x06\0\n\x01\n\n\n\x03\x04\ \x04\x12\x13\n\n\n\x02\x04\x01\x12\x04\x06\0\n\x01\n\n\n\x03\x04\x01\x01\
\x01\x01\x12\x03\x06\x08\x0b\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x07\x04\ \x12\x03\x06\x08\x0b\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x07\x04\x12\n\x0c\
\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\x01\ \n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
\x02\0\x01\x12\x03\x07\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x07\ \x12\x03\x07\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x07\x10\x11\n\
\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\x04\x13\n\x0c\n\x05\x04\ \x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\x04\x14\n\x0c\n\x05\x04\x01\x02\
\x01\x02\x01\x05\x12\x03\x08\x04\t\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\ \x01\x05\x12\x03\x08\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x08\
\x03\x08\n\x0e\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x08\x11\x12\n\x0b\ \x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x08\x12\x13\n\x0b\n\x04\
\n\x04\x04\x01\x02\x02\x12\x03\t\x04\x15\n\x0c\n\x05\x04\x01\x02\x02\x05\ \x04\x01\x02\x02\x12\x03\t\x04\x15\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\
\x12\x03\t\x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\t\n\x10\n\x0c\n\ \x03\t\x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\t\n\x10\n\x0c\n\x05\
\x05\x04\x01\x02\x02\x03\x12\x03\t\x13\x14\n\n\n\x02\x04\x02\x12\x04\x0b\ \x04\x01\x02\x02\x03\x12\x03\t\x13\x14\n\n\n\x02\x04\x02\x12\x04\x0b\0\
\0\x0f\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0b\x08\x17\n\x0b\n\x04\x04\x02\ \x0f\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0b\x08\x17\n\x0b\n\x04\x04\x02\
\x02\0\x12\x03\x0c\x04\x16\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0c\x04\ \x02\0\x12\x03\x0c\x04\x16\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0c\x04\
\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0c\x0b\x11\n\x0c\n\x05\x04\x02\ \n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0c\x0b\x11\n\x0c\n\x05\x04\x02\
\x02\0\x03\x12\x03\x0c\x14\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\r\x04\ \x02\0\x03\x12\x03\x0c\x14\x15\n\x0b\n\x04\x04\x02\x02\x01\x12\x03\r\x04\
\x13\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\r\x04\t\n\x0c\n\x05\x04\x02\ \x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\r\x04\n\n\x0c\n\x05\x04\x02\
\x02\x01\x01\x12\x03\r\n\x0e\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\r\ \x02\x01\x01\x12\x03\r\x0b\x0f\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\r\
\x11\x12\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x0e\x04\x15\n\x0c\n\x05\x04\ \x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\x0e\x04\x15\n\x0c\n\x05\x04\
\x02\x02\x02\x05\x12\x03\x0e\x04\t\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\ \x02\x02\x02\x05\x12\x03\x0e\x04\t\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\
\x03\x0e\n\x10\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x0e\x13\x14\n\n\n\ \x03\x0e\n\x10\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\x03\x0e\x13\x14\n\n\n\
\x02\x04\x03\x12\x04\x10\0\x13\x01\n\n\n\x03\x04\x03\x01\x12\x03\x10\x08\ \x02\x04\x03\x12\x04\x10\0\x13\x01\n\n\n\x03\x04\x03\x01\x12\x03\x10\x08\
\x10\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x11\x04\x16\n\x0c\n\x05\x04\x03\ \x10\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x11\x04\x16\n\x0c\n\x05\x04\x03\
\x02\0\x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x11\ \x02\0\x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x11\
\x0b\x11\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x11\x14\x15\n\x0b\n\x04\ \x0b\x11\n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x11\x14\x15\n\x0b\n\x04\
\x04\x03\x02\x01\x12\x03\x12\x04\x13\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\ \x04\x03\x02\x01\x12\x03\x12\x04\x14\n\x0c\n\x05\x04\x03\x02\x01\x05\x12\
\x03\x12\x04\t\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x12\n\x0e\n\x0c\n\ \x03\x12\x04\n\n\x0c\n\x05\x04\x03\x02\x01\x01\x12\x03\x12\x0b\x0f\n\x0c\
\x05\x04\x03\x02\x01\x03\x12\x03\x12\x11\x12\n\n\n\x02\x04\x04\x12\x04\ \n\x05\x04\x03\x02\x01\x03\x12\x03\x12\x12\x13\n\n\n\x02\x04\x04\x12\x04\
\x14\0\x16\x01\n\n\n\x03\x04\x04\x01\x12\x03\x14\x08\x16\n\x0b\n\x04\x04\ \x14\0\x16\x01\n\n\n\x03\x04\x04\x01\x12\x03\x14\x08\x16\n\x0b\n\x04\x04\
\x04\x02\0\x12\x03\x15\x04\x16\n\x0c\n\x05\x04\x04\x02\0\x05\x12\x03\x15\ \x04\x02\0\x12\x03\x15\x04\x16\n\x0c\n\x05\x04\x04\x02\0\x05\x12\x03\x15\
\x04\n\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03\x15\x0b\x11\n\x0c\n\x05\x04\ \x04\n\n\x0c\n\x05\x04\x04\x02\0\x01\x12\x03\x15\x0b\x11\n\x0c\n\x05\x04\

View File

@ -31,6 +31,7 @@ pub struct Revision {
pub delta: ::std::vec::Vec<u8>, pub delta: ::std::vec::Vec<u8>,
pub md5: ::std::string::String, pub md5: ::std::string::String,
pub doc_id: ::std::string::String, pub doc_id: ::std::string::String,
pub ty: RevType,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -154,6 +155,21 @@ impl Revision {
pub fn take_doc_id(&mut self) -> ::std::string::String { pub fn take_doc_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.doc_id, ::std::string::String::new()) ::std::mem::replace(&mut self.doc_id, ::std::string::String::new())
} }
// .RevType ty = 6;
pub fn get_ty(&self) -> RevType {
self.ty
}
pub fn clear_ty(&mut self) {
self.ty = RevType::Local;
}
// Param is passed by value, moved
pub fn set_ty(&mut self, v: RevType) {
self.ty = v;
}
} }
impl ::protobuf::Message for Revision { impl ::protobuf::Message for Revision {
@ -188,6 +204,9 @@ impl ::protobuf::Message for Revision {
5 => { 5 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.doc_id)?;
}, },
6 => {
::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 6, &mut self.unknown_fields)?
},
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
}, },
@ -215,6 +234,9 @@ impl ::protobuf::Message for Revision {
if !self.doc_id.is_empty() { if !self.doc_id.is_empty() {
my_size += ::protobuf::rt::string_size(5, &self.doc_id); my_size += ::protobuf::rt::string_size(5, &self.doc_id);
} }
if self.ty != RevType::Local {
my_size += ::protobuf::rt::enum_size(6, self.ty);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
my_size my_size
@ -236,6 +258,9 @@ impl ::protobuf::Message for Revision {
if !self.doc_id.is_empty() { if !self.doc_id.is_empty() {
os.write_string(5, &self.doc_id)?; os.write_string(5, &self.doc_id)?;
} }
if self.ty != RevType::Local {
os.write_enum(6, ::protobuf::ProtobufEnum::value(&self.ty))?;
}
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
} }
@ -299,6 +324,11 @@ impl ::protobuf::Message for Revision {
|m: &Revision| { &m.doc_id }, |m: &Revision| { &m.doc_id },
|m: &mut Revision| { &mut m.doc_id }, |m: &mut Revision| { &mut m.doc_id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<RevType>>(
"ty",
|m: &Revision| { &m.ty },
|m: &mut Revision| { &mut m.ty },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<Revision>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<Revision>(
"Revision", "Revision",
fields, fields,
@ -320,6 +350,7 @@ impl ::protobuf::Clear for Revision {
self.delta.clear(); self.delta.clear();
self.md5.clear(); self.md5.clear();
self.doc_id.clear(); self.doc_id.clear();
self.ty = RevType::Local;
self.unknown_fields.clear(); self.unknown_fields.clear();
} }
} }
@ -336,27 +367,87 @@ impl ::protobuf::reflect::ProtobufValue for Revision {
} }
} }
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub enum RevType {
Local = 0,
Remote = 1,
}
impl ::protobuf::ProtobufEnum for RevType {
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<RevType> {
match value {
0 => ::std::option::Option::Some(RevType::Local),
1 => ::std::option::Option::Some(RevType::Remote),
_ => ::std::option::Option::None
}
}
fn values() -> &'static [Self] {
static values: &'static [RevType] = &[
RevType::Local,
RevType::Remote,
];
values
}
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
::protobuf::reflect::EnumDescriptor::new_pb_name::<RevType>("RevType", file_descriptor_proto())
})
}
}
impl ::std::marker::Copy for RevType {
}
impl ::std::default::Default for RevType {
fn default() -> Self {
RevType::Local
}
}
impl ::protobuf::reflect::ProtobufValue for RevType {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
}
}
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0erevision.proto\"\x80\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\ \n\x0erevision.proto\"\x9a\x01\n\x08Revision\x12\x1e\n\x0bbase_rev_id\
\x18\x01\x20\x01(\x03R\tbaseRevId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\ \x18\x01\x20\x01(\x03R\tbaseRevId\x12\x15\n\x06rev_id\x18\x02\x20\x01(\
\x03R\x05revId\x12\x14\n\x05delta\x18\x03\x20\x01(\x0cR\x05delta\x12\x10\ \x03R\x05revId\x12\x14\n\x05delta\x18\x03\x20\x01(\x0cR\x05delta\x12\x10\
\n\x03md5\x18\x04\x20\x01(\tR\x03md5\x12\x15\n\x06doc_id\x18\x05\x20\x01\ \n\x03md5\x18\x04\x20\x01(\tR\x03md5\x12\x15\n\x06doc_id\x18\x05\x20\x01\
(\tR\x05docIdJ\xbd\x02\n\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\ (\tR\x05docId\x12\x18\n\x02ty\x18\x06\x20\x01(\x0e2\x08.RevTypeR\x02ty*\
\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\ \x20\n\x07RevType\x12\t\n\x05Local\x10\0\x12\n\n\x06Remote\x10\x01J\xde\
\x03\x02\x08\x10\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\ \x03\n\x06\x12\x04\0\0\r\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
\x04\0\x02\0\x05\x12\x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\ \x04\0\x12\x04\x02\0\t\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x10\n\x0b\
\x03\n\x15\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x18\x19\n\x0b\n\x04\ \n\x04\x04\0\x02\0\x12\x03\x03\x04\x1a\n\x0c\n\x05\x04\0\x02\0\x05\x12\
\x04\0\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\ \x03\x03\x04\t\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\n\x15\n\x0c\n\x05\
\x04\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\n\x10\n\x0c\n\x05\ \x04\0\x02\0\x03\x12\x03\x03\x18\x19\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
\x04\0\x02\x01\x03\x12\x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\x02\x12\x03\ \x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\x05\
\x05\x04\x14\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\ \x04\0\x02\x01\x01\x12\x03\x04\n\x10\n\x0c\n\x05\x04\0\x02\x01\x03\x12\
\x04\0\x02\x02\x01\x12\x03\x05\n\x0f\n\x0c\n\x05\x04\0\x02\x02\x03\x12\ \x03\x04\x13\x14\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x14\n\x0c\n\
\x03\x05\x12\x13\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x13\n\x0c\n\ \x05\x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\
\x05\x04\0\x02\x03\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\ \x12\x03\x05\n\x0f\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x12\x13\n\
\x12\x03\x06\x0b\x0e\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x11\x12\n\ \x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x04\x13\n\x0c\n\x05\x04\0\x02\x03\
\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\0\x02\x04\ \x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06\x0b\x0e\
\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x0b\x11\ \n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06\x11\x12\n\x0b\n\x04\x04\0\x02\
\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07\x14\x15b\x06proto3\ \x04\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x04\n\
\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\x0b\x11\n\x0c\n\x05\x04\0\x02\
\x04\x03\x12\x03\x07\x14\x15\n\x0b\n\x04\x04\0\x02\x05\x12\x03\x08\x04\
\x13\n\x0c\n\x05\x04\0\x02\x05\x06\x12\x03\x08\x04\x0b\n\x0c\n\x05\x04\0\
\x02\x05\x01\x12\x03\x08\x0c\x0e\n\x0c\n\x05\x04\0\x02\x05\x03\x12\x03\
\x08\x11\x12\n\n\n\x02\x05\0\x12\x04\n\0\r\x01\n\n\n\x03\x05\0\x01\x12\
\x03\n\x05\x0c\n\x0b\n\x04\x05\0\x02\0\x12\x03\x0b\x04\x0e\n\x0c\n\x05\
\x05\0\x02\0\x01\x12\x03\x0b\x04\t\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\
\x0b\x0c\r\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x0c\x04\x0f\n\x0c\n\x05\x05\
\0\x02\x01\x01\x12\x03\x0c\x04\n\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\
\x0c\r\x0eb\x06proto3\
"; ";
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

@ -2,21 +2,21 @@ syntax = "proto3";
message CreateDocParams { message CreateDocParams {
string id = 1; string id = 1;
bytes data = 2; string data = 2;
} }
message Doc { message Doc {
string id = 1; string id = 1;
bytes data = 2; string data = 2;
int64 rev_id = 3; int64 rev_id = 3;
} }
message UpdateDocParams { message UpdateDocParams {
string doc_id = 1; string doc_id = 1;
bytes data = 2; string data = 2;
int64 rev_id = 3; int64 rev_id = 3;
} }
message DocDelta { message DocDelta {
string doc_id = 1; string doc_id = 1;
bytes data = 2; string data = 2;
} }
message QueryDocParams { message QueryDocParams {
string doc_id = 1; string doc_id = 1;

View File

@ -6,4 +6,9 @@ message Revision {
bytes delta = 3; bytes delta = 3;
string md5 = 4; string md5 = 4;
string doc_id = 5; string doc_id = 5;
RevType ty = 6;
}
enum RevType {
Local = 0;
Remote = 1;
} }

View File

@ -14,6 +14,13 @@ pub(crate) struct DocCache {
impl DocCache { impl DocCache {
pub(crate) fn new() -> Self { Self { inner: DashMap::new() } } pub(crate) fn new() -> Self { Self { inner: DashMap::new() } }
pub(crate) fn all_docs(&self) -> Vec<Arc<EditDocContext>> {
self.inner
.iter()
.map(|kv| kv.value().clone())
.collect::<Vec<Arc<EditDocContext>>>()
}
pub(crate) fn set(&self, doc: Arc<EditDocContext>) { pub(crate) fn set(&self, doc: Arc<EditDocContext>) {
let doc_id = doc.id.clone(); let doc_id = doc.id.clone();
if self.inner.contains_key(&doc_id) { if self.inner.contains_key(&doc_id) {

View File

@ -2,16 +2,21 @@ use crate::{
entities::doc::{CreateDocParams, Doc, DocDelta, QueryDocParams, UpdateDocParams}, entities::doc::{CreateDocParams, Doc, DocDelta, QueryDocParams, UpdateDocParams},
errors::{internal_error, DocError}, errors::{internal_error, DocError},
module::DocumentUser, module::DocumentUser,
services::{cache::DocCache, doc::edit_doc_context::EditDocContext, server::Server, ws::WsDocumentManager}, services::{
cache::DocCache,
doc::{edit_doc_context::EditDocContext, rev_manager::RevisionManager},
server::Server,
ws::WsDocumentManager,
},
sql_tables::doc::{DocTable, DocTableSql, OpTableSql}, sql_tables::doc::{DocTable, DocTableSql, OpTableSql},
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_database::{ConnectionPool, SqliteConnection}; use flowy_database::{ConnectionPool, SqliteConnection};
use flowy_infra::future::{wrap_future, FnFuture};
use crate::services::doc::rev_manager::RevisionManager;
use flowy_ot::core::Delta; use flowy_ot::core::Delta;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::sync::Arc; use std::sync::Arc;
use tokio::time::{interval, Duration};
pub(crate) struct DocController { pub(crate) struct DocController {
server: Server, server: Server,
@ -27,14 +32,23 @@ impl DocController {
let doc_sql = Arc::new(DocTableSql {}); let doc_sql = Arc::new(DocTableSql {});
let op_sql = Arc::new(OpTableSql {}); let op_sql = Arc::new(OpTableSql {});
let cache = Arc::new(DocCache::new()); let cache = Arc::new(DocCache::new());
Self {
let controller = Self {
server, server,
doc_sql, doc_sql,
op_sql, op_sql,
user, user,
ws, ws,
cache, cache: cache.clone(),
} };
// tokio::spawn(async move {
// tokio::select! {
// _ = event_loop(cache.clone()) => {},
// }
// });
controller
} }
#[tracing::instrument(skip(self, conn), err)] #[tracing::instrument(skip(self, conn), err)]
@ -49,7 +63,11 @@ impl DocController {
} }
#[tracing::instrument(level = "debug", skip(self, pool), err)] #[tracing::instrument(level = "debug", skip(self, pool), err)]
pub(crate) async fn open(&self, params: QueryDocParams, pool: Arc<ConnectionPool>) -> Result<Arc<EditDocContext>, DocError> { pub(crate) async fn open(
&self,
params: QueryDocParams,
pool: Arc<ConnectionPool>,
) -> Result<Arc<EditDocContext>, DocError> {
if self.cache.is_opened(&params.doc_id) == false { if self.cache.is_opened(&params.doc_id) == false {
return match self._open(params, pool).await { return match self._open(params, pool).await {
Ok(doc) => Ok(doc), Ok(doc) => Ok(doc),
@ -81,7 +99,7 @@ impl DocController {
#[tracing::instrument(level = "debug", skip(self, delta), err)] #[tracing::instrument(level = "debug", skip(self, delta), err)]
pub(crate) fn edit_doc(&self, delta: DocDelta) -> Result<Doc, DocError> { pub(crate) fn edit_doc(&self, delta: DocDelta) -> Result<Doc, DocError> {
let edit_doc_ctx = self.cache.get(&delta.doc_id)?; let edit_doc_ctx = self.cache.get(&delta.doc_id)?;
let _ = edit_doc_ctx.apply_local_delta(Bytes::from(delta.data))?; let _ = edit_doc_ctx.compose_local_delta(Bytes::from(delta.data))?;
Ok(edit_doc_ctx.doc()) Ok(edit_doc_ctx.doc())
} }
} }
@ -104,7 +122,11 @@ impl DocController {
} }
#[tracing::instrument(level = "debug", skip(self, pool), err)] #[tracing::instrument(level = "debug", skip(self, pool), err)]
async fn read_doc_from_server(&self, params: QueryDocParams, pool: Arc<ConnectionPool>) -> Result<Arc<EditDocContext>, DocError> { async fn read_doc_from_server(
&self,
params: QueryDocParams,
pool: Arc<ConnectionPool>,
) -> Result<Arc<EditDocContext>, DocError> {
let token = self.user.token()?; let token = self.user.token()?;
match self.server.read_doc(&token, params).await? { match self.server.read_doc(&token, params).await? {
None => Err(DocError::not_found()), None => Err(DocError::not_found()),
@ -151,7 +173,7 @@ impl DocController {
// Opti: require upgradable_read lock and then upgrade to write lock using // Opti: require upgradable_read lock and then upgrade to write lock using
// RwLockUpgradableReadGuard::upgrade(xx) of ws // RwLockUpgradableReadGuard::upgrade(xx) of ws
let doc_id = doc.id.clone(); let doc_id = doc.id.clone();
let delta = Delta::from_bytes(doc.data)?; let delta = Delta::from_bytes(&doc.data)?;
let ws_sender = self.ws.read().sender(); let ws_sender = self.ws.read().sender();
let rev_manager = RevisionManager::new(&doc_id, doc.rev_id, self.op_sql.clone(), pool, ws_sender); let rev_manager = RevisionManager::new(&doc_id, doc.rev_id, self.op_sql.clone(), pool, ws_sender);
let edit_ctx = Arc::new(EditDocContext::new(&doc_id, delta, rev_manager)?); let edit_ctx = Arc::new(EditDocContext::new(&doc_id, delta, rev_manager)?);
@ -160,3 +182,14 @@ impl DocController {
Ok(edit_ctx) Ok(edit_ctx)
} }
} }
#[allow(dead_code)]
fn event_loop(_cache: Arc<DocCache>) -> FnFuture<()> {
let mut i = interval(Duration::from_secs(3));
wrap_future(async move {
loop {
// cache.all_docs().iter().for_each(|doc| doc.tick());
i.tick().await;
}
})
}

View File

@ -2,7 +2,7 @@ use crate::{
errors::DocError, errors::DocError,
services::doc::{view::View, History, UndoResult, RECORD_THRESHOLD}, services::doc::{view::View, History, UndoResult, RECORD_THRESHOLD},
}; };
use bytes::Bytes;
use flowy_ot::core::*; use flowy_ot::core::*;
pub trait DocumentData { pub trait DocumentData {
@ -57,10 +57,29 @@ impl Document {
pub fn set_delta(&mut self, data: Delta) { self.delta = data; } pub fn set_delta(&mut self, data: Delta) { self.delta = data; }
pub fn apply_delta(&mut self, delta: Delta) -> Result<(), DocError> { pub fn compose_delta(&mut self, delta: &Delta) -> Result<(), DocError> {
log::trace!("Apply delta: {}", delta); let composed_delta = self.delta.compose(delta)?;
let _ = self.add_delta(&delta)?; let mut undo_delta = delta.invert(&self.delta);
log::debug!("Document: {}", self.to_json());
let now = chrono::Utc::now().timestamp_millis() as usize;
if now - self.last_edit_time < RECORD_THRESHOLD {
if let Some(last_delta) = self.history.undo() {
log::trace!("compose previous change");
log::trace!("current = {}", undo_delta);
log::trace!("previous = {}", last_delta);
undo_delta = undo_delta.compose(&last_delta)?;
}
} else {
self.last_edit_time = now;
}
log::trace!("👉 receive change undo: {}", undo_delta);
if !undo_delta.is_empty() {
self.history.record(undo_delta);
}
log::trace!("document delta: {}", &composed_delta);
self.delta = composed_delta;
Ok(()) Ok(())
} }
@ -71,7 +90,7 @@ impl Document {
let text = data.into_string()?; let text = data.into_string()?;
let delta = self.view.insert(&self.delta, &text, interval)?; let delta = self.view.insert(&self.delta, &text, interval)?;
log::trace!("👉 receive change: {}", delta); log::trace!("👉 receive change: {}", delta);
self.add_delta(&delta)?; self.compose_delta(&delta)?;
Ok(delta) Ok(delta)
} }
@ -81,19 +100,19 @@ impl Document {
let delete = self.view.delete(&self.delta, interval)?; let delete = self.view.delete(&self.delta, interval)?;
if !delete.is_empty() { if !delete.is_empty() {
log::trace!("👉 receive change: {}", delete); log::trace!("👉 receive change: {}", delete);
let _ = self.add_delta(&delete)?; let _ = self.compose_delta(&delete)?;
} }
Ok(delete) Ok(delete)
} }
pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<(), DocError> { pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<Delta, DocError> {
let _ = validate_interval(&self.delta, &interval)?; let _ = validate_interval(&self.delta, &interval)?;
log::trace!("format with {} at {}", attribute, interval); log::trace!("format with {} at {}", attribute, interval);
let format_delta = self.view.format(&self.delta, attribute.clone(), interval).unwrap(); let format_delta = self.view.format(&self.delta, attribute.clone(), interval).unwrap();
log::trace!("👉 receive change: {}", format_delta); log::trace!("👉 receive change: {}", format_delta);
self.add_delta(&format_delta)?; self.compose_delta(&format_delta)?;
Ok(()) Ok(format_delta)
} }
pub fn replace<T: DocumentData>(&mut self, interval: Interval, data: T) -> Result<Delta, DocError> { pub fn replace<T: DocumentData>(&mut self, interval: Interval, data: T) -> Result<Delta, DocError> {
@ -103,7 +122,7 @@ impl Document {
if !text.is_empty() { if !text.is_empty() {
delta = self.view.insert(&self.delta, &text, interval)?; delta = self.view.insert(&self.delta, &text, interval)?;
log::trace!("👉 receive change: {}", delta); log::trace!("👉 receive change: {}", delta);
self.add_delta(&delta)?; self.compose_delta(&delta)?;
} }
if !interval.is_empty() { if !interval.is_empty() {
@ -148,32 +167,6 @@ impl Document {
} }
impl Document { impl Document {
fn add_delta(&mut self, delta: &Delta) -> Result<(), DocError> {
let composed_delta = self.delta.compose(delta)?;
let mut undo_delta = delta.invert(&self.delta);
let now = chrono::Utc::now().timestamp_millis() as usize;
if now - self.last_edit_time < RECORD_THRESHOLD {
if let Some(last_delta) = self.history.undo() {
log::trace!("compose previous change");
log::trace!("current = {}", undo_delta);
log::trace!("previous = {}", last_delta);
undo_delta = undo_delta.compose(&last_delta)?;
}
} else {
self.last_edit_time = now;
}
log::trace!("👉 receive change undo: {}", undo_delta);
if !undo_delta.is_empty() {
self.history.record(undo_delta);
}
log::trace!("document delta: {}", &composed_delta);
self.delta = composed_delta;
Ok(())
}
fn invert_change(&self, change: &Delta) -> Result<(Delta, Delta), DocError> { fn invert_change(&self, change: &Delta) -> Result<(Delta, Delta), DocError> {
// c = a.compose(b) // c = a.compose(b)
// d = b.invert(a) // d = b.invert(a)

View File

@ -6,16 +6,16 @@ use crate::{
errors::*, errors::*,
services::{ services::{
doc::{rev_manager::RevisionManager, Document}, doc::{rev_manager::RevisionManager, Document},
util::{bytes_to_rev_id, md5}, util::bytes_to_rev_id,
ws::{WsDocumentHandler, WsDocumentSender}, ws::WsDocumentHandler,
}, },
sql_tables::{OpTable, OpTableSql}, sql_tables::{OpTableSql, RevTable},
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_ot::core::Delta; use flowy_ot::core::Delta;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::{convert::TryFrom, sync::Arc}; use std::{convert::TryFrom, sync::Arc};
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
pub type DocId = String; pub type DocId = String;
@ -30,49 +30,30 @@ impl EditDocContext {
let id = doc_id.to_owned(); let id = doc_id.to_owned();
let rev_manager = Arc::new(rev_manager); let rev_manager = Arc::new(rev_manager);
let document = Arc::new(RwLock::new(Document::from_delta(delta))); let document = Arc::new(RwLock::new(Document::from_delta(delta)));
let edit_context = Self { id, document, rev_manager }; let edit_context = Self {
edit_context.composing_delta(); id,
document,
rev_manager,
};
Ok(edit_context) Ok(edit_context)
} }
pub(crate) fn doc(&self) -> Doc { pub(crate) fn doc(&self) -> Doc {
Doc { Doc {
id: self.id.clone(), id: self.id.clone(),
data: self.document.read().to_bytes(), data: self.document.read().to_json(),
rev_id: self.rev_manager.rev(), rev_id: self.rev_manager.rev_id(),
} }
} }
#[tracing::instrument(level = "debug", skip(self, data), err)] #[tracing::instrument(level = "debug", skip(self, data), err)]
pub(crate) fn apply_local_delta(&self, data: Bytes) -> Result<(), DocError> { pub(crate) fn compose_local_delta(&self, data: Bytes) -> Result<(), DocError> {
let doc_id = self.id.clone(); let delta = Delta::from_bytes(&data)?;
let (base_rev_id, rev_id) = self.rev_manager.next_rev(); self.document.write().compose_delta(&delta)?;
let revision = Revision::new(base_rev_id, rev_id, data.to_vec(), md5(&data), doc_id); self.rev_manager.add_delta(data);
let delta = Delta::from_bytes(data.to_vec())?;
self.document.write().apply_delta(delta)?;
self.rev_manager.add_local(revision);
Ok(()) Ok(())
} }
fn composing_delta(&self) {
let rev_manager = self.rev_manager.clone();
let document = self.document.clone();
tokio::spawn(async move {
let notified = rev_manager.notified();
tokio::select! {
_ = notified => {
if let Some(delta) = rev_manager.next_compose_delta() {
log::info!("😁receive delta: {:?}", delta);
document.write().apply_delta(delta).unwrap();
log::info!("😁Document: {:?}", document.read().to_plain_string());
}
}
}
});
}
} }
impl WsDocumentHandler for EditDocContext { impl WsDocumentHandler for EditDocContext {
@ -82,14 +63,18 @@ impl WsDocumentHandler for EditDocContext {
WsDataType::Rev => { WsDataType::Rev => {
let bytes = Bytes::from(doc_data.data); let bytes = Bytes::from(doc_data.data);
let revision = Revision::try_from(bytes)?; let revision = Revision::try_from(bytes)?;
self.rev_manager.add_remote(revision); self.rev_manager.add_revision(revision);
self.rev_manager.next_compose_delta(|delta| {
let _ = self.document.write().compose_delta(delta)?;
log::debug!("😁Document: {:?}", self.document.read().to_plain_string());
Ok(())
});
}, },
WsDataType::Acked => { WsDataType::Acked => {
let rev_id = bytes_to_rev_id(doc_data.data)?; let rev_id = bytes_to_rev_id(doc_data.data)?;
self.rev_manager.remove(rev_id); self.rev_manager.remove(rev_id);
}, },
} }
Result::<(), DocError>::Ok(()) Result::<(), DocError>::Ok(())
}; };

View File

@ -1,21 +1,20 @@
use crate::{ use crate::{
entities::{ entities::doc::{RevType, Revision},
doc::Revision,
ws::{WsDataType, WsDocumentData},
},
errors::{internal_error, DocError}, errors::{internal_error, DocError},
services::{ services::{
util::{bytes_to_rev_id, RevIdCounter}, util::{md5, RevIdCounter},
ws::{WsDocumentHandler, WsDocumentSender}, ws::{WsDocumentHandler, WsDocumentSender},
}, },
sql_tables::{OpTable, OpTableSql}, sql_tables::{OpTableSql, RevTable},
}; };
use bytes::Bytes; use bytes::Bytes;
use flowy_database::ConnectionPool; use flowy_database::ConnectionPool;
use flowy_infra::future::wrap_future;
use flowy_ot::core::Delta; use flowy_ot::core::Delta;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::{collections::BTreeMap, sync::Arc}; use std::{
collections::{BTreeMap, VecDeque},
sync::Arc,
};
use tokio::sync::{futures::Notified, Notify}; use tokio::sync::{futures::Notified, Notify};
pub struct RevisionManager { pub struct RevisionManager {
@ -24,7 +23,8 @@ pub struct RevisionManager {
pool: Arc<ConnectionPool>, pool: Arc<ConnectionPool>,
rev_id_counter: RevIdCounter, rev_id_counter: RevIdCounter,
ws_sender: Arc<dyn WsDocumentSender>, ws_sender: Arc<dyn WsDocumentSender>,
rev_cache: RwLock<BTreeMap<i64, Revision>>, local_rev_cache: Arc<RwLock<BTreeMap<i64, Revision>>>,
remote_rev_cache: RwLock<VecDeque<Revision>>,
notify: Notify, notify: Notify,
} }
@ -37,67 +37,98 @@ impl RevisionManager {
ws_sender: Arc<dyn WsDocumentSender>, ws_sender: Arc<dyn WsDocumentSender>,
) -> Self { ) -> Self {
let rev_id_counter = RevIdCounter::new(rev_id); let rev_id_counter = RevIdCounter::new(rev_id);
let rev_cache = RwLock::new(BTreeMap::new()); let local_rev_cache = Arc::new(RwLock::new(BTreeMap::new()));
let remote_rev_cache = RwLock::new(VecDeque::new());
Self { Self {
doc_id: doc_id.to_owned(), doc_id: doc_id.to_owned(),
op_sql, op_sql,
pool, pool,
rev_id_counter, rev_id_counter,
ws_sender, ws_sender,
rev_cache, local_rev_cache,
remote_rev_cache,
notify: Notify::new(), notify: Notify::new(),
} }
} }
pub fn next_compose_delta(&self) -> Option<Delta> { pub fn next_compose_delta<F>(&self, mut f: F)
// let delta = Delta::from_bytes(revision.delta)?; where
// F: FnMut(&Delta) -> Result<(), DocError>,
// log::debug!("Remote delta: {:?}", delta); {
if let Some(rev) = self.remote_rev_cache.write().pop_front() {
match Delta::from_bytes(&rev.delta) {
Ok(delta) => match f(&delta) {
Ok(_) => {},
Err(e) => {
log::error!("{}", e);
self.remote_rev_cache.write().push_front(rev);
},
},
Err(_) => {},
}
}
} }
pub fn notified(&self) -> Notified { self.notify.notified() } #[tracing::instrument(level = "debug", skip(self, delta_data))]
pub fn add_delta(&self, delta_data: Bytes) -> Result<(), DocError> {
pub fn next_rev(&self) -> (i64, i64) { let (base_rev_id, rev_id) = self.next_rev_id();
let cur = self.rev_id_counter.value(); let revision = Revision::new(
let next = self.rev_id_counter.next(); base_rev_id,
(cur, next) rev_id,
delta_data.to_vec(),
md5(&delta_data),
self.doc_id.clone(),
RevType::Local,
);
let _ = self.add_revision(revision)?;
Ok(())
} }
pub fn rev(&self) -> i64 { self.rev_id_counter.value() } #[tracing::instrument(level = "debug", skip(self, revision))]
pub fn add_revision(&self, revision: Revision) -> Result<(), DocError> {
pub fn add_local(&self, revision: Revision) -> Result<(), DocError> { match revision.ty {
self.rev_cache.write().insert(revision.rev_id, revision.clone()); RevType::Local => {
self.local_rev_cache.write().insert(revision.rev_id, revision.clone());
// self.save_revision(revision.clone());
match self.ws_sender.send(revision.into()) { match self.ws_sender.send(revision.into()) {
Ok(_) => {}, Ok(_) => {},
Err(e) => { Err(e) => {
log::error!("Send delta failed: {:?}", e); log::error!("Send delta failed: {:?}", e);
}, },
} }
// self.save_revision(revision.clone()); },
Ok(()) RevType::Remote => {
self.remote_rev_cache.write().push_back(revision);
self.notify.notify_waiters();
},
} }
#[tracing::instrument(level = "debug", skip(self, revision))]
pub fn add_remote(&self, revision: Revision) -> Result<(), DocError> {
self.rev_cache.write().insert(revision.rev_id, revision);
// self.save_revision(revision.clone());
self.notify.notify_waiters();
Ok(()) Ok(())
} }
pub fn remove(&self, rev_id: i64) -> Result<(), DocError> { pub fn remove(&self, rev_id: i64) -> Result<(), DocError> {
self.rev_cache.write().remove(&rev_id); self.local_rev_cache.write().remove(&rev_id);
// self.delete_revision(rev_id); // self.delete_revision(rev_id);
Ok(()) Ok(())
} }
pub fn rev_notified(&self) -> Notified { self.notify.notified() }
pub fn next_rev_id(&self) -> (i64, i64) {
let cur = self.rev_id_counter.value();
let next = self.rev_id_counter.next();
(cur, next)
}
pub fn rev_id(&self) -> i64 { self.rev_id_counter.value() }
fn save_revision(&self, revision: Revision) { fn save_revision(&self, revision: Revision) {
let op_sql = self.op_sql.clone(); let op_sql = self.op_sql.clone();
let pool = self.pool.clone(); let pool = self.pool.clone();
tokio::spawn(async move { tokio::spawn(async move {
let conn = &*pool.get().map_err(internal_error).unwrap(); let conn = &*pool.get().map_err(internal_error).unwrap();
let result = conn.immediate_transaction::<_, DocError, _>(|| { let result = conn.immediate_transaction::<_, DocError, _>(|| {
let op_table: OpTable = revision.into(); let op_table: RevTable = revision.into();
let _ = op_sql.create_op_table(op_table, conn).unwrap(); let _ = op_sql.create_op_table(op_table, conn).unwrap();
Ok(()) Ok(())
}); });

View File

@ -1,35 +1,35 @@
use crate::{ use crate::{
errors::DocError, errors::DocError,
sql_tables::doc::{OpChangeset, OpTable}, sql_tables::doc::{RevChangeset, RevTable},
}; };
use flowy_database::{ use flowy_database::{
prelude::*, prelude::*,
schema::{op_table, op_table::dsl}, schema::{rev_table, rev_table::dsl},
SqliteConnection, SqliteConnection,
}; };
pub struct OpTableSql {} pub struct OpTableSql {}
impl OpTableSql { impl OpTableSql {
pub(crate) fn create_op_table(&self, op_table: OpTable, conn: &SqliteConnection) -> Result<(), DocError> { pub(crate) fn create_op_table(&self, op_table: RevTable, conn: &SqliteConnection) -> Result<(), DocError> {
let _ = diesel::insert_into(op_table::table).values(op_table).execute(conn)?; let _ = diesel::insert_into(rev_table::table).values(op_table).execute(conn)?;
Ok(()) Ok(())
} }
pub(crate) fn update_op_table(&self, changeset: OpChangeset, conn: &SqliteConnection) -> Result<(), DocError> { pub(crate) fn update_op_table(&self, changeset: RevChangeset, conn: &SqliteConnection) -> Result<(), DocError> {
let filter = dsl::op_table.filter(op_table::dsl::rev_id.eq(changeset.rev_id)); let filter = dsl::rev_table.filter(rev_table::dsl::rev_id.eq(changeset.rev_id));
let affected_row = diesel::update(filter).set(changeset).execute(conn)?; let affected_row = diesel::update(filter).set(changeset).execute(conn)?;
debug_assert_eq!(affected_row, 1); debug_assert_eq!(affected_row, 1);
Ok(()) Ok(())
} }
pub(crate) fn read_op_table(&self, conn: &SqliteConnection) -> Result<Vec<OpTable>, DocError> { pub(crate) fn read_op_table(&self, conn: &SqliteConnection) -> Result<Vec<RevTable>, DocError> {
let ops = dsl::op_table.load::<OpTable>(conn)?; let ops = dsl::rev_table.load::<RevTable>(conn)?;
Ok(ops) Ok(ops)
} }
pub(crate) fn delete_op_table(&self, rev_id: i64, conn: &SqliteConnection) -> Result<(), DocError> { pub(crate) fn delete_op_table(&self, rev_id: i64, conn: &SqliteConnection) -> Result<(), DocError> {
let filter = dsl::op_table.filter(op_table::dsl::rev_id.eq(rev_id)); let filter = dsl::rev_table.filter(rev_table::dsl::rev_id.eq(rev_id));
let affected_row = diesel::delete(filter).execute(conn)?; let affected_row = diesel::delete(filter).execute(conn)?;
debug_assert_eq!(affected_row, 1); debug_assert_eq!(affected_row, 1);
Ok(()) Ok(())

View File

@ -1,68 +1,104 @@
use crate::entities::doc::Revision; use crate::entities::doc::{RevType, Revision};
use diesel::sql_types::Integer; use diesel::sql_types::Integer;
use flowy_database::schema::op_table; use flowy_database::schema::rev_table;
#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
#[table_name = "op_table"] #[table_name = "rev_table"]
#[primary_key(doc_id)] #[primary_key(doc_id)]
pub(crate) struct OpTable { pub(crate) struct RevTable {
pub(crate) doc_id: String, pub(crate) doc_id: String,
pub(crate) base_rev_id: i64, pub(crate) base_rev_id: i64,
pub(crate) rev_id: i64, pub(crate) rev_id: i64,
pub(crate) data: Vec<u8>, pub(crate) data: Vec<u8>,
pub(crate) md5: String, pub(crate) md5: String,
pub(crate) state: OpState, pub(crate) state: RevState,
pub(crate) ty: RevTableType,
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
#[repr(i32)] #[repr(i32)]
#[sql_type = "Integer"] #[sql_type = "Integer"]
pub enum OpState { pub enum RevState {
Local = 0, Local = 0,
Acked = 1, Acked = 1,
} }
impl std::default::Default for OpState { impl std::default::Default for RevState {
fn default() -> Self { OpState::Local } fn default() -> Self { RevState::Local }
} }
impl std::convert::From<i32> for OpState { impl std::convert::From<i32> for RevState {
fn from(value: i32) -> Self { fn from(value: i32) -> Self {
match value { match value {
0 => OpState::Local, 0 => RevState::Local,
1 => OpState::Acked, 1 => RevState::Acked,
o => { o => {
log::error!("Unsupported view type {}, fallback to ViewType::Docs", o); log::error!("Unsupported rev state {}, fallback to RevState::Local", o);
OpState::Local RevState::Local
}, },
} }
} }
} }
impl RevState {
impl OpState {
pub fn value(&self) -> i32 { *self as i32 } pub fn value(&self) -> i32 { *self as i32 }
} }
impl_sql_integer_expression!(RevState);
impl_sql_integer_expression!(OpState); #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
#[repr(i32)]
#[derive(AsChangeset, Identifiable, Default, Debug)] #[sql_type = "Integer"]
#[table_name = "op_table"] pub enum RevTableType {
#[primary_key(doc_id)] Local = 0,
pub(crate) struct OpChangeset { Remote = 1,
pub(crate) doc_id: String,
pub(crate) rev_id: i64,
pub(crate) state: Option<OpState>,
} }
impl std::convert::Into<OpTable> for Revision { impl std::default::Default for RevTableType {
fn into(self) -> OpTable { fn default() -> Self { RevTableType::Local }
OpTable { }
impl std::convert::From<i32> for RevTableType {
fn from(value: i32) -> Self {
match value {
0 => RevTableType::Local,
1 => RevTableType::Remote,
o => {
log::error!("Unsupported rev type {}, fallback to RevTableType::Local", o);
RevTableType::Local
},
}
}
}
impl RevTableType {
pub fn value(&self) -> i32 { *self as i32 }
}
impl_sql_integer_expression!(RevTableType);
#[derive(AsChangeset, Identifiable, Default, Debug)]
#[table_name = "rev_table"]
#[primary_key(doc_id)]
pub(crate) struct RevChangeset {
pub(crate) doc_id: String,
pub(crate) rev_id: i64,
pub(crate) state: Option<RevState>,
}
impl std::convert::Into<RevTable> for Revision {
fn into(self) -> RevTable {
RevTable {
doc_id: self.doc_id, doc_id: self.doc_id,
base_rev_id: self.base_rev_id, base_rev_id: self.base_rev_id,
rev_id: self.rev_id, rev_id: self.rev_id,
data: self.delta, data: self.delta,
md5: self.md5, md5: self.md5,
state: OpState::Local, state: RevState::Local,
ty: rev_ty_to_rev_state(self.ty),
} }
} }
} }
fn rev_ty_to_rev_state(ty: RevType) -> RevTableType {
match ty {
RevType::Local => RevTableType::Local,
RevType::Remote => RevTableType::Remote,
}
}

View File

@ -5,7 +5,7 @@ use flowy_database::schema::doc_table;
#[table_name = "doc_table"] #[table_name = "doc_table"]
pub(crate) struct DocTable { pub(crate) struct DocTable {
pub(crate) id: String, pub(crate) id: String,
pub(crate) data: Vec<u8>, pub(crate) data: String,
pub(crate) revision: i64, pub(crate) revision: i64,
} }
@ -23,7 +23,7 @@ impl DocTable {
#[table_name = "doc_table"] #[table_name = "doc_table"]
pub(crate) struct DocTableChangeset { pub(crate) struct DocTableChangeset {
pub id: String, pub id: String,
pub data: Vec<u8>, pub data: String,
} }
impl DocTableChangeset { impl DocTableChangeset {

View File

@ -7,7 +7,7 @@ fn attributes_bold_added() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Bold(0, Interval::new(3, 5), true), Bold(0, Interval::new(3, 5), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"123"}, {"insert":"123"},
@ -24,9 +24,9 @@ fn attributes_bold_added_and_invert_all() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#),
Bold(0, Interval::new(0, 3), false), Bold(0, Interval::new(0, 3), false),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -36,9 +36,9 @@ fn attributes_bold_added_and_invert_partial_suffix() {
let ops = vec![ let ops = vec![
Insert(0, "1234", 0), Insert(0, "1234", 0),
Bold(0, Interval::new(0, 4), true), Bold(0, Interval::new(0, 4), true),
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
Bold(0, Interval::new(2, 4), false), Bold(0, Interval::new(2, 4), false),
AssertOpsJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#), AssertDocJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -48,11 +48,11 @@ fn attributes_bold_added_and_invert_partial_suffix2() {
let ops = vec![ let ops = vec![
Insert(0, "1234", 0), Insert(0, "1234", 0),
Bold(0, Interval::new(0, 4), true), Bold(0, Interval::new(0, 4), true),
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
Bold(0, Interval::new(2, 4), false), Bold(0, Interval::new(2, 4), false),
AssertOpsJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#), AssertDocJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#),
Bold(0, Interval::new(2, 4), true), Bold(0, Interval::new(2, 4), true),
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -62,19 +62,22 @@ fn attributes_bold_added_with_new_line() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Bold(0, Interval::new(0, 6), true), Bold(0, Interval::new(0, 6), true),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}},{"insert":"\n"}]"#), AssertDocJson(
0,
r#"[{"insert":"123456","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
),
Insert(0, "\n", 3), Insert(0, "\n", 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"},{"insert":"456","attributes":{"bold":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"},{"insert":"456","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
), ),
Insert(0, "\n", 4), Insert(0, "\n", 4),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n\n"},{"insert":"456","attributes":{"bold":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n\n"},{"insert":"456","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
), ),
Insert(0, "a", 4), Insert(0, "a", 4),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\na\n"},{"insert":"456","attributes":{"bold":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\na\n"},{"insert":"456","attributes":{"bold":"true"}},{"insert":"\n"}]"#,
), ),
@ -87,9 +90,9 @@ fn attributes_bold_added_and_invert_partial_prefix() {
let ops = vec![ let ops = vec![
Insert(0, "1234", 0), Insert(0, "1234", 0),
Bold(0, Interval::new(0, 4), true), Bold(0, Interval::new(0, 4), true),
AssertOpsJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"1234","attributes":{"bold":"true"}}]"#),
Bold(0, Interval::new(0, 2), false), Bold(0, Interval::new(0, 2), false),
AssertOpsJson(0, r#"[{"insert":"12"},{"insert":"34","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"12"},{"insert":"34","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -99,9 +102,9 @@ fn attributes_bold_added_consecutive() {
let ops = vec![ let ops = vec![
Insert(0, "1234", 0), Insert(0, "1234", 0),
Bold(0, Interval::new(0, 1), true), Bold(0, Interval::new(0, 1), true),
AssertOpsJson(0, r#"[{"insert":"1","attributes":{"bold":"true"}},{"insert":"234"}]"#), AssertDocJson(0, r#"[{"insert":"1","attributes":{"bold":"true"}},{"insert":"234"}]"#),
Bold(0, Interval::new(1, 2), true), Bold(0, Interval::new(1, 2), true),
AssertOpsJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#), AssertDocJson(0, r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -112,12 +115,12 @@ fn attributes_bold_added_italic() {
Insert(0, "1234", 0), Insert(0, "1234", 0),
Bold(0, Interval::new(0, 4), true), Bold(0, Interval::new(0, 4), true),
Italic(0, Interval::new(0, 4), true), Italic(0, Interval::new(0, 4), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1234","attributes":{"italic":"true","bold":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"1234","attributes":{"italic":"true","bold":"true"}},{"insert":"\n"}]"#,
), ),
Insert(0, "5678", 4), Insert(0, "5678", 4),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"12345678","attributes":{"bold":"true","italic":"true"}},{"insert":"\n"}]"#, r#"[{"insert":"12345678","attributes":{"bold":"true","italic":"true"}},{"insert":"\n"}]"#,
), ),
@ -130,9 +133,9 @@ fn attributes_bold_added_italic2() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Bold(0, Interval::new(0, 6), true), Bold(0, Interval::new(0, 6), true),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Italic(0, Interval::new(0, 2), true), Italic(0, Interval::new(0, 2), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"italic":"true","bold":"true"}}, {"insert":"12","attributes":{"italic":"true","bold":"true"}},
@ -140,7 +143,7 @@ fn attributes_bold_added_italic2() {
"#, "#,
), ),
Italic(0, Interval::new(4, 6), true), Italic(0, Interval::new(4, 6), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"italic":"true","bold":"true"}}, {"insert":"12","attributes":{"italic":"true","bold":"true"}},
@ -159,7 +162,7 @@ fn attributes_bold_added_italic3() {
Insert(0, "123456789", 0), Insert(0, "123456789", 0),
Bold(0, Interval::new(0, 5), true), Bold(0, Interval::new(0, 5), true),
Italic(0, Interval::new(0, 2), true), Italic(0, Interval::new(0, 2), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"bold":"true","italic":"true"}}, {"insert":"12","attributes":{"bold":"true","italic":"true"}},
@ -167,7 +170,7 @@ fn attributes_bold_added_italic3() {
"#, "#,
), ),
Italic(0, Interval::new(2, 4), true), Italic(0, Interval::new(2, 4), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"1234","attributes":{"bold":"true","italic":"true"}}, {"insert":"1234","attributes":{"bold":"true","italic":"true"}},
@ -176,7 +179,7 @@ fn attributes_bold_added_italic3() {
"#, "#,
), ),
Bold(0, Interval::new(7, 9), true), Bold(0, Interval::new(7, 9), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"1234","attributes":{"bold":"true","italic":"true"}}, {"insert":"1234","attributes":{"bold":"true","italic":"true"}},
@ -196,7 +199,7 @@ fn attributes_bold_added_italic_delete() {
Insert(0, "123456789", 0), Insert(0, "123456789", 0),
Bold(0, Interval::new(0, 5), true), Bold(0, Interval::new(0, 5), true),
Italic(0, Interval::new(0, 2), true), Italic(0, Interval::new(0, 2), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"italic":"true","bold":"true"}}, {"insert":"12","attributes":{"italic":"true","bold":"true"}},
@ -204,14 +207,14 @@ fn attributes_bold_added_italic_delete() {
"#, "#,
), ),
Italic(0, Interval::new(2, 4), true), Italic(0, Interval::new(2, 4), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"1234","attributes":{"bold":"true","italic":"true"}} {"insert":"1234","attributes":{"bold":"true","italic":"true"}}
,{"insert":"5","attributes":{"bold":"true"}},{"insert":"6789"}]"#, ,{"insert":"5","attributes":{"bold":"true"}},{"insert":"6789"}]"#,
), ),
Bold(0, Interval::new(7, 9), true), Bold(0, Interval::new(7, 9), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"1234","attributes":{"bold":"true","italic":"true"}}, {"insert":"1234","attributes":{"bold":"true","italic":"true"}},
@ -220,7 +223,7 @@ fn attributes_bold_added_italic_delete() {
"#, "#,
), ),
Delete(0, Interval::new(0, 5)), Delete(0, Interval::new(0, 5)),
AssertOpsJson(0, r#"[{"insert":"67"},{"insert":"89","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"67"},{"insert":"89","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -230,9 +233,9 @@ fn attributes_bold_added_italic_delete() {
fn attributes_merge_inserted_text_with_same_attribute() { fn attributes_merge_inserted_text_with_same_attribute() {
let ops = vec![ let ops = vec![
InsertBold(0, "123", Interval::new(0, 3)), InsertBold(0, "123", Interval::new(0, 3)),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#),
InsertBold(0, "456", Interval::new(3, 6)), InsertBold(0, "456", Interval::new(3, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -241,12 +244,12 @@ fn attributes_merge_inserted_text_with_same_attribute() {
fn attributes_compose_attr_attributes_with_attr_attributes_test() { fn attributes_compose_attr_attributes_with_attr_attributes_test() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
InsertBold(1, "7", Interval::new(0, 1)), InsertBold(1, "7", Interval::new(0, 1)),
AssertOpsJson(1, r#"[{"insert":"7","attributes":{"bold":"true"}}]"#), AssertDocJson(1, r#"[{"insert":"7","attributes":{"bold":"true"}}]"#),
Transform(0, 1), Transform(0, 1),
AssertOpsJson(0, r#"[{"insert":"1234567","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"1234567","attributes":{"bold":"true"}}]"#),
AssertOpsJson(1, r#"[{"insert":"1234567","attributes":{"bold":"true"}}]"#), AssertDocJson(1, r#"[{"insert":"1234567","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -259,7 +262,7 @@ fn attributes_compose_attr_attributes_with_attr_attributes_test2() {
Bold(0, Interval::new(0, 6), true), Bold(0, Interval::new(0, 6), true),
Italic(0, Interval::new(0, 2), true), Italic(0, Interval::new(0, 2), true),
Italic(0, Interval::new(4, 6), true), Italic(0, Interval::new(4, 6), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"bold":"true","italic":"true"}}, {"insert":"12","attributes":{"bold":"true","italic":"true"}},
@ -268,9 +271,9 @@ fn attributes_compose_attr_attributes_with_attr_attributes_test2() {
"#, "#,
), ),
InsertBold(1, "7", Interval::new(0, 1)), InsertBold(1, "7", Interval::new(0, 1)),
AssertOpsJson(1, r#"[{"insert":"7","attributes":{"bold":"true"}}]"#), AssertDocJson(1, r#"[{"insert":"7","attributes":{"bold":"true"}}]"#),
Transform(0, 1), Transform(0, 1),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"italic":"true","bold":"true"}}, {"insert":"12","attributes":{"italic":"true","bold":"true"}},
@ -279,7 +282,7 @@ fn attributes_compose_attr_attributes_with_attr_attributes_test2() {
{"insert":"7","attributes":{"bold":"true"}}] {"insert":"7","attributes":{"bold":"true"}}]
"#, "#,
), ),
AssertOpsJson( AssertDocJson(
1, 1,
r#"[ r#"[
{"insert":"12","attributes":{"italic":"true","bold":"true"}}, {"insert":"12","attributes":{"italic":"true","bold":"true"}},
@ -299,12 +302,12 @@ fn attributes_compose_attr_attributes_with_no_attr_attributes_test() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Insert(1, "7", 0), Insert(1, "7", 0),
AssertOpsJson(1, r#"[{"insert":"7"}]"#), AssertDocJson(1, r#"[{"insert":"7"}]"#),
Transform(0, 1), Transform(0, 1),
AssertOpsJson(0, expected), AssertDocJson(0, expected),
AssertOpsJson(1, expected), AssertDocJson(1, expected),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -313,9 +316,9 @@ fn attributes_compose_attr_attributes_with_no_attr_attributes_test() {
fn attributes_replace_heading() { fn attributes_replace_heading() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Delete(0, Interval::new(0, 2)), Delete(0, Interval::new(0, 2)),
AssertOpsJson(0, r#"[{"insert":"3456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"3456","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -325,9 +328,9 @@ fn attributes_replace_heading() {
fn attributes_replace_trailing() { fn attributes_replace_trailing() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Delete(0, Interval::new(5, 6)), Delete(0, Interval::new(5, 6)),
AssertOpsJson(0, r#"[{"insert":"12345","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"12345","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -337,11 +340,11 @@ fn attributes_replace_trailing() {
fn attributes_replace_middle() { fn attributes_replace_middle() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Delete(0, Interval::new(0, 2)), Delete(0, Interval::new(0, 2)),
AssertOpsJson(0, r#"[{"insert":"3456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"3456","attributes":{"bold":"true"}}]"#),
Delete(0, Interval::new(2, 4)), Delete(0, Interval::new(2, 4)),
AssertOpsJson(0, r#"[{"insert":"34","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"34","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -351,9 +354,9 @@ fn attributes_replace_middle() {
fn attributes_replace_all() { fn attributes_replace_all() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Delete(0, Interval::new(0, 6)), Delete(0, Interval::new(0, 6)),
AssertOpsJson(0, r#"[]"#), AssertDocJson(0, r#"[]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -363,9 +366,9 @@ fn attributes_replace_all() {
fn attributes_replace_with_text() { fn attributes_replace_with_text() {
let ops = vec![ let ops = vec![
InsertBold(0, "123456", Interval::new(0, 6)), InsertBold(0, "123456", Interval::new(0, 6)),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Replace(0, Interval::new(0, 3), "ab"), Replace(0, Interval::new(0, 3), "ab"),
AssertOpsJson(0, r#"[{"insert":"ab"},{"insert":"456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"ab"},{"insert":"456","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
@ -376,9 +379,9 @@ fn attributes_header_insert_newline_at_middle() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Header(0, Interval::new(0, 6), 1), Header(0, Interval::new(0, 6), 1),
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}}]"#), AssertDocJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}}]"#),
Insert(0, "\n", 3), Insert(0, "\n", 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#, r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#,
), ),
@ -393,17 +396,17 @@ fn attributes_header_insert_double_newline_at_middle() {
Insert(0, "123456", 0), Insert(0, "123456", 0),
Header(0, Interval::new(0, 6), 1), Header(0, Interval::new(0, 6), 1),
Insert(0, "\n", 3), Insert(0, "\n", 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#, r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#,
), ),
Insert(0, "\n", 4), Insert(0, "\n", 4),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#, r#"[{"insert":"123"},{"insert":"\n\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#,
), ),
Insert(0, "\n", 4), Insert(0, "\n", 4),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n\n","attributes":{"header":1}},{"insert":"\n456"},{"insert":"\n","attributes":{"header":1}}]"#, r#"[{"insert":"123"},{"insert":"\n\n","attributes":{"header":1}},{"insert":"\n456"},{"insert":"\n","attributes":{"header":1}}]"#,
), ),
@ -418,7 +421,7 @@ fn attributes_header_insert_newline_at_trailing() {
Insert(0, "123456", 0), Insert(0, "123456", 0),
Header(0, Interval::new(0, 6), 1), Header(0, Interval::new(0, 6), 1),
Insert(0, "\n", 6), Insert(0, "\n", 6),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}},{"insert":"\n"}]"#, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}},{"insert":"\n"}]"#,
), ),
@ -434,7 +437,7 @@ fn attributes_header_insert_double_newline_at_trailing() {
Header(0, Interval::new(0, 6), 1), Header(0, Interval::new(0, 6), 1),
Insert(0, "\n", 6), Insert(0, "\n", 6),
Insert(0, "\n", 7), Insert(0, "\n", 7),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}},{"insert":"\n\n"}]"#, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}},{"insert":"\n\n"}]"#,
), ),
@ -448,7 +451,7 @@ fn attributes_link_added() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Link(0, Interval::new(0, 6), "https://appflowy.io"), Link(0, Interval::new(0, 6), "https://appflowy.io"),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
@ -463,7 +466,7 @@ fn attributes_link_format_with_bold() {
Insert(0, "123456", 0), Insert(0, "123456", 0),
Link(0, Interval::new(0, 6), "https://appflowy.io"), Link(0, Interval::new(0, 6), "https://appflowy.io"),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"123","attributes":{"bold":"true","link":"https://appflowy.io"}}, {"insert":"123","attributes":{"bold":"true","link":"https://appflowy.io"}},
@ -481,12 +484,12 @@ fn attributes_link_insert_char_at_head() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Link(0, Interval::new(0, 6), "https://appflowy.io"), Link(0, Interval::new(0, 6), "https://appflowy.io"),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
Insert(0, "a", 0), Insert(0, "a", 0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"a"},{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"a"},{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
@ -501,7 +504,7 @@ fn attributes_link_insert_char_at_middle() {
Insert(0, "1256", 0), Insert(0, "1256", 0),
Link(0, Interval::new(0, 4), "https://appflowy.io"), Link(0, Interval::new(0, 4), "https://appflowy.io"),
Insert(0, "34", 2), Insert(0, "34", 2),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
@ -515,12 +518,12 @@ fn attributes_link_insert_char_at_trailing() {
let ops = vec![ let ops = vec![
Insert(0, "123456", 0), Insert(0, "123456", 0),
Link(0, Interval::new(0, 6), "https://appflowy.io"), Link(0, Interval::new(0, 6), "https://appflowy.io"),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
Insert(0, "a", 6), Insert(0, "a", 6),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"a\n"}]"#, r#"[{"insert":"123456","attributes":{"link":"https://appflowy.io"}},{"insert":"a\n"}]"#,
), ),
@ -535,7 +538,7 @@ fn attributes_link_insert_newline_at_middle() {
Insert(0, "123456", 0), Insert(0, "123456", 0),
Link(0, Interval::new(0, 6), "https://appflowy.io"), Link(0, Interval::new(0, 6), "https://appflowy.io"),
Insert(0, NEW_LINE, 3), Insert(0, NEW_LINE, 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"},{"insert":"456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"123","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"},{"insert":"456","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
@ -549,9 +552,9 @@ fn attributes_link_auto_format() {
let site = "https://appflowy.io"; let site = "https://appflowy.io";
let ops = vec![ let ops = vec![
Insert(0, site, 0), Insert(0, site, 0),
AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#), AssertDocJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#),
Insert(0, WHITESPACE, site.len()), Insert(0, WHITESPACE, site.len()),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#, r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#,
), ),
@ -567,7 +570,7 @@ fn attributes_link_auto_format_exist() {
Insert(0, site, 0), Insert(0, site, 0),
Link(0, Interval::new(0, site.len()), site), Link(0, Interval::new(0, site.len()), site),
Insert(0, WHITESPACE, site.len()), Insert(0, WHITESPACE, site.len()),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#, r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#,
), ),
@ -583,7 +586,7 @@ fn attributes_link_auto_format_exist2() {
Insert(0, site, 0), Insert(0, site, 0),
Link(0, Interval::new(0, site.len() / 2), site), Link(0, Interval::new(0, site.len() / 2), site),
Insert(0, WHITESPACE, site.len()), Insert(0, WHITESPACE, site.len()),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"https://a","attributes":{"link":"https://appflowy.io"}},{"insert":"ppflowy.io \n"}]"#, r#"[{"insert":"https://a","attributes":{"link":"https://appflowy.io"}},{"insert":"ppflowy.io \n"}]"#,
), ),
@ -597,7 +600,7 @@ fn attributes_bullet_added() {
let ops = vec![ let ops = vec![
Insert(0, "12", 0), Insert(0, "12", 0),
Bullet(0, Interval::new(0, 1), true), Bullet(0, Interval::new(0, 1), true),
AssertOpsJson(0, r#"[{"insert":"12"},{"insert":"\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(0, r#"[{"insert":"12"},{"insert":"\n","attributes":{"list":"bullet"}}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
@ -608,11 +611,14 @@ fn attributes_bullet_added_2() {
let ops = vec![ let ops = vec![
Insert(0, "1", 0), Insert(0, "1", 0),
Bullet(0, Interval::new(0, 1), true), Bullet(0, Interval::new(0, 1), true),
AssertOpsJson(0, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(0, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}}]"#),
Insert(0, NEW_LINE, 1), Insert(0, NEW_LINE, 1),
AssertOpsJson(0, r#"[{"insert":"1"},{"insert":"\n\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(
0,
r#"[{"insert":"1"},{"insert":"\n\n","attributes":{"list":"bullet"}}]"#,
),
Insert(0, "2", 2), Insert(0, "2", 2),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
@ -629,7 +635,7 @@ fn attributes_bullet_remove_partial() {
Insert(0, NEW_LINE, 1), Insert(0, NEW_LINE, 1),
Insert(0, "2", 2), Insert(0, "2", 2),
Bullet(0, Interval::new(2, 3), false), Bullet(0, Interval::new(2, 3), false),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2\n"}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2\n"}]"#,
), ),
@ -645,7 +651,7 @@ fn attributes_bullet_auto_exit() {
Bullet(0, Interval::new(0, 1), true), Bullet(0, Interval::new(0, 1), true),
Insert(0, NEW_LINE, 1), Insert(0, NEW_LINE, 1),
Insert(0, NEW_LINE, 2), Insert(0, NEW_LINE, 2),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"\n"}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"\n"}]"#,
), ),
@ -660,9 +666,12 @@ fn attributes_preserve_block_when_insert_newline_inside() {
Insert(0, "12", 0), Insert(0, "12", 0),
Bullet(0, Interval::new(0, 2), true), Bullet(0, Interval::new(0, 2), true),
Insert(0, NEW_LINE, 2), Insert(0, NEW_LINE, 2),
AssertOpsJson(0, r#"[{"insert":"12"},{"insert":"\n\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(
0,
r#"[{"insert":"12"},{"insert":"\n\n","attributes":{"list":"bullet"}}]"#,
),
Insert(0, "34", 3), Insert(0, "34", 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12"},{"insert":"\n","attributes":{"list":"bullet"}}, {"insert":"12"},{"insert":"\n","attributes":{"list":"bullet"}},
@ -670,7 +679,7 @@ fn attributes_preserve_block_when_insert_newline_inside() {
]"#, ]"#,
), ),
Insert(0, NEW_LINE, 3), Insert(0, NEW_LINE, 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12"},{"insert":"\n\n","attributes":{"list":"bullet"}}, {"insert":"12"},{"insert":"\n\n","attributes":{"list":"bullet"}},
@ -678,7 +687,7 @@ fn attributes_preserve_block_when_insert_newline_inside() {
]"#, ]"#,
), ),
Insert(0, "ab", 3), Insert(0, "ab", 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12"},{"insert":"\n","attributes":{"list":"bullet"}}, {"insert":"12"},{"insert":"\n","attributes":{"list":"bullet"}},
@ -697,12 +706,12 @@ fn attributes_preserve_header_format_on_merge() {
Insert(0, "123456", 0), Insert(0, "123456", 0),
Header(0, Interval::new(0, 6), 1), Header(0, Interval::new(0, 6), 1),
Insert(0, NEW_LINE, 3), Insert(0, NEW_LINE, 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#, r#"[{"insert":"123"},{"insert":"\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#,
), ),
Delete(0, Interval::new(3, 4)), Delete(0, Interval::new(3, 4)),
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}}]"#), AssertDocJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"header":1}}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
@ -714,12 +723,15 @@ fn attributes_preserve_list_format_on_merge() {
Insert(0, "123456", 0), Insert(0, "123456", 0),
Bullet(0, Interval::new(0, 6), true), Bullet(0, Interval::new(0, 6), true),
Insert(0, NEW_LINE, 3), Insert(0, NEW_LINE, 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"123"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
Delete(0, Interval::new(3, 4)), Delete(0, Interval::new(3, 4)),
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(
0,
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);

View File

@ -45,6 +45,9 @@ pub enum TestOp {
#[display(fmt = "Transform")] #[display(fmt = "Transform")]
Transform(usize, usize), Transform(usize, usize),
#[display(fmt = "TransformPrime")]
TransformPrime(usize, usize),
// invert the delta_a base on the delta_b // invert the delta_a base on the delta_b
#[display(fmt = "Invert")] #[display(fmt = "Invert")]
Invert(usize, usize), Invert(usize, usize),
@ -61,12 +64,23 @@ pub enum TestOp {
#[display(fmt = "AssertStr")] #[display(fmt = "AssertStr")]
AssertStr(usize, &'static str), AssertStr(usize, &'static str),
#[display(fmt = "AssertOpsJson")] #[display(fmt = "AssertDocJson")]
AssertOpsJson(usize, &'static str), AssertDocJson(usize, &'static str),
#[display(fmt = "AssertPrimeJson")]
AssertPrimeJson(usize, &'static str),
#[display(fmt = "DocComposeDelta")]
DocComposeDelta(usize, usize),
#[display(fmt = "ApplyPrimeDelta")]
DocComposePrime(usize, usize),
} }
pub struct TestBuilder { pub struct TestBuilder {
documents: Vec<Document>, documents: Vec<Document>,
deltas: Vec<Option<Delta>>,
primes: Vec<Option<Delta>>,
} }
impl TestBuilder { impl TestBuilder {
@ -78,7 +92,11 @@ impl TestBuilder {
env_logger::init(); env_logger::init();
}); });
Self { documents: vec![] } Self {
documents: vec![],
deltas: vec![],
primes: vec![],
}
} }
fn run_op(&mut self, op: &TestOp) { fn run_op(&mut self, op: &TestOp) {
@ -86,15 +104,18 @@ impl TestBuilder {
match op { match op {
TestOp::Insert(delta_i, s, index) => { TestOp::Insert(delta_i, s, index) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
document.insert(*index, s).unwrap(); let delta = document.insert(*index, s).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Delete(delta_i, iv) => { TestOp::Delete(delta_i, iv) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
document.replace(*iv, "").unwrap(); let delta = document.replace(*iv, "").unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Replace(delta_i, iv, s) => { TestOp::Replace(delta_i, iv, s) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
document.replace(*iv, s).unwrap(); let delta = document.replace(*iv, s).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::InsertBold(delta_i, s, iv) => { TestOp::InsertBold(delta_i, s, iv) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
@ -104,7 +125,8 @@ impl TestBuilder {
TestOp::Bold(delta_i, iv, enable) => { TestOp::Bold(delta_i, iv, enable) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
let attribute = Attribute::Bold(*enable); let attribute = Attribute::Bold(*enable);
document.format(*iv, attribute).unwrap(); let delta = document.format(*iv, attribute).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Italic(delta_i, iv, enable) => { TestOp::Italic(delta_i, iv, enable) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
@ -112,22 +134,26 @@ impl TestBuilder {
true => Attribute::Italic(true), true => Attribute::Italic(true),
false => Attribute::Italic(false), false => Attribute::Italic(false),
}; };
document.format(*iv, attribute).unwrap(); let delta = document.format(*iv, attribute).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Header(delta_i, iv, level) => { TestOp::Header(delta_i, iv, level) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
let attribute = Attribute::Header(*level); let attribute = Attribute::Header(*level);
document.format(*iv, attribute).unwrap(); let delta = document.format(*iv, attribute).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Link(delta_i, iv, link) => { TestOp::Link(delta_i, iv, link) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
let attribute = Attribute::Link(link.to_owned()); let attribute = Attribute::Link(link.to_owned());
document.format(*iv, attribute).unwrap(); let delta = document.format(*iv, attribute).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Bullet(delta_i, iv, enable) => { TestOp::Bullet(delta_i, iv, enable) => {
let document = &mut self.documents[*delta_i]; let document = &mut self.documents[*delta_i];
let attribute = Attribute::Bullet(*enable); let attribute = Attribute::Bullet(*enable);
document.format(*iv, attribute).unwrap(); let delta = document.format(*iv, attribute).unwrap();
self.deltas.insert(*delta_i, Some(delta));
}, },
TestOp::Transform(delta_a_i, delta_b_i) => { TestOp::Transform(delta_a_i, delta_b_i) => {
let (a_prime, b_prime) = self.documents[*delta_a_i] let (a_prime, b_prime) = self.documents[*delta_a_i]
@ -142,6 +168,15 @@ impl TestBuilder {
self.documents[*delta_a_i].set_delta(data_left); self.documents[*delta_a_i].set_delta(data_left);
self.documents[*delta_b_i].set_delta(data_right); self.documents[*delta_b_i].set_delta(data_right);
}, },
TestOp::TransformPrime(a_doc_index, b_doc_index) => {
let (prime_left, prime_right) = self.documents[*a_doc_index]
.delta()
.transform(&self.documents[*b_doc_index].delta())
.unwrap();
self.primes.insert(*a_doc_index, Some(prime_left));
self.primes.insert(*b_doc_index, Some(prime_right));
},
TestOp::Invert(delta_a_i, delta_b_i) => { TestOp::Invert(delta_a_i, delta_b_i) => {
let delta_a = &self.documents[*delta_a_i].delta(); let delta_a = &self.documents[*delta_a_i].delta();
let delta_b = &self.documents[*delta_b_i].delta(); let delta_b = &self.documents[*delta_b_i].delta();
@ -177,22 +212,50 @@ impl TestBuilder {
assert_eq!(&self.documents[*delta_i].to_plain_string(), expected); assert_eq!(&self.documents[*delta_i].to_plain_string(), expected);
}, },
TestOp::AssertOpsJson(delta_i, expected) => { TestOp::AssertDocJson(delta_i, expected) => {
let delta_i_json = self.documents[*delta_i].to_json(); let delta_json = self.documents[*delta_i].to_json();
let expected_delta: Delta = serde_json::from_str(expected).unwrap(); let expected_delta: Delta = serde_json::from_str(expected).unwrap();
let target_delta: Delta = serde_json::from_str(&delta_i_json).unwrap(); let target_delta: Delta = serde_json::from_str(&delta_json).unwrap();
if expected_delta != target_delta { if expected_delta != target_delta {
log::error!("✅ expect: {}", expected,); log::error!("✅ expect: {}", expected,);
log::error!("❌ receive: {}", delta_i_json); log::error!("❌ receive: {}", delta_json);
} }
assert_eq!(target_delta, expected_delta); assert_eq!(target_delta, expected_delta);
}, },
TestOp::AssertPrimeJson(doc_i, expected) => {
let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json();
let expected_prime: Delta = serde_json::from_str(expected).unwrap();
let target_prime: Delta = serde_json::from_str(&prime_json).unwrap();
if expected_prime != target_prime {
log::error!("✅ expect prime: {}", expected,);
log::error!("❌ receive prime: {}", prime_json);
}
assert_eq!(target_prime, expected_prime);
},
TestOp::DocComposeDelta(doc_index, delta_i) => {
let delta = self.deltas.get(*delta_i).unwrap().as_ref().unwrap();
self.documents[*doc_index].compose_delta(delta);
},
TestOp::DocComposePrime(doc_index, prime_i) => {
let delta = self
.primes
.get(*prime_i)
.expect("Must call TransformPrime first")
.as_ref()
.unwrap();
let new_delta = self.documents[*doc_index].delta().compose(delta).unwrap();
self.documents[*doc_index].set_delta(new_delta);
},
} }
} }
pub fn run_script<C: CustomDocument>(mut self, script: Vec<TestOp>) { pub fn run_script<C: CustomDocument>(mut self, script: Vec<TestOp>) {
self.documents = vec![Document::new::<C>(), Document::new::<C>()]; self.documents = vec![Document::new::<C>(), Document::new::<C>()];
self.primes = vec![None, None];
self.deltas = vec![None, None];
for (_i, op) in script.iter().enumerate() { for (_i, op) in script.iter().enumerate() {
self.run_op(op); self.run_op(op);
} }

View File

@ -8,7 +8,7 @@ fn attributes_insert_text() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
Insert(0, "456", 3), Insert(0, "456", 3),
AssertOpsJson(0, r#"[{"insert":"123456"}]"#), AssertDocJson(0, r#"[{"insert":"123456"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -18,7 +18,7 @@ fn attributes_insert_text_at_head() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
Insert(0, "456", 0), Insert(0, "456", 0),
AssertOpsJson(0, r#"[{"insert":"456123"}]"#), AssertDocJson(0, r#"[{"insert":"456123"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -28,7 +28,7 @@ fn attributes_insert_text_at_middle() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
Insert(0, "456", 1), Insert(0, "456", 1),
AssertOpsJson(0, r#"[{"insert":"145623"}]"#), AssertDocJson(0, r#"[{"insert":"145623"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -69,7 +69,10 @@ fn delta_get_ops_in_interval_2() {
vec![OpBuilder::insert("23").build()] vec![OpBuilder::insert("23").build()]
); );
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(), vec![insert_a.clone()]); assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(),
vec![insert_a.clone()]
);
assert_eq!( assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(0, 4)).ops(), DeltaIter::from_interval(&delta, Interval::new(0, 4)).ops(),
@ -109,9 +112,18 @@ fn delta_get_ops_in_interval_4() {
delta.ops.push(insert_b.clone()); delta.ops.push(insert_b.clone());
delta.ops.push(insert_c.clone()); delta.ops.push(insert_c.clone());
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(), vec![insert_a]); assert_eq!(
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(2, 4)).ops(), vec![insert_b]); DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(),
assert_eq!(DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(), vec![insert_c]); vec![insert_a]
);
assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(2, 4)).ops(),
vec![insert_b]
);
assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(),
vec![insert_c]
);
assert_eq!( assert_eq!(
DeltaIter::from_interval(&delta, Interval::new(2, 5)).ops(), DeltaIter::from_interval(&delta, Interval::new(2, 5)).ops(),
@ -443,7 +455,7 @@ fn compose() {
} }
} }
#[test] #[test]
fn transform() { fn transform_random_delta() {
for _ in 0..1000 { for _ in 0..1000 {
let mut rng = Rng::default(); let mut rng = Rng::default();
let s = rng.gen_string(20); let s = rng.gen_string(20);
@ -461,19 +473,7 @@ fn transform() {
} }
#[test] #[test]
fn transform2() { fn transform_with_two_delta_test() {
let ops = vec![
Insert(0, "123", 0),
Insert(1, "456", 0),
Transform(0, 1),
AssertOpsJson(0, r#"[{"insert":"123456"}]"#),
AssertOpsJson(1, r#"[{"insert":"123456"}]"#),
];
TestBuilder::new().run_script::<PlainDoc>(ops);
}
#[test]
fn delta_transform_test() {
let mut a = Delta::default(); let mut a = Delta::default();
let mut a_s = String::new(); let mut a_s = String::new();
a.insert("123", AttributeBuilder::new().add(Attribute::Bold(true)).build()); a.insert("123", AttributeBuilder::new().add(Attribute::Bold(true)).build());
@ -509,6 +509,65 @@ fn delta_transform_test() {
); );
} }
#[test]
fn transform_two_plain_delta_test() {
let ops = vec![
Insert(0, "123", 0),
Insert(1, "456", 0),
Transform(0, 1),
AssertDocJson(0, r#"[{"insert":"123456"}]"#),
AssertDocJson(1, r#"[{"insert":"123456"}]"#),
];
TestBuilder::new().run_script::<PlainDoc>(ops);
}
#[test]
fn transform_two_plain_delta_test2() {
let ops = vec![
Insert(0, "123", 0),
Insert(1, "456", 0),
TransformPrime(0, 1),
DocComposePrime(0, 1),
DocComposePrime(1, 0),
AssertDocJson(0, r#"[{"insert":"123456"}]"#),
AssertDocJson(1, r#"[{"insert":"123456"}]"#),
];
TestBuilder::new().run_script::<PlainDoc>(ops);
}
#[test]
fn transform_two_non_seq_delta() {
let ops = vec![
Insert(0, "123", 0),
Insert(1, "456", 0),
TransformPrime(0, 1),
AssertPrimeJson(0, r#"[{"insert":"123"},{"retain":3}]"#),
AssertPrimeJson(1, r#"[{"retain":3},{"insert":"456"}]"#),
DocComposePrime(0, 1),
Insert(1, "78", 3),
Insert(1, "9", 5),
DocComposePrime(1, 0),
AssertDocJson(0, r#"[{"insert":"123456"}]"#),
AssertDocJson(1, r#"[{"insert":"123456789"}]"#),
];
TestBuilder::new().run_script::<PlainDoc>(ops);
}
#[test]
fn transform_two_conflict_non_seq_delta() {
let ops = vec![
Insert(0, "123", 0),
Insert(1, "456", 0),
TransformPrime(0, 1),
DocComposePrime(0, 1),
Insert(1, "78", 0),
DocComposePrime(1, 0),
AssertDocJson(0, r#"[{"insert":"123456"}]"#),
AssertDocJson(1, r#"[{"insert":"12378456"}]"#),
];
TestBuilder::new().run_script::<PlainDoc>(ops);
}
#[test] #[test]
fn delta_invert_no_attribute_delta() { fn delta_invert_no_attribute_delta() {
let mut delta = Delta::default(); let mut delta = Delta::default();
@ -531,7 +590,7 @@ fn delta_invert_no_attribute_delta2() {
Insert(0, "123", 0), Insert(0, "123", 0),
Insert(1, "4567", 0), Insert(1, "4567", 0),
Invert(0, 1), Invert(0, 1),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -541,10 +600,10 @@ fn delta_invert_attribute_delta_with_no_attribute_delta() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#),
Insert(1, "4567", 0), Insert(1, "4567", 0),
Invert(0, 1), Invert(0, 1),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -555,14 +614,14 @@ fn delta_invert_attribute_delta_with_no_attribute_delta2() {
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Insert(0, "456", 3), Insert(0, "456", 3),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"123456","attributes":{"bold":"true"}}] {"insert":"123456","attributes":{"bold":"true"}}]
"#, "#,
), ),
Italic(0, Interval::new(2, 4), true), Italic(0, Interval::new(2, 4), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"bold":"true"}}, {"insert":"12","attributes":{"bold":"true"}},
@ -572,7 +631,7 @@ fn delta_invert_attribute_delta_with_no_attribute_delta2() {
), ),
Insert(1, "abc", 0), Insert(1, "abc", 0),
Invert(0, 1), Invert(0, 1),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"bold":"true"}}, {"insert":"12","attributes":{"bold":"true"}},
@ -590,9 +649,9 @@ fn delta_invert_no_attribute_delta_with_attribute_delta() {
Insert(0, "123", 0), Insert(0, "123", 0),
Insert(1, "4567", 0), Insert(1, "4567", 0),
Bold(1, Interval::new(0, 3), true), Bold(1, Interval::new(0, 3), true),
AssertOpsJson(1, r#"[{"insert":"456","attributes":{"bold":"true"}},{"insert":"7"}]"#), AssertDocJson(1, r#"[{"insert":"456","attributes":{"bold":"true"}},{"insert":"7"}]"#),
Invert(0, 1), Invert(0, 1),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -601,19 +660,17 @@ fn delta_invert_no_attribute_delta_with_attribute_delta() {
fn delta_invert_no_attribute_delta_with_attribute_delta2() { fn delta_invert_no_attribute_delta_with_attribute_delta2() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
Insert(1, "abc", 0), Insert(1, "abc", 0),
Bold(1, Interval::new(0, 3), true), Bold(1, Interval::new(0, 3), true),
Insert(1, "d", 3), Insert(1, "d", 3),
Italic(1, Interval::new(1, 3), true), Italic(1, Interval::new(1, 3), true),
AssertOpsJson( AssertDocJson(
1, 1,
r#"[{"insert":"a","attributes":{"bold":"true"}},{"insert":"bc","attributes": r#"[{"insert":"a","attributes":{"bold":"true"}},{"insert":"bc","attributes":{"bold":"true","italic":"true"}},{"insert":"d","attributes":{"bold":"true"}}]"#,
{"bold":"true","italic":"true"}},{"insert":"d","attributes":{"bold":"true"
}}]"#,
), ),
Invert(0, 1), Invert(0, 1),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -624,9 +681,9 @@ fn delta_invert_attribute_delta_with_attribute_delta() {
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Insert(0, "456", 3), Insert(0, "456", 3),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#), AssertDocJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Italic(0, Interval::new(2, 4), true), Italic(0, Interval::new(2, 4), true),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"bold":"true"}}, {"insert":"12","attributes":{"bold":"true"}},
@ -638,7 +695,7 @@ fn delta_invert_attribute_delta_with_attribute_delta() {
Bold(1, Interval::new(0, 3), true), Bold(1, Interval::new(0, 3), true),
Insert(1, "d", 3), Insert(1, "d", 3),
Italic(1, Interval::new(1, 3), true), Italic(1, Interval::new(1, 3), true),
AssertOpsJson( AssertDocJson(
1, 1,
r#"[ r#"[
{"insert":"a","attributes":{"bold":"true"}}, {"insert":"a","attributes":{"bold":"true"}},
@ -647,7 +704,7 @@ fn delta_invert_attribute_delta_with_attribute_delta() {
]"#, ]"#,
), ),
Invert(0, 1), Invert(0, 1),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"12","attributes":{"bold":"true"}}, {"insert":"12","attributes":{"bold":"true"}},

View File

@ -4,7 +4,7 @@ use flowy_ot::core::{Interval, NEW_LINE, WHITESPACE};
#[test] #[test]
fn history_insert_undo() { fn history_insert_undo() {
let ops = vec![Insert(0, "123", 0), Undo(0), AssertOpsJson(0, r#"[{"insert":"\n"}]"#)]; let ops = vec![Insert(0, "123", 0), Undo(0), AssertDocJson(0, r#"[{"insert":"\n"}]"#)];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -15,9 +15,9 @@ fn history_insert_undo_with_lagging() {
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Insert(0, "456", 0), Insert(0, "456", 0),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -26,11 +26,11 @@ fn history_insert_undo_with_lagging() {
fn history_insert_redo() { fn history_insert_redo() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -43,13 +43,13 @@ fn history_insert_redo_with_lagging() {
Insert(0, "456", 3), Insert(0, "456", 3),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
AssertStr(0, "123456\n"), AssertStr(0, "123456\n"),
AssertOpsJson(0, r#"[{"insert":"123456\n"}]"#), AssertDocJson(0, r#"[{"insert":"123456\n"}]"#),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson(0, r#"[{"insert":"123456\n"}]"#), AssertDocJson(0, r#"[{"insert":"123456\n"}]"#),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -60,7 +60,7 @@ fn history_bold_undo() {
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -72,7 +72,7 @@ fn history_bold_undo_with_lagging() {
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -83,9 +83,9 @@ fn history_bold_redo() {
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson(0, r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#), AssertDocJson(0, r#" [{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -97,9 +97,9 @@ fn history_bold_redo_with_lagging() {
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123\n"}]"#), AssertDocJson(0, r#"[{"insert":"123\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -108,11 +108,11 @@ fn history_bold_redo_with_lagging() {
fn history_delete_undo() { fn history_delete_undo() {
let ops = vec![ let ops = vec![
Insert(0, "123", 0), Insert(0, "123", 0),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
Delete(0, Interval::new(0, 3)), Delete(0, Interval::new(0, 3)),
AssertOpsJson(0, r#"[]"#), AssertDocJson(0, r#"[]"#),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123"}]"#), AssertDocJson(0, r#"[{"insert":"123"}]"#),
]; ];
TestBuilder::new().run_script::<PlainDoc>(ops); TestBuilder::new().run_script::<PlainDoc>(ops);
} }
@ -123,7 +123,7 @@ fn history_delete_undo_2() {
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Delete(0, Interval::new(0, 1)), Delete(0, Interval::new(0, 1)),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"23","attributes":{"bold":"true"}}, {"insert":"23","attributes":{"bold":"true"}},
@ -131,7 +131,7 @@ fn history_delete_undo_2() {
"#, "#,
), ),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -144,7 +144,7 @@ fn history_delete_undo_with_lagging() {
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Delete(0, Interval::new(0, 1)), Delete(0, Interval::new(0, 1)),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"23","attributes":{"bold":"true"}}, {"insert":"23","attributes":{"bold":"true"}},
@ -152,7 +152,7 @@ fn history_delete_undo_with_lagging() {
"#, "#,
), ),
Undo(0), Undo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"123","attributes":{"bold":"true"}}, {"insert":"123","attributes":{"bold":"true"}},
@ -169,10 +169,10 @@ fn history_delete_redo() {
Insert(0, "123", 0), Insert(0, "123", 0),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Delete(0, Interval::new(0, 3)), Delete(0, Interval::new(0, 3)),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
Undo(0), Undo(0),
Redo(0), Redo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -183,7 +183,7 @@ fn history_replace_undo() {
Insert(0, "123", 0), Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Replace(0, Interval::new(0, 2), "ab"), Replace(0, Interval::new(0, 2), "ab"),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"ab"}, {"insert":"ab"},
@ -191,7 +191,7 @@ fn history_replace_undo() {
"#, "#,
), ),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -204,7 +204,7 @@ fn history_replace_undo_with_lagging() {
Bold(0, Interval::new(0, 3), true), Bold(0, Interval::new(0, 3), true),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Replace(0, Interval::new(0, 2), "ab"), Replace(0, Interval::new(0, 2), "ab"),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"ab"}, {"insert":"ab"},
@ -212,7 +212,7 @@ fn history_replace_undo_with_lagging() {
"#, "#,
), ),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}},{"insert":"\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
} }
@ -225,7 +225,7 @@ fn history_replace_redo() {
Replace(0, Interval::new(0, 2), "ab"), Replace(0, Interval::new(0, 2), "ab"),
Undo(0), Undo(0),
Redo(0), Redo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[ r#"[
{"insert":"ab"}, {"insert":"ab"},
@ -244,9 +244,9 @@ fn history_header_added_undo() {
Insert(0, "\n", 3), Insert(0, "\n", 3),
Insert(0, "\n", 4), Insert(0, "\n", 4),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#, r#"[{"insert":"123"},{"insert":"\n\n","attributes":{"header":1}},{"insert":"456"},{"insert":"\n","attributes":{"header":1}}]"#,
), ),
@ -263,9 +263,9 @@ fn history_link_added_undo() {
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Link(0, Interval::new(0, site.len()), site), Link(0, Interval::new(0, site.len()), site),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#), AssertDocJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#, r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io"}},{"insert":"\n"}]"#,
), ),
@ -279,15 +279,15 @@ fn history_link_auto_format_undo_with_lagging() {
let site = "https://appflowy.io"; let site = "https://appflowy.io";
let ops = vec![ let ops = vec![
Insert(0, site, 0), Insert(0, site, 0),
AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#), AssertDocJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Insert(0, WHITESPACE, site.len()), Insert(0, WHITESPACE, site.len()),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#, r#"[{"insert":"https://appflowy.io","attributes":{"link":"https://appflowy.io/"}},{"insert":" \n"}]"#,
), ),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#), AssertDocJson(0, r#"[{"insert":"https://appflowy.io\n"}]"#),
]; ];
TestBuilder::new().run_script::<FlowyDoc>(ops); TestBuilder::new().run_script::<FlowyDoc>(ops);
@ -300,14 +300,14 @@ fn history_bullet_undo() {
Bullet(0, Interval::new(0, 1), true), Bullet(0, Interval::new(0, 1), true),
Insert(0, NEW_LINE, 1), Insert(0, NEW_LINE, 1),
Insert(0, "2", 2), Insert(0, "2", 2),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
Redo(0), Redo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
@ -325,17 +325,17 @@ fn history_bullet_undo_with_lagging() {
Insert(0, NEW_LINE, 1), Insert(0, NEW_LINE, 1),
Insert(0, "2", 2), Insert(0, "2", 2),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(0, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}}]"#),
Undo(0), Undo(0),
AssertOpsJson(0, r#"[{"insert":"\n"}]"#), AssertDocJson(0, r#"[{"insert":"\n"}]"#),
Redo(0), Redo(0),
Redo(0), Redo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"1"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"2"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
@ -352,14 +352,17 @@ fn history_undo_attribute_on_merge_between_line() {
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
Insert(0, NEW_LINE, 3), Insert(0, NEW_LINE, 3),
Wait(RECORD_THRESHOLD), Wait(RECORD_THRESHOLD),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"123"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),
Delete(0, Interval::new(3, 4)), // delete the newline Delete(0, Interval::new(3, 4)), // delete the newline
AssertOpsJson(0, r#"[{"insert":"123456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#), AssertDocJson(
0,
r#"[{"insert":"123456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
),
Undo(0), Undo(0),
AssertOpsJson( AssertDocJson(
0, 0,
r#"[{"insert":"123"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#, r#"[{"insert":"123"},{"insert":"\n","attributes":{"list":"bullet"}},{"insert":"456"},{"insert":"\n","attributes":{"list":"bullet"}}]"#,
), ),

View File

@ -48,10 +48,7 @@ impl std::convert::TryFrom<Vec<u8>> for Delta {
impl std::convert::TryFrom<Bytes> for Delta { impl std::convert::TryFrom<Bytes> for Delta {
type Error = OTError; type Error = OTError;
fn try_from(value: Bytes) -> Result<Self, Self::Error> { fn try_from(bytes: Bytes) -> Result<Self, Self::Error> { Delta::from_bytes(&bytes) }
let bytes = value.to_vec();
Delta::from_bytes(bytes)
}
} }
// impl<T: AsRef<Vec<u8>>> std::convert::From<T> for Delta { // impl<T: AsRef<Vec<u8>>> std::convert::From<T> for Delta {
@ -94,8 +91,8 @@ impl Delta {
pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or("".to_owned()) } pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or("".to_owned()) }
pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, OTError> { pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, OTError> {
let json = str::from_utf8(&bytes)?; let json = str::from_utf8(bytes.as_ref())?;
Self::from_json(json) Self::from_json(json)
} }
@ -271,8 +268,12 @@ impl OperationTransformable for Delta {
other_iter.next_op_len().unwrap_or(MAX_IV_LEN), other_iter.next_op_len().unwrap_or(MAX_IV_LEN),
); );
let op = iter.next_op_with_len(length).unwrap_or(OpBuilder::retain(length).build()); let op = iter
let other_op = other_iter.next_op_with_len(length).unwrap_or(OpBuilder::retain(length).build()); .next_op_with_len(length)
.unwrap_or(OpBuilder::retain(length).build());
let other_op = other_iter
.next_op_with_len(length)
.unwrap_or(OpBuilder::retain(length).build());
debug_assert_eq!(op.len(), other_op.len()); debug_assert_eq!(op.len(), other_op.len());

View File

@ -65,10 +65,11 @@ pub struct CreateViewParams {
pub view_type: ViewType, pub view_type: ViewType,
#[pb(index = 6)] #[pb(index = 6)]
pub data: Vec<u8>, pub data: String,
} }
const VIEW_DEFAULT_DATA: &str = "[{\"insert\":\"\\n\"}]"; pub const VIEW_DEFAULT_DATA: &str = "[{\"insert\":\"\\n\"}]";
#[allow(dead_code)]
pub fn default_delta() -> Vec<u8> { VIEW_DEFAULT_DATA.as_bytes().to_vec() } pub fn default_delta() -> Vec<u8> { VIEW_DEFAULT_DATA.as_bytes().to_vec() }
impl CreateViewParams { impl CreateViewParams {
@ -79,7 +80,7 @@ impl CreateViewParams {
desc, desc,
thumbnail, thumbnail,
view_type, view_type,
data: default_delta(), data: VIEW_DEFAULT_DATA.to_string(),
} }
} }
} }
@ -88,9 +89,13 @@ impl TryInto<CreateViewParams> for CreateViewRequest {
type Error = WorkspaceError; type Error = WorkspaceError;
fn try_into(self) -> Result<CreateViewParams, Self::Error> { fn try_into(self) -> Result<CreateViewParams, Self::Error> {
let name = ViewName::parse(self.name).map_err(|e| WorkspaceError::view_name().context(e))?.0; let name = ViewName::parse(self.name)
.map_err(|e| WorkspaceError::view_name().context(e))?
.0;
let belong_to_id = AppId::parse(self.belong_to_id).map_err(|e| WorkspaceError::app_id().context(e))?.0; let belong_to_id = AppId::parse(self.belong_to_id)
.map_err(|e| WorkspaceError::app_id().context(e))?
.0;
let thumbnail = match self.thumbnail { let thumbnail = match self.thumbnail {
None => "".to_string(), None => "".to_string(),
@ -101,7 +106,13 @@ impl TryInto<CreateViewParams> for CreateViewRequest {
}, },
}; };
Ok(CreateViewParams::new(belong_to_id, name, self.desc, self.view_type, thumbnail)) Ok(CreateViewParams::new(
belong_to_id,
name,
self.desc,
self.view_type,
thumbnail,
))
} }
} }

View File

@ -3,7 +3,7 @@ use crate::{
errors::WorkspaceError, errors::WorkspaceError,
}; };
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use flowy_document::entities::doc::DocDelta;
use std::convert::TryInto; use std::convert::TryInto;
#[derive(Default, ProtoBuf)] #[derive(Default, ProtoBuf)]
@ -69,16 +69,26 @@ impl TryInto<UpdateViewParams> for UpdateViewRequest {
type Error = WorkspaceError; type Error = WorkspaceError;
fn try_into(self) -> Result<UpdateViewParams, Self::Error> { fn try_into(self) -> Result<UpdateViewParams, Self::Error> {
let view_id = ViewId::parse(self.view_id).map_err(|e| WorkspaceError::view_id().context(e))?.0; let view_id = ViewId::parse(self.view_id)
.map_err(|e| WorkspaceError::view_id().context(e))?
.0;
let name = match self.name { let name = match self.name {
None => None, None => None,
Some(name) => Some(ViewName::parse(name).map_err(|e| WorkspaceError::view_name().context(e))?.0), Some(name) => Some(
ViewName::parse(name)
.map_err(|e| WorkspaceError::view_name().context(e))?
.0,
),
}; };
let desc = match self.desc { let desc = match self.desc {
None => None, None => None,
Some(desc) => Some(ViewDesc::parse(desc).map_err(|e| WorkspaceError::view_desc().context(e))?.0), Some(desc) => Some(
ViewDesc::parse(desc)
.map_err(|e| WorkspaceError::view_desc().context(e))?
.0,
),
}; };
let thumbnail = match self.thumbnail { let thumbnail = match self.thumbnail {
@ -99,25 +109,23 @@ impl TryInto<UpdateViewParams> for UpdateViewRequest {
}) })
} }
} }
// #[derive(Default, ProtoBuf)]
#[derive(Default, ProtoBuf)] // pub struct DocDeltaRequest {
pub struct ApplyChangesetRequest { // #[pb(index = 1)]
#[pb(index = 1)] // pub view_id: String,
pub view_id: String, //
// #[pb(index = 2)]
#[pb(index = 2)] // pub data: String,
pub data: Vec<u8>, // }
} //
// impl TryInto<DocDelta> for DocDeltaRequest {
impl TryInto<DocDelta> for ApplyChangesetRequest { // type Error = WorkspaceError;
type Error = WorkspaceError; //
// fn try_into(self) -> Result<DocDelta, Self::Error> {
fn try_into(self) -> Result<DocDelta, Self::Error> { // let view_id = ViewId::parse(self.view_id)
let view_id = ViewId::parse(self.view_id).map_err(|e| WorkspaceError::view_id().context(e))?.0; // .map_err(|e| WorkspaceError::view_id().context(e))?
// .0;
// Opti: Vec<u8> -> Delta -> Vec<u8> //
let data = DeltaData::parse(self.data).map_err(|e| WorkspaceError::view_data().context(e))?.0; // Ok(DocDelta { doc_id: view_id, data: self.data })
// }
Ok(DocDelta { doc_id: view_id, data }) // }
}
}

View File

@ -1,6 +1,5 @@
use crate::{ use crate::{
entities::view::{ entities::view::{
ApplyChangesetRequest,
CreateViewParams, CreateViewParams,
CreateViewRequest, CreateViewRequest,
DeleteViewParams, DeleteViewParams,
@ -57,11 +56,11 @@ pub(crate) async fn update_view_handler(
#[tracing::instrument(skip(data, controller), err)] #[tracing::instrument(skip(data, controller), err)]
pub(crate) async fn apply_doc_delta_handler( pub(crate) async fn apply_doc_delta_handler(
data: Data<ApplyChangesetRequest>, data: Data<DocDelta>,
controller: Unit<Arc<ViewController>>, controller: Unit<Arc<ViewController>>,
) -> DataResult<Doc, WorkspaceError> { ) -> DataResult<Doc, WorkspaceError> {
let params: DocDelta = data.into_inner().try_into()?; // let params: DocDelta = data.into_inner().try_into()?;
let doc = controller.apply_doc_delta(params).await?; let doc = controller.apply_doc_delta(data.into_inner()).await?;
data_result(doc) data_result(doc)
} }

View File

@ -387,7 +387,7 @@ pub struct CreateViewParams {
pub desc: ::std::string::String, pub desc: ::std::string::String,
pub thumbnail: ::std::string::String, pub thumbnail: ::std::string::String,
pub view_type: ViewType, pub view_type: ViewType,
pub data: ::std::vec::Vec<u8>, pub data: ::std::string::String,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -523,10 +523,10 @@ impl CreateViewParams {
self.view_type = v; self.view_type = v;
} }
// bytes data = 6; // string data = 6;
pub fn get_data(&self) -> &[u8] { pub fn get_data(&self) -> &str {
&self.data &self.data
} }
pub fn clear_data(&mut self) { pub fn clear_data(&mut self) {
@ -534,19 +534,19 @@ impl CreateViewParams {
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_data(&mut self, v: ::std::vec::Vec<u8>) { pub fn set_data(&mut self, v: ::std::string::String) {
self.data = v; self.data = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_data(&mut self) -> &mut ::std::vec::Vec<u8> { pub fn mut_data(&mut self) -> &mut ::std::string::String {
&mut self.data &mut self.data
} }
// Take field // Take field
pub fn take_data(&mut self) -> ::std::vec::Vec<u8> { pub fn take_data(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.data, ::std::vec::Vec::new()) ::std::mem::replace(&mut self.data, ::std::string::String::new())
} }
} }
@ -575,7 +575,7 @@ impl ::protobuf::Message for CreateViewParams {
::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.view_type, 5, &mut self.unknown_fields)? ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.view_type, 5, &mut self.unknown_fields)?
}, },
6 => { 6 => {
::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.data)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?;
}, },
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -605,7 +605,7 @@ impl ::protobuf::Message for CreateViewParams {
my_size += ::protobuf::rt::enum_size(5, self.view_type); my_size += ::protobuf::rt::enum_size(5, self.view_type);
} }
if !self.data.is_empty() { if !self.data.is_empty() {
my_size += ::protobuf::rt::bytes_size(6, &self.data); my_size += ::protobuf::rt::string_size(6, &self.data);
} }
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
@ -629,7 +629,7 @@ impl ::protobuf::Message for CreateViewParams {
os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?; os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.view_type))?;
} }
if !self.data.is_empty() { if !self.data.is_empty() {
os.write_bytes(6, &self.data)?; os.write_string(6, &self.data)?;
} }
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
@ -694,7 +694,7 @@ impl ::protobuf::Message for CreateViewParams {
|m: &CreateViewParams| { &m.view_type }, |m: &CreateViewParams| { &m.view_type },
|m: &mut CreateViewParams| { &mut m.view_type }, |m: &mut CreateViewParams| { &mut m.view_type },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"data", "data",
|m: &CreateViewParams| { &m.data }, |m: &CreateViewParams| { &m.data },
|m: &mut CreateViewParams| { &mut m.data }, |m: &mut CreateViewParams| { &mut m.data },
@ -1441,7 +1441,7 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\nbelongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04\ \nbelongToId\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\x12\n\x04\
desc\x18\x03\x20\x01(\tR\x04desc\x12\x1c\n\tthumbnail\x18\x04\x20\x01(\t\ desc\x18\x03\x20\x01(\tR\x04desc\x12\x1c\n\tthumbnail\x18\x04\x20\x01(\t\
R\tthumbnail\x12&\n\tview_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08view\ R\tthumbnail\x12&\n\tview_type\x18\x05\x20\x01(\x0e2\t.ViewTypeR\x08view\
Type\x12\x12\n\x04data\x18\x06\x20\x01(\x0cR\x04data\"\x97\x02\n\x04View\ Type\x12\x12\n\x04data\x18\x06\x20\x01(\tR\x04data\"\x97\x02\n\x04View\
\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x20\n\x0cbelong_to_id\x18\ \x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x20\n\x0cbelong_to_id\x18\
\x02\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04na\ \x02\x20\x01(\tR\nbelongToId\x12\x12\n\x04name\x18\x03\x20\x01(\tR\x04na\
me\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04desc\x12&\n\tview_type\x18\ me\x12\x12\n\x04desc\x18\x04\x20\x01(\tR\x04desc\x12&\n\tview_type\x18\
@ -1483,9 +1483,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x12\x03\x0e\x04\x1b\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0e\x04\x0c\ \x12\x03\x0e\x04\x1b\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0e\x04\x0c\
\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\x0e\r\x16\n\x0c\n\x05\x04\x01\ \n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\x0e\r\x16\n\x0c\n\x05\x04\x01\
\x02\x04\x03\x12\x03\x0e\x19\x1a\n\x0b\n\x04\x04\x01\x02\x05\x12\x03\x0f\ \x02\x04\x03\x12\x03\x0e\x19\x1a\n\x0b\n\x04\x04\x01\x02\x05\x12\x03\x0f\
\x04\x13\n\x0c\n\x05\x04\x01\x02\x05\x05\x12\x03\x0f\x04\t\n\x0c\n\x05\ \x04\x14\n\x0c\n\x05\x04\x01\x02\x05\x05\x12\x03\x0f\x04\n\n\x0c\n\x05\
\x04\x01\x02\x05\x01\x12\x03\x0f\n\x0e\n\x0c\n\x05\x04\x01\x02\x05\x03\ \x04\x01\x02\x05\x01\x12\x03\x0f\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x05\x03\
\x12\x03\x0f\x11\x12\n\n\n\x02\x04\x02\x12\x04\x11\0\x1b\x01\n\n\n\x03\ \x12\x03\x0f\x12\x13\n\n\n\x02\x04\x02\x12\x04\x11\0\x1b\x01\n\n\n\x03\
\x04\x02\x01\x12\x03\x11\x08\x0c\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x12\ \x04\x02\x01\x12\x03\x11\x08\x0c\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x12\
\x04\x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\ \x04\x12\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x12\x04\n\n\x0c\n\x05\x04\
\x02\x02\0\x01\x12\x03\x12\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\ \x02\x02\0\x01\x12\x03\x12\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\

View File

@ -944,7 +944,7 @@ impl ::protobuf::reflect::ProtobufValue for UpdateViewParams {
} }
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct ApplyChangesetRequest { pub struct DocDeltaRequest {
// message fields // message fields
pub view_id: ::std::string::String, pub view_id: ::std::string::String,
pub data: ::std::vec::Vec<u8>, pub data: ::std::vec::Vec<u8>,
@ -953,14 +953,14 @@ pub struct ApplyChangesetRequest {
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
} }
impl<'a> ::std::default::Default for &'a ApplyChangesetRequest { impl<'a> ::std::default::Default for &'a DocDeltaRequest {
fn default() -> &'a ApplyChangesetRequest { fn default() -> &'a DocDeltaRequest {
<ApplyChangesetRequest as ::protobuf::Message>::default_instance() <DocDeltaRequest as ::protobuf::Message>::default_instance()
} }
} }
impl ApplyChangesetRequest { impl DocDeltaRequest {
pub fn new() -> ApplyChangesetRequest { pub fn new() -> DocDeltaRequest {
::std::default::Default::default() ::std::default::Default::default()
} }
@ -1017,7 +1017,7 @@ impl ApplyChangesetRequest {
} }
} }
impl ::protobuf::Message for ApplyChangesetRequest { impl ::protobuf::Message for DocDeltaRequest {
fn is_initialized(&self) -> bool { fn is_initialized(&self) -> bool {
true true
} }
@ -1092,8 +1092,8 @@ impl ::protobuf::Message for ApplyChangesetRequest {
Self::descriptor_static() Self::descriptor_static()
} }
fn new() -> ApplyChangesetRequest { fn new() -> DocDeltaRequest {
ApplyChangesetRequest::new() DocDeltaRequest::new()
} }
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@ -1102,29 +1102,29 @@ impl ::protobuf::Message for ApplyChangesetRequest {
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>(
"view_id", "view_id",
|m: &ApplyChangesetRequest| { &m.view_id }, |m: &DocDeltaRequest| { &m.view_id },
|m: &mut ApplyChangesetRequest| { &mut m.view_id }, |m: &mut DocDeltaRequest| { &mut m.view_id },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>(
"data", "data",
|m: &ApplyChangesetRequest| { &m.data }, |m: &DocDeltaRequest| { &m.data },
|m: &mut ApplyChangesetRequest| { &mut m.data }, |m: &mut DocDeltaRequest| { &mut m.data },
)); ));
::protobuf::reflect::MessageDescriptor::new_pb_name::<ApplyChangesetRequest>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocDeltaRequest>(
"ApplyChangesetRequest", "DocDeltaRequest",
fields, fields,
file_descriptor_proto() file_descriptor_proto()
) )
}) })
} }
fn default_instance() -> &'static ApplyChangesetRequest { fn default_instance() -> &'static DocDeltaRequest {
static instance: ::protobuf::rt::LazyV2<ApplyChangesetRequest> = ::protobuf::rt::LazyV2::INIT; static instance: ::protobuf::rt::LazyV2<DocDeltaRequest> = ::protobuf::rt::LazyV2::INIT;
instance.get(ApplyChangesetRequest::new) instance.get(DocDeltaRequest::new)
} }
} }
impl ::protobuf::Clear for ApplyChangesetRequest { impl ::protobuf::Clear for DocDeltaRequest {
fn clear(&mut self) { fn clear(&mut self) {
self.view_id.clear(); self.view_id.clear();
self.data.clear(); self.data.clear();
@ -1132,13 +1132,13 @@ impl ::protobuf::Clear for ApplyChangesetRequest {
} }
} }
impl ::std::fmt::Debug for ApplyChangesetRequest { impl ::std::fmt::Debug for DocDeltaRequest {
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 ApplyChangesetRequest { impl ::protobuf::reflect::ProtobufValue for DocDeltaRequest {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self) ::protobuf::reflect::ReflectValueRef::Message(self)
} }
@ -1156,55 +1156,55 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x03\x20\x01(\tH\x01R\x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\ \x03\x20\x01(\tH\x01R\x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\
\x02R\tthumbnail\x12\x1b\n\x08is_trash\x18\x05\x20\x01(\x08H\x03R\x07isT\ \x02R\tthumbnail\x12\x1b\n\x08is_trash\x18\x05\x20\x01(\x08H\x03R\x07isT\
rashB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnailB\ rashB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnailB\
\x11\n\x0fone_of_is_trash\"D\n\x15ApplyChangesetRequest\x12\x17\n\x07vie\ \x11\n\x0fone_of_is_trash\">\n\x0fDocDeltaRequest\x12\x17\n\x07view_id\
w_id\x18\x01\x20\x01(\tR\x06viewId\x12\x12\n\x04data\x18\x02\x20\x01(\ \x18\x01\x20\x01(\tR\x06viewId\x12\x12\n\x04data\x18\x02\x20\x01(\x0cR\
\x0cR\x04dataJ\xc6\x07\n\x06\x12\x04\0\0\x13\x01\n\x08\n\x01\x0c\x12\x03\ \x04dataJ\xc6\x07\n\x06\x12\x04\0\0\x13\x01\n\x08\n\x01\x0c\x12\x03\0\0\
\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\ \x12\n\n\n\x02\x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\
\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\ \x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x17\n\x0c\n\x05\x04\
\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\ \0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\
\x03\x0b\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\ \x0b\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\x16\n\x0b\n\x04\x04\
\x04\0\x08\0\x12\x03\x04\x04*\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x04\n\ \0\x08\0\x12\x03\x04\x04*\n\x0c\n\x05\x04\0\x08\0\x01\x12\x03\x04\n\x15\
\x15\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x18(\n\x0c\n\x05\x04\0\x02\ \n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x18(\n\x0c\n\x05\x04\0\x02\x01\
\x01\x05\x12\x03\x04\x18\x1e\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\ \x05\x12\x03\x04\x18\x1e\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x1f#\
\x1f#\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04&'\n\x0b\n\x04\x04\0\x08\ \n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04&'\n\x0b\n\x04\x04\0\x08\x01\
\x01\x12\x03\x05\x04*\n\x0c\n\x05\x04\0\x08\x01\x01\x12\x03\x05\n\x15\n\ \x12\x03\x05\x04*\n\x0c\n\x05\x04\0\x08\x01\x01\x12\x03\x05\n\x15\n\x0b\
\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x18(\n\x0c\n\x05\x04\0\x02\x02\x05\ \n\x04\x04\0\x02\x02\x12\x03\x05\x18(\n\x0c\n\x05\x04\0\x02\x02\x05\x12\
\x12\x03\x05\x18\x1e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x1f#\n\ \x03\x05\x18\x1e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x1f#\n\x0c\n\
\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05&'\n\x0b\n\x04\x04\0\x08\x02\x12\ \x05\x04\0\x02\x02\x03\x12\x03\x05&'\n\x0b\n\x04\x04\0\x08\x02\x12\x03\
\x03\x06\x044\n\x0c\n\x05\x04\0\x08\x02\x01\x12\x03\x06\n\x1a\n\x0b\n\ \x06\x044\n\x0c\n\x05\x04\0\x08\x02\x01\x12\x03\x06\n\x1a\n\x0b\n\x04\
\x04\x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\x12\ \x04\0\x02\x03\x12\x03\x06\x1d2\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\
\x03\x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\x05\ \x06\x1d#\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06$-\n\x0c\n\x05\x04\0\
\x04\0\x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x08\x03\x12\x03\x07\ \x02\x03\x03\x12\x03\x0601\n\x0b\n\x04\x04\0\x08\x03\x12\x03\x07\x040\n\
\x040\n\x0c\n\x05\x04\0\x08\x03\x01\x12\x03\x07\n\x19\n\x0b\n\x04\x04\0\ \x0c\n\x05\x04\0\x08\x03\x01\x12\x03\x07\n\x19\n\x0b\n\x04\x04\0\x02\x04\
\x02\x04\x12\x03\x07\x1c.\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x1c\ \x12\x03\x07\x1c.\n\x0c\n\x05\x04\0\x02\x04\x05\x12\x03\x07\x1c\x20\n\
\x20\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07!)\n\x0c\n\x05\x04\0\x02\ \x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07!)\n\x0c\n\x05\x04\0\x02\x04\x03\
\x04\x03\x12\x03\x07,-\n\n\n\x02\x04\x01\x12\x04\t\0\x0f\x01\n\n\n\x03\ \x12\x03\x07,-\n\n\n\x02\x04\x01\x12\x04\t\0\x0f\x01\n\n\n\x03\x04\x01\
\x04\x01\x01\x12\x03\t\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\ \x01\x12\x03\t\x08\x18\n\x0b\n\x04\x04\x01\x02\0\x12\x03\n\x04\x17\n\x0c\
\x17\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\ \n\x05\x04\x01\x02\0\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
\x02\0\x01\x12\x03\n\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x15\ \x12\x03\n\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\n\x15\x16\n\x0b\
\x16\n\x0b\n\x04\x04\x01\x08\0\x12\x03\x0b\x04*\n\x0c\n\x05\x04\x01\x08\ \n\x04\x04\x01\x08\0\x12\x03\x0b\x04*\n\x0c\n\x05\x04\x01\x08\0\x01\x12\
\0\x01\x12\x03\x0b\n\x15\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x18(\n\ \x03\x0b\n\x15\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x0b\x18(\n\x0c\n\x05\
\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x0b\x18\x1e\n\x0c\n\x05\x04\x01\ \x04\x01\x02\x01\x05\x12\x03\x0b\x18\x1e\n\x0c\n\x05\x04\x01\x02\x01\x01\
\x02\x01\x01\x12\x03\x0b\x1f#\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\ \x12\x03\x0b\x1f#\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x0b&'\n\x0b\n\
\x0b&'\n\x0b\n\x04\x04\x01\x08\x01\x12\x03\x0c\x04*\n\x0c\n\x05\x04\x01\ \x04\x04\x01\x08\x01\x12\x03\x0c\x04*\n\x0c\n\x05\x04\x01\x08\x01\x01\
\x08\x01\x01\x12\x03\x0c\n\x15\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0c\ \x12\x03\x0c\n\x15\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\x0c\x18(\n\x0c\n\
\x18(\n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\x0c\x18\x1e\n\x0c\n\x05\ \x05\x04\x01\x02\x02\x05\x12\x03\x0c\x18\x1e\n\x0c\n\x05\x04\x01\x02\x02\
\x04\x01\x02\x02\x01\x12\x03\x0c\x1f#\n\x0c\n\x05\x04\x01\x02\x02\x03\ \x01\x12\x03\x0c\x1f#\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0c&'\n\
\x12\x03\x0c&'\n\x0b\n\x04\x04\x01\x08\x02\x12\x03\r\x044\n\x0c\n\x05\ \x0b\n\x04\x04\x01\x08\x02\x12\x03\r\x044\n\x0c\n\x05\x04\x01\x08\x02\
\x04\x01\x08\x02\x01\x12\x03\r\n\x1a\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\ \x01\x12\x03\r\n\x1a\n\x0b\n\x04\x04\x01\x02\x03\x12\x03\r\x1d2\n\x0c\n\
\r\x1d2\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\r\x1d#\n\x0c\n\x05\x04\ \x05\x04\x01\x02\x03\x05\x12\x03\r\x1d#\n\x0c\n\x05\x04\x01\x02\x03\x01\
\x01\x02\x03\x01\x12\x03\r$-\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\r01\ \x12\x03\r$-\n\x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\r01\n\x0b\n\x04\x04\
\n\x0b\n\x04\x04\x01\x08\x03\x12\x03\x0e\x040\n\x0c\n\x05\x04\x01\x08\ \x01\x08\x03\x12\x03\x0e\x040\n\x0c\n\x05\x04\x01\x08\x03\x01\x12\x03\
\x03\x01\x12\x03\x0e\n\x19\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\x1c.\ \x0e\n\x19\n\x0b\n\x04\x04\x01\x02\x04\x12\x03\x0e\x1c.\n\x0c\n\x05\x04\
\n\x0c\n\x05\x04\x01\x02\x04\x05\x12\x03\x0e\x1c\x20\n\x0c\n\x05\x04\x01\ \x01\x02\x04\x05\x12\x03\x0e\x1c\x20\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\
\x02\x04\x01\x12\x03\x0e!)\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\x03\x0e,-\ \x03\x0e!)\n\x0c\n\x05\x04\x01\x02\x04\x03\x12\x03\x0e,-\n\n\n\x02\x04\
\n\n\n\x02\x04\x02\x12\x04\x10\0\x13\x01\n\n\n\x03\x04\x02\x01\x12\x03\ \x02\x12\x04\x10\0\x13\x01\n\n\n\x03\x04\x02\x01\x12\x03\x10\x08\x17\n\
\x10\x08\x1d\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x11\x04\x17\n\x0c\n\x05\ \x0b\n\x04\x04\x02\x02\0\x12\x03\x11\x04\x17\n\x0c\n\x05\x04\x02\x02\0\
\x04\x02\x02\0\x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\ \x05\x12\x03\x11\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x11\x0b\x12\
\x03\x11\x0b\x12\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x11\x15\x16\n\x0b\ \n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x11\x15\x16\n\x0b\n\x04\x04\x02\
\n\x04\x04\x02\x02\x01\x12\x03\x12\x04\x13\n\x0c\n\x05\x04\x02\x02\x01\ \x02\x01\x12\x03\x12\x04\x13\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x12\
\x05\x12\x03\x12\x04\t\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x12\n\x0e\ \x04\t\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x12\n\x0e\n\x0c\n\x05\x04\
\n\x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x12\x11\x12b\x06proto3\ \x02\x02\x01\x03\x12\x03\x12\x11\x12b\x06proto3\
"; ";
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

@ -13,7 +13,7 @@ message CreateViewParams {
string desc = 3; string desc = 3;
string thumbnail = 4; string thumbnail = 4;
ViewType view_type = 5; ViewType view_type = 5;
bytes data = 6; string data = 6;
} }
message View { message View {
string id = 1; string id = 1;

View File

@ -14,7 +14,7 @@ message UpdateViewParams {
oneof one_of_thumbnail { string thumbnail = 4; }; oneof one_of_thumbnail { string thumbnail = 4; };
oneof one_of_is_trash { bool is_trash = 5; }; oneof one_of_is_trash { bool is_trash = 5; };
} }
message ApplyChangesetRequest { message DocDeltaRequest {
string view_id = 1; string view_id = 1;
bytes data = 2; bytes data = 2;
} }

View File

@ -1,5 +1,5 @@
# https://rust-lang.github.io/rustfmt/?version=master&search= # https://rust-lang.github.io/rustfmt/?version=master&search=
max_width = 140 max_width = 120
tab_spaces = 4 tab_spaces = 4
fn_single_line = true fn_single_line = true
match_block_trailing_comma = true match_block_trailing_comma = true