Przeglądaj źródła

[server]: replace pool with transaction for sql api

appflowy 3 lat temu
rodzic
commit
4cc8d2b3f1
32 zmienionych plików z 706 dodań i 988 usunięć
  1. 18 60
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_query.pb.dart
  2. 7 10
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_query.pbjson.dart
  3. 0 28
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pb.dart
  4. 2 4
      app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pbjson.dart
  5. 38 115
      backend/src/service/app/app.rs
  6. 85 30
      backend/src/service/app/router.rs
  7. 51 8
      backend/src/service/trash/router.rs
  8. 31 59
      backend/src/service/trash/trash.rs
  9. 4 8
      backend/src/service/user/user_default.rs
  10. 88 20
      backend/src/service/view/router.rs
  11. 72 138
      backend/src/service/view/view.rs
  12. 105 27
      backend/src/service/workspace/router.rs
  13. 50 118
      backend/src/service/workspace/workspace.rs
  14. 23 21
      backend/tests/api/workspace.rs
  15. 16 1
      backend/tests/helper.rs
  16. 1 1
      rust-lib/flowy-derive/src/derive_cache/derive_cache.rs
  17. 5 34
      rust-lib/flowy-workspace/src/entities/app/app_query.rs
  18. 1 17
      rust-lib/flowy-workspace/src/entities/view/view_query.rs
  19. 1 0
      rust-lib/flowy-workspace/src/entities/view/view_update.rs
  20. 3 7
      rust-lib/flowy-workspace/src/handlers/app_handler.rs
  21. 1 4
      rust-lib/flowy-workspace/src/handlers/view_handler.rs
  22. 1 1
      rust-lib/flowy-workspace/src/lib.rs
  23. 36 152
      rust-lib/flowy-workspace/src/protobuf/model/app_query.rs
  24. 16 94
      rust-lib/flowy-workspace/src/protobuf/model/view_query.rs
  25. 2 5
      rust-lib/flowy-workspace/src/protobuf/proto/app_query.proto
  26. 0 2
      rust-lib/flowy-workspace/src/protobuf/proto/view_query.proto
  27. 4 6
      rust-lib/flowy-workspace/src/services/app_controller.rs
  28. 2 2
      rust-lib/flowy-workspace/src/services/server/mod.rs
  29. 35 3
      rust-lib/flowy-workspace/src/services/server/server_api.rs
  30. 2 2
      rust-lib/flowy-workspace/src/services/server/server_api_mock.rs
  31. 5 10
      rust-lib/flowy-workspace/src/sql_tables/app/app_sql.rs
  32. 1 1
      rust-lib/flowy-workspace/tests/workspace/app_test.rs

+ 18 - 60
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_query.pb.dart

@@ -12,24 +12,19 @@ import 'package:protobuf/protobuf.dart' as $pb;
 class QueryAppRequest extends $pb.GeneratedMessage {
 class QueryAppRequest extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryAppRequest', createEmptyInstance: create)
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryAppRequest', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
-    ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'readBelongings')
-    ..aOB(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
+    ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
   QueryAppRequest._() : super();
   QueryAppRequest._() : super();
   factory QueryAppRequest({
   factory QueryAppRequest({
     $core.String? appId,
     $core.String? appId,
-    $core.bool? readBelongings,
     $core.bool? isTrash,
     $core.bool? isTrash,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (appId != null) {
     if (appId != null) {
       _result.appId = appId;
       _result.appId = appId;
     }
     }
-    if (readBelongings != null) {
-      _result.readBelongings = readBelongings;
-    }
     if (isTrash != null) {
     if (isTrash != null) {
       _result.isTrash = isTrash;
       _result.isTrash = isTrash;
     }
     }
@@ -66,70 +61,51 @@ class QueryAppRequest extends $pb.GeneratedMessage {
   void clearAppId() => clearField(1);
   void clearAppId() => clearField(1);
 
 
   @$pb.TagNumber(2)
   @$pb.TagNumber(2)
-  $core.bool get readBelongings => $_getBF(1);
+  $core.bool get isTrash => $_getBF(1);
   @$pb.TagNumber(2)
   @$pb.TagNumber(2)
-  set readBelongings($core.bool v) { $_setBool(1, v); }
+  set isTrash($core.bool v) { $_setBool(1, v); }
   @$pb.TagNumber(2)
   @$pb.TagNumber(2)
-  $core.bool hasReadBelongings() => $_has(1);
+  $core.bool hasIsTrash() => $_has(1);
   @$pb.TagNumber(2)
   @$pb.TagNumber(2)
-  void clearReadBelongings() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $core.bool get isTrash => $_getBF(2);
-  @$pb.TagNumber(3)
-  set isTrash($core.bool v) { $_setBool(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasIsTrash() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearIsTrash() => clearField(3);
+  void clearIsTrash() => clearField(2);
 }
 }
 
 
-class QueryAppParams extends $pb.GeneratedMessage {
-  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryAppParams', createEmptyInstance: create)
+class AppIdentifier extends $pb.GeneratedMessage {
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'AppIdentifier', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId')
-    ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'readBelongings')
-    ..aOB(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
-  QueryAppParams._() : super();
-  factory QueryAppParams({
+  AppIdentifier._() : super();
+  factory AppIdentifier({
     $core.String? appId,
     $core.String? appId,
-    $core.bool? readBelongings,
-    $core.bool? isTrash,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (appId != null) {
     if (appId != null) {
       _result.appId = appId;
       _result.appId = appId;
     }
     }
-    if (readBelongings != null) {
-      _result.readBelongings = readBelongings;
-    }
-    if (isTrash != null) {
-      _result.isTrash = isTrash;
-    }
     return _result;
     return _result;
   }
   }
-  factory QueryAppParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
-  factory QueryAppParams.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+  factory AppIdentifier.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory AppIdentifier.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')
-  QueryAppParams clone() => QueryAppParams()..mergeFromMessage(this);
+  AppIdentifier clone() => AppIdentifier()..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')
-  QueryAppParams copyWith(void Function(QueryAppParams) updates) => super.copyWith((message) => updates(message as QueryAppParams)) as QueryAppParams; // ignore: deprecated_member_use
+  AppIdentifier copyWith(void Function(AppIdentifier) updates) => super.copyWith((message) => updates(message as AppIdentifier)) as AppIdentifier; // ignore: deprecated_member_use
   $pb.BuilderInfo get info_ => _i;
   $pb.BuilderInfo get info_ => _i;
   @$core.pragma('dart2js:noInline')
   @$core.pragma('dart2js:noInline')
-  static QueryAppParams create() => QueryAppParams._();
-  QueryAppParams createEmptyInstance() => create();
-  static $pb.PbList<QueryAppParams> createRepeated() => $pb.PbList<QueryAppParams>();
+  static AppIdentifier create() => AppIdentifier._();
+  AppIdentifier createEmptyInstance() => create();
+  static $pb.PbList<AppIdentifier> createRepeated() => $pb.PbList<AppIdentifier>();
   @$core.pragma('dart2js:noInline')
   @$core.pragma('dart2js:noInline')
-  static QueryAppParams getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<QueryAppParams>(create);
-  static QueryAppParams? _defaultInstance;
+  static AppIdentifier getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<AppIdentifier>(create);
+  static AppIdentifier? _defaultInstance;
 
 
   @$pb.TagNumber(1)
   @$pb.TagNumber(1)
   $core.String get appId => $_getSZ(0);
   $core.String get appId => $_getSZ(0);
@@ -139,23 +115,5 @@ class QueryAppParams extends $pb.GeneratedMessage {
   $core.bool hasAppId() => $_has(0);
   $core.bool hasAppId() => $_has(0);
   @$pb.TagNumber(1)
   @$pb.TagNumber(1)
   void clearAppId() => clearField(1);
   void clearAppId() => clearField(1);
-
-  @$pb.TagNumber(2)
-  $core.bool get readBelongings => $_getBF(1);
-  @$pb.TagNumber(2)
-  set readBelongings($core.bool v) { $_setBool(1, v); }
-  @$pb.TagNumber(2)
-  $core.bool hasReadBelongings() => $_has(1);
-  @$pb.TagNumber(2)
-  void clearReadBelongings() => clearField(2);
-
-  @$pb.TagNumber(3)
-  $core.bool get isTrash => $_getBF(2);
-  @$pb.TagNumber(3)
-  set isTrash($core.bool v) { $_setBool(2, v); }
-  @$pb.TagNumber(3)
-  $core.bool hasIsTrash() => $_has(2);
-  @$pb.TagNumber(3)
-  void clearIsTrash() => clearField(3);
 }
 }
 
 

+ 7 - 10
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/app_query.pbjson.dart

@@ -13,22 +13,19 @@ const QueryAppRequest$json = const {
   '1': 'QueryAppRequest',
   '1': 'QueryAppRequest',
   '2': const [
   '2': const [
     const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'},
     const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'},
-    const {'1': 'read_belongings', '3': 2, '4': 1, '5': 8, '10': 'readBelongings'},
-    const {'1': 'is_trash', '3': 3, '4': 1, '5': 8, '10': 'isTrash'},
+    const {'1': 'is_trash', '3': 2, '4': 1, '5': 8, '10': 'isTrash'},
   ],
   ],
 };
 };
 
 
 /// Descriptor for `QueryAppRequest`. Decode as a `google.protobuf.DescriptorProto`.
 /// Descriptor for `QueryAppRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryAppRequestDescriptor = $convert.base64Decode('Cg9RdWVyeUFwcFJlcXVlc3QSFQoGYXBwX2lkGAEgASgJUgVhcHBJZBInCg9yZWFkX2JlbG9uZ2luZ3MYAiABKAhSDnJlYWRCZWxvbmdpbmdzEhkKCGlzX3RyYXNoGAMgASgIUgdpc1RyYXNo');
-@$core.Deprecated('Use queryAppParamsDescriptor instead')
-const QueryAppParams$json = const {
-  '1': 'QueryAppParams',
+final $typed_data.Uint8List queryAppRequestDescriptor = $convert.base64Decode('Cg9RdWVyeUFwcFJlcXVlc3QSFQoGYXBwX2lkGAEgASgJUgVhcHBJZBIZCghpc190cmFzaBgCIAEoCFIHaXNUcmFzaA==');
+@$core.Deprecated('Use appIdentifierDescriptor instead')
+const AppIdentifier$json = const {
+  '1': 'AppIdentifier',
   '2': const [
   '2': const [
     const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'},
     const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'},
-    const {'1': 'read_belongings', '3': 2, '4': 1, '5': 8, '10': 'readBelongings'},
-    const {'1': 'is_trash', '3': 3, '4': 1, '5': 8, '10': 'isTrash'},
   ],
   ],
 };
 };
 
 
-/// Descriptor for `QueryAppParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryAppParamsDescriptor = $convert.base64Decode('Cg5RdWVyeUFwcFBhcmFtcxIVCgZhcHBfaWQYASABKAlSBWFwcElkEicKD3JlYWRfYmVsb25naW5ncxgCIAEoCFIOcmVhZEJlbG9uZ2luZ3MSGQoIaXNfdHJhc2gYAyABKAhSB2lzVHJhc2g=');
+/// Descriptor for `AppIdentifier`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List appIdentifierDescriptor = $convert.base64Decode('Cg1BcHBJZGVudGlmaWVyEhUKBmFwcF9pZBgBIAEoCVIFYXBwSWQ=');

+ 0 - 28
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pb.dart

@@ -12,22 +12,17 @@ import 'package:protobuf/protobuf.dart' as $pb;
 class QueryViewRequest extends $pb.GeneratedMessage {
 class QueryViewRequest extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryViewRequest', createEmptyInstance: create)
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryViewRequest', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
-    ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'readBelongings')
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
   QueryViewRequest._() : super();
   QueryViewRequest._() : super();
   factory QueryViewRequest({
   factory QueryViewRequest({
     $core.String? viewId,
     $core.String? viewId,
-    $core.bool? readBelongings,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (viewId != null) {
     if (viewId != null) {
       _result.viewId = viewId;
       _result.viewId = viewId;
     }
     }
-    if (readBelongings != null) {
-      _result.readBelongings = readBelongings;
-    }
     return _result;
     return _result;
   }
   }
   factory QueryViewRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory QueryViewRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -59,36 +54,22 @@ class QueryViewRequest extends $pb.GeneratedMessage {
   $core.bool hasViewId() => $_has(0);
   $core.bool hasViewId() => $_has(0);
   @$pb.TagNumber(1)
   @$pb.TagNumber(1)
   void clearViewId() => clearField(1);
   void clearViewId() => clearField(1);
-
-  @$pb.TagNumber(2)
-  $core.bool get readBelongings => $_getBF(1);
-  @$pb.TagNumber(2)
-  set readBelongings($core.bool v) { $_setBool(1, v); }
-  @$pb.TagNumber(2)
-  $core.bool hasReadBelongings() => $_has(1);
-  @$pb.TagNumber(2)
-  void clearReadBelongings() => clearField(2);
 }
 }
 
 
 class QueryViewParams extends $pb.GeneratedMessage {
 class QueryViewParams extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryViewParams', createEmptyInstance: create)
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryViewParams', createEmptyInstance: create)
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
     ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'viewId')
-    ..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'readBelongings')
     ..hasRequiredFields = false
     ..hasRequiredFields = false
   ;
   ;
 
 
   QueryViewParams._() : super();
   QueryViewParams._() : super();
   factory QueryViewParams({
   factory QueryViewParams({
     $core.String? viewId,
     $core.String? viewId,
-    $core.bool? readBelongings,
   }) {
   }) {
     final _result = create();
     final _result = create();
     if (viewId != null) {
     if (viewId != null) {
       _result.viewId = viewId;
       _result.viewId = viewId;
     }
     }
-    if (readBelongings != null) {
-      _result.readBelongings = readBelongings;
-    }
     return _result;
     return _result;
   }
   }
   factory QueryViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
   factory QueryViewParams.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@@ -120,15 +101,6 @@ class QueryViewParams extends $pb.GeneratedMessage {
   $core.bool hasViewId() => $_has(0);
   $core.bool hasViewId() => $_has(0);
   @$pb.TagNumber(1)
   @$pb.TagNumber(1)
   void clearViewId() => clearField(1);
   void clearViewId() => clearField(1);
-
-  @$pb.TagNumber(2)
-  $core.bool get readBelongings => $_getBF(1);
-  @$pb.TagNumber(2)
-  set readBelongings($core.bool v) { $_setBool(1, v); }
-  @$pb.TagNumber(2)
-  $core.bool hasReadBelongings() => $_has(1);
-  @$pb.TagNumber(2)
-  void clearReadBelongings() => clearField(2);
 }
 }
 
 
 class OpenViewRequest extends $pb.GeneratedMessage {
 class OpenViewRequest extends $pb.GeneratedMessage {

+ 2 - 4
app_flowy/packages/flowy_sdk/lib/protobuf/flowy-workspace/view_query.pbjson.dart

@@ -13,23 +13,21 @@ const QueryViewRequest$json = const {
   '1': 'QueryViewRequest',
   '1': 'QueryViewRequest',
   '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': 'read_belongings', '3': 2, '4': 1, '5': 8, '10': 'readBelongings'},
   ],
   ],
 };
 };
 
 
 /// Descriptor for `QueryViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
 /// Descriptor for `QueryViewRequest`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryViewRequestDescriptor = $convert.base64Decode('ChBRdWVyeVZpZXdSZXF1ZXN0EhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBInCg9yZWFkX2JlbG9uZ2luZ3MYAiABKAhSDnJlYWRCZWxvbmdpbmdz');
+final $typed_data.Uint8List queryViewRequestDescriptor = $convert.base64Decode('ChBRdWVyeVZpZXdSZXF1ZXN0EhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZA==');
 @$core.Deprecated('Use queryViewParamsDescriptor instead')
 @$core.Deprecated('Use queryViewParamsDescriptor instead')
 const QueryViewParams$json = const {
 const QueryViewParams$json = const {
   '1': 'QueryViewParams',
   '1': 'QueryViewParams',
   '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': 'read_belongings', '3': 2, '4': 1, '5': 8, '10': 'readBelongings'},
   ],
   ],
 };
 };
 
 
 /// Descriptor for `QueryViewParams`. Decode as a `google.protobuf.DescriptorProto`.
 /// Descriptor for `QueryViewParams`. Decode as a `google.protobuf.DescriptorProto`.
-final $typed_data.Uint8List queryViewParamsDescriptor = $convert.base64Decode('Cg9RdWVyeVZpZXdQYXJhbXMSFwoHdmlld19pZBgBIAEoCVIGdmlld0lkEicKD3JlYWRfYmVsb25naW5ncxgCIAEoCFIOcmVhZEJlbG9uZ2luZ3M=');
+final $typed_data.Uint8List queryViewParamsDescriptor = $convert.base64Decode('Cg9RdWVyeVZpZXdQYXJhbXMSFwoHdmlld19pZBgBIAEoCVIGdmlld0lk');
 @$core.Deprecated('Use openViewRequestDescriptor instead')
 @$core.Deprecated('Use openViewRequestDescriptor instead')
 const OpenViewRequest$json = const {
 const OpenViewRequest$json = const {
   '1': 'OpenViewRequest',
   '1': 'OpenViewRequest',

+ 38 - 115
backend/src/service/app/app.rs

@@ -1,39 +1,31 @@
-use anyhow::Context;
-use chrono::Utc;
-use protobuf::Message;
-use sqlx::{postgres::PgArguments, PgPool, Postgres};
-
-use flowy_net::{
-    errors::{invalid_params, ServerError},
-    response::FlowyResponse,
+use crate::{
+    entities::workspace::{AppTable, APP_TABLE},
+    service::{app::sql_builder::*, user::LoggedUser, view::read_view_belong_to_id},
+    sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
 };
 };
+
+use chrono::Utc;
+use flowy_net::errors::{invalid_params, ServerError};
 use flowy_workspace::{
 use flowy_workspace::{
     entities::{
     entities::{
         app::parser::{AppDesc, AppName},
         app::parser::{AppDesc, AppName},
         workspace::parser::WorkspaceId,
         workspace::parser::WorkspaceId,
     },
     },
-    protobuf::{App, CreateAppParams, QueryAppParams, RepeatedView, UpdateAppParams},
-};
-
-use crate::{
-    entities::workspace::{AppTable, APP_TABLE},
-    service::{app::sql_builder::*, user::LoggedUser, view::read_views_belong_to_id},
-    sqlx_ext::{map_sqlx_error, SqlBuilder},
+    protobuf::{App, CreateAppParams, RepeatedView},
 };
 };
+use protobuf::Message;
+use sqlx::{postgres::PgArguments, Postgres};
+use uuid::Uuid;
 
 
 pub(crate) async fn create_app(
 pub(crate) async fn create_app(
-    pool: &PgPool,
+    transaction: &mut DBTransaction<'_>,
     mut params: CreateAppParams,
     mut params: CreateAppParams,
     logged_user: LoggedUser,
     logged_user: LoggedUser,
-) -> Result<FlowyResponse, ServerError> {
+) -> Result<App, ServerError> {
     let name = AppName::parse(params.take_name()).map_err(invalid_params)?;
     let name = AppName::parse(params.take_name()).map_err(invalid_params)?;
     let workspace_id = WorkspaceId::parse(params.take_workspace_id()).map_err(invalid_params)?;
     let workspace_id = WorkspaceId::parse(params.take_workspace_id()).map_err(invalid_params)?;
     let user_id = logged_user.as_uuid()?.to_string();
     let user_id = logged_user.as_uuid()?.to_string();
     let desc = AppDesc::parse(params.take_desc()).map_err(invalid_params)?;
     let desc = AppDesc::parse(params.take_desc()).map_err(invalid_params)?;
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to create app")?;
 
 
     let (sql, args, app) = NewAppSqlBuilder::new(&user_id, workspace_id.as_ref())
     let (sql, args, app) = NewAppSqlBuilder::new(&user_id, workspace_id.as_ref())
         .name(name.as_ref())
         .name(name.as_ref())
@@ -42,137 +34,68 @@ pub(crate) async fn create_app(
         .build()?;
         .build()?;
 
 
     let _ = sqlx::query_with(&sql, args)
     let _ = sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to create app.")?;
-
-    FlowyResponse::success().pb(app)
+    Ok(app)
 }
 }
 
 
 pub(crate) async fn read_app(
 pub(crate) async fn read_app(
-    pool: &PgPool,
-    params: QueryAppParams,
-) -> Result<FlowyResponse, ServerError> {
-    let app_id = check_app_id(params.app_id)?;
-
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to read app")?;
-
+    transaction: &mut DBTransaction<'_>,
+    app_id: Uuid,
+    user: &LoggedUser,
+) -> Result<App, ServerError> {
     let (sql, args) = SqlBuilder::select(APP_TABLE)
     let (sql, args) = SqlBuilder::select(APP_TABLE)
         .add_field("*")
         .add_field("*")
         .and_where_eq("id", app_id)
         .and_where_eq("id", app_id)
         .build()?;
         .build()?;
 
 
     let table = sqlx::query_as_with::<Postgres, AppTable, PgArguments>(&sql, args)
     let table = sqlx::query_as_with::<Postgres, AppTable, PgArguments>(&sql, args)
-        .fetch_one(&mut transaction)
+        .fetch_one(transaction as &mut DBTransaction<'_>)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
     let mut views = RepeatedView::default();
     let mut views = RepeatedView::default();
-    if params.read_belongings {
-        views.set_items(
-            read_views_belong_to_id(&mut transaction, &table.id.to_string())
-                .await?
-                .into(),
-        );
-    }
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to read app.")?;
+    views.set_items(
+        read_view_belong_to_id(user, transaction as &mut DBTransaction<'_>, &table.id.to_string())
+            .await?
+            .into(),
+    );
 
 
     let mut app: App = table.into();
     let mut app: App = table.into();
     app.set_belongings(views);
     app.set_belongings(views);
-
-    FlowyResponse::success().pb(app)
+    Ok(app)
 }
 }
 
 
 pub(crate) async fn update_app(
 pub(crate) async fn update_app(
-    pool: &PgPool,
-    params: UpdateAppParams,
-) -> Result<FlowyResponse, ServerError> {
-    let app_id = check_app_id(params.get_app_id().to_string())?;
-    let name = match params.has_name() {
-        false => None,
-        true => Some(
-            AppName::parse(params.get_name().to_owned())
-                .map_err(invalid_params)?
-                .0,
-        ),
-    };
-
-    let color_style = match params.has_color_style() {
-        false => None,
-        true => {
-            let color_bytes = params.get_color_style().write_to_bytes()?;
-            Some(color_bytes)
-        },
-    };
-
-    let desc = match params.has_desc() {
-        false => None,
-        true => Some(
-            AppDesc::parse(params.get_desc().to_owned())
-                .map_err(invalid_params)?
-                .0,
-        ),
-    };
-
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to update app")?;
-
+    transaction: &mut DBTransaction<'_>,
+    app_id: Uuid,
+    name: Option<String>,
+    desc: Option<String>,
+    color_style: Option<Vec<u8>>,
+) -> Result<(), ServerError> {
     let (sql, args) = SqlBuilder::update(APP_TABLE)
     let (sql, args) = SqlBuilder::update(APP_TABLE)
         .add_some_arg("name", name)
         .add_some_arg("name", name)
         .add_some_arg("color_style", color_style)
         .add_some_arg("color_style", color_style)
         .add_some_arg("description", desc)
         .add_some_arg("description", desc)
         .add_some_arg("modified_time", Some(Utc::now()))
         .add_some_arg("modified_time", Some(Utc::now()))
-        .add_arg_if(params.has_is_trash(), "is_trash", params.get_is_trash())
         .and_where_eq("id", app_id)
         .and_where_eq("id", app_id)
         .build()?;
         .build()?;
 
 
     sqlx::query_with(&sql, args)
     sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to update app.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(())
 }
 }
 
 
-pub(crate) async fn delete_app(pool: &PgPool, app_id: &str) -> Result<FlowyResponse, ServerError> {
-    let app_id = check_app_id(app_id.to_owned())?;
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to delete app")?;
-
-    let (sql, args) = SqlBuilder::delete(APP_TABLE)
-        .and_where_eq("id", app_id)
-        .build()?;
-
+pub(crate) async fn delete_app(transaction: &mut DBTransaction<'_>, app_id: Uuid) -> Result<(), ServerError> {
+    let (sql, args) = SqlBuilder::delete(APP_TABLE).and_where_eq("id", app_id).build()?;
     let _ = sqlx::query_with(&sql, args)
     let _ = sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to delete app.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(())
 }
 }

+ 85 - 30
backend/src/service/app/router.rs

@@ -2,21 +2,22 @@ use actix_web::{
     web::{Data, Payload},
     web::{Data, Payload},
     HttpResponse,
     HttpResponse,
 };
 };
+use flowy_net::errors::{invalid_params, ServerError};
+use flowy_workspace::protobuf::{AppIdentifier, CreateAppParams, DeleteAppParams, UpdateAppParams};
+use protobuf::Message;
 use sqlx::PgPool;
 use sqlx::PgPool;
 
 
-use flowy_net::errors::ServerError;
-use flowy_workspace::protobuf::{
-    CreateAppParams,
-    DeleteAppParams,
-    QueryAppParams,
-    UpdateAppParams,
-};
-
 use crate::service::{
 use crate::service::{
-    app::app::{create_app, delete_app, read_app, update_app},
+    app::{
+        app::{create_app, delete_app, read_app, update_app},
+        sql_builder::check_app_id,
+    },
     user::LoggedUser,
     user::LoggedUser,
     util::parse_from_payload,
     util::parse_from_payload,
 };
 };
+use anyhow::Context;
+use flowy_net::response::FlowyResponse;
+use flowy_workspace::entities::app::parser::{AppDesc, AppName};
 
 
 pub async fn create_handler(
 pub async fn create_handler(
     payload: Payload,
     payload: Payload,
@@ -24,33 +25,87 @@ pub async fn create_handler(
     logged_user: LoggedUser,
     logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: CreateAppParams = parse_from_payload(payload).await?;
     let params: CreateAppParams = parse_from_payload(payload).await?;
-    let resp = create_app(pool.get_ref(), params, logged_user).await?;
-    Ok(resp.into())
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to create app")?;
+
+    let app = create_app(&mut transaction, params, logged_user).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to create app.")?;
+
+    Ok(FlowyResponse::success().pb(app)?.into())
 }
 }
 
 
-pub async fn read_handler(
-    payload: Payload,
-    pool: Data<PgPool>,
-) -> Result<HttpResponse, ServerError> {
-    let params: QueryAppParams = parse_from_payload(payload).await?;
-    let resp = read_app(pool.get_ref(), params).await?;
-    Ok(resp.into())
+pub async fn read_handler(payload: Payload, pool: Data<PgPool>, user: LoggedUser) -> Result<HttpResponse, ServerError> {
+    let params: AppIdentifier = parse_from_payload(payload).await?;
+    let app_id = check_app_id(params.app_id)?;
+
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to read app")?;
+    let app = read_app(&mut transaction, app_id, &user).await?;
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to read app.")?;
+
+    Ok(FlowyResponse::success().pb(app)?.into())
 }
 }
 
 
-pub async fn update_handler(
-    payload: Payload,
-    pool: Data<PgPool>,
-) -> Result<HttpResponse, ServerError> {
+pub async fn update_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
     let params: UpdateAppParams = parse_from_payload(payload).await?;
     let params: UpdateAppParams = parse_from_payload(payload).await?;
-    let resp = update_app(pool.get_ref(), params).await?;
-    Ok(resp.into())
+    let app_id = check_app_id(params.get_app_id().to_string())?;
+    let name = match params.has_name() {
+        false => None,
+        true => Some(AppName::parse(params.get_name().to_owned()).map_err(invalid_params)?.0),
+    };
+
+    let color_style = match params.has_color_style() {
+        false => None,
+        true => {
+            let color_bytes = params.get_color_style().write_to_bytes()?;
+            Some(color_bytes)
+        },
+    };
+
+    let desc = match params.has_desc() {
+        false => None,
+        true => Some(AppDesc::parse(params.get_desc().to_owned()).map_err(invalid_params)?.0),
+    };
+
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to update app")?;
+
+    let _ = update_app(&mut transaction, app_id, name, desc, color_style).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to update app.")?;
+    Ok(FlowyResponse::success().into())
 }
 }
 
 
-pub async fn delete_handler(
-    payload: Payload,
-    pool: Data<PgPool>,
-) -> Result<HttpResponse, ServerError> {
+pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
     let params: DeleteAppParams = parse_from_payload(payload).await?;
     let params: DeleteAppParams = parse_from_payload(payload).await?;
-    let resp = delete_app(pool.get_ref(), &params.app_id).await?;
-    Ok(resp.into())
+    let app_id = check_app_id(params.app_id.to_owned())?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to delete app")?;
+
+    let _ = delete_app(&mut transaction, app_id).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to delete app.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }

+ 51 - 8
backend/src/service/trash/router.rs

@@ -3,12 +3,20 @@ use crate::service::{
     user::LoggedUser,
     user::LoggedUser,
     util::parse_from_payload,
     util::parse_from_payload,
 };
 };
+use ::protobuf::ProtobufEnum;
 use actix_web::{
 use actix_web::{
     web::{Data, Payload},
     web::{Data, Payload},
     HttpResponse,
     HttpResponse,
 };
 };
-use flowy_net::errors::ServerError;
-use flowy_workspace::protobuf::{CreateTrashParams, TrashIdentifiers};
+use anyhow::Context;
+use flowy_net::{
+    errors::{invalid_params, ServerError},
+    response::FlowyResponse,
+};
+use flowy_workspace::{
+    entities::trash::parser::{TrashId, TrashIds, TrashTypeParser},
+    protobuf::{CreateTrashParams, TrashIdentifiers},
+};
 use sqlx::PgPool;
 use sqlx::PgPool;
 
 
 pub async fn create_handler(
 pub async fn create_handler(
@@ -17,17 +25,52 @@ pub async fn create_handler(
     logged_user: LoggedUser,
     logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: CreateTrashParams = parse_from_payload(payload).await?;
     let params: CreateTrashParams = parse_from_payload(payload).await?;
-    let resp = create_trash(pool.get_ref(), params, logged_user).await?;
-    Ok(resp.into())
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to create trash")?;
+
+    let trash_id = TrashId::parse(params.id).map_err(invalid_params)?;
+    let ty = TrashTypeParser::parse(params.ty.value()).map_err(invalid_params)?;
+    let _ = create_trash(&mut transaction, trash_id.as_ref(), ty, logged_user).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to create trash.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }
 
 
 pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
 pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
     let params: TrashIdentifiers = parse_from_payload(payload).await?;
     let params: TrashIdentifiers = parse_from_payload(payload).await?;
-    let resp = delete_trash(pool.get_ref(), params).await?;
-    Ok(resp.into())
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to delete trash")?;
+
+    let trash_ids = TrashIds::parse(params.ids.into_vec()).map_err(invalid_params)?;
+    let _ = delete_trash(&mut transaction, trash_ids.0).await?;
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to delete trash.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }
 
 
 pub async fn read_handler(pool: Data<PgPool>, logged_user: LoggedUser) -> Result<HttpResponse, ServerError> {
 pub async fn read_handler(pool: Data<PgPool>, logged_user: LoggedUser) -> Result<HttpResponse, ServerError> {
-    let resp = read_trash(pool.get_ref(), logged_user).await?;
-    Ok(resp.into())
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to read trash")?;
+
+    let repeated_trash = read_trash(&mut transaction, logged_user).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to read view.")?;
+
+    Ok(FlowyResponse::success().pb(repeated_trash)?.into())
 }
 }

+ 31 - 59
backend/src/service/trash/trash.rs

@@ -1,88 +1,65 @@
 use crate::{
 use crate::{
     entities::workspace::{TrashTable, TRASH_TABLE},
     entities::workspace::{TrashTable, TRASH_TABLE},
-    service::{user::LoggedUser, view::read_view_with_transaction},
+    service::{user::LoggedUser, view::read_view_table},
     sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
     sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
 };
 };
 use ::protobuf::ProtobufEnum;
 use ::protobuf::ProtobufEnum;
-use anyhow::Context;
-use flowy_net::{
-    errors::{invalid_params, ServerError},
-    response::FlowyResponse,
-};
-use flowy_workspace::{
-    entities::trash::parser::{TrashId, TrashIds, TrashTypeParser},
-    protobuf::{CreateTrashParams, RepeatedTrash, Trash, TrashIdentifiers, TrashType},
-};
-use sqlx::{postgres::PgArguments, PgPool, Postgres};
+use flowy_net::{errors::ServerError, response::FlowyResponse};
+use flowy_workspace::protobuf::{CreateTrashParams, RepeatedTrash, Trash, TrashIdentifiers, TrashType};
+use sqlx::{postgres::PgArguments, Postgres};
 
 
 pub(crate) async fn create_trash(
 pub(crate) async fn create_trash(
-    pool: &PgPool,
-    params: CreateTrashParams,
+    transaction: &mut DBTransaction<'_>,
+    trash_id: &str,
+    ty: i32,
     user: LoggedUser,
     user: LoggedUser,
-) -> Result<FlowyResponse, ServerError> {
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to create trash")?;
-
-    let trash_id = TrashId::parse(params.id).map_err(invalid_params)?;
-    let ty = TrashTypeParser::parse(params.ty.value()).map_err(invalid_params)?;
-
+) -> Result<(), ServerError> {
     let (sql, args) = SqlBuilder::create(TRASH_TABLE)
     let (sql, args) = SqlBuilder::create(TRASH_TABLE)
-        .add_arg("id", trash_id.as_ref())
+        .add_arg("id", trash_id)
         .add_arg("user_id", &user.user_id)
         .add_arg("user_id", &user.user_id)
         .add_arg("ty", ty)
         .add_arg("ty", ty)
         .build()?;
         .build()?;
 
 
     let _ = sqlx::query_with(&sql, args)
     let _ = sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to trash view.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(())
 }
 }
 
 
-pub(crate) async fn delete_trash(pool: &PgPool, params: TrashIdentifiers) -> Result<FlowyResponse, ServerError> {
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to delete trash")?;
-
-    let trash_ids = TrashIds::parse(params.ids.into_vec()).map_err(invalid_params)?;
-    for trash_id in trash_ids.0 {
+pub(crate) async fn delete_trash(
+    transaction: &mut DBTransaction<'_>,
+    trash_ids: Vec<String>,
+) -> Result<(), ServerError> {
+    for trash_id in trash_ids {
         let (sql, args) = SqlBuilder::delete(TRASH_TABLE).and_where_eq("id", &trash_id).build()?;
         let (sql, args) = SqlBuilder::delete(TRASH_TABLE).and_where_eq("id", &trash_id).build()?;
         let _ = sqlx::query_with(&sql, args)
         let _ = sqlx::query_with(&sql, args)
-            .execute(&mut transaction)
+            .execute(transaction as &mut DBTransaction<'_>)
             .await
             .await
             .map_err(map_sqlx_error)?;
             .map_err(map_sqlx_error)?;
     }
     }
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to delete view.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(())
 }
 }
 
 
-pub(crate) async fn read_trash(pool: &PgPool, user: LoggedUser) -> Result<FlowyResponse, ServerError> {
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to read trash")?;
+pub(crate) async fn read_trash_ids(
+    _user: &LoggedUser,
+    _transaction: &mut DBTransaction<'_>,
+) -> Result<Vec<String>, ServerError> {
+    Ok(vec![])
+}
 
 
+pub(crate) async fn read_trash(
+    transaction: &mut DBTransaction<'_>,
+    user: LoggedUser,
+) -> Result<RepeatedTrash, ServerError> {
     let (sql, args) = SqlBuilder::select(TRASH_TABLE)
     let (sql, args) = SqlBuilder::select(TRASH_TABLE)
         .add_field("*")
         .add_field("*")
         .and_where_eq("user_id", &user.user_id)
         .and_where_eq("user_id", &user.user_id)
         .build()?;
         .build()?;
 
 
     let tables = sqlx::query_as_with::<Postgres, TrashTable, PgArguments>(&sql, args)
     let tables = sqlx::query_as_with::<Postgres, TrashTable, PgArguments>(&sql, args)
-        .fetch_all(&mut transaction)
+        .fetch_all(transaction as &mut DBTransaction<'_>)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
@@ -93,7 +70,7 @@ pub(crate) async fn read_trash(pool: &PgPool, user: LoggedUser) -> Result<FlowyR
             Some(ty) => match ty {
             Some(ty) => match ty {
                 TrashType::Unknown => {},
                 TrashType::Unknown => {},
                 TrashType::View => {
                 TrashType::View => {
-                    trash.push(read_view_with_transaction(table.id, &mut transaction).await?.into());
+                    trash.push(read_view_table(table.id, transaction).await?.into());
                 },
                 },
             },
             },
         }
         }
@@ -102,10 +79,5 @@ pub(crate) async fn read_trash(pool: &PgPool, user: LoggedUser) -> Result<FlowyR
     let mut repeated_trash = RepeatedTrash::default();
     let mut repeated_trash = RepeatedTrash::default();
     repeated_trash.set_items(trash.into());
     repeated_trash.set_items(trash.into());
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to read view.")?;
-
-    FlowyResponse::success().pb(repeated_trash)
+    Ok(repeated_trash)
 }
 }

+ 4 - 8
backend/src/service/user/user_default.rs

@@ -1,7 +1,7 @@
 use crate::{
 use crate::{
     service::{
     service::{
         app::sql_builder::NewAppSqlBuilder as AppBuilder,
         app::sql_builder::NewAppSqlBuilder as AppBuilder,
-        view::create_view_with_transaction,
+        view::create_view,
         workspace::sql_builder::NewWorkspaceBuilder as WorkspaceBuilder,
         workspace::sql_builder::NewWorkspaceBuilder as WorkspaceBuilder,
     },
     },
     sqlx_ext::{map_sqlx_error, DBTransaction},
     sqlx_ext::{map_sqlx_error, DBTransaction},
@@ -19,7 +19,7 @@ pub async fn create_default_workspace(
 ) -> Result<Workspace, ServerError> {
 ) -> Result<Workspace, ServerError> {
     let workspace = create_workspace(transaction, user_id).await?;
     let workspace = create_workspace(transaction, user_id).await?;
     let app = create_app(transaction, user_id, &workspace).await?;
     let app = create_app(transaction, user_id, &workspace).await?;
-    let _ = create_view(transaction, &app).await?;
+    let _ = create_default_view(transaction, &app).await?;
 
 
     Ok(workspace)
     Ok(workspace)
 }
 }
@@ -56,7 +56,7 @@ async fn create_app(
     Ok(app)
     Ok(app)
 }
 }
 
 
-async fn create_view(transaction: &mut DBTransaction<'_>, app: &App) -> Result<View, ServerError> {
+async fn create_default_view(transaction: &mut DBTransaction<'_>, app: &App) -> Result<View, ServerError> {
     let params = CreateViewParams {
     let params = CreateViewParams {
         belong_to_id: app.id.clone(),
         belong_to_id: app.id.clone(),
         name: "DefaultView".to_string(),
         name: "DefaultView".to_string(),
@@ -68,11 +68,7 @@ async fn create_view(transaction: &mut DBTransaction<'_>, app: &App) -> Result<V
         cached_size: Default::default(),
         cached_size: Default::default(),
     };
     };
 
 
-    let _name = "DefaultView".to_string();
-    let _desc = "View created by AppFlowy Server".to_string();
-    let _thumbnail = "http://1.png".to_string();
-
-    let view = create_view_with_transaction(transaction, params).await?;
+    let view = create_view(transaction, params).await?;
 
 
     Ok(view)
     Ok(view)
 }
 }

+ 88 - 20
backend/src/service/view/router.rs

@@ -1,16 +1,23 @@
+use crate::service::{
+    doc::doc::DocBiz,
+    user::LoggedUser,
+    util::parse_from_payload,
+    view::{create_view, delete_view, read_view, sql_builder::check_view_ids, update_view},
+};
 use actix_web::{
 use actix_web::{
     web::{Data, Payload},
     web::{Data, Payload},
     HttpResponse,
     HttpResponse,
 };
 };
-use flowy_net::errors::ServerError;
-use flowy_workspace::protobuf::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams};
-use sqlx::PgPool;
-
-use crate::service::{
-    doc::doc::DocBiz,
-    util::parse_from_payload,
-    view::{create_view, delete_views, read_view, update_view},
+use anyhow::Context;
+use flowy_net::{
+    errors::{invalid_params, ServerError},
+    response::FlowyResponse,
+};
+use flowy_workspace::{
+    entities::view::parser::{ViewDesc, ViewName, ViewThumbnail},
+    protobuf::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams},
 };
 };
+use sqlx::PgPool;
 use std::sync::Arc;
 use std::sync::Arc;
 
 
 pub async fn create_handler(
 pub async fn create_handler(
@@ -19,28 +26,89 @@ pub async fn create_handler(
     _doc_biz: Data<Arc<DocBiz>>,
     _doc_biz: Data<Arc<DocBiz>>,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: CreateViewParams = parse_from_payload(payload).await?;
     let params: CreateViewParams = parse_from_payload(payload).await?;
-    let resp = create_view(pool.get_ref(), params).await?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to create view")?;
+
+    let view = create_view(&mut transaction, params).await?;
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to create view.")?;
+
+    let resp = FlowyResponse::success().pb(view)?;
     Ok(resp.into())
     Ok(resp.into())
 }
 }
 
 
-pub async fn read_handler(
-    payload: Payload,
-    pool: Data<PgPool>,
-    doc_biz: Data<Arc<DocBiz>>,
-) -> Result<HttpResponse, ServerError> {
+pub async fn read_handler(payload: Payload, pool: Data<PgPool>, user: LoggedUser) -> Result<HttpResponse, ServerError> {
     let params: QueryViewParams = parse_from_payload(payload).await?;
     let params: QueryViewParams = parse_from_payload(payload).await?;
-    let resp = read_view(pool.get_ref(), params, doc_biz).await?;
-    Ok(resp.into())
+    let view_id = check_view_ids(vec![params.view_id])?.pop().unwrap();
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to read view")?;
+    let view = read_view(&user, view_id, &mut transaction).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to read view.")?;
+
+    Ok(FlowyResponse::success().pb(view)?.into())
 }
 }
 
 
 pub async fn update_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
 pub async fn update_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
     let params: UpdateViewParams = parse_from_payload(payload).await?;
     let params: UpdateViewParams = parse_from_payload(payload).await?;
-    let resp = update_view(pool.get_ref(), params).await?;
-    Ok(resp.into())
+    let view_id = check_view_ids(vec![params.view_id.clone()])?.pop().unwrap();
+    let name = match params.has_name() {
+        false => None,
+        true => Some(ViewName::parse(params.get_name().to_owned()).map_err(invalid_params)?.0),
+    };
+
+    let desc = match params.has_desc() {
+        false => None,
+        true => Some(ViewDesc::parse(params.get_desc().to_owned()).map_err(invalid_params)?.0),
+    };
+
+    let thumbnail = match params.has_thumbnail() {
+        false => None,
+        true => Some(
+            ViewThumbnail::parse(params.get_thumbnail().to_owned())
+                .map_err(invalid_params)?
+                .0,
+        ),
+    };
+
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to update app")?;
+
+    let _ = update_view(&mut transaction, view_id, name, desc, thumbnail).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to update view.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }
 
 
 pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
 pub async fn delete_handler(payload: Payload, pool: Data<PgPool>) -> Result<HttpResponse, ServerError> {
     let params: DeleteViewParams = parse_from_payload(payload).await?;
     let params: DeleteViewParams = parse_from_payload(payload).await?;
-    let resp = delete_views(pool.get_ref(), params.view_ids.into_vec()).await?;
-    Ok(resp.into())
+    let view_ids = check_view_ids(params.view_ids.to_vec())?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to delete view")?;
+
+    let _ = delete_view(&mut transaction, view_ids).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to delete view.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }

+ 72 - 138
backend/src/service/view/view.rs

@@ -1,48 +1,64 @@
-use anyhow::Context;
+use crate::{
+    entities::workspace::{ViewTable, VIEW_TABLE},
+    service::{
+        doc::{create_doc, delete_doc},
+        trash::read_trash_ids,
+        user::LoggedUser,
+        view::sql_builder::*,
+    },
+    sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
+};
 use chrono::Utc;
 use chrono::Utc;
-use sqlx::{postgres::PgArguments, PgPool, Postgres};
-
 use flowy_document::protobuf::CreateDocParams;
 use flowy_document::protobuf::CreateDocParams;
-use flowy_net::{
-    errors::{invalid_params, ServerError},
-    response::FlowyResponse,
-};
+use flowy_net::errors::{invalid_params, ServerError};
 use flowy_workspace::{
 use flowy_workspace::{
     entities::{
     entities::{
         app::parser::AppId,
         app::parser::AppId,
         view::parser::{ViewDesc, ViewName, ViewThumbnail},
         view::parser::{ViewDesc, ViewName, ViewThumbnail},
     },
     },
-    protobuf::{CreateViewParams, QueryViewParams, RepeatedView, UpdateViewParams, View},
-};
-
-use crate::{
-    entities::workspace::{ViewTable, VIEW_TABLE},
-    service::{
-        doc::{create_doc, delete_doc, doc::DocBiz},
-        view::sql_builder::*,
-    },
-    sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
+    protobuf::{CreateViewParams, RepeatedView, View},
 };
 };
-use actix_web::web::Data;
-use std::sync::Arc;
+use sqlx::{postgres::PgArguments, Postgres};
 use uuid::Uuid;
 use uuid::Uuid;
 
 
-pub(crate) async fn create_view(pool: &PgPool, params: CreateViewParams) -> Result<FlowyResponse, ServerError> {
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to create view")?;
-    let view = create_view_with_transaction(&mut transaction, params).await?;
-    transaction
-        .commit()
+pub(crate) async fn update_view(
+    transaction: &mut DBTransaction<'_>,
+    view_id: Uuid,
+    name: Option<String>,
+    desc: Option<String>,
+    thumbnail: Option<String>,
+) -> Result<(), ServerError> {
+    let (sql, args) = SqlBuilder::update(VIEW_TABLE)
+        .add_some_arg("name", name)
+        .add_some_arg("description", desc)
+        .add_some_arg("thumbnail", thumbnail)
+        .add_some_arg("modified_time", Some(Utc::now()))
+        .and_where_eq("id", view_id)
+        .build()?;
+
+    sqlx::query_with(&sql, args)
+        .execute(transaction)
         .await
         .await
-        .context("Failed to commit SQL transaction to create view.")?;
+        .map_err(map_sqlx_error)?;
+
+    Ok(())
+}
+
+pub(crate) async fn delete_view(transaction: &mut DBTransaction<'_>, view_ids: Vec<Uuid>) -> Result<(), ServerError> {
+    for view_id in view_ids {
+        let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;
+        let _ = sqlx::query_with(&sql, args)
+            .execute(transaction as &mut DBTransaction<'_>)
+            .await
+            .map_err(map_sqlx_error)?;
 
 
-    FlowyResponse::success().pb(view)
+        let _ = delete_doc(transaction, view_id).await?;
+    }
+    Ok(())
 }
 }
 
 
 #[tracing::instrument(name = "create_view", level = "debug", skip(transaction), err)]
 #[tracing::instrument(name = "create_view", level = "debug", skip(transaction), err)]
-pub(crate) async fn create_view_with_transaction(
+pub(crate) async fn create_view(
     transaction: &mut DBTransaction<'_>,
     transaction: &mut DBTransaction<'_>,
     params: CreateViewParams,
     params: CreateViewParams,
 ) -> Result<View, ServerError> {
 ) -> Result<View, ServerError> {
@@ -70,128 +86,43 @@ pub(crate) async fn create_view_with_transaction(
     Ok(view)
     Ok(view)
 }
 }
 
 
-pub(crate) async fn read_view_with_transaction(
+pub(crate) async fn read_view(
+    user: &LoggedUser,
     view_id: Uuid,
     view_id: Uuid,
     transaction: &mut DBTransaction<'_>,
     transaction: &mut DBTransaction<'_>,
-) -> Result<ViewTable, ServerError> {
-    let (sql, args) = SqlBuilder::select(VIEW_TABLE)
-        .add_field("*")
-        .and_where_eq("id", view_id)
-        .build()?;
-
-    let table = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
-        .fetch_one(transaction as &mut DBTransaction<'_>)
-        .await
-        .map_err(map_sqlx_error)?;
-    Ok(table)
-}
-
-pub(crate) async fn read_view(
-    pool: &PgPool,
-    params: QueryViewParams,
-    _doc_biz: Data<Arc<DocBiz>>,
-) -> Result<FlowyResponse, ServerError> {
-    let view_id = check_view_ids(vec![params.view_id])?.pop().unwrap();
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to read view")?;
-    let table = read_view_with_transaction(view_id, &mut transaction).await?;
+) -> Result<View, ServerError> {
+    let table = read_view_table(view_id, transaction as &mut DBTransaction<'_>).await?;
     let mut views = RepeatedView::default();
     let mut views = RepeatedView::default();
-    if params.read_belongings {
-        views.set_items(
-            read_views_belong_to_id(&mut transaction, &table.id.to_string())
-                .await?
-                .into(),
-        )
-    }
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to read view.")?;
-
+    views.set_items(
+        read_view_belong_to_id(&user, transaction, &table.id.to_string())
+            .await?
+            .into(),
+    );
     let mut view: View = table.into();
     let mut view: View = table.into();
     view.set_belongings(views);
     view.set_belongings(views);
-
-    FlowyResponse::success().pb(view)
+    Ok(view)
 }
 }
 
 
-pub(crate) async fn update_view(pool: &PgPool, params: UpdateViewParams) -> Result<FlowyResponse, ServerError> {
-    let view_id = check_view_ids(vec![params.view_id.clone()])?.pop().unwrap();
-
-    let name = match params.has_name() {
-        false => None,
-        true => Some(ViewName::parse(params.get_name().to_owned()).map_err(invalid_params)?.0),
-    };
-
-    let desc = match params.has_desc() {
-        false => None,
-        true => Some(ViewDesc::parse(params.get_desc().to_owned()).map_err(invalid_params)?.0),
-    };
-
-    let thumbnail = match params.has_thumbnail() {
-        false => None,
-        true => Some(
-            ViewThumbnail::parse(params.get_thumbnail().to_owned())
-                .map_err(invalid_params)?
-                .0,
-        ),
-    };
-
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to update app")?;
-
-    let (sql, args) = SqlBuilder::update(VIEW_TABLE)
-        .add_some_arg("name", name)
-        .add_some_arg("description", desc)
-        .add_some_arg("thumbnail", thumbnail)
-        .add_some_arg("modified_time", Some(Utc::now()))
+pub(crate) async fn read_view_table(
+    view_id: Uuid,
+    transaction: &mut DBTransaction<'_>,
+) -> Result<ViewTable, ServerError> {
+    let (sql, args) = SqlBuilder::select(VIEW_TABLE)
+        .add_field("*")
         .and_where_eq("id", view_id)
         .and_where_eq("id", view_id)
         .build()?;
         .build()?;
 
 
-    sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+    let table = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
+        .fetch_one(transaction as &mut DBTransaction<'_>)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to update view.")?;
-
-    Ok(FlowyResponse::success())
-}
-
-pub(crate) async fn delete_views(pool: &PgPool, view_ids: Vec<String>) -> Result<FlowyResponse, ServerError> {
-    let view_ids = check_view_ids(view_ids)?;
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to delete view")?;
-
-    for view_id in view_ids {
-        let (sql, args) = SqlBuilder::delete(VIEW_TABLE).and_where_eq("id", &view_id).build()?;
-        let _ = sqlx::query_with(&sql, args)
-            .execute(&mut transaction)
-            .await
-            .map_err(map_sqlx_error)?;
-
-        let _ = delete_doc(&mut transaction, view_id).await?;
-    }
-
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to delete view.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(table)
 }
 }
 
 
 // transaction must be commit from caller
 // transaction must be commit from caller
-pub(crate) async fn read_views_belong_to_id<'c>(
+pub(crate) async fn read_view_belong_to_id<'c>(
+    user: &LoggedUser,
     transaction: &mut DBTransaction<'_>,
     transaction: &mut DBTransaction<'_>,
     id: &str,
     id: &str,
 ) -> Result<Vec<View>, ServerError> {
 ) -> Result<Vec<View>, ServerError> {
@@ -201,11 +132,14 @@ pub(crate) async fn read_views_belong_to_id<'c>(
         .and_where_eq("belong_to_id", id)
         .and_where_eq("belong_to_id", id)
         .build()?;
         .build()?;
 
 
-    let tables = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
-        .fetch_all(transaction)
+    let mut tables = sqlx::query_as_with::<Postgres, ViewTable, PgArguments>(&sql, args)
+        .fetch_all(transaction as &mut DBTransaction<'_>)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
+    let read_trash_ids = read_trash_ids(user, transaction).await?;
+    tables.retain(|table| !read_trash_ids.contains(&table.id.to_string()));
+
     let views = tables.into_iter().map(|table| table.into()).collect::<Vec<View>>();
     let views = tables.into_iter().map(|table| table.into()).collect::<Vec<View>>();
 
 
     Ok(views)
     Ok(views)

+ 105 - 27
backend/src/service/workspace/router.rs

@@ -1,22 +1,28 @@
+use crate::service::{
+    user::LoggedUser,
+    util::parse_from_payload,
+    workspace::{
+        create_workspace,
+        delete_workspace,
+        read_workspaces,
+        sql_builder::check_workspace_id,
+        update_workspace,
+    },
+};
 use actix_web::{
 use actix_web::{
     web::{Data, Payload},
     web::{Data, Payload},
     HttpResponse,
     HttpResponse,
 };
 };
-use sqlx::PgPool;
-
-use flowy_net::errors::ServerError;
-use flowy_workspace::protobuf::{
-    CreateWorkspaceParams,
-    DeleteWorkspaceParams,
-    QueryWorkspaceParams,
-    UpdateWorkspaceParams,
+use anyhow::Context;
+use flowy_net::{
+    errors::{invalid_params, ServerError},
+    response::FlowyResponse,
 };
 };
-
-use crate::service::{
-    user::LoggedUser,
-    util::parse_from_payload,
-    workspace::{create_workspace, delete_workspace, read_workspaces, update_workspace},
+use flowy_workspace::{
+    entities::workspace::parser::{WorkspaceDesc, WorkspaceName},
+    protobuf::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams},
 };
 };
+use sqlx::PgPool;
 
 
 pub async fn create_handler(
 pub async fn create_handler(
     payload: Payload,
     payload: Payload,
@@ -24,8 +30,19 @@ pub async fn create_handler(
     logged_user: LoggedUser,
     logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: CreateWorkspaceParams = parse_from_payload(payload).await?;
     let params: CreateWorkspaceParams = parse_from_payload(payload).await?;
-    let resp = create_workspace(pool.get_ref(), params, logged_user).await?;
-    Ok(resp.into())
+    let name = WorkspaceName::parse(params.get_name().to_owned()).map_err(invalid_params)?;
+    let desc = WorkspaceDesc::parse(params.get_desc().to_owned()).map_err(invalid_params)?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to create workspace")?;
+    let workspace = create_workspace(&mut transaction, name.as_ref(), desc.as_ref(), logged_user).await?;
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to create workspace.")?;
+
+    Ok(FlowyResponse::success().pb(workspace)?.into())
 }
 }
 
 
 pub async fn read_handler(
 pub async fn read_handler(
@@ -34,13 +51,24 @@ pub async fn read_handler(
     logged_user: LoggedUser,
     logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: QueryWorkspaceParams = parse_from_payload(payload).await?;
     let params: QueryWorkspaceParams = parse_from_payload(payload).await?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to read workspace")?;
+
     let workspace_id = if params.has_workspace_id() {
     let workspace_id = if params.has_workspace_id() {
         Some(params.get_workspace_id().to_owned())
         Some(params.get_workspace_id().to_owned())
     } else {
     } else {
         None
         None
     };
     };
-    let resp = read_workspaces(pool.get_ref(), workspace_id, logged_user).await?;
-    Ok(resp.into())
+    let repeated_workspace = read_workspaces(&mut transaction, workspace_id, logged_user).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to read workspace.")?;
+
+    Ok(FlowyResponse::success().pb(repeated_workspace)?.into())
 }
 }
 
 
 pub async fn delete_handler(
 pub async fn delete_handler(
@@ -49,8 +77,19 @@ pub async fn delete_handler(
     _logged_user: LoggedUser,
     _logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: DeleteWorkspaceParams = parse_from_payload(payload).await?;
     let params: DeleteWorkspaceParams = parse_from_payload(payload).await?;
-    let resp = delete_workspace(pool.get_ref(), params.get_workspace_id()).await?;
-    Ok(resp.into())
+    let workspace_id = check_workspace_id(params.get_workspace_id().to_owned())?;
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to delete workspace")?;
+
+    let _ = delete_workspace(&mut transaction, workspace_id).await?;
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to delete workspace.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }
 
 
 pub async fn update_handler(
 pub async fn update_handler(
@@ -59,14 +98,53 @@ pub async fn update_handler(
     _logged_user: LoggedUser,
     _logged_user: LoggedUser,
 ) -> Result<HttpResponse, ServerError> {
 ) -> Result<HttpResponse, ServerError> {
     let params: UpdateWorkspaceParams = parse_from_payload(payload).await?;
     let params: UpdateWorkspaceParams = parse_from_payload(payload).await?;
-    let resp = update_workspace(pool.get_ref(), params).await?;
-    Ok(resp.into())
+    let workspace_id = check_workspace_id(params.get_id().to_owned())?;
+    let name = match params.has_name() {
+        false => None,
+        true => {
+            let name = WorkspaceName::parse(params.get_name().to_owned())
+                .map_err(invalid_params)?
+                .0;
+            Some(name)
+        },
+    };
+
+    let desc = match params.has_desc() {
+        false => None,
+        true => {
+            let desc = WorkspaceDesc::parse(params.get_desc().to_owned())
+                .map_err(invalid_params)?
+                .0;
+            Some(desc)
+        },
+    };
+
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to update workspace")?;
+
+    let _ = update_workspace(&mut transaction, workspace_id, name, desc).await?;
+
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to update workspace.")?;
+
+    Ok(FlowyResponse::success().into())
 }
 }
 
 
-pub async fn workspace_list(
-    pool: Data<PgPool>,
-    logged_user: LoggedUser,
-) -> Result<HttpResponse, ServerError> {
-    let resp = read_workspaces(pool.get_ref(), None, logged_user).await?;
-    Ok(resp.into())
+pub async fn workspace_list(pool: Data<PgPool>, logged_user: LoggedUser) -> Result<HttpResponse, ServerError> {
+    let mut transaction = pool
+        .begin()
+        .await
+        .context("Failed to acquire a Postgres connection to read workspaces")?;
+
+    let repeated_workspace = read_workspaces(&mut transaction, None, logged_user).await?;
+    transaction
+        .commit()
+        .await
+        .context("Failed to commit SQL transaction to read workspace.")?;
+
+    Ok(FlowyResponse::success().pb(repeated_workspace)?.into())
 }
 }

+ 50 - 118
backend/src/service/workspace/workspace.rs

@@ -1,85 +1,41 @@
-use anyhow::Context;
-use sqlx::{postgres::PgArguments, PgPool, Postgres};
-
-use flowy_net::{
-    errors::{invalid_params, ServerError},
-    response::FlowyResponse,
-};
-use flowy_workspace::{
-    entities::workspace::parser::{WorkspaceDesc, WorkspaceId, WorkspaceName},
-    protobuf::{App, CreateWorkspaceParams, RepeatedApp, RepeatedWorkspace, UpdateWorkspaceParams},
-};
-
+use super::sql_builder::NewWorkspaceBuilder;
 use crate::{
 use crate::{
     entities::workspace::{AppTable, WorkspaceTable, WORKSPACE_TABLE},
     entities::workspace::{AppTable, WorkspaceTable, WORKSPACE_TABLE},
-    service::{user::LoggedUser, view::read_views_belong_to_id, workspace::sql_builder::*},
+    service::{app::app::read_app, user::LoggedUser, workspace::sql_builder::*},
     sqlx_ext::*,
     sqlx_ext::*,
 };
 };
-
-use super::sql_builder::NewWorkspaceBuilder;
+use anyhow::Context;
+use flowy_net::errors::{invalid_params, ServerError};
+use flowy_workspace::{
+    entities::workspace::parser::WorkspaceId,
+    protobuf::{RepeatedApp, RepeatedWorkspace, Workspace},
+};
+use sqlx::{postgres::PgArguments, Postgres};
+use uuid::Uuid;
 
 
 pub(crate) async fn create_workspace(
 pub(crate) async fn create_workspace(
-    pool: &PgPool,
-    params: CreateWorkspaceParams,
+    transaction: &mut DBTransaction<'_>,
+    name: &str,
+    desc: &str,
     logged_user: LoggedUser,
     logged_user: LoggedUser,
-) -> Result<FlowyResponse, ServerError> {
-    let name = WorkspaceName::parse(params.get_name().to_owned()).map_err(invalid_params)?;
-    let desc = WorkspaceDesc::parse(params.get_desc().to_owned()).map_err(invalid_params)?;
+) -> Result<Workspace, ServerError> {
     let user_id = logged_user.as_uuid()?.to_string();
     let user_id = logged_user.as_uuid()?.to_string();
-
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to create workspace")?;
-
-    let (sql, args, workspace) = NewWorkspaceBuilder::new(&user_id)
-        .name(name.as_ref())
-        .desc(desc.as_ref())
-        .build()?;
+    let (sql, args, workspace) = NewWorkspaceBuilder::new(&user_id).name(name).desc(desc).build()?;
 
 
     let _ = sqlx::query_with(&sql, args)
     let _ = sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to create workspace.")?;
-
-    FlowyResponse::success().pb(workspace)
+    Ok(workspace)
 }
 }
 
 
 pub(crate) async fn update_workspace(
 pub(crate) async fn update_workspace(
-    pool: &PgPool,
-    params: UpdateWorkspaceParams,
-) -> Result<FlowyResponse, ServerError> {
-    let workspace_id = check_workspace_id(params.get_id().to_owned())?;
-    let name = match params.has_name() {
-        false => None,
-        true => {
-            let name = WorkspaceName::parse(params.get_name().to_owned())
-                .map_err(invalid_params)?
-                .0;
-            Some(name)
-        },
-    };
-
-    let desc = match params.has_desc() {
-        false => None,
-        true => {
-            let desc = WorkspaceDesc::parse(params.get_desc().to_owned())
-                .map_err(invalid_params)?
-                .0;
-            Some(desc)
-        },
-    };
-
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to update workspace")?;
-
+    transaction: &mut DBTransaction<'_>,
+    workspace_id: Uuid,
+    name: Option<String>,
+    desc: Option<String>,
+) -> Result<(), ServerError> {
     let (sql, args) = SqlBuilder::update(WORKSPACE_TABLE)
     let (sql, args) = SqlBuilder::update(WORKSPACE_TABLE)
         .add_some_arg("name", name)
         .add_some_arg("name", name)
         .add_some_arg("description", desc)
         .add_some_arg("description", desc)
@@ -87,55 +43,35 @@ pub(crate) async fn update_workspace(
         .build()?;
         .build()?;
 
 
     sqlx::query_with(&sql, args)
     sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to update workspace.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(())
 }
 }
 
 
 pub(crate) async fn delete_workspace(
 pub(crate) async fn delete_workspace(
-    pool: &PgPool,
-    workspace_id: &str,
-) -> Result<FlowyResponse, ServerError> {
-    let workspace_id = check_workspace_id(workspace_id.to_owned())?;
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to delete workspace")?;
-
+    transaction: &mut DBTransaction<'_>,
+    workspace_id: Uuid,
+) -> Result<(), ServerError> {
     let (sql, args) = SqlBuilder::delete(WORKSPACE_TABLE)
     let (sql, args) = SqlBuilder::delete(WORKSPACE_TABLE)
         .and_where_eq("id", workspace_id)
         .and_where_eq("id", workspace_id)
         .build()?;
         .build()?;
 
 
     let _ = sqlx::query_with(&sql, args)
     let _ = sqlx::query_with(&sql, args)
-        .execute(&mut transaction)
+        .execute(transaction)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to delete workspace.")?;
-
-    Ok(FlowyResponse::success())
+    Ok(())
 }
 }
 
 
 pub async fn read_workspaces(
 pub async fn read_workspaces(
-    pool: &PgPool,
+    transaction: &mut DBTransaction<'_>,
     workspace_id: Option<String>,
     workspace_id: Option<String>,
     logged_user: LoggedUser,
     logged_user: LoggedUser,
-) -> Result<FlowyResponse, ServerError> {
+) -> Result<RepeatedWorkspace, ServerError> {
     let user_id = logged_user.as_uuid()?.to_string();
     let user_id = logged_user.as_uuid()?.to_string();
-    let mut transaction = pool
-        .begin()
-        .await
-        .context("Failed to acquire a Postgres connection to read workspace")?;
 
 
     let mut builder = SqlBuilder::select(WORKSPACE_TABLE)
     let mut builder = SqlBuilder::select(WORKSPACE_TABLE)
         .add_field("*")
         .add_field("*")
@@ -148,7 +84,7 @@ pub async fn read_workspaces(
 
 
     let (sql, args) = builder.build()?;
     let (sql, args) = builder.build()?;
     let tables = sqlx::query_as_with::<Postgres, WorkspaceTable, PgArguments>(&sql, args)
     let tables = sqlx::query_as_with::<Postgres, WorkspaceTable, PgArguments>(&sql, args)
-        .fetch_all(&mut transaction)
+        .fetch_all(transaction as &mut DBTransaction<'_>)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
@@ -156,49 +92,45 @@ pub async fn read_workspaces(
     let mut workspaces = vec![];
     let mut workspaces = vec![];
     // Opti: combine the query
     // Opti: combine the query
     for table in tables {
     for table in tables {
-        let mut apps = read_apps_belong_to_workspace(&mut transaction, &table.id.to_string())
-            .await
-            .context("Get workspace app")
-            .unwrap_or(RepeatedApp::default());
-
-        for app in &mut apps.items {
-            let views = read_views_belong_to_id(&mut transaction, &app.id).await?;
-            app.mut_belongings().set_items(views.into());
-        }
+        let apps = read_workspace_apps(
+            &logged_user,
+            transaction as &mut DBTransaction<'_>,
+            &table.id.to_string(),
+        )
+        .await
+        .context("Get workspace app")
+        .unwrap_or(RepeatedApp::default());
 
 
         let workspace = make_workspace_from_table(table, Some(apps));
         let workspace = make_workspace_from_table(table, Some(apps));
         workspaces.push(workspace);
         workspaces.push(workspace);
     }
     }
-    transaction
-        .commit()
-        .await
-        .context("Failed to commit SQL transaction to read workspace.")?;
 
 
     repeated_workspace.set_items(workspaces.into());
     repeated_workspace.set_items(workspaces.into());
-    FlowyResponse::success().pb(repeated_workspace)
+    Ok(repeated_workspace)
 }
 }
 
 
 // transaction must be commit from caller
 // transaction must be commit from caller
-async fn read_apps_belong_to_workspace<'c>(
+async fn read_workspace_apps<'c>(
+    user: &LoggedUser,
     transaction: &mut DBTransaction<'_>,
     transaction: &mut DBTransaction<'_>,
     workspace_id: &str,
     workspace_id: &str,
 ) -> Result<RepeatedApp, ServerError> {
 ) -> Result<RepeatedApp, ServerError> {
-    let transaction = transaction;
     let workspace_id = WorkspaceId::parse(workspace_id.to_owned()).map_err(invalid_params)?;
     let workspace_id = WorkspaceId::parse(workspace_id.to_owned()).map_err(invalid_params)?;
     let (sql, args) = SqlBuilder::select("app_table")
     let (sql, args) = SqlBuilder::select("app_table")
         .add_field("*")
         .add_field("*")
         .and_where_eq("workspace_id", workspace_id.0)
         .and_where_eq("workspace_id", workspace_id.0)
         .build()?;
         .build()?;
 
 
-    let tables = sqlx::query_as_with::<Postgres, AppTable, PgArguments>(&sql, args)
-        .fetch_all(transaction)
+    let app_tables = sqlx::query_as_with::<Postgres, AppTable, PgArguments>(&sql, args)
+        .fetch_all(transaction as &mut DBTransaction<'_>)
         .await
         .await
         .map_err(map_sqlx_error)?;
         .map_err(map_sqlx_error)?;
 
 
-    let apps = tables
-        .into_iter()
-        .map(|table| table.into())
-        .collect::<Vec<App>>();
+    let mut apps = vec![];
+    for table in app_tables {
+        let app = read_app(transaction, table.id, user).await?;
+        apps.push(app);
+    }
 
 
     let mut repeated_app = RepeatedApp::default();
     let mut repeated_app = RepeatedApp::default();
     repeated_app.set_items(apps.into());
     repeated_app.set_items(apps.into());

+ 23 - 21
backend/tests/api/workspace.rs

@@ -1,7 +1,7 @@
 use crate::helper::*;
 use crate::helper::*;
 use flowy_workspace::entities::{
 use flowy_workspace::entities::{
-    app::{DeleteAppParams, QueryAppParams, UpdateAppParams},
-    view::{DeleteViewParams, QueryViewParams, UpdateViewParams},
+    app::{AppIdentifier, DeleteAppParams, UpdateAppParams},
+    view::UpdateViewParams,
     workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams},
     workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams},
 };
 };
 
 
@@ -74,7 +74,7 @@ async fn app_create() {
 #[actix_rt::test]
 #[actix_rt::test]
 async fn app_read() {
 async fn app_read() {
     let test = AppTest::new().await;
     let test = AppTest::new().await;
-    let read_params = QueryAppParams::new(&test.app.id);
+    let read_params = AppIdentifier::new(&test.app.id);
     assert_eq!(test.server.read_app(read_params).await.is_some(), true);
     assert_eq!(test.server.read_app(read_params).await.is_some(), true);
 }
 }
 
 
@@ -85,7 +85,7 @@ async fn app_read_with_belongs() {
     let _ = create_test_view(&test.server, &test.app.id).await;
     let _ = create_test_view(&test.server, &test.app.id).await;
     let _ = create_test_view(&test.server, &test.app.id).await;
     let _ = create_test_view(&test.server, &test.app.id).await;
 
 
-    let read_params = QueryAppParams::new(&test.app.id).read_belongings();
+    let read_params = AppIdentifier::new(&test.app.id);
     let app = test.server.read_app(read_params).await.unwrap();
     let app = test.server.read_app(read_params).await.unwrap();
     assert_eq!(app.belongings.len(), 2);
     assert_eq!(app.belongings.len(), 2);
 }
 }
@@ -98,9 +98,10 @@ async fn app_read_with_belongs_in_trash() {
     let view = create_test_view(&test.server, &test.app.id).await;
     let view = create_test_view(&test.server, &test.app.id).await;
 
 
     let update_params = UpdateViewParams::new(&view.id).trash();
     let update_params = UpdateViewParams::new(&view.id).trash();
+    // create trash
     test.server.update_view(update_params).await;
     test.server.update_view(update_params).await;
 
 
-    let read_params = QueryAppParams::new(&test.app.id).read_belongings();
+    let read_params = AppIdentifier::new(&test.app.id);
     let app = test.server.read_app(read_params).await.unwrap();
     let app = test.server.read_app(read_params).await.unwrap();
     assert_eq!(app.belongings.len(), 1);
     assert_eq!(app.belongings.len(), 1);
 }
 }
@@ -114,7 +115,7 @@ async fn app_update() {
     let update_params = UpdateAppParams::new(&test.app.id).name(new_name);
     let update_params = UpdateAppParams::new(&test.app.id).name(new_name);
     test.server.update_app(update_params).await;
     test.server.update_app(update_params).await;
 
 
-    let read_params = QueryAppParams::new(&test.app.id);
+    let read_params = AppIdentifier::new(&test.app.id);
     let app = test.server.read_app(read_params).await.unwrap();
     let app = test.server.read_app(read_params).await.unwrap();
     assert_eq!(&app.name, new_name);
     assert_eq!(&app.name, new_name);
 }
 }
@@ -127,7 +128,7 @@ async fn app_delete() {
         app_id: test.app.id.clone(),
         app_id: test.app.id.clone(),
     };
     };
     test.server.delete_app(delete_params).await;
     test.server.delete_app(delete_params).await;
-    let read_params = QueryAppParams::new(&test.app.id);
+    let read_params = AppIdentifier::new(&test.app.id);
     assert_eq!(test.server.read_app(read_params).await.is_none(), true);
     assert_eq!(test.server.read_app(read_params).await.is_none(), true);
 }
 }
 
 
@@ -137,20 +138,21 @@ async fn view_create() {
     log::info!("{:?}", test.view);
     log::info!("{:?}", test.view);
 }
 }
 
 
-#[actix_rt::test]
-async fn view_update() {
-    let test = ViewTest::new().await;
-    let new_name = "name view name";
-
-    // update
-    let update_params = UpdateViewParams::new(&test.view.id).trash().name(new_name);
-    test.server.update_view(update_params).await;
-
-    // read
-    let read_params = QueryViewParams::new(&test.view.id).trash();
-    let view = test.server.read_view(read_params).await.unwrap();
-    assert_eq!(&view.name, new_name);
-}
+// #[actix_rt::test]
+// async fn view_update() {
+//     let test = ViewTest::new().await;
+//     let new_name = "name view name";
+//
+//     // update
+//     let update_params =
+// UpdateViewParams::new(&test.view.id).trash().name(new_name);     test.server.
+// update_view(update_params).await;
+//
+//     // read
+//     let read_params = QueryViewParams::new(&test.view.id).trash();
+//     let view = test.server.read_view(read_params).await.unwrap();
+//     assert_eq!(&view.name, new_name);
+// }
 
 
 // #[actix_rt::test]
 // #[actix_rt::test]
 // async fn view_delete() {
 // async fn view_delete() {

+ 16 - 1
backend/tests/helper.rs

@@ -84,7 +84,7 @@ impl TestUserServer {
         app
         app
     }
     }
 
 
-    pub async fn read_app(&self, params: QueryAppParams) -> Option<App> {
+    pub async fn read_app(&self, params: AppIdentifier) -> Option<App> {
         let url = format!("{}/api/app", self.http_addr());
         let url = format!("{}/api/app", self.http_addr());
         let app = read_app_request(self.user_token(), params, &url).await.unwrap();
         let app = read_app_request(self.user_token(), params, &url).await.unwrap();
         app
         app
@@ -122,6 +122,21 @@ impl TestUserServer {
         delete_view_request(self.user_token(), params, &url).await.unwrap();
         delete_view_request(self.user_token(), params, &url).await.unwrap();
     }
     }
 
 
+    pub async fn create_trash(&self, params: CreateTrashParams) {
+        let url = format!("{}/api/trash", self.http_addr());
+        create_trash_request(self.user_token(), params, &url).await.unwrap();
+    }
+
+    pub async fn delete_trash(&self, params: TrashIdentifiers) {
+        let url = format!("{}/api/trash", self.http_addr());
+        delete_trash_request(self.user_token(), params, &url).await.unwrap();
+    }
+
+    pub async fn read_trash(&self) -> RepeatedTrash {
+        let url = format!("{}/api/trash", self.http_addr());
+        read_trash_request(self.user_token(), &url).await.unwrap()
+    }
+
     pub async fn read_doc(&self, params: DocIdentifier) -> Option<Doc> {
     pub async fn read_doc(&self, params: DocIdentifier) -> Option<Doc> {
         let url = format!("{}/api/doc", self.http_addr());
         let url = format!("{}/api/doc", self.http_addr());
         let doc = read_doc_request(self.user_token(), params, &url).await.unwrap();
         let doc = read_doc_request(self.user_token(), params, &url).await.unwrap();

+ 1 - 1
rust-lib/flowy-derive/src/derive_cache/derive_cache.rs

@@ -17,7 +17,7 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
         "String" => TypeCategory::Str,
         "String" => TypeCategory::Str,
         "KeyValue"
         "KeyValue"
         | "QueryAppRequest"
         | "QueryAppRequest"
-        | "QueryAppParams"
+        | "AppIdentifier"
         | "CreateAppRequest"
         | "CreateAppRequest"
         | "ColorStyle"
         | "ColorStyle"
         | "CreateAppParams"
         | "CreateAppParams"

+ 5 - 34
rust-lib/flowy-workspace/src/entities/app/app_query.rs

@@ -8,9 +8,6 @@ pub struct QueryAppRequest {
     pub app_id: String,
     pub app_id: String,
 
 
     #[pb(index = 2)]
     #[pb(index = 2)]
-    pub read_belongings: bool,
-
-    #[pb(index = 3)]
     pub is_trash: bool,
     pub is_trash: bool,
 }
 }
 
 
@@ -18,60 +15,34 @@ impl QueryAppRequest {
     pub fn new(app_id: &str) -> Self {
     pub fn new(app_id: &str) -> Self {
         QueryAppRequest {
         QueryAppRequest {
             app_id: app_id.to_string(),
             app_id: app_id.to_string(),
-            read_belongings: false,
             is_trash: false,
             is_trash: false,
         }
         }
     }
     }
-
-    pub fn read_views(mut self) -> Self {
-        self.read_belongings = true;
-        self
-    }
 }
 }
 
 
 #[derive(ProtoBuf, Default, Clone, Debug)]
 #[derive(ProtoBuf, Default, Clone, Debug)]
-pub struct QueryAppParams {
+pub struct AppIdentifier {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub app_id: String,
     pub app_id: String,
-
-    #[pb(index = 2)]
-    pub read_belongings: bool,
-
-    #[pb(index = 3)]
-    pub is_trash: bool,
 }
 }
 
 
-impl QueryAppParams {
+impl AppIdentifier {
     pub fn new(app_id: &str) -> Self {
     pub fn new(app_id: &str) -> Self {
         Self {
         Self {
             app_id: app_id.to_string(),
             app_id: app_id.to_string(),
             ..Default::default()
             ..Default::default()
         }
         }
     }
     }
-
-    pub fn read_belongings(mut self) -> Self {
-        self.read_belongings = true;
-        self
-    }
-
-    pub fn trash(mut self) -> Self {
-        self.is_trash = true;
-        self
-    }
 }
 }
 
 
-impl TryInto<QueryAppParams> for QueryAppRequest {
+impl TryInto<AppIdentifier> for QueryAppRequest {
     type Error = WorkspaceError;
     type Error = WorkspaceError;
 
 
-    fn try_into(self) -> Result<QueryAppParams, Self::Error> {
+    fn try_into(self) -> Result<AppIdentifier, Self::Error> {
         let app_id = AppId::parse(self.app_id)
         let app_id = AppId::parse(self.app_id)
             .map_err(|e| WorkspaceError::app_id().context(e))?
             .map_err(|e| WorkspaceError::app_id().context(e))?
             .0;
             .0;
 
 
-        Ok(QueryAppParams {
-            app_id,
-            read_belongings: self.read_belongings,
-            is_trash: self.is_trash,
-        })
+        Ok(AppIdentifier { app_id })
     }
     }
 }
 }

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

@@ -7,16 +7,12 @@ use std::convert::TryInto;
 pub struct QueryViewRequest {
 pub struct QueryViewRequest {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub view_id: String,
     pub view_id: String,
-
-    #[pb(index = 2)]
-    pub read_belongings: bool,
 }
 }
 
 
 impl QueryViewRequest {
 impl QueryViewRequest {
     pub fn new(view_id: &str) -> Self {
     pub fn new(view_id: &str) -> Self {
         Self {
         Self {
             view_id: view_id.to_owned(),
             view_id: view_id.to_owned(),
-            read_belongings: false,
         }
         }
     }
     }
 }
 }
@@ -25,23 +21,14 @@ impl QueryViewRequest {
 pub struct QueryViewParams {
 pub struct QueryViewParams {
     #[pb(index = 1)]
     #[pb(index = 1)]
     pub view_id: String,
     pub view_id: String,
-
-    #[pb(index = 2)]
-    pub read_belongings: bool,
 }
 }
 
 
 impl QueryViewParams {
 impl QueryViewParams {
     pub fn new(view_id: &str) -> Self {
     pub fn new(view_id: &str) -> Self {
         Self {
         Self {
             view_id: view_id.to_owned(),
             view_id: view_id.to_owned(),
-            ..Default::default()
         }
         }
     }
     }
-
-    pub fn read_belongings(mut self) -> Self {
-        self.read_belongings = true;
-        self
-    }
 }
 }
 
 
 impl std::convert::Into<DocIdentifier> for QueryViewParams {
 impl std::convert::Into<DocIdentifier> for QueryViewParams {
@@ -55,10 +42,7 @@ impl TryInto<QueryViewParams> for QueryViewRequest {
             .map_err(|e| WorkspaceError::view_id().context(e))?
             .map_err(|e| WorkspaceError::view_id().context(e))?
             .0;
             .0;
 
 
-        Ok(QueryViewParams {
-            view_id,
-            read_belongings: self.read_belongings,
-        })
+        Ok(QueryViewParams { view_id })
     }
     }
 }
 }
 
 

+ 1 - 0
rust-lib/flowy-workspace/src/entities/view/view_update.rs

@@ -54,6 +54,7 @@ impl UpdateViewParams {
         self.is_trash = Some(true);
         self.is_trash = Some(true);
         self
         self
     }
     }
+
     pub fn name(mut self, name: &str) -> Self {
     pub fn name(mut self, name: &str) -> Self {
         self.name = Some(name.to_owned());
         self.name = Some(name.to_owned());
         self
         self

+ 3 - 7
rust-lib/flowy-workspace/src/handlers/app_handler.rs

@@ -1,11 +1,11 @@
 use crate::{
 use crate::{
     entities::app::{
     entities::app::{
         App,
         App,
+        AppIdentifier,
         CreateAppParams,
         CreateAppParams,
         CreateAppRequest,
         CreateAppRequest,
         DeleteAppParams,
         DeleteAppParams,
         DeleteAppRequest,
         DeleteAppRequest,
-        QueryAppParams,
         QueryAppRequest,
         QueryAppRequest,
         UpdateAppParams,
         UpdateAppParams,
         UpdateAppRequest,
         UpdateAppRequest,
@@ -53,13 +53,9 @@ pub(crate) async fn read_app_handler(
     app_controller: Unit<Arc<AppController>>,
     app_controller: Unit<Arc<AppController>>,
     view_controller: Unit<Arc<ViewController>>,
     view_controller: Unit<Arc<ViewController>>,
 ) -> DataResult<App, WorkspaceError> {
 ) -> DataResult<App, WorkspaceError> {
-    let params: QueryAppParams = data.into_inner().try_into()?;
+    let params: AppIdentifier = data.into_inner().try_into()?;
     let mut app = app_controller.read_app(params.clone()).await?;
     let mut app = app_controller.read_app(params.clone()).await?;
-
-    // The View's belonging is the view indexed by the belong_to_id for now
-    if params.read_belongings {
-        app.belongings = view_controller.read_views_belong_to(&params.app_id).await?;
-    }
+    app.belongings = view_controller.read_views_belong_to(&params.app_id).await?;
 
 
     data_result(app)
     data_result(app)
 }
 }

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

@@ -35,10 +35,7 @@ pub(crate) async fn read_view_handler(
 ) -> DataResult<View, WorkspaceError> {
 ) -> DataResult<View, WorkspaceError> {
     let params: QueryViewParams = data.into_inner().try_into()?;
     let params: QueryViewParams = data.into_inner().try_into()?;
     let mut view = controller.read_view(params.clone()).await?;
     let mut view = controller.read_view(params.clone()).await?;
-
-    if params.read_belongings {
-        view.belongings = controller.read_views_belong_to(&params.view_id).await?;
-    }
+    view.belongings = controller.read_views_belong_to(&params.view_id).await?;
 
 
     data_result(view)
     data_result(view)
 }
 }

+ 1 - 1
rust-lib/flowy-workspace/src/lib.rs

@@ -20,7 +20,7 @@ extern crate flowy_database;
 
 
 pub mod prelude {
 pub mod prelude {
     pub use crate::{
     pub use crate::{
-        entities::{app::*, view::*, workspace::*},
+        entities::{app::*, trash::*, view::*, workspace::*},
         errors::*,
         errors::*,
         module::*,
         module::*,
         services::*,
         services::*,

+ 36 - 152
rust-lib/flowy-workspace/src/protobuf/model/app_query.rs

@@ -27,7 +27,6 @@
 pub struct QueryAppRequest {
 pub struct QueryAppRequest {
     // message fields
     // message fields
     pub app_id: ::std::string::String,
     pub app_id: ::std::string::String,
-    pub read_belongings: bool,
     pub is_trash: bool,
     pub is_trash: bool,
     // special fields
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub unknown_fields: ::protobuf::UnknownFields,
@@ -71,22 +70,7 @@ impl QueryAppRequest {
         ::std::mem::replace(&mut self.app_id, ::std::string::String::new())
         ::std::mem::replace(&mut self.app_id, ::std::string::String::new())
     }
     }
 
 
-    // bool read_belongings = 2;
-
-
-    pub fn get_read_belongings(&self) -> bool {
-        self.read_belongings
-    }
-    pub fn clear_read_belongings(&mut self) {
-        self.read_belongings = false;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_read_belongings(&mut self, v: bool) {
-        self.read_belongings = v;
-    }
-
-    // bool is_trash = 3;
+    // bool is_trash = 2;
 
 
 
 
     pub fn get_is_trash(&self) -> bool {
     pub fn get_is_trash(&self) -> bool {
@@ -115,13 +99,6 @@ impl ::protobuf::Message for QueryAppRequest {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?;
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?;
                 },
                 },
                 2 => {
                 2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.read_belongings = tmp;
-                },
-                3 => {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
                     if wire_type != ::protobuf::wire_format::WireTypeVarint {
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                         return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
                     }
                     }
@@ -143,9 +120,6 @@ impl ::protobuf::Message for QueryAppRequest {
         if !self.app_id.is_empty() {
         if !self.app_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.app_id);
             my_size += ::protobuf::rt::string_size(1, &self.app_id);
         }
         }
-        if self.read_belongings != false {
-            my_size += 2;
-        }
         if self.is_trash != false {
         if self.is_trash != false {
             my_size += 2;
             my_size += 2;
         }
         }
@@ -158,11 +132,8 @@ impl ::protobuf::Message for QueryAppRequest {
         if !self.app_id.is_empty() {
         if !self.app_id.is_empty() {
             os.write_string(1, &self.app_id)?;
             os.write_string(1, &self.app_id)?;
         }
         }
-        if self.read_belongings != false {
-            os.write_bool(2, self.read_belongings)?;
-        }
         if self.is_trash != false {
         if self.is_trash != false {
-            os.write_bool(3, self.is_trash)?;
+            os.write_bool(2, self.is_trash)?;
         }
         }
         os.write_unknown_fields(self.get_unknown_fields())?;
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
         ::std::result::Result::Ok(())
@@ -207,11 +178,6 @@ impl ::protobuf::Message for QueryAppRequest {
                 |m: &QueryAppRequest| { &m.app_id },
                 |m: &QueryAppRequest| { &m.app_id },
                 |m: &mut QueryAppRequest| { &mut m.app_id },
                 |m: &mut QueryAppRequest| { &mut m.app_id },
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
-                "read_belongings",
-                |m: &QueryAppRequest| { &m.read_belongings },
-                |m: &mut QueryAppRequest| { &mut m.read_belongings },
-            ));
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
             fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
                 "is_trash",
                 "is_trash",
                 |m: &QueryAppRequest| { &m.is_trash },
                 |m: &QueryAppRequest| { &m.is_trash },
@@ -234,7 +200,6 @@ impl ::protobuf::Message for QueryAppRequest {
 impl ::protobuf::Clear for QueryAppRequest {
 impl ::protobuf::Clear for QueryAppRequest {
     fn clear(&mut self) {
     fn clear(&mut self) {
         self.app_id.clear();
         self.app_id.clear();
-        self.read_belongings = false;
         self.is_trash = false;
         self.is_trash = false;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
@@ -253,24 +218,22 @@ impl ::protobuf::reflect::ProtobufValue for QueryAppRequest {
 }
 }
 
 
 #[derive(PartialEq,Clone,Default)]
 #[derive(PartialEq,Clone,Default)]
-pub struct QueryAppParams {
+pub struct AppIdentifier {
     // message fields
     // message fields
     pub app_id: ::std::string::String,
     pub app_id: ::std::string::String,
-    pub read_belongings: bool,
-    pub is_trash: bool,
     // special fields
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
     pub cached_size: ::protobuf::CachedSize,
 }
 }
 
 
-impl<'a> ::std::default::Default for &'a QueryAppParams {
-    fn default() -> &'a QueryAppParams {
-        <QueryAppParams as ::protobuf::Message>::default_instance()
+impl<'a> ::std::default::Default for &'a AppIdentifier {
+    fn default() -> &'a AppIdentifier {
+        <AppIdentifier as ::protobuf::Message>::default_instance()
     }
     }
 }
 }
 
 
-impl QueryAppParams {
-    pub fn new() -> QueryAppParams {
+impl AppIdentifier {
+    pub fn new() -> AppIdentifier {
         ::std::default::Default::default()
         ::std::default::Default::default()
     }
     }
 
 
@@ -299,39 +262,9 @@ impl QueryAppParams {
     pub fn take_app_id(&mut self) -> ::std::string::String {
     pub fn take_app_id(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.app_id, ::std::string::String::new())
         ::std::mem::replace(&mut self.app_id, ::std::string::String::new())
     }
     }
-
-    // bool read_belongings = 2;
-
-
-    pub fn get_read_belongings(&self) -> bool {
-        self.read_belongings
-    }
-    pub fn clear_read_belongings(&mut self) {
-        self.read_belongings = false;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_read_belongings(&mut self, v: bool) {
-        self.read_belongings = v;
-    }
-
-    // bool is_trash = 3;
-
-
-    pub fn get_is_trash(&self) -> bool {
-        self.is_trash
-    }
-    pub fn clear_is_trash(&mut self) {
-        self.is_trash = false;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_is_trash(&mut self, v: bool) {
-        self.is_trash = v;
-    }
 }
 }
 
 
-impl ::protobuf::Message for QueryAppParams {
+impl ::protobuf::Message for AppIdentifier {
     fn is_initialized(&self) -> bool {
     fn is_initialized(&self) -> bool {
         true
         true
     }
     }
@@ -343,20 +276,6 @@ impl ::protobuf::Message for QueryAppParams {
                 1 => {
                 1 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?;
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?;
                 },
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.read_belongings = tmp;
-                },
-                3 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.is_trash = tmp;
-                },
                 _ => {
                 _ => {
                     ::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())?;
                 },
                 },
@@ -372,12 +291,6 @@ impl ::protobuf::Message for QueryAppParams {
         if !self.app_id.is_empty() {
         if !self.app_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.app_id);
             my_size += ::protobuf::rt::string_size(1, &self.app_id);
         }
         }
-        if self.read_belongings != false {
-            my_size += 2;
-        }
-        if self.is_trash != false {
-            my_size += 2;
-        }
         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
@@ -387,12 +300,6 @@ impl ::protobuf::Message for QueryAppParams {
         if !self.app_id.is_empty() {
         if !self.app_id.is_empty() {
             os.write_string(1, &self.app_id)?;
             os.write_string(1, &self.app_id)?;
         }
         }
-        if self.read_belongings != false {
-            os.write_bool(2, self.read_belongings)?;
-        }
-        if self.is_trash != false {
-            os.write_bool(3, self.is_trash)?;
-        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
         ::std::result::Result::Ok(())
     }
     }
@@ -423,8 +330,8 @@ impl ::protobuf::Message for QueryAppParams {
         Self::descriptor_static()
         Self::descriptor_static()
     }
     }
 
 
-    fn new() -> QueryAppParams {
-        QueryAppParams::new()
+    fn new() -> AppIdentifier {
+        AppIdentifier::new()
     }
     }
 
 
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
     fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
@@ -433,81 +340,58 @@ impl ::protobuf::Message for QueryAppParams {
             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>(
                 "app_id",
                 "app_id",
-                |m: &QueryAppParams| { &m.app_id },
-                |m: &mut QueryAppParams| { &mut m.app_id },
-            ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
-                "read_belongings",
-                |m: &QueryAppParams| { &m.read_belongings },
-                |m: &mut QueryAppParams| { &mut m.read_belongings },
+                |m: &AppIdentifier| { &m.app_id },
+                |m: &mut AppIdentifier| { &mut m.app_id },
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
-                "is_trash",
-                |m: &QueryAppParams| { &m.is_trash },
-                |m: &mut QueryAppParams| { &mut m.is_trash },
-            ));
-            ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryAppParams>(
-                "QueryAppParams",
+            ::protobuf::reflect::MessageDescriptor::new_pb_name::<AppIdentifier>(
+                "AppIdentifier",
                 fields,
                 fields,
                 file_descriptor_proto()
                 file_descriptor_proto()
             )
             )
         })
         })
     }
     }
 
 
-    fn default_instance() -> &'static QueryAppParams {
-        static instance: ::protobuf::rt::LazyV2<QueryAppParams> = ::protobuf::rt::LazyV2::INIT;
-        instance.get(QueryAppParams::new)
+    fn default_instance() -> &'static AppIdentifier {
+        static instance: ::protobuf::rt::LazyV2<AppIdentifier> = ::protobuf::rt::LazyV2::INIT;
+        instance.get(AppIdentifier::new)
     }
     }
 }
 }
 
 
-impl ::protobuf::Clear for QueryAppParams {
+impl ::protobuf::Clear for AppIdentifier {
     fn clear(&mut self) {
     fn clear(&mut self) {
         self.app_id.clear();
         self.app_id.clear();
-        self.read_belongings = false;
-        self.is_trash = false;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
 }
 }
 
 
-impl ::std::fmt::Debug for QueryAppParams {
+impl ::std::fmt::Debug for AppIdentifier {
     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 QueryAppParams {
+impl ::protobuf::reflect::ProtobufValue for AppIdentifier {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
     fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
         ::protobuf::reflect::ReflectValueRef::Message(self)
         ::protobuf::reflect::ReflectValueRef::Message(self)
     }
     }
 }
 }
 
 
 static file_descriptor_proto_data: &'static [u8] = b"\
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x0fapp_query.proto\"l\n\x0fQueryAppRequest\x12\x15\n\x06app_id\x18\
-    \x01\x20\x01(\tR\x05appId\x12'\n\x0fread_belongings\x18\x02\x20\x01(\x08\
-    R\x0ereadBelongings\x12\x19\n\x08is_trash\x18\x03\x20\x01(\x08R\x07isTra\
-    sh\"k\n\x0eQueryAppParams\x12\x15\n\x06app_id\x18\x01\x20\x01(\tR\x05app\
-    Id\x12'\n\x0fread_belongings\x18\x02\x20\x01(\x08R\x0ereadBelongings\x12\
-    \x19\n\x08is_trash\x18\x03\x20\x01(\x08R\x07isTrashJ\x8c\x03\n\x06\x12\
-    \x04\0\0\x0b\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\
-    \x02\0\x06\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\x16\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\x11\n\x0c\n\x05\x04\0\x02\0\
-    \x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x1d\n\
-    \x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\x08\n\x0c\n\x05\x04\0\x02\
-    \x01\x01\x12\x03\x04\t\x18\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x1b\
-    \x1c\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x16\n\x0c\n\x05\x04\0\x02\
-    \x02\x05\x12\x03\x05\x04\x08\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\t\
-    \x11\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x14\x15\n\n\n\x02\x04\x01\
-    \x12\x04\x07\0\x0b\x01\n\n\n\x03\x04\x01\x01\x12\x03\x07\x08\x16\n\x0b\n\
-    \x04\x04\x01\x02\0\x12\x03\x08\x04\x16\n\x0c\n\x05\x04\x01\x02\0\x05\x12\
-    \x03\x08\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x08\x0b\x11\n\x0c\n\
-    \x05\x04\x01\x02\0\x03\x12\x03\x08\x14\x15\n\x0b\n\x04\x04\x01\x02\x01\
-    \x12\x03\t\x04\x1d\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\t\x04\x08\n\
-    \x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\t\t\x18\n\x0c\n\x05\x04\x01\x02\
-    \x01\x03\x12\x03\t\x1b\x1c\n\x0b\n\x04\x04\x01\x02\x02\x12\x03\n\x04\x16\
-    \n\x0c\n\x05\x04\x01\x02\x02\x05\x12\x03\n\x04\x08\n\x0c\n\x05\x04\x01\
-    \x02\x02\x01\x12\x03\n\t\x11\n\x0c\n\x05\x04\x01\x02\x02\x03\x12\x03\n\
-    \x14\x15b\x06proto3\
+    \n\x0fapp_query.proto\"C\n\x0fQueryAppRequest\x12\x15\n\x06app_id\x18\
+    \x01\x20\x01(\tR\x05appId\x12\x19\n\x08is_trash\x18\x02\x20\x01(\x08R\
+    \x07isTrash\"&\n\rAppIdentifier\x12\x15\n\x06app_id\x18\x01\x20\x01(\tR\
+    \x05appIdJ\xe7\x01\n\x06\x12\x04\0\0\x08\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\x16\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\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\
+    \0\x02\x01\x12\x03\x04\x04\x16\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\
+    \x04\x08\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\x11\n\x0c\n\x05\x04\
+    \0\x02\x01\x03\x12\x03\x04\x14\x15\n\n\n\x02\x04\x01\x12\x04\x06\0\x08\
+    \x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x15\n\x0b\n\x04\x04\x01\x02\0\
+    \x12\x03\x07\x04\x16\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\x11\n\x0c\n\x05\x04\x01\x02\
+    \0\x03\x12\x03\x07\x14\x15b\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;

+ 16 - 94
rust-lib/flowy-workspace/src/protobuf/model/view_query.rs

@@ -27,7 +27,6 @@
 pub struct QueryViewRequest {
 pub struct QueryViewRequest {
     // message fields
     // message fields
     pub view_id: ::std::string::String,
     pub view_id: ::std::string::String,
-    pub read_belongings: bool,
     // special fields
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
     pub cached_size: ::protobuf::CachedSize,
@@ -69,21 +68,6 @@ impl QueryViewRequest {
     pub fn take_view_id(&mut self) -> ::std::string::String {
     pub fn take_view_id(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
         ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
     }
     }
-
-    // bool read_belongings = 2;
-
-
-    pub fn get_read_belongings(&self) -> bool {
-        self.read_belongings
-    }
-    pub fn clear_read_belongings(&mut self) {
-        self.read_belongings = false;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_read_belongings(&mut self, v: bool) {
-        self.read_belongings = v;
-    }
 }
 }
 
 
 impl ::protobuf::Message for QueryViewRequest {
 impl ::protobuf::Message for QueryViewRequest {
@@ -98,13 +82,6 @@ impl ::protobuf::Message for QueryViewRequest {
                 1 => {
                 1 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
                 },
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.read_belongings = tmp;
-                },
                 _ => {
                 _ => {
                     ::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())?;
                 },
                 },
@@ -120,9 +97,6 @@ impl ::protobuf::Message for QueryViewRequest {
         if !self.view_id.is_empty() {
         if !self.view_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.view_id);
             my_size += ::protobuf::rt::string_size(1, &self.view_id);
         }
         }
-        if self.read_belongings != false {
-            my_size += 2;
-        }
         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
@@ -132,9 +106,6 @@ impl ::protobuf::Message for QueryViewRequest {
         if !self.view_id.is_empty() {
         if !self.view_id.is_empty() {
             os.write_string(1, &self.view_id)?;
             os.write_string(1, &self.view_id)?;
         }
         }
-        if self.read_belongings != false {
-            os.write_bool(2, self.read_belongings)?;
-        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
         ::std::result::Result::Ok(())
     }
     }
@@ -178,11 +149,6 @@ impl ::protobuf::Message for QueryViewRequest {
                 |m: &QueryViewRequest| { &m.view_id },
                 |m: &QueryViewRequest| { &m.view_id },
                 |m: &mut QueryViewRequest| { &mut m.view_id },
                 |m: &mut QueryViewRequest| { &mut m.view_id },
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
-                "read_belongings",
-                |m: &QueryViewRequest| { &m.read_belongings },
-                |m: &mut QueryViewRequest| { &mut m.read_belongings },
-            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryViewRequest>(
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryViewRequest>(
                 "QueryViewRequest",
                 "QueryViewRequest",
                 fields,
                 fields,
@@ -200,7 +166,6 @@ impl ::protobuf::Message for QueryViewRequest {
 impl ::protobuf::Clear for QueryViewRequest {
 impl ::protobuf::Clear for QueryViewRequest {
     fn clear(&mut self) {
     fn clear(&mut self) {
         self.view_id.clear();
         self.view_id.clear();
-        self.read_belongings = false;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
 }
 }
@@ -221,7 +186,6 @@ impl ::protobuf::reflect::ProtobufValue for QueryViewRequest {
 pub struct QueryViewParams {
 pub struct QueryViewParams {
     // message fields
     // message fields
     pub view_id: ::std::string::String,
     pub view_id: ::std::string::String,
-    pub read_belongings: bool,
     // special fields
     // special fields
     pub unknown_fields: ::protobuf::UnknownFields,
     pub unknown_fields: ::protobuf::UnknownFields,
     pub cached_size: ::protobuf::CachedSize,
     pub cached_size: ::protobuf::CachedSize,
@@ -263,21 +227,6 @@ impl QueryViewParams {
     pub fn take_view_id(&mut self) -> ::std::string::String {
     pub fn take_view_id(&mut self) -> ::std::string::String {
         ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
         ::std::mem::replace(&mut self.view_id, ::std::string::String::new())
     }
     }
-
-    // bool read_belongings = 2;
-
-
-    pub fn get_read_belongings(&self) -> bool {
-        self.read_belongings
-    }
-    pub fn clear_read_belongings(&mut self) {
-        self.read_belongings = false;
-    }
-
-    // Param is passed by value, moved
-    pub fn set_read_belongings(&mut self, v: bool) {
-        self.read_belongings = v;
-    }
 }
 }
 
 
 impl ::protobuf::Message for QueryViewParams {
 impl ::protobuf::Message for QueryViewParams {
@@ -292,13 +241,6 @@ impl ::protobuf::Message for QueryViewParams {
                 1 => {
                 1 => {
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
                     ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.view_id)?;
                 },
                 },
-                2 => {
-                    if wire_type != ::protobuf::wire_format::WireTypeVarint {
-                        return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
-                    }
-                    let tmp = is.read_bool()?;
-                    self.read_belongings = tmp;
-                },
                 _ => {
                 _ => {
                     ::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())?;
                 },
                 },
@@ -314,9 +256,6 @@ impl ::protobuf::Message for QueryViewParams {
         if !self.view_id.is_empty() {
         if !self.view_id.is_empty() {
             my_size += ::protobuf::rt::string_size(1, &self.view_id);
             my_size += ::protobuf::rt::string_size(1, &self.view_id);
         }
         }
-        if self.read_belongings != false {
-            my_size += 2;
-        }
         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
@@ -326,9 +265,6 @@ impl ::protobuf::Message for QueryViewParams {
         if !self.view_id.is_empty() {
         if !self.view_id.is_empty() {
             os.write_string(1, &self.view_id)?;
             os.write_string(1, &self.view_id)?;
         }
         }
-        if self.read_belongings != false {
-            os.write_bool(2, self.read_belongings)?;
-        }
         os.write_unknown_fields(self.get_unknown_fields())?;
         os.write_unknown_fields(self.get_unknown_fields())?;
         ::std::result::Result::Ok(())
         ::std::result::Result::Ok(())
     }
     }
@@ -372,11 +308,6 @@ impl ::protobuf::Message for QueryViewParams {
                 |m: &QueryViewParams| { &m.view_id },
                 |m: &QueryViewParams| { &m.view_id },
                 |m: &mut QueryViewParams| { &mut m.view_id },
                 |m: &mut QueryViewParams| { &mut m.view_id },
             ));
             ));
-            fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
-                "read_belongings",
-                |m: &QueryViewParams| { &m.read_belongings },
-                |m: &mut QueryViewParams| { &mut m.read_belongings },
-            ));
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryViewParams>(
             ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryViewParams>(
                 "QueryViewParams",
                 "QueryViewParams",
                 fields,
                 fields,
@@ -394,7 +325,6 @@ impl ::protobuf::Message for QueryViewParams {
 impl ::protobuf::Clear for QueryViewParams {
 impl ::protobuf::Clear for QueryViewParams {
     fn clear(&mut self) {
     fn clear(&mut self) {
         self.view_id.clear();
         self.view_id.clear();
-        self.read_belongings = false;
         self.unknown_fields.clear();
         self.unknown_fields.clear();
     }
     }
 }
 }
@@ -571,30 +501,22 @@ impl ::protobuf::reflect::ProtobufValue for OpenViewRequest {
 }
 }
 
 
 static file_descriptor_proto_data: &'static [u8] = b"\
 static file_descriptor_proto_data: &'static [u8] = b"\
-    \n\x10view_query.proto\"T\n\x10QueryViewRequest\x12\x17\n\x07view_id\x18\
-    \x01\x20\x01(\tR\x06viewId\x12'\n\x0fread_belongings\x18\x02\x20\x01(\
-    \x08R\x0ereadBelongings\"S\n\x0fQueryViewParams\x12\x17\n\x07view_id\x18\
-    \x01\x20\x01(\tR\x06viewId\x12'\n\x0fread_belongings\x18\x02\x20\x01(\
-    \x08R\x0ereadBelongings\"*\n\x0fOpenViewRequest\x12\x17\n\x07view_id\x18\
-    \x01\x20\x01(\tR\x06viewIdJ\xed\x02\n\x06\x12\x04\0\0\x0c\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\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\
-    \x17\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\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x15\
-    \x16\n\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x04\x1d\n\x0c\n\x05\x04\0\x02\
-    \x01\x05\x12\x03\x04\x04\x08\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\
-    \x18\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x1b\x1c\n\n\n\x02\x04\x01\
-    \x12\x04\x06\0\t\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x17\n\x0b\n\
-    \x04\x04\x01\x02\0\x12\x03\x07\x04\x17\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\x12\n\x0c\n\
-    \x05\x04\x01\x02\0\x03\x12\x03\x07\x15\x16\n\x0b\n\x04\x04\x01\x02\x01\
-    \x12\x03\x08\x04\x1d\n\x0c\n\x05\x04\x01\x02\x01\x05\x12\x03\x08\x04\x08\
-    \n\x0c\n\x05\x04\x01\x02\x01\x01\x12\x03\x08\t\x18\n\x0c\n\x05\x04\x01\
-    \x02\x01\x03\x12\x03\x08\x1b\x1c\n\n\n\x02\x04\x02\x12\x04\n\0\x0c\x01\n\
-    \n\n\x03\x04\x02\x01\x12\x03\n\x08\x17\n\x0b\n\x04\x04\x02\x02\0\x12\x03\
-    \x0b\x04\x17\n\x0c\n\x05\x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\
-    \x04\x02\x02\0\x01\x12\x03\x0b\x0b\x12\n\x0c\n\x05\x04\x02\x02\0\x03\x12\
-    \x03\x0b\x15\x16b\x06proto3\
+    \n\x10view_query.proto\"+\n\x10QueryViewRequest\x12\x17\n\x07view_id\x18\
+    \x01\x20\x01(\tR\x06viewId\"*\n\x0fQueryViewParams\x12\x17\n\x07view_id\
+    \x18\x01\x20\x01(\tR\x06viewId\"*\n\x0fOpenViewRequest\x12\x17\n\x07view\
+    _id\x18\x01\x20\x01(\tR\x06viewIdJ\xff\x01\n\x06\x12\x04\0\0\n\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\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\
+    \x04\x17\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\x12\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\
+    \x15\x16\n\n\n\x02\x04\x01\x12\x04\x05\0\x07\x01\n\n\n\x03\x04\x01\x01\
+    \x12\x03\x05\x08\x17\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x06\x04\x17\n\x0c\
+    \n\x05\x04\x01\x02\0\x05\x12\x03\x06\x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\
+    \x12\x03\x06\x0b\x12\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x06\x15\x16\n\
+    \n\n\x02\x04\x02\x12\x04\x08\0\n\x01\n\n\n\x03\x04\x02\x01\x12\x03\x08\
+    \x08\x17\n\x0b\n\x04\x04\x02\x02\0\x12\x03\t\x04\x17\n\x0c\n\x05\x04\x02\
+    \x02\0\x05\x12\x03\t\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\t\x0b\
+    \x12\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\t\x15\x16b\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;

+ 2 - 5
rust-lib/flowy-workspace/src/protobuf/proto/app_query.proto

@@ -2,11 +2,8 @@ syntax = "proto3";
 
 
 message QueryAppRequest {
 message QueryAppRequest {
     string app_id = 1;
     string app_id = 1;
-    bool read_belongings = 2;
-    bool is_trash = 3;
+    bool is_trash = 2;
 }
 }
-message QueryAppParams {
+message AppIdentifier {
     string app_id = 1;
     string app_id = 1;
-    bool read_belongings = 2;
-    bool is_trash = 3;
 }
 }

+ 0 - 2
rust-lib/flowy-workspace/src/protobuf/proto/view_query.proto

@@ -2,11 +2,9 @@ syntax = "proto3";
 
 
 message QueryViewRequest {
 message QueryViewRequest {
     string view_id = 1;
     string view_id = 1;
-    bool read_belongings = 2;
 }
 }
 message QueryViewParams {
 message QueryViewParams {
     string view_id = 1;
     string view_id = 1;
-    bool read_belongings = 2;
 }
 }
 message OpenViewRequest {
 message OpenViewRequest {
     string view_id = 1;
     string view_id = 1;

+ 4 - 6
rust-lib/flowy-workspace/src/services/app_controller.rs

@@ -51,10 +51,8 @@ impl AppController {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub(crate) async fn read_app(&self, params: QueryAppParams) -> Result<App, WorkspaceError> {
-        let app_table = self
-            .sql
-            .read_app(&params.app_id, Some(params.is_trash), &*self.database.db_connection()?)?;
+    pub(crate) async fn read_app(&self, params: AppIdentifier) -> Result<App, WorkspaceError> {
+        let app_table = self.sql.read_app(&params.app_id, &*self.database.db_connection()?)?;
         let _ = self.read_app_on_server(params)?;
         let _ = self.read_app_on_server(params)?;
         Ok(app_table.into())
         Ok(app_table.into())
     }
     }
@@ -87,7 +85,7 @@ impl AppController {
         let conn = &*self.database.db_connection()?;
         let conn = &*self.database.db_connection()?;
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
         conn.immediate_transaction::<_, WorkspaceError, _>(|| {
             let _ = self.sql.update_app(changeset, conn)?;
             let _ = self.sql.update_app(changeset, conn)?;
-            let app: App = self.sql.read_app(&app_id, None, conn)?.into();
+            let app: App = self.sql.read_app(&app_id, conn)?.into();
             send_dart_notification(&app_id, WorkspaceNotification::AppUpdated)
             send_dart_notification(&app_id, WorkspaceNotification::AppUpdated)
                 .payload(app)
                 .payload(app)
                 .send();
                 .send();
@@ -143,7 +141,7 @@ impl AppController {
     }
     }
 
 
     #[tracing::instrument(level = "debug", skip(self), err)]
     #[tracing::instrument(level = "debug", skip(self), err)]
-    fn read_app_on_server(&self, params: QueryAppParams) -> Result<(), WorkspaceError> {
+    fn read_app_on_server(&self, params: AppIdentifier) -> Result<(), WorkspaceError> {
         let token = self.user.token()?;
         let token = self.user.token()?;
         let server = self.server.clone();
         let server = self.server.clone();
         spawn(async move {
         spawn(async move {

+ 2 - 2
rust-lib/flowy-workspace/src/services/server/mod.rs

@@ -8,7 +8,7 @@ pub use server_api_mock::*;
 
 
 use crate::{
 use crate::{
     entities::{
     entities::{
-        app::{App, CreateAppParams, DeleteAppParams, QueryAppParams, UpdateAppParams},
+        app::{App, AppIdentifier, CreateAppParams, DeleteAppParams, UpdateAppParams},
         view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View},
         view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View},
         workspace::{
         workspace::{
             CreateWorkspaceParams,
             CreateWorkspaceParams,
@@ -53,7 +53,7 @@ pub trait WorkspaceServerAPI {
     // App
     // App
     fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<App, WorkspaceError>;
     fn create_app(&self, token: &str, params: CreateAppParams) -> ResultFuture<App, WorkspaceError>;
 
 
-    fn read_app(&self, token: &str, params: QueryAppParams) -> ResultFuture<Option<App>, WorkspaceError>;
+    fn read_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<Option<App>, WorkspaceError>;
 
 
     fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError>;
     fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError>;
 
 

+ 35 - 3
rust-lib/flowy-workspace/src/services/server/server_api.rs

@@ -1,6 +1,7 @@
 use crate::{
 use crate::{
     entities::{
     entities::{
-        app::{App, CreateAppParams, DeleteAppParams, QueryAppParams, UpdateAppParams},
+        app::{App, AppIdentifier, CreateAppParams, DeleteAppParams, UpdateAppParams},
+        trash::CreateTrashParams,
         view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View},
         view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View},
         workspace::{
         workspace::{
             CreateWorkspaceParams,
             CreateWorkspaceParams,
@@ -14,6 +15,8 @@ use crate::{
     errors::WorkspaceError,
     errors::WorkspaceError,
     services::server::WorkspaceServerAPI,
     services::server::WorkspaceServerAPI,
 };
 };
+
+use crate::entities::trash::{RepeatedTrash, TrashIdentifiers};
 use flowy_infra::future::ResultFuture;
 use flowy_infra::future::ResultFuture;
 use flowy_net::{config::*, request::HttpRequestBuilder};
 use flowy_net::{config::*, request::HttpRequestBuilder};
 
 
@@ -84,7 +87,7 @@ impl WorkspaceServerAPI for WorkspaceServer {
         ResultFuture::new(async move { create_app_request(&token, params, &url).await })
         ResultFuture::new(async move { create_app_request(&token, params, &url).await })
     }
     }
 
 
-    fn read_app(&self, token: &str, params: QueryAppParams) -> ResultFuture<Option<App>, WorkspaceError> {
+    fn read_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<Option<App>, WorkspaceError> {
         let token = token.to_owned();
         let token = token.to_owned();
         let url = self.config.app_url();
         let url = self.config.app_url();
         ResultFuture::new(async move { read_app_request(&token, params, &url).await })
         ResultFuture::new(async move { read_app_request(&token, params, &url).await })
@@ -174,7 +177,7 @@ pub async fn create_app_request(token: &str, params: CreateAppParams, url: &str)
     Ok(app)
     Ok(app)
 }
 }
 
 
-pub async fn read_app_request(token: &str, params: QueryAppParams, url: &str) -> Result<Option<App>, WorkspaceError> {
+pub async fn read_app_request(token: &str, params: AppIdentifier, url: &str) -> Result<Option<App>, WorkspaceError> {
     let app = request_builder()
     let app = request_builder()
         .get(&url.to_owned())
         .get(&url.to_owned())
         .header(HEADER_TOKEN, token)
         .header(HEADER_TOKEN, token)
@@ -250,3 +253,32 @@ pub async fn delete_view_request(token: &str, params: DeleteViewParams, url: &st
         .await?;
         .await?;
     Ok(())
     Ok(())
 }
 }
+
+pub async fn create_trash_request(token: &str, params: CreateTrashParams, url: &str) -> Result<(), WorkspaceError> {
+    let _ = request_builder()
+        .post(&url.to_owned())
+        .header(HEADER_TOKEN, token)
+        .protobuf(params)?
+        .send()
+        .await?;
+    Ok(())
+}
+
+pub async fn delete_trash_request(token: &str, params: TrashIdentifiers, url: &str) -> Result<(), WorkspaceError> {
+    let _ = request_builder()
+        .delete(&url.to_owned())
+        .header(HEADER_TOKEN, token)
+        .protobuf(params)?
+        .send()
+        .await?;
+    Ok(())
+}
+
+pub async fn read_trash_request(token: &str, url: &str) -> Result<RepeatedTrash, WorkspaceError> {
+    let repeated_trash = request_builder()
+        .get(&url.to_owned())
+        .header(HEADER_TOKEN, token)
+        .response::<RepeatedTrash>()
+        .await?;
+    Ok(repeated_trash)
+}

+ 2 - 2
rust-lib/flowy-workspace/src/services/server/server_api_mock.rs

@@ -1,6 +1,6 @@
 use crate::{
 use crate::{
     entities::{
     entities::{
-        app::{App, CreateAppParams, DeleteAppParams, QueryAppParams, RepeatedApp, UpdateAppParams},
+        app::{App, AppIdentifier, CreateAppParams, DeleteAppParams, RepeatedApp, UpdateAppParams},
         view::{CreateViewParams, DeleteViewParams, QueryViewParams, RepeatedView, UpdateViewParams, View},
         view::{CreateViewParams, DeleteViewParams, QueryViewParams, RepeatedView, UpdateViewParams, View},
         workspace::{
         workspace::{
             CreateWorkspaceParams,
             CreateWorkspaceParams,
@@ -95,7 +95,7 @@ impl WorkspaceServerAPI for WorkspaceServerMock {
         ResultFuture::new(async { Ok(app) })
         ResultFuture::new(async { Ok(app) })
     }
     }
 
 
-    fn read_app(&self, _token: &str, _params: QueryAppParams) -> ResultFuture<Option<App>, WorkspaceError> {
+    fn read_app(&self, _token: &str, _params: AppIdentifier) -> ResultFuture<Option<App>, WorkspaceError> {
         ResultFuture::new(async { Ok(None) })
         ResultFuture::new(async { Ok(None) })
     }
     }
 
 

+ 5 - 10
rust-lib/flowy-workspace/src/sql_tables/app/app_sql.rs

@@ -31,17 +31,12 @@ impl AppTableSql {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub(crate) fn read_app(
-        &self,
-        app_id: &str,
-        is_trash: Option<bool>,
-        conn: &SqliteConnection,
-    ) -> Result<AppTable, WorkspaceError> {
-        let mut filter = dsl::app_table.filter(app_table::id.eq(app_id)).into_boxed();
+    pub(crate) fn read_app(&self, app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> {
+        let filter = dsl::app_table.filter(app_table::id.eq(app_id)).into_boxed();
 
 
-        if let Some(is_trash) = is_trash {
-            filter = filter.filter(app_table::is_trash.eq(is_trash));
-        }
+        // if let Some(is_trash) = is_trash {
+        //     filter = filter.filter(app_table::is_trash.eq(is_trash));
+        // }
 
 
         let app_table = filter.first::<AppTable>(conn)?;
         let app_table = filter.first::<AppTable>(conn)?;
         Ok(app_table)
         Ok(app_table)

+ 1 - 1
rust-lib/flowy-workspace/tests/workspace/app_test.rs

@@ -40,7 +40,7 @@ async fn app_create_with_view() {
     let view_a = create_view_with_request(&test.sdk, request_a).await;
     let view_a = create_view_with_request(&test.sdk, request_a).await;
     let view_b = create_view_with_request(&test.sdk, request_b).await;
     let view_b = create_view_with_request(&test.sdk, request_b).await;
 
 
-    let query = QueryAppRequest::new(&test.app.id).read_views();
+    let query = QueryAppRequest::new(&test.app.id);
     let view_from_db = read_app(&test.sdk, query);
     let view_from_db = read_app(&test.sdk, query);
 
 
     assert_eq!(view_from_db.belongings[0], view_a);
     assert_eq!(view_from_db.belongings[0], view_a);