Skip to content

Commit 9122cc1

Browse files
committed
Debounce drift table updates
This can be a problem during the very first sync, where all exercises, units, ingredients are loaded and rebuild on every new data point.
1 parent eb2bb0f commit 9122cc1

2 files changed

Lines changed: 18 additions & 3 deletions

File tree

lib/providers/exercise_repository.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ class ExerciseRepository {
165165

166166
late StreamController<ExerciseState> controller;
167167
final subs = <StreamSubscription>[];
168+
Timer? emitTimer;
168169

169170
void emit() {
170171
if (exerciseRows == null ||
@@ -303,14 +304,22 @@ class ExerciseRepository {
303304
controller.add(ExerciseState(exercises));
304305
}
305306

307+
// A full rebuild runs on every table update. During the initial sync many
308+
// updates arrive in bursts, so coalesce them into a single rebuild once
309+
// they settle instead of reassembling the whole catalog hundreds of times.
310+
void scheduleEmit() {
311+
emitTimer?.cancel();
312+
emitTimer = Timer(const Duration(milliseconds: 200), emit);
313+
}
314+
306315
controller = StreamController<ExerciseState>(
307316
onListen: () {
308317
void addSub<T>(Stream<T> source, void Function(T) assign) {
309318
subs.add(
310319
source.listen(
311320
(value) {
312321
assign(value);
313-
emit();
322+
scheduleEmit();
314323
},
315324
onError: controller.addError,
316325
),
@@ -334,6 +343,7 @@ class ExerciseRepository {
334343
addSub(_db.select(_db.exerciseCommentTable).watch(), (v) => comments = v);
335344
},
336345
onCancel: () async {
346+
emitTimer?.cancel();
337347
for (final s in subs) {
338348
await s.cancel();
339349
}

lib/providers/nutrition_repository.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import 'package:collection/collection.dart';
2020
import 'package:drift/drift.dart';
2121
import 'package:flutter_riverpod/flutter_riverpod.dart';
2222
import 'package:logging/logging.dart';
23+
import 'package:stream_transform/stream_transform.dart';
2324
import 'package:wger/database/powersync/database.dart';
2425
import 'package:wger/models/nutrition/ingredient.dart';
2526
import 'package:wger/models/nutrition/ingredient_weight_unit.dart';
@@ -40,6 +41,10 @@ class NutritionRepository {
4041

4142
NutritionRepository(this._db);
4243

44+
/// Coalesces bursts of Drift table updates (e.g. during the initial sync) so
45+
/// the heavy per-emission hydration runs once they settle, not on every write.
46+
static const _hydrationDebounce = Duration(milliseconds: 200);
47+
4348
// --- Plans ---
4449

4550
/// Streams all nutritional plans from the local PowerSync-backed Drift table.
@@ -113,7 +118,7 @@ class NutritionRepository {
113118
OrderingTerm.asc(_db.mealTable.time),
114119
]);
115120

116-
return query.watch().map(_hydrateMeals);
121+
return query.watch().debounce(_hydrationDebounce).map(_hydrateMeals);
117122
}
118123

119124
/// Collapses cross-joined rows into hydrated [Meal]s with their child items.
@@ -268,7 +273,7 @@ class NutritionRepository {
268273
),
269274
])..orderBy([OrderingTerm(expression: _db.logItemTable.datetime)]);
270275

271-
return query.watch().map(_hydrateLogs);
276+
return query.watch().debounce(_hydrationDebounce).map(_hydrateLogs);
272277
}
273278

274279
/// Collapses the cross-joined rows into hydrated [LogItem]s.

0 commit comments

Comments
 (0)