Skip to content

Commit b23b3ad

Browse files
committed
Two more tests
1 parent c0d7042 commit b23b3ad

File tree

7 files changed

+68
-5
lines changed

7 files changed

+68
-5
lines changed

packages/powersync_core/lib/src/database/powersync_db_mixin.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,9 @@ SELECT * FROM crud_entries;
504504
await database.refreshSchema();
505505
}
506506

507+
/// Create a [SyncStream] instance for the given [name] and [parameters].
508+
///
509+
/// Use [SyncStream.subscribe] to subscribe to the returned stream.
507510
SyncStream syncStream(String name, [Map<String, Object?>? parameters]) {
508511
return _connections.syncStream(name, parameters);
509512
}

packages/powersync_core/lib/src/sync/connection_manager.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ final class _ActiveSubscription {
355355

356356
final class _SyncStreamSubscriptionHandle implements SyncStreamSubscription {
357357
final _ActiveSubscription _source;
358+
var _active = true;
358359

359360
_SyncStreamSubscriptionHandle(this._source) {
360361
_source.refcount++;
@@ -368,9 +369,12 @@ final class _SyncStreamSubscriptionHandle implements SyncStreamSubscription {
368369
Map<String, Object?>? get parameters => _source.parameters;
369370

370371
@override
371-
void unsubscribe() async {
372-
_finalizer.detach(this);
373-
_source.decrementRefCount();
372+
void unsubscribe() {
373+
if (_active) {
374+
_active = false;
375+
_finalizer.detach(this);
376+
_source.decrementRefCount();
377+
}
374378
}
375379

376380
@override

packages/powersync_core/lib/src/sync/options.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ final class SyncOptions {
2727
/// The [SyncClientImplementation] to use.
2828
final SyncClientImplementation syncImplementation;
2929

30+
/// Whether streams that have been defined with `auto_subscribe: true` should
31+
/// be synced when they don't have an explicit subscription.
32+
///
33+
/// This is enabled by default.
3034
final bool? includeDefaultStreams;
3135

3236
const SyncOptions({

packages/powersync_core/lib/src/sync/stream.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ abstract interface class SyncStreamDescription {
2424
abstract interface class SyncSubscriptionDescription
2525
extends SyncStreamDescription {
2626
/// Whether this stream is active, meaning that the subscription has been
27-
/// acknownledged by the sync serivce.
27+
/// acknowledged by the sync serivce.
2828
bool get active;
2929

3030
/// Whether this stream subscription is included by default, regardless of

packages/powersync_core/lib/src/sync/streaming_sync.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,8 @@ final class _ActiveRustStreamingIteration {
622622

623623
List<Object?> _encodeSubscriptions(List<SubscribedStream> subscriptions) {
624624
return sync._activeSubscriptions
625-
.map((s) => {'name': s.name, 'params': s.parameters})
625+
.map((s) =>
626+
{'name': s.name, 'params': convert.json.decode(s.parameters)})
626627
.toList();
627628
}
628629

packages/powersync_core/lib/src/sync/sync_status.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,21 @@ extension InternalSyncStatusAccess on SyncStatus {
212212
_internalSubscriptions;
213213
}
214214

215+
/// Current information about a [SyncStream] that the sync client is subscribed
216+
/// to.
215217
final class SyncStreamStatus {
218+
/// If the [SyncStatus] is currently [SyncStatus.downloading], download
219+
/// progress for this stream.
216220
final ProgressWithOperations? progress;
217221
final CoreActiveStreamSubscription _internal;
218222

223+
/// The [SyncSubscriptionDescription] providing information about the current
224+
/// stream state.
219225
SyncSubscriptionDescription get subscription => _internal;
226+
227+
/// The [StreamPriority] of the current stream.
228+
///
229+
/// New data on higher-priority streams can interrupt lower-priority streams.
220230
StreamPriority get priority => _internal.priority;
221231

222232
SyncStreamStatus._(this._internal, SyncDownloadProgress? progress)

packages/powersync_core/test/sync/stream_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,4 +219,45 @@ void main() {
219219
var status = await stream.next;
220220
expect(status.forStream(subscription), isNotNull);
221221
});
222+
223+
test('unsubscribing multiple times has no effect', () async {
224+
final a = await database.syncStream('a').subscribe();
225+
final aAgain = await database.syncStream('a').subscribe();
226+
a.unsubscribe();
227+
a.unsubscribe(); // Should not decrement the refcount again
228+
229+
// Pretend the streams are expired - they should still be requested because
230+
// the core extension extends the lifetime of streams currently referenced
231+
// before connecting.
232+
await database.execute(
233+
'UPDATE ps_stream_subscriptions SET expires_at = unixepoch() - 1000');
234+
235+
await waitForConnection();
236+
final request = await syncService.waitForListener;
237+
expect(
238+
json.decode(await request.readAsString()),
239+
containsPair(
240+
'streams',
241+
containsPair('subscriptions', isNotEmpty),
242+
),
243+
);
244+
aAgain.unsubscribe();
245+
});
246+
247+
test('unsubscribeAll', () async {
248+
final a = await database.syncStream('a').subscribe();
249+
await database.syncStream('a').unsubscribeAll();
250+
251+
// Despite a being active, it should not be requested.
252+
await waitForConnection();
253+
final request = await syncService.waitForListener;
254+
expect(
255+
json.decode(await request.readAsString()),
256+
containsPair(
257+
'streams',
258+
containsPair('subscriptions', isEmpty),
259+
),
260+
);
261+
a.unsubscribe();
262+
});
222263
}

0 commit comments

Comments
 (0)