Skip to content

Commit 96400b3

Browse files
[Alpha WIP] Web Support (#25)
Initial support for web platform
1 parent f994e16 commit 96400b3

File tree

71 files changed

+2665
-1110
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+2665
-1110
lines changed

.github/workflows/test.yaml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Check publish score
2424
run: |
2525
dart pub global activate pana
26-
dart pub global run pana --no-warning --exit-code-threshold 0
26+
dart pub global run pana --no-warning --exit-code-threshold 10
2727
2828
test:
2929
runs-on: ubuntu-latest
@@ -55,9 +55,14 @@ jobs:
5555
run: dart pub get
5656

5757
- name: Install SQLite
58-
run: ./scripts/install_sqlite.sh ${{ matrix.sqlite_version }} ${{ matrix.sqlite_url }}
58+
run: |
59+
./scripts/install_sqlite.sh ${{ matrix.sqlite_version }} ${{ matrix.sqlite_url }}
60+
mkdir -p assets && curl -LJ https://github.com/simolus3/sqlite3.dart/releases/download/sqlite3-2.3.0/sqlite3.wasm -o assets/sqlite3.wasm
61+
62+
- name: Compile WebWorker
63+
run: dart compile js -o assets/db_worker.js -O0 lib/src/web/worker/drift_worker.dart
5964

6065
- name: Run Tests
6166
run: |
6267
export LD_LIBRARY_PATH=./sqlite-autoconf-${{ matrix.sqlite_version }}/.libs
63-
dart test
68+
dart test -p vm,chrome

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
# https://dart.dev/guides/libraries/private-files#pubspeclock.
77
pubspec.lock
88

9+
# Test assets
10+
assets
11+
912
.idea
13+
.vscode
1014
*.db
1115
*.db-*
1216
test-db

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.7.0-alpha.1
2+
3+
- Added initial support for web platform.
4+
15
## 0.6.0
26

37
- Allow catching errors and continuing the transaction. This is technically a breaking change, although it should not be an issue in most cases.

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,29 @@ void main() async {
7474
7575
await db.close();
7676
}
77-
```
77+
```
78+
79+
# Web
80+
81+
Web support is provided by the [Drift](https://github.com/powersync-ja/drift/pull/1) library. Detailed instructions for compatibility and setup are listed in the link.
82+
83+
Web support requires Sqlite3 WASM and Drift worker Javascript files to be accessible via configurable URIs.
84+
85+
Default URIs are shown in the example below. URIs only need to be specified if they differ from default values.
86+
87+
Watched queries and table change notifications are only supported when using a custom Drift worker which is compiled by linking
88+
https://github.com/powersync-ja/drift/pull/1.
89+
90+
Setup
91+
92+
``` Dart
93+
import 'package:sqlite_async/sqlite_async.dart';
94+
95+
final db = SqliteDatabase(
96+
path: 'test.db',
97+
options: SqliteOptions(
98+
webSqliteOptions: WebSqliteOptions(
99+
wasmUri: 'sqlite3.wasm', workerUri: 'db_worker.js')));
100+
101+
```
102+

example/custom_functions_example.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1+
import 'dart:async';
12
import 'dart:io';
23
import 'dart:isolate';
34

5+
import 'package:sqlite3/common.dart';
46
import 'package:sqlite_async/sqlite_async.dart';
5-
import 'package:sqlite3/sqlite3.dart' as sqlite;
67

78
/// Since the functions need to be created on every SQLite connection,
89
/// we do this in a SqliteOpenFactory.
910
class TestOpenFactory extends DefaultSqliteOpenFactory {
1011
TestOpenFactory({required super.path, super.sqliteOptions});
1112

1213
@override
13-
sqlite.Database open(SqliteOpenOptions options) {
14-
final db = super.open(options);
14+
FutureOr<CommonDatabase> open(SqliteOpenOptions options) async {
15+
final db = await super.open(options);
1516

1617
db.createFunction(
1718
functionName: 'sleep',
18-
argumentCount: const sqlite.AllowedArgumentCount(1),
19+
argumentCount: const AllowedArgumentCount(1),
1920
function: (args) {
2021
final millis = args[0] as int;
2122
sleep(Duration(milliseconds: millis));
@@ -25,7 +26,7 @@ class TestOpenFactory extends DefaultSqliteOpenFactory {
2526

2627
db.createFunction(
2728
functionName: 'isolate_name',
28-
argumentCount: const sqlite.AllowedArgumentCount(0),
29+
argumentCount: const AllowedArgumentCount(0),
2930
function: (args) {
3031
return Isolate.current.debugName;
3132
},

example/linux_cli_example.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import 'dart:async';
12
import 'dart:ffi';
23

4+
import 'package:sqlite3/common.dart';
35
import 'package:sqlite_async/sqlite_async.dart';
46
import 'package:sqlite3/open.dart' as sqlite_open;
5-
import 'package:sqlite3/sqlite3.dart' as sqlite;
67

78
const defaultSqlitePath = 'libsqlite3.so.0';
89

@@ -16,7 +17,7 @@ class TestOpenFactory extends DefaultSqliteOpenFactory {
1617
this.sqlitePath = defaultSqlitePath});
1718

1819
@override
19-
sqlite.Database open(SqliteOpenOptions options) {
20+
FutureOr<CommonDatabase> open(SqliteOpenOptions options) async {
2021
// For details, see:
2122
// https://pub.dev/packages/sqlite3#manually-providing-sqlite3-libraries
2223
sqlite_open.open.overrideFor(sqlite_open.OperatingSystem.linux, () {

lib/drift.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/// Re-exports [Drift](https://pub.dev/packages/drift) to expose drift without
2+
/// adding it as a direct dependency.
3+
library;
4+
5+
export 'package:drift/wasm.dart';
6+
export 'package:sqlite_async/src/web/worker/worker_utils.dart';

lib/sqlite3_common.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Exports common Sqlite3 exports which are available on web and ffi environments
2+
export 'package:sqlite3/common.dart';

lib/sqlite_async.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
/// See [SqliteDatabase] as a starting point.
44
library;
55

6+
export 'src/common/abstract_open_factory.dart';
7+
export 'src/common/connection/sync_sqlite_connection.dart';
8+
export 'src/common/isolate_connection_factory.dart';
9+
export 'src/common/mutex.dart';
10+
export 'src/common/port_channel.dart';
11+
export 'src/common/sqlite_database.dart';
612
export 'src/isolate_connection_factory.dart';
713
export 'src/sqlite_connection.dart';
814
export 'src/sqlite_database.dart';
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import 'dart:async';
2+
import 'package:meta/meta.dart';
3+
4+
import 'package:sqlite_async/sqlite3_common.dart' as sqlite;
5+
import 'package:sqlite_async/src/sqlite_options.dart';
6+
7+
/// Factory to create new SQLite database connections.
8+
///
9+
/// Since connections are opened in dedicated background isolates, this class
10+
/// must be safe to pass to different isolates.
11+
abstract class SqliteOpenFactory<Database extends sqlite.CommonDatabase> {
12+
String get path;
13+
14+
FutureOr<Database> open(SqliteOpenOptions options);
15+
}
16+
17+
class SqliteOpenOptions {
18+
/// Whether this is the primary write connection for the database.
19+
final bool primaryConnection;
20+
21+
/// Whether this connection is read-only.
22+
final bool readOnly;
23+
24+
const SqliteOpenOptions(
25+
{required this.primaryConnection, required this.readOnly});
26+
27+
sqlite.OpenMode get openMode {
28+
if (primaryConnection) {
29+
return sqlite.OpenMode.readWriteCreate;
30+
} else if (readOnly) {
31+
return sqlite.OpenMode.readOnly;
32+
} else {
33+
return sqlite.OpenMode.readWrite;
34+
}
35+
}
36+
}
37+
38+
/// The default database factory.
39+
///
40+
/// This takes care of opening the database, and running PRAGMA statements
41+
/// to configure the connection.
42+
///
43+
/// Override the [open] method to customize the process.
44+
abstract class AbstractDefaultSqliteOpenFactory<
45+
Database extends sqlite.CommonDatabase>
46+
implements SqliteOpenFactory<Database> {
47+
@override
48+
final String path;
49+
final SqliteOptions sqliteOptions;
50+
51+
const AbstractDefaultSqliteOpenFactory(
52+
{required this.path,
53+
this.sqliteOptions = const SqliteOptions.defaults()});
54+
55+
List<String> pragmaStatements(SqliteOpenOptions options);
56+
57+
@protected
58+
FutureOr<Database> openDB(SqliteOpenOptions options);
59+
60+
@override
61+
FutureOr<Database> open(SqliteOpenOptions options) async {
62+
var db = await openDB(options);
63+
64+
for (var statement in pragmaStatements(options)) {
65+
db.execute(statement);
66+
}
67+
return db;
68+
}
69+
}

0 commit comments

Comments
 (0)