diff --git a/drift_website/README.md b/drift_website/README.md index adae9b656..1068fdb9b 100644 --- a/drift_website/README.md +++ b/drift_website/README.md @@ -1,15 +1,20 @@ # drift_website -A documentation site built with Jaspr +Documentation for the Drift project, built with `jaspr_content`. -## Running the project +## Building the Documentation -Run your project using `jaspr serve`. +To start the website for preview purposes, run + +```shell +dart run jaspr_cli:jaspr serve --no-managed-build-options +``` The development server will be available on `http://localhost:8080`. -## Building the project +To build the website, run: -Build your project using `jaspr build`. - -The output will be located inside the `build/jaspr/` directory. +```shell +dart run jaspr_cli:jaspr serve --no-managed-build-options +rm -r build/jaspr/packages build/jaspr/.dart_tool build/jaspr/.build.manifest +``` diff --git a/drift_website/content/examples/existing_databases.md b/drift_website/content/examples/existing_databases.md index d32c4ae0b..5bbcdaf63 100644 --- a/drift_website/content/examples/existing_databases.md +++ b/drift_website/content/examples/existing_databases.md @@ -77,20 +77,27 @@ LazyDatabase _openConnection() { } ``` -=== "Using `drift_flutter`" + - {{ load_snippet('(full)','lib/snippets/examples/existing_databases_flutter.dart.excerpt.json',indent=4) }} + -=== "Using `package:drift/native.dart`" + - In drift, you can use a [LazyDatabase](https://pub.dev/documentation/drift/latest/drift/LazyDatabase-class.html) - to perform that work just before your drift database is opened: + - {{ load_snippet('(full)','lib/snippets/examples/existing_databases_native.dart.excerpt.json',indent=4) }} + +In drift, you can use a [LazyDatabase](https://pub.dev/documentation/drift/latest/drift/LazyDatabase-class.html) +to perform that work just before your drift database is opened: + + + + + + !!! warning - This snippet only works on native platforms. See [existing databases on the web](../Platforms/web.md#using-existing-databases) for web support. + This snippet only works on native platforms. See [existing databases on the web](../platforms/web.md#using-existing-databases) for web support. Finally, use that method to open your database: diff --git a/drift_website/content/examples/index.md b/drift_website/content/examples/index.md index 97bbd0cdc..d85d3f7e3 100644 --- a/drift_website/content/examples/index.md +++ b/drift_website/content/examples/index.md @@ -50,7 +50,7 @@ Additional patterns are also shown and explained on this website: [web_worker]: https://github.com/simolus3/drift/tree/develop/examples/web_worker_example [flutter_web_worker]: https://github.com/simolus3/drift/tree/develop/examples/flutter_web_worker_example [migration]: https://github.com/simolus3/drift/tree/develop/examples/migrations_example -[migration tooling](../Migrations/tests.md#verifying-data-integrity) +[migration tooling](../migrations/tests.md#verifying-data-integrity) [with_built_value]: https://github.com/simolus3/drift/tree/develop/examples/with_built_value [multi_package]: https://github.com/simolus3/drift/tree/develop/examples/multi_package diff --git a/drift_website/content/examples/server_sync.md b/drift_website/content/examples/server_sync.md index 4a7d3248f..6070a2382 100644 --- a/drift_website/content/examples/server_sync.md +++ b/drift_website/content/examples/server_sync.md @@ -7,7 +7,7 @@ description: Approaches for syncing drift databases between clients and backends At its core, drift is a package to access relational databases. On clients, that would typically be a SQLite3 database, which is what drift is optimized for. -More recently, drift also gained stable support for [PostgreSQL databases](../Platforms/postgres.md) as well. +More recently, drift also gained stable support for [PostgreSQL databases](../platforms/postgres.md) as well. This allows drift to be deployed in [fullstack Dart applications](https://github.com/simolus3/drift/tree/develop/examples/multi_package), where a server uses drift to talk to a Postgres database and clients use it to manage a sqlite3 database. Thanks to utilities like [DialectAwareSqlType](https://pub.dev/documentation/drift/latest/drift/DialectAwareSqlType-class.html), diff --git a/drift_website/content/generation_options/index.md b/drift_website/content/generation_options/index.md index 3a67ecb26..752c6c600 100644 --- a/drift_website/content/generation_options/index.md +++ b/drift_website/content/generation_options/index.md @@ -188,7 +188,7 @@ We currently support the following extensions: different tables. This requires a build flag when compiling SQLite. `sqlite3_flutter_libs` sets that flag, but other SQLite distributions might not. - `moor_ffi`: Enables support for functions that are only available when using a `NativeDatabase`. This contains `pow`, `sqrt` and a variety - of trigonometric functions. Details on those functions are available [here](../Platforms/vm.md#drift-only-functions). + of trigonometric functions. Details on those functions are available [here](../platforms/vm.md#drift-only-functions). - `math`: Assumes that sqlite3 was compiled with [math functions](https://www.sqlite.org/lang_mathfunc.html). This module is largely incompatible with the `moor_ffi` module. - `spellfix1`: Assumes that the [spellfix1](https://www.sqlite.org/spellfix1.html) diff --git a/drift_website/content/guides/upgrading.md b/drift_website/content/guides/upgrading.md index 3d690bb8a..46b6346b9 100644 --- a/drift_website/content/guides/upgrading.md +++ b/drift_website/content/guides/upgrading.md @@ -108,7 +108,7 @@ Also, you may have to - Format your sources again: Run `dart format .`. - Re-run the build: Run `dart run build_runner build -d`. - - If you have been using generated [migration test files](Migrations/exports.md), + - If you have been using generated [migration test files](../migrations/exports.md), re-generate them as well with `dart run drift_dev schema generate drift_schemas/ test/generated_migrations/` (you may have to adapt the command to the directories you use for schemas). - Manually fix the changed order of imports caused by the migration. @@ -189,7 +189,7 @@ If you opt for a rename, also update your imports and `include:` parameters in d #### Build configuration -When configuring moor builders for [options](generation_options/index.md), you have to update your `build.yaml` files to reflect the new builder keys: +When configuring moor builders for [options](../generation_options/index.md), you have to update your `build.yaml` files to reflect the new builder keys: | Moor builder key | Drift builder key | | ------------------------------------------- | ------------------------------ | diff --git a/drift_website/content/platforms/postgres.md b/drift_website/content/platforms/postgres.md index 113c8ffc3..fb3e69f79 100644 --- a/drift_website/content/platforms/postgres.md +++ b/drift_website/content/platforms/postgres.md @@ -91,7 +91,7 @@ This section lists affected APIs and workarounds to make them work PostgreSQL. Most parts of the `Migrator` API are SQLite-specific. You will be able to create tables on PostgreSQL as well, but methods like `alterTable` will only work with SQLite. While it's possible to use drift migrations with PostgreSQL databases, the recommended approach for now is to -[export your drift schema](../Tools/index.md#exporting) and then use dedicated migration tools for PostgreSQL. +[export your drift schema](../tools/index.md#exporting) and then use dedicated migration tools for PostgreSQL. In sqlite3, the current schema version is stored in the database file. To support drift's migration API being built on top of this mechanism in Postgres as well, drift creates a `__schema` table storing diff --git a/drift_website/lib/src/components/page_ref.dart b/drift_website/lib/src/components/page_ref.dart index bb4d6e91b..3c1398c91 100644 --- a/drift_website/lib/src/components/page_ref.dart +++ b/drift_website/lib/src/components/page_ref.dart @@ -19,7 +19,7 @@ final class PageRef implements CustomComponent { return null; } - if (url.extension(href.path) == '.md') { + if (href.authority == '' && url.extension(href.path) == '.md') { return _PageLink(ref: href, child: builder.build(children)); } } @@ -44,7 +44,7 @@ final class _PageLink extends StatelessComponent { ); if (referencedPage == null) { - return BrokenComponent('broken link to $resolvedRef'); + return BrokenComponent('broken link to ${ref.path} from ${page.path}'); } return a( diff --git a/drift_website/lib/src/generated_snippets.dart b/drift_website/lib/src/generated_snippets.dart index d3ca5783b..03364b1a2 100644 --- a/drift_website/lib/src/generated_snippets.dart +++ b/drift_website/lib/src/generated_snippets.dart @@ -4,6 +4,7 @@ const generatedSnippets = { 'lib/src/snippets/setup/migrate_to_drift/database.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\npart \'database.g.dart\';\n\n@DriftDatabase(include: {\'schema.drift\'})\nclass AppDatabase extends _\$AppDatabase {\n AppDatabase() : super(_openDatabase());\n\n @override\n int get schemaVersion => throw UnimplementedError(\n \'todo: The schema version used by your existing database\',\n );\n\n @override\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (m) async {\n await m.createAll();\n },\n onUpgrade: (m, from, to) async {\n // This is similar to the `onUpgrade` callback from sqflite. When\n // migrating to drift, it should contain your existing migration logic.\n // You can access the raw database by using `customStatement`\n },\n beforeOpen: (details) async {\n // This is a good place to enable pragmas you expect, e.g.\n await customStatement(\'pragma foreign_keys = ON;\');\n },\n );\n }\n\n static QueryExecutor _openDatabase() {\n throw UnimplementedError(\n \'todo: Open database compatible with the one that already exists\',\n );\n }\n\n Future<List<TestData>> queryWithGeneratedCode() async {\n return findWithValue(12).get();\n }\n\n Stream<List<TestData>> queryWithDartCode() {\n final query = select(test)..where((row) => row.value.isBiggerThanValue(12));\n return query.watch();\n }\n\n}\n\n','start': 'import \'package:drift/drift.dart\';\n\npart \'database.g.dart\';\n\n@DriftDatabase(include: {\'schema.drift\'})\nclass AppDatabase extends _\$AppDatabase {\n AppDatabase() : super(_openDatabase());\n\n @override\n int get schemaVersion => throw UnimplementedError(\n \'todo: The schema version used by your existing database\',\n );\n\n @override\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (m) async {\n await m.createAll();\n },\n onUpgrade: (m, from, to) async {\n // This is similar to the `onUpgrade` callback from sqflite. When\n // migrating to drift, it should contain your existing migration logic.\n // You can access the raw database by using `customStatement`\n },\n beforeOpen: (details) async {\n // This is a good place to enable pragmas you expect, e.g.\n await customStatement(\'pragma foreign_keys = ON;\');\n },\n );\n }\n\n static QueryExecutor _openDatabase() {\n throw UnimplementedError(\n \'todo: Open database compatible with the one that already exists\',\n );\n }\n\n}\n\n','drift-query': ' Future<List<TestData>> queryWithGeneratedCode() async {\n return findWithValue(12).get();\n }\n','dart-query': ' Stream<List<TestData>> queryWithDartCode() {\n final query = select(test)..where((row) => row.value.isBiggerThanValue(12));\n return query.watch();\n }\n\n',}, 'lib/src/snippets/setup/custom_flutter_setup.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'dart:io\';\nimport \'package:drift/native.dart\';\nimport \'package:path_provider/path_provider.dart\';\nimport \'package:path/path.dart\' as p;\nimport \'package:sqlite3/sqlite3.dart\';\nimport \'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart\';\n\nLazyDatabase openConnection() {\n // the LazyDatabase util lets us find the right location for the file async.\n return LazyDatabase(() async {\n // put the database file, called db.sqlite here, into the documents folder\n // for your app.\n final dbFolder = await getApplicationDocumentsDirectory();\n final file = File(p.join(dbFolder.path, \'db.sqlite\'));\n\n // Also work around limitations on old Android versions\n if (Platform.isAndroid) {\n await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();\n }\n\n // Make sqlite3 pick a more suitable location for temporary files - the\n // one from the system may be inaccessible due to sandboxing.\n final cachebase = (await getTemporaryDirectory()).path;\n // We can\'t access /tmp on Android, which sqlite3 would try by default.\n // Explicitly tell it about the correct temporary directory.\n sqlite3.tempDirectory = cachebase;\n\n return NativeDatabase.createInBackground(file);\n });\n}\n\n','custom': 'import \'dart:io\';\nimport \'package:drift/native.dart\';\nimport \'package:path_provider/path_provider.dart\';\nimport \'package:path/path.dart\' as p;\nimport \'package:sqlite3/sqlite3.dart\';\nimport \'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart\';\n\nLazyDatabase openConnection() {\n // the LazyDatabase util lets us find the right location for the file async.\n return LazyDatabase(() async {\n // put the database file, called db.sqlite here, into the documents folder\n // for your app.\n final dbFolder = await getApplicationDocumentsDirectory();\n final file = File(p.join(dbFolder.path, \'db.sqlite\'));\n\n // Also work around limitations on old Android versions\n if (Platform.isAndroid) {\n await applyWorkaroundToOpenSqlite3OnOldAndroidVersions();\n }\n\n // Make sqlite3 pick a more suitable location for temporary files - the\n // one from the system may be inaccessible due to sandboxing.\n final cachebase = (await getTemporaryDirectory()).path;\n // We can\'t access /tmp on Android, which sqlite3 would try by default.\n // Explicitly tell it about the correct temporary directory.\n sqlite3.tempDirectory = cachebase;\n\n return NativeDatabase.createInBackground(file);\n });\n}\n\n',}, 'lib/src/snippets/setup/database.dart.snippet.json': {'(full)': '// ignore_for_file: unused_element\nimport \'package:drift/drift.dart\';\n\nimport \'package:drift_flutter/drift_flutter.dart\';\nimport \'package:path_provider/path_provider.dart\';\nimport \'dart:io\';\nimport \'package:drift/native.dart\';\nimport \'package:drift_postgres/drift_postgres.dart\';\nimport \'package:postgres/postgres.dart\' as pg;\n\n\npart \'database.g.dart\';\n\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 32)();\n TextColumn get content => text().named(\'body\')();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\n@DriftDatabase(tables: [TodoItems])\nclass AppDatabase extends _\$AppDatabase {\n // After generating code, this class needs to define a `schemaVersion` getter\n // and a constructor telling drift where the database should be stored.\n // These are described in the getting started guide: https://drift.simonbinder.eu/setup/\n AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n\n static QueryExecutor _openConnection() {\n throw \'should not show as snippet\';\n }\n\n}\n\nclass OpenFlutter {\n static QueryExecutor _openConnection() {\n return driftDatabase(\n name: \'my_database\',\n native: const DriftNativeOptions(\n // By default, `driftDatabase` from `package:drift_flutter` stores the\n // database files in `getApplicationDocumentsDirectory()`.\n databaseDirectory: getApplicationSupportDirectory,\n ),\n // If you need web support, see https://drift.simonbinder.eu/platforms/web/\n );\n }\n}\n\nclass OpenPostgres {\n static QueryExecutor _openConnection() {\n return PgDatabase(\n endpoint: pg.Endpoint(\n host: \'localhost\',\n database: \'database\',\n username: \'dart\',\n password: \'mysecurepassword\',\n ),\n );\n }\n}\n\nclass OpenSqlite3 {\n static QueryExecutor _openConnection() {\n return NativeDatabase.createInBackground(File(\'path/to/your/database\'));\n }\n}\n\nclass WidgetsFlutterBinding {\n static void ensureInitialized() {}\n}\n\nvoid main() async {\n WidgetsFlutterBinding.ensureInitialized();\n\n final database = AppDatabase();\n\n await database.into(database.todoItems).insert(TodoItemsCompanion.insert(\n title: \'todo: finish drift setup\',\n content: \'We can now write queries and define our own tables.\',\n ));\n List<TodoItem> allItems = await database.select(database.todoItems).get();\n\n print(\'items in database: \$allItems\');\n}\n','flutter': 'import \'package:drift/drift.dart\';\nimport \'package:drift_flutter/drift_flutter.dart\';\nimport \'package:path_provider/path_provider.dart\';\n\npart \'database.g.dart\';\n\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 32)();\n TextColumn get content => text().named(\'body\')();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\n@DriftDatabase(tables: [TodoItems])\nclass AppDatabase extends _\$AppDatabase {\n // After generating code, this class needs to define a `schemaVersion` getter\n // and a constructor telling drift where the database should be stored.\n // These are described in the getting started guide: https://drift.simonbinder.eu/setup/\n AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n\n static QueryExecutor _openConnection() {\n return driftDatabase(\n name: \'my_database\',\n native: const DriftNativeOptions(\n // By default, `driftDatabase` from `package:drift_flutter` stores the\n // database files in `getApplicationDocumentsDirectory()`.\n databaseDirectory: getApplicationSupportDirectory,\n ),\n // If you need web support, see https://drift.simonbinder.eu/platforms/web/\n );\n }\n}\n','sqlite3': 'import \'package:drift/drift.dart\';\nimport \'dart:io\';\nimport \'package:drift/native.dart\';\n\npart \'database.g.dart\';\n\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 32)();\n TextColumn get content => text().named(\'body\')();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\n@DriftDatabase(tables: [TodoItems])\nclass AppDatabase extends _\$AppDatabase {\n // After generating code, this class needs to define a `schemaVersion` getter\n // and a constructor telling drift where the database should be stored.\n // These are described in the getting started guide: https://drift.simonbinder.eu/setup/\n AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n\n static QueryExecutor _openConnection() {\n return NativeDatabase.createInBackground(File(\'path/to/your/database\'));\n }\n}\n','postgres': 'import \'package:drift/drift.dart\';\nimport \'package:drift_postgres/drift_postgres.dart\';\nimport \'package:postgres/postgres.dart\' as pg;\n\npart \'database.g.dart\';\n\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 32)();\n TextColumn get content => text().named(\'body\')();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\n@DriftDatabase(tables: [TodoItems])\nclass AppDatabase extends _\$AppDatabase {\n // After generating code, this class needs to define a `schemaVersion` getter\n // and a constructor telling drift where the database should be stored.\n // These are described in the getting started guide: https://drift.simonbinder.eu/setup/\n AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n\n static QueryExecutor _openConnection() {\n return PgDatabase(\n endpoint: pg.Endpoint(\n host: \'localhost\',\n database: \'database\',\n username: \'dart\',\n password: \'mysecurepassword\',\n ),\n );\n }\n}\n','before_generation': 'import \'package:drift/drift.dart\';\n\npart \'database.g.dart\';\n\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 32)();\n TextColumn get content => text().named(\'body\')();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\n@DriftDatabase(tables: [TodoItems])\nclass AppDatabase extends _\$AppDatabase {\n}\n','table': 'class TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 32)();\n TextColumn get content => text().named(\'body\')();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\n','use': 'void main() async {\n WidgetsFlutterBinding.ensureInitialized();\n\n final database = AppDatabase();\n\n await database.into(database.todoItems).insert(TodoItemsCompanion.insert(\n title: \'todo: finish drift setup\',\n content: \'We can now write queries and define our own tables.\',\n ));\n List<TodoItem> allItems = await database.select(database.todoItems).get();\n\n print(\'items in database: \$allItems\');\n}\n',}, +'lib/src/snippets/setup/testing.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\nimport \'package:test/test.dart\';\n// the file defined above, you can test any drift database of course\nimport \'database.dart\';\n\nvoid main() {\n late AppDatabase database;\n\n setUp(() {\n database = AppDatabase(\n DatabaseConnection(\n NativeDatabase.memory(),\n // Recommended for widget tests to avoid test errors.\n closeStreamsSynchronously: true,\n ),\n );\n });\n tearDown(() async {\n await database.close();\n });\n}\n',}, 'lib/src/snippets/isolates.dart.snippet.json': {'(full)': 'import \'dart:io\';\nimport \'dart:isolate\';\n\nimport \'package:drift/drift.dart\';\nimport \'package:drift/isolate.dart\';\nimport \'package:drift/native.dart\';\nimport \'package:path/path.dart\' as p;\nimport \'package:path_provider/path_provider.dart\';\n\npart \'isolates.g.dart\';\n\nQueryExecutor _openConnection() {\n return NativeDatabase.memory();\n}\n\nclass SomeTable extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get content => text()();\n}\n\n// Copying the definitions here because we can\'t import Flutter in documentation\n// snippets.\nclass RootIsolateToken {\n static RootIsolateToken? instance;\n}\n\nclass BackgroundIsolateBinaryMessenger {\n static void ensureInitialized(RootIsolateToken token) {}\n}\n\n\n@DriftDatabase(tables: [SomeTable] /* ... */)\nclass MyDatabase extends _\$MyDatabase {\n // A constructor like this can use the default connection as described in the\n // getting started guide, but also allows overriding the connection.\n MyDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n}\n\nFuture<DriftIsolate> createIsolateWithSpawn() async {\n final token = RootIsolateToken.instance!;\n return await DriftIsolate.spawn(() {\n // This function runs in a new isolate, so we must first initialize the\n // messenger to use platform channels.\n BackgroundIsolateBinaryMessenger.ensureInitialized(token);\n\n // The callback to DriftIsolate.spawn() must return the database connection\n // to use.\n return LazyDatabase(() async {\n // Note that this runs on a background isolate, which only started to\n // support platform channels in Flutter 3.7. For earlier Flutter versions,\n // a workaround is described later in this article.\n final dbFolder = await getApplicationDocumentsDirectory();\n final path = p.join(dbFolder.path, \'app.db\');\n\n return NativeDatabase(File(path));\n });\n });\n}\n\nFuture<DriftIsolate> createIsolateManually() async {\n final receiveIsolate = ReceivePort(\'receive drift isolate handle\');\n await Isolate.spawn<SendPort>((message) async {\n final server = DriftIsolate.inCurrent(() {\n // Again, this needs to return the LazyDatabase or the connection to use.\n throw \'stub\';\n });\n\n // Now, inform the original isolate about the created server:\n message.send(server);\n }, receiveIsolate.sendPort);\n\n final server = await receiveIsolate.first as DriftIsolate;\n receiveIsolate.close();\n return server;\n}\n\nFuture<DriftIsolate> createIsolate() => createIsolateWithSpawn();\n\nvoid main() async {\n final isolate = await createIsolate();\n\n // After creating the isolate, calling connect() will return a connection\n // which can be used to create a database.\n // As long as the isolate is used by only one database (it is here), we can\n // use `singleClientMode` to dispose the isolate after closing the connection.\n final database = MyDatabase(await isolate.connect(singleClientMode: true));\n\n // you can now use your database exactly like you regularly would, it\n // transparently uses a background isolate to execute queries.\n // Just using the db to avoid an analyzer error, this isn\'t part of the docs.\n database.customSelect(\'SELECT 1\');\n}\n\nvoid connectSynchronously() {\n MyDatabase(\n DatabaseConnection.delayed(Future.sync(() async {\n final isolate = await createIsolate();\n return isolate.connect(singleClientMode: true);\n })),\n );\n}\n\n\nFuture<DriftIsolate> _createDriftIsolate() async {\n // this method is called from the main isolate. Since we can\'t use\n // getApplicationDocumentsDirectory on a background isolate, we calculate\n // the database path in the foreground isolate and then inform the\n // background isolate about the path.\n final dir = await getApplicationDocumentsDirectory();\n final path = p.join(dir.path, \'db.sqlite\');\n final receivePort = ReceivePort();\n\n await Isolate.spawn(\n _startBackground,\n _IsolateStartRequest(receivePort.sendPort, path),\n );\n\n // _startBackground will send the DriftIsolate to this ReceivePort\n return await receivePort.first as DriftIsolate;\n}\n\nvoid _startBackground(_IsolateStartRequest request) {\n // this is the entry point from the background isolate! Let\'s create\n // the database from the path we received\n final executor = NativeDatabase(File(request.targetPath));\n // we\'re using DriftIsolate.inCurrent here as this method already runs on a\n // background isolate. If we used DriftIsolate.spawn, a third isolate would be\n // started which is not what we want!\n final driftIsolate = DriftIsolate.inCurrent(\n () => DatabaseConnection(executor),\n );\n // inform the starting isolate about this, so that it can call .connect()\n request.sendDriftIsolate.send(driftIsolate);\n}\n\n// used to bundle the SendPort and the target path, since isolate entry point\n// functions can only take one parameter.\nclass _IsolateStartRequest {\n final SendPort sendDriftIsolate;\n final String targetPath;\n\n _IsolateStartRequest(this.sendDriftIsolate, this.targetPath);\n}\n\nDatabaseConnection createDriftIsolateAndConnect() {\n return DatabaseConnection.delayed(Future.sync(() async {\n final isolate = await _createDriftIsolate();\n return await isolate.connect(singleClientMode: true);\n }));\n}\n\nQueryExecutor createSimple() {\n return LazyDatabase(() async {\n final dir = await getApplicationDocumentsDirectory();\n final file = File(p.join(dir.path, \'db.sqlite\'));\n\n // Using createInBackground creates a drift isolate with the recommended\n // options behind the scenes.\n return NativeDatabase.createInBackground(file);\n });\n}\n\nFuture<void> invalidIsolateUsage() async {\n final database = MyDatabase(NativeDatabase.memory());\n\n // Unfortunately, this doesn\'t work: Drift databases contain references to\n // async primitives like streams and futures that can\'t be serialized across\n // isolates like this.\n await Isolate.run(() async {\n await database.batch((batch) {\n // ...\n });\n });\n}\n\nFuture<List<SomeTableData>> _complexAndExpensiveOperationToFetchRows() async {\n throw \'stub\';\n}\n\nFuture<void> insertBulkData(MyDatabase database) async {\n // computeWithDatabase is an extension provided by package:drift/isolate.dart\n await database.computeWithDatabase(\n computation: (database) async {\n // Expensive computation that runs on its own isolate but talks to the\n // main database.\n final rows = await _complexAndExpensiveOperationToFetchRows();\n await database.batch((batch) {\n batch.insertAll(database.someTable, rows);\n });\n },\n connect: (connection) {\n // This function is responsible for creating a second instance of your\n // database class with a short-lived [connection].\n // For this to work, your database class needs to have a constructor that\n // allows taking a connection as described above.\n return MyDatabase(connection);\n },\n );\n}\n\nFuture<void> customIsolateUsage(MyDatabase database) async {\n final connection = await database.serializableConnection();\n\n await Isolate.run(\n () async {\n // We can\'t share the [database] object across isolates, but the connection\n // is fine!\n final databaseForIsolate = MyDatabase(await connection.connect());\n\n try {\n await databaseForIsolate.batch((batch) {\n // (...)\n });\n } finally {\n databaseForIsolate.close();\n }\n },\n debugName: \'My custom database task\',\n );\n}\n','isolate': 'import \'package:drift/isolate.dart\';\n\n@DriftDatabase(tables: [SomeTable] /* ... */)\nclass MyDatabase extends _\$MyDatabase {\n // A constructor like this can use the default connection as described in the\n // getting started guide, but also allows overriding the connection.\n MyDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n}\nvoid main() async {\n final isolate = await createIsolate();\n\n // After creating the isolate, calling connect() will return a connection\n // which can be used to create a database.\n // As long as the isolate is used by only one database (it is here), we can\n // use `singleClientMode` to dispose the isolate after closing the connection.\n final database = MyDatabase(await isolate.connect(singleClientMode: true));\n\n // you can now use your database exactly like you regularly would, it\n // transparently uses a background isolate to execute queries.\n}\n','initialization': 'import \'package:path/path.dart\' as p;\nimport \'package:path_provider/path_provider.dart\';\n\nFuture<DriftIsolate> _createDriftIsolate() async {\n // this method is called from the main isolate. Since we can\'t use\n // getApplicationDocumentsDirectory on a background isolate, we calculate\n // the database path in the foreground isolate and then inform the\n // background isolate about the path.\n final dir = await getApplicationDocumentsDirectory();\n final path = p.join(dir.path, \'db.sqlite\');\n final receivePort = ReceivePort();\n\n await Isolate.spawn(\n _startBackground,\n _IsolateStartRequest(receivePort.sendPort, path),\n );\n\n // _startBackground will send the DriftIsolate to this ReceivePort\n return await receivePort.first as DriftIsolate;\n}\n\nvoid _startBackground(_IsolateStartRequest request) {\n // this is the entry point from the background isolate! Let\'s create\n // the database from the path we received\n final executor = NativeDatabase(File(request.targetPath));\n // we\'re using DriftIsolate.inCurrent here as this method already runs on a\n // background isolate. If we used DriftIsolate.spawn, a third isolate would be\n // started which is not what we want!\n final driftIsolate = DriftIsolate.inCurrent(\n () => DatabaseConnection(executor),\n );\n // inform the starting isolate about this, so that it can call .connect()\n request.sendDriftIsolate.send(driftIsolate);\n}\n\n// used to bundle the SendPort and the target path, since isolate entry point\n// functions can only take one parameter.\nclass _IsolateStartRequest {\n final SendPort sendDriftIsolate;\n final String targetPath;\n\n _IsolateStartRequest(this.sendDriftIsolate, this.targetPath);\n}\n','database-definition': '\n@DriftDatabase(tables: [SomeTable] /* ... */)\nclass MyDatabase extends _\$MyDatabase {\n // A constructor like this can use the default connection as described in the\n // getting started guide, but also allows overriding the connection.\n MyDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());\n\n @override\n int get schemaVersion => 1;\n}\n','driftisolate-spawn': 'Future<DriftIsolate> createIsolateWithSpawn() async {\n final token = RootIsolateToken.instance!;\n return await DriftIsolate.spawn(() {\n // This function runs in a new isolate, so we must first initialize the\n // messenger to use platform channels.\n BackgroundIsolateBinaryMessenger.ensureInitialized(token);\n\n // The callback to DriftIsolate.spawn() must return the database connection\n // to use.\n return LazyDatabase(() async {\n // Note that this runs on a background isolate, which only started to\n // support platform channels in Flutter 3.7. For earlier Flutter versions,\n // a workaround is described later in this article.\n final dbFolder = await getApplicationDocumentsDirectory();\n final path = p.join(dbFolder.path, \'app.db\');\n\n return NativeDatabase(File(path));\n });\n });\n}\n','custom-spawn': 'Future<DriftIsolate> createIsolateManually() async {\n final receiveIsolate = ReceivePort(\'receive drift isolate handle\');\n await Isolate.spawn<SendPort>((message) async {\n final server = DriftIsolate.inCurrent(() {\n // Again, this needs to return the LazyDatabase or the connection to use.\n });\n\n // Now, inform the original isolate about the created server:\n message.send(server);\n }, receiveIsolate.sendPort);\n\n final server = await receiveIsolate.first as DriftIsolate;\n receiveIsolate.close();\n return server;\n}\n','delayed': ' MyDatabase(\n DatabaseConnection.delayed(Future.sync(() async {\n final isolate = await createIsolate();\n return isolate.connect(singleClientMode: true);\n })),\n );\n','init_connect': 'DatabaseConnection createDriftIsolateAndConnect() {\n return DatabaseConnection.delayed(Future.sync(() async {\n final isolate = await _createDriftIsolate();\n return await isolate.connect(singleClientMode: true);\n }));\n}\n','simple': 'QueryExecutor createSimple() {\n return LazyDatabase(() async {\n final dir = await getApplicationDocumentsDirectory();\n final file = File(p.join(dir.path, \'db.sqlite\'));\n\n // Using createInBackground creates a drift isolate with the recommended\n // options behind the scenes.\n return NativeDatabase.createInBackground(file);\n });\n}\n','invalid': 'Future<void> invalidIsolateUsage() async {\n final database = MyDatabase(NativeDatabase.memory());\n\n // Unfortunately, this doesn\'t work: Drift databases contain references to\n // async primitives like streams and futures that can\'t be serialized across\n // isolates like this.\n await Isolate.run(() async {\n await database.batch((batch) {\n // ...\n });\n });\n}\n','compute': 'Future<void> insertBulkData(MyDatabase database) async {\n // computeWithDatabase is an extension provided by package:drift/isolate.dart\n await database.computeWithDatabase(\n computation: (database) async {\n // Expensive computation that runs on its own isolate but talks to the\n // main database.\n final rows = await _complexAndExpensiveOperationToFetchRows();\n await database.batch((batch) {\n batch.insertAll(database.someTable, rows);\n });\n },\n connect: (connection) {\n // This function is responsible for creating a second instance of your\n // database class with a short-lived [connection].\n // For this to work, your database class needs to have a constructor that\n // allows taking a connection as described above.\n return MyDatabase(connection);\n },\n );\n}\n','custom-compute': 'Future<void> customIsolateUsage(MyDatabase database) async {\n final connection = await database.serializableConnection();\n\n await Isolate.run(\n () async {\n // We can\'t share the [database] object across isolates, but the connection\n // is fine!\n final databaseForIsolate = MyDatabase(await connection.connect());\n\n try {\n await databaseForIsolate.batch((batch) {\n // (...)\n });\n } finally {\n databaseForIsolate.close();\n }\n },\n debugName: \'My custom database task\',\n );\n}\n',}, 'lib/src/snippets/custom_row_classes/employee.dart.snippet.json': {'(full)': 'class EmployeeWithStaff {}\n',}, 'lib/src/snippets/custom_row_classes/employees_sql.drift.snippet.json': {'(full)': 'import \'employee.dart\';\n\nCREATE TABLE employees(\n id INTEGER NOT NULL PRIMARY KEY,\n name TEXT NOT NULL,\n supervisor INTEGER REFERENCES employees(id)\n);\n\nemployeeWithStaff WITH EmployeeWithStaff: SELECT\n self.**,\n supervisor.name,\n LIST(SELECT * FROM employees WHERE supervisor = self.id) AS staff\n FROM employees AS self\n INNER JOIN employees supervisor ON supervisor.id = self.supervisor\n WHERE id = ?;\n','example': 'CREATE TABLE employees(\n id INTEGER NOT NULL PRIMARY KEY,\n name TEXT NOT NULL,\n supervisor INTEGER REFERENCES employees(id)\n);\n\nemployeeWithStaff WITH EmployeeWithStaff: SELECT\n self.**,\n supervisor.name,\n LIST(SELECT * FROM employees WHERE supervisor = self.id) AS staff\n FROM employees AS self\n INNER JOIN employees supervisor ON supervisor.id = self.supervisor\n WHERE id = ?;\n',}, @@ -84,5 +85,4 @@ const generatedSnippets = { 'lib/src/snippets/modular/custom_types/table.dart.types.temp.dart.snippet.json': {'(full)': 'typedef T0 = Duration;\n',}, 'lib/src/snippets/modular/custom_types/drift_table.drift.types.temp.dart.snippet.json': {'(full)': 'typedef T0 = Duration;\n',}, 'lib/src/snippets/modular/drift/with_existing.drift.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/modular/drift/row_class.dart\' as i0;\ntypedef T0 = i0.User;\ntypedef T1 = i0.UserWithFriends;\n',}, -'lib/src/snippets/setup/testing.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\nimport \'package:test/test.dart\';\n// the file defined above, you can test any drift database of course\nimport \'database.dart\';\n\nvoid main() {\n late AppDatabase database;\n\n setUp(() {\n database = AppDatabase(\n DatabaseConnection(\n NativeDatabase.memory(),\n // Recommended for widget tests to avoid test errors.\n closeStreamsSynchronously: true,\n ),\n );\n });\n tearDown(() async {\n await database.close();\n });\n}\n',}, }; diff --git a/drift_website/pubspec.yaml b/drift_website/pubspec.yaml index 49b41cb1b..de7f3a9e6 100644 --- a/drift_website/pubspec.yaml +++ b/drift_website/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: sqlcipher_flutter_libs: ^0.6.8 test: ^1.26.3 rxdart: ^0.28.0 - jaspr_content_snippets: ^0.1.2 + jaspr_content_snippets: ^0.1.3 glob: ^2.1.3 markdown: ^7.3.0 @@ -36,6 +36,14 @@ dev_dependencies: json_serializable: ^6.11.1 sass_builder: ^2.3.1 + jaspr_cli: + # This stops jaspr from messing with the builder configuration. Upstream PR: + # https://github.com/schultek/jaspr/pull/592 + git: + url: https://github.com/simolus3/jaspr.git + ref: c9c59cea8e64de2f4cd135e162ac69a9f3df1312 + path: packages/jaspr_cli + jaspr: mode: static