Skip to content

Commit b866741

Browse files
authored
Merge pull request #249 from powersync-ja/version-check-on-init
Improve compatibility check for core extension
2 parents 0949fe1 + d405df9 commit b866741

File tree

7 files changed

+111
-21
lines changed

7 files changed

+111
-21
lines changed

packages/powersync_core/lib/powersync_core.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ export 'src/database/powersync_database.dart';
99
export 'src/exceptions.dart';
1010
export 'src/log.dart';
1111
export 'src/open_factory.dart';
12-
export 'src/powersync_database.dart';
1312
export 'src/schema.dart';
1413
export 'src/sync_status.dart';
1514
export 'src/uuid.dart';
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import 'package:sqlite_async/sqlite3_common.dart';
2+
3+
/// A parsed (major, minor, patch) version triple representing a version of the
4+
/// loaded core extension.
5+
extension type const PowerSyncCoreVersion((int, int, int) _tuple) {
6+
int get major => _tuple.$1;
7+
int get minor => _tuple.$2;
8+
int get patch => _tuple.$3;
9+
10+
int compareTo(PowerSyncCoreVersion other) {
11+
return switch (major.compareTo(other.major)) {
12+
0 => switch (minor.compareTo(other.minor)) {
13+
0 => patch.compareTo(other.patch),
14+
var other => other,
15+
},
16+
var other => other,
17+
};
18+
}
19+
20+
bool operator <(PowerSyncCoreVersion other) => compareTo(other) < 0;
21+
bool operator >=(PowerSyncCoreVersion other) => compareTo(other) >= 0;
22+
23+
String get versionString => '$major.$minor.$patch';
24+
25+
void checkSupported() {
26+
const isWeb = bool.fromEnvironment('dart.library.js_interop');
27+
28+
if (this < minimum || this >= maximumExclusive) {
29+
var message =
30+
'Unsupported powersync extension version. This version of the '
31+
'PowerSync SDK needs >=${minimum.versionString} '
32+
'<${maximumExclusive.versionString}, '
33+
'but detected version $versionString.';
34+
if (isWeb) {
35+
message +=
36+
'\nTry downloading the updated assets: https://docs.powersync.com/client-sdk-references/flutter/flutter-web-support#assets';
37+
}
38+
39+
throw SqliteException(1, message);
40+
}
41+
}
42+
43+
/// Parses the output of `powersync_rs_version()`, e.g. `0.3.9/5d64f366`, into
44+
/// a [PowerSyncCoreVersion].
45+
static PowerSyncCoreVersion parse(String version) {
46+
try {
47+
final [major, minor, patch] =
48+
version.split(RegExp(r'[./]')).take(3).map(int.parse).toList();
49+
50+
return PowerSyncCoreVersion((major, minor, patch));
51+
} catch (e) {
52+
throw SqliteException(1,
53+
'Unsupported powersync extension version. Need >=0.2.0 <1.0.0, got: $version. Details: $e');
54+
}
55+
}
56+
57+
/// The minimum version of the sqlite core extensions we support. We check
58+
/// this version when opening databases to fail early and with an actionable
59+
/// error message.
60+
// Note: When updating this, also update the download URL in
61+
// scripts/init_powersync_core_binary.dart and the version ref in
62+
// packages/sqlite3_wasm_build/build.sh
63+
static const minimum = PowerSyncCoreVersion((0, 3, 11));
64+
65+
/// The first version of the core extensions that this version of the Dart
66+
/// SDK doesn't support.
67+
static const maximumExclusive = PowerSyncCoreVersion((1, 0, 0));
68+
}

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

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:powersync_core/sqlite_async.dart';
77
import 'package:powersync_core/src/abort_controller.dart';
88
import 'package:powersync_core/src/connector.dart';
99
import 'package:powersync_core/src/crud.dart';
10+
import 'package:powersync_core/src/database/core_version.dart';
1011
import 'package:powersync_core/src/powersync_update_notification.dart';
1112
import 'package:powersync_core/src/schema.dart';
1213
import 'package:powersync_core/src/schema_logic.dart';
@@ -93,23 +94,7 @@ mixin PowerSyncDatabaseMixin implements SqliteConnection {
9394
1, 'The powersync extension is not loaded correctly. Details: $e');
9495
}
9596

96-
// Parse version
97-
List<int> versionInts;
98-
try {
99-
versionInts =
100-
version.split(RegExp(r'[./]')).take(3).map(int.parse).toList();
101-
} catch (e) {
102-
throw SqliteException(1,
103-
'Unsupported powersync extension version. Need >=0.2.0 <1.0.0, got: $version. Details: $e');
104-
}
105-
106-
// Validate >=0.2.0 <1.0.0
107-
if (versionInts[0] != 0 ||
108-
(versionInts[1] < 2) ||
109-
(versionInts[1] == 2 && versionInts[2] < 0)) {
110-
throw SqliteException(1,
111-
'Unsupported powersync extension version. Need >=0.2.0 <1.0.0, got: $version');
112-
}
97+
PowerSyncCoreVersion.parse(version).checkSupported();
11398
}
11499

115100
/// Wait for initialization to complete.

packages/powersync_core/lib/src/powersync_database.dart

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import 'package:powersync_core/src/database/core_version.dart';
2+
import 'package:sqlite3/common.dart';
3+
import 'package:test/test.dart';
4+
5+
void main() {
6+
group('PowerSyncCoreVersion', () {
7+
test('parse', () {
8+
expect(PowerSyncCoreVersion.parse('0.3.9/5d64f366'), (0, 3, 9));
9+
});
10+
11+
test('compare', () {
12+
void expectLess(String a, String b) {
13+
final parsedA = PowerSyncCoreVersion.parse(a);
14+
final parsedB = PowerSyncCoreVersion.parse(b);
15+
16+
expect(parsedA.compareTo(parsedB), -1);
17+
expect(parsedB.compareTo(parsedA), 1);
18+
19+
expect(parsedA.compareTo(parsedA), 0);
20+
expect(parsedB.compareTo(parsedB), 0);
21+
}
22+
23+
expectLess('0.1.0', '1.0.0');
24+
expectLess('1.0.0', '1.2.0');
25+
expectLess('0.3.9', '0.3.11');
26+
});
27+
28+
test('checkSupported', () {
29+
expect(PowerSyncCoreVersion.parse('0.3.10').checkSupported,
30+
throwsA(isA<SqliteException>()));
31+
expect(PowerSyncCoreVersion.parse('1.0.0').checkSupported,
32+
throwsA(isA<SqliteException>()));
33+
34+
PowerSyncCoreVersion.minimum.checkSupported();
35+
expect(PowerSyncCoreVersion.maximumExclusive.checkSupported,
36+
throwsA(isA<SqliteException>()));
37+
});
38+
});
39+
}

packages/sqlite3_wasm_build/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set -e
33

44
SQLITE_VERSION="2.7.4"
5-
POWERSYNC_CORE_VERSION="0.3.10"
5+
POWERSYNC_CORE_VERSION="0.3.11"
66
SQLITE_PATH="sqlite3.dart"
77

88
if [ -d "$SQLITE_PATH" ]; then

scripts/init_powersync_core_binary.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import 'dart:io';
66
import 'package:melos/melos.dart';
77

88
final sqliteUrl =
9-
'https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v0.3.10';
9+
'https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v0.3.11';
1010

1111
void main() async {
1212
final sqliteCoreFilename = getLibraryForPlatform();

0 commit comments

Comments
 (0)