瀏覽代碼

[server]: trash table and create params

appflowy 3 年之前
父節點
當前提交
8e40ae60e6
共有 43 個文件被更改,包括 666 次插入345 次删除
  1. 13 13
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-document/doc.pb.dart
  2. 5 5
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-document/doc.pbjson.dart
  3. 26 36
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_create.pb.dart
  4. 19 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_create.pbenum.dart
  5. 15 5
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_create.pbjson.dart
  6. 41 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_delete.pb.dart
  7. 10 0
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_delete.pbjson.dart
  8. 6 0
      backend/migrations/20211015065001_trash.sql
  9. 6 0
      backend/src/application.rs
  10. 2 2
      backend/src/service/doc/crud.rs
  11. 2 2
      backend/src/service/doc/doc.rs
  12. 2 2
      backend/src/service/doc/router.rs
  13. 1 0
      backend/src/service/mod.rs
  14. 4 0
      backend/src/service/trash/mod.rs
  15. 23 0
      backend/src/service/trash/router.rs
  16. 18 0
      backend/src/service/trash/trash.rs
  17. 1 2
      backend/src/service/view/router.rs
  18. 3 3
      backend/tests/api/doc.rs
  19. 2 2
      backend/tests/document/helper.rs
  20. 2 2
      backend/tests/helper.rs
  21. 1 1
      rust-lib/flowy-database/migrations/2021-07-09-063045_flowy-user/up.sql
  22. 1 1
      rust-lib/flowy-database/src/schema.rs
  23. 4 2
      rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
  24. 3 3
      rust-lib/flowy-document/src/entities/doc/doc.rs
  25. 3 7
      rust-lib/flowy-document/src/module.rs
  26. 28 28
      rust-lib/flowy-document/src/protobuf/model/doc.rs
  27. 1 1
      rust-lib/flowy-document/src/protobuf/proto/doc.proto
  28. 5 5
      rust-lib/flowy-document/src/services/doc/doc_controller.rs
  29. 3 3
      rust-lib/flowy-document/src/services/server/mod.rs
  30. 5 5
      rust-lib/flowy-document/src/services/server/server_api.rs
  31. 3 3
      rust-lib/flowy-document/src/services/server/server_api_mock.rs
  32. 16 10
      rust-lib/flowy-workspace/src/entities/trash/trash_create.rs
  33. 6 0
      rust-lib/flowy-workspace/src/entities/trash/trash_delete.rs
  34. 6 1
      rust-lib/flowy-workspace/src/entities/view/view_create.rs
  35. 6 6
      rust-lib/flowy-workspace/src/entities/view/view_query.rs
  36. 2 2
      rust-lib/flowy-workspace/src/handlers/view_handler.rs
  37. 140 137
      rust-lib/flowy-workspace/src/protobuf/model/trash_create.rs
  38. 169 5
      rust-lib/flowy-workspace/src/protobuf/model/trash_delete.rs
  39. 6 3
      rust-lib/flowy-workspace/src/protobuf/proto/trash_create.proto
  40. 3 0
      rust-lib/flowy-workspace/src/protobuf/proto/trash_delete.proto
  41. 15 20
      rust-lib/flowy-workspace/src/services/trash_can.rs
  42. 9 13
      rust-lib/flowy-workspace/src/services/view_controller.rs
  43. 30 15
      rust-lib/flowy-workspace/src/sql_tables/trash/trash_table.rs

+ 13 - 13
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-document/doc.pb.dart

@@ -371,14 +371,14 @@ class NewDocUser extends $pb.GeneratedMessage {
   void clearDocId() => clearField(3);
 }
 
-class QueryDocParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryDocParams', createEmptyInstance: create)
+class DocIdentifier extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DocIdentifier', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'docId')
     ..hasRequiredFields = false
   ;
 
-  QueryDocParams._() : super();
-  factory QueryDocParams({
+  DocIdentifier._() : super();
+  factory DocIdentifier({
     $core.String? docId,
   }) {
     final _result = create();
@@ -387,26 +387,26 @@ class QueryDocParams extends $pb.GeneratedMessage {
     }
     return _result;
   }
-  factory QueryDocParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory QueryDocParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory DocIdentifier.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DocIdentifier.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
   'Will be removed in next major version')
-  QueryDocParams clone() => QueryDocParams()..mergeFromMessage(this);
+  DocIdentifier clone() => DocIdentifier()..mergeFromMessage(this);
   @$core.Deprecated(
   'Using this can add significant overhead to your binary. '
   'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
   'Will be removed in next major version')
-  QueryDocParams copyWith(void Function(QueryDocParams) updates) => super.copyWith((message) => updates(message as QueryDocParams)) as QueryDocParams; // ignore: deprecated_member_use
+  DocIdentifier copyWith(void Function(DocIdentifier) updates) => super.copyWith((message) => updates(message as DocIdentifier)) as DocIdentifier; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
-  static QueryDocParams create() => QueryDocParams._();
-  QueryDocParams createEmptyInstance() => create();
-  static $pb.PbList<QueryDocParams> createRepeated() => $pb.PbList<QueryDocParams>();
+  static DocIdentifier create() => DocIdentifier._();
+  DocIdentifier createEmptyInstance() => create();
+  static $pb.PbList<DocIdentifier> createRepeated() => $pb.PbList<DocIdentifier>();
   @$core.pragma('dart2js:noInline')
-  static QueryDocParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<QueryDocParams>(create);
-  static QueryDocParams? _defaultInstance;
+  static DocIdentifier getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DocIdentifier>(create);
+  static DocIdentifier? _defaultInstance;
 
   @$pb.TagNumber(1)
   $core.String get docId => $_getSZ(0);

+ 5 - 5
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-document/doc.pbjson.dart

@@ -67,13 +67,13 @@ const NewDocUser$json = const {
 
 /// Descriptor for `NewDocUser`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List newDocUserDescriptor = $convert.base64Decode('CgpOZXdEb2NVc2VyEhcKB3VzZXJfaWQYASABKAlSBnVzZXJJZBIVCgZyZXZfaWQYAiABKANSBXJldklkEhUKBmRvY19pZBgDIAEoCVIFZG9jSWQ=');
-@$core.Deprecated('Use queryDocParamsDescriptor instead')
-const QueryDocParams$json = const {
-  '1': 'QueryDocParams',
+@$core.Deprecated('Use docIdentifierDescriptor instead')
+const DocIdentifier$json = const {
+  '1': 'DocIdentifier',
   '2': const [
     const {'1': 'doc_id', '3': 1, '4': 1, '5': 9, '10': 'docId'},
   ],
 };
 
-/// Descriptor for `QueryDocParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryDocParamsDescriptor = $convert.base64Decode('Cg5RdWVyeURvY1BhcmFtcxIVCgZkb2NfaWQYASABKAlSBWRvY0lk');
+/// Descriptor for `DocIdentifier`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List docIdentifierDescriptor = $convert.base64Decode('Cg1Eb2NJZGVudGlmaWVyEhUKBmRvY19pZBgBIAEoCVIFZG9jSWQ=');

+ 26 - 36
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_create.pb.dart

@@ -10,34 +10,28 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
+import 'trash_create.pbenum.dart';
+
+export 'trash_create.pbenum.dart';
+
 class CreateTrashParams extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateTrashParams', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
-    ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
-    ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'modifiedTime')
-    ..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'createTime')
+    ..e<TrashType>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: TrashType.Unknown, valueOf: TrashType.valueOf, enumValues: TrashType.values)
     ..hasRequiredFields = false
   ;
 
   CreateTrashParams._() : super();
   factory CreateTrashParams({
     $core.String? id,
-    $core.String? name,
-    $fixnum.Int64? modifiedTime,
-    $fixnum.Int64? createTime,
+    TrashType? ty,
   }) {
     final _result = create();
     if (id != null) {
       _result.id = id;
     }
-    if (name != null) {
-      _result.name = name;
-    }
-    if (modifiedTime != null) {
-      _result.modifiedTime = modifiedTime;
-    }
-    if (createTime != null) {
-      _result.createTime = createTime;
+    if (ty != null) {
+      _result.ty = ty;
     }
     return _result;
   }
@@ -72,31 +66,13 @@ class CreateTrashParams extends $pb.GeneratedMessage {
   void clearId() => clearField(1);
 
   @$pb.TagNumber(2)
-  $core.String get name => $_getSZ(1);
+  TrashType get ty => $_getN(1);
   @$pb.TagNumber(2)
-  set name($core.String v) { $_setString(1, v); }
+  set ty(TrashType v) { setField(2, v); }
   @$pb.TagNumber(2)
-  $core.bool hasName() => $_has(1);
+  $core.bool hasTy() => $_has(1);
   @$pb.TagNumber(2)
-  void clearName() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $fixnum.Int64 get modifiedTime => $_getI64(2);
-  @$pb.TagNumber(3)
-  set modifiedTime($fixnum.Int64 v) { $_setInt64(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasModifiedTime() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearModifiedTime() => clearField(3);
-
-  @$pb.TagNumber(4)
-  $fixnum.Int64 get createTime => $_getI64(3);
-  @$pb.TagNumber(4)
-  set createTime($fixnum.Int64 v) { $_setInt64(3, v); }
-  @$pb.TagNumber(4)
-  $core.bool hasCreateTime() => $_has(3);
-  @$pb.TagNumber(4)
-  void clearCreateTime() => clearField(4);
+  void clearTy() => clearField(2);
 }
 
 class Trash extends $pb.GeneratedMessage {
@@ -105,6 +81,7 @@ class Trash extends $pb.GeneratedMessage {
     ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
     ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'modifiedTime')
     ..aInt64(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'createTime')
+    ..e<TrashType>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: TrashType.Unknown, valueOf: TrashType.valueOf, enumValues: TrashType.values)
     ..hasRequiredFields = false
   ;
 
@@ -114,6 +91,7 @@ class Trash extends $pb.GeneratedMessage {
     $core.String? name,
     $fixnum.Int64? modifiedTime,
     $fixnum.Int64? createTime,
+    TrashType? ty,
   }) {
     final _result = create();
     if (id != null) {
@@ -128,6 +106,9 @@ class Trash extends $pb.GeneratedMessage {
     if (createTime != null) {
       _result.createTime = createTime;
     }
+    if (ty != null) {
+      _result.ty = ty;
+    }
     return _result;
   }
   factory Trash.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -186,6 +167,15 @@ class Trash extends $pb.GeneratedMessage {
   $core.bool hasCreateTime() => $_has(3);
   @$pb.TagNumber(4)
   void clearCreateTime() => clearField(4);
+
+  @$pb.TagNumber(5)
+  TrashType get ty => $_getN(4);
+  @$pb.TagNumber(5)
+  set ty(TrashType v) { setField(5, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasTy() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearTy() => clearField(5);
 }
 
 class RepeatedTrash extends $pb.GeneratedMessage {

+ 19 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_create.pbenum.dart

@@ -5,3 +5,22 @@
 // @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: UNDEFINED_SHOWN_NAME
+import 'dart:core' as $core;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class TrashType extends $pb.ProtobufEnum {
+  static const TrashType Unknown = TrashType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
+  static const TrashType View = TrashType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'View');
+
+  static const $core.List<TrashType> values = <TrashType> [
+    Unknown,
+    View,
+  ];
+
+  static final $core.Map<$core.int, TrashType> _byValue = $pb.ProtobufEnum.initByValue(values);
+  static TrashType? valueOf($core.int value) => _byValue[value];
+
+  const TrashType._($core.int v, $core.String n) : super(v, n);
+}
+

+ 15 - 5
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_create.pbjson.dart

@@ -8,19 +8,28 @@
 import 'dart:core' as $core;
 import 'dart:convert' as $convert;
 import 'dart:typed_data' as $typed_data;
+@$core.Deprecated('Use trashTypeDescriptor instead')
+const TrashType$json = const {
+  '1': 'TrashType',
+  '2': const [
+    const {'1': 'Unknown', '2': 0},
+    const {'1': 'View', '2': 1},
+  ],
+};
+
+/// Descriptor for `TrashType`. Decode as a `google.protobuf.EnumDescriptorProto`.
+final $typed_data.Uint8List trashTypeDescriptor = $convert.base64Decode('CglUcmFzaFR5cGUSCwoHVW5rbm93bhAAEggKBFZpZXcQAQ==');
 @$core.Deprecated('Use createTrashParamsDescriptor instead')
 const CreateTrashParams$json = const {
   '1': 'CreateTrashParams',
   '2': const [
     const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
-    const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
-    const {'1': 'modified_time', '3': 3, '4': 1, '5': 3, '10': 'modifiedTime'},
-    const {'1': 'create_time', '3': 4, '4': 1, '5': 3, '10': 'createTime'},
+    const {'1': 'ty', '3': 2, '4': 1, '5': 14, '6': '.TrashType', '10': 'ty'},
   ],
 };
 
 /// Descriptor for `CreateTrashParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List createTrashParamsDescriptor = $convert.base64Decode('ChFDcmVhdGVUcmFzaFBhcmFtcxIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRIjCg1tb2RpZmllZF90aW1lGAMgASgDUgxtb2RpZmllZFRpbWUSHwoLY3JlYXRlX3RpbWUYBCABKANSCmNyZWF0ZVRpbWU=');
+final $typed_data.Uint8List createTrashParamsDescriptor = $convert.base64Decode('ChFDcmVhdGVUcmFzaFBhcmFtcxIOCgJpZBgBIAEoCVICaWQSGgoCdHkYAiABKA4yCi5UcmFzaFR5cGVSAnR5');
 @$core.Deprecated('Use trashDescriptor instead')
 const Trash$json = const {
   '1': 'Trash',
@@ -29,11 +38,12 @@ const Trash$json = const {
     const {'1': 'name', '3': 2, '4': 1, '5': 9, '10': 'name'},
     const {'1': 'modified_time', '3': 3, '4': 1, '5': 3, '10': 'modifiedTime'},
     const {'1': 'create_time', '3': 4, '4': 1, '5': 3, '10': 'createTime'},
+    const {'1': 'ty', '3': 5, '4': 1, '5': 14, '6': '.TrashType', '10': 'ty'},
   ],
 };
 
 /// Descriptor for `Trash`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List trashDescriptor = $convert.base64Decode('CgVUcmFzaBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRIjCg1tb2RpZmllZF90aW1lGAMgASgDUgxtb2RpZmllZFRpbWUSHwoLY3JlYXRlX3RpbWUYBCABKANSCmNyZWF0ZVRpbWU=');
+final $typed_data.Uint8List trashDescriptor = $convert.base64Decode('CgVUcmFzaBIOCgJpZBgBIAEoCVICaWQSEgoEbmFtZRgCIAEoCVIEbmFtZRIjCg1tb2RpZmllZF90aW1lGAMgASgDUgxtb2RpZmllZFRpbWUSHwoLY3JlYXRlX3RpbWUYBCABKANSCmNyZWF0ZVRpbWUSGgoCdHkYBSABKA4yCi5UcmFzaFR5cGVSAnR5');
 @$core.Deprecated('Use repeatedTrashDescriptor instead')
 const RepeatedTrash$json = const {
   '1': 'RepeatedTrash',

+ 41 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_delete.pb.dart

@@ -56,3 +56,44 @@ class TrashIdentifier extends $pb.GeneratedMessage {
   void clearId() => clearField(1);
 }
 
+class TrashIdentifiers extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'TrashIdentifiers', createEmptyInstance: create)
+    ..pPS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ids')
+    ..hasRequiredFields = false
+  ;
+
+  TrashIdentifiers._() : super();
+  factory TrashIdentifiers({
+    $core.Iterable<$core.String>? ids,
+  }) {
+    final _result = create();
+    if (ids != null) {
+      _result.ids.addAll(ids);
+    }
+    return _result;
+  }
+  factory TrashIdentifiers.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory TrashIdentifiers.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  TrashIdentifiers clone() => TrashIdentifiers()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  TrashIdentifiers copyWith(void Function(TrashIdentifiers) updates) => super.copyWith((message) => updates(message as TrashIdentifiers)) as TrashIdentifiers; // ignore: deprecated_member_use
+  $pb.BuilderInfo get info_ => _i;
+  @$core.pragma('dart2js:noInline')
+  static TrashIdentifiers create() => TrashIdentifiers._();
+  TrashIdentifiers createEmptyInstance() => create();
+  static $pb.PbList<TrashIdentifiers> createRepeated() => $pb.PbList<TrashIdentifiers>();
+  @$core.pragma('dart2js:noInline')
+  static TrashIdentifiers getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<TrashIdentifiers>(create);
+  static TrashIdentifiers? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$core.String> get ids => $_getList(0);
+}
+

+ 10 - 0
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/trash_delete.pbjson.dart

@@ -18,3 +18,13 @@ const TrashIdentifier$json = const {
 
 /// Descriptor for `TrashIdentifier`. Decode as a `google.protobuf.DescriptorProto`.
 final $typed_data.Uint8List trashIdentifierDescriptor = $convert.base64Decode('Cg9UcmFzaElkZW50aWZpZXISDgoCaWQYASABKAlSAmlk');
+@$core.Deprecated('Use trashIdentifiersDescriptor instead')
+const TrashIdentifiers$json = const {
+  '1': 'TrashIdentifiers',
+  '2': const [
+    const {'1': 'ids', '3': 1, '4': 3, '5': 9, '10': 'ids'},
+  ],
+};
+
+/// Descriptor for `TrashIdentifiers`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List trashIdentifiersDescriptor = $convert.base64Decode('ChBUcmFzaElkZW50aWZpZXJzEhAKA2lkcxgBIAMoCVIDaWRz');

+ 6 - 0
backend/migrations/20211015065001_trash.sql

@@ -0,0 +1,6 @@
+-- Add migration script here
+CREATE TABLE IF NOT EXISTS trash_table(
+    id uuid NOT NULL,
+    PRIMARY KEY (id),
+    ty INTEGER NOT NULL DEFAULT 0
+);

+ 6 - 0
backend/src/application.rs

@@ -16,6 +16,7 @@ use crate::{
     service::{
         app::router as app,
         doc::router as doc,
+        trash::router as trash,
         user::router as user,
         view::router as view,
         workspace::router as workspace,
@@ -118,6 +119,11 @@ fn user_scope() -> Scope {
             .route(web::get().to(doc::read_handler))
             .route(web::patch().to(doc::update_handler))
         )
+        .service(web::resource("/trash")
+            .route(web::post().to(trash::create_handler))
+            .route(web::delete().to(trash::delete_handler))
+            .route(web::get().to(trash::read_handler))
+        )
         // password
         .service(web::resource("/password_change")
             .route(web::post().to(user::change_password))

+ 2 - 2
backend/src/service/doc/crud.rs

@@ -3,7 +3,7 @@ use crate::{
     sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
 };
 use anyhow::Context;
-use flowy_document::protobuf::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams};
+use flowy_document::protobuf::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams};
 use flowy_net::errors::ServerError;
 use sqlx::{postgres::PgArguments, PgPool, Postgres};
 use uuid::Uuid;
@@ -24,7 +24,7 @@ pub(crate) async fn create_doc(
 }
 
 #[tracing::instrument(level = "debug", skip(pool), err)]
-pub(crate) async fn read_doc(pool: &PgPool, params: QueryDocParams) -> Result<Doc, ServerError> {
+pub(crate) async fn read_doc(pool: &PgPool, params: DocIdentifier) -> Result<Doc, ServerError> {
     let doc_id = Uuid::parse_str(&params.doc_id)?;
     let mut transaction = pool
         .begin()

+ 2 - 2
backend/src/service/doc/doc.rs

@@ -8,7 +8,7 @@ use crate::service::{
 };
 use actix_web::web::Data;
 use dashmap::DashMap;
-use flowy_document::protobuf::QueryDocParams;
+use flowy_document::protobuf::DocIdentifier;
 use flowy_net::errors::{internal_error, ServerError};
 use sqlx::PgPool;
 use std::sync::Arc;
@@ -71,7 +71,7 @@ impl DocManager {
     pub async fn get(&self, doc_id: &str, pg_pool: Data<PgPool>) -> Result<Option<Arc<DocHandle>>, ServerError> {
         match self.docs_map.get(doc_id) {
             None => {
-                let params = QueryDocParams {
+                let params = DocIdentifier {
                     doc_id: doc_id.to_string(),
                     ..Default::default()
                 };

+ 2 - 2
backend/src/service/doc/router.rs

@@ -7,7 +7,7 @@ use actix_web::{
     HttpResponse,
 };
 use anyhow::Context;
-use flowy_document::protobuf::{CreateDocParams, QueryDocParams, UpdateDocParams};
+use flowy_document::protobuf::{CreateDocParams, DocIdentifier, UpdateDocParams};
 use flowy_net::{errors::ServerError, response::FlowyResponse};
 use sqlx::PgPool;
 
@@ -31,7 +31,7 @@ pub async fn create_handler(payload: Payload, pool: Data<PgPool>) -> Result<Http
 
 #[tracing::instrument(level = "debug", skip(payload, pool), err)]
 pub async fn read_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
-    let params: QueryDocParams = parse_from_payload(payload).await?;
+    let params: DocIdentifier = parse_from_payload(payload).await?;
     let doc = read_doc(pool.get_ref(), params).await?;
     let response = FlowyResponse::success().pb(doc)?;
     Ok(response.into())

+ 1 - 0
backend/src/service/mod.rs

@@ -1,6 +1,7 @@
 pub mod app;
 pub mod doc;
 pub(crate) mod log;
+pub mod trash;
 pub mod user;
 pub(crate) mod util;
 pub mod view;

+ 4 - 0
backend/src/service/trash/mod.rs

@@ -0,0 +1,4 @@
+pub mod router;
+mod trash;
+
+pub(crate) use trash::*;

+ 23 - 0
backend/src/service/trash/router.rs

@@ -0,0 +1,23 @@
+use crate::service::util::parse_from_payload;
+use actix_web::{
+    web::{Data, Payload},
+    HttpResponse,
+};
+use flowy_net::errors::ServerError;
+use flowy_workspace::protobuf::{Trash, TrashIdentifiers};
+use sqlx::PgPool;
+
+pub async fn create_handler(payload: Payload, _pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
+    let _params: Trash = parse_from_payload(payload).await?;
+    unimplemented!()
+}
+
+pub async fn delete_handler(payload: Payload, _pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
+    let _params: TrashIdentifiers = parse_from_payload(payload).await?;
+    unimplemented!()
+}
+
+pub async fn read_handler(payload: Payload, _pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
+    let _params: TrashIdentifiers = parse_from_payload(payload).await?;
+    unimplemented!()
+}

+ 18 - 0
backend/src/service/trash/trash.rs

@@ -0,0 +1,18 @@
+use anyhow::Context;
+use flowy_net::{errors::ServerError, response::FlowyResponse};
+use flowy_workspace::protobuf::Trash;
+use sqlx::PgPool;
+
+pub(crate) async fn create_trash(pool: &PgPool, _params: Trash) -> Result<FlowyResponse, ServerError> {
+    let transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to create trash")?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to trash view.")?;
+
+    Ok(FlowyResponse::success())
+}

+ 1 - 2
backend/src/service/view/router.rs

@@ -2,10 +2,9 @@ use actix_web::{
     web::{Data, Payload},
     HttpResponse,
 };
-use sqlx::PgPool;
-
 use flowy_net::errors::ServerError;
 use flowy_workspace::protobuf::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams};
+use sqlx::PgPool;
 
 use crate::service::{
     doc::doc::DocBiz,

+ 3 - 3
backend/tests/api/doc.rs

@@ -1,12 +1,12 @@
 use crate::helper::ViewTest;
-use flowy_document::entities::doc::QueryDocParams;
+use flowy_document::entities::doc::DocIdentifier;
 use flowy_workspace::entities::view::DeleteViewParams;
 
 #[actix_rt::test]
 async fn doc_read() {
     let test = ViewTest::new().await;
 
-    let params = QueryDocParams {
+    let params = DocIdentifier {
         doc_id: test.view.id.clone(),
     };
 
@@ -22,7 +22,7 @@ async fn doc_delete() {
     };
     test.server.delete_view(delete_params).await;
 
-    let params = QueryDocParams {
+    let params = DocIdentifier {
         doc_id: test.view.id.clone(),
     };
     let doc = test.server.read_doc(params).await;

+ 2 - 2
backend/tests/document/helper.rs

@@ -6,7 +6,7 @@ use sqlx::PgPool;
 use tokio::time::{sleep, Duration};
 
 use backend::service::doc::{crud::update_doc, doc::DocManager};
-use flowy_document::{entities::doc::QueryDocParams, services::doc::edit::ClientEditDoc as ClientEditDocContext};
+use flowy_document::{entities::doc::DocIdentifier, services::doc::edit::ClientEditDoc as ClientEditDocContext};
 use flowy_net::config::ServerConfig;
 use flowy_test::{workspace::ViewTest, FlowyTest};
 use flowy_user::services::user::UserSession;
@@ -80,7 +80,7 @@ impl ScriptContext {
         let pool = self.client_user_session.db_pool().unwrap();
         let doc_id = self.doc_id.clone();
 
-        let edit_context = flowy_document.open(QueryDocParams { doc_id }, pool).await.unwrap();
+        let edit_context = flowy_document.open(DocIdentifier { doc_id }, pool).await.unwrap();
         self.client_edit_context = Some(edit_context);
     }
 

+ 2 - 2
backend/tests/helper.rs

@@ -6,7 +6,7 @@ use backend::{
 
 use backend::application::init_app_context;
 use flowy_document::{
-    entities::doc::{Doc, QueryDocParams},
+    entities::doc::{Doc, DocIdentifier},
     prelude::*,
 };
 use flowy_user::{errors::UserError, prelude::*};
@@ -122,7 +122,7 @@ impl TestUserServer {
         delete_view_request(self.user_token(), params, &url).await.unwrap();
     }
 
-    pub async fn read_doc(&self, params: QueryDocParams) -> Option<Doc> {
+    pub async fn read_doc(&self, params: DocIdentifier) -> Option<Doc> {
         let url = format!("{}/api/doc", self.http_addr());
         let doc = read_doc_request(self.user_token(), params, &url).await.unwrap();
         doc

+ 1 - 1
rust-lib/flowy-database/migrations/2021-07-09-063045_flowy-user/up.sql

@@ -49,5 +49,5 @@ CREATE TABLE trash_table (
     desc TEXT NOT NULL DEFAULT '',
     modified_time BIGINT NOT NULL DEFAULT 0,
     create_time BIGINT NOT NULL DEFAULT 0,
-    source INTEGER NOT NULL DEFAULT 0
+    ty INTEGER NOT NULL DEFAULT 0
 );

+ 1 - 1
rust-lib/flowy-database/src/schema.rs

@@ -40,7 +40,7 @@ table! {
         desc -> Text,
         modified_time -> BigInt,
         create_time -> BigInt,
-        source -> Integer,
+        ty -> Integer,
     }
 }
 

+ 4 - 2
rust-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -39,6 +39,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "QueryWorkspaceParams"
         | "CurrentWorkspace"
         | "TrashIdentifier"
+        | "TrashIdentifiers"
         | "CreateTrashParams"
         | "Trash"
         | "RepeatedTrash"
@@ -61,7 +62,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "UpdateDocParams"
         | "DocDelta"
         | "NewDocUser"
-        | "QueryDocParams"
+        | "DocIdentifier"
         | "RevId"
         | "Revision"
         | "RevisionRange"
@@ -82,7 +83,8 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         | "UpdateUserParams"
         | "UserError"
         => TypeCategory::Protobuf,
-        "ViewType"
+        "TrashType"
+        | "ViewType"
         | "WorkspaceEvent"
         | "ErrorCode"
         | "WorkspaceNotification"

+ 3 - 3
rust-lib/flowy-document/src/entities/doc/doc.rs

@@ -76,11 +76,11 @@ pub struct NewDocUser {
 }
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
-pub struct QueryDocParams {
+pub struct DocIdentifier {
     #[pb(index = 1)]
     pub doc_id: String,
 }
 
-impl std::convert::From<String> for QueryDocParams {
-    fn from(doc_id: String) -> Self { QueryDocParams { doc_id } }
+impl std::convert::From<String> for DocIdentifier {
+    fn from(doc_id: String) -> Self { DocIdentifier { doc_id } }
 }

+ 3 - 7
rust-lib/flowy-document/src/module.rs

@@ -1,5 +1,5 @@
 use crate::{
-    entities::doc::{CreateDocParams, DocDelta, QueryDocParams},
+    entities::doc::{CreateDocParams, DocDelta, DocIdentifier},
     errors::DocError,
     services::{
         doc::{doc_controller::DocController, edit::ClientEditDoc},
@@ -42,16 +42,12 @@ impl FlowyDocument {
         Ok(())
     }
 
-    pub fn delete(&self, params: QueryDocParams) -> Result<(), DocError> {
+    pub fn delete(&self, params: DocIdentifier) -> Result<(), DocError> {
         let _ = self.doc_ctrl.delete(params)?;
         Ok(())
     }
 
-    pub async fn open(
-        &self,
-        params: QueryDocParams,
-        pool: Arc<ConnectionPool>,
-    ) -> Result<Arc<ClientEditDoc>, DocError> {
+    pub async fn open(&self, params: DocIdentifier, pool: Arc<ConnectionPool>) -> Result<Arc<ClientEditDoc>, DocError> {
         let edit_context = self.doc_ctrl.open(params, pool).await?;
         Ok(edit_context)
     }

+ 28 - 28
rust-lib/flowy-document/src/protobuf/model/doc.rs

@@ -1169,7 +1169,7 @@ impl ::protobuf::reflect::ProtobufValue for NewDocUser {
 }
 
 #[derive(PartialEq,Clone,Default)]
-pub struct QueryDocParams {
+pub struct DocIdentifier {
     // message fields
     pub doc_id: ::std::string::String,
     // special fields
@@ -1177,14 +1177,14 @@ pub struct QueryDocParams {
     pub cached_size: ::protobuf::CachedSize,
 }
 
-impl<'a> ::std::default::Default for &'a QueryDocParams {
-    fn default() -> &'a QueryDocParams {
-        <QueryDocParams as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a DocIdentifier {
+    fn default() -> &'a DocIdentifier {
+        <DocIdentifier as ::protobuf::Message>::default_instance()
     }
 }
 
-impl QueryDocParams {
-    pub fn new() -> QueryDocParams {
+impl DocIdentifier {
+    pub fn new() -> DocIdentifier {
         ::std::default::Default::default()
     }
 
@@ -1215,7 +1215,7 @@ impl QueryDocParams {
     }
 }
 
-impl ::protobuf::Message for QueryDocParams {
+impl ::protobuf::Message for DocIdentifier {
     fn is_initialized(&self) -> bool {
         true
     }
@@ -1281,8 +1281,8 @@ impl ::protobuf::Message for QueryDocParams {
         Self::descriptor_static()
     }
 
-    fn new() -> QueryDocParams {
-        QueryDocParams::new()
+    fn new() -> DocIdentifier {
+        DocIdentifier::new()
     }
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -1291,37 +1291,37 @@ impl ::protobuf::Message for QueryDocParams {
             let mut fields = ::std::vec::Vec::new();
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
                 "doc_id",
-                |m: &QueryDocParams| { &m.doc_id },
-                |m: &mut QueryDocParams| { &mut m.doc_id },
+                |m: &DocIdentifier| { &m.doc_id },
+                |m: &mut DocIdentifier| { &mut m.doc_id },
             ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryDocParams>(
-                "QueryDocParams",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<DocIdentifier>(
+                "DocIdentifier",
                 fields,
                 file_descriptor_proto()
             )
         })
     }
 
-    fn default_instance() -> &'static QueryDocParams {
-        static instance: ::protobuf::rt::LazyV2<QueryDocParams> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(QueryDocParams::new)
+    fn default_instance() -> &'static DocIdentifier {
+        static instance: ::protobuf::rt::LazyV2<DocIdentifier> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(DocIdentifier::new)
     }
 }
 
-impl ::protobuf::Clear for QueryDocParams {
+impl ::protobuf::Clear for DocIdentifier {
     fn clear(&mut self) {
         self.doc_id.clear();
         self.unknown_fields.clear();
     }
 }
 
-impl ::std::fmt::Debug for QueryDocParams {
+impl ::std::fmt::Debug for DocIdentifier {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         ::protobuf::text_format::fmt(self, f)
     }
 }
 
-impl ::protobuf::reflect::ProtobufValue for QueryDocParams {
+impl ::protobuf::reflect::ProtobufValue for DocIdentifier {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
@@ -1339,14 +1339,14 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     cId\x12\x12\n\x04data\x18\x02\x20\x01(\tR\x04data\"S\n\nNewDocUser\x12\
     \x17\n\x07user_id\x18\x01\x20\x01(\tR\x06userId\x12\x15\n\x06rev_id\x18\
     \x02\x20\x01(\x03R\x05revId\x12\x15\n\x06doc_id\x18\x03\x20\x01(\tR\x05d\
-    ocId\"'\n\x0eQueryDocParams\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05d\
-    ocIdJ\xdb\x07\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\
-    \n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\
-    \x08\x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x04\0\
-    \x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\
-    \r\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\x04\x04\0\x02\
-    \x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\
-    \n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\
+    ocId\"&\n\rDocIdentifier\x12\x15\n\x06doc_id\x18\x01\x20\x01(\tR\x05docI\
+    dJ\xdb\x07\n\x06\x12\x04\0\0\x1c\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\
+    \n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\
+    \x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x04\0\x02\0\
+    \x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\r\n\
+    \x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\x04\x04\0\x02\x01\
+    \x12\x03\x04\x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\
+    \x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\
     \x01\x03\x12\x03\x04\x12\x13\n\n\n\x02\x04\x01\x12\x04\x06\0\x0b\x01\n\n\
     \n\x03\x04\x01\x01\x12\x03\x06\x08\x0b\n\x0b\n\x04\x04\x01\x02\0\x12\x03\
     \x07\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\x0c\n\x05\
@@ -1386,7 +1386,7 @@ static file_descriptor_proto_data: &'static [u8] = b"\
     \x0c\n\x05\x04\x04\x02\x02\x05\x12\x03\x18\x04\n\n\x0c\n\x05\x04\x04\x02\
     \x02\x01\x12\x03\x18\x0b\x11\n\x0c\n\x05\x04\x04\x02\x02\x03\x12\x03\x18\
     \x14\x15\n\n\n\x02\x04\x05\x12\x04\x1a\0\x1c\x01\n\n\n\x03\x04\x05\x01\
-    \x12\x03\x1a\x08\x16\n\x0b\n\x04\x04\x05\x02\0\x12\x03\x1b\x04\x16\n\x0c\
+    \x12\x03\x1a\x08\x15\n\x0b\n\x04\x04\x05\x02\0\x12\x03\x1b\x04\x16\n\x0c\
     \n\x05\x04\x05\x02\0\x05\x12\x03\x1b\x04\n\n\x0c\n\x05\x04\x05\x02\0\x01\
     \x12\x03\x1b\x0b\x11\n\x0c\n\x05\x04\x05\x02\0\x03\x12\x03\x1b\x14\x15b\
     \x06proto3\

+ 1 - 1
rust-lib/flowy-document/src/protobuf/proto/doc.proto

@@ -24,6 +24,6 @@ message NewDocUser {
     int64 rev_id = 2;
     string doc_id = 3;
 }
-message QueryDocParams {
+message DocIdentifier {
     string doc_id = 1;
 }

+ 5 - 5
rust-lib/flowy-document/src/services/doc/doc_controller.rs

@@ -3,7 +3,7 @@ use std::sync::Arc;
 use bytes::Bytes;
 
 use crate::{
-    entities::doc::{CreateDocParams, Doc, DocDelta, QueryDocParams},
+    entities::doc::{CreateDocParams, Doc, DocDelta, DocIdentifier},
     errors::{DocError, DocResult},
     module::DocumentUser,
     services::{
@@ -59,7 +59,7 @@ impl DocController {
     #[tracing::instrument(level = "debug", skip(self, pool), err)]
     pub(crate) async fn open(
         &self,
-        params: QueryDocParams,
+        params: DocIdentifier,
         pool: Arc<ConnectionPool>,
     ) -> Result<Arc<ClientEditDoc>, DocError> {
         if self.cache.is_opened(&params.doc_id) == false {
@@ -78,7 +78,7 @@ impl DocController {
     }
 
     #[tracing::instrument(level = "debug", skip(self), err)]
-    pub(crate) fn delete(&self, params: QueryDocParams) -> Result<(), DocError> {
+    pub(crate) fn delete(&self, params: DocIdentifier) -> Result<(), DocError> {
         let doc_id = &params.doc_id;
         self.cache.remove(doc_id);
         self.ws_manager.remove_handler(doc_id);
@@ -96,7 +96,7 @@ impl DocController {
 
 impl DocController {
     #[tracing::instrument(level = "debug", skip(self), err)]
-    fn delete_doc_on_server(&self, params: QueryDocParams) -> Result<(), DocError> {
+    fn delete_doc_on_server(&self, params: DocIdentifier) -> Result<(), DocError> {
         let token = self.user.token()?;
         let server = self.server.clone();
         tokio::spawn(async move {
@@ -138,7 +138,7 @@ struct RevisionServerImpl {
 
 impl RevisionServer for RevisionServerImpl {
     fn fetch_document_from_remote(&self, doc_id: &str) -> ResultFuture<Doc, DocError> {
-        let params = QueryDocParams {
+        let params = DocIdentifier {
             doc_id: doc_id.to_string(),
         };
         let server = self.server.clone();

+ 3 - 3
rust-lib/flowy-document/src/services/server/mod.rs

@@ -5,7 +5,7 @@ mod server_api_mock;
 pub use server_api::*;
 // TODO: ignore mock files in production
 use crate::{
-    entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams},
+    entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams},
     errors::DocError,
 };
 use flowy_infra::future::ResultFuture;
@@ -17,11 +17,11 @@ pub(crate) type Server = Arc<dyn DocumentServerAPI + Send + Sync>;
 pub trait DocumentServerAPI {
     fn create_doc(&self, token: &str, params: CreateDocParams) -> ResultFuture<(), DocError>;
 
-    fn read_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<Option<Doc>, DocError>;
+    fn read_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError>;
 
     fn update_doc(&self, token: &str, params: UpdateDocParams) -> ResultFuture<(), DocError>;
 
-    fn delete_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<(), DocError>;
+    fn delete_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<(), DocError>;
 }
 
 pub(crate) fn construct_doc_server(server_config: &ServerConfig) -> Arc<dyn DocumentServerAPI + Send + Sync> {

+ 5 - 5
rust-lib/flowy-document/src/services/server/server_api.rs

@@ -1,5 +1,5 @@
 use crate::{
-    entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams},
+    entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams},
     errors::DocError,
     services::server::DocumentServerAPI,
 };
@@ -21,7 +21,7 @@ impl DocumentServerAPI for DocServer {
         ResultFuture::new(async move { create_doc_request(&token, params, &url).await })
     }
 
-    fn read_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<Option<Doc>, DocError> {
+    fn read_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError> {
         let token = token.to_owned();
         let url = self.config.doc_url();
         ResultFuture::new(async move { read_doc_request(&token, params, &url).await })
@@ -33,7 +33,7 @@ impl DocumentServerAPI for DocServer {
         ResultFuture::new(async move { update_doc_request(&token, params, &url).await })
     }
 
-    fn delete_doc(&self, token: &str, params: QueryDocParams) -> ResultFuture<(), DocError> {
+    fn delete_doc(&self, token: &str, params: DocIdentifier) -> ResultFuture<(), DocError> {
         let token = token.to_owned();
         let url = self.config.doc_url();
         ResultFuture::new(async move { delete_doc_request(&token, params, &url).await })
@@ -54,7 +54,7 @@ pub async fn create_doc_request(token: &str, params: CreateDocParams, url: &str)
     Ok(())
 }
 
-pub async fn read_doc_request(token: &str, params: QueryDocParams, url: &str) -> Result<Option<Doc>, DocError> {
+pub async fn read_doc_request(token: &str, params: DocIdentifier, url: &str) -> Result<Option<Doc>, DocError> {
     let doc = request_builder()
         .get(&url.to_owned())
         .header(HEADER_TOKEN, token)
@@ -75,7 +75,7 @@ pub async fn update_doc_request(token: &str, params: UpdateDocParams, url: &str)
     Ok(())
 }
 
-pub async fn delete_doc_request(token: &str, params: QueryDocParams, url: &str) -> Result<(), DocError> {
+pub async fn delete_doc_request(token: &str, params: DocIdentifier, url: &str) -> Result<(), DocError> {
     let _ = request_builder()
         .delete(url)
         .header(HEADER_TOKEN, token)

+ 3 - 3
rust-lib/flowy-document/src/services/server/server_api_mock.rs

@@ -1,5 +1,5 @@
 use crate::{
-    entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams},
+    entities::doc::{CreateDocParams, Doc, DocIdentifier, UpdateDocParams},
     errors::DocError,
     services::server::DocumentServerAPI,
 };
@@ -11,7 +11,7 @@ impl DocumentServerAPI for DocServerMock {
         ResultFuture::new(async { Ok(()) })
     }
 
-    fn read_doc(&self, _token: &str, _params: QueryDocParams) -> ResultFuture<Option<Doc>, DocError> {
+    fn read_doc(&self, _token: &str, _params: DocIdentifier) -> ResultFuture<Option<Doc>, DocError> {
         ResultFuture::new(async { Ok(None) })
     }
 
@@ -19,7 +19,7 @@ impl DocumentServerAPI for DocServerMock {
         ResultFuture::new(async { Ok(()) })
     }
 
-    fn delete_doc(&self, _token: &str, _params: QueryDocParams) -> ResultFuture<(), DocError> {
+    fn delete_doc(&self, _token: &str, _params: DocIdentifier) -> ResultFuture<(), DocError> {
         ResultFuture::new(async { Ok(()) })
     }
 }

+ 16 - 10
rust-lib/flowy-workspace/src/entities/trash/trash_create.rs

@@ -1,6 +1,15 @@
-use crate::{impl_def_and_def_mut};
-use flowy_derive::ProtoBuf;
-use std::convert::TryInto;
+use crate::impl_def_and_def_mut;
+use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
+
+#[derive(PartialEq, Debug, ProtoBuf_Enum, Clone)]
+pub enum TrashType {
+    Unknown = 0,
+    View    = 1,
+}
+
+impl std::default::Default for TrashType {
+    fn default() -> Self { TrashType::Unknown }
+}
 
 #[derive(PartialEq, ProtoBuf, Default, Debug, Clone)]
 pub struct CreateTrashParams {
@@ -8,13 +17,7 @@ pub struct CreateTrashParams {
     pub id: String,
 
     #[pb(index = 2)]
-    pub name: String,
-
-    #[pb(index = 3)]
-    pub modified_time: i64,
-
-    #[pb(index = 4)]
-    pub create_time: i64,
+    pub ty: TrashType,
 }
 
 #[derive(PartialEq, ProtoBuf, Default, Debug, Clone)]
@@ -30,6 +33,9 @@ pub struct Trash {
 
     #[pb(index = 4)]
     pub create_time: i64,
+
+    #[pb(index = 5)]
+    pub ty: TrashType,
 }
 
 #[derive(PartialEq, Debug, Default, ProtoBuf, Clone)]

+ 6 - 0
rust-lib/flowy-workspace/src/entities/trash/trash_delete.rs

@@ -5,3 +5,9 @@ pub struct TrashIdentifier {
     #[pb(index = 1)]
     pub id: String,
 }
+
+#[derive(PartialEq, ProtoBuf, Default, Debug, Clone)]
+pub struct TrashIdentifiers {
+    #[pb(index = 1)]
+    pub ids: Vec<String>,
+}

+ 6 - 1
rust-lib/flowy-workspace/src/entities/view/view_create.rs

@@ -1,5 +1,9 @@
 use crate::{
-    entities::{app::parser::AppId, trash::Trash, view::parser::*},
+    entities::{
+        app::parser::AppId,
+        trash::{Trash, TrashType},
+        view::parser::*,
+    },
     errors::WorkspaceError,
     impl_def_and_def_mut,
 };
@@ -161,6 +165,7 @@ impl std::convert::Into<Trash> for View {
             name: self.name,
             modified_time: self.modified_time,
             create_time: self.create_time,
+            ty: TrashType::View,
         }
     }
 }

+ 6 - 6
rust-lib/flowy-workspace/src/entities/view/view_query.rs

@@ -1,6 +1,6 @@
 use crate::{entities::view::parser::ViewId, errors::WorkspaceError};
 use flowy_derive::ProtoBuf;
-use flowy_document::entities::doc::QueryDocParams;
+use flowy_document::entities::doc::DocIdentifier;
 use std::convert::TryInto;
 
 #[derive(Default, ProtoBuf)]
@@ -61,8 +61,8 @@ impl QueryViewParams {
     }
 }
 
-impl std::convert::Into<QueryDocParams> for QueryViewParams {
-    fn into(self) -> QueryDocParams { QueryDocParams { doc_id: self.view_id } }
+impl std::convert::Into<DocIdentifier> for QueryViewParams {
+    fn into(self) -> DocIdentifier { DocIdentifier { doc_id: self.view_id } }
 }
 
 impl TryInto<QueryViewParams> for QueryViewRequest {
@@ -86,13 +86,13 @@ pub struct OpenViewRequest {
     pub view_id: String,
 }
 
-impl std::convert::TryInto<QueryDocParams> for OpenViewRequest {
+impl std::convert::TryInto<DocIdentifier> for OpenViewRequest {
     type Error = WorkspaceError;
 
-    fn try_into(self) -> Result<QueryDocParams, Self::Error> {
+    fn try_into(self) -> Result<DocIdentifier, Self::Error> {
         let view_id = ViewId::parse(self.view_id)
             .map_err(|e| WorkspaceError::view_id().context(e))?
             .0;
-        Ok(QueryDocParams { doc_id: view_id })
+        Ok(DocIdentifier { doc_id: view_id })
     }
 }

+ 2 - 2
rust-lib/flowy-workspace/src/handlers/view_handler.rs

@@ -15,7 +15,7 @@ use crate::{
     services::ViewController,
 };
 use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
-use flowy_document::entities::doc::{DocDelta, QueryDocParams};
+use flowy_document::entities::doc::{DocDelta, DocIdentifier};
 use std::{convert::TryInto, sync::Arc};
 
 #[tracing::instrument(skip(data, controller), err)]
@@ -79,7 +79,7 @@ pub(crate) async fn open_view_handler(
     data: Data<OpenViewRequest>,
     controller: Unit<Arc<ViewController>>,
 ) -> DataResult<DocDelta, WorkspaceError> {
-    let params: QueryDocParams = data.into_inner().try_into()?;
+    let params: DocIdentifier = data.into_inner().try_into()?;
     let doc = controller.open_view(params).await?;
     data_result(doc)
 }

+ 140 - 137
rust-lib/flowy-workspace/src/protobuf/model/trash_create.rs

@@ -27,9 +27,7 @@
 pub struct CreateTrashParams {
     // message fields
     pub id: ::std::string::String,
-    pub name: ::std::string::String,
-    pub modified_time: i64,
-    pub create_time: i64,
+    pub ty: TrashType,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -72,60 +70,19 @@ impl CreateTrashParams {
         ::std::mem::replace(&mut self.id, ::std::string::String::new())
     }
 
-    // string name = 2;
-
-
-    pub fn get_name(&self) -> &str {
-        &self.name
-    }
-    pub fn clear_name(&mut self) {
-        self.name.clear();
-    }
-
-    // Param is passed by value, moved
-    pub fn set_name(&mut self, v: ::std::string::String) {
-        self.name = v;
-    }
-
-    // Mutable pointer to the field.
-    // If field is not initialized, it is initialized with default value first.
-    pub fn mut_name(&mut self) -> &mut ::std::string::String {
-        &mut self.name
-    }
-
-    // Take field
-    pub fn take_name(&mut self) -> ::std::string::String {
-        ::std::mem::replace(&mut self.name, ::std::string::String::new())
-    }
-
-    // int64 modified_time = 3;
-
-
-    pub fn get_modified_time(&self) -> i64 {
-        self.modified_time
-    }
-    pub fn clear_modified_time(&mut self) {
-        self.modified_time = 0;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_modified_time(&mut self, v: i64) {
-        self.modified_time = v;
-    }
-
-    // int64 create_time = 4;
+    // .TrashType ty = 2;
 
 
-    pub fn get_create_time(&self) -> i64 {
-        self.create_time
+    pub fn get_ty(&self) -> TrashType {
+        self.ty
     }
-    pub fn clear_create_time(&mut self) {
-        self.create_time = 0;
+    pub fn clear_ty(&mut self) {
+        self.ty = TrashType::Unknown;
     }
 
     // Param is passed by value, moved
-    pub fn set_create_time(&mut self, v: i64) {
-        self.create_time = v;
+    pub fn set_ty(&mut self, v: TrashType) {
+        self.ty = v;
     }
 }
 
@@ -142,21 +99,7 @@ impl ::protobuf::Message for CreateTrashParams {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
                 },
                 2 => {
-                    ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.name)?;
-                },
-                3 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int64()?;
-                    self.modified_time = tmp;
-                },
-                4 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_int64()?;
-                    self.create_time = tmp;
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 2, &mut self.unknown_fields)?
                 },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@@ -173,14 +116,8 @@ impl ::protobuf::Message for CreateTrashParams {
         if !self.id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.id);
         }
-        if !self.name.is_empty() {
-            my_size += ::protobuf::rt::string_size(2, &self.name);
-        }
-        if self.modified_time != 0 {
-            my_size += ::protobuf::rt::value_size(3, self.modified_time, ::protobuf::wire_format::WireTypeVarint);
-        }
-        if self.create_time != 0 {
-            my_size += ::protobuf::rt::value_size(4, self.create_time, ::protobuf::wire_format::WireTypeVarint);
+        if self.ty != TrashType::Unknown {
+            my_size += ::protobuf::rt::enum_size(2, self.ty);
         }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
@@ -191,14 +128,8 @@ impl ::protobuf::Message for CreateTrashParams {
         if !self.id.is_empty() {
             os.write_string(1, &self.id)?;
         }
-        if !self.name.is_empty() {
-            os.write_string(2, &self.name)?;
-        }
-        if self.modified_time != 0 {
-            os.write_int64(3, self.modified_time)?;
-        }
-        if self.create_time != 0 {
-            os.write_int64(4, self.create_time)?;
+        if self.ty != TrashType::Unknown {
+            os.write_enum(2, ::protobuf::ProtobufEnum::value(&self.ty))?;
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
@@ -243,20 +174,10 @@ impl ::protobuf::Message for CreateTrashParams {
                 |m: &CreateTrashParams| { &m.id },
                 |m: &mut CreateTrashParams| { &mut m.id },
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
-                "name",
-                |m: &CreateTrashParams| { &m.name },
-                |m: &mut CreateTrashParams| { &mut m.name },
-            ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
-                "modified_time",
-                |m: &CreateTrashParams| { &m.modified_time },
-                |m: &mut CreateTrashParams| { &mut m.modified_time },
-            ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>(
-                "create_time",
-                |m: &CreateTrashParams| { &m.create_time },
-                |m: &mut CreateTrashParams| { &mut m.create_time },
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<TrashType>>(
+                "ty",
+                |m: &CreateTrashParams| { &m.ty },
+                |m: &mut CreateTrashParams| { &mut m.ty },
             ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<CreateTrashParams>(
                 "CreateTrashParams",
@@ -275,9 +196,7 @@ impl ::protobuf::Message for CreateTrashParams {
 impl ::protobuf::Clear for CreateTrashParams {
     fn clear(&mut self) {
         self.id.clear();
-        self.name.clear();
-        self.modified_time = 0;
-        self.create_time = 0;
+        self.ty = TrashType::Unknown;
         self.unknown_fields.clear();
     }
 }
@@ -301,6 +220,7 @@ pub struct Trash {
     pub name: ::std::string::String,
     pub modified_time: i64,
     pub create_time: i64,
+    pub ty: TrashType,
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
@@ -398,6 +318,21 @@ impl Trash {
     pub fn set_create_time(&mut self, v: i64) {
         self.create_time = v;
     }
+
+    // .TrashType ty = 5;
+
+
+    pub fn get_ty(&self) -> TrashType {
+        self.ty
+    }
+    pub fn clear_ty(&mut self) {
+        self.ty = TrashType::Unknown;
+    }
+
+    // Param is passed by value, moved
+    pub fn set_ty(&mut self, v: TrashType) {
+        self.ty = v;
+    }
 }
 
 impl ::protobuf::Message for Trash {
@@ -429,6 +364,9 @@ impl ::protobuf::Message for Trash {
                     let tmp = is.read_int64()?;
                     self.create_time = tmp;
                 },
+                5 => {
+                    ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 5, &mut self.unknown_fields)?
+                },
                 _ => {
                     ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
                 },
@@ -453,6 +391,9 @@ impl ::protobuf::Message for Trash {
         if self.create_time != 0 {
             my_size += ::protobuf::rt::value_size(4, self.create_time, ::protobuf::wire_format::WireTypeVarint);
         }
+        if self.ty != TrashType::Unknown {
+            my_size += ::protobuf::rt::enum_size(5, self.ty);
+        }
         my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
         self.cached_size.set(my_size);
         my_size
@@ -471,6 +412,9 @@ impl ::protobuf::Message for Trash {
         if self.create_time != 0 {
             os.write_int64(4, self.create_time)?;
         }
+        if self.ty != TrashType::Unknown {
+            os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.ty))?;
+        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
     }
@@ -529,6 +473,11 @@ impl ::protobuf::Message for Trash {
                 |m: &Trash| { &m.create_time },
                 |m: &mut Trash| { &mut m.create_time },
             ));
+            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<TrashType>>(
+                "ty",
+                |m: &Trash| { &m.ty },
+                |m: &mut Trash| { &mut m.ty },
+            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<Trash>(
                 "Trash",
                 fields,
@@ -549,6 +498,7 @@ impl ::protobuf::Clear for Trash {
         self.name.clear();
         self.modified_time = 0;
         self.create_time = 0;
+        self.ty = TrashType::Unknown;
         self.unknown_fields.clear();
     }
 }
@@ -731,45 +681,98 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedTrash {
     }
 }
 
+#[derive(Clone,PartialEq,Eq,Debug,Hash)]
+pub enum TrashType {
+    Unknown = 0,
+    View = 1,
+}
+
+impl ::protobuf::ProtobufEnum for TrashType {
+    fn value(&self) -> i32 {
+        *self as i32
+    }
+
+    fn from_i32(value: i32) -> ::std::option::Option<TrashType> {
+        match value {
+            0 => ::std::option::Option::Some(TrashType::Unknown),
+            1 => ::std::option::Option::Some(TrashType::View),
+            _ => ::std::option::Option::None
+        }
+    }
+
+    fn values() -> &'static [Self] {
+        static values: &'static [TrashType] = &[
+            TrashType::Unknown,
+            TrashType::View,
+        ];
+        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::<TrashType>("TrashType", file_descriptor_proto())
+        })
+    }
+}
+
+impl ::std::marker::Copy for TrashType {
+}
+
+impl ::std::default::Default for TrashType {
+    fn default() -> Self {
+        TrashType::Unknown
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for TrashType {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x12trash_create.proto\"}\n\x11CreateTrashParams\x12\x0e\n\x02id\x18\
-    \x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12\
-    #\n\rmodified_time\x18\x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcr\
-    eate_time\x18\x04\x20\x01(\x03R\ncreateTime\"q\n\x05Trash\x12\x0e\n\x02i\
-    d\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04nam\
-    e\x12#\n\rmodified_time\x18\x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\
-    \x0bcreate_time\x18\x04\x20\x01(\x03R\ncreateTime\"-\n\rRepeatedTrash\
-    \x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.TrashR\x05itemsJ\xd7\x04\n\
-    \x06\x12\x04\0\0\x10\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\
-    \x12\x04\x02\0\x07\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\x0b\n\
-    \x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x04\0\x02\0\x05\x12\x03\
-    \x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\r\n\x0c\n\x05\x04\
-    \0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\
-    \x04\x14\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\n\n\x0c\n\x05\x04\
-    \0\x02\x01\x01\x12\x03\x04\x0b\x0f\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\
-    \x04\x12\x13\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x1c\n\x0c\n\x05\
-    \x04\0\x02\x02\x05\x12\x03\x05\x04\t\n\x0c\n\x05\x04\0\x02\x02\x01\x12\
-    \x03\x05\n\x17\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x1a\x1b\n\x0b\n\
-    \x04\x04\0\x02\x03\x12\x03\x06\x04\x1a\n\x0c\n\x05\x04\0\x02\x03\x05\x12\
-    \x03\x06\x04\t\n\x0c\n\x05\x04\0\x02\x03\x01\x12\x03\x06\n\x15\n\x0c\n\
-    \x05\x04\0\x02\x03\x03\x12\x03\x06\x18\x19\n\n\n\x02\x04\x01\x12\x04\x08\
-    \0\r\x01\n\n\n\x03\x04\x01\x01\x12\x03\x08\x08\r\n\x0b\n\x04\x04\x01\x02\
-    \0\x12\x03\t\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\t\x04\n\n\x0c\
-    \n\x05\x04\x01\x02\0\x01\x12\x03\t\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\
-    \x12\x03\t\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\n\x04\x14\n\x0c\n\
-    \x05\x04\x01\x02\x01\x05\x12\x03\n\x04\n\n\x0c\n\x05\x04\x01\x02\x01\x01\
-    \x12\x03\n\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\n\x12\x13\n\
-    \x0b\n\x04\x04\x01\x02\x02\x12\x03\x0b\x04\x1c\n\x0c\n\x05\x04\x01\x02\
-    \x02\x05\x12\x03\x0b\x04\t\n\x0c\n\x05\x04\x01\x02\x02\x01\x12\x03\x0b\n\
-    \x17\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\x0b\x1a\x1b\n\x0b\n\x04\x04\
-    \x01\x02\x03\x12\x03\x0c\x04\x1a\n\x0c\n\x05\x04\x01\x02\x03\x05\x12\x03\
-    \x0c\x04\t\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\x0c\n\x15\n\x0c\n\x05\
-    \x04\x01\x02\x03\x03\x12\x03\x0c\x18\x19\n\n\n\x02\x04\x02\x12\x04\x0e\0\
-    \x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\x0e\x08\x15\n\x0b\n\x04\x04\x02\
-    \x02\0\x12\x03\x0f\x04\x1d\n\x0c\n\x05\x04\x02\x02\0\x04\x12\x03\x0f\x04\
-    \x0c\n\x0c\n\x05\x04\x02\x02\0\x06\x12\x03\x0f\r\x12\n\x0c\n\x05\x04\x02\
-    \x02\0\x01\x12\x03\x0f\x13\x18\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0f\
-    \x1b\x1cb\x06proto3\
+    \n\x12trash_create.proto\"?\n\x11CreateTrashParams\x12\x0e\n\x02id\x18\
+    \x01\x20\x01(\tR\x02id\x12\x1a\n\x02ty\x18\x02\x20\x01(\x0e2\n.TrashType\
+    R\x02ty\"\x8d\x01\n\x05Trash\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\
+    \x12\x12\n\x04name\x18\x02\x20\x01(\tR\x04name\x12#\n\rmodified_time\x18\
+    \x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcreate_time\x18\x04\x20\
+    \x01(\x03R\ncreateTime\x12\x1a\n\x02ty\x18\x05\x20\x01(\x0e2\n.TrashType\
+    R\x02ty\"-\n\rRepeatedTrash\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06\
+    .TrashR\x05items*\"\n\tTrashType\x12\x0b\n\x07Unknown\x10\0\x12\x08\n\
+    \x04View\x10\x01J\x8a\x05\n\x06\x12\x04\0\0\x13\x01\n\x08\n\x01\x0c\x12\
+    \x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\
+    \x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\
+    \x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\
+    \x03\x03\x0b\r\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11\n\x0b\n\
+    \x04\x04\0\x02\x01\x12\x03\x04\x04\x15\n\x0c\n\x05\x04\0\x02\x01\x06\x12\
+    \x03\x04\x04\r\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0e\x10\n\x0c\n\
+    \x05\x04\0\x02\x01\x03\x12\x03\x04\x13\x14\n\n\n\x02\x04\x01\x12\x04\x06\
+    \0\x0c\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\r\n\x0b\n\x04\x04\x01\
+    \x02\0\x12\x03\x07\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\
+    \n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\r\n\x0c\n\x05\x04\x01\
+    \x02\0\x03\x12\x03\x07\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\
+    \x04\x14\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x08\x04\n\n\x0c\n\x05\
+    \x04\x01\x02\x01\x01\x12\x03\x08\x0b\x0f\n\x0c\n\x05\x04\x01\x02\x01\x03\
+    \x12\x03\x08\x12\x13\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\t\x04\x1c\n\x0c\
+    \n\x05\x04\x01\x02\x02\x05\x12\x03\t\x04\t\n\x0c\n\x05\x04\x01\x02\x02\
+    \x01\x12\x03\t\n\x17\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\t\x1a\x1b\n\
+    \x0b\n\x04\x04\x01\x02\x03\x12\x03\n\x04\x1a\n\x0c\n\x05\x04\x01\x02\x03\
+    \x05\x12\x03\n\x04\t\n\x0c\n\x05\x04\x01\x02\x03\x01\x12\x03\n\n\x15\n\
+    \x0c\n\x05\x04\x01\x02\x03\x03\x12\x03\n\x18\x19\n\x0b\n\x04\x04\x01\x02\
+    \x04\x12\x03\x0b\x04\x15\n\x0c\n\x05\x04\x01\x02\x04\x06\x12\x03\x0b\x04\
+    \r\n\x0c\n\x05\x04\x01\x02\x04\x01\x12\x03\x0b\x0e\x10\n\x0c\n\x05\x04\
+    \x01\x02\x04\x03\x12\x03\x0b\x13\x14\n\n\n\x02\x04\x02\x12\x04\r\0\x0f\
+    \x01\n\n\n\x03\x04\x02\x01\x12\x03\r\x08\x15\n\x0b\n\x04\x04\x02\x02\0\
+    \x12\x03\x0e\x04\x1d\n\x0c\n\x05\x04\x02\x02\0\x04\x12\x03\x0e\x04\x0c\n\
+    \x0c\n\x05\x04\x02\x02\0\x06\x12\x03\x0e\r\x12\n\x0c\n\x05\x04\x02\x02\0\
+    \x01\x12\x03\x0e\x13\x18\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0e\x1b\
+    \x1c\n\n\n\x02\x05\0\x12\x04\x10\0\x13\x01\n\n\n\x03\x05\0\x01\x12\x03\
+    \x10\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\x11\x04\x10\n\x0c\n\x05\x05\
+    \0\x02\0\x01\x12\x03\x11\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x11\
+    \x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x12\x04\r\n\x0c\n\x05\x05\0\
+    \x02\x01\x01\x12\x03\x12\x04\x08\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\
+    \x12\x0b\x0cb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 169 - 5
rust-lib/flowy-workspace/src/protobuf/model/trash_delete.rs

@@ -182,13 +182,177 @@ impl ::protobuf::reflect::ProtobufValue for TrashIdentifier {
     }
 }
 
+#[derive(PartialEq,Clone,Default)]
+pub struct TrashIdentifiers {
+    // message fields
+    pub ids: ::protobuf::RepeatedField<::std::string::String>,
+    // special fields
+    pub unknown_fields: ::protobuf::UnknownFields,
+    pub cached_size: ::protobuf::CachedSize,
+}
+
+impl<'a> ::std::default::Default for &'a TrashIdentifiers {
+    fn default() -> &'a TrashIdentifiers {
+        <TrashIdentifiers as ::protobuf::Message>::default_instance()
+    }
+}
+
+impl TrashIdentifiers {
+    pub fn new() -> TrashIdentifiers {
+        ::std::default::Default::default()
+    }
+
+    // repeated string ids = 1;
+
+
+    pub fn get_ids(&self) -> &[::std::string::String] {
+        &self.ids
+    }
+    pub fn clear_ids(&mut self) {
+        self.ids.clear();
+    }
+
+    // Param is passed by value, moved
+    pub fn set_ids(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) {
+        self.ids = v;
+    }
+
+    // Mutable pointer to the field.
+    pub fn mut_ids(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> {
+        &mut self.ids
+    }
+
+    // Take field
+    pub fn take_ids(&mut self) -> ::protobuf::RepeatedField<::std::string::String> {
+        ::std::mem::replace(&mut self.ids, ::protobuf::RepeatedField::new())
+    }
+}
+
+impl ::protobuf::Message for TrashIdentifiers {
+    fn is_initialized(&self) -> bool {
+        true
+    }
+
+    fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        while !is.eof()? {
+            let (field_number, wire_type) = is.read_tag_unpack()?;
+            match field_number {
+                1 => {
+                    ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.ids)?;
+                },
+                _ => {
+                    ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
+                },
+            };
+        }
+        ::std::result::Result::Ok(())
+    }
+
+    // Compute sizes of nested messages
+    #[allow(unused_variables)]
+    fn compute_size(&self) -> u32 {
+        let mut my_size = 0;
+        for value in &self.ids {
+            my_size += ::protobuf::rt::string_size(1, &value);
+        };
+        my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
+        self.cached_size.set(my_size);
+        my_size
+    }
+
+    fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
+        for v in &self.ids {
+            os.write_string(1, &v)?;
+        };
+        os.write_unknown_fields(self.get_unknown_fields())?;
+        ::std::result::Result::Ok(())
+    }
+
+    fn get_cached_size(&self) -> u32 {
+        self.cached_size.get()
+    }
+
+    fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
+        &self.unknown_fields
+    }
+
+    fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
+        &mut self.unknown_fields
+    }
+
+    fn as_any(&self) -> &dyn (::std::any::Any) {
+        self as &dyn (::std::any::Any)
+    }
+    fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
+        self as &mut dyn (::std::any::Any)
+    }
+    fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
+        self
+    }
+
+    fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
+        Self::descriptor_static()
+    }
+
+    fn new() -> TrashIdentifiers {
+        TrashIdentifiers::new()
+    }
+
+    fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
+        static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
+        descriptor.get(|| {
+            let mut fields = ::std::vec::Vec::new();
+            fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
+                "ids",
+                |m: &TrashIdentifiers| { &m.ids },
+                |m: &mut TrashIdentifiers| { &mut m.ids },
+            ));
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<TrashIdentifiers>(
+                "TrashIdentifiers",
+                fields,
+                file_descriptor_proto()
+            )
+        })
+    }
+
+    fn default_instance() -> &'static TrashIdentifiers {
+        static instance: ::protobuf::rt::LazyV2<TrashIdentifiers> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(TrashIdentifiers::new)
+    }
+}
+
+impl ::protobuf::Clear for TrashIdentifiers {
+    fn clear(&mut self) {
+        self.ids.clear();
+        self.unknown_fields.clear();
+    }
+}
+
+impl ::std::fmt::Debug for TrashIdentifiers {
+    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+        ::protobuf::text_format::fmt(self, f)
+    }
+}
+
+impl ::protobuf::reflect::ProtobufValue for TrashIdentifiers {
+    fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
+        ::protobuf::reflect::ReflectValueRef::Message(self)
+    }
+}
+
 static file_descriptor_proto_data: &'static [u8] = b"\
     \n\x12trash_delete.proto\"!\n\x0fTrashIdentifier\x12\x0e\n\x02id\x18\x01\
-    \x20\x01(\tR\x02idJa\n\x06\x12\x04\0\0\x04\x01\n\x08\n\x01\x0c\x12\x03\0\
-    \0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\0\x01\x12\x03\
-    \x02\x08\x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\x05\x04\
-    \0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\
-    \x0b\r\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11b\x06proto3\
+    \x20\x01(\tR\x02id\"$\n\x10TrashIdentifiers\x12\x10\n\x03ids\x18\x01\x20\
+    \x03(\tR\x03idsJ\xbe\x01\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\x0c\x12\
+    \x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\0\x01\
+    \x12\x03\x02\x08\x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x12\n\x0c\n\
+    \x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\
+    \x03\x03\x0b\r\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x10\x11\n\n\n\x02\
+    \x04\x01\x12\x04\x05\0\x07\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x18\
+    \n\x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04\x1c\n\x0c\n\x05\x04\x01\x02\0\
+    \x04\x12\x03\x06\x04\x0c\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x06\r\x13\
+    \n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x14\x17\n\x0c\n\x05\x04\x01\
+    \x02\0\x03\x12\x03\x06\x1a\x1bb\x06proto3\
 ";
 
 static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

+ 6 - 3
rust-lib/flowy-workspace/src/protobuf/proto/trash_create.proto

@@ -2,16 +2,19 @@ syntax = "proto3";
 
 message CreateTrashParams {
     string id = 1;
-    string name = 2;
-    int64 modified_time = 3;
-    int64 create_time = 4;
+    TrashType ty = 2;
 }
 message Trash {
     string id = 1;
     string name = 2;
     int64 modified_time = 3;
     int64 create_time = 4;
+    TrashType ty = 5;
 }
 message RepeatedTrash {
     repeated Trash items = 1;
 }
+enum TrashType {
+    Unknown = 0;
+    View = 1;
+}

+ 3 - 0
rust-lib/flowy-workspace/src/protobuf/proto/trash_delete.proto

@@ -3,3 +3,6 @@ syntax = "proto3";
 message TrashIdentifier {
     string id = 1;
 }
+message TrashIdentifiers {
+    repeated string ids = 1;
+}

+ 15 - 20
rust-lib/flowy-workspace/src/services/trash_can.rs

@@ -1,23 +1,22 @@
 use crate::{
-    entities::trash::{RepeatedTrash, Trash},
+    entities::trash::{RepeatedTrash, Trash, TrashType},
     errors::{WorkspaceError, WorkspaceResult},
     module::WorkspaceDatabase,
     notify::{send_anonymous_dart_notification, WorkspaceNotification},
-    sql_tables::trash::{TrashSource, TrashTable, TrashTableSql},
+    sql_tables::trash::{TrashTable, TrashTableSql},
 };
 use flowy_database::SqliteConnection;
-
-use std::{sync::Arc};
+use std::sync::Arc;
 use tokio::sync::{broadcast, mpsc};
 
 #[derive(Clone)]
 pub enum TrashEvent {
-    Putback(TrashSource, Vec<String>, mpsc::Sender<WorkspaceResult<()>>),
-    Delete(TrashSource, Vec<String>, mpsc::Sender<WorkspaceResult<()>>),
+    Putback(TrashType, Vec<String>, mpsc::Sender<WorkspaceResult<()>>),
+    Delete(TrashType, Vec<String>, mpsc::Sender<WorkspaceResult<()>>),
 }
 
 impl TrashEvent {
-    pub fn select(self, s: TrashSource) -> Option<TrashEvent> {
+    pub fn select(self, s: TrashType) -> Option<TrashEvent> {
         match &self {
             TrashEvent::Putback(source, _, _) => {
                 if source == &s {
@@ -57,10 +56,11 @@ impl TrashCan {
         let trash_table = TrashTableSql::read(trash_id, &*self.database.db_connection()?)?;
         tracing::Span::current().record(
             "putback",
-            &format!("{:?}: {}", &trash_table.source, trash_table.id).as_str(),
+            &format!("{:?}: {}", &trash_table.ty, trash_table.id).as_str(),
         );
-        self.notify
-            .send(TrashEvent::Putback(trash_table.source, vec![trash_table.id], tx));
+        let _ = self
+            .notify
+            .send(TrashEvent::Putback(trash_table.ty.into(), vec![trash_table.id], tx))?;
 
         let _ = rx.recv().await.unwrap()?;
         let conn = self.database.db_connection()?;
@@ -84,7 +84,7 @@ impl TrashCan {
         let trash_table = TrashTableSql::read(trash_id, &*self.database.db_connection()?)?;
         let _ = self
             .notify
-            .send(TrashEvent::Delete(trash_table.source, vec![trash_table.id], tx));
+            .send(TrashEvent::Delete(trash_table.ty.into(), vec![trash_table.id], tx));
 
         let _ = rx.recv().await.unwrap()?;
         let _ = TrashTableSql::delete_trash(trash_id, &*self.database.db_connection()?)?;
@@ -98,13 +98,8 @@ impl TrashCan {
     // DELETE operations. It’s not possible for us to use these commands to
     // CREATE and DROP tables operations because those are auto-commit in the
     // database.
-    #[tracing::instrument(level = "debug", skip(self, trash, source, conn), fields(add_trash)  err)]
-    pub fn add<T: Into<Trash>>(
-        &self,
-        trash: T,
-        source: TrashSource,
-        conn: &SqliteConnection,
-    ) -> Result<(), WorkspaceError> {
+    #[tracing::instrument(level = "debug", skip(self, trash, ty, conn), fields(add_trash)  err)]
+    pub fn add<T: Into<Trash>>(&self, trash: T, ty: TrashType, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
         let trash = trash.into();
         let trash_table = TrashTable {
             id: trash.id,
@@ -112,12 +107,12 @@ impl TrashCan {
             desc: "".to_owned(),
             modified_time: trash.modified_time,
             create_time: trash.create_time,
-            source,
+            ty: ty.into(),
         };
 
         tracing::Span::current().record(
             "add_trash",
-            &format!("{:?}: {}", &trash_table.source, trash_table.id).as_str(),
+            &format!("{:?}: {}", &trash_table.ty, trash_table.id).as_str(),
         );
 
         let _ = TrashTableSql::create_trash(trash_table, &*conn)?;

+ 9 - 13
rust-lib/flowy-workspace/src/services/view_controller.rs

@@ -8,26 +8,22 @@ use crate::{
 };
 
 use crate::{
-    entities::{
-        view::{DeleteViewParams, QueryViewParams, RepeatedView},
-    },
+    entities::view::{DeleteViewParams, QueryViewParams, RepeatedView},
     errors::internal_error,
     module::WorkspaceUser,
     notify::WorkspaceNotification,
     services::{TrashCan, TrashEvent},
-    sql_tables::trash::TrashSource,
 };
 use flowy_database::SqliteConnection;
 use flowy_document::{
-    entities::doc::{CreateDocParams, DocDelta, QueryDocParams},
+    entities::doc::{CreateDocParams, DocDelta, DocIdentifier},
     module::FlowyDocument,
 };
 
-use crate::errors::WorkspaceResult;
-use futures::{FutureExt, StreamExt, TryStreamExt};
+use crate::{entities::trash::TrashType, errors::WorkspaceResult};
+use futures::{FutureExt, StreamExt};
 use std::sync::Arc;
 
-
 pub(crate) struct ViewController {
     user: Arc<dyn WorkspaceUser>,
     server: Server,
@@ -93,7 +89,7 @@ impl ViewController {
     }
 
     #[tracing::instrument(level = "debug", skip(self), err)]
-    pub(crate) async fn open_view(&self, params: QueryDocParams) -> Result<DocDelta, WorkspaceError> {
+    pub(crate) async fn open_view(&self, params: DocIdentifier) -> Result<DocDelta, WorkspaceError> {
         let edit_context = self.document.open(params, self.database.db_pool()?).await?;
         Ok(edit_context.delta().await.map_err(internal_error)?)
     }
@@ -149,7 +145,7 @@ impl ViewController {
             },
             Some(is_trash) => {
                 if is_trash {
-                    self.trash_can.add(updated_view.clone(), TrashSource::View, conn)?;
+                    self.trash_can.add(updated_view.clone(), TrashType::View, conn)?;
                 }
                 let _ = notify_view_num_did_change(&updated_view.belong_to_id, conn)?;
             },
@@ -229,7 +225,7 @@ impl ViewController {
             loop {
                 let mut stream = Box::pin(rx.recv().into_stream().filter_map(|result| async move {
                     match result {
-                        Ok(event) => event.select(TrashSource::View),
+                        Ok(event) => event.select(TrashType::View),
                         Err(_) => None,
                     }
                 }));
@@ -270,7 +266,7 @@ fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, event: TrashEvent) {
                 })?;
                 Ok::<(), WorkspaceError>(())
             };
-            ret.send(result());
+            let _ = ret.send(result());
         },
         TrashEvent::Delete(_, delete_ids, ret) => {
             let result = || {
@@ -288,7 +284,7 @@ fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, event: TrashEvent) {
                 })?;
                 Ok::<(), WorkspaceError>(())
             };
-            ret.send(result());
+            let _ = ret.send(result());
         },
     }
 }

+ 30 - 15
rust-lib/flowy-workspace/src/sql_tables/trash/trash_table.rs

@@ -1,5 +1,5 @@
-use crate::entities::trash::Trash;
-use diesel::sql_types::{Integer};
+use crate::entities::trash::{Trash, TrashType};
+use diesel::sql_types::Integer;
 use flowy_database::schema::trash_table;
 
 #[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)]
@@ -10,7 +10,7 @@ pub(crate) struct TrashTable {
     pub desc: String,
     pub modified_time: i64,
     pub create_time: i64,
-    pub source: TrashSource,
+    pub ty: SqlTrashType,
 }
 impl std::convert::Into<Trash> for TrashTable {
     fn into(self) -> Trash {
@@ -19,6 +19,7 @@ impl std::convert::Into<Trash> for TrashTable {
             name: self.name,
             modified_time: self.modified_time,
             create_time: self.create_time,
+            ty: self.ty.into(),
         }
     }
 }
@@ -26,27 +27,41 @@ impl std::convert::Into<Trash> for TrashTable {
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
 #[repr(i32)]
 #[sql_type = "Integer"]
-pub enum TrashSource {
+pub(crate) enum SqlTrashType {
     Unknown = 0,
     View    = 1,
 }
 
-impl std::default::Default for TrashSource {
-    fn default() -> Self { TrashSource::Unknown }
-}
-
-impl std::convert::From<i32> for TrashSource {
+impl std::convert::From<i32> for SqlTrashType {
     fn from(value: i32) -> Self {
         match value {
-            0 => TrashSource::Unknown,
-            1 => TrashSource::View,
-            _o => TrashSource::Unknown,
+            0 => SqlTrashType::Unknown,
+            1 => SqlTrashType::View,
+            _o => SqlTrashType::Unknown,
         }
     }
 }
 
-impl TrashSource {
-    pub fn value(&self) -> i32 { *self as i32 }
+impl SqlTrashType {
+    pub(crate) fn value(&self) -> i32 { *self as i32 }
+}
+
+impl_sql_integer_expression!(SqlTrashType);
+
+impl std::convert::Into<TrashType> for SqlTrashType {
+    fn into(self) -> TrashType {
+        match self {
+            SqlTrashType::Unknown => TrashType::Unknown,
+            SqlTrashType::View => TrashType::View,
+        }
+    }
 }
 
-impl_sql_integer_expression!(TrashSource);
+impl std::convert::From<TrashType> for SqlTrashType {
+    fn from(ty: TrashType) -> Self {
+        match ty {
+            TrashType::Unknown => SqlTrashType::Unknown,
+            TrashType::View => SqlTrashType::View,
+        }
+    }
+}