diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6f6cad4..c1bcd0a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -35,19 +35,19 @@ jobs: include: - sqlite_version: "3440200" sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3440200.tar.gz" - dart_sdk: 3.5.0 + dart_sdk: stable - sqlite_version: "3430200" sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3430200.tar.gz" - dart_sdk: 3.5.0 + dart_sdk: stable - sqlite_version: "3420000" sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3420000.tar.gz" - dart_sdk: 3.5.0 + dart_sdk: stable - sqlite_version: "3410100" sqlite_url: "https://www.sqlite.org/2023/sqlite-autoconf-3410100.tar.gz" - dart_sdk: 3.5.0 + dart_sdk: stable - sqlite_version: "3380000" sqlite_url: "https://www.sqlite.org/2022/sqlite-autoconf-3380000.tar.gz" - dart_sdk: 3.5.0 + dart_sdk: stable steps: - uses: actions/checkout@v3 - uses: dart-lang/setup-dart@v1 diff --git a/melos.yaml b/melos.yaml index 8de8bfe..bd27884 100644 --- a/melos.yaml +++ b/melos.yaml @@ -41,7 +41,7 @@ scripts: test: description: Run tests in a specific package. - run: dart test -p chrome,vm + run: dart test -p chrome,vm --compiler dart2js,dart2wasm exec: concurrency: 1 packageFilters: diff --git a/packages/drift_sqlite_async/CHANGELOG.md b/packages/drift_sqlite_async/CHANGELOG.md index 4c23e85..d39db6f 100644 --- a/packages/drift_sqlite_async/CHANGELOG.md +++ b/packages/drift_sqlite_async/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.1 + +- Fix lints. + ## 0.2.0 - Automatically run Drift migrations diff --git a/analysis_options.yaml b/packages/drift_sqlite_async/analysis_options.yaml similarity index 100% rename from analysis_options.yaml rename to packages/drift_sqlite_async/analysis_options.yaml diff --git a/packages/drift_sqlite_async/lib/drift_sqlite_async.dart b/packages/drift_sqlite_async/lib/drift_sqlite_async.dart index f842c5b..83d04fc 100644 --- a/packages/drift_sqlite_async/lib/drift_sqlite_async.dart +++ b/packages/drift_sqlite_async/lib/drift_sqlite_async.dart @@ -1,4 +1,2 @@ -library drift_sqlite_async; - export './src/connection.dart'; export './src/executor.dart'; diff --git a/packages/drift_sqlite_async/lib/src/executor.dart b/packages/drift_sqlite_async/lib/src/executor.dart index 0727dd8..dbd4c96 100644 --- a/packages/drift_sqlite_async/lib/src/executor.dart +++ b/packages/drift_sqlite_async/lib/src/executor.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:drift/backends.dart'; -import 'package:drift/src/runtime/query_builder/query_builder.dart'; +import 'package:drift/drift.dart'; import 'package:sqlite_async/sqlite3_common.dart'; import 'package:sqlite_async/sqlite_async.dart'; @@ -19,6 +19,7 @@ class _SqliteAsyncDelegate extends _SqliteAsyncQueryDelegate _SqliteAsyncDelegate(this.db) : super(db, db.writeLock); + @override bool isInTransaction = false; // unused @override diff --git a/packages/drift_sqlite_async/pubspec.yaml b/packages/drift_sqlite_async/pubspec.yaml index f88dccb..98eb766 100644 --- a/packages/drift_sqlite_async/pubspec.yaml +++ b/packages/drift_sqlite_async/pubspec.yaml @@ -1,5 +1,5 @@ name: drift_sqlite_async -version: 0.2.0 +version: 0.2.1 homepage: https://github.com/powersync-ja/sqlite_async.dart repository: https://github.com/powersync-ja/sqlite_async.dart description: Use Drift with a sqlite_async database, allowing both to be used in the same application. @@ -16,10 +16,12 @@ environment: dependencies: drift: ">=2.19.0 <3.0.0" sqlite_async: ^0.11.0 + dev_dependencies: build_runner: ^2.4.8 drift_dev: ">=2.19.0 <3.0.0" glob: ^2.1.2 + lints: ^5.0.0 sqlite3: ^2.4.0 test: ^1.25.2 test_api: ^0.7.0 diff --git a/packages/drift_sqlite_async/test/basic_test.dart b/packages/drift_sqlite_async/test/basic_test.dart index 1b33562..371c149 100644 --- a/packages/drift_sqlite_async/test/basic_test.dart +++ b/packages/drift_sqlite_async/test/basic_test.dart @@ -1,5 +1,7 @@ // TODO @TestOn('!browser') +library; + import 'dart:async'; import 'package:drift/drift.dart'; diff --git a/packages/drift_sqlite_async/test/db_test.dart b/packages/drift_sqlite_async/test/db_test.dart index 372f0fa..39a5224 100644 --- a/packages/drift_sqlite_async/test/db_test.dart +++ b/packages/drift_sqlite_async/test/db_test.dart @@ -1,5 +1,7 @@ // TODO @TestOn('!browser') +library; + import 'package:drift/drift.dart'; import 'package:sqlite_async/sqlite_async.dart'; import 'package:test/test.dart'; diff --git a/packages/drift_sqlite_async/test/generated/database.dart b/packages/drift_sqlite_async/test/generated/database.dart index 7747be4..928c7dd 100644 --- a/packages/drift_sqlite_async/test/generated/database.dart +++ b/packages/drift_sqlite_async/test/generated/database.dart @@ -21,7 +21,7 @@ class TodoDatabase extends _$TodoDatabase { } class TodosMigrationDatabase extends TodoDatabase { - TodosMigrationDatabase(SqliteConnection db) : super(db); + TodosMigrationDatabase(super.db); @override MigrationStrategy get migration { diff --git a/packages/drift_sqlite_async/test/migration_test.dart b/packages/drift_sqlite_async/test/migration_test.dart index e05c212..ca9cb3f 100644 --- a/packages/drift_sqlite_async/test/migration_test.dart +++ b/packages/drift_sqlite_async/test/migration_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'package:sqlite_async/sqlite_async.dart'; import 'package:test/test.dart'; diff --git a/packages/sqlite_async/CHANGELOG.md b/packages/sqlite_async/CHANGELOG.md index b49c6ab..ea77953 100644 --- a/packages/sqlite_async/CHANGELOG.md +++ b/packages/sqlite_async/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.11.2 + +- Support latest version of `package:sqlite3_web`. +- Support `dart2wasm`. + ## 0.11.1 - Remove remaining `dart:js_util` imports in favor of new interop APIs. diff --git a/packages/sqlite_async/analysis_options.yaml b/packages/sqlite_async/analysis_options.yaml new file mode 100644 index 0000000..572dd23 --- /dev/null +++ b/packages/sqlite_async/analysis_options.yaml @@ -0,0 +1 @@ +include: package:lints/recommended.yaml diff --git a/packages/sqlite_async/lib/src/web/database.dart b/packages/sqlite_async/lib/src/web/database.dart index a4f0ddf..04da846 100644 --- a/packages/sqlite_async/lib/src/web/database.dart +++ b/packages/sqlite_async/lib/src/web/database.dart @@ -1,8 +1,10 @@ import 'dart:async'; import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; import 'package:sqlite3/common.dart'; import 'package:sqlite3_web/sqlite3_web.dart'; +import 'package:sqlite3_web/protocol_utils.dart' as proto; import 'package:sqlite_async/sqlite_async.dart'; import 'package:sqlite_async/src/utils/shared_utils.dart'; import 'package:sqlite_async/src/web/database/broadcast_updates.dart'; @@ -256,9 +258,15 @@ class _ExclusiveTransactionContext extends _ExclusiveContext { // JavaScript object. This is the converted into a Dart ResultSet. return await wrapSqliteException(() async { var res = await _database._database.customRequest(CustomDatabaseMessage( - CustomDatabaseMessageKind.executeInTransaction, sql, parameters)); - var result = - Map.from((res as JSObject).dartify() as Map); + CustomDatabaseMessageKind.executeInTransaction, sql, parameters)) + as JSObject; + + if (res.has('format') && (res['format'] as JSNumber).toDartInt == 2) { + // Newer workers use a serialization format more efficient than dartify(). + return proto.deserializeResultSet(res['r'] as JSObject); + } + + var result = Map.from(res.dartify() as Map); final columnNames = [ for (final entry in result['columnNames']) entry as String ]; @@ -303,9 +311,14 @@ Future wrapSqliteException(Future Function() callback) async { try { return await callback(); } on RemoteException catch (ex) { + if (ex.exception case final serializedCause?) { + throw serializedCause; + } + + // Older versions of package:sqlite_web reported SqliteExceptions as strings + // only. if (ex.toString().contains('SqliteException')) { RegExp regExp = RegExp(r'SqliteException\((\d+)\)'); - // The SQLite Web package wraps these in remote errors throw SqliteException( int.parse(regExp.firstMatch(ex.message)?.group(1) ?? '0'), ex.message); diff --git a/packages/sqlite_async/lib/src/web/protocol.dart b/packages/sqlite_async/lib/src/web/protocol.dart index e6206d6..cb3a5fd 100644 --- a/packages/sqlite_async/lib/src/web/protocol.dart +++ b/packages/sqlite_async/lib/src/web/protocol.dart @@ -3,6 +3,7 @@ library; import 'dart:js_interop'; +import 'package:sqlite3_web/protocol_utils.dart' as proto; enum CustomDatabaseMessageKind { requestSharedLock, @@ -19,15 +20,24 @@ extension type CustomDatabaseMessage._raw(JSObject _) implements JSObject { required JSString rawKind, JSString rawSql, JSArray rawParameters, + JSArrayBuffer typeInfo, }); factory CustomDatabaseMessage(CustomDatabaseMessageKind kind, [String? sql, List parameters = const []]) { - final rawSql = sql?.toJS ?? ''.toJS; - final rawParameters = - [for (final parameter in parameters) parameter.jsify()].toJS; + final rawSql = (sql ?? '').toJS; + // Serializing parameters this way is backwards-compatible with dartify() + // on the other end, but a bit more efficient while also suppporting sound + // communcation between dart2js workers and dart2wasm clients. + // Older workers ignore the typeInfo, but that's not a problem. + final (rawParameters, typeInfo) = proto.serializeParameters(parameters); + return CustomDatabaseMessage._( - rawKind: kind.name.toJS, rawSql: rawSql, rawParameters: rawParameters); + rawKind: kind.name.toJS, + rawSql: rawSql, + rawParameters: rawParameters, + typeInfo: typeInfo, + ); } external JSString get rawKind; @@ -36,6 +46,9 @@ extension type CustomDatabaseMessage._raw(JSObject _) implements JSObject { external JSArray get rawParameters; + /// Not set in earlier versions of this package. + external JSArrayBuffer? get typeInfo; + CustomDatabaseMessageKind get kind { return CustomDatabaseMessageKind.values.byName(rawKind.toDart); } diff --git a/packages/sqlite_async/lib/src/web/web_sqlite_open_factory.dart b/packages/sqlite_async/lib/src/web/web_sqlite_open_factory.dart index 247999d..5089b95 100644 --- a/packages/sqlite_async/lib/src/web/web_sqlite_open_factory.dart +++ b/packages/sqlite_async/lib/src/web/web_sqlite_open_factory.dart @@ -15,7 +15,7 @@ Map> webSQLiteImplementations = {}; /// Web implementation of [AbstractDefaultSqliteOpenFactory] class DefaultSqliteOpenFactory extends AbstractDefaultSqliteOpenFactory - implements WebSqliteOpenFactory { + with WebSqliteOpenFactory { late final Future _initialized = Future.sync(() { final cacheKey = sqliteOptions.webSqliteOptions.wasmUri + sqliteOptions.webSqliteOptions.workerUri; @@ -45,9 +45,8 @@ class DefaultSqliteOpenFactory ); } - @override - /// This is currently not supported on web + @override CommonDatabase openDB(SqliteOpenOptions options) { throw UnimplementedError( 'Direct access to CommonDatabase is not available on web.'); @@ -61,7 +60,7 @@ class DefaultSqliteOpenFactory /// Due to being asynchronous, the under laying CommonDatabase is not accessible Future openConnection(SqliteOpenOptions options) async { final workers = await _initialized; - final connection = await workers.connectToRecommended(path); + final connection = await connectToWorker(workers, path); // When the database is accessed through a shared worker, we implement // mutexes over custom messages sent through the shared worker. In other diff --git a/packages/sqlite_async/lib/src/web/worker/throttled_common_database.dart b/packages/sqlite_async/lib/src/web/worker/throttled_common_database.dart index 07264bf..5f33b6d 100644 --- a/packages/sqlite_async/lib/src/web/worker/throttled_common_database.dart +++ b/packages/sqlite_async/lib/src/web/worker/throttled_common_database.dart @@ -107,6 +107,7 @@ class ThrottledCommonDatabase extends CommonDatabase { @override VoidPredicate? get commitFilter => _db.commitFilter; + @override set commitFilter(VoidPredicate? filter) => _db.commitFilter = filter; @override diff --git a/packages/sqlite_async/lib/src/web/worker/worker_utils.dart b/packages/sqlite_async/lib/src/web/worker/worker_utils.dart index 5a6e1b3..af39747 100644 --- a/packages/sqlite_async/lib/src/web/worker/worker_utils.dart +++ b/packages/sqlite_async/lib/src/web/worker/worker_utils.dart @@ -1,8 +1,12 @@ import 'dart:js_interop'; +import 'dart:js_interop_unsafe'; +import 'package:meta/meta.dart'; import 'package:mutex/mutex.dart'; import 'package:sqlite3/wasm.dart'; import 'package:sqlite3_web/sqlite3_web.dart'; +import 'package:sqlite3_web/protocol_utils.dart' as proto; + import 'throttled_common_database.dart'; import '../protocol.dart'; @@ -12,9 +16,9 @@ import '../protocol.dart'; /// can be extended to perform custom requests. base class AsyncSqliteController extends DatabaseController { @override - Future openDatabase( - WasmSqlite3 sqlite3, String path, String vfs) async { - final db = sqlite3.open(path, vfs: vfs); + Future openDatabase(WasmSqlite3 sqlite3, String path, + String vfs, JSAny? additionalData) async { + final db = openUnderlying(sqlite3, path, vfs, additionalData); // Register any custom functions here if needed @@ -23,6 +27,18 @@ base class AsyncSqliteController extends DatabaseController { return AsyncSqliteDatabase(database: throttled); } + /// Opens a database with the `sqlite3` package that will be wrapped in a + /// [ThrottledCommonDatabase] for [openDatabase]. + @visibleForOverriding + CommonDatabase openUnderlying( + WasmSqlite3 sqlite3, + String path, + String vfs, + JSAny? additionalData, + ) { + return sqlite3.open(path, vfs: vfs); + } + @override Future handleCustomRequest( ClientConnection connection, JSAny? request) { @@ -61,25 +77,32 @@ class AsyncSqliteDatabase extends WorkerDatabase { return database.autocommit.toJS; case CustomDatabaseMessageKind.executeInTransaction: final sql = message.rawSql.toDart; - final parameters = [ - for (final raw in (message.rawParameters).toDart) raw.dartify() - ]; + final hasTypeInfo = message.typeInfo.isDefinedAndNotNull; + final parameters = proto.deserializeParameters( + message.rawParameters, message.typeInfo); if (database.autocommit) { throw SqliteException(0, "Transaction rolled back by earlier statement. Cannot execute: $sql"); } - var res = database.select(sql, parameters); - var dartMap = resultSetToMap(res); - - var jsObject = dartMap.jsify(); + var res = database.select(sql, parameters); + if (hasTypeInfo) { + // If the client is sending a request that has parameters with type + // information, it will also support a newer serialization format for + // result sets. + return JSObject() + ..['format'] = 2.toJS + ..['r'] = proto.serializeResultSet(res); + } else { + var dartMap = resultSetToMap(res); + var jsObject = dartMap.jsify(); + return jsObject; + } - return jsObject; case CustomDatabaseMessageKind.executeBatchInTransaction: final sql = message.rawSql.toDart; - final parameters = [ - for (final raw in (message.rawParameters).toDart) raw.dartify() - ]; + final parameters = proto.deserializeParameters( + message.rawParameters, message.typeInfo); if (database.autocommit) { throw SqliteException(0, "Transaction rolled back by earlier statement. Cannot execute: $sql"); diff --git a/packages/sqlite_async/lib/web.dart b/packages/sqlite_async/lib/web.dart index c7f9628..8051edb 100644 --- a/packages/sqlite_async/lib/web.dart +++ b/packages/sqlite_async/lib/web.dart @@ -2,7 +2,7 @@ /// /// These expose methods allowing database instances to be shared across web /// workers. -library sqlite_async.web; +library; import 'package:sqlite3_web/sqlite3_web.dart'; import 'package:web/web.dart'; @@ -31,7 +31,7 @@ typedef WebDatabaseEndpoint = ({ /// /// The [DefaultSqliteOpenFactory] class implements this interface only when /// compiling for the web. -abstract interface class WebSqliteOpenFactory +abstract mixin class WebSqliteOpenFactory implements SqliteOpenFactory { /// Opens a [WebSqlite] instance for the given [options]. /// @@ -39,7 +39,21 @@ abstract interface class WebSqliteOpenFactory /// opened needs to be customized. Implementers should be aware that the /// result of this method is cached and will be re-used by the open factory /// when provided with the same [options] again. - Future openWebSqlite(WebSqliteOptions options); + Future openWebSqlite(WebSqliteOptions options) async { + return WebSqlite.open( + worker: Uri.parse(options.workerUri), + wasmModule: Uri.parse(options.wasmUri), + ); + } + + /// Uses [WebSqlite] to connects to the recommended database setup for [name]. + /// + /// This typically just calls [WebSqlite.connectToRecommended], but subclasses + /// can customize the behavior where needed. + Future connectToWorker( + WebSqlite sqlite, String name) { + return sqlite.connectToRecommended(name); + } } /// A [SqliteConnection] interface implemented by opened connections when @@ -91,6 +105,7 @@ abstract class WebSqliteConnection implements SqliteConnection { /// This only has an effect when IndexedDB storage is used. /// /// See [flush] for details. + @override Future writeLock(Future Function(SqliteWriteContext tx) callback, {Duration? lockTimeout, String? debugContext, bool? flush}); @@ -101,6 +116,7 @@ abstract class WebSqliteConnection implements SqliteConnection { /// This only has an effect when IndexedDB storage is used. /// /// See [flush] for details. + @override Future writeTransaction( Future Function(SqliteWriteContext tx) callback, {Duration? lockTimeout, diff --git a/packages/sqlite_async/pubspec.yaml b/packages/sqlite_async/pubspec.yaml index 1ffa8b4..e4ea5ce 100644 --- a/packages/sqlite_async/pubspec.yaml +++ b/packages/sqlite_async/pubspec.yaml @@ -1,6 +1,6 @@ name: sqlite_async description: High-performance asynchronous interface for SQLite on Dart and Flutter. -version: 0.11.1 +version: 0.11.2 repository: https://github.com/powersync-ja/sqlite_async.dart environment: sdk: ">=3.5.0 <4.0.0" @@ -13,7 +13,7 @@ topics: dependencies: sqlite3: ^2.7.2 - sqlite3_web: ^0.2.2 + sqlite3_web: ^0.3.0 async: ^2.10.0 collection: ^1.17.0 mutex: ^3.1.0 @@ -21,8 +21,7 @@ dependencies: web: ^1.0.0 dev_dependencies: - dcli: ^4.0.0 - lints: ^3.0.0 + lints: ^5.0.0 test: ^1.21.0 test_api: ^0.7.0 glob: ^2.1.1 @@ -31,6 +30,7 @@ dev_dependencies: shelf_static: ^1.1.2 stream_channel: ^2.1.2 path: ^1.9.0 + test_descriptor: ^2.0.2 platforms: android: diff --git a/packages/sqlite_async/test/basic_test.dart b/packages/sqlite_async/test/basic_test.dart index e07daf4..0aca7bc 100644 --- a/packages/sqlite_async/test/basic_test.dart +++ b/packages/sqlite_async/test/basic_test.dart @@ -6,6 +6,7 @@ import 'package:test/test.dart'; import 'utils/test_utils_impl.dart'; final testUtils = TestUtils(); +const _isDart2Wasm = bool.fromEnvironment('dart.tool.dart2wasm'); void main() { group('Shared Basic Tests', () { @@ -125,48 +126,67 @@ void main() { expect(savedTx!.closed, equals(true)); }); - test('should properly report errors in transactions', () async { - final db = await testUtils.setupDatabase(path: path); - await createTables(db); + test( + 'should properly report errors in transactions', + () async { + final db = await testUtils.setupDatabase(path: path); + await createTables(db); - var tp = db.writeTransaction((tx) async { - await tx.execute( - 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', - [1, 'test1']); - await tx.execute( - 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', - [2, 'test2']); - expect(await tx.getAutoCommit(), equals(false)); - try { + var tp = db.writeTransaction((tx) async { await tx.execute( 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', - [2, 'test3']); - } catch (e) { - // Ignore - } - - expect(await tx.getAutoCommit(), equals(true)); - expect(tx.closed, equals(false)); - - // Will not be executed because of the above rollback - await tx.execute( - 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', - [4, 'test4']); - }); - - // The error propagates up to the transaction + [1, 'test1']); + await tx.execute( + 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', + [2, 'test2']); + expect(await tx.getAutoCommit(), equals(false)); + try { + await tx.execute( + 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', + [2, 'test3']); + } catch (e) { + // Ignore + } + + expect(await tx.getAutoCommit(), equals(true)); + expect(tx.closed, equals(false)); + + // Will not be executed because of the above rollback + await tx.execute( + 'INSERT OR ROLLBACK INTO test_data(id, description) VALUES(?, ?)', + [4, 'test4']); + }); + + // The error propagates up to the transaction + await expectLater( + tp, + throwsA((e) => + e is SqliteException && + e.message + .contains('Transaction rolled back by earlier statement'))); + + expect(await db.get('SELECT count() count FROM test_data'), + equals({'count': 0})); + + // Check that we can open another transaction afterwards + await db.writeTransaction((tx) async {}); + }, + skip: _isDart2Wasm + ? 'Fails due to compiler bug, https://dartbug.com/59981' + : null, + ); + + test('reports exceptions as SqliteExceptions', () async { + final db = await testUtils.setupDatabase(path: path); await expectLater( - tp, - throwsA((e) => - e is SqliteException && - e.message - .contains('Transaction rolled back by earlier statement'))); - - expect(await db.get('SELECT count() count FROM test_data'), - equals({'count': 0})); - - // Check that we can open another transaction afterwards - await db.writeTransaction((tx) async {}); + db.get('SELECT invalid_statement;'), + throwsA( + isA() + .having((e) => e.causingStatement, 'causingStatement', + 'SELECT invalid_statement;') + .having((e) => e.extendedResultCode, 'extendedResultCode', 1), + ), + ); }); }); } diff --git a/packages/sqlite_async/test/close_test.dart b/packages/sqlite_async/test/close_test.dart index dcb3390..6a72f3d 100644 --- a/packages/sqlite_async/test/close_test.dart +++ b/packages/sqlite_async/test/close_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'dart:io'; import 'package:sqlite_async/sqlite_async.dart'; diff --git a/packages/sqlite_async/test/isolate_test.dart b/packages/sqlite_async/test/isolate_test.dart index 60bea87..3a3af98 100644 --- a/packages/sqlite_async/test/isolate_test.dart +++ b/packages/sqlite_async/test/isolate_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'dart:isolate'; import 'package:test/test.dart'; diff --git a/packages/sqlite_async/test/native/basic_test.dart b/packages/sqlite_async/test/native/basic_test.dart index 263ab39..eba5493 100644 --- a/packages/sqlite_async/test/native/basic_test.dart +++ b/packages/sqlite_async/test/native/basic_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'dart:async'; import 'dart:math'; diff --git a/packages/sqlite_async/test/native/native_mutex_test.dart b/packages/sqlite_async/test/native/native_mutex_test.dart index 699a877..e9b5a54 100644 --- a/packages/sqlite_async/test/native/native_mutex_test.dart +++ b/packages/sqlite_async/test/native/native_mutex_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'dart:isolate'; import 'package:sqlite_async/src/native/native_isolate_mutex.dart'; diff --git a/packages/sqlite_async/test/native/schema_test.dart b/packages/sqlite_async/test/native/schema_test.dart index c358402..423d33b 100644 --- a/packages/sqlite_async/test/native/schema_test.dart +++ b/packages/sqlite_async/test/native/schema_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'dart:async'; import 'package:sqlite_async/sqlite_async.dart'; diff --git a/packages/sqlite_async/test/native/watch_test.dart b/packages/sqlite_async/test/native/watch_test.dart index 67077db..4e4fb83 100644 --- a/packages/sqlite_async/test/native/watch_test.dart +++ b/packages/sqlite_async/test/native/watch_test.dart @@ -1,4 +1,6 @@ @TestOn('!browser') +library; + import 'dart:async'; import 'dart:isolate'; import 'dart:math'; diff --git a/packages/sqlite_async/test/server/worker_server.dart b/packages/sqlite_async/test/server/worker_server.dart index 30cffe9..4d060e2 100644 --- a/packages/sqlite_async/test/server/worker_server.dart +++ b/packages/sqlite_async/test/server/worker_server.dart @@ -1,6 +1,5 @@ import 'dart:io'; -import 'package:dcli/dcli.dart'; import 'package:path/path.dart' as p; import 'package:shelf/shelf.dart'; import 'package:shelf/shelf_io.dart' as io; @@ -10,8 +9,7 @@ import 'package:stream_channel/stream_channel.dart'; import 'asset_server.dart'; Future hybridMain(StreamChannel channel) async { - final directory = p.normalize( - p.join(DartScript.self.pathToScriptDirectory, '../../../../assets')); + final directory = p.normalize('../../assets'); final sqliteOutputPath = p.join(directory, 'sqlite3.wasm'); diff --git a/packages/sqlite_async/test/utils/abstract_test_utils.dart b/packages/sqlite_async/test/utils/abstract_test_utils.dart index f1ec6ea..e787a45 100644 --- a/packages/sqlite_async/test/utils/abstract_test_utils.dart +++ b/packages/sqlite_async/test/utils/abstract_test_utils.dart @@ -1,5 +1,4 @@ import 'package:sqlite_async/sqlite_async.dart'; -import 'package:test_api/src/backend/invoker.dart'; class TestDefaultSqliteOpenFactory extends DefaultSqliteOpenFactory { final String sqlitePath; @@ -9,14 +8,7 @@ class TestDefaultSqliteOpenFactory extends DefaultSqliteOpenFactory { } abstract class AbstractTestUtils { - String dbPath() { - final test = Invoker.current!.liveTest; - var testName = test.test.name; - var testShortName = - testName.replaceAll(RegExp(r'[\s\./]'), '_').toLowerCase(); - var dbName = "test-db/$testShortName.db"; - return dbName; - } + String dbPath(); /// Generates a test open factory Future testFactory( diff --git a/packages/sqlite_async/test/utils/native_test_utils.dart b/packages/sqlite_async/test/utils/native_test_utils.dart index e23bb65..66bf57c 100644 --- a/packages/sqlite_async/test/utils/native_test_utils.dart +++ b/packages/sqlite_async/test/utils/native_test_utils.dart @@ -8,6 +8,7 @@ import 'package:glob/list_local_fs.dart'; import 'package:sqlite_async/sqlite3_common.dart'; import 'package:sqlite_async/sqlite_async.dart'; import 'package:sqlite3/open.dart' as sqlite_open; +import 'package:test_descriptor/test_descriptor.dart' as d; import 'abstract_test_utils.dart'; @@ -52,8 +53,7 @@ class TestSqliteOpenFactory extends TestDefaultSqliteOpenFactory { class TestUtils extends AbstractTestUtils { @override String dbPath() { - Directory("test-db").createSync(recursive: false); - return super.dbPath(); + return d.path('test.db'); } @override diff --git a/packages/sqlite_async/test/utils/stub_test_utils.dart b/packages/sqlite_async/test/utils/stub_test_utils.dart index 5e3a953..852009f 100644 --- a/packages/sqlite_async/test/utils/stub_test_utils.dart +++ b/packages/sqlite_async/test/utils/stub_test_utils.dart @@ -1,6 +1,11 @@ import 'abstract_test_utils.dart'; class TestUtils extends AbstractTestUtils { + @override + String dbPath() { + throw UnimplementedError(); + } + @override Future cleanDb({required String path}) { throw UnimplementedError(); diff --git a/packages/sqlite_async/test/utils/web_test_utils.dart b/packages/sqlite_async/test/utils/web_test_utils.dart index 32b7e05..ac718f2 100644 --- a/packages/sqlite_async/test/utils/web_test_utils.dart +++ b/packages/sqlite_async/test/utils/web_test_utils.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:js_interop'; +import 'dart:math'; import 'package:sqlite_async/sqlite_async.dart'; import 'package:test/test.dart'; @@ -9,6 +10,8 @@ import 'abstract_test_utils.dart'; @JS('URL.createObjectURL') external String _createObjectURL(Blob blob); +String? _dbPath; + class TestUtils extends AbstractTestUtils { late Future _isInitialized; late final SqliteOptions webOptions; @@ -19,7 +22,7 @@ class TestUtils extends AbstractTestUtils { Future _init() async { final channel = spawnHybridUri('/test/server/worker_server.dart'); - final port = await channel.stream.first as int; + final port = (await channel.stream.first as num).toInt(); final sqliteWasmUri = 'http://localhost:$port/sqlite3.wasm'; // Cross origin workers are not supported, but we can supply a Blob var sqliteUri = 'http://localhost:$port/db_worker.js'; @@ -33,6 +36,21 @@ class TestUtils extends AbstractTestUtils { wasmUri: sqliteWasmUri.toString(), workerUri: sqliteUri)); } + @override + String dbPath() { + if (_dbPath case final path?) { + return path; + } + + final created = _dbPath = 'test-db/${Random().nextInt(1 << 31)}/test.db'; + addTearDown(() { + // Pick a new path for the next test. + _dbPath = null; + }); + + return created; + } + @override Future cleanDb({required String path}) async {} diff --git a/packages/sqlite_async/test/web/watch_test.dart b/packages/sqlite_async/test/web/watch_test.dart index 50bbae0..c6757b9 100644 --- a/packages/sqlite_async/test/web/watch_test.dart +++ b/packages/sqlite_async/test/web/watch_test.dart @@ -1,4 +1,6 @@ @TestOn('browser') +library; + import 'package:sqlite_async/sqlite_async.dart'; import 'package:test/test.dart'; diff --git a/scripts/sqlite3_wasm_download.dart b/scripts/sqlite3_wasm_download.dart index 28d91b4..62acbbe 100644 --- a/scripts/sqlite3_wasm_download.dart +++ b/scripts/sqlite3_wasm_download.dart @@ -1,4 +1,6 @@ /// Downloads sqlite3.wasm +library; + import 'dart:io'; final sqliteUrl =