Port tabs and anotations

This commit is contained in:
Simon Binder
2025-10-08 22:26:46 +02:00
parent b480fa08e5
commit c12d4e13e9
12 changed files with 84 additions and 111 deletions
-40
View File
@@ -1,40 +0,0 @@
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
import 'package:drift/wasm.dart';
import 'package:web/web.dart';
void main() async {
window.setProperty(
'start_compat_check'.toJS,
() {
Future(() async {
final btn = document.querySelector('#drift-compat-btn')!;
final results =
document.querySelector('#drift-compat-results') as HTMLElement;
btn.attributes['disabled'] = 'true'.toJS;
results.innerText = '';
try {
final db = await WasmDatabase.open(
databaseName: 'test_db',
// These URLs need to be absolute because we're serving this JS file
// under `/web`.
sqlite3Uri: Uri.parse('/sqlite3.wasm'),
driftWorkerUri: Uri.parse('/drift_worker.dart.js'),
);
results.innerText += '''
Chosen implementation: ${db.chosenImplementation}
Features missing: ${db.missingFeatures}
''';
await db.resolvedExecutor.close();
} catch (e, s) {
results.innerText += 'Error: $e, Trace: \n$s';
} finally {
btn.attributes['disabled'] = 'false'.toJS;
}
});
}.toJS);
}
+1
View File
@@ -76,6 +76,7 @@ targets:
- "web/drift_worker.dart"
builders:
build_web_compilers:entrypoint:
enabled: true
options:
compiler: dart2js
build_web_compilers:dart2js_archive_extractor:
+4 -8
View File
@@ -41,17 +41,15 @@ The SQL equivalent of this table would be:
CREATE TABLE todo_items (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title TEXT,
created_at INTEGER -- (1)!
created_at INTEGER -- Drift stores `dateTime()` columns as unix timestamps by default
);
```
{.annotate }
1. By default, `dateTime()` columns are stored as Unix timestamps. To store them as ISO-8601 strings, see [DateTime options](#datetime-options).
Some technical notes:
- The name of the table, `todo_items` is automatically derived from the class name. This can be customized by overriding the `tableName` getter. See [Table Names](#changing-sql-names) for more information.
- The `id` column is automatically set as the primary key because it is an auto-incrementing integer. See [Primary Keys](#primary-keys) for more information.
- By default, `dateTime()` columns are stored as Unix timestamps. To store them as ISO-8601 strings, see [DateTime options](#datetime-options).
## Add to database
@@ -180,10 +178,8 @@ for inserts, as the database will use the default as a fallback.
Similarly to `withDefault()`, this sets a default value for columns.
Unlike `withDefault()` however, this value is computed in Dart instead of in
the database (1).
This means that adding, removing, or changing the default value does not require a database migration:
{ .annotate }
1. Because this default value is only applied in your Dart code, it is not applied when interacting with the database outside of Drift.
This means that adding, removing, or changing the default value does not require a database migration,
However, because this default value is only applied in your Dart code, it is not applied when interacting with the database outside of Drift.
<Snippet href="/lib/src/snippets/dart_api/tables.dart" name="client_default" />
+2 -4
View File
@@ -31,10 +31,8 @@ targets:
another_db: lib/database2.dart
```
You can also optionally specify the directory where the test files and schema (1) files are stored.
{ .annotate }
1. Drift will generate multiple schema files, one for each version of your database schema. These files are used to compare the current schema with the previous schema and generate the migration code.
You can also optionally specify the directory where the test files and schema files are stored.
Drift will generate multiple schema files, one for each version of your database schema. These files are used to compare the current schema with the previous schema and generate the migration code.
```yaml title="build.yaml"
targets:
+14 -9
View File
@@ -95,22 +95,27 @@ This can then be used to manually create and verify data at a specific version:
Instead (or in addition to) [writing tests](#verifying-a-database-schema-at-runtime) to ensure your migrations work as they should,
`drift_dev` provides an API to verify the current schema at runtime without any additional setup on native platforms.
<Tabs>
=== "Native"
<TabItem label="Native" value="native">
{{ load_snippet('native','lib/snippets/migrations/runtime_verification.dart.excerpt.json', indent=4) }}
<Snippet href="/lib/src/snippets/migrations/runtime_verification.dart" name="native" />
</TabItem>
=== "Web (since drift 2.22)"
<TabItem label="Web (since drift 2.22)" value="web">
Starting from drift version 2.22, this functionality is also available on the web. Since the method internally
opens another database to create the expected schema, the web variant needs to be configured explicitly:
Starting from drift version 2.22, this functionality is also available on the web. Since the method internally
opens another database to create the expected schema, the web variant needs to be configured explicitly:
{{ load_snippet('web','lib/snippets/migrations/runtime_verification_web.dart.excerpt.json', indent=4) }}
<Snippet href="/lib/src/snippets/migrations/runtime_verification_web.dart" name="web" />
It's also possible to re-use code between your native and web checks with conditional imports.
You can check the [example app](https://github.com/simolus3/drift/tree/develop/examples/app/lib/database/connection) for
inspiration.
It's also possible to re-use code between your native and web checks with conditional imports.
You can check the [example app](https://github.com/simolus3/drift/tree/develop/examples/app/lib/database/connection) for
inspiration.
</TabItem>
</Tabs>
When you use `validateDatabaseSchema`, drift will transparently:
+21 -19
View File
@@ -1,13 +1,9 @@
---
title: Web
description: Drift support in Flutter and Dart web apps.
---
<script src="/compatibility.dart.js"></script>
!!! success ""
!!! success "Stable web support"
__Good news__: With drift 2.9.0, web support is stable and officially supported!
The `WasmDatabase.open` API is the preferred way to run drift on the web. While older
@@ -104,8 +100,6 @@ web/
correct `Content-Type` header for wasm files.
#### Additional headers
On browsers that support it, drift uses the origin-private part of the [FileSystem Access API](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API) to store databases efficiently.
@@ -146,25 +140,33 @@ Also, note that the `sqlite3.wasm` file needs to be served with a `Content-Type`
From a perspective of the Dart code used, drift on the web is similar to drift on other platforms.
You can follow the [getting started guide](../setup.md) as a general setup guide.
=== "Flutter (sqlite3)"
<Tabs>
If you're using `package:drift_flutter` to setup your database, you enable web support by passing
`DriftWebOptions` with URIs to the WebAssembly module and the drift worker:
<TabItem label="Flutter (sqlite3)" value="flutter">
{{ load_snippet('flutter','lib/snippets/platforms/web.dart.excerpt.json',indent=4) }}
If you're using `package:drift_flutter` to setup your database, you enable web support by passing
`DriftWebOptions` with URIs to the WebAssembly module and the drift worker:
If you need more control on how you're opening web databases (e.g. to prefer certain storage
APIs, see the manual setup for Dart in the next tab).
<Snippet href="/lib/src/snippets/platforms/web.dart" name="flutter" />
=== "Dart (sqlite3)"
If you need more control on how you're opening web databases (e.g. to prefer certain storage
APIs, see the manual setup for Dart in the next tab).
Instead of using a `NativeDatabase` in your database classes, you can use the `WasmDatabase` optimized
for the web:
</TabItem>
{{ load_snippet('connect','lib/snippets/platforms/web.dart.excerpt.json',indent=4) }}
<TabItem label="Dart (sqlite3)" value="dart">
Instead of using a `NativeDatabase` in your database classes, you can use the `WasmDatabase` optimized
for the web:
<Snippet href="/lib/src/snippets/platforms/web.dart" name="connect" />
When you call `WasmDatabase.open`, drift will automatically find a suitable persistence implementation
supported by the current browser.
</TabItem>
</Tabs>
When you call `WasmDatabase.open`, drift will automatically find a suitable persistence implementation
supported by the current browser.
A full example that works on the web (and all other platforms supported by drift) is available
[here](https://github.com/simolus3/drift/tree/develop/examples/app).
+9 -28
View File
@@ -83,35 +83,16 @@ We can create an in-memory version of the database by using a
place to open the database is the `setUp` and `tearDown` methods from
`package:test`:
```dart
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:test/test.dart';
// the file defined above, you can test any drift database of course
import 'database.dart';
<Snippet href="/lib/src/snippets/setup/testing.dart" name="(full)" />
void main() {
late MyDatabase database;
!!! note "Closing streams synchronously"
setUp(() {
database = MyDatabase(DatabaseConnection(
NativeDatabase.memory(),
closeStreamsSynchronously: true, // (1)!
));
});
tearDown(() async {
await database.close();
});
}
```
{.annotate }
1. By default, unsubscribing from a query stream created by drift will keep the stream open for one event
loop iteration. This is useful for e.g. Flutter apps, where rebuilds may cause a `StreamBuilder` to
re-subscribe to streams frequently.
In Flutter widget tests however, it's illegal to keep these timers open after a test concludes.
To avoid issues with Drift in that setups, pass a `DatabaseConnection` with `closeStreamsSynchronously: true`
to your database.
By default, unsubscribing from a query stream created by drift will keep the stream open for one event
loop iteration. This is useful for e.g. Flutter apps, where rebuilds may cause a `StreamBuilder` to
re-subscribe to streams frequently.
In Flutter widget tests however, it's illegal to keep these timers open after a test concludes.
To avoid issues with Drift in that setups, pass a `DatabaseConnection` with `closeStreamsSynchronously: true`
to your database.
With that setup in place, we can finally write some tests:
```dart
@@ -138,4 +119,4 @@ test('stream emits a new user when the name updates', () async {
## Testing migrations
Drift can help you generate code for schema migrations. For more details, see
[this guide](Migrations/tests.md).
[this guide](migrations/tests.md).
+1
View File
@@ -5,6 +5,7 @@
@use "src/styles/details";
@use "src/styles/header";
@use "src/styles/sidebar";
@use "src/styles/ui";
@use "src/styles/constants" as c;
@use "src/jaspr";
@@ -25,10 +25,12 @@ final class _WebCompatibilityCheckState extends State<WebCompatibilityCheck> {
builder: (context, snapshot) {
return div([
if (_compatibilityResult == null) ...[
button([text('Check compatibility')]),
button(classes: 'compat', [
text('Check compatibility'),
], onClick: startCheck),
pre([text('Compatibility check not started yet.')]),
] else if (snapshot.connectionState == ConnectionState.active)
progress([])
] else if (snapshot.connectionState == ConnectionState.waiting)
text('Loading...')
else if (snapshot.hasError)
pre([
text('Error: ${snapshot.error}, Trace:\n${snapshot.stackTrace}'),
@@ -84,4 +84,5 @@ const generatedSnippets = {
'lib/src/snippets/modular/custom_types/table.dart.types.temp.dart.snippet.json': {'(full)': '<span><span class="keyword">typedef</span> <span class="type">T0</span> = <span class="class">Duration</span>;</span>\n',},
'lib/src/snippets/modular/custom_types/drift_table.drift.types.temp.dart.snippet.json': {'(full)': '<span><span class="keyword">typedef</span> <span class="type">T0</span> = <span class="class">Duration</span>;</span>\n',},
'lib/src/snippets/modular/drift/with_existing.drift.types.temp.dart.snippet.json': {'(full)': '<span><span class="keyword">import</span> <span class="string">\'package:drift_website/src/snippets/modular/drift/row_class.dart\'</span> <span class="keyword">as</span> <span class="variable importPrefix">i0</span>;\n<span class="keyword">typedef</span> <span class="type">T0</span> = <span class="variable importPrefix">i0</span>.<span class="class">User</span>;\n<span class="keyword">typedef</span> <span class="type">T1</span> = <span class="variable importPrefix">i0</span>.<span class="class">UserWithFriends</span>;</span>\n',},
'lib/src/snippets/setup/testing.dart.snippet.json': {'(full)': '<span><span class="keyword">import</span> <span class="string"><a href="https://pub.dev/documentation/drift/latest/drift/drift-library.html">\'package:drift/drift.dart\'</a></span>;\n<span class="keyword">import</span> <span class="string"><a href="https://pub.dev/documentation/drift/latest/native/native-library.html">\'package:drift/native.dart\'</a></span>;\n<span class="keyword">import</span> <span class="string">\'package:test/test.dart\'</span>;\n<span class="comment">// the file defined above, you can test any drift database of course</span>\n<span class="keyword">import</span> <span class="string">\'database.dart\'</span>;\n\n<span class="keyword void">void</span> <span class="function declaration static">main</span>() {\n <span class="keyword">late</span> <span class="class">AppDatabase</span> <span class="variable declaration">database</span>;\n\n <span class="function">setUp</span>(() {\n <span class="variable">database</span> = <span class="class constructor">AppDatabase</span>(\n <span class="class constructor"><a href="https://pub.dev/documentation/drift/latest/drift/DatabaseConnection-class.html">DatabaseConnection</a></span>(\n <span class="class constructor"><a href="https://pub.dev/documentation/drift/latest/native/NativeDatabase-class.html">NativeDatabase</a></span>.<span class="method constructor"><a href="https://pub.dev/documentation/drift/latest/native/NativeDatabase/NativeDatabase.memory.html">memory</a></span>(),\n <span class="comment">// Recommended for widget tests to avoid test errors.</span>\n <span class="parameter label"><a href="https://pub.dev/documentation/drift/latest/drift/DatabaseConnection/DatabaseConnection.html">closeStreamsSynchronously</a></span>: <span class="boolean">true</span>,\n ),\n );\n });\n <span class="function">tearDown</span>(() <span class="keyword control">async</span> {\n <span class="keyword control">await</span> <span class="variable">database</span>.<span class="method instance"><a href="https://pub.dev/documentation/drift/latest/drift/GeneratedDatabase/close.html">close</a></span>();\n });\n}</span>\n',},
};
@@ -0,0 +1,22 @@
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:test/test.dart';
// the file defined above, you can test any drift database of course
import 'database.dart';
void main() {
late AppDatabase database;
setUp(() {
database = AppDatabase(
DatabaseConnection(
NativeDatabase.memory(),
// Recommended for widget tests to avoid test errors.
closeStreamsSynchronously: true,
),
);
});
tearDown(() async {
await database.close();
});
}
+4
View File
@@ -0,0 +1,4 @@
button.compat {
border: 2px solid var(--primary);
padding: 0.25em;
}