refactor extract observable payload

This commit is contained in:
appflowy 2021-09-07 17:12:03 +08:00
parent 024ab85864
commit f18cc717ea
47 changed files with 1220 additions and 751 deletions

View file

@ -1,8 +1,6 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/user/presentation/sign_up_screen.dart'; import 'package:app_flowy/user/presentation/sign_up_screen.dart';
import 'package:app_flowy/welcome/domain/i_welcome.dart'; import 'package:app_flowy/welcome/domain/i_welcome.dart';
import 'package:app_flowy/workspace/infrastructure/repos/user_repo.dart';
import 'package:app_flowy/workspace/presentation/workspace/workspace_select_screen.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra_ui/widget/route/animation.dart'; import 'package:flowy_infra_ui/widget/route/animation.dart';
import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart';

View file

@ -1,4 +1,6 @@
import 'package:app_flowy/workspace/application/workspace/workspace_list_bloc.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/workspace/welcome_bloc.dart';
import 'package:app_flowy/workspace/domain/i_user.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text_button.dart'; import 'package:flowy_infra_ui/style_widget/text_button.dart';
import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
@ -17,9 +19,9 @@ class WelcomeScreen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (_) => create: (_) => getIt<WelcomeBloc>(param1: repo.user)
WorkspaceListBloc(repo)..add(const WorkspaceListEvent.initial()), ..add(const WelcomeEvent.initial()),
child: BlocBuilder<WorkspaceListBloc, WorkspaceListState>( child: BlocBuilder<WelcomeBloc, WelcomeState>(
builder: (context, state) { builder: (context, state) {
return Scaffold( return Scaffold(
body: Padding( body: Padding(
@ -37,7 +39,7 @@ class WelcomeScreen extends StatelessWidget {
); );
} }
Widget _renderBody(WorkspaceListState state) { Widget _renderBody(WelcomeState state) {
final body = state.successOrFailure.fold( final body = state.successOrFailure.fold(
(_) => _renderList(state.workspaces), (_) => _renderList(state.workspaces),
(error) => FlowyErrorPage(error.toString()), (error) => FlowyErrorPage(error.toString()),
@ -54,8 +56,8 @@ class WelcomeScreen extends StatelessWidget {
fontSize: 14, fontSize: 14,
onPressed: () { onPressed: () {
context context
.read<WorkspaceListBloc>() .read<WelcomeBloc>()
.add(const WorkspaceListEvent.createWorkspace("workspace", "")); .add(const WelcomeEvent.createWorkspace("workspace", ""));
}, },
), ),
); );
@ -77,9 +79,7 @@ class WelcomeScreen extends StatelessWidget {
} }
void _handleOnPress(BuildContext context, Workspace workspace) { void _handleOnPress(BuildContext context, Workspace workspace) {
context context.read<WelcomeBloc>().add(WelcomeEvent.openWorkspace(workspace));
.read<WorkspaceListBloc>()
.add(WorkspaceListEvent.openWorkspace(workspace));
Navigator.of(context).pop(workspace.id); Navigator.of(context).pop(workspace.id);
} }

View file

@ -52,6 +52,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
); );
} }
// ignore: unused_element
Stream<MenuState> _fetchApps() async* { Stream<MenuState> _fetchApps() async* {
final appsOrFail = await workspace.getApps(); final appsOrFail = await workspace.getApps();
yield appsOrFail.fold( yield appsOrFail.fold(

View file

@ -16,17 +16,17 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
Stream<MenuUserState> mapEventToState(MenuUserEvent event) async* { Stream<MenuUserState> mapEventToState(MenuUserEvent event) async* {
yield* event.map( yield* event.map(
initial: (_) async* { initial: (_) async* {
// fetch workspaces // // fetch workspaces
iUserImpl.fetchWorkspaces().then((result) { // iUserImpl.fetchWorkspaces().then((result) {
result.fold( // result.fold(
(workspaces) async* { // (workspaces) async* {
yield state.copyWith(workspaces: some(workspaces)); // yield state.copyWith(workspaces: some(workspaces));
}, // },
(error) async* { // (error) async* {
yield state.copyWith(successOrFailure: right(error.msg)); // yield state.copyWith(successOrFailure: right(error.msg));
}, // },
); // );
}); // });
}, },
fetchWorkspaces: (_FetchWorkspaces value) async* {}, fetchWorkspaces: (_FetchWorkspaces value) async* {},
); );

View file

@ -0,0 +1,110 @@
import 'package:app_flowy/workspace/domain/i_user.dart';
import 'package:app_flowy/workspace/infrastructure/repos/user_repo.dart';
import 'package:flowy_infra/flowy_logger.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart';
part 'welcome_bloc.freezed.dart';
class WelcomeBloc extends Bloc<WelcomeEvent, WelcomeState> {
UserRepo repo;
IUserWorkspaceListWatch watcher;
WelcomeBloc({required this.repo, required this.watcher})
: super(WelcomeState.initial());
@override
Stream<WelcomeState> mapEventToState(
WelcomeEvent event,
) async* {
yield* event.map(initial: (e) async* {
watcher.startWatching(
workspaceListUpdatedCallback: (workspacesOrFail) =>
_handleWorkspaceListUpdated(workspacesOrFail),
);
yield* _fetchWorkspaces();
}, openWorkspace: (e) async* {
yield* _openWorkspace(e.workspace);
}, createWorkspace: (e) async* {
yield* _createWorkspace(e.name, e.desc);
}, workspacesReveived: (e) async* {
yield e.workspacesOrFail.fold(
(workspaces) => state.copyWith(
workspaces: workspaces, successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
);
});
}
Stream<WelcomeState> _fetchWorkspaces() async* {
final workspacesOrFailed = await repo.getWorkspaces();
yield workspacesOrFailed.fold(
(workspaces) =>
state.copyWith(workspaces: workspaces, successOrFailure: left(unit)),
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
},
);
}
Stream<WelcomeState> _openWorkspace(Workspace workspace) async* {
final result = await repo.openWorkspace(workspace.id);
yield result.fold(
(workspaces) => state.copyWith(successOrFailure: left(unit)),
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
},
);
}
Stream<WelcomeState> _createWorkspace(String name, String desc) async* {
final result = await repo.createWorkspace(name, desc);
yield result.fold(
(workspace) {
// add(const WelcomeEvent.fetchWorkspaces());
return state.copyWith(successOrFailure: left(unit));
},
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
},
);
}
void _handleWorkspaceListUpdated(
Either<List<Workspace>, WorkspaceError> workspacesOrFail) {
add(WelcomeEvent.workspacesReveived(workspacesOrFail));
}
}
@freezed
abstract class WelcomeEvent with _$WelcomeEvent {
const factory WelcomeEvent.initial() = Initial;
// const factory WelcomeEvent.fetchWorkspaces() = FetchWorkspace;
const factory WelcomeEvent.createWorkspace(String name, String desc) =
CreateWorkspace;
const factory WelcomeEvent.openWorkspace(Workspace workspace) = OpenWorkspace;
const factory WelcomeEvent.workspacesReveived(
Either<List<Workspace>, WorkspaceError> workspacesOrFail) =
WorkspacesReceived;
}
@freezed
abstract class WelcomeState implements _$WelcomeState {
const factory WelcomeState({
required bool isLoading,
required List<Workspace> workspaces,
required Either<Unit, WorkspaceError> successOrFailure,
}) = _WelcomeState;
factory WelcomeState.initial() => WelcomeState(
isLoading: false,
workspaces: List.empty(),
successOrFailure: left(unit),
);
}

View file

@ -1,7 +1,7 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'workspace_list_bloc.dart'; part of 'welcome_bloc.dart';
// ************************************************************************** // **************************************************************************
// FreezedGenerator // FreezedGenerator
@ -13,17 +13,13 @@ final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc /// @nodoc
class _$WorkspaceListEventTearOff { class _$WelcomeEventTearOff {
const _$WorkspaceListEventTearOff(); const _$WelcomeEventTearOff();
Initial initial() { Initial initial() {
return const Initial(); return const Initial();
} }
FetchWorkspace fetchWorkspaces() {
return const FetchWorkspace();
}
CreateWorkspace createWorkspace(String name, String desc) { CreateWorkspace createWorkspace(String name, String desc) {
return CreateWorkspace( return CreateWorkspace(
name, name,
@ -36,64 +32,73 @@ class _$WorkspaceListEventTearOff {
workspace, workspace,
); );
} }
WorkspacesReceived workspacesReveived(
Either<List<Workspace>, WorkspaceError> workspacesOrFail) {
return WorkspacesReceived(
workspacesOrFail,
);
}
} }
/// @nodoc /// @nodoc
const $WorkspaceListEvent = _$WorkspaceListEventTearOff(); const $WelcomeEvent = _$WelcomeEventTearOff();
/// @nodoc /// @nodoc
mixin _$WorkspaceListEvent { mixin _$WelcomeEvent {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() initial, required TResult Function() initial,
required TResult Function() fetchWorkspaces,
required TResult Function(String name, String desc) createWorkspace, required TResult Function(String name, String desc) createWorkspace,
required TResult Function(Workspace workspace) openWorkspace, required TResult Function(Workspace workspace) openWorkspace,
required TResult Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFail)
workspacesReveived,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function()? fetchWorkspaces,
TResult Function(String name, String desc)? createWorkspace, TResult Function(String name, String desc)? createWorkspace,
TResult Function(Workspace workspace)? openWorkspace, TResult Function(Workspace workspace)? openWorkspace,
TResult Function(Either<List<Workspace>, WorkspaceError> workspacesOrFail)?
workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(FetchWorkspace value) fetchWorkspaces,
required TResult Function(CreateWorkspace value) createWorkspace, required TResult Function(CreateWorkspace value) createWorkspace,
required TResult Function(OpenWorkspace value) openWorkspace, required TResult Function(OpenWorkspace value) openWorkspace,
required TResult Function(WorkspacesReceived value) workspacesReveived,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(FetchWorkspace value)? fetchWorkspaces,
TResult Function(CreateWorkspace value)? createWorkspace, TResult Function(CreateWorkspace value)? createWorkspace,
TResult Function(OpenWorkspace value)? openWorkspace, TResult Function(OpenWorkspace value)? openWorkspace,
TResult Function(WorkspacesReceived value)? workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
abstract class $WorkspaceListEventCopyWith<$Res> { abstract class $WelcomeEventCopyWith<$Res> {
factory $WorkspaceListEventCopyWith( factory $WelcomeEventCopyWith(
WorkspaceListEvent value, $Res Function(WorkspaceListEvent) then) = WelcomeEvent value, $Res Function(WelcomeEvent) then) =
_$WorkspaceListEventCopyWithImpl<$Res>; _$WelcomeEventCopyWithImpl<$Res>;
} }
/// @nodoc /// @nodoc
class _$WorkspaceListEventCopyWithImpl<$Res> class _$WelcomeEventCopyWithImpl<$Res> implements $WelcomeEventCopyWith<$Res> {
implements $WorkspaceListEventCopyWith<$Res> { _$WelcomeEventCopyWithImpl(this._value, this._then);
_$WorkspaceListEventCopyWithImpl(this._value, this._then);
final WorkspaceListEvent _value; final WelcomeEvent _value;
// ignore: unused_field // ignore: unused_field
final $Res Function(WorkspaceListEvent) _then; final $Res Function(WelcomeEvent) _then;
} }
/// @nodoc /// @nodoc
@ -103,7 +108,7 @@ abstract class $InitialCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class _$InitialCopyWithImpl<$Res> extends _$WorkspaceListEventCopyWithImpl<$Res> class _$InitialCopyWithImpl<$Res> extends _$WelcomeEventCopyWithImpl<$Res>
implements $InitialCopyWith<$Res> { implements $InitialCopyWith<$Res> {
_$InitialCopyWithImpl(Initial _value, $Res Function(Initial) _then) _$InitialCopyWithImpl(Initial _value, $Res Function(Initial) _then)
: super(_value, (v) => _then(v as Initial)); : super(_value, (v) => _then(v as Initial));
@ -119,7 +124,7 @@ class _$Initial implements Initial {
@override @override
String toString() { String toString() {
return 'WorkspaceListEvent.initial()'; return 'WelcomeEvent.initial()';
} }
@override @override
@ -134,9 +139,11 @@ class _$Initial implements Initial {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() initial, required TResult Function() initial,
required TResult Function() fetchWorkspaces,
required TResult Function(String name, String desc) createWorkspace, required TResult Function(String name, String desc) createWorkspace,
required TResult Function(Workspace workspace) openWorkspace, required TResult Function(Workspace workspace) openWorkspace,
required TResult Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFail)
workspacesReveived,
}) { }) {
return initial(); return initial();
} }
@ -145,9 +152,10 @@ class _$Initial implements Initial {
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function()? fetchWorkspaces,
TResult Function(String name, String desc)? createWorkspace, TResult Function(String name, String desc)? createWorkspace,
TResult Function(Workspace workspace)? openWorkspace, TResult Function(Workspace workspace)? openWorkspace,
TResult Function(Either<List<Workspace>, WorkspaceError> workspacesOrFail)?
workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (initial != null) { if (initial != null) {
@ -160,9 +168,9 @@ class _$Initial implements Initial {
@optionalTypeArgs @optionalTypeArgs
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(FetchWorkspace value) fetchWorkspaces,
required TResult Function(CreateWorkspace value) createWorkspace, required TResult Function(CreateWorkspace value) createWorkspace,
required TResult Function(OpenWorkspace value) openWorkspace, required TResult Function(OpenWorkspace value) openWorkspace,
required TResult Function(WorkspacesReceived value) workspacesReveived,
}) { }) {
return initial(this); return initial(this);
} }
@ -171,9 +179,9 @@ class _$Initial implements Initial {
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(FetchWorkspace value)? fetchWorkspaces,
TResult Function(CreateWorkspace value)? createWorkspace, TResult Function(CreateWorkspace value)? createWorkspace,
TResult Function(OpenWorkspace value)? openWorkspace, TResult Function(OpenWorkspace value)? openWorkspace,
TResult Function(WorkspacesReceived value)? workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (initial != null) { if (initial != null) {
@ -183,104 +191,10 @@ class _$Initial implements Initial {
} }
} }
abstract class Initial implements WorkspaceListEvent { abstract class Initial implements WelcomeEvent {
const factory Initial() = _$Initial; const factory Initial() = _$Initial;
} }
/// @nodoc
abstract class $FetchWorkspaceCopyWith<$Res> {
factory $FetchWorkspaceCopyWith(
FetchWorkspace value, $Res Function(FetchWorkspace) then) =
_$FetchWorkspaceCopyWithImpl<$Res>;
}
/// @nodoc
class _$FetchWorkspaceCopyWithImpl<$Res>
extends _$WorkspaceListEventCopyWithImpl<$Res>
implements $FetchWorkspaceCopyWith<$Res> {
_$FetchWorkspaceCopyWithImpl(
FetchWorkspace _value, $Res Function(FetchWorkspace) _then)
: super(_value, (v) => _then(v as FetchWorkspace));
@override
FetchWorkspace get _value => super._value as FetchWorkspace;
}
/// @nodoc
class _$FetchWorkspace implements FetchWorkspace {
const _$FetchWorkspace();
@override
String toString() {
return 'WorkspaceListEvent.fetchWorkspaces()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is FetchWorkspace);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() fetchWorkspaces,
required TResult Function(String name, String desc) createWorkspace,
required TResult Function(Workspace workspace) openWorkspace,
}) {
return fetchWorkspaces();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? fetchWorkspaces,
TResult Function(String name, String desc)? createWorkspace,
TResult Function(Workspace workspace)? openWorkspace,
required TResult orElse(),
}) {
if (fetchWorkspaces != null) {
return fetchWorkspaces();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(FetchWorkspace value) fetchWorkspaces,
required TResult Function(CreateWorkspace value) createWorkspace,
required TResult Function(OpenWorkspace value) openWorkspace,
}) {
return fetchWorkspaces(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(FetchWorkspace value)? fetchWorkspaces,
TResult Function(CreateWorkspace value)? createWorkspace,
TResult Function(OpenWorkspace value)? openWorkspace,
required TResult orElse(),
}) {
if (fetchWorkspaces != null) {
return fetchWorkspaces(this);
}
return orElse();
}
}
abstract class FetchWorkspace implements WorkspaceListEvent {
const factory FetchWorkspace() = _$FetchWorkspace;
}
/// @nodoc /// @nodoc
abstract class $CreateWorkspaceCopyWith<$Res> { abstract class $CreateWorkspaceCopyWith<$Res> {
factory $CreateWorkspaceCopyWith( factory $CreateWorkspaceCopyWith(
@ -291,7 +205,7 @@ abstract class $CreateWorkspaceCopyWith<$Res> {
/// @nodoc /// @nodoc
class _$CreateWorkspaceCopyWithImpl<$Res> class _$CreateWorkspaceCopyWithImpl<$Res>
extends _$WorkspaceListEventCopyWithImpl<$Res> extends _$WelcomeEventCopyWithImpl<$Res>
implements $CreateWorkspaceCopyWith<$Res> { implements $CreateWorkspaceCopyWith<$Res> {
_$CreateWorkspaceCopyWithImpl( _$CreateWorkspaceCopyWithImpl(
CreateWorkspace _value, $Res Function(CreateWorkspace) _then) CreateWorkspace _value, $Res Function(CreateWorkspace) _then)
@ -330,7 +244,7 @@ class _$CreateWorkspace implements CreateWorkspace {
@override @override
String toString() { String toString() {
return 'WorkspaceListEvent.createWorkspace(name: $name, desc: $desc)'; return 'WelcomeEvent.createWorkspace(name: $name, desc: $desc)';
} }
@override @override
@ -358,9 +272,11 @@ class _$CreateWorkspace implements CreateWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() initial, required TResult Function() initial,
required TResult Function() fetchWorkspaces,
required TResult Function(String name, String desc) createWorkspace, required TResult Function(String name, String desc) createWorkspace,
required TResult Function(Workspace workspace) openWorkspace, required TResult Function(Workspace workspace) openWorkspace,
required TResult Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFail)
workspacesReveived,
}) { }) {
return createWorkspace(name, desc); return createWorkspace(name, desc);
} }
@ -369,9 +285,10 @@ class _$CreateWorkspace implements CreateWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function()? fetchWorkspaces,
TResult Function(String name, String desc)? createWorkspace, TResult Function(String name, String desc)? createWorkspace,
TResult Function(Workspace workspace)? openWorkspace, TResult Function(Workspace workspace)? openWorkspace,
TResult Function(Either<List<Workspace>, WorkspaceError> workspacesOrFail)?
workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (createWorkspace != null) { if (createWorkspace != null) {
@ -384,9 +301,9 @@ class _$CreateWorkspace implements CreateWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(FetchWorkspace value) fetchWorkspaces,
required TResult Function(CreateWorkspace value) createWorkspace, required TResult Function(CreateWorkspace value) createWorkspace,
required TResult Function(OpenWorkspace value) openWorkspace, required TResult Function(OpenWorkspace value) openWorkspace,
required TResult Function(WorkspacesReceived value) workspacesReveived,
}) { }) {
return createWorkspace(this); return createWorkspace(this);
} }
@ -395,9 +312,9 @@ class _$CreateWorkspace implements CreateWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(FetchWorkspace value)? fetchWorkspaces,
TResult Function(CreateWorkspace value)? createWorkspace, TResult Function(CreateWorkspace value)? createWorkspace,
TResult Function(OpenWorkspace value)? openWorkspace, TResult Function(OpenWorkspace value)? openWorkspace,
TResult Function(WorkspacesReceived value)? workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (createWorkspace != null) { if (createWorkspace != null) {
@ -407,7 +324,7 @@ class _$CreateWorkspace implements CreateWorkspace {
} }
} }
abstract class CreateWorkspace implements WorkspaceListEvent { abstract class CreateWorkspace implements WelcomeEvent {
const factory CreateWorkspace(String name, String desc) = _$CreateWorkspace; const factory CreateWorkspace(String name, String desc) = _$CreateWorkspace;
String get name => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError;
@ -426,8 +343,7 @@ abstract class $OpenWorkspaceCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class _$OpenWorkspaceCopyWithImpl<$Res> class _$OpenWorkspaceCopyWithImpl<$Res> extends _$WelcomeEventCopyWithImpl<$Res>
extends _$WorkspaceListEventCopyWithImpl<$Res>
implements $OpenWorkspaceCopyWith<$Res> { implements $OpenWorkspaceCopyWith<$Res> {
_$OpenWorkspaceCopyWithImpl( _$OpenWorkspaceCopyWithImpl(
OpenWorkspace _value, $Res Function(OpenWorkspace) _then) OpenWorkspace _value, $Res Function(OpenWorkspace) _then)
@ -459,7 +375,7 @@ class _$OpenWorkspace implements OpenWorkspace {
@override @override
String toString() { String toString() {
return 'WorkspaceListEvent.openWorkspace(workspace: $workspace)'; return 'WelcomeEvent.openWorkspace(workspace: $workspace)';
} }
@override @override
@ -484,9 +400,11 @@ class _$OpenWorkspace implements OpenWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult when<TResult extends Object?>({ TResult when<TResult extends Object?>({
required TResult Function() initial, required TResult Function() initial,
required TResult Function() fetchWorkspaces,
required TResult Function(String name, String desc) createWorkspace, required TResult Function(String name, String desc) createWorkspace,
required TResult Function(Workspace workspace) openWorkspace, required TResult Function(Workspace workspace) openWorkspace,
required TResult Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFail)
workspacesReveived,
}) { }) {
return openWorkspace(workspace); return openWorkspace(workspace);
} }
@ -495,9 +413,10 @@ class _$OpenWorkspace implements OpenWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function()? fetchWorkspaces,
TResult Function(String name, String desc)? createWorkspace, TResult Function(String name, String desc)? createWorkspace,
TResult Function(Workspace workspace)? openWorkspace, TResult Function(Workspace workspace)? openWorkspace,
TResult Function(Either<List<Workspace>, WorkspaceError> workspacesOrFail)?
workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (openWorkspace != null) { if (openWorkspace != null) {
@ -510,9 +429,9 @@ class _$OpenWorkspace implements OpenWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(FetchWorkspace value) fetchWorkspaces,
required TResult Function(CreateWorkspace value) createWorkspace, required TResult Function(CreateWorkspace value) createWorkspace,
required TResult Function(OpenWorkspace value) openWorkspace, required TResult Function(OpenWorkspace value) openWorkspace,
required TResult Function(WorkspacesReceived value) workspacesReveived,
}) { }) {
return openWorkspace(this); return openWorkspace(this);
} }
@ -521,9 +440,9 @@ class _$OpenWorkspace implements OpenWorkspace {
@optionalTypeArgs @optionalTypeArgs
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(FetchWorkspace value)? fetchWorkspaces,
TResult Function(CreateWorkspace value)? createWorkspace, TResult Function(CreateWorkspace value)? createWorkspace,
TResult Function(OpenWorkspace value)? openWorkspace, TResult Function(OpenWorkspace value)? openWorkspace,
TResult Function(WorkspacesReceived value)? workspacesReveived,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (openWorkspace != null) { if (openWorkspace != null) {
@ -533,7 +452,7 @@ class _$OpenWorkspace implements OpenWorkspace {
} }
} }
abstract class OpenWorkspace implements WorkspaceListEvent { abstract class OpenWorkspace implements WelcomeEvent {
const factory OpenWorkspace(Workspace workspace) = _$OpenWorkspace; const factory OpenWorkspace(Workspace workspace) = _$OpenWorkspace;
Workspace get workspace => throw _privateConstructorUsedError; Workspace get workspace => throw _privateConstructorUsedError;
@ -543,14 +462,146 @@ abstract class OpenWorkspace implements WorkspaceListEvent {
} }
/// @nodoc /// @nodoc
class _$WorkspaceListStateTearOff { abstract class $WorkspacesReceivedCopyWith<$Res> {
const _$WorkspaceListStateTearOff(); factory $WorkspacesReceivedCopyWith(
WorkspacesReceived value, $Res Function(WorkspacesReceived) then) =
_$WorkspacesReceivedCopyWithImpl<$Res>;
$Res call({Either<List<Workspace>, WorkspaceError> workspacesOrFail});
}
_WorkspaceListState call( /// @nodoc
class _$WorkspacesReceivedCopyWithImpl<$Res>
extends _$WelcomeEventCopyWithImpl<$Res>
implements $WorkspacesReceivedCopyWith<$Res> {
_$WorkspacesReceivedCopyWithImpl(
WorkspacesReceived _value, $Res Function(WorkspacesReceived) _then)
: super(_value, (v) => _then(v as WorkspacesReceived));
@override
WorkspacesReceived get _value => super._value as WorkspacesReceived;
@override
$Res call({
Object? workspacesOrFail = freezed,
}) {
return _then(WorkspacesReceived(
workspacesOrFail == freezed
? _value.workspacesOrFail
: workspacesOrFail // ignore: cast_nullable_to_non_nullable
as Either<List<Workspace>, WorkspaceError>,
));
}
}
/// @nodoc
class _$WorkspacesReceived implements WorkspacesReceived {
const _$WorkspacesReceived(this.workspacesOrFail);
@override
final Either<List<Workspace>, WorkspaceError> workspacesOrFail;
@override
String toString() {
return 'WelcomeEvent.workspacesReveived(workspacesOrFail: $workspacesOrFail)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is WorkspacesReceived &&
(identical(other.workspacesOrFail, workspacesOrFail) ||
const DeepCollectionEquality()
.equals(other.workspacesOrFail, workspacesOrFail)));
}
@override
int get hashCode =>
runtimeType.hashCode ^
const DeepCollectionEquality().hash(workspacesOrFail);
@JsonKey(ignore: true)
@override
$WorkspacesReceivedCopyWith<WorkspacesReceived> get copyWith =>
_$WorkspacesReceivedCopyWithImpl<WorkspacesReceived>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String name, String desc) createWorkspace,
required TResult Function(Workspace workspace) openWorkspace,
required TResult Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFail)
workspacesReveived,
}) {
return workspacesReveived(workspacesOrFail);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String name, String desc)? createWorkspace,
TResult Function(Workspace workspace)? openWorkspace,
TResult Function(Either<List<Workspace>, WorkspaceError> workspacesOrFail)?
workspacesReveived,
required TResult orElse(),
}) {
if (workspacesReveived != null) {
return workspacesReveived(workspacesOrFail);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(CreateWorkspace value) createWorkspace,
required TResult Function(OpenWorkspace value) openWorkspace,
required TResult Function(WorkspacesReceived value) workspacesReveived,
}) {
return workspacesReveived(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(CreateWorkspace value)? createWorkspace,
TResult Function(OpenWorkspace value)? openWorkspace,
TResult Function(WorkspacesReceived value)? workspacesReveived,
required TResult orElse(),
}) {
if (workspacesReveived != null) {
return workspacesReveived(this);
}
return orElse();
}
}
abstract class WorkspacesReceived implements WelcomeEvent {
const factory WorkspacesReceived(
Either<List<Workspace>, WorkspaceError> workspacesOrFail) =
_$WorkspacesReceived;
Either<List<Workspace>, WorkspaceError> get workspacesOrFail =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$WorkspacesReceivedCopyWith<WorkspacesReceived> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
class _$WelcomeStateTearOff {
const _$WelcomeStateTearOff();
_WelcomeState call(
{required bool isLoading, {required bool isLoading,
required List<Workspace> workspaces, required List<Workspace> workspaces,
required Either<Unit, WorkspaceError> successOrFailure}) { required Either<Unit, WorkspaceError> successOrFailure}) {
return _WorkspaceListState( return _WelcomeState(
isLoading: isLoading, isLoading: isLoading,
workspaces: workspaces, workspaces: workspaces,
successOrFailure: successOrFailure, successOrFailure: successOrFailure,
@ -559,25 +610,25 @@ class _$WorkspaceListStateTearOff {
} }
/// @nodoc /// @nodoc
const $WorkspaceListState = _$WorkspaceListStateTearOff(); const $WelcomeState = _$WelcomeStateTearOff();
/// @nodoc /// @nodoc
mixin _$WorkspaceListState { mixin _$WelcomeState {
bool get isLoading => throw _privateConstructorUsedError; bool get isLoading => throw _privateConstructorUsedError;
List<Workspace> get workspaces => throw _privateConstructorUsedError; List<Workspace> get workspaces => throw _privateConstructorUsedError;
Either<Unit, WorkspaceError> get successOrFailure => Either<Unit, WorkspaceError> get successOrFailure =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@JsonKey(ignore: true) @JsonKey(ignore: true)
$WorkspaceListStateCopyWith<WorkspaceListState> get copyWith => $WelcomeStateCopyWith<WelcomeState> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc /// @nodoc
abstract class $WorkspaceListStateCopyWith<$Res> { abstract class $WelcomeStateCopyWith<$Res> {
factory $WorkspaceListStateCopyWith( factory $WelcomeStateCopyWith(
WorkspaceListState value, $Res Function(WorkspaceListState) then) = WelcomeState value, $Res Function(WelcomeState) then) =
_$WorkspaceListStateCopyWithImpl<$Res>; _$WelcomeStateCopyWithImpl<$Res>;
$Res call( $Res call(
{bool isLoading, {bool isLoading,
List<Workspace> workspaces, List<Workspace> workspaces,
@ -585,13 +636,12 @@ abstract class $WorkspaceListStateCopyWith<$Res> {
} }
/// @nodoc /// @nodoc
class _$WorkspaceListStateCopyWithImpl<$Res> class _$WelcomeStateCopyWithImpl<$Res> implements $WelcomeStateCopyWith<$Res> {
implements $WorkspaceListStateCopyWith<$Res> { _$WelcomeStateCopyWithImpl(this._value, this._then);
_$WorkspaceListStateCopyWithImpl(this._value, this._then);
final WorkspaceListState _value; final WelcomeState _value;
// ignore: unused_field // ignore: unused_field
final $Res Function(WorkspaceListState) _then; final $Res Function(WelcomeState) _then;
@override @override
$Res call({ $Res call({
@ -617,11 +667,11 @@ class _$WorkspaceListStateCopyWithImpl<$Res>
} }
/// @nodoc /// @nodoc
abstract class _$WorkspaceListStateCopyWith<$Res> abstract class _$WelcomeStateCopyWith<$Res>
implements $WorkspaceListStateCopyWith<$Res> { implements $WelcomeStateCopyWith<$Res> {
factory _$WorkspaceListStateCopyWith( factory _$WelcomeStateCopyWith(
_WorkspaceListState value, $Res Function(_WorkspaceListState) then) = _WelcomeState value, $Res Function(_WelcomeState) then) =
__$WorkspaceListStateCopyWithImpl<$Res>; __$WelcomeStateCopyWithImpl<$Res>;
@override @override
$Res call( $Res call(
{bool isLoading, {bool isLoading,
@ -630,15 +680,14 @@ abstract class _$WorkspaceListStateCopyWith<$Res>
} }
/// @nodoc /// @nodoc
class __$WorkspaceListStateCopyWithImpl<$Res> class __$WelcomeStateCopyWithImpl<$Res> extends _$WelcomeStateCopyWithImpl<$Res>
extends _$WorkspaceListStateCopyWithImpl<$Res> implements _$WelcomeStateCopyWith<$Res> {
implements _$WorkspaceListStateCopyWith<$Res> { __$WelcomeStateCopyWithImpl(
__$WorkspaceListStateCopyWithImpl( _WelcomeState _value, $Res Function(_WelcomeState) _then)
_WorkspaceListState _value, $Res Function(_WorkspaceListState) _then) : super(_value, (v) => _then(v as _WelcomeState));
: super(_value, (v) => _then(v as _WorkspaceListState));
@override @override
_WorkspaceListState get _value => super._value as _WorkspaceListState; _WelcomeState get _value => super._value as _WelcomeState;
@override @override
$Res call({ $Res call({
@ -646,7 +695,7 @@ class __$WorkspaceListStateCopyWithImpl<$Res>
Object? workspaces = freezed, Object? workspaces = freezed,
Object? successOrFailure = freezed, Object? successOrFailure = freezed,
}) { }) {
return _then(_WorkspaceListState( return _then(_WelcomeState(
isLoading: isLoading == freezed isLoading: isLoading == freezed
? _value.isLoading ? _value.isLoading
: isLoading // ignore: cast_nullable_to_non_nullable : isLoading // ignore: cast_nullable_to_non_nullable
@ -665,8 +714,8 @@ class __$WorkspaceListStateCopyWithImpl<$Res>
/// @nodoc /// @nodoc
class _$_WorkspaceListState implements _WorkspaceListState { class _$_WelcomeState implements _WelcomeState {
const _$_WorkspaceListState( const _$_WelcomeState(
{required this.isLoading, {required this.isLoading,
required this.workspaces, required this.workspaces,
required this.successOrFailure}); required this.successOrFailure});
@ -680,13 +729,13 @@ class _$_WorkspaceListState implements _WorkspaceListState {
@override @override
String toString() { String toString() {
return 'WorkspaceListState(isLoading: $isLoading, workspaces: $workspaces, successOrFailure: $successOrFailure)'; return 'WelcomeState(isLoading: $isLoading, workspaces: $workspaces, successOrFailure: $successOrFailure)';
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(dynamic other) {
return identical(this, other) || return identical(this, other) ||
(other is _WorkspaceListState && (other is _WelcomeState &&
(identical(other.isLoading, isLoading) || (identical(other.isLoading, isLoading) ||
const DeepCollectionEquality() const DeepCollectionEquality()
.equals(other.isLoading, isLoading)) && .equals(other.isLoading, isLoading)) &&
@ -707,16 +756,16 @@ class _$_WorkspaceListState implements _WorkspaceListState {
@JsonKey(ignore: true) @JsonKey(ignore: true)
@override @override
_$WorkspaceListStateCopyWith<_WorkspaceListState> get copyWith => _$WelcomeStateCopyWith<_WelcomeState> get copyWith =>
__$WorkspaceListStateCopyWithImpl<_WorkspaceListState>(this, _$identity); __$WelcomeStateCopyWithImpl<_WelcomeState>(this, _$identity);
} }
abstract class _WorkspaceListState implements WorkspaceListState { abstract class _WelcomeState implements WelcomeState {
const factory _WorkspaceListState( const factory _WelcomeState(
{required bool isLoading, {required bool isLoading,
required List<Workspace> workspaces, required List<Workspace> workspaces,
required Either<Unit, WorkspaceError> successOrFailure}) = required Either<Unit, WorkspaceError> successOrFailure}) =
_$_WorkspaceListState; _$_WelcomeState;
@override @override
bool get isLoading => throw _privateConstructorUsedError; bool get isLoading => throw _privateConstructorUsedError;
@ -727,6 +776,6 @@ abstract class _WorkspaceListState implements WorkspaceListState {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$WorkspaceListStateCopyWith<_WorkspaceListState> get copyWith => _$WelcomeStateCopyWith<_WelcomeState> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }

View file

@ -1,91 +0,0 @@
import 'package:app_flowy/workspace/infrastructure/repos/user_repo.dart';
import 'package:flowy_infra/flowy_logger.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart';
part 'workspace_list_bloc.freezed.dart';
class WorkspaceListBloc extends Bloc<WorkspaceListEvent, WorkspaceListState> {
UserRepo repo;
WorkspaceListBloc(this.repo) : super(WorkspaceListState.initial());
@override
Stream<WorkspaceListState> mapEventToState(
WorkspaceListEvent event,
) async* {
yield* event.map(initial: (e) async* {
yield* _fetchWorkspaces();
}, openWorkspace: (e) async* {
yield* _openWorkspace(e.workspace);
}, createWorkspace: (e) async* {
yield* _createWorkspace(e.name, e.desc);
}, fetchWorkspaces: (e) async* {
yield* _fetchWorkspaces();
});
}
Stream<WorkspaceListState> _fetchWorkspaces() async* {
final workspacesOrFailed = await repo.fetchWorkspaces();
yield workspacesOrFailed.fold(
(workspaces) =>
state.copyWith(workspaces: workspaces, successOrFailure: left(unit)),
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
},
);
}
Stream<WorkspaceListState> _openWorkspace(Workspace workspace) async* {
final result = await repo.openWorkspace(workspace.id);
yield result.fold(
(workspaces) => state.copyWith(successOrFailure: left(unit)),
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
},
);
}
Stream<WorkspaceListState> _createWorkspace(String name, String desc) async* {
final result = await repo.createWorkspace(name, desc);
yield result.fold(
(workspace) {
add(const WorkspaceListEvent.fetchWorkspaces());
return state.copyWith(successOrFailure: left(unit));
},
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
},
);
}
}
@freezed
abstract class WorkspaceListEvent with _$WorkspaceListEvent {
const factory WorkspaceListEvent.initial() = Initial;
const factory WorkspaceListEvent.fetchWorkspaces() = FetchWorkspace;
const factory WorkspaceListEvent.createWorkspace(String name, String desc) =
CreateWorkspace;
const factory WorkspaceListEvent.openWorkspace(Workspace workspace) =
OpenWorkspace;
}
@freezed
abstract class WorkspaceListState implements _$WorkspaceListState {
const factory WorkspaceListState({
required bool isLoading,
required List<Workspace> workspaces,
required Either<Unit, WorkspaceError> successOrFailure,
}) = _WorkspaceListState;
factory WorkspaceListState.initial() => WorkspaceListState(
isLoading: false,
workspaces: List.empty(),
successOrFailure: left(unit),
);
}

View file

@ -8,9 +8,7 @@ export 'package:flowy_sdk/protobuf/flowy-workspace/workspace_create.pb.dart';
export 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart'; export 'package:flowy_sdk/protobuf/flowy-user/errors.pb.dart';
export 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; export 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
typedef UserCreateWorkspaceCallback = void Function( typedef WorkspaceListUpdatedCallback = void Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFailed);
typedef UserDeleteWorkspaceCallback = void Function(
Either<List<Workspace>, WorkspaceError> workspacesOrFailed); Either<List<Workspace>, WorkspaceError> workspacesOrFailed);
abstract class IUser { abstract class IUser {
@ -21,10 +19,9 @@ abstract class IUser {
Future<Either<Unit, UserError>> signOut(); Future<Either<Unit, UserError>> signOut();
} }
abstract class IUserWatch { abstract class IUserWorkspaceListWatch {
void startWatching( void startWatching(
{UserCreateWorkspaceCallback? createWorkspaceCallback, {WorkspaceListUpdatedCallback? workspaceListUpdatedCallback});
UserDeleteWorkspaceCallback? deleteWorkspaceCallback});
Future<void> stopWatching(); Future<void> stopWatching();
} }

View file

@ -2,7 +2,7 @@ import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
typedef ViewUpdatedCallback = void Function(View view); typedef ViewUpdatedCallback = void Function(Either<View, WorkspaceError>);
abstract class IView { abstract class IView {
Future<Either<View, WorkspaceError>> readView(); Future<Either<View, WorkspaceError>> readView();

View file

@ -7,6 +7,7 @@ import 'package:app_flowy/workspace/application/menu/menu_watch.dart';
import 'package:app_flowy/workspace/application/view/doc_watch_bloc.dart'; import 'package:app_flowy/workspace/application/view/doc_watch_bloc.dart';
import 'package:app_flowy/workspace/application/view/view_bloc.dart'; import 'package:app_flowy/workspace/application/view/view_bloc.dart';
import 'package:app_flowy/workspace/application/view/view_list_bloc.dart'; import 'package:app_flowy/workspace/application/view/view_list_bloc.dart';
import 'package:app_flowy/workspace/application/workspace/welcome_bloc.dart';
import 'package:app_flowy/workspace/domain/i_doc.dart'; import 'package:app_flowy/workspace/domain/i_doc.dart';
import 'package:app_flowy/workspace/domain/i_view.dart'; import 'package:app_flowy/workspace/domain/i_view.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
@ -57,8 +58,9 @@ class HomeDepsResolver {
// User // User
getIt.registerFactoryParam<IUser, UserProfile, void>( getIt.registerFactoryParam<IUser, UserProfile, void>(
(user, _) => IUserImpl(repo: UserRepo(user: user))); (user, _) => IUserImpl(repo: UserRepo(user: user)));
getIt.registerFactoryParam<IUserWatch, UserProfile, void>( getIt.registerFactoryParam<IUserWorkspaceListWatch, UserProfile, void>(
(user, _) => IUserWatchImpl(repo: UserWatchRepo(user: user))); (user, _) =>
IUserWorkspaceListWatchImpl(repo: UserWatchRepo(user: user)));
//Menu Bloc //Menu Bloc
getIt.registerFactoryParam<MenuBloc, UserProfile, String>( getIt.registerFactoryParam<MenuBloc, UserProfile, String>(
@ -93,6 +95,13 @@ class HomeDepsResolver {
getIt.registerFactoryParam<ViewListBloc, List<View>, void>( getIt.registerFactoryParam<ViewListBloc, List<View>, void>(
(views, _) => ViewListBloc(views: views)); (views, _) => ViewListBloc(views: views));
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
(user, _) => WelcomeBloc(
repo: UserRepo(user: user),
watcher: getIt<IUserWorkspaceListWatch>(param1: user),
),
);
// getIt.registerFactoryParam<ViewBloc, String, void>( // getIt.registerFactoryParam<ViewBloc, String, void>(
// (viewId, _) => ViewBloc(iViewImpl: getIt<IView>(param1: viewId))); // (viewId, _) => ViewBloc(iViewImpl: getIt<IView>(param1: viewId)));
} }

View file

@ -31,22 +31,20 @@ class IUserImpl extends IUser {
@override @override
Future<Either<List<Workspace>, WorkspaceError>> fetchWorkspaces() { Future<Either<List<Workspace>, WorkspaceError>> fetchWorkspaces() {
return repo.fetchWorkspaces(); return repo.getWorkspaces();
} }
} }
class IUserWatchImpl extends IUserWatch { class IUserWorkspaceListWatchImpl extends IUserWorkspaceListWatch {
UserWatchRepo repo; UserWatchRepo repo;
IUserWatchImpl({ IUserWorkspaceListWatchImpl({
required this.repo, required this.repo,
}); });
@override @override
void startWatching( void startWatching({
{UserCreateWorkspaceCallback? createWorkspaceCallback, WorkspaceListUpdatedCallback? workspaceListUpdatedCallback,
UserDeleteWorkspaceCallback? deleteWorkspaceCallback}) { }) {
repo.startWatching( repo.startWatching(workspaceListUpdated: workspaceListUpdatedCallback);
createWorkspace: createWorkspaceCallback,
deleteWorkspace: deleteWorkspaceCallback);
} }
@override @override

View file

@ -20,9 +20,9 @@ class IWorkspaceImpl extends IWorkspace {
@override @override
Future<Either<List<App>, WorkspaceError>> getApps() { Future<Either<List<App>, WorkspaceError>> getApps() {
return repo.getWorkspace().then((result) { return repo.getApps().then((result) {
return result.fold( return result.fold(
(workspace) => left(workspace.apps.items), (apps) => left(apps),
(error) => right(error), (error) => right(error),
); );
}); });

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:app_flowy/workspace/domain/i_app.dart'; import 'package:app_flowy/workspace/domain/i_app.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/flowy_logger.dart'; import 'package:flowy_infra/flowy_logger.dart';
@ -11,6 +12,7 @@ import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pbenum.dart';
import 'package:flowy_sdk/rust_stream.dart'; import 'package:flowy_sdk/rust_stream.dart';
import 'helper.dart';
class AppRepository { class AppRepository {
String appId; String appId;
@ -56,13 +58,12 @@ class AppWatchRepository {
AppCreateViewCallback? _createView; AppCreateViewCallback? _createView;
AppDeleteViewCallback? _deleteView; AppDeleteViewCallback? _deleteView;
AppUpdatedCallback? _update; AppUpdatedCallback? _update;
late ObservableExtractor _extractor;
String appId; String appId;
late AppRepository _repo;
AppWatchRepository({ AppWatchRepository({
required this.appId, required this.appId,
}) { });
_repo = AppRepository(appId: appId);
}
void startWatching( void startWatching(
{AppCreateViewCallback? createView, {AppCreateViewCallback? createView,
@ -71,52 +72,48 @@ class AppWatchRepository {
_createView = createView; _createView = createView;
_deleteView = deleteView; _deleteView = deleteView;
_update = update; _update = update;
_subscription = RustStreamReceiver.listen((observable) { _extractor = ObservableExtractor(
if (observable.subjectId != appId) { id: appId,
return; callback: (ty, result) => _handleObservableType(ty, result),
} );
_subscription =
final ty = WorkspaceObservable.valueOf(observable.ty); RustStreamReceiver.listen((observable) => _extractor.parse(observable));
if (ty != null) {
_handleObservableType(ty);
}
});
} }
void _handleObservableType(WorkspaceObservable ty) { void _handleObservableType(
WorkspaceObservable ty, Either<Uint8List, WorkspaceError> result) {
switch (ty) { switch (ty) {
case WorkspaceObservable.AppCreateView: case WorkspaceObservable.AppCreateView:
if (_createView == null) { if (_createView != null) {
return;
}
_repo.getViews().then((result) {
result.fold( result.fold(
(views) => _createView!(left(views)), (payload) {
final repeatedView = RepeatedView.fromBuffer(payload);
_createView!(left(repeatedView.items));
},
(error) => _createView!(right(error)), (error) => _createView!(right(error)),
); );
}); }
break; break;
case WorkspaceObservable.AppDeleteView: case WorkspaceObservable.AppDeleteView:
if (_deleteView == null) { if (_deleteView != null) {
return;
}
_repo.getViews().then((result) {
result.fold( result.fold(
(views) => _deleteView!(left(views)), (payload) => _deleteView!(
left(RepeatedView.fromBuffer(payload).items),
),
(error) => _deleteView!(right(error)), (error) => _deleteView!(right(error)),
); );
}); }
break; break;
case WorkspaceObservable.AppUpdated: case WorkspaceObservable.AppUpdated:
if (_update == null) { if (_update != null) {
return;
}
_repo.getAppDesc().then((result) {
result.fold( result.fold(
(app) => _update!(app.name, app.desc), (payload) {
final app = App.fromBuffer(payload);
_update!(app.name, app.desc);
},
(error) => Log.error(error), (error) => Log.error(error),
); );
}); }
break; break;
default: default:
break; break;

View file

@ -0,0 +1,35 @@
import 'dart:typed_data';
import 'package:flowy_sdk/protobuf/flowy-observable/protobuf.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart';
import 'package:dartz/dartz.dart';
class ObservableExtractor {
String id;
void Function(WorkspaceObservable, Either<Uint8List, WorkspaceError>)
callback;
ObservableExtractor({required this.id, required this.callback});
void parse(ObservableSubject subject) {
if (subject.id != id) {
return;
}
final ty = WorkspaceObservable.valueOf(subject.ty);
if (ty == null) {
return;
}
if (subject.hasPayload()) {
final bytes = Uint8List.fromList(subject.error);
callback(ty, left(bytes));
} else if (subject.hasError()) {
final bytes = Uint8List.fromList(subject.error);
final error = WorkspaceError.fromBuffer(bytes);
callback(ty, right(error));
} else {
// do nothing
}
}
}

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
@ -32,7 +33,7 @@ class UserRepo {
return UserEventSignOut().send(); return UserEventSignOut().send();
} }
Future<Either<List<Workspace>, WorkspaceError>> fetchWorkspaces() { Future<Either<List<Workspace>, WorkspaceError>> getWorkspaces() {
final request = QueryWorkspaceRequest.create(); final request = QueryWorkspaceRequest.create();
return WorkspaceEventReadWorkspaces(request).send().then((result) { return WorkspaceEventReadWorkspaces(request).send().then((result) {
@ -69,8 +70,7 @@ class UserRepo {
class UserWatchRepo { class UserWatchRepo {
StreamSubscription<ObservableSubject>? _subscription; StreamSubscription<ObservableSubject>? _subscription;
UserCreateWorkspaceCallback? _createWorkspace; WorkspaceListUpdatedCallback? _workspaceListUpdated;
UserDeleteWorkspaceCallback? _deleteWorkspace;
late UserRepo _repo; late UserRepo _repo;
UserWatchRepo({ UserWatchRepo({
required UserProfile user, required UserProfile user,
@ -78,19 +78,16 @@ class UserWatchRepo {
_repo = UserRepo(user: user); _repo = UserRepo(user: user);
} }
void startWatching( void startWatching({WorkspaceListUpdatedCallback? workspaceListUpdated}) {
{UserCreateWorkspaceCallback? createWorkspace, _workspaceListUpdated = workspaceListUpdated;
UserDeleteWorkspaceCallback? deleteWorkspace}) {
_createWorkspace = createWorkspace;
_deleteWorkspace = deleteWorkspace;
_subscription = RustStreamReceiver.listen((observable) { _subscription = RustStreamReceiver.listen((observable) {
if (observable.subjectId != _repo.user.id) { if (observable.id != _repo.user.id) {
return; return;
} }
final ty = WorkspaceObservable.valueOf(observable.ty); final ty = WorkspaceObservable.valueOf(observable.ty);
if (ty != null) { if (ty != null) {
_handleObservableType(ty); _handleObservableType(ty, Uint8List.fromList(observable.payload));
} }
}); });
} }
@ -99,31 +96,23 @@ class UserWatchRepo {
await _subscription?.cancel(); await _subscription?.cancel();
} }
void _handleObservableType(WorkspaceObservable ty) { void _handleObservableType(WorkspaceObservable ty, Uint8List payload) {
if (_workspaceListUpdated == null) {
return;
}
switch (ty) { switch (ty) {
case WorkspaceObservable.UserCreateWorkspace: case WorkspaceObservable.UserCreateWorkspace:
if (_createWorkspace == null) {
return;
}
_repo.fetchWorkspaces().then((result) {
result.fold(
(workspaces) => _createWorkspace!(left(workspaces)),
(error) => _createWorkspace!(right(error)),
);
});
break;
case WorkspaceObservable.UserDeleteWorkspace: case WorkspaceObservable.UserDeleteWorkspace:
if (_deleteWorkspace == null) { case WorkspaceObservable.WorkspaceListUpdated:
if (_workspaceListUpdated == null) {
return; return;
} }
_repo.fetchWorkspaces().then((result) {
result.fold(
(workspaces) => _deleteWorkspace!(left(workspaces)),
(error) => _deleteWorkspace!(right(error)),
);
});
break;
final workspaces = RepeatedWorkspace.fromBuffer(payload);
_workspaceListUpdated!(left(workspaces.items));
break;
default: default:
break; break;
} }

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/flowy_logger.dart'; import 'package:flowy_infra/flowy_logger.dart';
@ -12,6 +13,8 @@ import 'package:flowy_sdk/rust_stream.dart';
import 'package:app_flowy/workspace/domain/i_view.dart'; import 'package:app_flowy/workspace/domain/i_view.dart';
import 'helper.dart';
class ViewRepository { class ViewRepository {
View view; View view;
ViewRepository({ ViewRepository({
@ -27,42 +30,41 @@ class ViewRepository {
class ViewWatchRepository { class ViewWatchRepository {
StreamSubscription<ObservableSubject>? _subscription; StreamSubscription<ObservableSubject>? _subscription;
ViewUpdatedCallback? _update; ViewUpdatedCallback? _update;
late ObservableExtractor _extractor;
View view; View view;
late ViewRepository _repo;
ViewWatchRepository({ ViewWatchRepository({
required this.view, required this.view,
}) { });
_repo = ViewRepository(view: view);
}
void startWatching({ void startWatching({
ViewUpdatedCallback? update, ViewUpdatedCallback? update,
}) { }) {
_update = update; _update = update;
_subscription = RustStreamReceiver.listen((observable) { _extractor = ObservableExtractor(
if (observable.subjectId != view.id) { id: view.id,
return; callback: (ty, result) {
} _handleObservableType(ty, result);
},
);
final ty = WorkspaceObservable.valueOf(observable.ty); _subscription =
if (ty != null) { RustStreamReceiver.listen((observable) => _extractor.parse(observable));
_handleObservableType(ty);
}
});
} }
void _handleObservableType(WorkspaceObservable ty) { void _handleObservableType(
WorkspaceObservable ty, Either<Uint8List, WorkspaceError> result) {
switch (ty) { switch (ty) {
case WorkspaceObservable.ViewUpdated: case WorkspaceObservable.ViewUpdated:
if (_update == null) { if (_update != null) {
return;
}
_repo.readView().then((result) {
result.fold( result.fold(
(view) => _update!(view), (payload) {
(error) => Log.error(error), final view = View.fromBuffer(payload);
_update!(left(view));
},
(error) => _update!(right(error)),
); );
}); }
break; break;
default: default:
break; break;

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_infra/flowy_logger.dart'; import 'package:flowy_infra/flowy_logger.dart';
@ -14,6 +15,8 @@ import 'package:flowy_sdk/rust_stream.dart';
import 'package:app_flowy/workspace/domain/i_workspace.dart'; import 'package:app_flowy/workspace/domain/i_workspace.dart';
import 'helper.dart';
class WorkspaceRepo { class WorkspaceRepo {
UserProfile user; UserProfile user;
String workspaceId; String workspaceId;
@ -23,25 +26,15 @@ class WorkspaceRepo {
}); });
Future<Either<App, WorkspaceError>> createApp(String appName, String desc) { Future<Either<App, WorkspaceError>> createApp(String appName, String desc) {
return WorkspaceEventReadCurWorkspace().send().then((result) { final request = CreateAppRequest.create()
return result.fold( ..name = appName
(workspace) { ..workspaceId = workspaceId
final request = CreateAppRequest.create() ..desc = desc;
..name = appName return WorkspaceEventCreateApp(request).send();
..workspaceId = workspace.id
..desc = desc;
return WorkspaceEventCreateApp(request).send();
},
(error) {
return right(error);
},
);
});
} }
Future<Either<Workspace, WorkspaceError>> getWorkspace() { Future<Either<Workspace, WorkspaceError>> getWorkspace() {
final request = QueryWorkspaceRequest.create()..workspaceId = workspaceId; final request = QueryWorkspaceRequest.create()..workspaceId = workspaceId;
return WorkspaceEventReadWorkspaces(request).send().then((result) { return WorkspaceEventReadWorkspaces(request).send().then((result) {
return result.fold( return result.fold(
(workspaces) { (workspaces) {
@ -57,6 +50,16 @@ class WorkspaceRepo {
); );
}); });
} }
Future<Either<List<App>, WorkspaceError>> getApps() {
final request = QueryWorkspaceRequest.create()..workspaceId = workspaceId;
return WorkspaceEventReadWorkspaceApps(request).send().then((result) {
return result.fold(
(apps) => left(apps.items),
(error) => right(error),
);
});
}
} }
class WorkspaceWatchRepo { class WorkspaceWatchRepo {
@ -64,16 +67,14 @@ class WorkspaceWatchRepo {
WorkspaceCreateAppCallback? _createApp; WorkspaceCreateAppCallback? _createApp;
WorkspaceDeleteAppCallback? _deleteApp; WorkspaceDeleteAppCallback? _deleteApp;
WorkspaceUpdatedCallback? _update; WorkspaceUpdatedCallback? _update;
late ObservableExtractor _extractor;
final UserProfile user; final UserProfile user;
final String workspaceId; final String workspaceId;
late WorkspaceRepo _repo;
WorkspaceWatchRepo({ WorkspaceWatchRepo({
required this.user, required this.user,
required this.workspaceId, required this.workspaceId,
}) { });
_repo = WorkspaceRepo(user: user, workspaceId: workspaceId);
}
void startWatching({ void startWatching({
WorkspaceCreateAppCallback? createApp, WorkspaceCreateAppCallback? createApp,
@ -84,54 +85,50 @@ class WorkspaceWatchRepo {
_deleteApp = deleteApp; _deleteApp = deleteApp;
_update = update; _update = update;
_subscription = RustStreamReceiver.listen((observable) { _extractor = ObservableExtractor(
if (observable.subjectId != workspaceId) { id: workspaceId,
return; callback: (ty, result) {
} _handleObservableType(ty, result);
},
);
final ty = WorkspaceObservable.valueOf(observable.ty); _subscription =
if (ty != null) { RustStreamReceiver.listen((observable) => _extractor.parse(observable));
_handleObservableType(ty);
}
});
} }
void _handleObservableType(WorkspaceObservable ty) { void _handleObservableType(
WorkspaceObservable ty, Either<Uint8List, WorkspaceError> result) {
switch (ty) { switch (ty) {
case WorkspaceObservable.WorkspaceUpdated: case WorkspaceObservable.WorkspaceUpdated:
if (_update == null) { if (_update != null) {
return;
}
_repo.getWorkspace().then((result) {
result.fold( result.fold(
(workspace) => _update!(workspace.name, workspace.desc), (payload) {
final workspace = Workspace.fromBuffer(payload);
_update!(workspace.name, workspace.desc);
},
(error) => Log.error(error), (error) => Log.error(error),
); );
}); }
break; break;
case WorkspaceObservable.WorkspaceCreateApp: case WorkspaceObservable.WorkspaceCreateApp:
if (_createApp == null) { if (_createApp != null) {
return;
}
_repo.getWorkspace().then((result) {
result.fold( result.fold(
(workspace) => _createApp!(left(workspace.apps.items)), (payload) => _createApp!(
left(RepeatedApp.fromBuffer(payload).items),
),
(error) => _createApp!(right(error)), (error) => _createApp!(right(error)),
); );
}); }
break; break;
case WorkspaceObservable.WorkspaceDeleteApp: case WorkspaceObservable.WorkspaceDeleteApp:
if (_deleteApp == null) { if (_deleteApp != null) {
return;
}
_repo.getWorkspace().then((result) {
result.fold( result.fold(
(workspace) => _deleteApp!(left(workspace.apps.items)), (payload) => _deleteApp!(
left(RepeatedApp.fromBuffer(payload).items),
),
(error) => _deleteApp!(right(error)), (error) => _deleteApp!(right(error)),
); );
}); }
break; break;
default: default:
break; break;

View file

@ -84,6 +84,23 @@ class WorkspaceEventOpenWorkspace {
} }
} }
class WorkspaceEventReadWorkspaceApps {
QueryWorkspaceRequest request;
WorkspaceEventReadWorkspaceApps(this.request);
Future<Either<RepeatedApp, WorkspaceError>> send() {
final request = FFIRequest.create()
..event = WorkspaceEvent.ReadWorkspaceApps.toString()
..payload = requestToBytes(this.request);
return Dispatch.asyncRequest(request)
.then((bytesResult) => bytesResult.fold(
(okBytes) => left(RepeatedApp.fromBuffer(okBytes)),
(errBytes) => right(WorkspaceError.fromBuffer(errBytes)),
));
}
}
class WorkspaceEventCreateApp { class WorkspaceEventCreateApp {
CreateAppRequest request; CreateAppRequest request;
WorkspaceEventCreateApp(this.request); WorkspaceEventCreateApp(this.request);

View file

@ -9,22 +9,33 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb; import 'package:protobuf/protobuf.dart' as $pb;
enum ObservableSubject_OneOfSubjectPayload { enum ObservableSubject_OneOfPayload {
subjectPayload, payload,
notSet
}
enum ObservableSubject_OneOfError {
error,
notSet notSet
} }
class ObservableSubject extends $pb.GeneratedMessage { class ObservableSubject extends $pb.GeneratedMessage {
static const $core.Map<$core.int, ObservableSubject_OneOfSubjectPayload> _ObservableSubject_OneOfSubjectPayloadByTag = { static const $core.Map<$core.int, ObservableSubject_OneOfPayload> _ObservableSubject_OneOfPayloadByTag = {
4 : ObservableSubject_OneOfSubjectPayload.subjectPayload, 4 : ObservableSubject_OneOfPayload.payload,
0 : ObservableSubject_OneOfSubjectPayload.notSet 0 : ObservableSubject_OneOfPayload.notSet
};
static const $core.Map<$core.int, ObservableSubject_OneOfError> _ObservableSubject_OneOfErrorByTag = {
5 : ObservableSubject_OneOfError.error,
0 : ObservableSubject_OneOfError.notSet
}; };
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ObservableSubject', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'ObservableSubject', createEmptyInstance: create)
..oo(0, [4]) ..oo(0, [4])
..oo(1, [5])
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'category') ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'category')
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.O3) ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.O3)
..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'subjectId') ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id')
..a<$core.List<$core.int>>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'subjectPayload', $pb.PbFieldType.OY) ..a<$core.List<$core.int>>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'payload', $pb.PbFieldType.OY)
..a<$core.List<$core.int>>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'error', $pb.PbFieldType.OY)
..hasRequiredFields = false ..hasRequiredFields = false
; ;
@ -32,8 +43,9 @@ class ObservableSubject extends $pb.GeneratedMessage {
factory ObservableSubject({ factory ObservableSubject({
$core.String? category, $core.String? category,
$core.int? ty, $core.int? ty,
$core.String? subjectId, $core.String? id,
$core.List<$core.int>? subjectPayload, $core.List<$core.int>? payload,
$core.List<$core.int>? error,
}) { }) {
final _result = create(); final _result = create();
if (category != null) { if (category != null) {
@ -42,11 +54,14 @@ class ObservableSubject extends $pb.GeneratedMessage {
if (ty != null) { if (ty != null) {
_result.ty = ty; _result.ty = ty;
} }
if (subjectId != null) { if (id != null) {
_result.subjectId = subjectId; _result.id = id;
} }
if (subjectPayload != null) { if (payload != null) {
_result.subjectPayload = subjectPayload; _result.payload = payload;
}
if (error != null) {
_result.error = error;
} }
return _result; return _result;
} }
@ -71,8 +86,11 @@ class ObservableSubject extends $pb.GeneratedMessage {
static ObservableSubject getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ObservableSubject>(create); static ObservableSubject getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ObservableSubject>(create);
static ObservableSubject? _defaultInstance; static ObservableSubject? _defaultInstance;
ObservableSubject_OneOfSubjectPayload whichOneOfSubjectPayload() => _ObservableSubject_OneOfSubjectPayloadByTag[$_whichOneof(0)]!; ObservableSubject_OneOfPayload whichOneOfPayload() => _ObservableSubject_OneOfPayloadByTag[$_whichOneof(0)]!;
void clearOneOfSubjectPayload() => clearField($_whichOneof(0)); void clearOneOfPayload() => clearField($_whichOneof(0));
ObservableSubject_OneOfError whichOneOfError() => _ObservableSubject_OneOfErrorByTag[$_whichOneof(1)]!;
void clearOneOfError() => clearField($_whichOneof(1));
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.String get category => $_getSZ(0); $core.String get category => $_getSZ(0);
@ -93,21 +111,30 @@ class ObservableSubject extends $pb.GeneratedMessage {
void clearTy() => clearField(2); void clearTy() => clearField(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
$core.String get subjectId => $_getSZ(2); $core.String get id => $_getSZ(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
set subjectId($core.String v) { $_setString(2, v); } set id($core.String v) { $_setString(2, v); }
@$pb.TagNumber(3) @$pb.TagNumber(3)
$core.bool hasSubjectId() => $_has(2); $core.bool hasId() => $_has(2);
@$pb.TagNumber(3) @$pb.TagNumber(3)
void clearSubjectId() => clearField(3); void clearId() => clearField(3);
@$pb.TagNumber(4) @$pb.TagNumber(4)
$core.List<$core.int> get subjectPayload => $_getN(3); $core.List<$core.int> get payload => $_getN(3);
@$pb.TagNumber(4) @$pb.TagNumber(4)
set subjectPayload($core.List<$core.int> v) { $_setBytes(3, v); } set payload($core.List<$core.int> v) { $_setBytes(3, v); }
@$pb.TagNumber(4) @$pb.TagNumber(4)
$core.bool hasSubjectPayload() => $_has(3); $core.bool hasPayload() => $_has(3);
@$pb.TagNumber(4) @$pb.TagNumber(4)
void clearSubjectPayload() => clearField(4); void clearPayload() => clearField(4);
@$pb.TagNumber(5)
$core.List<$core.int> get error => $_getN(4);
@$pb.TagNumber(5)
set error($core.List<$core.int> v) { $_setBytes(4, v); }
@$pb.TagNumber(5)
$core.bool hasError() => $_has(4);
@$pb.TagNumber(5)
void clearError() => clearField(5);
} }

View file

@ -14,13 +14,15 @@ const ObservableSubject$json = const {
'2': const [ '2': const [
const {'1': 'category', '3': 1, '4': 1, '5': 9, '10': 'category'}, const {'1': 'category', '3': 1, '4': 1, '5': 9, '10': 'category'},
const {'1': 'ty', '3': 2, '4': 1, '5': 5, '10': 'ty'}, const {'1': 'ty', '3': 2, '4': 1, '5': 5, '10': 'ty'},
const {'1': 'subject_id', '3': 3, '4': 1, '5': 9, '10': 'subjectId'}, const {'1': 'id', '3': 3, '4': 1, '5': 9, '10': 'id'},
const {'1': 'subject_payload', '3': 4, '4': 1, '5': 12, '9': 0, '10': 'subjectPayload'}, const {'1': 'payload', '3': 4, '4': 1, '5': 12, '9': 0, '10': 'payload'},
const {'1': 'error', '3': 5, '4': 1, '5': 12, '9': 1, '10': 'error'},
], ],
'8': const [ '8': const [
const {'1': 'one_of_subject_payload'}, const {'1': 'one_of_payload'},
const {'1': 'one_of_error'},
], ],
}; };
/// Descriptor for `ObservableSubject`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `ObservableSubject`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List observableSubjectDescriptor = $convert.base64Decode('ChFPYnNlcnZhYmxlU3ViamVjdBIaCghjYXRlZ29yeRgBIAEoCVIIY2F0ZWdvcnkSDgoCdHkYAiABKAVSAnR5Eh0KCnN1YmplY3RfaWQYAyABKAlSCXN1YmplY3RJZBIpCg9zdWJqZWN0X3BheWxvYWQYBCABKAxIAFIOc3ViamVjdFBheWxvYWRCGAoWb25lX29mX3N1YmplY3RfcGF5bG9hZA=='); final $typed_data.Uint8List observableSubjectDescriptor = $convert.base64Decode('ChFPYnNlcnZhYmxlU3ViamVjdBIaCghjYXRlZ29yeRgBIAEoCVIIY2F0ZWdvcnkSDgoCdHkYAiABKAVSAnR5Eg4KAmlkGAMgASgJUgJpZBIaCgdwYXlsb2FkGAQgASgMSABSB3BheWxvYWQSFgoFZXJyb3IYBSABKAxIAVIFZXJyb3JCEAoOb25lX29mX3BheWxvYWRCDgoMb25lX29mX2Vycm9y');

View file

@ -15,6 +15,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
static const WorkspaceEvent ReadWorkspaces = WorkspaceEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadWorkspaces'); static const WorkspaceEvent ReadWorkspaces = WorkspaceEvent._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadWorkspaces');
static const WorkspaceEvent DeleteWorkspace = WorkspaceEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteWorkspace'); static const WorkspaceEvent DeleteWorkspace = WorkspaceEvent._(3, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteWorkspace');
static const WorkspaceEvent OpenWorkspace = WorkspaceEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenWorkspace'); static const WorkspaceEvent OpenWorkspace = WorkspaceEvent._(4, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'OpenWorkspace');
static const WorkspaceEvent ReadWorkspaceApps = WorkspaceEvent._(5, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadWorkspaceApps');
static const WorkspaceEvent CreateApp = WorkspaceEvent._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateApp'); static const WorkspaceEvent CreateApp = WorkspaceEvent._(101, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateApp');
static const WorkspaceEvent DeleteApp = WorkspaceEvent._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteApp'); static const WorkspaceEvent DeleteApp = WorkspaceEvent._(102, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteApp');
static const WorkspaceEvent ReadApp = WorkspaceEvent._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadApp'); static const WorkspaceEvent ReadApp = WorkspaceEvent._(103, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadApp');
@ -30,6 +31,7 @@ class WorkspaceEvent extends $pb.ProtobufEnum {
ReadWorkspaces, ReadWorkspaces,
DeleteWorkspace, DeleteWorkspace,
OpenWorkspace, OpenWorkspace,
ReadWorkspaceApps,
CreateApp, CreateApp,
DeleteApp, DeleteApp,
ReadApp, ReadApp,

View file

@ -17,6 +17,7 @@ const WorkspaceEvent$json = const {
const {'1': 'ReadWorkspaces', '2': 2}, const {'1': 'ReadWorkspaces', '2': 2},
const {'1': 'DeleteWorkspace', '2': 3}, const {'1': 'DeleteWorkspace', '2': 3},
const {'1': 'OpenWorkspace', '2': 4}, const {'1': 'OpenWorkspace', '2': 4},
const {'1': 'ReadWorkspaceApps', '2': 5},
const {'1': 'CreateApp', '2': 101}, const {'1': 'CreateApp', '2': 101},
const {'1': 'DeleteApp', '2': 102}, const {'1': 'DeleteApp', '2': 102},
const {'1': 'ReadApp', '2': 103}, const {'1': 'ReadApp', '2': 103},
@ -29,4 +30,4 @@ const WorkspaceEvent$json = const {
}; };
/// Descriptor for `WorkspaceEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. /// Descriptor for `WorkspaceEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSDQoJQ3JlYXRlQXBwEGUSDQoJRGVsZXRlQXBwEGYSCwoHUmVhZEFwcBBnEg0KCVVwZGF0ZUFwcBBoEg8KCkNyZWF0ZVZpZXcQyQESDQoIUmVhZFZpZXcQygESDwoKVXBkYXRlVmlldxDLARIPCgpEZWxldGVWaWV3EMwB'); final $typed_data.Uint8List workspaceEventDescriptor = $convert.base64Decode('Cg5Xb3Jrc3BhY2VFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAE=');

View file

@ -1,14 +1,77 @@
#[rustfmt::skip]
/*
diesel master support on_conflict on sqlite but not 1.4.7 version. Workaround for this
match dsl::workspace_table
.filter(workspace_table::id.eq(table.id.clone()))
.count()
.get_result(conn)
.unwrap_or(0)
{
0 => diesel::insert_into(workspace_table::table).values(table)
.on_conflict(workspace_table::id)
.do_update()
.set(WorkspaceTableChangeset::from_table(workspace_table))
.execute(conn)?,
_ => {
let changeset = WorkspaceTableChangeset::from_table(table);
let filter = dsl::workspace_table.filter(workspace_table::id.eq(changeset.id.clone()));
diesel::update(filter).set(changeset).execute(conn)?;
},
}
is equivalent to:
match diesel_record_count!(workspace_table, &table.id, conn) {
0 => diesel_insert_table!(workspace_table, table, conn),
_ => diesel_update_table!(workspace_table, WorkspaceTableChangeset::from_table(table), &*conn),
}
*/
#[macro_export]
macro_rules! diesel_insert_table {
(
$table_name:ident,
$table:expr,
$connection:expr
) => {
{
let _ = diesel::insert_into($table_name::table)
.values($table.clone())
// .on_conflict($table_name::dsl::id)
// .do_update()
// .set(WorkspaceTableChangeset::from_table(workspace_table))
.execute($connection)?;
}
};
}
#[macro_export]
macro_rules! diesel_record_count {
(
$table_name:ident,
$id:expr,
$connection:expr
) => {
$table_name::dsl::$table_name
.filter($table_name::dsl::id.eq($id.clone()))
.count()
.get_result($connection)
.unwrap_or(0);
};
}
#[macro_export] #[macro_export]
macro_rules! diesel_update_table { macro_rules! diesel_update_table {
( (
$table_name:ident, $table_name:ident,
$changeset:ident, $changeset:expr,
$connection:expr $connection:expr
) => { ) => {{
let filter = $table_name::dsl::$table_name.filter($table_name::dsl::id.eq($changeset.id.clone())); let filter = $table_name::dsl::$table_name.filter($table_name::dsl::id.eq($changeset.id.clone()));
let affected_row = diesel::update(filter).set($changeset).execute(&*$connection)?; let affected_row = diesel::update(filter).set($changeset).execute($connection)?;
debug_assert_eq!(affected_row, 1); debug_assert_eq!(affected_row, 1);
}; }};
} }
#[macro_export] #[macro_export]

View file

@ -16,15 +16,13 @@ pub struct DocTableSql {
impl DocTableSql { impl DocTableSql {
pub(crate) fn create_doc_table(&self, doc_table: DocTable) -> Result<(), DocError> { pub(crate) fn create_doc_table(&self, doc_table: DocTable) -> Result<(), DocError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
let _ = diesel::insert_into(doc_table::table) let _ = diesel::insert_into(doc_table::table).values(doc_table).execute(&*conn)?;
.values(doc_table)
.execute(&*conn)?;
Ok(()) Ok(())
} }
pub(crate) fn update_doc_table(&self, changeset: DocTableChangeset) -> Result<(), DocError> { pub(crate) fn update_doc_table(&self, changeset: DocTableChangeset) -> Result<(), DocError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
diesel_update_table!(doc_table, changeset, conn); diesel_update_table!(doc_table, changeset, &*conn);
Ok(()) Ok(())
} }

View file

@ -9,10 +9,13 @@ pub struct ObservableSubject {
pub ty: i32, pub ty: i32,
#[pb(index = 3)] #[pb(index = 3)]
pub subject_id: String, pub id: String,
#[pb(index = 4, one_of)] #[pb(index = 4, one_of)]
pub subject_payload: Option<Vec<u8>>, pub payload: Option<Vec<u8>>,
#[pb(index = 5, one_of)]
pub error: Option<Vec<u8>>,
} }
impl std::default::Default for ObservableSubject { impl std::default::Default for ObservableSubject {
@ -20,8 +23,9 @@ impl std::default::Default for ObservableSubject {
Self { Self {
category: "".to_string(), category: "".to_string(),
ty: 0, ty: 0,
subject_id: "".to_string(), id: "".to_string(),
subject_payload: None, payload: None,
error: None,
} }
} }
} }

View file

@ -28,9 +28,10 @@ pub struct ObservableSubject {
// message fields // message fields
pub category: ::std::string::String, pub category: ::std::string::String,
pub ty: i32, pub ty: i32,
pub subject_id: ::std::string::String, pub id: ::std::string::String,
// message oneof groups // message oneof groups
pub one_of_subject_payload: ::std::option::Option<ObservableSubject_oneof_one_of_subject_payload>, pub one_of_payload: ::std::option::Option<ObservableSubject_oneof_one_of_payload>,
pub one_of_error: ::std::option::Option<ObservableSubject_oneof_one_of_error>,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -43,8 +44,13 @@ impl<'a> ::std::default::Default for &'a ObservableSubject {
} }
#[derive(Clone,PartialEq,Debug)] #[derive(Clone,PartialEq,Debug)]
pub enum ObservableSubject_oneof_one_of_subject_payload { pub enum ObservableSubject_oneof_one_of_payload {
subject_payload(::std::vec::Vec<u8>), payload(::std::vec::Vec<u8>),
}
#[derive(Clone,PartialEq,Debug)]
pub enum ObservableSubject_oneof_one_of_error {
error(::std::vec::Vec<u8>),
} }
impl ObservableSubject { impl ObservableSubject {
@ -93,74 +99,123 @@ impl ObservableSubject {
self.ty = v; self.ty = v;
} }
// string subject_id = 3; // string id = 3;
pub fn get_subject_id(&self) -> &str { pub fn get_id(&self) -> &str {
&self.subject_id &self.id
} }
pub fn clear_subject_id(&mut self) { pub fn clear_id(&mut self) {
self.subject_id.clear(); self.id.clear();
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_subject_id(&mut self, v: ::std::string::String) { pub fn set_id(&mut self, v: ::std::string::String) {
self.subject_id = v; self.id = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_subject_id(&mut self) -> &mut ::std::string::String { pub fn mut_id(&mut self) -> &mut ::std::string::String {
&mut self.subject_id &mut self.id
} }
// Take field // Take field
pub fn take_subject_id(&mut self) -> ::std::string::String { pub fn take_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.subject_id, ::std::string::String::new()) ::std::mem::replace(&mut self.id, ::std::string::String::new())
} }
// bytes subject_payload = 4; // bytes payload = 4;
pub fn get_subject_payload(&self) -> &[u8] { pub fn get_payload(&self) -> &[u8] {
match self.one_of_subject_payload { match self.one_of_payload {
::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref v)) => v, ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(ref v)) => v,
_ => &[], _ => &[],
} }
} }
pub fn clear_subject_payload(&mut self) { pub fn clear_payload(&mut self) {
self.one_of_subject_payload = ::std::option::Option::None; self.one_of_payload = ::std::option::Option::None;
} }
pub fn has_subject_payload(&self) -> bool { pub fn has_payload(&self) -> bool {
match self.one_of_subject_payload { match self.one_of_payload {
::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(..)) => true, ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(..)) => true,
_ => false, _ => false,
} }
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_subject_payload(&mut self, v: ::std::vec::Vec<u8>) { pub fn set_payload(&mut self, v: ::std::vec::Vec<u8>) {
self.one_of_subject_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(v)) self.one_of_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(v))
} }
// Mutable pointer to the field. // Mutable pointer to the field.
pub fn mut_subject_payload(&mut self) -> &mut ::std::vec::Vec<u8> { pub fn mut_payload(&mut self) -> &mut ::std::vec::Vec<u8> {
if let ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(_)) = self.one_of_subject_payload { if let ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(_)) = self.one_of_payload {
} else { } else {
self.one_of_subject_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(::std::vec::Vec::new())); self.one_of_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(::std::vec::Vec::new()));
} }
match self.one_of_subject_payload { match self.one_of_payload {
::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref mut v)) => v, ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(ref mut v)) => v,
_ => panic!(), _ => panic!(),
} }
} }
// Take field // Take field
pub fn take_subject_payload(&mut self) -> ::std::vec::Vec<u8> { pub fn take_payload(&mut self) -> ::std::vec::Vec<u8> {
if self.has_subject_payload() { if self.has_payload() {
match self.one_of_subject_payload.take() { match self.one_of_payload.take() {
::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(v)) => v, ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(v)) => v,
_ => panic!(),
}
} else {
::std::vec::Vec::new()
}
}
// bytes error = 5;
pub fn get_error(&self) -> &[u8] {
match self.one_of_error {
::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(ref v)) => v,
_ => &[],
}
}
pub fn clear_error(&mut self) {
self.one_of_error = ::std::option::Option::None;
}
pub fn has_error(&self) -> bool {
match self.one_of_error {
::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(..)) => true,
_ => false,
}
}
// Param is passed by value, moved
pub fn set_error(&mut self, v: ::std::vec::Vec<u8>) {
self.one_of_error = ::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(v))
}
// Mutable pointer to the field.
pub fn mut_error(&mut self) -> &mut ::std::vec::Vec<u8> {
if let ::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(_)) = self.one_of_error {
} else {
self.one_of_error = ::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(::std::vec::Vec::new()));
}
match self.one_of_error {
::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(ref mut v)) => v,
_ => panic!(),
}
}
// Take field
pub fn take_error(&mut self) -> ::std::vec::Vec<u8> {
if self.has_error() {
match self.one_of_error.take() {
::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(v)) => v,
_ => panic!(), _ => panic!(),
} }
} else { } else {
@ -189,13 +244,19 @@ impl ::protobuf::Message for ObservableSubject {
self.ty = tmp; self.ty = tmp;
}, },
3 => { 3 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.subject_id)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?;
}, },
4 => { 4 => {
if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
} }
self.one_of_subject_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_subject_payload::subject_payload(is.read_bytes()?)); self.one_of_payload = ::std::option::Option::Some(ObservableSubject_oneof_one_of_payload::payload(is.read_bytes()?));
},
5 => {
if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
self.one_of_error = ::std::option::Option::Some(ObservableSubject_oneof_one_of_error::error(is.read_bytes()?));
}, },
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -215,16 +276,23 @@ impl ::protobuf::Message for ObservableSubject {
if self.ty != 0 { if self.ty != 0 {
my_size += ::protobuf::rt::value_size(2, self.ty, ::protobuf::wire_format::WireTypeVarint); my_size += ::protobuf::rt::value_size(2, self.ty, ::protobuf::wire_format::WireTypeVarint);
} }
if !self.subject_id.is_empty() { if !self.id.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.subject_id); my_size += ::protobuf::rt::string_size(3, &self.id);
} }
if let ::std::option::Option::Some(ref v) = self.one_of_subject_payload { if let ::std::option::Option::Some(ref v) = self.one_of_payload {
match v { match v {
&ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref v) => { &ObservableSubject_oneof_one_of_payload::payload(ref v) => {
my_size += ::protobuf::rt::bytes_size(4, &v); my_size += ::protobuf::rt::bytes_size(4, &v);
}, },
}; };
} }
if let ::std::option::Option::Some(ref v) = self.one_of_error {
match v {
&ObservableSubject_oneof_one_of_error::error(ref v) => {
my_size += ::protobuf::rt::bytes_size(5, &v);
},
};
}
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
@ -237,16 +305,23 @@ impl ::protobuf::Message for ObservableSubject {
if self.ty != 0 { if self.ty != 0 {
os.write_int32(2, self.ty)?; os.write_int32(2, self.ty)?;
} }
if !self.subject_id.is_empty() { if !self.id.is_empty() {
os.write_string(3, &self.subject_id)?; os.write_string(3, &self.id)?;
} }
if let ::std::option::Option::Some(ref v) = self.one_of_subject_payload { if let ::std::option::Option::Some(ref v) = self.one_of_payload {
match v { match v {
&ObservableSubject_oneof_one_of_subject_payload::subject_payload(ref v) => { &ObservableSubject_oneof_one_of_payload::payload(ref v) => {
os.write_bytes(4, v)?; os.write_bytes(4, v)?;
}, },
}; };
} }
if let ::std::option::Option::Some(ref v) = self.one_of_error {
match v {
&ObservableSubject_oneof_one_of_error::error(ref v) => {
os.write_bytes(5, v)?;
},
};
}
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
} }
@ -296,14 +371,19 @@ impl ::protobuf::Message for ObservableSubject {
|m: &mut ObservableSubject| { &mut m.ty }, |m: &mut ObservableSubject| { &mut m.ty },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"subject_id", "id",
|m: &ObservableSubject| { &m.subject_id }, |m: &ObservableSubject| { &m.id },
|m: &mut ObservableSubject| { &mut m.subject_id }, |m: &mut ObservableSubject| { &mut m.id },
)); ));
fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor::<_>( fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor::<_>(
"subject_payload", "payload",
ObservableSubject::has_subject_payload, ObservableSubject::has_payload,
ObservableSubject::get_subject_payload, ObservableSubject::get_payload,
));
fields.push(::protobuf::reflect::accessor::make_singular_bytes_accessor::<_>(
"error",
ObservableSubject::has_error,
ObservableSubject::get_error,
)); ));
::protobuf::reflect::MessageDescriptor::new_pb_name::<ObservableSubject>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<ObservableSubject>(
"ObservableSubject", "ObservableSubject",
@ -323,8 +403,9 @@ impl ::protobuf::Clear for ObservableSubject {
fn clear(&mut self) { fn clear(&mut self) {
self.category.clear(); self.category.clear();
self.ty = 0; self.ty = 0;
self.subject_id.clear(); self.id.clear();
self.one_of_subject_payload = ::std::option::Option::None; self.one_of_payload = ::std::option::Option::None;
self.one_of_error = ::std::option::Option::None;
self.unknown_fields.clear(); self.unknown_fields.clear();
} }
} }
@ -342,25 +423,29 @@ impl ::protobuf::reflect::ProtobufValue for ObservableSubject {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\rsubject.proto\"\xa3\x01\n\x11ObservableSubject\x12\x1a\n\x08category\ \n\rsubject.proto\"\xa5\x01\n\x11ObservableSubject\x12\x1a\n\x08category\
\x18\x01\x20\x01(\tR\x08category\x12\x0e\n\x02ty\x18\x02\x20\x01(\x05R\ \x18\x01\x20\x01(\tR\x08category\x12\x0e\n\x02ty\x18\x02\x20\x01(\x05R\
\x02ty\x12\x1d\n\nsubject_id\x18\x03\x20\x01(\tR\tsubjectId\x12)\n\x0fsu\ \x02ty\x12\x0e\n\x02id\x18\x03\x20\x01(\tR\x02id\x12\x1a\n\x07payload\
bject_payload\x18\x04\x20\x01(\x0cH\0R\x0esubjectPayloadB\x18\n\x16one_o\ \x18\x04\x20\x01(\x0cH\0R\x07payload\x12\x16\n\x05error\x18\x05\x20\x01(\
f_subject_payloadJ\xa1\x02\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\x0c\x12\ \x0cH\x01R\x05errorB\x10\n\x0eone_of_payloadB\x0e\n\x0cone_of_errorJ\xf3\
\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x04\0\x01\ \x02\n\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\
\x12\x03\x02\x08\x19\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\ \x04\0\x12\x04\x02\0\x08\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x19\n\
\x05\x04\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\ \x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x04\0\x02\0\x05\
\x03\x03\x0b\x13\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x16\x17\n\x0b\n\ \x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x0b\x13\n\x0c\
\x04\x04\0\x02\x01\x12\x03\x04\x04\x11\n\x0c\n\x05\x04\0\x02\x01\x05\x12\ \n\x05\x04\0\x02\0\x03\x12\x03\x03\x16\x17\n\x0b\n\x04\x04\0\x02\x01\x12\
\x03\x04\x04\t\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\n\x0c\n\x0c\n\ \x03\x04\x04\x11\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\t\n\x0c\n\
\x05\x04\0\x02\x01\x03\x12\x03\x04\x0f\x10\n\x0b\n\x04\x04\0\x02\x02\x12\ \x05\x04\0\x02\x01\x01\x12\x03\x04\n\x0c\n\x0c\n\x05\x04\0\x02\x01\x03\
\x03\x05\x04\x1a\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\ \x12\x03\x04\x0f\x10\n\x0b\n\x04\x04\0\x02\x02\x12\x03\x05\x04\x12\n\x0c\
\x05\x04\0\x02\x02\x01\x12\x03\x05\x0b\x15\n\x0c\n\x05\x04\0\x02\x02\x03\ \n\x05\x04\0\x02\x02\x05\x12\x03\x05\x04\n\n\x0c\n\x05\x04\0\x02\x02\x01\
\x12\x03\x05\x18\x19\n\x0b\n\x04\x04\0\x08\0\x12\x03\x06\x04?\n\x0c\n\ \x12\x03\x05\x0b\r\n\x0c\n\x05\x04\0\x02\x02\x03\x12\x03\x05\x10\x11\n\
\x05\x04\0\x08\0\x01\x12\x03\x06\n\x20\n\x0b\n\x04\x04\0\x02\x03\x12\x03\ \x0b\n\x04\x04\0\x08\0\x12\x03\x06\x04/\n\x0c\n\x05\x04\0\x08\0\x01\x12\
\x06#=\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06#(\n\x0c\n\x05\x04\0\x02\ \x03\x06\n\x18\n\x0b\n\x04\x04\0\x02\x03\x12\x03\x06\x1b-\n\x0c\n\x05\
\x03\x01\x12\x03\x06)8\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06;<b\x06p\ \x04\0\x02\x03\x05\x12\x03\x06\x1b\x20\n\x0c\n\x05\x04\0\x02\x03\x01\x12\
roto3\ \x03\x06!(\n\x0c\n\x05\x04\0\x02\x03\x03\x12\x03\x06+,\n\x0b\n\x04\x04\0\
\x08\x01\x12\x03\x07\x04+\n\x0c\n\x05\x04\0\x08\x01\x01\x12\x03\x07\n\
\x16\n\x0b\n\x04\x04\0\x02\x04\x12\x03\x07\x19)\n\x0c\n\x05\x04\0\x02\
\x04\x05\x12\x03\x07\x19\x1e\n\x0c\n\x05\x04\0\x02\x04\x01\x12\x03\x07\
\x1f$\n\x0c\n\x05\x04\0\x02\x04\x03\x12\x03\x07'(b\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View file

@ -3,6 +3,7 @@ syntax = "proto3";
message ObservableSubject { message ObservableSubject {
string category = 1; string category = 1;
int32 ty = 2; int32 ty = 2;
string subject_id = 3; string id = 3;
oneof one_of_subject_payload { bytes subject_payload = 4; }; oneof one_of_payload { bytes payload = 4; };
oneof one_of_error { bytes error = 5; };
} }

View file

@ -22,16 +22,26 @@ impl FlowySDKConfig {
pub fn new(root: &str) -> Self { pub fn new(root: &str) -> Self {
FlowySDKConfig { FlowySDKConfig {
root: root.to_owned(), root: root.to_owned(),
log_filter: std::env::var("RUST_LOG").unwrap_or("info".to_owned()), log_filter: crate_log_filter(None),
} }
} }
pub fn log_filter(mut self, filter: &str) -> Self { pub fn log_filter(mut self, filter: &str) -> Self {
self.log_filter = filter.to_owned(); self.log_filter = crate_log_filter(Some(filter.to_owned()));
self self
} }
} }
fn crate_log_filter(level: Option<String>) -> String {
let level = level.unwrap_or(std::env::var("RUST_LOG").unwrap_or("info".to_owned()));
let mut filters = vec![];
filters.push(format!("flowy_sdk={}", level));
filters.push(format!("flowy_workspace={}", level));
filters.push(format!("flowy_user={}", level));
filters.push(format!("info"));
filters.join(",")
}
#[derive(Clone)] #[derive(Clone)]
pub struct FlowySDK { pub struct FlowySDK {
config: FlowySDKConfig, config: FlowySDKConfig,

View file

@ -111,7 +111,7 @@ impl UserSession {
pub async fn update_user(&self, params: UpdateUserParams) -> Result<(), UserError> { pub async fn update_user(&self, params: UpdateUserParams) -> Result<(), UserError> {
let session = self.get_session()?; let session = self.get_session()?;
let changeset = UserTableChangeset::new(params.clone()); let changeset = UserTableChangeset::new(params.clone());
diesel_update_table!(user_table, changeset, self.db_conn()?); diesel_update_table!(user_table, changeset, &*self.db_conn()?);
let _ = self.update_user_on_server(&session.token, params).await?; let _ = self.update_user_on_server(&session.token, params).await?;
Ok(()) Ok(())
@ -231,7 +231,7 @@ impl UserSession {
pub async fn update_user(_server: Server, pool: Arc<ConnectionPool>, params: UpdateUserParams) -> Result<(), UserError> { pub async fn update_user(_server: Server, pool: Arc<ConnectionPool>, params: UpdateUserParams) -> Result<(), UserError> {
let changeset = UserTableChangeset::new(params); let changeset = UserTableChangeset::new(params);
let conn = pool.get()?; let conn = pool.get()?;
diesel_update_table!(user_table, changeset, conn); diesel_update_table!(user_table, changeset, &*conn);
Ok(()) Ok(())
} }

View file

@ -19,6 +19,9 @@ protobuf = {version = "2.18.0"}
log = "0.4.14" log = "0.4.14"
diesel = {version = "1.4.7", features = ["sqlite"]} diesel = {version = "1.4.7", features = ["sqlite"]}
diesel_derives = {version = "1.4.1", features = ["sqlite"]} diesel_derives = {version = "1.4.1", features = ["sqlite"]}
#diesel = { git = "https://github.com/diesel-rs/diesel.git", branch = "master", features = ["sqlite"] }
#diesel_derives = { git = "https://github.com/diesel-rs/diesel.git", branch = "master",features = ["sqlite"] }
futures-core = { version = "0.3", default-features = false } futures-core = { version = "0.3", default-features = false }
pin-project = "1.0.0" pin-project = "1.0.0"
strum = "0.21" strum = "0.21"

View file

@ -5,41 +5,44 @@ use strum_macros::Display;
#[event_err = "WorkspaceError"] #[event_err = "WorkspaceError"]
pub enum WorkspaceEvent { pub enum WorkspaceEvent {
#[event(input = "CreateWorkspaceRequest", output = "Workspace")] #[event(input = "CreateWorkspaceRequest", output = "Workspace")]
CreateWorkspace = 0, CreateWorkspace = 0,
#[event(output = "Workspace")] #[event(output = "Workspace")]
ReadCurWorkspace = 1, ReadCurWorkspace = 1,
#[event(input = "QueryWorkspaceRequest", output = "RepeatedWorkspace")] #[event(input = "QueryWorkspaceRequest", output = "RepeatedWorkspace")]
ReadWorkspaces = 2, ReadWorkspaces = 2,
#[event(input = "DeleteWorkspaceRequest")] #[event(input = "DeleteWorkspaceRequest")]
DeleteWorkspace = 3, DeleteWorkspace = 3,
#[event(input = "QueryWorkspaceRequest", output = "Workspace")] #[event(input = "QueryWorkspaceRequest", output = "Workspace")]
OpenWorkspace = 4, OpenWorkspace = 4,
#[event(input = "QueryWorkspaceRequest", output = "RepeatedApp")]
ReadWorkspaceApps = 5,
#[event(input = "CreateAppRequest", output = "App")] #[event(input = "CreateAppRequest", output = "App")]
CreateApp = 101, CreateApp = 101,
#[event(input = "DeleteAppRequest")] #[event(input = "DeleteAppRequest")]
DeleteApp = 102, DeleteApp = 102,
#[event(input = "QueryAppRequest", output = "App")] #[event(input = "QueryAppRequest", output = "App")]
ReadApp = 103, ReadApp = 103,
#[event(input = "UpdateAppRequest")] #[event(input = "UpdateAppRequest")]
UpdateApp = 104, UpdateApp = 104,
#[event(input = "CreateViewRequest", output = "View")] #[event(input = "CreateViewRequest", output = "View")]
CreateView = 201, CreateView = 201,
#[event(input = "QueryViewRequest", output = "View")] #[event(input = "QueryViewRequest", output = "View")]
ReadView = 202, ReadView = 202,
#[event(input = "UpdateViewRequest")] #[event(input = "UpdateViewRequest")]
UpdateView = 203, UpdateView = 203,
#[event(input = "DeleteViewRequest")] #[event(input = "DeleteViewRequest")]
DeleteView = 204, DeleteView = 204,
} }

View file

@ -55,8 +55,7 @@ pub(crate) async fn read_app_handler(
// The View's belonging is the view indexed by the belong_to_id for now // The View's belonging is the view indexed by the belong_to_id for now
if params.read_belongings { if params.read_belongings {
let views = view_controller.read_views_belong_to(&params.app_id).await?; app.belongings = view_controller.read_views_belong_to(&params.app_id).await?;
app.belongings = RepeatedView { items: views };
} }
data_result(app) data_result(app)

View file

@ -36,8 +36,7 @@ pub(crate) async fn read_view_handler(
let mut view = controller.read_view(params.clone()).await?; let mut view = controller.read_view(params.clone()).await?;
if params.read_belongings { if params.read_belongings {
let views = controller.read_views_belong_to(&params.view_id).await?; view.belongings = controller.read_views_belong_to(&params.view_id).await?;
view.belongings = RepeatedView { items: views }
} }
data_result(view) data_result(view)

View file

@ -1,4 +1,8 @@
use crate::{entities::workspace::*, errors::WorkspaceError, services::WorkspaceController}; use crate::{
entities::{app::RepeatedApp, workspace::*},
errors::WorkspaceError,
services::WorkspaceController,
};
use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit}; use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};
@ -19,6 +23,12 @@ pub(crate) async fn read_cur_workspace_handler(controller: Unit<Arc<WorkspaceCon
data_result(workspace) data_result(workspace)
} }
#[tracing::instrument(skip(controller), err)]
pub(crate) async fn read_workspace_apps_handler(controller: Unit<Arc<WorkspaceController>>) -> DataResult<RepeatedApp, WorkspaceError> {
let repeated_app = controller.read_workspace_apps().await?;
data_result(repeated_app)
}
#[tracing::instrument(skip(data, controller), err)] #[tracing::instrument(skip(data, controller), err)]
pub(crate) async fn read_workspaces_handler( pub(crate) async fn read_workspaces_handler(
data: Data<QueryWorkspaceRequest>, data: Data<QueryWorkspaceRequest>,

View file

@ -52,7 +52,8 @@ pub fn create(user: Arc<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>
.event(WorkspaceEvent::CreateWorkspace, create_workspace_handler) .event(WorkspaceEvent::CreateWorkspace, create_workspace_handler)
.event(WorkspaceEvent::ReadCurWorkspace, read_cur_workspace_handler) .event(WorkspaceEvent::ReadCurWorkspace, read_cur_workspace_handler)
.event(WorkspaceEvent::ReadWorkspaces, read_workspaces_handler) .event(WorkspaceEvent::ReadWorkspaces, read_workspaces_handler)
.event(WorkspaceEvent::OpenWorkspace, open_workspace_handler); .event(WorkspaceEvent::OpenWorkspace, open_workspace_handler)
.event(WorkspaceEvent::ReadWorkspaceApps, read_workspace_apps_handler);
module = module module = module
.event(WorkspaceEvent::CreateApp, create_app_handler) .event(WorkspaceEvent::CreateApp, create_app_handler)

View file

@ -28,22 +28,23 @@ impl std::default::Default for WorkspaceObservable {
fn default() -> Self { WorkspaceObservable::Unknown } fn default() -> Self { WorkspaceObservable::Unknown }
} }
pub(crate) struct ObservableSender { pub(crate) struct ObservableBuilder {
ty: WorkspaceObservable, id: String,
subject_id: String,
payload: Option<Bytes>, payload: Option<Bytes>,
error: Option<Bytes>,
ty: WorkspaceObservable,
} }
impl ObservableSender { impl ObservableBuilder {
pub(crate) fn new(subject_id: &str, ty: WorkspaceObservable) -> Self { pub(crate) fn new(id: &str, ty: WorkspaceObservable) -> Self {
Self { Self {
subject_id: subject_id.to_owned(), id: id.to_owned(),
ty, ty,
payload: None, payload: None,
error: None,
} }
} }
#[allow(dead_code)]
pub(crate) fn payload<T>(mut self, payload: T) -> Self pub(crate) fn payload<T>(mut self, payload: T) -> Self
where where
T: ToBytes, T: ToBytes,
@ -58,10 +59,28 @@ impl ObservableSender {
self self
} }
pub(crate) fn send(self) { pub(crate) fn error<T>(mut self, error: T) -> Self
log::trace!("Workspace observable id: {}, ty: {:?}", self.subject_id, self.ty); where
T: ToBytes,
{
match error.into_bytes() {
Ok(bytes) => self.error = Some(bytes),
Err(e) => {
log::error!("Set observable error failed: {:?}", e);
},
}
self
}
let subject_payload = match self.payload { pub(crate) fn build(self) {
log::trace!("Workspace observable id: {}, ty: {:?}", self.id, self.ty);
let payload = match self.payload {
None => None,
Some(bytes) => Some(bytes.to_vec()),
};
let error = match self.error {
None => None, None => None,
Some(bytes) => Some(bytes.to_vec()), Some(bytes) => Some(bytes.to_vec()),
}; };
@ -69,8 +88,9 @@ impl ObservableSender {
let subject = ObservableSubject { let subject = ObservableSubject {
category: OBSERVABLE_CATEGORY.to_string(), category: OBSERVABLE_CATEGORY.to_string(),
ty: self.ty as i32, ty: self.ty as i32,
subject_id: self.subject_id, id: self.id,
subject_payload, payload,
error,
}; };
match RustStreamSender::post(subject) { match RustStreamSender::post(subject) {
Ok(_) => {}, Ok(_) => {},
@ -78,13 +98,3 @@ impl ObservableSender {
} }
} }
} }
pub(crate) fn send_observable(id: &str, ty: WorkspaceObservable) { ObservableSender::new(id, ty).send(); }
#[allow(dead_code)]
pub(crate) fn send_observable_with_payload<T>(id: &str, ty: WorkspaceObservable, payload: T)
where
T: ToBytes,
{
ObservableSender::new(id, ty).payload(payload).send();
}

View file

@ -30,6 +30,7 @@ pub enum WorkspaceEvent {
ReadWorkspaces = 2, ReadWorkspaces = 2,
DeleteWorkspace = 3, DeleteWorkspace = 3,
OpenWorkspace = 4, OpenWorkspace = 4,
ReadWorkspaceApps = 5,
CreateApp = 101, CreateApp = 101,
DeleteApp = 102, DeleteApp = 102,
ReadApp = 103, ReadApp = 103,
@ -52,6 +53,7 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
2 => ::std::option::Option::Some(WorkspaceEvent::ReadWorkspaces), 2 => ::std::option::Option::Some(WorkspaceEvent::ReadWorkspaces),
3 => ::std::option::Option::Some(WorkspaceEvent::DeleteWorkspace), 3 => ::std::option::Option::Some(WorkspaceEvent::DeleteWorkspace),
4 => ::std::option::Option::Some(WorkspaceEvent::OpenWorkspace), 4 => ::std::option::Option::Some(WorkspaceEvent::OpenWorkspace),
5 => ::std::option::Option::Some(WorkspaceEvent::ReadWorkspaceApps),
101 => ::std::option::Option::Some(WorkspaceEvent::CreateApp), 101 => ::std::option::Option::Some(WorkspaceEvent::CreateApp),
102 => ::std::option::Option::Some(WorkspaceEvent::DeleteApp), 102 => ::std::option::Option::Some(WorkspaceEvent::DeleteApp),
103 => ::std::option::Option::Some(WorkspaceEvent::ReadApp), 103 => ::std::option::Option::Some(WorkspaceEvent::ReadApp),
@ -71,6 +73,7 @@ impl ::protobuf::ProtobufEnum for WorkspaceEvent {
WorkspaceEvent::ReadWorkspaces, WorkspaceEvent::ReadWorkspaces,
WorkspaceEvent::DeleteWorkspace, WorkspaceEvent::DeleteWorkspace,
WorkspaceEvent::OpenWorkspace, WorkspaceEvent::OpenWorkspace,
WorkspaceEvent::ReadWorkspaceApps,
WorkspaceEvent::CreateApp, WorkspaceEvent::CreateApp,
WorkspaceEvent::DeleteApp, WorkspaceEvent::DeleteApp,
WorkspaceEvent::ReadApp, WorkspaceEvent::ReadApp,
@ -107,41 +110,44 @@ impl ::protobuf::reflect::ProtobufValue for WorkspaceEvent {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0bevent.proto*\xf3\x01\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\ \n\x0bevent.proto*\x8a\x02\n\x0eWorkspaceEvent\x12\x13\n\x0fCreateWorksp\
ace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorkspa\ ace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorkspa\
ces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspac\ ces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspac\
e\x10\x04\x12\r\n\tCreateApp\x10e\x12\r\n\tDeleteApp\x10f\x12\x0b\n\x07R\ e\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\r\n\tCreateApp\x10e\
eadApp\x10g\x12\r\n\tUpdateApp\x10h\x12\x0f\n\nCreateView\x10\xc9\x01\ \x12\r\n\tDeleteApp\x10f\x12\x0b\n\x07ReadApp\x10g\x12\r\n\tUpdateApp\
\x12\r\n\x08ReadView\x10\xca\x01\x12\x0f\n\nUpdateView\x10\xcb\x01\x12\ \x10h\x12\x0f\n\nCreateView\x10\xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\
\x0f\n\nDeleteView\x10\xcc\x01J\xbf\x04\n\x06\x12\x04\0\0\x10\x01\n\x08\ \x12\x0f\n\nUpdateView\x10\xcb\x01\x12\x0f\n\nDeleteView\x10\xcc\x01J\
\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x10\x01\n\n\n\ \xe8\x04\n\x06\x12\x04\0\0\x11\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\
\x03\x05\0\x01\x12\x03\x02\x05\x13\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\ \x02\x05\0\x12\x04\x02\0\x11\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x13\
\x04\x18\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x13\n\x0c\n\x05\x05\ \n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x18\n\x0c\n\x05\x05\0\x02\0\x01\
\0\x02\0\x02\x12\x03\x03\x16\x17\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\ \x12\x03\x03\x04\x13\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x16\x17\n\
\x04\x19\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x14\n\x0c\n\x05\ \x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x19\n\x0c\n\x05\x05\0\x02\x01\
\x05\0\x02\x01\x02\x12\x03\x04\x17\x18\n\x0b\n\x04\x05\0\x02\x02\x12\x03\ \x01\x12\x03\x04\x04\x14\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x17\
\x05\x04\x17\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x12\n\x0c\n\ \x18\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x17\n\x0c\n\x05\x05\0\x02\
\x05\x05\0\x02\x02\x02\x12\x03\x05\x15\x16\n\x0b\n\x04\x05\0\x02\x03\x12\ \x02\x01\x12\x03\x05\x04\x12\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\
\x03\x06\x04\x18\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\ \x15\x16\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x18\n\x0c\n\x05\x05\0\
\n\x05\x05\0\x02\x03\x02\x12\x03\x06\x16\x17\n\x0b\n\x04\x05\0\x02\x04\ \x02\x03\x01\x12\x03\x06\x04\x13\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\
\x12\x03\x07\x04\x16\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x11\n\ \x06\x16\x17\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x16\n\x0c\n\x05\
\x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\x14\x15\n\x0b\n\x04\x05\0\x02\ \x05\0\x02\x04\x01\x12\x03\x07\x04\x11\n\x0c\n\x05\x05\0\x02\x04\x02\x12\
\x05\x12\x03\x08\x04\x14\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\r\ \x03\x07\x14\x15\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x1a\n\x0c\n\
\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x08\x10\x13\n\x0b\n\x04\x05\0\x02\ \x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x05\0\x02\x05\x02\
\x06\x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\x04\r\n\ \x12\x03\x08\x18\x19\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x14\n\x0c\n\
\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\x10\x13\n\x0b\n\x04\x05\0\x02\x07\ \x05\x05\0\x02\x06\x01\x12\x03\t\x04\r\n\x0c\n\x05\x05\0\x02\x06\x02\x12\
\x12\x03\n\x04\x12\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\n\x04\x0b\n\x0c\ \x03\t\x10\x13\n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x14\n\x0c\n\x05\
\n\x05\x05\0\x02\x07\x02\x12\x03\n\x0e\x11\n\x0b\n\x04\x05\0\x02\x08\x12\ \x05\0\x02\x07\x01\x12\x03\n\x04\r\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\
\x03\x0b\x04\x14\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\x0b\x04\r\n\x0c\n\ \n\x10\x13\n\x0b\n\x04\x05\0\x02\x08\x12\x03\x0b\x04\x12\n\x0c\n\x05\x05\
\x05\x05\0\x02\x08\x02\x12\x03\x0b\x10\x13\n\x0b\n\x04\x05\0\x02\t\x12\ \0\x02\x08\x01\x12\x03\x0b\x04\x0b\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\
\x03\x0c\x04\x15\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\x0c\x04\x0e\n\x0c\n\ \x0b\x0e\x11\n\x0b\n\x04\x05\0\x02\t\x12\x03\x0c\x04\x14\n\x0c\n\x05\x05\
\x05\x05\0\x02\t\x02\x12\x03\x0c\x11\x14\n\x0b\n\x04\x05\0\x02\n\x12\x03\ \0\x02\t\x01\x12\x03\x0c\x04\r\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x0c\
\r\x04\x13\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\r\x04\x0c\n\x0c\n\x05\x05\ \x10\x13\n\x0b\n\x04\x05\0\x02\n\x12\x03\r\x04\x15\n\x0c\n\x05\x05\0\x02\
\0\x02\n\x02\x12\x03\r\x0f\x12\n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\ \n\x01\x12\x03\r\x04\x0e\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\x11\x14\n\
\x15\n\x0c\n\x05\x05\0\x02\x0b\x01\x12\x03\x0e\x04\x0e\n\x0c\n\x05\x05\0\ \x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\x13\n\x0c\n\x05\x05\0\x02\x0b\
\x02\x0b\x02\x12\x03\x0e\x11\x14\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x0f\ \x01\x12\x03\x0e\x04\x0c\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\x0e\x0f\
\x04\x15\n\x0c\n\x05\x05\0\x02\x0c\x01\x12\x03\x0f\x04\x0e\n\x0c\n\x05\ \x12\n\x0b\n\x04\x05\0\x02\x0c\x12\x03\x0f\x04\x15\n\x0c\n\x05\x05\0\x02\
\x05\0\x02\x0c\x02\x12\x03\x0f\x11\x14b\x06proto3\ \x0c\x01\x12\x03\x0f\x04\x0e\n\x0c\n\x05\x05\0\x02\x0c\x02\x12\x03\x0f\
\x11\x14\n\x0b\n\x04\x05\0\x02\r\x12\x03\x10\x04\x15\n\x0c\n\x05\x05\0\
\x02\r\x01\x12\x03\x10\x04\x0e\n\x0c\n\x05\x05\0\x02\r\x02\x12\x03\x10\
\x11\x14b\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View file

@ -6,6 +6,7 @@ enum WorkspaceEvent {
ReadWorkspaces = 2; ReadWorkspaces = 2;
DeleteWorkspace = 3; DeleteWorkspace = 3;
OpenWorkspace = 4; OpenWorkspace = 4;
ReadWorkspaceApps = 5;
CreateApp = 101; CreateApp = 101;
DeleteApp = 102; DeleteApp = 102;
ReadApp = 103; ReadApp = 103;

View file

@ -7,6 +7,7 @@ use crate::{
sql_tables::app::{AppTable, AppTableChangeset, AppTableSql}, sql_tables::app::{AppTable, AppTableChangeset, AppTableSql},
}; };
use crate::entities::view::RepeatedView;
use std::sync::Arc; use std::sync::Arc;
pub(crate) struct AppController { pub(crate) struct AppController {
@ -24,7 +25,7 @@ impl AppController {
view_controller: Arc<ViewController>, view_controller: Arc<ViewController>,
server: Server, server: Server,
) -> Self { ) -> Self {
let sql = Arc::new(AppTableSql { database }); let sql = Arc::new(AppTableSql::new(database));
Self { Self {
user, user,
sql, sql,
@ -38,7 +39,12 @@ impl AppController {
let app = self.create_app_on_server(params).await?; let app = self.create_app_on_server(params).await?;
let app_table = AppTable::new(app.clone()); let app_table = AppTable::new(app.clone());
let _ = self.sql.create_app(app_table)?; let _ = self.sql.create_app(app_table)?;
send_observable(&app.workspace_id, WorkspaceObservable::WorkspaceCreateApp);
// Opti: transaction
let apps = self.read_local_apps(&app.workspace_id)?;
ObservableBuilder::new(&app.workspace_id, WorkspaceObservable::WorkspaceCreateApp)
.payload(apps)
.build();
Ok(app) Ok(app)
} }
@ -51,16 +57,31 @@ impl AppController {
pub(crate) async fn delete_app(&self, app_id: &str) -> Result<(), WorkspaceError> { pub(crate) async fn delete_app(&self, app_id: &str) -> Result<(), WorkspaceError> {
let app = self.sql.delete_app(app_id)?; let app = self.sql.delete_app(app_id)?;
let _ = self.delete_app_on_server(app_id).await?; let _ = self.delete_app_on_server(app_id).await?;
send_observable(&app.workspace_id, WorkspaceObservable::WorkspaceDeleteApp);
// Opti: transaction
let apps = self.read_local_apps(&app.workspace_id)?;
ObservableBuilder::new(&app.workspace_id, WorkspaceObservable::WorkspaceDeleteApp)
.payload(apps)
.build();
Ok(()) Ok(())
} }
fn read_local_apps(&self, workspace_id: &str) -> Result<RepeatedApp, WorkspaceError> {
let app_tables = self.sql.read_apps(workspace_id, false)?;
let apps = app_tables.into_iter().map(|table| table.into()).collect::<Vec<App>>();
Ok(RepeatedApp { items: apps })
}
pub(crate) async fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> { pub(crate) async fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> {
let changeset = AppTableChangeset::new(params.clone()); let changeset = AppTableChangeset::new(params.clone());
let app_id = changeset.id.clone(); let app_id = changeset.id.clone();
let _ = self.sql.update_app(changeset)?; let _ = self.sql.update_app(changeset)?;
let _ = self.update_app_on_server(params).await?; let _ = self.update_app_on_server(params).await?;
send_observable(&app_id, WorkspaceObservable::AppUpdated);
let app: App = self.sql.read_app(&app_id, false)?.into();
ObservableBuilder::new(&app_id, WorkspaceObservable::AppUpdated)
.payload(app)
.build();
Ok(()) Ok(())
} }
} }
@ -114,12 +135,11 @@ impl AppController {
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 {
match server.read_app(&token, params).await { // Opti: retry?
Ok(_) => {}, let app = server.read_app(&token, params).await.unwrap();
Err(e) => { match app {
// TODO: retry? None => {},
log::error!("Read app failed: {:?}", e); Some(_) => {},
},
} }
}); });
Ok(()) Ok(())

View file

@ -1,7 +1,9 @@
pub fn spawn<F>(f: F) use tokio::task::JoinHandle;
pub fn spawn<F>(f: F) -> JoinHandle<F::Output>
where where
F: std::future::Future + Send + 'static, F: std::future::Future + Send + 'static,
F::Output: Send + 'static, F::Output: Send + 'static,
{ {
let _ = tokio::spawn(f); tokio::spawn(f)
} }

View file

@ -2,14 +2,15 @@ use crate::{
entities::view::{CreateViewParams, UpdateViewParams, View}, entities::view::{CreateViewParams, UpdateViewParams, View},
errors::WorkspaceError, errors::WorkspaceError,
module::WorkspaceDatabase, module::WorkspaceDatabase,
observable::{send_observable, WorkspaceObservable}, observable::WorkspaceObservable,
services::{helper::spawn, server::Server}, services::{helper::spawn, server::Server},
sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql}, sql_tables::view::{ViewTable, ViewTableChangeset, ViewTableSql},
}; };
use crate::{ use crate::{
entities::view::{DeleteViewParams, QueryViewParams}, entities::view::{DeleteViewParams, QueryViewParams, RepeatedView},
module::WorkspaceUser, module::WorkspaceUser,
observable::ObservableBuilder,
}; };
use std::sync::Arc; use std::sync::Arc;
@ -30,7 +31,10 @@ impl ViewController {
let view_table = ViewTable::new(view.clone()); let view_table = ViewTable::new(view.clone());
let _ = self.sql.create_view(view_table)?; let _ = self.sql.create_view(view_table)?;
send_observable(&view.belong_to_id, WorkspaceObservable::AppCreateView); let repeated_view = self.read_local_views_belong_to(&view.belong_to_id)?;
ObservableBuilder::new(&view.belong_to_id, WorkspaceObservable::AppCreateView)
.payload(repeated_view)
.build();
Ok(view) Ok(view)
} }
@ -42,14 +46,19 @@ impl ViewController {
} }
pub(crate) async fn delete_view(&self, view_id: &str) -> Result<(), WorkspaceError> { pub(crate) async fn delete_view(&self, view_id: &str) -> Result<(), WorkspaceError> {
let view = self.sql.delete_view(view_id)?; let view_table = self.sql.delete_view(view_id)?;
let _ = self.delete_view_on_server(view_id).await?; let _ = self.delete_view_on_server(view_id).await?;
send_observable(&view.belong_to_id, WorkspaceObservable::AppDeleteView);
let repeated_view = self.read_local_views_belong_to(&view_table.belong_to_id)?;
ObservableBuilder::new(&view_table.belong_to_id, WorkspaceObservable::AppDeleteView)
.payload(repeated_view)
.build();
Ok(()) Ok(())
} }
// belong_to_id will be the app_id or view_id. // belong_to_id will be the app_id or view_id.
pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<Vec<View>, WorkspaceError> { pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
// TODO: read from server
let views = self let views = self
.sql .sql
.read_views_belong_to(belong_to_id)? .read_views_belong_to(belong_to_id)?
@ -57,16 +66,19 @@ impl ViewController {
.map(|view_table| view_table.into()) .map(|view_table| view_table.into())
.collect::<Vec<View>>(); .collect::<Vec<View>>();
Ok(views) Ok(RepeatedView { items: views })
} }
pub(crate) async fn update_view(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> { pub(crate) async fn update_view(&self, params: UpdateViewParams) -> Result<(), WorkspaceError> {
let changeset = ViewTableChangeset::new(params.clone()); let changeset = ViewTableChangeset::new(params.clone());
let view_id = changeset.id.clone(); let view_id = changeset.id.clone();
let _ = self.sql.update_view(changeset)?; let _ = self.sql.update_view(changeset)?;
let _ = self.update_view_on_server(params).await?; let _ = self.update_view_on_server(params).await?;
send_observable(&view_id, WorkspaceObservable::ViewUpdated);
let view: View = self.sql.read_view(&view_id, false)?.into();
ObservableBuilder::new(&view_id, WorkspaceObservable::ViewUpdated)
.payload(view)
.build();
Ok(()) Ok(())
} }
} }
@ -129,4 +141,16 @@ impl ViewController {
}); });
Ok(()) Ok(())
} }
// belong_to_id will be the app_id or view_id.
fn read_local_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
let views = self
.sql
.read_views_belong_to(belong_to_id)?
.into_iter()
.map(|view_table| view_table.into())
.collect::<Vec<View>>();
Ok(RepeatedView { items: views })
}
} }

View file

@ -2,13 +2,14 @@ use crate::{
entities::{app::App, workspace::*}, entities::{app::App, workspace::*},
errors::*, errors::*,
module::{WorkspaceDatabase, WorkspaceUser}, module::{WorkspaceDatabase, WorkspaceUser},
observable::{send_observable, WorkspaceObservable}, observable::WorkspaceObservable,
services::{helper::spawn, server::Server, AppController}, services::{helper::spawn, server::Server, AppController},
sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset}, sql_tables::workspace::{WorkspaceSql, WorkspaceTable, WorkspaceTableChangeset},
}; };
use flowy_infra::kv::KV; use flowy_infra::kv::KV;
use crate::{entities::app::RepeatedApp, observable::ObservableBuilder};
use std::sync::Arc; use std::sync::Arc;
pub(crate) struct WorkspaceController { pub(crate) struct WorkspaceController {
@ -25,7 +26,7 @@ impl WorkspaceController {
app_controller: Arc<AppController>, app_controller: Arc<AppController>,
server: Server, server: Server,
) -> Self { ) -> Self {
let sql = Arc::new(WorkspaceSql { database }); let sql = Arc::new(WorkspaceSql::new(database));
Self { Self {
user, user,
sql, sql,
@ -39,7 +40,12 @@ impl WorkspaceController {
let user_id = self.user.user_id()?; let user_id = self.user.user_id()?;
let workspace_table = WorkspaceTable::new(workspace.clone(), &user_id); let workspace_table = WorkspaceTable::new(workspace.clone(), &user_id);
let _ = self.sql.create_workspace(workspace_table)?; let _ = self.sql.create_workspace(workspace_table)?;
send_observable(&user_id, WorkspaceObservable::UserCreateWorkspace);
// Opti: read all local workspaces may cause performance issues
let repeated_workspace = self.read_local_workspaces(None, &user_id)?;
ObservableBuilder::new(&user_id, WorkspaceObservable::UserCreateWorkspace)
.payload(repeated_workspace)
.build();
Ok(workspace) Ok(workspace)
} }
@ -48,7 +54,13 @@ impl WorkspaceController {
let workspace_id = changeset.id.clone(); let workspace_id = changeset.id.clone();
let _ = self.sql.update_workspace(changeset)?; let _ = self.sql.update_workspace(changeset)?;
let _ = self.update_workspace_on_server(params).await?; let _ = self.update_workspace_on_server(params).await?;
send_observable(&workspace_id, WorkspaceObservable::WorkspaceUpdated);
// Opti: transaction
let user_id = self.user.user_id()?;
let workspace = self.read_local_workspace(workspace_id.clone(), &user_id)?;
ObservableBuilder::new(&workspace_id, WorkspaceObservable::WorkspaceUpdated)
.payload(workspace)
.build();
Ok(()) Ok(())
} }
@ -56,23 +68,21 @@ impl WorkspaceController {
let user_id = self.user.user_id()?; let user_id = self.user.user_id()?;
let _ = self.sql.delete_workspace(workspace_id)?; let _ = self.sql.delete_workspace(workspace_id)?;
let _ = self.delete_workspace_on_server(workspace_id).await?; let _ = self.delete_workspace_on_server(workspace_id).await?;
send_observable(&user_id, WorkspaceObservable::UserDeleteWorkspace);
// Opti: read all local workspaces may cause performance issues
let repeated_workspace = self.read_local_workspaces(None, &user_id)?;
ObservableBuilder::new(&user_id, WorkspaceObservable::UserDeleteWorkspace)
.payload(repeated_workspace)
.build();
Ok(()) Ok(())
} }
pub(crate) async fn open_workspace(&self, params: QueryWorkspaceParams) -> Result<Workspace, WorkspaceError> { pub(crate) async fn open_workspace(&self, params: QueryWorkspaceParams) -> Result<Workspace, WorkspaceError> {
let user_id = self.user.user_id()?; let user_id = self.user.user_id()?;
if let Some(workspace_id) = params.workspace_id.clone() { if let Some(workspace_id) = params.workspace_id.clone() {
self.read_workspaces_on_server(params.clone()); let workspace = self.read_local_workspace(workspace_id, &user_id)?;
let result = self.read_workspace_table(Some(workspace_id), user_id)?; set_current_workspace(&workspace.id);
match result.first() { Ok(workspace)
None => Err(ErrorBuilder::new(ErrorCode::RecordNotFound).build()),
Some(workspace_table) => {
let workspace: Workspace = workspace_table.clone().into();
set_current_workspace(&workspace.id);
Ok(workspace)
},
}
} else { } else {
return Err(ErrorBuilder::new(ErrorCode::WorkspaceIdInvalid) return Err(ErrorBuilder::new(ErrorCode::WorkspaceIdInvalid)
.msg("Opened workspace id should not be empty") .msg("Opened workspace id should not be empty")
@ -82,25 +92,44 @@ impl WorkspaceController {
pub(crate) async fn read_workspaces(&self, params: QueryWorkspaceParams) -> Result<RepeatedWorkspace, WorkspaceError> { pub(crate) async fn read_workspaces(&self, params: QueryWorkspaceParams) -> Result<RepeatedWorkspace, WorkspaceError> {
let user_id = self.user.user_id()?; let user_id = self.user.user_id()?;
let workspace_tables = self.read_workspace_table(params.workspace_id.clone(), user_id.clone())?; let workspaces = self.read_local_workspaces(params.workspace_id.clone(), &user_id)?;
let _ = self.read_workspaces_on_server(user_id, params).await?;
Ok(workspaces)
}
pub(crate) async fn read_cur_workspace(&self) -> Result<Workspace, WorkspaceError> {
let workspace_id = get_current_workspace()?;
let user_id = self.user.user_id()?;
let workspace = self.read_local_workspace(workspace_id, &user_id)?;
Ok(workspace)
}
pub(crate) async fn read_workspace_apps(&self) -> Result<RepeatedApp, WorkspaceError> {
let workspace_id = get_current_workspace()?;
let apps = self.read_local_apps(&workspace_id)?;
// TODO: read from server
Ok(RepeatedApp { items: apps })
}
#[tracing::instrument(level = "debug", skip(self), err)]
fn read_local_workspaces(&self, workspace_id: Option<String>, user_id: &str) -> Result<RepeatedWorkspace, WorkspaceError> {
let sql = self.sql.clone();
let workspace_id = workspace_id.to_owned();
let workspace_tables = sql.read_workspaces(workspace_id, user_id)?;
let mut workspaces = vec![]; let mut workspaces = vec![];
for table in workspace_tables { for table in workspace_tables {
let apps = self.read_apps(&table.id).await?; let apps = self.read_local_apps(&table.id)?;
let mut workspace: Workspace = table.into(); let mut workspace: Workspace = table.into();
workspace.apps.items = apps; workspace.apps.items = apps;
workspaces.push(workspace); workspaces.push(workspace);
} }
let _ = self.read_workspaces_on_server(user_id, params).await?;
Ok(RepeatedWorkspace { items: workspaces }) Ok(RepeatedWorkspace { items: workspaces })
} }
pub(crate) async fn read_cur_workspace(&self) -> Result<Workspace, WorkspaceError> { fn read_local_workspace(&self, workspace_id: String, user_id: &str) -> Result<Workspace, WorkspaceError> {
let params = QueryWorkspaceParams { // Opti: fetch single workspace from local db
workspace_id: Some(get_current_workspace()?), let mut repeated_workspace = self.read_local_workspaces(Some(workspace_id), user_id)?;
};
let mut repeated_workspace = self.read_workspaces(params).await?;
if repeated_workspace.is_empty() { if repeated_workspace.is_empty() {
return Err(ErrorBuilder::new(ErrorCode::RecordNotFound).build()); return Err(ErrorBuilder::new(ErrorCode::RecordNotFound).build());
} }
@ -110,13 +139,8 @@ impl WorkspaceController {
Ok(workspace) Ok(workspace)
} }
pub(crate) async fn read_cur_apps(&self) -> Result<Vec<App>, WorkspaceError> { #[tracing::instrument(level = "debug", skip(self), err)]
let workspace_id = get_current_workspace()?; fn read_local_apps(&self, workspace_id: &str) -> Result<Vec<App>, WorkspaceError> {
let apps = self.read_apps(&workspace_id).await?;
Ok(apps)
}
pub(crate) async fn read_apps(&self, workspace_id: &str) -> Result<Vec<App>, WorkspaceError> {
let apps = self let apps = self
.sql .sql
.read_apps_belong_to_workspace(workspace_id)? .read_apps_belong_to_workspace(workspace_id)?
@ -126,13 +150,6 @@ impl WorkspaceController {
Ok(apps) Ok(apps)
} }
fn read_workspace_table(&self, workspace_id: Option<String>, user_id: String) -> Result<Vec<WorkspaceTable>, WorkspaceError> {
let sql = self.sql.clone();
let workspace_id = workspace_id.to_owned();
let workspace = sql.read_workspaces(workspace_id, &user_id)?;
Ok(workspace)
}
} }
impl WorkspaceController { impl WorkspaceController {
@ -185,17 +202,27 @@ impl WorkspaceController {
#[tracing::instrument(skip(self), err)] #[tracing::instrument(skip(self), err)]
async fn read_workspaces_on_server(&self, user_id: String, params: QueryWorkspaceParams) -> Result<(), WorkspaceError> { async fn read_workspaces_on_server(&self, user_id: String, params: QueryWorkspaceParams) -> Result<(), WorkspaceError> {
let (token, server) = self.token_with_server()?; let (token, server) = self.token_with_server()?;
let sql = self.sql.clone();
let conn = self.sql.get_db_conn()?;
spawn(async move { spawn(async move {
match server.read_workspace(&token, params).await { // Opti: retry?
Ok(workspaces) => { let workspaces = server.read_workspace(&token, params).await?;
log::debug!("Workspace list: {:?}", workspaces); let _ = (&*conn).immediate_transaction::<_, WorkspaceError, _>(|| {
send_observable(&user_id, WorkspaceObservable::UserCreateWorkspace); for workspace in &workspaces.items {
}, let mut m_workspace = workspace.clone();
Err(e) => { let repeated_app = m_workspace.apps.take_items();
// TODO: retry? let workspace_table = WorkspaceTable::new(m_workspace, &user_id);
log::error!("Delete workspace failed: {:?}", e); log::debug!("Save workspace: {} to disk", &workspace.id);
}, let _ = sql.create_workspace_with(workspace_table, &*conn)?;
} log::debug!("Save workspace: {} apps to disk", &workspace.id);
let _ = sql.create_apps(repeated_app, &*conn)?;
}
Ok(())
})?;
ObservableBuilder::new(&user_id, WorkspaceObservable::WorkspaceListUpdated)
.payload(workspaces)
.build();
Result::<(), WorkspaceError>::Ok(())
}); });
Ok(()) Ok(())

View file

@ -6,33 +6,43 @@ use crate::{
use flowy_database::{ use flowy_database::{
prelude::*, prelude::*,
schema::{app_table, app_table::dsl}, schema::{app_table, app_table::dsl},
SqliteConnection,
}; };
use std::sync::Arc; use std::sync::Arc;
pub struct AppTableSql { pub struct AppTableSql {
pub database: Arc<dyn WorkspaceDatabase>, database: Arc<dyn WorkspaceDatabase>,
}
impl AppTableSql {
pub fn new(database: Arc<dyn WorkspaceDatabase>) -> Self { Self { database } }
} }
impl AppTableSql { impl AppTableSql {
pub(crate) fn create_app(&self, app_table: AppTable) -> Result<(), WorkspaceError> { pub(crate) fn create_app(&self, app_table: AppTable) -> Result<(), WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
let _ = diesel::insert_into(app_table::table) let _ = self.create_app_with(app_table, &*conn)?;
.values(app_table) Ok(())
.execute(&*conn)?; }
pub(crate) fn create_app_with(&self, app_table: AppTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
match diesel_record_count!(app_table, &app_table.id, conn) {
0 => diesel_insert_table!(app_table, &app_table, conn),
_ => {
let changeset = AppTableChangeset::from_table(app_table);
diesel_update_table!(app_table, changeset, conn)
},
}
Ok(()) Ok(())
} }
pub(crate) fn update_app(&self, changeset: AppTableChangeset) -> Result<(), WorkspaceError> { pub(crate) fn update_app(&self, changeset: AppTableChangeset) -> Result<(), WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
diesel_update_table!(app_table, changeset, conn); diesel_update_table!(app_table, changeset, &*conn);
Ok(()) Ok(())
} }
pub(crate) fn read_app( pub(crate) fn read_app(&self, app_id: &str, is_trash: bool) -> Result<AppTable, WorkspaceError> {
&self,
app_id: &str,
is_trash: bool,
) -> Result<AppTable, WorkspaceError> {
let app_table = dsl::app_table let app_table = dsl::app_table
.filter(app_table::id.eq(app_id)) .filter(app_table::id.eq(app_id))
.filter(app_table::is_trash.eq(is_trash)) .filter(app_table::is_trash.eq(is_trash))
@ -41,6 +51,15 @@ impl AppTableSql {
Ok(app_table) Ok(app_table)
} }
pub(crate) fn read_apps(&self, workspace_id: &str, is_trash: bool) -> Result<Vec<AppTable>, WorkspaceError> {
let app_table = dsl::app_table
.filter(app_table::workspace_id.eq(workspace_id))
.filter(app_table::is_trash.eq(is_trash))
.load::<AppTable>(&*(self.database.db_connection()?))?;
Ok(app_table)
}
pub(crate) fn delete_app(&self, app_id: &str) -> Result<AppTable, WorkspaceError> { pub(crate) fn delete_app(&self, app_id: &str) -> Result<AppTable, WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
// TODO: group into sql transaction // TODO: group into sql transaction

View file

@ -75,7 +75,7 @@ impl_sql_binary_expression!(ColorStyleCol);
#[derive(AsChangeset, Identifiable, Default, Debug)] #[derive(AsChangeset, Identifiable, Default, Debug)]
#[table_name = "app_table"] #[table_name = "app_table"]
pub struct AppTableChangeset { pub(crate) struct AppTableChangeset {
pub id: String, pub id: String,
pub name: Option<String>, pub name: Option<String>,
pub desc: Option<String>, pub desc: Option<String>,
@ -83,7 +83,7 @@ pub struct AppTableChangeset {
} }
impl AppTableChangeset { impl AppTableChangeset {
pub fn new(params: UpdateAppParams) -> Self { pub(crate) fn new(params: UpdateAppParams) -> Self {
AppTableChangeset { AppTableChangeset {
id: params.app_id, id: params.app_id,
name: params.name, name: params.name,
@ -91,6 +91,15 @@ impl AppTableChangeset {
is_trash: params.is_trash, is_trash: params.is_trash,
} }
} }
pub(crate) fn from_table(table: AppTable) -> Self {
AppTableChangeset {
id: table.id,
name: Some(table.name),
desc: Some(table.desc),
is_trash: Some(table.is_trash),
}
}
} }
impl std::convert::Into<App> for AppTable { impl std::convert::Into<App> for AppTable {

View file

@ -16,17 +16,11 @@ pub struct ViewTableSql {
impl ViewTableSql { impl ViewTableSql {
pub(crate) fn create_view(&self, view_table: ViewTable) -> Result<(), WorkspaceError> { pub(crate) fn create_view(&self, view_table: ViewTable) -> Result<(), WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
let _ = diesel::insert_into(view_table::table) let _ = diesel::insert_into(view_table::table).values(view_table).execute(&*conn)?;
.values(view_table)
.execute(&*conn)?;
Ok(()) Ok(())
} }
pub(crate) fn read_view( pub(crate) fn read_view(&self, view_id: &str, is_trash: bool) -> Result<ViewTable, WorkspaceError> {
&self,
view_id: &str,
is_trash: bool,
) -> Result<ViewTable, WorkspaceError> {
let view_table = dsl::view_table let view_table = dsl::view_table
.filter(view_table::id.eq(view_id)) .filter(view_table::id.eq(view_id))
.filter(view_table::is_trash.eq(is_trash)) .filter(view_table::is_trash.eq(is_trash))
@ -35,10 +29,7 @@ impl ViewTableSql {
Ok(view_table) Ok(view_table)
} }
pub(crate) fn read_views_belong_to( pub(crate) fn read_views_belong_to(&self, belong_to_id: &str) -> Result<Vec<ViewTable>, WorkspaceError> {
&self,
belong_to_id: &str,
) -> Result<Vec<ViewTable>, WorkspaceError> {
let view_tables = dsl::view_table let view_tables = dsl::view_table
.filter(view_table::belong_to_id.eq(belong_to_id)) .filter(view_table::belong_to_id.eq(belong_to_id))
.load::<ViewTable>(&*(self.database.db_connection()?))?; .load::<ViewTable>(&*(self.database.db_connection()?))?;
@ -48,7 +39,7 @@ impl ViewTableSql {
pub(crate) fn update_view(&self, changeset: ViewTableChangeset) -> Result<(), WorkspaceError> { pub(crate) fn update_view(&self, changeset: ViewTableChangeset) -> Result<(), WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
diesel_update_table!(view_table, changeset, conn); diesel_update_table!(view_table, changeset, &*conn);
Ok(()) Ok(())
} }

View file

@ -1,34 +1,71 @@
use crate::{ use crate::{
entities::app::App,
errors::WorkspaceError, errors::WorkspaceError,
module::WorkspaceDatabase, module::WorkspaceDatabase,
sql_tables::{ sql_tables::{
app::AppTable, app::{AppTable, AppTableSql},
workspace::{WorkspaceTable, WorkspaceTableChangeset}, workspace::{WorkspaceTable, WorkspaceTableChangeset},
}, },
}; };
use diesel::SqliteConnection;
use flowy_database::{ use flowy_database::{
macros::*,
prelude::*, prelude::*,
schema::{workspace_table, workspace_table::dsl}, schema::{workspace_table, workspace_table::dsl},
DBConnection,
}; };
use std::sync::Arc; use std::sync::Arc;
pub struct WorkspaceSql { pub(crate) struct WorkspaceSql {
pub database: Arc<dyn WorkspaceDatabase>, database: Arc<dyn WorkspaceDatabase>,
app_sql: Arc<AppTableSql>,
} }
impl WorkspaceSql { impl WorkspaceSql {
pub fn create_workspace(&self, workspace_table: WorkspaceTable) -> Result<(), WorkspaceError> { pub fn new(database: Arc<dyn WorkspaceDatabase>) -> Self {
let _ = diesel::insert_into(workspace_table::table) Self {
.values(workspace_table) database: database.clone(),
.execute(&*(self.database.db_connection()?))?; app_sql: Arc::new(AppTableSql::new(database.clone())),
}
}
}
impl WorkspaceSql {
pub(crate) fn create_workspace(&self, table: WorkspaceTable) -> Result<(), WorkspaceError> {
let conn = &*self.database.db_connection()?;
//[[immediate_transaction]]
// https://sqlite.org/lang_transaction.html
// IMMEDIATE cause the database connection to start a new write immediately,
// without waiting for a write statement. The BEGIN IMMEDIATE might fail
// with SQLITE_BUSY if another write transaction is already active on another
// database connection.
//
// EXCLUSIVE is similar to IMMEDIATE in that a write transaction is started
// immediately. EXCLUSIVE and IMMEDIATE are the same in WAL mode, but in
// other journaling modes, EXCLUSIVE prevents other database connections from
// reading the database while the transaction is underway.
(conn).immediate_transaction::<_, WorkspaceError, _>(|| self.create_workspace_with(table, conn))
}
pub(crate) fn create_workspace_with(&self, table: WorkspaceTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
match diesel_record_count!(workspace_table, &table.id, conn) {
0 => diesel_insert_table!(workspace_table, &table, conn),
_ => {
let changeset = WorkspaceTableChangeset::from_table(table);
diesel_update_table!(workspace_table, changeset, conn);
},
}
Ok(()) Ok(())
} }
pub fn read_workspaces( pub(crate) fn create_apps(&self, apps: Vec<App>, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
&self, for app in apps {
workspace_id: Option<String>, let _ = self.app_sql.create_app_with(AppTable::new(app), conn)?;
user_id: &str, }
) -> Result<Vec<WorkspaceTable>, WorkspaceError> { Ok(())
}
pub(crate) fn read_workspaces(&self, workspace_id: Option<String>, user_id: &str) -> Result<Vec<WorkspaceTable>, WorkspaceError> {
let workspaces = match workspace_id { let workspaces = match workspace_id {
None => dsl::workspace_table None => dsl::workspace_table
.filter(workspace_table::user_id.eq(user_id)) .filter(workspace_table::user_id.eq(user_id))
@ -42,25 +79,19 @@ impl WorkspaceSql {
Ok(workspaces) Ok(workspaces)
} }
pub fn update_workspace( pub(crate) fn update_workspace(&self, changeset: WorkspaceTableChangeset) -> Result<(), WorkspaceError> {
&self,
changeset: WorkspaceTableChangeset,
) -> Result<(), WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
diesel_update_table!(workspace_table, changeset, conn); diesel_update_table!(workspace_table, changeset, &*conn);
Ok(()) Ok(())
} }
pub fn delete_workspace(&self, workspace_id: &str) -> Result<(), WorkspaceError> { pub(crate) fn delete_workspace(&self, workspace_id: &str) -> Result<(), WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
diesel_delete_table!(workspace_table, workspace_id, conn); diesel_delete_table!(workspace_table, workspace_id, conn);
Ok(()) Ok(())
} }
pub(crate) fn read_apps_belong_to_workspace( pub(crate) fn read_apps_belong_to_workspace(&self, workspace_id: &str) -> Result<Vec<AppTable>, WorkspaceError> {
&self,
workspace_id: &str,
) -> Result<Vec<AppTable>, WorkspaceError> {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
let apps = conn.immediate_transaction::<_, WorkspaceError, _>(|| { let apps = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
@ -73,4 +104,9 @@ impl WorkspaceSql {
Ok(apps) Ok(apps)
} }
pub(crate) fn get_db_conn(&self) -> Result<DBConnection, WorkspaceError> {
let db = self.database.db_connection()?;
Ok(db)
}
} }

View file

@ -60,4 +60,12 @@ impl WorkspaceTableChangeset {
desc: params.desc, desc: params.desc,
} }
} }
pub(crate) fn from_table(table: WorkspaceTable) -> Self {
WorkspaceTableChangeset {
id: table.id,
name: Some(table.name),
desc: Some(table.desc),
}
}
} }