mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Fix startup sync results not propagated to main isolate
This commit is contained in:
parent
a04ecefed9
commit
f97476e4f0
13 changed files with 229 additions and 45 deletions
|
@ -13,6 +13,7 @@ import 'package:nc_photos/entity/file_util.dart' as file_util;
|
|||
import 'package:nc_photos/progress_util.dart';
|
||||
import 'package:nc_photos/rx_extension.dart';
|
||||
import 'package:nc_photos/use_case/file/list_file.dart';
|
||||
import 'package:nc_photos/use_case/find_file_descriptor.dart';
|
||||
import 'package:nc_photos/use_case/remove.dart';
|
||||
import 'package:nc_photos/use_case/sync_dir.dart';
|
||||
import 'package:nc_photos/use_case/update_property.dart';
|
||||
|
@ -20,6 +21,7 @@ import 'package:np_codegen/np_codegen.dart';
|
|||
import 'package:np_common/lazy.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_common/or_null.dart';
|
||||
import 'package:np_db/np_db.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
|
@ -233,6 +235,69 @@ class FilesController {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> applySyncResult({
|
||||
DbSyncIdResult? favorites,
|
||||
List<int>? fileExifs,
|
||||
}) async {
|
||||
if (favorites?.isNotEmpty != true && fileExifs?.isNotEmpty != true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do async ops first
|
||||
final fileExifFiles =
|
||||
await fileExifs?.letFuture((e) async => await FindFileDescriptor(_c)(
|
||||
account,
|
||||
e,
|
||||
onFileNotFound: (id) {
|
||||
_log.warning("[applySyncResult] File id not found: $id");
|
||||
},
|
||||
));
|
||||
|
||||
final next = LinkedHashMap.of(_dataStreamController.value.files);
|
||||
if (favorites != null && favorites.isNotEmpty) {
|
||||
_applySyncFavoriteResult(next, favorites);
|
||||
}
|
||||
if (fileExifFiles != null && fileExifFiles.isNotEmpty) {
|
||||
_applySyncFileExifResult(next, fileExifFiles);
|
||||
}
|
||||
_dataStreamController.addWithValue((value) => value.copyWith(files: next));
|
||||
}
|
||||
|
||||
void _applySyncFavoriteResult(
|
||||
Map<int, FileDescriptor> next, DbSyncIdResult result) {
|
||||
for (final id in result.insert) {
|
||||
final f = next[id];
|
||||
if (f == null) {
|
||||
_log.warning("[_applySyncFavoriteResult] File id not found: $id");
|
||||
continue;
|
||||
}
|
||||
if (f is File) {
|
||||
next[id] = f.copyWith(isFavorite: true);
|
||||
} else {
|
||||
next[id] = f.copyWith(fdIsFavorite: true);
|
||||
}
|
||||
}
|
||||
for (final id in result.delete) {
|
||||
final f = next[id];
|
||||
if (f == null) {
|
||||
_log.warning("[_applySyncFavoriteResult] File id not found: $id");
|
||||
continue;
|
||||
}
|
||||
if (f is File) {
|
||||
next[id] = f.copyWith(isFavorite: false);
|
||||
} else {
|
||||
next[id] = f.copyWith(fdIsFavorite: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _applySyncFileExifResult(
|
||||
Map<int, FileDescriptor> next, List<FileDescriptor> results) {
|
||||
for (final f in results) {
|
||||
next[f.fdId] = f;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _load() async {
|
||||
var lastData = _FilesStreamEvent(
|
||||
files: const {},
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/controller/files_controller.dart';
|
||||
import 'package:nc_photos/controller/persons_controller.dart';
|
||||
import 'package:nc_photos/entity/person.dart';
|
||||
import 'package:nc_photos/use_case/startup_sync.dart';
|
||||
|
||||
|
@ -15,14 +17,19 @@ class SyncController {
|
|||
_isDisposed = true;
|
||||
}
|
||||
|
||||
Future<void> requestSync(
|
||||
Account account, PersonProvider personProvider) async {
|
||||
Future<void> requestSync({
|
||||
required Account account,
|
||||
required FilesController filesController,
|
||||
required PersonsController personsController,
|
||||
required PersonProvider personProvider,
|
||||
}) async {
|
||||
if (_isDisposed) {
|
||||
return;
|
||||
}
|
||||
if (_syncCompleter == null) {
|
||||
_syncCompleter = Completer();
|
||||
final result = await StartupSync.runInIsolate(account, personProvider);
|
||||
final result = await StartupSync.runInIsolate(
|
||||
account, filesController, personsController, personProvider);
|
||||
if (!_isDisposed && result.isSyncPersonUpdated) {
|
||||
onPeopleUpdated?.call();
|
||||
}
|
||||
|
@ -32,15 +39,23 @@ class SyncController {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> requestResync(
|
||||
Account account, PersonProvider personProvider) async {
|
||||
Future<void> requestResync({
|
||||
required Account account,
|
||||
required FilesController filesController,
|
||||
required PersonsController personsController,
|
||||
required PersonProvider personProvider,
|
||||
}) async {
|
||||
if (_syncCompleter?.isCompleted == true) {
|
||||
_syncCompleter = null;
|
||||
return requestSync(account, personProvider);
|
||||
} else {
|
||||
// already syncing
|
||||
return requestSync(account, personProvider);
|
||||
}
|
||||
return requestSync(
|
||||
account: account,
|
||||
filesController: filesController,
|
||||
personsController: personsController,
|
||||
personProvider: personProvider,
|
||||
);
|
||||
}
|
||||
|
||||
final Account account;
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:nc_photos/db/entity_converter.dart';
|
|||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/event/event.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_db/np_db.dart';
|
||||
|
||||
part 'cache_favorite.g.dart';
|
||||
|
||||
|
@ -15,18 +16,18 @@ class CacheFavorite {
|
|||
|
||||
/// Cache favorites using results from remote
|
||||
///
|
||||
/// Return number of files updated
|
||||
Future<int> call(Account account, Iterable<int> remoteFileIds) async {
|
||||
/// Return the fileIds of the affected files
|
||||
Future<DbSyncIdResult> call(
|
||||
Account account, Iterable<int> remoteFileIds) async {
|
||||
_log.info("[call] Cache favorites");
|
||||
final result = await _c.npDb.syncFavoriteFiles(
|
||||
account: account.toDb(),
|
||||
favoriteFileIds: remoteFileIds.toList(),
|
||||
);
|
||||
final count = result.insert + result.delete + result.update;
|
||||
if (count > 0) {
|
||||
if (result.isNotEmpty) {
|
||||
KiwiContainer().resolve<EventBus>().fire(FavoriteResyncedEvent(account));
|
||||
}
|
||||
return count;
|
||||
return result;
|
||||
}
|
||||
|
||||
final DiContainer _c;
|
||||
|
|
|
@ -7,6 +7,8 @@ import 'package:logging/logging.dart';
|
|||
import 'package:mutex/mutex.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/app_init.dart' as app_init;
|
||||
import 'package:nc_photos/controller/files_controller.dart';
|
||||
import 'package:nc_photos/controller/persons_controller.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/person.dart';
|
||||
import 'package:nc_photos/event/event.dart';
|
||||
|
@ -14,8 +16,11 @@ import 'package:nc_photos/use_case/person/sync_person.dart';
|
|||
import 'package:nc_photos/use_case/sync_favorite.dart';
|
||||
import 'package:nc_photos/use_case/sync_tag.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_common/type.dart';
|
||||
import 'package:np_db/np_db.dart';
|
||||
import 'package:np_platform_util/np_platform_util.dart';
|
||||
import 'package:to_string/to_string.dart';
|
||||
|
||||
part 'startup_sync.g.dart';
|
||||
|
||||
|
@ -28,7 +33,11 @@ class StartupSync {
|
|||
|
||||
/// Sync in a background isolate
|
||||
static Future<SyncResult> runInIsolate(
|
||||
Account account, PersonProvider personProvider) async {
|
||||
Account account,
|
||||
FilesController filesController,
|
||||
PersonsController personsController,
|
||||
PersonProvider personProvider,
|
||||
) async {
|
||||
return _mutex.protect(() async {
|
||||
if (getRawPlatform() == NpPlatform.web) {
|
||||
// not supported on web
|
||||
|
@ -42,7 +51,7 @@ class StartupSync {
|
|||
final result = SyncResult.fromJson(resultJson);
|
||||
// events fired in background isolate won't be noticed by the main isolate,
|
||||
// so we fire them again here
|
||||
_broadcastResult(account, result);
|
||||
_broadcastResult(account, filesController, personsController, result);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
@ -52,16 +61,16 @@ class StartupSync {
|
|||
Account account, PersonProvider personProvider) async {
|
||||
_log.info("[_run] Begin sync");
|
||||
final stopwatch = Stopwatch()..start();
|
||||
late final int syncFavoriteCount;
|
||||
late final bool isSyncPersonUpdated;
|
||||
DbSyncIdResult? syncFavoriteResult;
|
||||
DbSyncIdResult? syncTagResult;
|
||||
var isSyncPersonUpdated = false;
|
||||
try {
|
||||
syncFavoriteCount = await SyncFavorite(_c)(account);
|
||||
syncFavoriteResult = await SyncFavorite(_c)(account);
|
||||
} catch (e, stackTrace) {
|
||||
_log.shout("[_run] Failed while SyncFavorite", e, stackTrace);
|
||||
syncFavoriteCount = -1;
|
||||
}
|
||||
try {
|
||||
await SyncTag(_c)(account);
|
||||
syncTagResult = await SyncTag(_c)(account);
|
||||
} catch (e, stackTrace) {
|
||||
_log.shout("[_run] Failed while SyncTag", e, stackTrace);
|
||||
}
|
||||
|
@ -72,16 +81,28 @@ class StartupSync {
|
|||
}
|
||||
_log.info("[_run] Elapsed time: ${stopwatch.elapsedMilliseconds}ms");
|
||||
return SyncResult(
|
||||
syncFavoriteCount: syncFavoriteCount,
|
||||
syncFavoriteResult: syncFavoriteResult,
|
||||
syncTagResult: syncTagResult,
|
||||
isSyncPersonUpdated: isSyncPersonUpdated,
|
||||
);
|
||||
}
|
||||
|
||||
static void _broadcastResult(Account account, SyncResult result) {
|
||||
final eventBus = KiwiContainer().resolve<EventBus>();
|
||||
if (result.syncFavoriteCount > 0) {
|
||||
static void _broadcastResult(
|
||||
Account account,
|
||||
FilesController filesController,
|
||||
PersonsController personsController,
|
||||
SyncResult result,
|
||||
) {
|
||||
_$StartupSyncNpLog.log.info('[_broadcastResult] $result');
|
||||
if (result.syncFavoriteResult != null) {
|
||||
filesController.applySyncResult(favorites: result.syncFavoriteResult!);
|
||||
// legacy
|
||||
final eventBus = KiwiContainer().resolve<EventBus>();
|
||||
eventBus.fire(FavoriteResyncedEvent(account));
|
||||
}
|
||||
if (result.isSyncPersonUpdated) {
|
||||
personsController.reload();
|
||||
}
|
||||
}
|
||||
|
||||
final DiContainer _c;
|
||||
|
@ -89,23 +110,35 @@ class StartupSync {
|
|||
static final _mutex = Mutex();
|
||||
}
|
||||
|
||||
@toString
|
||||
class SyncResult {
|
||||
const SyncResult({
|
||||
required this.syncFavoriteCount,
|
||||
required this.syncFavoriteResult,
|
||||
required this.syncTagResult,
|
||||
required this.isSyncPersonUpdated,
|
||||
});
|
||||
|
||||
factory SyncResult.fromJson(JsonObj json) => SyncResult(
|
||||
syncFavoriteCount: json["syncFavoriteCount"],
|
||||
syncFavoriteResult: (json["syncFavoriteResult"] as Map?)
|
||||
?.cast<String, dynamic>()
|
||||
.let(DbSyncIdResult.fromJson),
|
||||
syncTagResult: (json["syncTagResult"] as Map?)
|
||||
?.cast<String, dynamic>()
|
||||
.let(DbSyncIdResult.fromJson),
|
||||
isSyncPersonUpdated: json["isSyncPersonUpdated"],
|
||||
);
|
||||
|
||||
JsonObj toJson() => {
|
||||
"syncFavoriteCount": syncFavoriteCount,
|
||||
"syncFavoriteResult": syncFavoriteResult?.toJson(),
|
||||
"syncTagResult": syncTagResult?.toJson(),
|
||||
"isSyncPersonUpdated": isSyncPersonUpdated,
|
||||
};
|
||||
|
||||
final int syncFavoriteCount;
|
||||
@override
|
||||
String toString() => _$toString();
|
||||
|
||||
final DbSyncIdResult? syncFavoriteResult;
|
||||
final DbSyncIdResult? syncTagResult;
|
||||
final bool isSyncPersonUpdated;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,3 +12,14 @@ extension _$StartupSyncNpLog on StartupSync {
|
|||
|
||||
static final log = Logger("use_case.startup_sync.StartupSync");
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// ToStringGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$SyncResultToString on SyncResult {
|
||||
String _$toString() {
|
||||
// ignore: unnecessary_string_interpolations
|
||||
return "SyncResult {syncFavoriteResult: $syncFavoriteResult, syncTagResult: $syncTagResult, isSyncPersonUpdated: $isSyncPersonUpdated}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:nc_photos/entity/file_util.dart' as file_util;
|
|||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:nc_photos/use_case/cache_favorite.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_db/np_db.dart';
|
||||
|
||||
part 'sync_favorite.g.dart';
|
||||
|
||||
|
@ -18,7 +19,7 @@ class SyncFavorite {
|
|||
/// Sync favorites in cache db with remote server
|
||||
///
|
||||
/// Return number of files updated
|
||||
Future<int> call(Account account) async {
|
||||
Future<DbSyncIdResult> call(Account account) async {
|
||||
_log.info("[call] Sync favorites with remote");
|
||||
final remote = await _getRemoteFavoriteFileIds(account);
|
||||
return await CacheFavorite(_c)(account, remote);
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:nc_photos/account.dart';
|
|||
import 'package:nc_photos/db/entity_converter.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_db/np_db.dart';
|
||||
|
||||
part 'sync_tag.g.dart';
|
||||
|
||||
|
@ -11,13 +12,16 @@ class SyncTag {
|
|||
const SyncTag(this._c);
|
||||
|
||||
/// Sync tags in cache db with remote server
|
||||
Future<void> call(Account account) async {
|
||||
///
|
||||
/// Return tagIds of the affected tags
|
||||
Future<DbSyncIdResult> call(Account account) async {
|
||||
_log.info("[call] Sync tags with remote");
|
||||
final remote = await _c.tagRepoRemote.list(account);
|
||||
await _c.npDb.syncTags(
|
||||
final result = await _c.npDb.syncTags(
|
||||
account: account.toDb(),
|
||||
tags: remote.map(DbTagConverter.toDb).toList(),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
final DiContainer _c;
|
||||
|
|
|
@ -609,7 +609,11 @@ class _HomePhotosState extends State<HomePhotos>
|
|||
if (isPostSuccess) {
|
||||
_isScrollbarVisible = true;
|
||||
context.read<AccountController>().syncController.requestSync(
|
||||
widget.account, _accountPrefController.personProvider.value);
|
||||
account: widget.account,
|
||||
filesController: context.read(),
|
||||
personsController: context.read(),
|
||||
personProvider: _accountPrefController.personProvider.value,
|
||||
);
|
||||
_tryStartMetadataTask(context);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,6 +10,8 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
|||
required this.accountPrefController,
|
||||
required this.collectionsController,
|
||||
required this.sessionController,
|
||||
required this.syncController,
|
||||
required this.personsController,
|
||||
}) : super(_State.init(
|
||||
zoom: prefController.homePhotosZoomLevel.value,
|
||||
isEnableMemoryCollection:
|
||||
|
@ -142,6 +144,12 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
|||
memoryCollections: ev.memoryCollections,
|
||||
isLoading: _itemTransformerQueue.isProcessing,
|
||||
));
|
||||
syncController.requestSync(
|
||||
account: account,
|
||||
filesController: controller,
|
||||
personsController: personsController,
|
||||
personProvider: accountPrefController.personProvider.value,
|
||||
);
|
||||
_tryStartMetadataTask();
|
||||
}
|
||||
|
||||
|
@ -403,6 +411,8 @@ class _Bloc extends Bloc<_Event, _State> with BlocLogger {
|
|||
final AccountPrefController accountPrefController;
|
||||
final CollectionsController collectionsController;
|
||||
final SessionController sessionController;
|
||||
final SyncController syncController;
|
||||
final PersonsController personsController;
|
||||
|
||||
final _itemTransformerQueue =
|
||||
ComputeQueue<_ItemTransformerArgument, _ItemTransformerResult>();
|
||||
|
|
|
@ -18,8 +18,10 @@ import 'package:nc_photos/controller/account_controller.dart';
|
|||
import 'package:nc_photos/controller/account_pref_controller.dart';
|
||||
import 'package:nc_photos/controller/collections_controller.dart';
|
||||
import 'package:nc_photos/controller/files_controller.dart';
|
||||
import 'package:nc_photos/controller/persons_controller.dart';
|
||||
import 'package:nc_photos/controller/pref_controller.dart';
|
||||
import 'package:nc_photos/controller/session_controller.dart';
|
||||
import 'package:nc_photos/controller/sync_controller.dart';
|
||||
import 'package:nc_photos/db/entity_converter.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/download_handler.dart';
|
||||
|
@ -87,6 +89,8 @@ class HomePhotos2 extends StatelessWidget {
|
|||
accountPrefController: accountController.accountPrefController,
|
||||
collectionsController: accountController.collectionsController,
|
||||
sessionController: accountController.sessionController,
|
||||
syncController: accountController.syncController,
|
||||
personsController: accountController.personsController,
|
||||
),
|
||||
child: const _WrappedHomePhotos(),
|
||||
);
|
||||
|
|
|
@ -109,8 +109,12 @@ class _WrappedAccountSettingsState extends State<_WrappedAccountSettings>
|
|||
if (_bloc.state.shouldResync &&
|
||||
_bloc.state.personProvider != PersonProvider.none) {
|
||||
_log.fine("[dispose] Requesting to resync account");
|
||||
_accountController.syncController
|
||||
.requestResync(_bloc.state.account, _bloc.state.personProvider);
|
||||
_accountController.syncController.requestResync(
|
||||
account: _bloc.state.account,
|
||||
filesController: context.read(),
|
||||
personsController: context.read(),
|
||||
personProvider: _bloc.state.personProvider,
|
||||
);
|
||||
}
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
|
|
|
@ -49,6 +49,36 @@ class DbSyncResult {
|
|||
final int update;
|
||||
}
|
||||
|
||||
/// Sync results with ids
|
||||
///
|
||||
/// The meaning of the ids returned depends on the specific call
|
||||
class DbSyncIdResult {
|
||||
const DbSyncIdResult({
|
||||
required this.insert,
|
||||
required this.delete,
|
||||
required this.update,
|
||||
});
|
||||
|
||||
factory DbSyncIdResult.fromJson(JsonObj json) => DbSyncIdResult(
|
||||
insert: (json["insert"] as List).cast<int>(),
|
||||
delete: (json["delete"] as List).cast<int>(),
|
||||
update: (json["update"] as List).cast<int>(),
|
||||
);
|
||||
|
||||
JsonObj toJson() => {
|
||||
"insert": insert,
|
||||
"delete": delete,
|
||||
"update": update,
|
||||
};
|
||||
|
||||
bool get isEmpty => insert.isEmpty && delete.isEmpty && update.isEmpty;
|
||||
bool get isNotEmpty => !isEmpty;
|
||||
|
||||
final List<int> insert;
|
||||
final List<int> delete;
|
||||
final List<int> update;
|
||||
}
|
||||
|
||||
@toString
|
||||
class DbLocationGroup with EquatableMixin {
|
||||
const DbLocationGroup({
|
||||
|
@ -235,7 +265,9 @@ abstract class NpDb {
|
|||
});
|
||||
|
||||
/// Add or replace nc albums in db
|
||||
Future<DbSyncResult> syncFavoriteFiles({
|
||||
///
|
||||
/// Return fileIds affected by this call
|
||||
Future<DbSyncIdResult> syncFavoriteFiles({
|
||||
required DbAccount account,
|
||||
required List<int> favoriteFileIds,
|
||||
});
|
||||
|
@ -374,7 +406,7 @@ abstract class NpDb {
|
|||
});
|
||||
|
||||
/// Replace all tags for [account]
|
||||
Future<DbSyncResult> syncTags({
|
||||
Future<DbSyncIdResult> syncTags({
|
||||
required DbAccount account,
|
||||
required List<DbTag> tags,
|
||||
});
|
||||
|
|
|
@ -337,7 +337,7 @@ class NpDbSqlite implements NpDb {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<DbSyncResult> syncFavoriteFiles({
|
||||
Future<DbSyncIdResult> syncFavoriteFiles({
|
||||
required DbAccount account,
|
||||
required List<int> favoriteFileIds,
|
||||
}) async {
|
||||
|
@ -370,10 +370,10 @@ class NpDbSqlite implements NpDb {
|
|||
isFavorite: const OrNull(false),
|
||||
);
|
||||
}
|
||||
return DbSyncResult(
|
||||
insert: inserts.length,
|
||||
delete: deletes.length,
|
||||
update: 0,
|
||||
return DbSyncIdResult(
|
||||
insert: inserts,
|
||||
delete: deletes,
|
||||
update: const [],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -834,7 +834,7 @@ class NpDbSqlite implements NpDb {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<DbSyncResult> syncTags({
|
||||
Future<DbSyncIdResult> syncTags({
|
||||
required DbAccount account,
|
||||
required List<DbTag> tags,
|
||||
}) async {
|
||||
|
@ -863,10 +863,10 @@ class NpDbSqlite implements NpDb {
|
|||
updates: updates,
|
||||
);
|
||||
}
|
||||
return DbSyncResult(
|
||||
insert: inserts.length,
|
||||
delete: deletes.length,
|
||||
update: updates.length,
|
||||
return DbSyncIdResult(
|
||||
insert: inserts.map((e) => e.id).toList(),
|
||||
delete: deletes.map((e) => e.id).toList(),
|
||||
update: updates.map((e) => e.id).toList(),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue