From 9ade419b2251e5005f4fb9ae6b5dcc39bb6d2c41 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 11 Sep 2021 20:09:46 +0800 Subject: [PATCH] create view with doc, ignore thumbnail for now --- .../workspace/application/app/app_bloc.dart | 6 +- .../application/view/doc_watch_bloc.dart | 10 ++- .../view/doc_watch_bloc.freezed.dart | 56 +++++++------- .../application/view/view_list_bloc.dart | 6 +- .../view/view_list_bloc.freezed.dart | 44 +++++------ app_flowy/lib/workspace/domain/i_doc.dart | 17 ++-- .../workspace/infrastructure/i_app_impl.dart | 18 +---- .../workspace/infrastructure/i_doc_impl.dart | 33 +++----- .../infrastructure/repos/doc_repo.dart | 41 ++++------ .../presentation/app/view_list_page.dart | 2 + .../presentation/doc/editor_page.dart | 6 +- .../presentation/home/home_screen.dart | 1 + .../flowy_infra/lib/flowy_logger.dart | 2 +- .../flowy_sdk/lib/dispatch/code_gen.dart | 60 ++++----------- backend/src/service/doc_service/router.rs | 2 +- .../user_default/user_default.rs | 26 ++++--- .../service/workspace_service/view/view.rs | 34 ++++---- backend/tests/api/helper.rs | 2 +- backend/tests/api/workspace.rs | 2 +- rust-lib/flowy-database/src/lib.rs | 2 +- rust-lib/flowy-dispatch/tests/api/helper.rs | 6 +- rust-lib/flowy-document/Flowy.toml | 2 +- .../flowy-document/src/entities/doc/doc.rs | 4 - rust-lib/flowy-document/src/errors.rs | 18 ++++- rust-lib/flowy-document/src/event.rs | 18 ----- rust-lib/flowy-document/src/lib.rs | 1 - rust-lib/flowy-document/src/module.rs | 4 +- .../src/services/doc_controller.rs | 77 +++++++++++++++---- .../flowy-document/tests/editor/doc_test.rs | 36 --------- .../flowy-document/tests/editor/helper.rs | 53 ------------- rust-lib/flowy-document/tests/editor/main.rs | 3 +- .../src/deps_resolve/editor_deps_impl.rs | 1 - .../src/deps_resolve/workspace_deps_impl.rs | 6 +- rust-lib/flowy-sdk/src/module.rs | 1 - rust-lib/flowy-test/src/builder.rs | 2 +- rust-lib/flowy-user/src/errors.rs | 7 +- .../src/services/user/user_session.rs | 12 +-- .../entities/view/parser/view_thumbnail.rs | 7 +- .../src/entities/view/view_create.rs | 2 +- rust-lib/flowy-workspace/src/module.rs | 26 ++++--- .../src/services/app_controller.rs | 9 ++- .../src/services/view_controller.rs | 13 ++-- .../src/services/workspace_controller.rs | 25 +++--- .../tests/workspace/app_test.rs | 1 - .../tests/workspace/view_test.rs | 1 - .../tests/workspace/workspace_test.rs | 2 +- 46 files changed, 295 insertions(+), 412 deletions(-) delete mode 100644 rust-lib/flowy-document/src/event.rs delete mode 100644 rust-lib/flowy-document/tests/editor/doc_test.rs delete mode 100644 rust-lib/flowy-document/tests/editor/helper.rs diff --git a/app_flowy/lib/workspace/application/app/app_bloc.dart b/app_flowy/lib/workspace/application/app/app_bloc.dart index 061b3cec5d..4c9a2298ae 100644 --- a/app_flowy/lib/workspace/application/app/app_bloc.dart +++ b/app_flowy/lib/workspace/application/app/app_bloc.dart @@ -21,8 +21,12 @@ class AppBloc extends Bloc { yield* _fetchViews(); }, createView: (CreateView value) async* { - iAppImpl.createView( + final viewOrFailed = await iAppImpl.createView( name: value.name, desc: value.desc, viewType: value.viewType); + yield viewOrFailed.fold((view) => state, (error) { + Log.error(error); + return state.copyWith(successOrFailure: right(error)); + }); }, ); } diff --git a/app_flowy/lib/workspace/application/view/doc_watch_bloc.dart b/app_flowy/lib/workspace/application/view/doc_watch_bloc.dart index dc94e73cd3..b72b41bbfd 100644 --- a/app_flowy/lib/workspace/application/view/doc_watch_bloc.dart +++ b/app_flowy/lib/workspace/application/view/doc_watch_bloc.dart @@ -1,7 +1,7 @@ +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/workspace/domain/i_doc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/errors.pb.dart'; part 'doc_watch_bloc.freezed.dart'; class DocWatchBloc extends Bloc { @@ -24,7 +24,9 @@ class DocWatchBloc extends Bloc { final docOrFail = await iDocImpl.readDoc(); yield docOrFail.fold( (doc) => DocWatchState.loadDoc(doc), - (error) => DocWatchState.loadFail(error), + (error) { + return DocWatchState.loadFail(error); + }, ); } } @@ -37,6 +39,6 @@ class DocWatchEvent with _$DocWatchEvent { @freezed class DocWatchState with _$DocWatchState { const factory DocWatchState.loading() = Loading; - const factory DocWatchState.loadDoc(Doc doc) = LoadDoc; - const factory DocWatchState.loadFail(DocError error) = LoadFail; + const factory DocWatchState.loadDoc(FlowyDoc doc) = LoadDoc; + const factory DocWatchState.loadFail(WorkspaceError error) = LoadFail; } diff --git a/app_flowy/lib/workspace/application/view/doc_watch_bloc.freezed.dart b/app_flowy/lib/workspace/application/view/doc_watch_bloc.freezed.dart index 2c79c6c2ba..d6e6dc44bc 100644 --- a/app_flowy/lib/workspace/application/view/doc_watch_bloc.freezed.dart +++ b/app_flowy/lib/workspace/application/view/doc_watch_bloc.freezed.dart @@ -154,13 +154,13 @@ class _$DocWatchStateTearOff { return const Loading(); } - LoadDoc loadDoc(Doc doc) { + LoadDoc loadDoc(FlowyDoc doc) { return LoadDoc( doc, ); } - LoadFail loadFail(DocError error) { + LoadFail loadFail(WorkspaceError error) { return LoadFail( error, ); @@ -175,15 +175,15 @@ mixin _$DocWatchState { @optionalTypeArgs TResult when({ required TResult Function() loading, - required TResult Function(Doc doc) loadDoc, - required TResult Function(DocError error) loadFail, + required TResult Function(FlowyDoc doc) loadDoc, + required TResult Function(WorkspaceError error) loadFail, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? loading, - TResult Function(Doc doc)? loadDoc, - TResult Function(DocError error)? loadFail, + TResult Function(FlowyDoc doc)? loadDoc, + TResult Function(WorkspaceError error)? loadFail, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -259,8 +259,8 @@ class _$Loading implements Loading { @optionalTypeArgs TResult when({ required TResult Function() loading, - required TResult Function(Doc doc) loadDoc, - required TResult Function(DocError error) loadFail, + required TResult Function(FlowyDoc doc) loadDoc, + required TResult Function(WorkspaceError error) loadFail, }) { return loading(); } @@ -269,8 +269,8 @@ class _$Loading implements Loading { @optionalTypeArgs TResult maybeWhen({ TResult Function()? loading, - TResult Function(Doc doc)? loadDoc, - TResult Function(DocError error)? loadFail, + TResult Function(FlowyDoc doc)? loadDoc, + TResult Function(WorkspaceError error)? loadFail, required TResult orElse(), }) { if (loading != null) { @@ -312,7 +312,7 @@ abstract class Loading implements DocWatchState { abstract class $LoadDocCopyWith<$Res> { factory $LoadDocCopyWith(LoadDoc value, $Res Function(LoadDoc) then) = _$LoadDocCopyWithImpl<$Res>; - $Res call({Doc doc}); + $Res call({FlowyDoc doc}); } /// @nodoc @@ -332,7 +332,7 @@ class _$LoadDocCopyWithImpl<$Res> extends _$DocWatchStateCopyWithImpl<$Res> doc == freezed ? _value.doc : doc // ignore: cast_nullable_to_non_nullable - as Doc, + as FlowyDoc, )); } } @@ -343,7 +343,7 @@ class _$LoadDoc implements LoadDoc { const _$LoadDoc(this.doc); @override - final Doc doc; + final FlowyDoc doc; @override String toString() { @@ -371,8 +371,8 @@ class _$LoadDoc implements LoadDoc { @optionalTypeArgs TResult when({ required TResult Function() loading, - required TResult Function(Doc doc) loadDoc, - required TResult Function(DocError error) loadFail, + required TResult Function(FlowyDoc doc) loadDoc, + required TResult Function(WorkspaceError error) loadFail, }) { return loadDoc(doc); } @@ -381,8 +381,8 @@ class _$LoadDoc implements LoadDoc { @optionalTypeArgs TResult maybeWhen({ TResult Function()? loading, - TResult Function(Doc doc)? loadDoc, - TResult Function(DocError error)? loadFail, + TResult Function(FlowyDoc doc)? loadDoc, + TResult Function(WorkspaceError error)? loadFail, required TResult orElse(), }) { if (loadDoc != null) { @@ -417,9 +417,9 @@ class _$LoadDoc implements LoadDoc { } abstract class LoadDoc implements DocWatchState { - const factory LoadDoc(Doc doc) = _$LoadDoc; + const factory LoadDoc(FlowyDoc doc) = _$LoadDoc; - Doc get doc => throw _privateConstructorUsedError; + FlowyDoc get doc => throw _privateConstructorUsedError; @JsonKey(ignore: true) $LoadDocCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -428,7 +428,7 @@ abstract class LoadDoc implements DocWatchState { abstract class $LoadFailCopyWith<$Res> { factory $LoadFailCopyWith(LoadFail value, $Res Function(LoadFail) then) = _$LoadFailCopyWithImpl<$Res>; - $Res call({DocError error}); + $Res call({WorkspaceError error}); } /// @nodoc @@ -448,7 +448,7 @@ class _$LoadFailCopyWithImpl<$Res> extends _$DocWatchStateCopyWithImpl<$Res> error == freezed ? _value.error : error // ignore: cast_nullable_to_non_nullable - as DocError, + as WorkspaceError, )); } } @@ -459,7 +459,7 @@ class _$LoadFail implements LoadFail { const _$LoadFail(this.error); @override - final DocError error; + final WorkspaceError error; @override String toString() { @@ -487,8 +487,8 @@ class _$LoadFail implements LoadFail { @optionalTypeArgs TResult when({ required TResult Function() loading, - required TResult Function(Doc doc) loadDoc, - required TResult Function(DocError error) loadFail, + required TResult Function(FlowyDoc doc) loadDoc, + required TResult Function(WorkspaceError error) loadFail, }) { return loadFail(error); } @@ -497,8 +497,8 @@ class _$LoadFail implements LoadFail { @optionalTypeArgs TResult maybeWhen({ TResult Function()? loading, - TResult Function(Doc doc)? loadDoc, - TResult Function(DocError error)? loadFail, + TResult Function(FlowyDoc doc)? loadDoc, + TResult Function(WorkspaceError error)? loadFail, required TResult orElse(), }) { if (loadFail != null) { @@ -533,9 +533,9 @@ class _$LoadFail implements LoadFail { } abstract class LoadFail implements DocWatchState { - const factory LoadFail(DocError error) = _$LoadFail; + const factory LoadFail(WorkspaceError error) = _$LoadFail; - DocError get error => throw _privateConstructorUsedError; + WorkspaceError get error => throw _privateConstructorUsedError; @JsonKey(ignore: true) $LoadFailCopyWith get copyWith => throw _privateConstructorUsedError; diff --git a/app_flowy/lib/workspace/application/view/view_list_bloc.dart b/app_flowy/lib/workspace/application/view/view_list_bloc.dart index 7602dbfe02..315d49d560 100644 --- a/app_flowy/lib/workspace/application/view/view_list_bloc.dart +++ b/app_flowy/lib/workspace/application/view/view_list_bloc.dart @@ -16,7 +16,7 @@ class ViewListBloc extends Bloc { yield ViewListState.initial(s.views); }, openView: (s) async* { - yield state.copyWith(selectedView: some(s.view.id)); + yield state.copyWith(openedView: some(s.view.id)); }, ); } @@ -32,13 +32,13 @@ class ViewListEvent with _$ViewListEvent { abstract class ViewListState implements _$ViewListState { const factory ViewListState({ required bool isLoading, - required Option selectedView, + required Option openedView, required Option> views, }) = _ViewListState; factory ViewListState.initial(List views) => ViewListState( isLoading: false, - selectedView: none(), + openedView: none(), views: some(views), ); } diff --git a/app_flowy/lib/workspace/application/view/view_list_bloc.freezed.dart b/app_flowy/lib/workspace/application/view/view_list_bloc.freezed.dart index e866b9b4e5..ca53f3266b 100644 --- a/app_flowy/lib/workspace/application/view/view_list_bloc.freezed.dart +++ b/app_flowy/lib/workspace/application/view/view_list_bloc.freezed.dart @@ -310,11 +310,11 @@ class _$ViewListStateTearOff { _ViewListState call( {required bool isLoading, - required Option selectedView, + required Option openedView, required Option> views}) { return _ViewListState( isLoading: isLoading, - selectedView: selectedView, + openedView: openedView, views: views, ); } @@ -326,7 +326,7 @@ const $ViewListState = _$ViewListStateTearOff(); /// @nodoc mixin _$ViewListState { bool get isLoading => throw _privateConstructorUsedError; - Option get selectedView => throw _privateConstructorUsedError; + Option get openedView => throw _privateConstructorUsedError; Option> get views => throw _privateConstructorUsedError; @JsonKey(ignore: true) @@ -340,7 +340,7 @@ abstract class $ViewListStateCopyWith<$Res> { ViewListState value, $Res Function(ViewListState) then) = _$ViewListStateCopyWithImpl<$Res>; $Res call( - {bool isLoading, Option selectedView, Option> views}); + {bool isLoading, Option openedView, Option> views}); } /// @nodoc @@ -355,7 +355,7 @@ class _$ViewListStateCopyWithImpl<$Res> @override $Res call({ Object? isLoading = freezed, - Object? selectedView = freezed, + Object? openedView = freezed, Object? views = freezed, }) { return _then(_value.copyWith( @@ -363,9 +363,9 @@ class _$ViewListStateCopyWithImpl<$Res> ? _value.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool, - selectedView: selectedView == freezed - ? _value.selectedView - : selectedView // ignore: cast_nullable_to_non_nullable + openedView: openedView == freezed + ? _value.openedView + : openedView // ignore: cast_nullable_to_non_nullable as Option, views: views == freezed ? _value.views @@ -383,7 +383,7 @@ abstract class _$ViewListStateCopyWith<$Res> __$ViewListStateCopyWithImpl<$Res>; @override $Res call( - {bool isLoading, Option selectedView, Option> views}); + {bool isLoading, Option openedView, Option> views}); } /// @nodoc @@ -400,7 +400,7 @@ class __$ViewListStateCopyWithImpl<$Res> @override $Res call({ Object? isLoading = freezed, - Object? selectedView = freezed, + Object? openedView = freezed, Object? views = freezed, }) { return _then(_ViewListState( @@ -408,9 +408,9 @@ class __$ViewListStateCopyWithImpl<$Res> ? _value.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool, - selectedView: selectedView == freezed - ? _value.selectedView - : selectedView // ignore: cast_nullable_to_non_nullable + openedView: openedView == freezed + ? _value.openedView + : openedView // ignore: cast_nullable_to_non_nullable as Option, views: views == freezed ? _value.views @@ -424,20 +424,18 @@ class __$ViewListStateCopyWithImpl<$Res> class _$_ViewListState implements _ViewListState { const _$_ViewListState( - {required this.isLoading, - required this.selectedView, - required this.views}); + {required this.isLoading, required this.openedView, required this.views}); @override final bool isLoading; @override - final Option selectedView; + final Option openedView; @override final Option> views; @override String toString() { - return 'ViewListState(isLoading: $isLoading, selectedView: $selectedView, views: $views)'; + return 'ViewListState(isLoading: $isLoading, openedView: $openedView, views: $views)'; } @override @@ -447,9 +445,9 @@ class _$_ViewListState implements _ViewListState { (identical(other.isLoading, isLoading) || const DeepCollectionEquality() .equals(other.isLoading, isLoading)) && - (identical(other.selectedView, selectedView) || + (identical(other.openedView, openedView) || const DeepCollectionEquality() - .equals(other.selectedView, selectedView)) && + .equals(other.openedView, openedView)) && (identical(other.views, views) || const DeepCollectionEquality().equals(other.views, views))); } @@ -458,7 +456,7 @@ class _$_ViewListState implements _ViewListState { int get hashCode => runtimeType.hashCode ^ const DeepCollectionEquality().hash(isLoading) ^ - const DeepCollectionEquality().hash(selectedView) ^ + const DeepCollectionEquality().hash(openedView) ^ const DeepCollectionEquality().hash(views); @JsonKey(ignore: true) @@ -470,13 +468,13 @@ class _$_ViewListState implements _ViewListState { abstract class _ViewListState implements ViewListState { const factory _ViewListState( {required bool isLoading, - required Option selectedView, + required Option openedView, required Option> views}) = _$_ViewListState; @override bool get isLoading => throw _privateConstructorUsedError; @override - Option get selectedView => throw _privateConstructorUsedError; + Option get openedView => throw _privateConstructorUsedError; @override Option> get views => throw _privateConstructorUsedError; @override diff --git a/app_flowy/lib/workspace/domain/i_doc.dart b/app_flowy/lib/workspace/domain/i_doc.dart index a7761978de..8f762d26a9 100644 --- a/app_flowy/lib/workspace/domain/i_doc.dart +++ b/app_flowy/lib/workspace/domain/i_doc.dart @@ -1,18 +1,17 @@ import 'package:flowy_editor/flowy_editor.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/doc_create.pb.dart'; import 'package:dartz/dartz.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-document/doc.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; -class Doc { - final DocInfo info; +class FlowyDoc { + final Doc doc; final Document data; - Doc({required this.info, required this.data}); + FlowyDoc({required this.doc, required this.data}); } abstract class IDoc { - Future> readDoc(); - Future> updateDoc( - {String? name, String? desc, String? text}); - Future> closeDoc(); + Future> readDoc(); + Future> updateDoc({String? text}); + Future> closeDoc(); } diff --git a/app_flowy/lib/workspace/infrastructure/i_app_impl.dart b/app_flowy/lib/workspace/infrastructure/i_app_impl.dart index 0e46d2b9ee..97c0f63f63 100644 --- a/app_flowy/lib/workspace/infrastructure/i_app_impl.dart +++ b/app_flowy/lib/workspace/infrastructure/i_app_impl.dart @@ -1,5 +1,4 @@ import 'package:app_flowy/workspace/infrastructure/repos/app_repo.dart'; -import 'package:app_flowy/workspace/infrastructure/repos/doc_repo.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart' as workspace; import 'package:app_flowy/workspace/domain/i_app.dart'; @@ -22,26 +21,11 @@ class IAppImpl extends IApp { {required String name, String? desc, required ViewType viewType}) { return repo.createView(name, desc ?? "", viewType).then((result) { return result.fold( - (view) => _createDoc(view), + (view) => left(view), (r) => right(r), ); }); } - - Future> _createDoc(View view) async { - switch (view.viewType) { - case ViewType.Doc: - final docRepo = DocRepository(docId: view.id); - final result = await docRepo.createDoc( - name: view.name, desc: "", text: "[{\"insert\":\"\\n\"}]"); - return result.fold((l) => left(view), (r) { - return right(workspace.WorkspaceError( - code: workspace.ErrorCode.Unknown, msg: r.msg)); - }); - default: - return left(view); - } - } } class IAppWatchImpl extends IAppWatch { diff --git a/app_flowy/lib/workspace/infrastructure/i_doc_impl.dart b/app_flowy/lib/workspace/infrastructure/i_doc_impl.dart index d941ba8bd0..2062e81ba8 100644 --- a/app_flowy/lib/workspace/infrastructure/i_doc_impl.dart +++ b/app_flowy/lib/workspace/infrastructure/i_doc_impl.dart @@ -2,10 +2,9 @@ import 'dart:convert'; import 'package:dartz/dartz.dart'; import 'package:flowy_editor/flowy_editor.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/errors.pb.dart'; - import 'package:app_flowy/workspace/domain/i_doc.dart'; import 'package:app_flowy/workspace/infrastructure/repos/doc_repo.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; class IDocImpl extends IDoc { DocRepository repo; @@ -13,35 +12,23 @@ class IDocImpl extends IDoc { IDocImpl({required this.repo}); @override - Future> closeDoc() { + Future> closeDoc() { return repo.closeDoc(); } @override - Future> readDoc() async { - final docInfoOrFail = await repo.readDoc(); - return docInfoOrFail.fold( - (info) => _loadDocument(info.path).then((result) => result.fold( - (document) => left(Doc(info: info, data: document)), - (error) => right(error))), - (error) => right(error), - ); + Future> readDoc() async { + final docOrFail = await repo.readDoc(); + + return docOrFail.fold((doc) { + return left(FlowyDoc(doc: doc, data: _decodeToDocument(doc.data))); + }, (error) => right(error)); } @override - Future> updateDoc( - {String? name, String? desc, String? text}) { + Future> updateDoc({String? text}) { final json = jsonEncode(text ?? ""); - return repo.updateDoc(name: name, desc: desc, text: json); - } - - Future> _loadDocument(String path) { - return repo.readDocData(path).then((docDataOrFail) { - return docDataOrFail.fold( - (docData) => left(_decodeToDocument(docData.text)), - (error) => right(error), - ); - }); + return repo.updateDoc(text: json); } Document _decodeToDocument(String text) { diff --git a/app_flowy/lib/workspace/infrastructure/repos/doc_repo.dart b/app_flowy/lib/workspace/infrastructure/repos/doc_repo.dart index 1834ee959a..3d646d41b1 100644 --- a/app_flowy/lib/workspace/infrastructure/repos/doc_repo.dart +++ b/app_flowy/lib/workspace/infrastructure/repos/doc_repo.dart @@ -1,9 +1,9 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/doc_create.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/doc_modify.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/doc_query.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-document/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-document/doc.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/view_query.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-workspace/view_update.pb.dart'; class DocRepository { final String docId; @@ -11,34 +11,19 @@ class DocRepository { required this.docId, }); - Future> createDoc( - {required String name, String? desc, String? text}) { - final request = - CreateDocRequest(id: docId, name: name, desc: desc, text: text); - - return EditorEventCreateDoc(request).send(); + Future> readDoc() { + final request = OpenViewRequest.create()..viewId = docId; + return WorkspaceEventOpenView(request).send(); } - Future> readDoc() { - final request = QueryDocRequest.create()..docId = docId; - return EditorEventReadDocInfo(request).send(); + Future> updateDoc({String? text}) { + final request = UpdateViewDataRequest.create() + ..viewId = docId + ..data = text ?? ""; + return WorkspaceEventUpdateViewData(request).send(); } - Future> readDocData(String path) { - final request = QueryDocDataRequest.create() - ..docId = docId - ..path = path; - return EditorEventReadDocData(request).send(); - } - - Future> updateDoc( - {String? name, String? desc, String? text}) { - final request = UpdateDocRequest(id: docId, name: name, text: text); - - return EditorEventUpdateDoc(request).send(); - } - - Future> closeDoc( + Future> closeDoc( {String? name, String? desc, String? text}) { throw UnimplementedError(); } diff --git a/app_flowy/lib/workspace/presentation/app/view_list_page.dart b/app_flowy/lib/workspace/presentation/app/view_list_page.dart index 3cff97b2e5..758c1fb5e9 100644 --- a/app_flowy/lib/workspace/presentation/app/view_list_page.dart +++ b/app_flowy/lib/workspace/presentation/app/view_list_page.dart @@ -1,4 +1,5 @@ import 'package:app_flowy/workspace/presentation/app/app_page.dart'; +import 'package:flowy_infra/flowy_logger.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -58,6 +59,7 @@ class ViewListPage extends StatelessWidget { viewCtx: viewCtx, isSelected: _isViewSelected(context, view.id), onOpen: (view) { + Log.debug("Open view: $view"); context.read().setSelectedView(view); final stackView = stackViewFromView(viewCtx.view); getIt().setStackView(stackView); diff --git a/app_flowy/lib/workspace/presentation/doc/editor_page.dart b/app_flowy/lib/workspace/presentation/doc/editor_page.dart index 3849995518..366771dc50 100644 --- a/app_flowy/lib/workspace/presentation/doc/editor_page.dart +++ b/app_flowy/lib/workspace/presentation/doc/editor_page.dart @@ -11,20 +11,20 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class EditorPage extends StatelessWidget { final FocusNode _focusNode = FocusNode(); late EditorController controller; - final Doc doc; + final FlowyDoc doc; EditorPage({Key? key, required this.doc}) : super(key: key) { controller = EditorController( document: doc.data, selection: const TextSelection.collapsed(offset: 0), - persistence: getIt(param1: doc.info.id), + persistence: getIt(param1: doc.doc.id), ); } @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => getIt(param1: doc.info.id), + create: (context) => getIt(param1: doc.doc.id), child: BlocBuilder( builder: (ctx, state) { return Column( diff --git a/app_flowy/lib/workspace/presentation/home/home_screen.dart b/app_flowy/lib/workspace/presentation/home/home_screen.dart index 688e89a0eb..94ab9b9c87 100644 --- a/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -36,6 +36,7 @@ class HomeScreen extends StatelessWidget { loading: (_) {}, unauthorized: (unauthorized) { // TODO: push to login screen when user token was invalid + Log.error("Push to login screen when user token was invalid"); }, ); }, diff --git a/app_flowy/packages/flowy_infra/lib/flowy_logger.dart b/app_flowy/packages/flowy_infra/lib/flowy_logger.dart index de4e3a7238..177a8fb197 100644 --- a/app_flowy/packages/flowy_infra/lib/flowy_logger.dart +++ b/app_flowy/packages/flowy_infra/lib/flowy_logger.dart @@ -8,7 +8,7 @@ class Log { Log() { _logger = Logger( printer: PrettyPrinter( - methodCount: 0, // number of method calls to be displayed + methodCount: 2, // number of method calls to be displayed errorMethodCount: 8, // number of method calls if stacktrace is provided lineLength: 120, // width of the output diff --git a/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart b/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart index 9b7a490c04..6bcfae5afd 100644 --- a/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart +++ b/app_flowy/packages/flowy_sdk/lib/dispatch/code_gen.dart @@ -237,70 +237,36 @@ class WorkspaceEventDeleteView { } } -class EditorEventCreateDoc { - CreateDocRequest request; - EditorEventCreateDoc(this.request); +class WorkspaceEventOpenView { + OpenViewRequest request; + WorkspaceEventOpenView(this.request); - Future> send() { + Future> send() { final request = FFIRequest.create() - ..event = EditorEvent.CreateDoc.toString() + ..event = WorkspaceEvent.OpenView.toString() ..payload = requestToBytes(this.request); return Dispatch.asyncRequest(request) .then((bytesResult) => bytesResult.fold( - (okBytes) => left(DocInfo.fromBuffer(okBytes)), - (errBytes) => right(DocError.fromBuffer(errBytes)), + (okBytes) => left(Doc.fromBuffer(okBytes)), + (errBytes) => right(WorkspaceError.fromBuffer(errBytes)), )); } } -class EditorEventUpdateDoc { - UpdateDocRequest request; - EditorEventUpdateDoc(this.request); +class WorkspaceEventUpdateViewData { + UpdateViewDataRequest request; + WorkspaceEventUpdateViewData(this.request); - Future> send() { + Future> send() { final request = FFIRequest.create() - ..event = EditorEvent.UpdateDoc.toString() + ..event = WorkspaceEvent.UpdateViewData.toString() ..payload = requestToBytes(this.request); return Dispatch.asyncRequest(request) .then((bytesResult) => bytesResult.fold( (bytes) => left(unit), - (errBytes) => right(DocError.fromBuffer(errBytes)), - )); - } -} - -class EditorEventReadDocInfo { - QueryDocRequest request; - EditorEventReadDocInfo(this.request); - - Future> send() { - final request = FFIRequest.create() - ..event = EditorEvent.ReadDocInfo.toString() - ..payload = requestToBytes(this.request); - - return Dispatch.asyncRequest(request) - .then((bytesResult) => bytesResult.fold( - (okBytes) => left(DocInfo.fromBuffer(okBytes)), - (errBytes) => right(DocError.fromBuffer(errBytes)), - )); - } -} - -class EditorEventReadDocData { - QueryDocDataRequest request; - EditorEventReadDocData(this.request); - - Future> send() { - final request = FFIRequest.create() - ..event = EditorEvent.ReadDocData.toString() - ..payload = requestToBytes(this.request); - - return Dispatch.asyncRequest(request) - .then((bytesResult) => bytesResult.fold( - (okBytes) => left(DocData.fromBuffer(okBytes)), - (errBytes) => right(DocError.fromBuffer(errBytes)), + (errBytes) => right(WorkspaceError.fromBuffer(errBytes)), )); } } diff --git a/backend/src/service/doc_service/router.rs b/backend/src/service/doc_service/router.rs index 28bd924b0d..59bd129c17 100644 --- a/backend/src/service/doc_service/router.rs +++ b/backend/src/service/doc_service/router.rs @@ -4,7 +4,7 @@ use actix_web::{ }; use sqlx::PgPool; -use flowy_document::protobuf::{CreateDocParams, QueryDocParams, UpdateDocParams}; +use flowy_document::protobuf::{QueryDocParams, UpdateDocParams}; use flowy_net::errors::ServerError; use crate::service::{ diff --git a/backend/src/service/workspace_service/user_default/user_default.rs b/backend/src/service/workspace_service/user_default/user_default.rs index 214c5a3747..7d7050bdd8 100644 --- a/backend/src/service/workspace_service/user_default/user_default.rs +++ b/backend/src/service/workspace_service/user_default/user_default.rs @@ -1,10 +1,10 @@ use flowy_net::errors::ServerError; -use flowy_workspace::protobuf::{App, View, ViewType, Workspace}; +use flowy_workspace::protobuf::{App, CreateViewParams, View, ViewType, Workspace}; use crate::{ service::workspace_service::{ app::sql_builder::NewAppSqlBuilder as AppBuilder, - view::sql_builder::NewViewSqlBuilder as ViewBuilder, + view::{create_view_with_transaction, sql_builder::NewViewSqlBuilder as ViewBuilder}, workspace::sql_builder::NewWorkspaceBuilder as WorkspaceBuilder, }, sqlx_ext::{map_sqlx_error, DBTransaction}, @@ -57,16 +57,18 @@ async fn create_app( } async fn create_view(transaction: &mut DBTransaction<'_>, app: &App) -> Result { - let (sql, args, view) = ViewBuilder::new(&app.id) - .name("DefaultView") - .desc("View created by AppFlowy") - .thumbnail("https://view.png") - .view_type(ViewType::Doc) - .build()?; + let params = CreateViewParams { + belong_to_id: app.id.clone(), + name: "DefaultView".to_string(), + desc: "View created by AppFlowy".to_string(), + thumbnail: "123.png".to_string(), + view_type: ViewType::Doc, + data: "[{\"insert\":\"\\n\"}]".to_string(), + unknown_fields: Default::default(), + cached_size: Default::default(), + }; + + let view = create_view_with_transaction(transaction, params).await?; - let _ = sqlx::query_with(&sql, args) - .execute(transaction) - .await - .map_err(map_sqlx_error)?; Ok(view) } diff --git a/backend/src/service/workspace_service/view/view.rs b/backend/src/service/workspace_service/view/view.rs index 1449710507..cd5dda8c25 100644 --- a/backend/src/service/workspace_service/view/view.rs +++ b/backend/src/service/workspace_service/view/view.rs @@ -28,15 +28,27 @@ pub(crate) async fn create_view( pool: &PgPool, params: CreateViewParams, ) -> Result { - let name = ViewName::parse(params.name).map_err(invalid_params)?; - let belong_to_id = AppId::parse(params.belong_to_id).map_err(invalid_params)?; - let thumbnail = ViewThumbnail::parse(params.thumbnail).map_err(invalid_params)?; - let desc = ViewDesc::parse(params.desc).map_err(invalid_params)?; - 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() + .await + .context("Failed to commit SQL transaction to create view.")?; + + FlowyResponse::success().pb(view) +} + +pub(crate) async fn create_view_with_transaction( + transaction: &mut DBTransaction<'_>, + params: CreateViewParams, +) -> Result { + let name = ViewName::parse(params.name).map_err(invalid_params)?; + let belong_to_id = AppId::parse(params.belong_to_id).map_err(invalid_params)?; + let thumbnail = ViewThumbnail::parse(params.thumbnail).map_err(invalid_params)?; + let desc = ViewDesc::parse(params.desc).map_err(invalid_params)?; let (sql, args, view) = NewViewSqlBuilder::new(belong_to_id.as_ref()) .name(name.as_ref()) @@ -46,21 +58,15 @@ pub(crate) async fn create_view( .build()?; let _ = sqlx::query_with(&sql, args) - .execute(&mut transaction) + .execute(transaction as &mut DBTransaction<'_>) .await .map_err(map_sqlx_error)?; let mut create_doc_params = CreateDocParams::new(); create_doc_params.set_data(params.data); create_doc_params.set_id(view.id.clone()); - let _ = create_doc(&mut transaction, create_doc_params).await?; - - transaction - .commit() - .await - .context("Failed to commit SQL transaction to create view.")?; - - FlowyResponse::success().pb(view) + let _ = create_doc(transaction, create_doc_params).await?; + Ok(view) } pub(crate) async fn read_view( diff --git a/backend/tests/api/helper.rs b/backend/tests/api/helper.rs index 6897685bd7..e32fff4d14 100644 --- a/backend/tests/api/helper.rs +++ b/backend/tests/api/helper.rs @@ -4,7 +4,7 @@ use backend::{ }; use flowy_document::{ - entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams}, + entities::doc::{Doc, QueryDocParams, UpdateDocParams}, prelude::*, }; use flowy_user::{errors::UserError, prelude::*}; diff --git a/backend/tests/api/workspace.rs b/backend/tests/api/workspace.rs index 3ab4ef32d2..cc2971a0ef 100644 --- a/backend/tests/api/workspace.rs +++ b/backend/tests/api/workspace.rs @@ -1,7 +1,7 @@ use crate::helper::*; use flowy_workspace::entities::{ app::{DeleteAppParams, QueryAppParams, UpdateAppParams}, - view::{CreateViewParams, DeleteViewParams, QueryViewParams, UpdateViewParams, View, ViewType}, + view::{DeleteViewParams, QueryViewParams, UpdateViewParams}, workspace::{ CreateWorkspaceParams, DeleteWorkspaceParams, diff --git a/rust-lib/flowy-database/src/lib.rs b/rust-lib/flowy-database/src/lib.rs index d0467df862..d645ecebc0 100644 --- a/rust-lib/flowy-database/src/lib.rs +++ b/rust-lib/flowy-database/src/lib.rs @@ -14,7 +14,7 @@ pub use diesel_derives::*; #[macro_use] extern crate diesel_migrations; -pub use flowy_sqlite::{DBConnection, Database}; +pub use flowy_sqlite::{ConnectionPool, DBConnection, Database}; pub type Error = diesel::result::Error; use diesel_migrations::*; diff --git a/rust-lib/flowy-dispatch/tests/api/helper.rs b/rust-lib/flowy-dispatch/tests/api/helper.rs index c2a8127550..f6a8110fba 100644 --- a/rust-lib/flowy-dispatch/tests/api/helper.rs +++ b/rust-lib/flowy-dispatch/tests/api/helper.rs @@ -4,10 +4,8 @@ use std::sync::Once; #[allow(dead_code)] pub fn setup_env() { static INIT: Once = Once::new(); - INIT.call_once(|| { - std::env::set_var("RUST_LOG", "flowy_dispatch=debug,debug"); - env_logger::init(); - }); + std::env::); + INIT.call_once(|| env_logger::init()); } pub fn init_dispatch(module_factory: F) -> EventDispatch diff --git a/rust-lib/flowy-document/Flowy.toml b/rust-lib/flowy-document/Flowy.toml index f66326779a..d0e50ebb1d 100644 --- a/rust-lib/flowy-document/Flowy.toml +++ b/rust-lib/flowy-document/Flowy.toml @@ -1,3 +1,3 @@ proto_crates = ["src/entities", "src/event.rs", "src/errors.rs", "src/observable"] -event_files = ["src/event.rs"] \ No newline at end of file +event_files = [] \ No newline at end of file diff --git a/rust-lib/flowy-document/src/entities/doc/doc.rs b/rust-lib/flowy-document/src/entities/doc/doc.rs index a90d4772e5..213985cefd 100644 --- a/rust-lib/flowy-document/src/entities/doc/doc.rs +++ b/rust-lib/flowy-document/src/entities/doc/doc.rs @@ -1,7 +1,3 @@ -use crate::{ - entities::doc::parser::*, - errors::{ErrorBuilder, *}, -}; use flowy_derive::ProtoBuf; use std::convert::TryInto; diff --git a/rust-lib/flowy-document/src/errors.rs b/rust-lib/flowy-document/src/errors.rs index 68f25b2ffd..db4102b9bb 100644 --- a/rust-lib/flowy-document/src/errors.rs +++ b/rust-lib/flowy-document/src/errors.rs @@ -17,6 +17,8 @@ pub struct DocError { impl DocError { fn new(code: ErrorCode, msg: &str) -> Self { Self { code, msg: msg.to_owned() } } + + pub fn is_record_not_found(&self) -> bool { self.code == ErrorCode::DocNotfound } } #[derive(Debug, Clone, ProtoBuf_Enum, Display, PartialEq, Eq)] @@ -39,13 +41,26 @@ impl std::default::Default for ErrorCode { } impl std::convert::From for DocError { - fn from(error: flowy_database::Error) -> Self { ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } + fn from(error: flowy_database::Error) -> Self { + match error { + flowy_database::Error::NotFound => ErrorBuilder::new(ErrorCode::DocNotfound).error(error).build(), + _ => ErrorBuilder::new(ErrorCode::InternalError).error(error).build(), + } + } } +// impl std::convert::From<::r2d2::Error> for DocError { +// fn from(error: r2d2::Error) -> Self { +// ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } } + impl std::convert::From for DocError { fn from(error: FileError) -> Self { ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } } +// impl std::convert::From for DocError { +// fn from(error: flowy_sqlite::Error) -> Self { +// ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } } + impl std::convert::From for DocError { fn from(error: ServerError) -> Self { let code = server_error_to_doc_error(error.code); @@ -54,6 +69,7 @@ impl std::convert::From for DocError { } use flowy_net::errors::ErrorCode as ServerErrorCode; + fn server_error_to_doc_error(code: ServerErrorCode) -> ErrorCode { match code { ServerErrorCode::UserUnauthorized => ErrorCode::UserUnauthorized, diff --git a/rust-lib/flowy-document/src/event.rs b/rust-lib/flowy-document/src/event.rs deleted file mode 100644 index eafec08fff..0000000000 --- a/rust-lib/flowy-document/src/event.rs +++ /dev/null @@ -1,18 +0,0 @@ -use flowy_derive::{Flowy_Event, ProtoBuf_Enum}; -use strum_macros::Display; - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] -#[event_err = "DocError"] -pub enum EditorEvent { - #[event(input = "CreateDocRequest")] - CreateDoc = 0, - - #[event(input = "UpdateDocRequest")] - UpdateDoc = 1, - - #[event(input = "QueryDocRequest", output = "Doc")] - ReadDoc = 2, - - #[event(input = "QueryDocRequest")] - DeleteDoc = 3, -} diff --git a/rust-lib/flowy-document/src/lib.rs b/rust-lib/flowy-document/src/lib.rs index d9610a4e74..58ec6b8fb1 100644 --- a/rust-lib/flowy-document/src/lib.rs +++ b/rust-lib/flowy-document/src/lib.rs @@ -1,6 +1,5 @@ pub mod entities; pub mod errors; -pub mod event; pub mod module; mod observable; pub mod protobuf; diff --git a/rust-lib/flowy-document/src/module.rs b/rust-lib/flowy-document/src/module.rs index d83b9ef769..18759c07ad 100644 --- a/rust-lib/flowy-document/src/module.rs +++ b/rust-lib/flowy-document/src/module.rs @@ -1,10 +1,8 @@ use crate::{ errors::DocError, - event::EditorEvent, services::{doc_controller::DocController, file_manager::FileManager, server::construct_doc_server}, }; -use flowy_database::DBConnection; -use flowy_dispatch::prelude::*; + use std::sync::Arc; use tokio::sync::RwLock; diff --git a/rust-lib/flowy-document/src/services/doc_controller.rs b/rust-lib/flowy-document/src/services/doc_controller.rs index aa005662b6..9d77ac282e 100644 --- a/rust-lib/flowy-document/src/services/doc_controller.rs +++ b/rust-lib/flowy-document/src/services/doc_controller.rs @@ -1,12 +1,14 @@ use crate::{ entities::doc::{CreateDocParams, Doc, QueryDocParams, UpdateDocParams}, - errors::DocError, + errors::{DocError, ErrorBuilder, ErrorCode}, module::DocumentUser, services::server::Server, sql_tables::doc::{DocTable, DocTableChangeset, DocTableSql}, }; -use flowy_database::SqliteConnection; +use flowy_database::{ConnectionPool, SqliteConnection}; + use std::sync::Arc; +use tokio::task::JoinHandle; pub struct DocController { server: Server, @@ -39,11 +41,12 @@ impl DocController { Ok(()) } - #[tracing::instrument(level = "debug", skip(self, conn), err)] - pub fn open(&self, params: QueryDocParams, conn: &SqliteConnection) -> Result { - let doc: Doc = self.sql.read_doc_table(¶ms.doc_id, conn)?.into(); - let _ = self.read_doc_on_server(params)?; - Ok(doc) + #[tracing::instrument(level = "debug", skip(self, pool), err)] + pub async fn open(&self, params: QueryDocParams, pool: Arc) -> Result { + match self._open(params.clone(), pool.clone()) { + Ok(doc_table) => Ok(doc_table.into()), + Err(error) => self.try_read_on_server(params, pool.clone(), error).await, + } } #[tracing::instrument(level = "debug", skip(self, conn), err)] @@ -71,19 +74,36 @@ impl DocController { Ok(()) } - #[tracing::instrument(level = "debug", skip(self), err)] - fn read_doc_on_server(&self, params: QueryDocParams) -> Result<(), DocError> { + #[tracing::instrument(level = "debug", skip(self, pool), err)] + fn read_doc_from_server( + &self, + params: QueryDocParams, + pool: Arc, + ) -> Result>, DocError> { let token = self.user.token()?; let server = self.server.clone(); - tokio::spawn(async move { - // Opti: handle the error and retry? - let _doc = server.read_doc(&token, params).await?; - // save to disk - // notify + let sql = self.sql.clone(); - Result::<(), DocError>::Ok(()) - }); - Ok(()) + Ok(tokio::spawn(async move { + match server.read_doc(&token, params).await? { + None => Err(ErrorBuilder::new(ErrorCode::DocNotfound).build()), + Some(doc) => { + let doc_table = DocTable::new(doc.clone()); + let _ = sql.create_doc_table(doc_table, &*(pool.get().unwrap()))?; + // TODO: notify + Ok(doc) + }, + } + })) + } + + #[tracing::instrument(level = "debug", skip(self), err)] + async fn sync_read_doc_from_server(&self, params: QueryDocParams) -> Result { + let token = self.user.token()?; + match self.server.read_doc(&token, params).await? { + None => Err(ErrorBuilder::new(ErrorCode::DocNotfound).build()), + Some(doc) => Ok(doc), + } } #[tracing::instrument(level = "debug", skip(self), err)] @@ -101,4 +121,27 @@ impl DocController { }); Ok(()) } + + fn _open(&self, params: QueryDocParams, pool: Arc) -> Result { + let doc_table = self.sql.read_doc_table(¶ms.doc_id, &*(pool.get().unwrap()))?; + let doc: Doc = doc_table.into(); + let _ = self.read_doc_from_server(params, pool.clone())?; + Ok(doc) + } + + async fn try_read_on_server(&self, params: QueryDocParams, pool: Arc, error: DocError) -> Result { + if error.is_record_not_found() { + log::debug!("Doc:{} don't exist, reading from server", params.doc_id); + self.read_doc_from_server(params, pool)?.await.map_err(internal_error)? + } else { + Err(error) + } + } +} + +fn internal_error(e: T) -> DocError +where + T: std::fmt::Debug, +{ + ErrorBuilder::new(ErrorCode::InternalError).error(e).build() } diff --git a/rust-lib/flowy-document/tests/editor/doc_test.rs b/rust-lib/flowy-document/tests/editor/doc_test.rs deleted file mode 100644 index 5dff27dc84..0000000000 --- a/rust-lib/flowy-document/tests/editor/doc_test.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::helper::*; -use flowy_test::FlowyEnv; - -#[test] -fn doc_create_test() { - let sdk = FlowyEnv::setup().sdk; - let doc = create_doc(&sdk, "flutter ❤️ rust"); - dbg!(&doc); - - let doc = read_doc_data(&sdk, &doc.id); - assert_eq!(doc.data, "flutter ❤️ rust".to_owned()); -} - -#[test] -fn doc_update_test() { - let sdk = FlowyEnv::setup().sdk; - let doc_desc = create_doc(&sdk, "flutter ❤️ rust"); - dbg!(&doc_desc); - - let content = "😁😁😁😁😁😁😁😁😁😁".to_owned(); - save_doc(&sdk, &doc_desc, &content); - - let doc = read_doc_data(&sdk, &doc_desc.id); - assert_eq!(doc.data, content); -} - -#[test] -fn doc_update_big_data_test() { - let sdk = FlowyEnv::setup().sdk; - let doc_desc = create_doc(&sdk, ""); - let content = "flutter ❤️ rust".repeat(1000000); - save_doc(&sdk, &doc_desc, &content); - - let doc = read_doc_data(&sdk, &doc_desc.id); - assert_eq!(doc.data, content); -} diff --git a/rust-lib/flowy-document/tests/editor/helper.rs b/rust-lib/flowy-document/tests/editor/helper.rs deleted file mode 100644 index 92b4bbd158..0000000000 --- a/rust-lib/flowy-document/tests/editor/helper.rs +++ /dev/null @@ -1,53 +0,0 @@ -use flowy_test::builder::DocTest; - -use flowy_document::{entities::doc::*, event::EditorEvent::*}; -use flowy_infra::uuid; -use flowy_test::prelude::*; - -pub fn create_doc(sdk: &FlowyTestSDK, text: &str) -> Doc { - let request = CreateDocRequest { - id: uuid(), - data: text.to_owned(), - }; - - let doc = DocTest::new(sdk.clone()) - .event(CreateDoc) - .request(request) - .sync_send() - .parse::(); - doc -} - -pub fn save_doc(sdk: &FlowyTestSDK, doc: &Doc, content: &str) { - let request = UpdateDocRequest { - id: doc.id.clone(), - data: Some(content.to_owned()), - }; - - let _ = DocTest::new(sdk.clone()).event(UpdateDoc).request(request).sync_send(); -} - -// #[allow(dead_code)] -// pub fn read_doc(doc_id: &str) -> DocInfo { -// let request = QueryDocRequest { -// doc_id: doc_id.to_string(), -// }; -// -// let doc = AnnieTestBuilder::new() -// .event(ReadDocInfo) -// .request(request) -// .sync_send() -// .parse::(); -// -// doc -// } - -pub(crate) fn read_doc_data(sdk: &FlowyTestSDK, doc_id: &str) -> Doc { - let request = QueryDocRequest { - doc_id: doc_id.to_string(), - }; - - let doc = DocTest::new(sdk.clone()).event(ReadDoc).request(request).sync_send().parse::(); - - doc -} diff --git a/rust-lib/flowy-document/tests/editor/main.rs b/rust-lib/flowy-document/tests/editor/main.rs index 7da3b8e032..8b13789179 100644 --- a/rust-lib/flowy-document/tests/editor/main.rs +++ b/rust-lib/flowy-document/tests/editor/main.rs @@ -1,2 +1 @@ -// mod doc_test; -// mod helper; + diff --git a/rust-lib/flowy-sdk/src/deps_resolve/editor_deps_impl.rs b/rust-lib/flowy-sdk/src/deps_resolve/editor_deps_impl.rs index 611c17affb..fc988a9bd6 100644 --- a/rust-lib/flowy-sdk/src/deps_resolve/editor_deps_impl.rs +++ b/rust-lib/flowy-sdk/src/deps_resolve/editor_deps_impl.rs @@ -1,4 +1,3 @@ -use flowy_database::DBConnection; use flowy_document::{ errors::{DocError, ErrorBuilder, ErrorCode}, module::DocumentUser, diff --git a/rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs b/rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs index 02f536869e..8282a85fe0 100644 --- a/rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs +++ b/rust-lib/flowy-sdk/src/deps_resolve/workspace_deps_impl.rs @@ -1,4 +1,4 @@ -use flowy_database::DBConnection; +use flowy_database::ConnectionPool; use flowy_user::services::user::UserSession; use flowy_workspace::{ errors::{ErrorBuilder, ErrorCode, WorkspaceError}, @@ -29,9 +29,9 @@ pub struct WorkspaceDatabaseImpl { } impl WorkspaceDatabase for WorkspaceDatabaseImpl { - fn db_connection(&self) -> Result { + fn db_pool(&self) -> Result, WorkspaceError> { self.user_session - .db_conn() + .db_pool() .map_err(|e| ErrorBuilder::new(ErrorCode::InternalError).error(e).build()) } } diff --git a/rust-lib/flowy-sdk/src/module.rs b/rust-lib/flowy-sdk/src/module.rs index f68dd50027..8722661b4d 100644 --- a/rust-lib/flowy-sdk/src/module.rs +++ b/rust-lib/flowy-sdk/src/module.rs @@ -1,5 +1,4 @@ use flowy_dispatch::prelude::Module; -use flowy_user::prelude::*; use crate::deps_resolve::{EditorUserImpl, WorkspaceDatabaseImpl, WorkspaceUserImpl}; use flowy_document::module::Document; diff --git a/rust-lib/flowy-test/src/builder.rs b/rust-lib/flowy-test/src/builder.rs index f90d2ad958..05f7342b02 100644 --- a/rust-lib/flowy-test/src/builder.rs +++ b/rust-lib/flowy-test/src/builder.rs @@ -7,7 +7,7 @@ use std::{ use crate::FlowyTestSDK; use flowy_dispatch::prelude::*; -use flowy_document::errors::DocError; + use flowy_sdk::*; use flowy_user::errors::UserError; use flowy_workspace::errors::WorkspaceError; diff --git a/rust-lib/flowy-user/src/errors.rs b/rust-lib/flowy-user/src/errors.rs index f82ea802ee..668beb4392 100644 --- a/rust-lib/flowy-user/src/errors.rs +++ b/rust-lib/flowy-user/src/errors.rs @@ -83,7 +83,12 @@ impl std::default::Default for ErrorCode { } impl std::convert::From for UserError { - fn from(error: flowy_database::Error) -> Self { ErrorBuilder::new(ErrorCode::InternalError).error(error).build() } + fn from(error: flowy_database::Error) -> Self { + match error { + flowy_database::Error::NotFound => ErrorBuilder::new(ErrorCode::UserNotExist).error(error).build(), + _ => ErrorBuilder::new(ErrorCode::InternalError).error(error).build(), + } + } } impl std::convert::From<::r2d2::Error> for UserError { diff --git a/rust-lib/flowy-user/src/services/user/user_session.rs b/rust-lib/flowy-user/src/services/user/user_session.rs index f7b2959540..ed5e0b5565 100644 --- a/rust-lib/flowy-user/src/services/user/user_session.rs +++ b/rust-lib/flowy-user/src/services/user/user_session.rs @@ -54,7 +54,7 @@ impl UserSession { } } - pub fn db_conn(&self) -> Result { + pub fn db_connection(&self) -> Result { let user_id = self.get_session()?.user_id; self.database.get_connection(&user_id) } @@ -101,7 +101,7 @@ impl UserSession { #[tracing::instrument(level = "debug", skip(self))] pub async fn sign_out(&self) -> Result<(), UserError> { let session = self.get_session()?; - let _ = diesel::delete(dsl::user_table.filter(dsl::id.eq(&session.user_id))).execute(&*(self.db_conn()?))?; + let _ = diesel::delete(dsl::user_table.filter(dsl::id.eq(&session.user_id))).execute(&*(self.db_connection()?))?; let _ = self.database.close_user_db(&session.user_id)?; let _ = self.set_session(None)?; let _ = self.sign_out_on_server(&session.token).await?; @@ -113,7 +113,7 @@ impl UserSession { pub async fn update_user(&self, params: UpdateUserParams) -> Result<(), UserError> { let session = self.get_session()?; let changeset = UserTableChangeset::new(params.clone()); - diesel_update_table!(user_table, changeset, &*self.db_conn()?); + diesel_update_table!(user_table, changeset, &*self.db_connection()?); let _ = self.update_user_on_server(&session.token, params).await?; Ok(()) @@ -123,7 +123,7 @@ impl UserSession { let (user_id, token) = self.get_session()?.into_part(); let user = dsl::user_table .filter(user_table::id.eq(&user_id)) - .first::(&*(self.db_conn()?))?; + .first::(&*(self.db_connection()?))?; let _ = self.read_user_profile_on_server(&token).await?; Ok(UserProfile::from(user)) @@ -187,7 +187,7 @@ impl UserSession { } async fn save_user(&self, user: UserTable) -> Result { - let conn = self.db_conn()?; + let conn = self.db_connection()?; let _ = diesel::insert_into(user_table::table).values(user.clone()).execute(&*conn)?; Ok(user) } @@ -236,7 +236,7 @@ pub async fn update_user(_server: Server, pool: Arc, params: Upd } impl UserDatabaseConnection for UserSession { - fn get_connection(&self) -> Result { self.db_conn().map_err(|e| format!("{:?}", e)) } + fn get_connection(&self) -> Result { self.db_connection().map_err(|e| format!("{:?}", e)) } } const SESSION_CACHE_KEY: &str = "session_cache_key"; diff --git a/rust-lib/flowy-workspace/src/entities/view/parser/view_thumbnail.rs b/rust-lib/flowy-workspace/src/entities/view/parser/view_thumbnail.rs index 303a2020a2..ce7aba0b15 100644 --- a/rust-lib/flowy-workspace/src/entities/view/parser/view_thumbnail.rs +++ b/rust-lib/flowy-workspace/src/entities/view/parser/view_thumbnail.rs @@ -3,10 +3,9 @@ pub struct ViewThumbnail(pub String); impl ViewThumbnail { pub fn parse(s: String) -> Result { - if s.trim().is_empty() { - return Err(format!("View thumbnail can not be empty or whitespace")); - } - + // if s.trim().is_empty() { + // return Err(format!("View thumbnail can not be empty or whitespace")); + // } // TODO: verify the thumbnail url is valid or not Ok(Self(s)) diff --git a/rust-lib/flowy-workspace/src/entities/view/view_create.rs b/rust-lib/flowy-workspace/src/entities/view/view_create.rs index f25e2c7bbd..52ae2fdf16 100644 --- a/rust-lib/flowy-workspace/src/entities/view/view_create.rs +++ b/rust-lib/flowy-workspace/src/entities/view/view_create.rs @@ -95,7 +95,7 @@ impl TryInto for CreateViewRequest { desc: self.desc, thumbnail, view_type: self.view_type, - data: "".to_owned(), + data: "[{\"insert\":\"\\n\"}]".to_owned(), }) } } diff --git a/rust-lib/flowy-workspace/src/module.rs b/rust-lib/flowy-workspace/src/module.rs index 14706a3a7f..4ee6b2d5aa 100644 --- a/rust-lib/flowy-workspace/src/module.rs +++ b/rust-lib/flowy-workspace/src/module.rs @@ -1,17 +1,13 @@ -use flowy_dispatch::prelude::*; - use crate::{ - errors::WorkspaceError, + errors::{ErrorBuilder, ErrorCode, WorkspaceError}, event::WorkspaceEvent, - services::{AppController, WorkspaceController}, + handlers::*, + services::{server::construct_workspace_server, AppController, ViewController, WorkspaceController}, }; use flowy_database::DBConnection; - -use crate::{ - handlers::*, - services::{server::construct_workspace_server, ViewController}, -}; +use flowy_dispatch::prelude::*; use flowy_document::module::Document; +use flowy_sqlite::ConnectionPool; use std::sync::Arc; pub trait WorkspaceDeps: WorkspaceUser + WorkspaceDatabase {} @@ -22,19 +18,27 @@ pub trait WorkspaceUser: Send + Sync { } pub trait WorkspaceDatabase: Send + Sync { - fn db_connection(&self) -> Result; + fn db_pool(&self) -> Result, WorkspaceError>; + + fn db_connection(&self) -> Result { + let pool = self.db_pool()?; + let conn = pool + .get() + .map_err(|e| ErrorBuilder::new(ErrorCode::InternalError).error(e).build())?; + Ok(conn) + } } pub fn create(user: Arc, database: Arc, document: Arc) -> Module { let server = construct_workspace_server(); let view_controller = Arc::new(ViewController::new(user.clone(), database.clone(), server.clone(), document)); - let app_controller = Arc::new(AppController::new(user.clone(), database.clone(), server.clone())); let workspace_controller = Arc::new(WorkspaceController::new( user.clone(), database.clone(), app_controller.clone(), + view_controller.clone(), server.clone(), )); diff --git a/rust-lib/flowy-workspace/src/services/app_controller.rs b/rust-lib/flowy-workspace/src/services/app_controller.rs index f5eaead7c3..9c02e7d052 100644 --- a/rust-lib/flowy-workspace/src/services/app_controller.rs +++ b/rust-lib/flowy-workspace/src/services/app_controller.rs @@ -31,11 +31,10 @@ impl AppController { #[tracing::instrument(level = "debug", skip(self), err)] pub(crate) async fn create_app(&self, params: CreateAppParams) -> Result { let app = self.create_app_on_server(params).await?; - let app_table = AppTable::new(app.clone()); let conn = &*self.database.db_connection()?; conn.immediate_transaction::<_, WorkspaceError, _>(|| { - let _ = self.sql.create_app(app_table, &*conn)?; + let _ = self.save_app(app.clone(), &*conn)?; let apps = self.read_local_apps(&app.workspace_id, &*conn)?; notify(&app.workspace_id, WorkspaceObservable::WorkspaceCreateApp) .payload(apps) @@ -46,6 +45,12 @@ impl AppController { Ok(app) } + pub(crate) fn save_app(&self, app: App, conn: &SqliteConnection) -> Result<(), WorkspaceError> { + let app_table = AppTable::new(app.clone()); + let _ = self.sql.create_app(app_table, &*conn)?; + Ok(()) + } + pub(crate) async fn read_app(&self, params: QueryAppParams) -> Result { let app_table = self .sql diff --git a/rust-lib/flowy-workspace/src/services/view_controller.rs b/rust-lib/flowy-workspace/src/services/view_controller.rs index 18482ed3c6..0fea5fd913 100644 --- a/rust-lib/flowy-workspace/src/services/view_controller.rs +++ b/rust-lib/flowy-workspace/src/services/view_controller.rs @@ -42,11 +42,9 @@ impl ViewController { pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result { let view = self.create_view_on_server(params.clone()).await?; let conn = &*self.database.db_connection()?; - let view_table = ViewTable::new(view.clone()); - // TODO: rollback anything created before if failed? conn.immediate_transaction::<_, WorkspaceError, _>(|| { - let _ = self.sql.create_view(view_table, conn)?; + let _ = self.save_view(view.clone(), conn)?; self.document.doc.create(CreateDocParams::new(&view.id, ¶ms.data), conn)?; let repeated_view = self.read_local_views_belong_to(&view.belong_to_id, conn)?; @@ -59,6 +57,12 @@ impl ViewController { Ok(view) } + pub(crate) fn save_view(&self, view: View, conn: &SqliteConnection) -> Result<(), WorkspaceError> { + let view_table = ViewTable::new(view); + let _ = self.sql.create_view(view_table, conn)?; + Ok(()) + } + pub(crate) async fn read_view(&self, params: QueryViewParams) -> Result { let conn = self.database.db_connection()?; let view_table = self.sql.read_view(¶ms.view_id, Some(params.is_trash), &*conn)?; @@ -68,8 +72,7 @@ impl ViewController { } pub(crate) async fn open_view(&self, params: QueryDocParams) -> Result { - let conn = self.database.db_connection()?; - let doc = self.document.doc.open(params, &*conn)?; + let doc = self.document.doc.open(params, self.database.db_pool()?).await?; Ok(doc) } diff --git a/rust-lib/flowy-workspace/src/services/workspace_controller.rs b/rust-lib/flowy-workspace/src/services/workspace_controller.rs index a2ccc638cc..d5cbb3cd01 100644 --- a/rust-lib/flowy-workspace/src/services/workspace_controller.rs +++ b/rust-lib/flowy-workspace/src/services/workspace_controller.rs @@ -6,12 +6,8 @@ use crate::{ errors::*, module::{WorkspaceDatabase, WorkspaceUser}, observable::*, - services::{helper::spawn, server::Server, AppController}, - sql_tables::{ - app::{AppTable, AppTableSql}, - view::{ViewTable, ViewTableSql}, - workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql}, - }, + services::{helper::spawn, server::Server, AppController, ViewController}, + sql_tables::workspace::{WorkspaceTable, WorkspaceTableChangeset, WorkspaceTableSql}, }; use flowy_database::SqliteConnection; use flowy_infra::kv::KV; @@ -20,8 +16,7 @@ use std::sync::Arc; pub(crate) struct WorkspaceController { pub user: Arc, pub workspace_sql: Arc, - pub app_sql: Arc, - pub view_sql: Arc, + pub view_controller: Arc, pub database: Arc, pub app_controller: Arc, server: Server, @@ -32,18 +27,16 @@ impl WorkspaceController { user: Arc, database: Arc, app_controller: Arc, + view_controller: Arc, server: Server, ) -> Self { let workspace_sql = Arc::new(WorkspaceTableSql {}); - let app_sql = Arc::new(AppTableSql {}); - let view_sql = Arc::new(ViewTableSql {}); Self { user, workspace_sql, - app_sql, - view_sql, database, app_controller, + view_controller, server, } } @@ -253,8 +246,8 @@ impl WorkspaceController { fn read_workspaces_on_server(&self, user_id: String, params: QueryWorkspaceParams) -> Result<(), WorkspaceError> { let (token, server) = self.token_with_server()?; let workspace_sql = self.workspace_sql.clone(); - let app_sql = self.app_sql.clone(); - let view_sql = self.view_sql.clone(); + let app_ctrl = self.app_controller.clone(); + let view_ctrl = self.view_controller.clone(); let conn = self.database.db_connection()?; spawn(async move { // Opti: handle the error and retry? @@ -270,14 +263,14 @@ impl WorkspaceController { log::debug!("Save {} apps", apps.len()); for mut app in apps { let views = app.belongings.take_items(); - match app_sql.create_app(AppTable::new(app), &*conn) { + match app_ctrl.save_app(app, &*conn) { Ok(_) => {}, Err(e) => log::error!("create app failed: {:?}", e), } log::debug!("Save {} views", views.len()); for view in views { - match view_sql.create_view(ViewTable::new(view), &*conn) { + match view_ctrl.save_view(view, &*conn) { Ok(_) => {}, Err(e) => log::error!("create view failed: {:?}", e), } diff --git a/rust-lib/flowy-workspace/tests/workspace/app_test.rs b/rust-lib/flowy-workspace/tests/workspace/app_test.rs index 948025f0de..fb9eb5fe15 100644 --- a/rust-lib/flowy-workspace/tests/workspace/app_test.rs +++ b/rust-lib/flowy-workspace/tests/workspace/app_test.rs @@ -1,5 +1,4 @@ use crate::helper::*; -use flowy_test::prelude::*; use flowy_workspace::entities::{app::QueryAppRequest, view::*}; diff --git a/rust-lib/flowy-workspace/tests/workspace/view_test.rs b/rust-lib/flowy-workspace/tests/workspace/view_test.rs index 8c59549245..fde1f9435e 100644 --- a/rust-lib/flowy-workspace/tests/workspace/view_test.rs +++ b/rust-lib/flowy-workspace/tests/workspace/view_test.rs @@ -1,6 +1,5 @@ use crate::helper::*; -use flowy_test::{FlowyEnv, FlowyTestSDK}; use flowy_workspace::entities::view::*; #[test] diff --git a/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs b/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs index 0b8a0cdb13..09b5311181 100644 --- a/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs +++ b/rust-lib/flowy-workspace/tests/workspace/workspace_test.rs @@ -1,7 +1,7 @@ use crate::helper::*; use flowy_test::{builder::*, FlowyEnv}; use flowy_workspace::{ - entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest, RepeatedWorkspace}, + entities::workspace::{CreateWorkspaceRequest, QueryWorkspaceRequest}, event::WorkspaceEvent::*, prelude::*, };