Skip to content

Commit 87cbfb9

Browse files
committed
Move options into single class
1 parent f5de535 commit 87cbfb9

File tree

12 files changed

+370
-119
lines changed

12 files changed

+370
-119
lines changed

packages/powersync_core/lib/powersync_core.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export 'src/exceptions.dart';
1010
export 'src/log.dart';
1111
export 'src/open_factory.dart';
1212
export 'src/schema.dart';
13+
export 'src/sync/options.dart' hide ResolvedSyncOptions;
1314
export 'src/sync/sync_status.dart'
1415
hide BucketProgress, InternalSyncDownloadProgress;
1516
export 'src/uuid.dart';

packages/powersync_core/lib/src/database/native/native_powersync_database.dart

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:powersync_core/src/log_internal.dart';
1515
import 'package:powersync_core/src/open_factory/abstract_powersync_open_factory.dart';
1616
import 'package:powersync_core/src/open_factory/native/native_open_factory.dart';
1717
import 'package:powersync_core/src/schema.dart';
18+
import 'package:powersync_core/src/sync/options.dart';
1819
import 'package:powersync_core/src/sync/streaming_sync.dart';
1920
import 'package:powersync_core/src/sync/sync_status.dart';
2021
import 'package:sqlite_async/sqlite3_common.dart';
@@ -118,10 +119,9 @@ class PowerSyncDatabaseImpl
118119
@internal
119120
Future<void> connectInternal({
120121
required PowerSyncBackendConnector connector,
121-
required Duration crudThrottleTime,
122+
required SyncOptions options,
122123
required AbortController abort,
123124
required Zone asyncWorkZone,
124-
Map<String, dynamic>? params,
125125
}) async {
126126
final dbRef = database.isolateConnectionFactory();
127127

@@ -134,6 +134,7 @@ class PowerSyncDatabaseImpl
134134
SendPort? initPort;
135135
final hasInitPort = Completer<void>();
136136
final receivedIsolateExit = Completer<void>();
137+
final resolved = ResolvedSyncOptions(options);
137138

138139
Future<void> waitForShutdown() async {
139140
// Only complete the abortion signal after the isolate shuts down. This
@@ -175,8 +176,8 @@ class PowerSyncDatabaseImpl
175176
} else if (action == 'init') {
176177
final port = initPort = data[1] as SendPort;
177178
hasInitPort.complete();
178-
var crudStream =
179-
database.onChange(['ps_crud'], throttle: crudThrottleTime);
179+
var crudStream = database
180+
.onChange(['ps_crud'], throttle: resolved.crudThrottleTime);
180181
crudUpdateSubscription = crudStream.listen((event) {
181182
port.send(['update']);
182183
});
@@ -238,8 +239,7 @@ class PowerSyncDatabaseImpl
238239
_PowerSyncDatabaseIsolateArgs(
239240
receiveMessages.sendPort,
240241
dbRef,
241-
retryDelay,
242-
clientParams,
242+
resolved,
243243
crudMutex.shared,
244244
syncMutex.shared,
245245
),
@@ -282,16 +282,14 @@ class PowerSyncDatabaseImpl
282282
class _PowerSyncDatabaseIsolateArgs {
283283
final SendPort sPort;
284284
final IsolateConnectionFactory dbRef;
285-
final Duration retryDelay;
286-
final Map<String, dynamic>? parameters;
285+
final ResolvedSyncOptions options;
287286
final SerializedMutex crudMutex;
288287
final SerializedMutex syncMutex;
289288

290289
_PowerSyncDatabaseIsolateArgs(
291290
this.sPort,
292291
this.dbRef,
293-
this.retryDelay,
294-
this.parameters,
292+
this.options,
295293
this.crudMutex,
296294
this.syncMutex,
297295
);
@@ -392,9 +390,8 @@ Future<void> _syncIsolate(_PowerSyncDatabaseIsolateArgs args) async {
392390
invalidCredentialsCallback: invalidateCredentials,
393391
uploadCrud: uploadCrud,
394392
crudUpdateTriggerStream: crudUpdateController.stream,
395-
retryDelay: args.retryDelay,
393+
options: args.options,
396394
client: http.Client(),
397-
syncParameters: args.parameters,
398395
crudMutex: crudMutex,
399396
syncMutex: syncMutex,
400397
);

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:powersync_core/sqlite_async.dart';
66
import 'package:powersync_core/src/abort_controller.dart';
77
import 'package:powersync_core/src/database/powersync_db_mixin.dart';
88
import 'package:powersync_core/src/open_factory/abstract_powersync_open_factory.dart';
9+
import '../sync/options.dart';
910
import 'powersync_database.dart';
1011

1112
import '../connector.dart';
@@ -110,12 +111,12 @@ class PowerSyncDatabaseImpl
110111

111112
@override
112113
@internal
113-
Future<void> connectInternal(
114-
{required PowerSyncBackendConnector connector,
115-
required Duration crudThrottleTime,
116-
required AbortController abort,
117-
required Zone asyncWorkZone,
118-
Map<String, dynamic>? params}) {
114+
Future<void> connectInternal({
115+
required PowerSyncBackendConnector connector,
116+
required AbortController abort,
117+
required Zone asyncWorkZone,
118+
required SyncOptions options,
119+
}) {
119120
throw UnimplementedError();
120121
}
121122

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:powersync_core/src/powersync_update_notification.dart';
1313
import 'package:powersync_core/src/schema.dart';
1414
import 'package:powersync_core/src/schema_logic.dart';
1515
import 'package:powersync_core/src/schema_logic.dart' as schema_logic;
16+
import 'package:powersync_core/src/sync/options.dart';
1617
import 'package:powersync_core/src/sync/sync_status.dart';
1718

1819
mixin PowerSyncDatabaseMixin implements SqliteConnection {
@@ -72,6 +73,7 @@ mixin PowerSyncDatabaseMixin implements SqliteConnection {
7273
/// Delay between retrying failed requests.
7374
/// Defaults to 5 seconds.
7475
/// Only has an effect if changed before calling [connect].
76+
@Deprecated('Set option when calling connect() instead')
7577
Duration retryDelay = const Duration(seconds: 5);
7678

7779
@protected
@@ -269,17 +271,30 @@ mixin PowerSyncDatabaseMixin implements SqliteConnection {
269271
///
270272
/// The connection is automatically re-opened if it fails for any reason.
271273
///
274+
/// To set sync parameters used in your sync rules (if any), use
275+
/// [SyncOptions.params]. [SyncOptions] can also be used to tune the behavior
276+
/// of the sync client, see that class for more information.
277+
///
272278
/// Status changes are reported on [statusStream].
273279
Future<void> connect({
274280
required PowerSyncBackendConnector connector,
275-
Duration crudThrottleTime = const Duration(milliseconds: 10),
276-
Map<String, dynamic>? params,
281+
SyncOptions? options,
282+
@Deprecated('Use SyncOptions.crudThrottleTime instead')
283+
Duration? crudThrottleTime,
284+
@Deprecated('Use SyncOptions.params instead') Map<String, dynamic>? params,
277285
}) async {
278286
// The initialization process acquires a sync connect lock (through
279287
// updateSchema), so ensure the database is ready before we try to acquire
280288
// the lock for the connection.
281289
await initialize();
282290

291+
final resolvedOptions = SyncOptions(
292+
crudThrottleTime: options?.crudThrottleTime ?? crudThrottleTime,
293+
// ignore: deprecated_member_use_from_same_package
294+
retryDelay: options?.retryDelay ?? retryDelay,
295+
params: options?.params ?? params,
296+
);
297+
283298
clientParams = params;
284299
var thisConnectAborter = AbortController();
285300
final zone = Zone.current;
@@ -294,8 +309,7 @@ mixin PowerSyncDatabaseMixin implements SqliteConnection {
294309

295310
await connectInternal(
296311
connector: connector,
297-
crudThrottleTime: crudThrottleTime,
298-
params: params,
312+
options: resolvedOptions,
299313
abort: thisConnectAborter,
300314
// Run follow-up async tasks in the parent zone, a new one is introduced
301315
// while we hold the lock (and async tasks won't hold the sync lock).
@@ -342,17 +356,13 @@ mixin PowerSyncDatabaseMixin implements SqliteConnection {
342356
/// [connect] method and should not be called elsewhere.
343357
/// This method will only be called internally when no other sync client is
344358
/// active, so the method should not call [disconnect] itself.
345-
///
346-
/// The [crudThrottleTime] is the throttle time between CRUD operations, it
347-
/// defaults to 10 milliseconds in [connect].
348359
@protected
349360
@internal
350361
Future<void> connectInternal({
351362
required PowerSyncBackendConnector connector,
352-
required Duration crudThrottleTime,
363+
required SyncOptions options,
353364
required AbortController abort,
354365
required Zone asyncWorkZone,
355-
Map<String, dynamic>? params,
356366
});
357367

358368
/// Close the sync connection.

packages/powersync_core/lib/src/database/web/web_powersync_database.dart

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:powersync_core/src/schema.dart';
1414
import 'package:powersync_core/src/sync/streaming_sync.dart';
1515
import 'package:sqlite_async/sqlite_async.dart';
1616

17+
import '../../sync/options.dart';
1718
import '../../web/sync_controller.dart';
1819

1920
/// A PowerSync managed database.
@@ -114,13 +115,11 @@ class PowerSyncDatabaseImpl
114115
@internal
115116
Future<void> connectInternal({
116117
required PowerSyncBackendConnector connector,
117-
required Duration crudThrottleTime,
118118
required AbortController abort,
119119
required Zone asyncWorkZone,
120-
Map<String, dynamic>? params,
120+
required SyncOptions options,
121121
}) async {
122-
final crudStream =
123-
database.onChange(['ps_crud'], throttle: crudThrottleTime);
122+
final resolved = ResolvedSyncOptions(options);
124123

125124
final storage = BucketStorage(database);
126125
StreamingSync sync;
@@ -130,25 +129,25 @@ class PowerSyncDatabaseImpl
130129
sync = await SyncWorkerHandle.start(
131130
database: this,
132131
connector: connector,
133-
crudThrottleTimeMs: crudThrottleTime.inMilliseconds,
132+
options: options,
134133
workerUri: Uri.base.resolve('/powersync_sync.worker.js'),
135-
syncParams: params,
136134
);
137135
} catch (e) {
138136
logger.warning(
139137
'Could not use shared worker for synchronization, falling back to locks.',
140138
e,
141139
);
140+
final crudStream =
141+
database.onChange(['ps_crud'], throttle: resolved.crudThrottleTime);
142142

143143
sync = StreamingSyncImplementation(
144144
adapter: storage,
145145
credentialsCallback: connector.getCredentialsCached,
146146
invalidCredentialsCallback: connector.prefetchCredentials,
147147
uploadCrud: () => connector.uploadData(this),
148148
crudUpdateTriggerStream: crudStream,
149-
retryDelay: Duration(seconds: 3),
149+
options: resolved,
150150
client: BrowserClient(),
151-
syncParameters: params,
152151
// Only allows 1 sync implementation to run at a time per database
153152
// This should be global (across tabs) when using Navigator locks.
154153
identifier: database.openFactory.path,
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import 'sync_status.dart';
2+
3+
/// An internal instruction emitted by the sync client in the core extension in
4+
/// response to the Dart SDK passing sync data into the extension.
5+
sealed class Instruction {
6+
factory Instruction.fromJson(Map<String, Object?> json) {
7+
return switch (json) {
8+
{'LogLine': final logLine} =>
9+
LogLine.fromJson(logLine as Map<String, Object?>),
10+
{'UpdateSyncStatus': final updateStatus} =>
11+
UpdateSyncStatus.fromJson(updateStatus as Map<String, Object?>),
12+
{'EstablishSyncStream': final establish} =>
13+
EstablishSyncStream.fromJson(establish as Map<String, Object?>),
14+
{'FetchCredentials': final creds} =>
15+
FetchCredentials.fromJson(creds as Map<String, Object?>),
16+
{'CloseSyncStream': _} => const CloseSyncStream(),
17+
{'FlushFileSystem': _} => const FlushFileSystem(),
18+
{'DidCompleteSync': _} => const DidCompleteSync(),
19+
_ => UnknownSyncLine(json)
20+
};
21+
}
22+
}
23+
24+
final class LogLine implements Instruction {
25+
final String severity;
26+
final String line;
27+
28+
LogLine({required this.severity, required this.line});
29+
30+
factory LogLine.fromJson(Map<String, Object?> json) {
31+
return LogLine(
32+
severity: json['severity'] as String,
33+
line: json['line'] as String,
34+
);
35+
}
36+
}
37+
38+
final class EstablishSyncStream implements Instruction {
39+
final Map<String, Object?> request;
40+
41+
EstablishSyncStream(this.request);
42+
43+
factory EstablishSyncStream.fromJson(Map<String, Object?> json) {
44+
return EstablishSyncStream(json['request'] as Map<String, Object?>);
45+
}
46+
}
47+
48+
final class UpdateSyncStatus implements Instruction {
49+
final CoreSyncStatus status;
50+
51+
UpdateSyncStatus({required this.status});
52+
53+
factory UpdateSyncStatus.fromJson(Map<String, Object?> json) {
54+
return UpdateSyncStatus(
55+
status:
56+
CoreSyncStatus.fromJson(json['status'] as Map<String, Object?>));
57+
}
58+
}
59+
60+
final class CoreSyncStatus implements Instruction {
61+
final bool connected;
62+
final bool connecting;
63+
final List<SyncPriorityStatus> priorityStatus;
64+
final DownloadProgress? downloading;
65+
66+
CoreSyncStatus({
67+
required this.connected,
68+
required this.connecting,
69+
required this.priorityStatus,
70+
required this.downloading,
71+
});
72+
73+
factory CoreSyncStatus.fromJson(Map<String, Object?> json) {
74+
return CoreSyncStatus(
75+
connected: json['connected'] as bool,
76+
connecting: json['connecting'] as bool,
77+
priorityStatus: [
78+
for (final entry in json['priority_status'] as List)
79+
_priorityStatusFromJson(entry as Map<String, Object?>)
80+
],
81+
downloading: switch (json['downloading']) {
82+
null => null,
83+
final raw as Map<String, Object?> => DownloadProgress.fromJson(raw),
84+
},
85+
);
86+
}
87+
88+
static SyncPriorityStatus _priorityStatusFromJson(Map<String, Object?> json) {
89+
return (
90+
priority: BucketPriority(json['priority'] as int),
91+
hasSynced: json['has_synced'] as bool?,
92+
lastSyncedAt: switch (json['last_synced_at']) {
93+
null => null,
94+
final lastSyncedAt as int =>
95+
DateTime.fromMillisecondsSinceEpoch(lastSyncedAt * 1000),
96+
},
97+
);
98+
}
99+
}
100+
101+
final class DownloadProgress implements Instruction {
102+
final Map<String, BucketProgress> progress;
103+
104+
DownloadProgress(this.progress);
105+
106+
factory DownloadProgress.fromJson(Map<String, Object?> line) {
107+
return DownloadProgress(line.map((k, v) =>
108+
MapEntry(k, _bucketProgressFromJson(v as Map<String, Object?>))));
109+
}
110+
111+
static BucketProgress _bucketProgressFromJson(Map<String, Object?> json) {
112+
return (
113+
priority: BucketPriority(json['priority'] as int),
114+
atLast: json['at_last'] as int,
115+
sinceLast: json['since_last'] as int,
116+
targetCount: json['target_count'] as int,
117+
);
118+
}
119+
}
120+
121+
final class FetchCredentials implements Instruction {
122+
final bool didExpire;
123+
124+
FetchCredentials(this.didExpire);
125+
126+
factory FetchCredentials.fromJson(Map<String, Object?> line) {
127+
return FetchCredentials(line['did_expire'] as bool);
128+
}
129+
}
130+
131+
final class CloseSyncStream implements Instruction {
132+
const CloseSyncStream();
133+
}
134+
135+
final class FlushFileSystem implements Instruction {
136+
const FlushFileSystem();
137+
}
138+
139+
final class DidCompleteSync implements Instruction {
140+
const DidCompleteSync();
141+
}
142+
143+
final class UnknownSyncLine implements Instruction {
144+
final Map<String, Object?> source;
145+
146+
UnknownSyncLine(this.source);
147+
}

0 commit comments

Comments
 (0)