diff --git a/drift_website/build.yaml b/drift_website/build.yaml index 5722045c2..0d0ae2fce 100644 --- a/drift_website/build.yaml +++ b/drift_website/build.yaml @@ -54,6 +54,8 @@ targets: builders: jaspr_content_snippets: enabled: true + options: + process_without_directives: true generate_for: include: - "lib/src/snippets/**/*.dart" @@ -61,6 +63,7 @@ targets: - "lib/src/snippets/*.dart" exclude: - "**/*.g.dart" + - "**/*.drift.dart" auto_apply_builders: false sources: - "$package$" diff --git a/drift_website/content/dart_api/expressions.md b/drift_website/content/dart_api/expressions.md index 2136dbc0c..0c3e3c591 100644 --- a/drift_website/content/dart_api/expressions.md +++ b/drift_website/content/dart_api/expressions.md @@ -109,7 +109,7 @@ Again, the `isNotIn` function works the other way around. Support for common JSON operators is provided through `package:drift/extensions/json1.dart`. This provides things like `jsonExtract` to extract fields from JSON or `jsonEach` to query -nested JSON structures. For more details, see the [JSON support](select.md#json-support) section on the page about selects or [this more complex example](../Examples/relationships.md#with-json-functions). +nested JSON structures. For more details, see the [JSON support](select.md#json-support) section on the page about selects or [this more complex example](../examples/relationships.md#with-json-functions). ## Aggregate functions (like count and sum) @@ -181,7 +181,7 @@ This ranking can be attached to each row: When using a `NativeDatabase`, a basic set of trigonometric functions will be available. It also defines the `REGEXP` function, which allows you to use `a REGEXP b` in SQL queries. -For more information, see the [list of functions](../Platforms/vm.md#drift-only-functions) here. +For more information, see the [list of functions](../platforms/vm.md#drift-only-functions) here. ## Subqueries diff --git a/drift_website/content/dart_api/select.md b/drift_website/content/dart_api/select.md index d982cb3b7..bb8f58389 100644 --- a/drift_website/content/dart_api/select.md +++ b/drift_website/content/dart_api/select.md @@ -15,23 +15,7 @@ For each table you've specified in the `@DriftDatabase` annotation on your datab a corresponding getter for a table will be generated. That getter can be used to run statements: -```dart -@DriftDatabase(tables: [TodoItems, Categories]) -class MyDatabase extends _$MyDatabase { - - // the schemaVersion getter and the constructor from the previous page - // have been omitted. - - // loads all todo entries - Future> get allTodoItems => select(todoItems).get(); - - // watches all todo entries in a given category. The stream will automatically - // emit new items whenever the underlying data changes. - Stream> watchEntriesInCategory(Category c) { - return (select(todos)..where((t) => t.category.equals(c.id))).watch(); - } -} -``` + Drift makes writing queries easy and safe. This page describes how to write basic select queries, but also explains how to use joins and subqueries for advanced queries. @@ -132,60 +116,20 @@ Note that the `like` check is _not_ performed in Dart - it's sent to the underly can efficiently compute it for all rows. ## Aliases + Sometimes, a query references a table more than once. Consider the following example to store saved routes for a navigation system: -```dart -class GeoPoints extends Table { - IntColumn get id => integer().autoIncrement()(); - TextColumn get name => text()(); - TextColumn get latitude => text()(); - TextColumn get longitude => text()(); -} -class Routes extends Table { - - IntColumn get id => integer().autoIncrement()(); - TextColumn get name => text()(); - - // contains the id for the start and destination geopoint. - IntColumn get start => integer()(); - IntColumn get destination => integer()(); -} -``` + Now, let's say we wanted to also load the start and destination `GeoPoint` object for each route. We'd have to use a join on the `geo-points` table twice: For the start and destination point. To express that in a query, aliases can be used: -```dart -class RouteWithPoints { - final Route route; - final GeoPoint start; - final GeoPoint destination; - RouteWithPoints({this.route, this.start, this.destination}); -} + -// inside the database class: -Future> loadRoutes() async { - // create aliases for the geoPoints table so that we can reference it twice - final start = alias(geoPoints, 's'); - final destination = alias(geoPoints, 'd'); - - final rows = await select(routes).join([ - innerJoin(start, start.id.equalsExp(routes.start)), - innerJoin(destination, destination.id.equalsExp(routes.destination)), - ]).get(); - - return rows.map((resultRow) { - return RouteWithPoints( - route: resultRow.readTable(routes), - start: resultRow.readTable(start), - destination: resultRow.readTable(destination), - ); - }).toList(); -} -``` The generated statement then looks like this: + ```sql SELECT routes.id, routes.name, routes.start, routes.destination, diff --git a/drift_website/content/dart_api/tables.md b/drift_website/content/dart_api/tables.md index 02414103c..8e6208966 100644 --- a/drift_website/content/dart_api/tables.md +++ b/drift_website/content/dart_api/tables.md @@ -66,7 +66,7 @@ dart run build_runner build ``` Drift initializes a brand-new database with all defined tables when the database is opened for the first time. (typically when running the app for the first time) -However, if a database already exists, Drift won't make any automatic changes to its structure. Please see [migrations](../Migrations/index.md) for an overview of what to do when changing the database like this. +However, if a database already exists, Drift won't make any automatic changes to its structure. Please see [migrations](../migrations/index.md) for an overview of what to do when changing the database like this. ## Column types @@ -87,7 +87,7 @@ Drift offers a variety of built-in column types to suit most database needs. | `DateTime` (see [options](#datetime-options)) | `late final createdAt = dateTime()()` | `INTEGER`or `TEXT` | | Your own | See [type converter docs](../type_converters.md). | Depending on type | | Enums | [`intEnum` or `textEnum`](../type_converters.md#implicit-enum-converters). | `INTEGER` or `TEXT` | -| Postgres Types | See [postgres docs](../Platforms/postgres.md). | Depending on type | +| Postgres Types | See [postgres docs](../platforms/postgres.md). | Depending on type | In addition to these basic types, columns can be configured to store any type which can be converted to a built-in type. See [type converters](../type_converters.md) for more information. @@ -103,13 +103,11 @@ For most tables, a single auto-incrementing integer column is sufficient as the With Drift, these columns are declared by using `autoIncrement()` in the definition of a column, which will: -
-1. Make that column the sole primary-key of the table. (1) -2. Make this column automatically count up by 1 for each new row. -
-1. Thus, you can't use `autoIncrement()` on multiple columns, or mix +1. Make that column the sole primary-key of the table. + Thus, you can't use `autoIncrement()` on multiple columns, or mix `autoIncrement()` and other [primary keys](#primary-keys) +2. Make this column automatically count up by 1 for each new row. For example, when declaring a table with an auto-incrementing column: @@ -167,7 +165,7 @@ statements. #### `withDefault()` Set a default value as a SQL expression that is applied in the database itself. See [expressions](../dart_api/expressions.md) for more information on how to write these expressions. Adding, removing, or changing the default value is considered a -[schema change](../Migrations/index.md) that requires special care. +[schema change](../migrations/index.md) that requires special care. A common example for default values is to add a column describing when the row has been created: @@ -207,7 +205,7 @@ should happen when the target row gets updated or deleted. Be aware that, in sqlite3, foreign key references aren't enabled by default. They need to be enabled with `PRAGMA foreign_keys = ON`. -A suitable place to issue that pragma with drift is in a [post-migration callback](../Migrations/index.md#post-migration-callbacks). +A suitable place to issue that pragma with drift is in a [post-migration callback](../migrations/index.md#post-migration-callbacks). ### Additional validation checks @@ -358,7 +356,7 @@ You can also add custom constraints to the table itself by overriding the `table -!!! note "SQL Validation" +!!! success "SQL Validation" Don't worry about syntax errors or unsupported features. Drift will validate the SQL you provide and throw an error during code generation if there are any issues. diff --git a/drift_website/content/faq.md b/drift_website/content/faq.md index bbf92846e..040040460 100644 --- a/drift_website/content/faq.md +++ b/drift_website/content/faq.md @@ -52,7 +52,7 @@ in your favorite dependency injection framework for flutter hence solves this pr ## Why am I getting no such table errors? -If you add another table after your app has already been installed, you need to write a [migration](Migrations/index.md) +If you add another table after your app has already been installed, you need to write a [migration](migrations/index.md) that covers creating that table. If you're in the process of developing your app and want to use un- and reinstall your app instead of writing migrations, that's fine too. Please note that your apps data might be backed up on Android, so manually deleting your app's data instead of a reinstall is necessary on some devices. @@ -60,7 +60,7 @@ manually deleting your app's data instead of a reinstall is necessary on some de ## How do I fix lints in generated files? Based on your linter settings, you might see some warnings in the `.g.dart` files generated by drift. Since lints are mainly used for -human-written code, we recommend to disable static analysis on generated files. For that, generate a top-level file called +human-written code, we recommend to disable static analysis on generated files. For that, generate a top-level file called `analysis_options.yaml` in your project and add this content: ```yaml analyzer: @@ -72,12 +72,12 @@ You might have to restart your IDE for the changes to apply. ## How can I inspect generated SQL? -All database implementations (`NativeDatabase`, `FlutterQueryExecutor`, ...) have a `logStatements` parameter that +All database implementations (`NativeDatabase`, `FlutterQueryExecutor`, ...) have a `logStatements` parameter that you can set to `true`. When enabled, drift will print the statements it runs. ## How do I insert data on the first app start? -You can populate the database on the first start of your app with a custom [migration strategy](Migrations/index.md). +You can populate the database on the first start of your app with a custom [migration strategy](migrations/index.md). To insert data when the database is created (which usually happens when the app is first run), you can use this: ```dart diff --git a/drift_website/content/index.md b/drift_website/content/index.md index 35d2ea12b..a17492492 100644 --- a/drift_website/content/index.md +++ b/drift_website/content/index.md @@ -31,62 +31,3 @@ and generating code. It also links a few pages intended for developers getting started with drift, so that you can explore the areas you're most interested in first. - -## Getting Started - -Here are a few things you can do to begin: - -* Explore the features of `jaspr_content` inside `lib/main.dart`. -* Read the [Quick Start Guide]({{links.quickstart}}) to understand how to set up your content-driven site. -* Start adding your own content pages in the `content/` directory. - -## Showcase - -`jaspr_content` supports all standard markdown syntax, allowing you to format your content effectively. It also supports adding custom components like this one: - - - This is an example of a custom component. You can create your own or use the ones provided by `jaspr_content` to enhance your documentation! - - - - -### Inline Elements - -Use `inline code` for brief mentions of code, **bold text** for emphasis, or *italic text* for highlighting. You can also create [links to external sites]({{links.website}}). - -### Blockquotes - -> This is a blockquote. It's great for highlighting important information or quotes. -> It has a custom color applied to it using `jaspr_content`s theming capabilities. - -### Code Blocks - -You can easily include code snippets. `jaspr_content` even comes with syntax highlighting and copy functionality out of the box. - -```dart -// lib/main.dart -import 'package:jaspr/jaspr.dart'; -import 'package:jaspr_content/jaspr_content.dart'; - -void main() { - runApp(ContentApp( - parsers: [ - MarkdownParser(), - ], - )); -} -``` - -## Images - -Displaying images is straightforward: - -![Jasper Photo](https://jaspr.site/images/jasper_resized/17.webp) - -You can even **zoom-in** by clicking on the image. - -## More to Discover! - -This is just a placeholder to get things started. - -Feel free to explore the [Documentation]({{links.docs}}) to understand the underlying architecture and how you can customize your site further. diff --git a/drift_website/content/migrations/index.md b/drift_website/content/migrations/index.md index 93a3bb320..cd3ebd133 100644 --- a/drift_website/content/migrations/index.md +++ b/drift_website/content/migrations/index.md @@ -197,4 +197,3 @@ beforeOpen: (details) async { await customStatement('PRAGMA foreign_keys = ON'); } ``` - diff --git a/drift_website/content/setup.md b/drift_website/content/setup.md index 6ad985089..1795a7211 100644 --- a/drift_website/content/setup.md +++ b/drift_website/content/setup.md @@ -25,7 +25,7 @@ adding a package to open database on the respective platform. -``` +```yaml dependencies: drift: ^{{ versions.drift }} drift_flutter: ^{{ versions.drift_flutter }} @@ -38,14 +38,14 @@ dev_dependencies: Alternatively, you can achieve the same result using the following command: -``` +```shell dart pub add drift drift_flutter path_provider dev:drift_dev dev:build_runner ``` -``` +```yaml dependencies: drift: ^{{ versions.drift }} sqlite3: ^{{ versions.sqlite3 }} @@ -64,7 +64,7 @@ dart pub add drift sqlite3 dev:drift_dev dev:build_runner -``` +```yaml dependencies: drift: ^{{ versions.drift }} postgres: ^{{ versions.postgres }} @@ -84,7 +84,7 @@ dart pub add drift postgres drift_postgres dev:drift_dev dev:build_runner Drift only generates code for sqlite3 by default. So, also create a `build.yaml` to [configure](generation_options/index.md) `drift_dev`: -``` +```yaml targets: $default: builders: @@ -187,7 +187,7 @@ started with drift: [selects](dart_api/select.md) or [inserts, updates and deletes](dart_api/writes.md). - Something to keep in mind for later: When changing the database, for instance by adding new columns or tables, you need to write a migration so that existing databases are transformed to the new - format. Drift's extensive [migration tools](Migrations/index.md) help with that. + format. Drift's extensive [migration tools](migrations/index.md) help with that. - Take a look at our [FAQ](./faq.md)! It will help you with the most common questions about drift projects. Once you're familiar with the basics, the [overview here](index.md) shows what diff --git a/drift_website/content/sql_api/drift_files.md b/drift_website/content/sql_api/drift_files.md index a42fbfac8..c2a9c2c55 100644 --- a/drift_website/content/sql_api/drift_files.md +++ b/drift_website/content/sql_api/drift_files.md @@ -1,17 +1,8 @@ --- - title: Drift files description: Learn everything about the `.drift` files, a powerful tool to define your database in SQL. - --- - - - - - - - Drift files are a new feature that lets you write all your database code in SQL. But unlike raw SQL strings you might pass to simple database clients, everything in a drift file is verified by drift's powerful SQL analyzer. @@ -22,11 +13,11 @@ dart_apis for them so that you don't have to read back results manually. To use this feature, lets create two files: `database.dart` and `tables.drift`. The Dart file only contains the minimum code to setup the database: -{{ load_snippet('overview','lib/snippets/drift_files/database.dart.excerpt.json') }} + We can now declare tables and queries in the drift file: -{{ load_snippet('(full)','lib/snippets/drift_files/tables.drift.excerpt.json') }} + After running the build runner with `dart run build_runner build`, drift will write the `database.g.dart` @@ -52,6 +43,7 @@ what we got: `todos` and the description of the associated category. ## Variables + Inside of named queries, you can use variables just like you would expect with sql. We support regular variables (`?`), explicitly indexed variables (`?123`) and colon-named variables (`:id`). We don't support variables declared @@ -63,16 +55,16 @@ When it's ambiguous, the analyzer might be unable to resolve the type of a variable. For those scenarios, you can also denote the explicit type of a variable: -{{ load_snippet('q1','lib/snippets/drift_files/small_snippets.drift.excerpt.json') }} + In addition to the base type, you can also declare that the type is nullable: -{{ load_snippet('q2','lib/snippets/drift_files/small_snippets.drift.excerpt.json') }} + Finally, you can declare that a variable should be required in Dart when using named parameters. To do so, add a `REQUIRED` keyword: -{{ load_snippet('q3','lib/snippets/drift_files/small_snippets.drift.excerpt.json') }} + Note that this only has an effect when the `named_parameters` [build option](../generation_options/index.md) is @@ -176,7 +168,7 @@ statement before it runs it. ## Imports You can put import statements at the top of a `drift` file: -{{ load_snippet('import','lib/snippets/drift_files/small_snippets.drift.excerpt.json') }} + All tables reachable from the other file will then also be visible in the current file and to the database that `includes` it. If you want @@ -194,13 +186,11 @@ know from Dart. ## Nested results - - Many queries fetch all columns from some table, typically by using the `SELECT table.*` syntax. That approach can become a bit tedious when applied over multiple tables from a join, as shown in this example: -{{ load_snippet('overview','lib/snippets/drift_files/nested.drift.excerpt.json') }} + To match the returned column names while avoiding name clashes in Dart, drift will generate a class having an `id`, `name`, `id1`, `lat`, `long`, `lat1` and @@ -208,7 +198,7 @@ a `long1` field. Of course, that's not helpful at all - was `lat1` coming from `from` or `to` again? Let's rewrite the query, this time using nested results: -{{ load_snippet('nested','lib/snippets/drift_files/nested.drift.excerpt.json') }} + As you can see, we can nest a result simply by using the drift-specific `table.**` syntax. @@ -247,13 +237,13 @@ Re-using the `coordinates` and `saved_routes` tables introduced in the example for [nested results](#nested-results), we add a new table storing coordinates along a route: -{{ load_snippet('route_points','lib/snippets/drift_files/nested.drift.excerpt.json') }} + Now, assume we wanted to query a route with information about all points along the way. While this requires two SQL statements, we can write this as a single drift query that is then split into the two statements automatically: -{{ load_snippet('list','lib/snippets/drift_files/nested.drift.excerpt.json') }} + This will generate a result set containing a `SavedRoute route` field along with a `List points` list of all points along the route. @@ -273,7 +263,7 @@ Drift files work perfectly together with drift's existing dart_api: - you can write Dart queries for tables declared in a drift file: -{{ load_snippet('dart_interop_insert','lib/snippets/drift_files/database.dart.excerpt.json') }} + - by importing Dart files into a drift file, you can write sql queries for tables declared in Dart. @@ -291,12 +281,12 @@ You can make most of both SQL and Dart with "Dart Templates", which is a Dart expression that gets inlined to a query at runtime. To use them, declare a $-variable in a query: -{{ load_snippet('filterTodos','lib/snippets/modular/drift/example.drift.excerpt.json') }} + Drift will generate a `Selectable` method with a `predicate` parameter that can be used to construct dynamic filters at runtime: -{{ load_snippet('watchInCategory','lib/snippets/modular/drift/dart_example.dart.excerpt.json') }} + This lets you write a single SQL query and dynamically apply a predicate at runtime! This feature works for @@ -311,7 +301,7 @@ This feature works for When used as expression, you can also supply a default value in your query: -{{ load_snippet('getTodos','lib/snippets/modular/drift/example.drift.excerpt.json') }} + This will make the `predicate` parameter optional in Dart. It will use the default SQL value (here, `TRUE`) when not explicitly set. @@ -365,11 +355,11 @@ Of course, the [warning](../type_converters.md#implicit-enum-converters) about a You can use custom row classes instead of having drift generate one for you. For instance, let's say you had a Dart class defined as -{{ load_snippet('user','lib/snippets/modular/drift/row_class.dart.excerpt.json') }} + Then, you can instruct drift to use that class as a row class as follows: -{{ load_snippet('users','lib/snippets/modular/drift/with_existing.drift.excerpt.json') }} + When using custom row classes defined in another Dart file, you also need to import that file into the file where you define the database. @@ -380,11 +370,11 @@ can be added after the name of the query. For instance, let's say we expand the existing Dart code in `row_class.dart` by adding another class: -{{ load_snippet('userwithfriends','lib/snippets/modular/drift/row_class.dart.excerpt.json') }} + Now, we can add a corresponding query using the new class for its rows: -{{ load_snippet('friends','lib/snippets/modular/drift/with_existing.drift.excerpt.json') }} + The `WITH UserWithFriends` syntax will make drift consider the `UserWithFriends` class. For every field in the constructor, drift will check the column from the query and diff --git a/drift_website/content/sql_api/extensions.md b/drift_website/content/sql_api/extensions.md index 745e3453c..b56541192 100644 --- a/drift_website/content/sql_api/extensions.md +++ b/drift_website/content/sql_api/extensions.md @@ -76,13 +76,13 @@ It's not possible to declare fts5 tables, or queries on fts5 tables, in Dart. You can learn more about the fts5 extension on [sqlite.org](https://www.sqlite.org/fts5.html). ## geopoly -The Geopoly module is an alternative interface to the [R-Tree](https://www.sqlite.org/rtree.html) extension -that uses the [GeoJSON](https://geojson.org/) notation ([RFC-7946](https://datatracker.ietf.org/doc/html/rfc7946)) +The Geopoly module is an alternative interface to the [R-Tree](https://www.sqlite.org/rtree.html) extension +that uses the [GeoJSON](https://geojson.org/) notation ([RFC-7946](https://datatracker.ietf.org/doc/html/rfc7946)) to describe two-dimensional polygons. -Geopoly includes functions for detecting when one polygon is contained within or overlaps with another, -for computing the area enclosed by a polygon, -for doing linear transformations of polygons, -for rendering polygons as [SVG](https://en.wikipedia.org/wiki/SVG), +Geopoly includes functions for detecting when one polygon is contained within or overlaps with another, +for computing the area enclosed by a polygon, +for doing linear transformations of polygons, +for rendering polygons as [SVG](https://en.wikipedia.org/wiki/SVG), and other similar operations. To enable the `geopoly` extension in drift files and compiled queries, modify the @@ -93,8 +93,8 @@ An example of creating a virtual table using this extension: ```sql create virtual table geo using geopoly(geoID, a, b); ``` -Sqlite will accept any types in additional columns (`geoID`, `a`, `b` from the example above), -so `drift` will generate a `DriftAny` type for these columns, which is not always convenient. +Sqlite will accept any types in additional columns (`geoID`, `a`, `b` from the example above), +so `drift` will generate a `DriftAny` type for these columns, which is not always convenient. To avoid this, you can add types as in this example: ```sql create virtual table geo using geopoly ( diff --git a/drift_website/content/sql_api/index.md b/drift_website/content/sql_api/index.md index 029990f67..a7e9d6300 100644 --- a/drift_website/content/sql_api/index.md +++ b/drift_website/content/sql_api/index.md @@ -23,9 +23,7 @@ What's different is how tables and queries are declared. For SQL to be recognize it needs to be put into a `.drift` file. In this example, we use a `.drift` file next to the database class named `tables.drift`: - - -{{ load_snippet('(full)','lib/snippets/drift_files/getting_started/tables.drift.excerpt.json') }} + !!! note "On that AS Category" @@ -38,15 +36,11 @@ database class named `tables.drift`: generate a different name with the `AS ` declaration at the end. - - Integrating drift files into the database is simple, they just need to be added to the `include` parameter of the `@DriftDatabase` annotation. The `tables` parameter can be omitted here, since there are no Dart-defined tables to be added to the database. - - -{{ load_snippet('(full)','lib/snippets/drift_files/getting_started/database.dart.excerpt.json') }} + To generate the `database.g.dart` file which contains the `_$AppDb` superclass, run `dart run build_runner build` on the command diff --git a/drift_website/content/sql_api/types.md b/drift_website/content/sql_api/types.md index 03fc7895a..541e3a318 100644 --- a/drift_website/content/sql_api/types.md +++ b/drift_website/content/sql_api/types.md @@ -1,12 +1,9 @@ --- - title: Custom SQL types description: Use custom SQL types in Drift files and Dart code. - --- - Drift's core library is written with sqlite3 as a primary target. This is reflected in the [SQL types][types] drift supports out of the box - these types supported by sqlite3 with a few additions that are handled in Dart. @@ -43,7 +40,7 @@ prepared statements and also be read from rows without manual conversions. In that case, a custom type class to implement `Duration` support for drift would be added: -{{ load_snippet('duration','lib/snippets/modular/custom_types/type.dart.excerpt.json') }} + This type defines the following things: @@ -61,9 +58,7 @@ This type defines the following things: To define a custom type on a Dart table, use the `customType` column builder method with the type: - - -{{ load_snippet('(full)','lib/snippets/modular/custom_types/table.dart.excerpt.json') }} + As the example shows, other column constraints like `clientDefault` can still be added to custom columns. You can even combine custom columns and type converters if needed. @@ -79,9 +74,7 @@ drift doesn't have a central register describing how to deal with custom type va In SQL, Drift's [inline Dart](drift_files.md#dart-interop) syntax may be used to define the custom type: - - -{{ load_snippet('(full)','lib/snippets/modular/custom_types/drift_table.drift.excerpt.json') }} + Please note that support for custom types in drift files is currently limited. For instance, custom types are not currently supported in `CAST` expressions. diff --git a/drift_website/lib/_style.scss b/drift_website/lib/_style.scss index 40b0f88b8..08ad21768 100644 --- a/drift_website/lib/_style.scss +++ b/drift_website/lib/_style.scss @@ -5,6 +5,7 @@ @use "src/styles/details"; @use "src/styles/header"; @use "src/styles/sidebar"; +@use "src/styles/constants" as c; @use "src/jaspr"; @@ -21,6 +22,8 @@ } .code-block { + margin: 1rem 0rem; + pre { margin-top: 0.25rem; border-radius: 0.375rem; @@ -35,4 +38,13 @@ white-space: pre; } } -} \ No newline at end of file + + .boolean { + color: var(--code-pink); + } +} + +.footnotes { + margin-top: 1rem; + border-top: 1px solid c.$color-separator; +} diff --git a/drift_website/lib/main.dart b/drift_website/lib/main.dart index 866f6ec51..ae2d77fa4 100644 --- a/drift_website/lib/main.dart +++ b/drift_website/lib/main.dart @@ -15,6 +15,7 @@ import 'package:watcher/watcher.dart'; // This file is generated automatically by Jaspr, do not remove or edit. import 'jaspr_options.dart'; +import 'src/common.dart'; import 'src/components/code.dart'; import 'src/components/collapsible.dart'; import 'src/components/header.dart'; @@ -61,7 +62,11 @@ void main() { }), ], templateEngine: MustacheTemplateEngine(), - parsers: [MarkdownParser()], + parsers: [ + MarkdownParser( + documentBuilder: (_) => driftMarkdownDocumentBuilder(), + ), + ], extensions: [ // Adds heading anchors to each heading. HeadingAnchorsExtension(), diff --git a/drift_website/lib/src/_jaspr.scss b/drift_website/lib/src/_jaspr.scss index 7c2ffeaeb..2a054fb07 100644 --- a/drift_website/lib/src/_jaspr.scss +++ b/drift_website/lib/src/_jaspr.scss @@ -424,10 +424,6 @@ .content :where(figcaption):not(:where([class~=not-content],[class~=not-content] *)) { color: var(--content-captions); } - .content :where(p):not(:where([class~=not-content],[class~=not-content] *)) { - margin-top: 1.25em; - margin-bottom: 1.25em; - } .content :where(blockquote):not(:where([class~=not-content],[class~=not-content] *)) { padding-left: 1em; margin-top: 1.6em; diff --git a/drift_website/lib/src/common.dart b/drift_website/lib/src/common.dart new file mode 100644 index 000000000..897ca2c40 --- /dev/null +++ b/drift_website/lib/src/common.dart @@ -0,0 +1,14 @@ +import 'package:jaspr_content/jaspr_content.dart'; +import 'package:markdown/markdown.dart' as md; + +import 'components/admonition.dart'; + +md.Document driftMarkdownDocumentBuilder() { + return md.Document( + blockSyntaxes: [ + ...MarkdownParser.defaultBlockSyntaxes, + const AdmonitionSyntax(), + ], + extensionSet: md.ExtensionSet.gitHubWeb, + ); +} diff --git a/drift_website/lib/src/components/admonition.dart b/drift_website/lib/src/components/admonition.dart new file mode 100644 index 000000000..7e0123be0 --- /dev/null +++ b/drift_website/lib/src/components/admonition.dart @@ -0,0 +1,90 @@ +import 'package:markdown/markdown.dart'; + +/// Parses blocks of the format used by Material for MkDocs +/// [Admonitions](https://squidfunk.github.io/mkdocs-material/reference/admonitions/). +final class AdmonitionSyntax extends BlockSyntax { + const AdmonitionSyntax(); + + @override + bool canParse(BlockParser parser) { + return pattern.hasMatch(parser.current.content); + } + + @override + Node? parse(BlockParser parser) { + final match = pattern.firstMatch(parser.current.content)!; + final collapsible = match.group(1)! == '???'; + final type = match.group(2)!; + final defaultTitle = + _defaultTitles[type] ?? + (throw ArgumentError.value( + type, + 'type', + 'Unknown type. Supported are: ${_defaultTitles.keys.join(', ')}', + )); + + final title = match.group(3); + parser.advance(); + + final childLines = parseChildLines(parser); + final children = BlockParser( + childLines, + parser.document, + ).parseLines(parentSyntax: this); + + if (collapsible) { + return Element('details', [ + Element('summary', [Text(title ?? defaultTitle)]), + ...children, + ])..attributes['class'] = type; + } else { + return Element('div', [ + Element('p', [Text(title ?? defaultTitle)]) + ..attributes['class'] = 'admonition-title', + ...children, + ])..attributes['class'] = 'admonition $type'; + } + } + + @override + List parseChildLines(BlockParser parser) { + final consumed = []; + + while (!parser.isDone) { + const prefix = ' '; + final content = parser.current.content; + + if (content.trim().isEmpty) { + consumed.add(Line(content)); + } else if (content.startsWith(prefix)) { + consumed.add(Line(content.substring(prefix.length))); + } else { + break; + } + + parser.advance(); + } + + return consumed; + } + + @override + RegExp get pattern => _pattern; + + static final _pattern = RegExp(r'(!!!|\?\?\?)\s+(\w+)(?:\s+"(.*)")?'); + + static const _defaultTitles = { + 'note': 'Note', + 'abstract': 'Abstract', + 'info': 'Info', + 'tip': 'Tip', + 'success': 'Success', + 'question': 'Question', + 'warning': 'Warning', + 'failure': 'Failure', + 'danger': 'Danger', + 'bug': 'Bug', + 'example': 'Example', + 'quote': 'Quote', + }; +} diff --git a/drift_website/lib/src/generated_snippets.dart b/drift_website/lib/src/generated_snippets.dart index 910c6c185..89a8357eb 100644 --- a/drift_website/lib/src/generated_snippets.dart +++ b/drift_website/lib/src/generated_snippets.dart @@ -5,6 +5,7 @@ const generatedSnippets = { '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/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',}, 'lib/src/snippets/custom_row_classes/named.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\n@UseRowClass(User, constructor: \'fromDb\')\nclass Users extends Table {\n // ...\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n DateTimeColumn get birthday => dateTime()();\n}\n\nclass User {\n final int id;\n final String name;\n final DateTime birthday;\n\n User.fromDb({required this.id, required this.name, required this.birthday});\n}\n','named': '@UseRowClass(User, constructor: \'fromDb\')\nclass Users extends Table {\n // ...\n}\n\nclass User {\n final int id;\n final String name;\n final DateTime birthday;\n\n User.fromDb({required this.id, required this.name, required this.birthday});\n}\n',}, 'lib/src/snippets/custom_row_classes/default.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\n@UseRowClass(User)\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n DateTimeColumn get birthday => dateTime()();\n}\n\nclass User {\n final int id;\n final String name;\n final DateTime birthday;\n\n User({required this.id, required this.name, required this.birthday});\n}\n\n@UseRowClass(Record) // Drift will use ({int id, String name})\nclass Categories extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n\ntypedef TodoItem = ({int id, String content, int author});\n\n@UseRowClass(TodoItem)\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get content => text()();\n IntColumn get author => integer().references(Users, #id)();\n}\n','start': '@UseRowClass(User)\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n DateTimeColumn get birthday => dateTime()();\n}\n\nclass User {\n final int id;\n final String name;\n final DateTime birthday;\n\n User({required this.id, required this.name, required this.birthday});\n}\n','record': '@UseRowClass(Record) // Drift will use ({int id, String name})\nclass Categories extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n','record-explicit': 'typedef TodoItem = ({int id, String content, int author});\n\n@UseRowClass(TodoItem)\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get content => text()();\n IntColumn get author => integer().references(Users, #id)();\n}\n',}, @@ -12,16 +13,23 @@ const generatedSnippets = { 'lib/src/snippets/modular/many_to_many/relational.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:rxdart/rxdart.dart\';\n\nimport \'shared.dart\' show BuyableItems;\nimport \'shared.drift.dart\';\n\nimport \'relational.drift.dart\';\n\ntypedef ShoppingCartWithItems = ({\n ShoppingCart cart,\n List<BuyableItem> items,\n});\n\nclass ShoppingCarts extends Table {\n IntColumn get id => integer().autoIncrement()();\n // we could also store some further information about the user creating\n // this cart etc.\n}\n\n@DataClassName(\'ShoppingCartEntry\')\nclass ShoppingCartEntries extends Table {\n // id of the cart that should contain this item.\n IntColumn get shoppingCart => integer().references(ShoppingCarts, #id)();\n // id of the item in this cart\n IntColumn get item => integer().references(BuyableItems, #id)();\n // again, we could store additional information like when the item was\n // added, an amount, etc.\n}\n\n@DriftDatabase(tables: [BuyableItems, ShoppingCarts, ShoppingCartEntries])\nclass RelationalDatabase extends \$RelationalDatabase {\n RelationalDatabase(super.e);\n\n @override\n int get schemaVersion => 1;\n\n Future<void> updateCart(ShoppingCartWithItems entry) {\n return transaction(() async {\n final cart = entry.cart;\n\n // first, we write the shopping cart\n await update(shoppingCarts).replace(cart);\n\n // we replace the entries of the cart, so first delete the old ones\n await (delete(shoppingCartEntries)\n ..where((entry) => entry.shoppingCart.equals(cart.id)))\n .go();\n\n // And write the new ones\n for (final item in entry.items) {\n await into(shoppingCartEntries)\n .insert(ShoppingCartEntry(shoppingCart: cart.id, item: item.id));\n }\n });\n }\n\n Future<ShoppingCartWithItems> createEmptyCart() async {\n final cart = await into(shoppingCarts)\n .insertReturning(const ShoppingCartsCompanion());\n // we set the items property to [] because we\'ve just created the cart - it\n // will be empty\n return (cart: cart, items: <BuyableItem>[]);\n }\n\n Stream<ShoppingCartWithItems> watchCart(int id) {\n // load information about the cart\n final cartQuery = select(shoppingCarts)\n ..where((cart) => cart.id.equals(id));\n\n // and also load information about the entries in this cart\n final contentQuery = select(shoppingCartEntries).join(\n [\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(shoppingCartEntries.item),\n ),\n ],\n )..where(shoppingCartEntries.shoppingCart.equals(id));\n\n final cartStream = cartQuery.watchSingle();\n\n final contentStream = contentQuery.watch().map((rows) {\n // we join the shoppingCartEntries with the buyableItems, but we\n // only care about the item here.\n return rows.map((row) => row.readTable(buyableItems)).toList();\n });\n\n // now, we can merge the two queries together in one stream\n return Rx.combineLatest2(cartStream, contentStream,\n (ShoppingCart cart, List<BuyableItem> items) {\n return (cart: cart, items: items);\n });\n }\n\n Stream<List<ShoppingCartWithItems>> watchAllCarts() {\n // start by watching all carts\n final cartStream = select(shoppingCarts).watch();\n\n return cartStream.switchMap((carts) {\n // this method is called whenever the list of carts changes. For each\n // cart, now we want to load all the items in it.\n // (we create a map from id to cart here just for performance reasons)\n final idToCart = {for (var cart in carts) cart.id: cart};\n final ids = idToCart.keys;\n\n // select all entries that are included in any cart that we found\n final entryQuery = select(shoppingCartEntries).join(\n [\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(shoppingCartEntries.item),\n )\n ],\n )..where(shoppingCartEntries.shoppingCart.isIn(ids));\n\n return entryQuery.watch().map((rows) {\n // Store the list of entries for each cart, again using maps for faster\n // lookups.\n final idToItems = <int, List<BuyableItem>>{};\n\n // for each entry (row) that is included in a cart, put it in the map\n // of items.\n for (final row in rows) {\n final item = row.readTable(buyableItems);\n final id = row.readTable(shoppingCartEntries).shoppingCart;\n\n idToItems.putIfAbsent(id, () => []).add(item);\n }\n\n // finally, all that\'s left is to merge the map of carts with the map of\n // entries\n return [\n for (var id in ids) (cart: idToCart[id]!, items: idToItems[id] ?? []),\n ];\n });\n });\n }\n}\n','cart_tables': 'class ShoppingCarts extends Table {\n IntColumn get id => integer().autoIncrement()();\n // we could also store some further information about the user creating\n // this cart etc.\n}\n\n@DataClassName(\'ShoppingCartEntry\')\nclass ShoppingCartEntries extends Table {\n // id of the cart that should contain this item.\n IntColumn get shoppingCart => integer().references(ShoppingCarts, #id)();\n // id of the item in this cart\n IntColumn get item => integer().references(BuyableItems, #id)();\n // again, we could store additional information like when the item was\n // added, an amount, etc.\n}\n','updateCart': ' Future<void> updateCart(ShoppingCartWithItems entry) {\n return transaction(() async {\n final cart = entry.cart;\n\n // first, we write the shopping cart\n await update(shoppingCarts).replace(cart);\n\n // we replace the entries of the cart, so first delete the old ones\n await (delete(shoppingCartEntries)\n ..where((entry) => entry.shoppingCart.equals(cart.id)))\n .go();\n\n // And write the new ones\n for (final item in entry.items) {\n await into(shoppingCartEntries)\n .insert(ShoppingCartEntry(shoppingCart: cart.id, item: item.id));\n }\n });\n }\n','createEmptyCart': ' Future<ShoppingCartWithItems> createEmptyCart() async {\n final cart = await into(shoppingCarts)\n .insertReturning(const ShoppingCartsCompanion());\n // we set the items property to [] because we\'ve just created the cart - it\n // will be empty\n return (cart: cart, items: <BuyableItem>[]);\n }\n','watchCart': ' Stream<ShoppingCartWithItems> watchCart(int id) {\n // load information about the cart\n final cartQuery = select(shoppingCarts)\n ..where((cart) => cart.id.equals(id));\n\n // and also load information about the entries in this cart\n final contentQuery = select(shoppingCartEntries).join(\n [\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(shoppingCartEntries.item),\n ),\n ],\n )..where(shoppingCartEntries.shoppingCart.equals(id));\n\n final cartStream = cartQuery.watchSingle();\n\n final contentStream = contentQuery.watch().map((rows) {\n // we join the shoppingCartEntries with the buyableItems, but we\n // only care about the item here.\n return rows.map((row) => row.readTable(buyableItems)).toList();\n });\n\n // now, we can merge the two queries together in one stream\n return Rx.combineLatest2(cartStream, contentStream,\n (ShoppingCart cart, List<BuyableItem> items) {\n return (cart: cart, items: items);\n });\n }\n','watchAllCarts': ' Stream<List<ShoppingCartWithItems>> watchAllCarts() {\n // start by watching all carts\n final cartStream = select(shoppingCarts).watch();\n\n return cartStream.switchMap((carts) {\n // this method is called whenever the list of carts changes. For each\n // cart, now we want to load all the items in it.\n // (we create a map from id to cart here just for performance reasons)\n final idToCart = {for (var cart in carts) cart.id: cart};\n final ids = idToCart.keys;\n\n // select all entries that are included in any cart that we found\n final entryQuery = select(shoppingCartEntries).join(\n [\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(shoppingCartEntries.item),\n )\n ],\n )..where(shoppingCartEntries.shoppingCart.isIn(ids));\n\n return entryQuery.watch().map((rows) {\n // Store the list of entries for each cart, again using maps for faster\n // lookups.\n final idToItems = <int, List<BuyableItem>>{};\n\n // for each entry (row) that is included in a cart, put it in the map\n // of items.\n for (final row in rows) {\n final item = row.readTable(buyableItems);\n final id = row.readTable(shoppingCartEntries).shoppingCart;\n\n idToItems.putIfAbsent(id, () => []).add(item);\n }\n\n // finally, all that\'s left is to merge the map of carts with the map of\n // entries\n return [\n for (var id in ids) (cart: idToCart[id]!, items: idToItems[id] ?? []),\n ];\n });\n });\n }\n',}, 'lib/src/snippets/modular/many_to_many/json.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/extensions/json1.dart\';\nimport \'package:json_annotation/json_annotation.dart\';\n\nimport \'json.drift.dart\';\nimport \'shared.dart\' show BuyableItems;\nimport \'shared.drift.dart\';\n\npart \'json.g.dart\';\n\ntypedef ShoppingCartWithItems = ({\n ShoppingCart cart,\n List<BuyableItem> items,\n});\n\n@DataClassName(\'ShoppingCart\')\nclass ShoppingCarts extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get entries => text().map(ShoppingCartEntries.converter)();\n\n // we could also store some further information about the user creating\n // this cart etc.\n}\n\n@JsonSerializable()\nclass ShoppingCartEntries {\n final List<int> items;\n\n ShoppingCartEntries({required this.items});\n\n factory ShoppingCartEntries.fromJson(Map<String, Object?> json) =>\n _\$ShoppingCartEntriesFromJson(json);\n\n Map<String, Object?> toJson() {\n return _\$ShoppingCartEntriesToJson(this);\n }\n\n static final converter = TypeConverter.json2(\n fromJson: (json) =>\n ShoppingCartEntries.fromJson(json as Map<String, Object?>),\n toJson: (entries) => entries.toJson(),\n );\n}\n\n\n@DriftDatabase(tables: [BuyableItems, ShoppingCarts])\nclass JsonBasedDatabase extends \$JsonBasedDatabase {\n JsonBasedDatabase(super.e);\n\n @override\n int get schemaVersion => 1;\n\n Future<ShoppingCartWithItems> createEmptyCart() async {\n final cart = await into(shoppingCarts)\n .insertReturning(const ShoppingCartsCompanion());\n\n // we set the items property to [] because we\'ve just created the cart - it\n // will be empty\n return (cart: cart, items: <BuyableItem>[]);\n }\n\n Future<void> updateCart(ShoppingCartWithItems entry) async {\n await update(shoppingCarts).replace(entry.cart.copyWith(\n entries: ShoppingCartEntries(items: [\n for (final item in entry.items) item.id,\n ])));\n }\n\n Stream<ShoppingCartWithItems> watchCart(int id) {\n final referencedItems = shoppingCarts.entries.jsonEach(this, r\'#\$.items\');\n\n final cartWithEntries = select(shoppingCarts).join(\n [\n // Join every referenced item from the json array\n innerJoin(referencedItems, const Constant(true), useColumns: false),\n // And use that to join the items\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(referencedItems.value.cast()),\n ),\n ],\n )..where(shoppingCarts.id.equals(id));\n\n return cartWithEntries.watch().map((rows) {\n late ShoppingCart cart;\n final entries = <BuyableItem>[];\n\n for (final row in rows) {\n cart = row.readTable(shoppingCarts);\n entries.add(row.readTable(buyableItems));\n }\n\n return (cart: cart, items: entries);\n });\n }\n\n Stream<List<ShoppingCartWithItems>> watchAllCarts() {\n final referencedItems = shoppingCarts.entries.jsonEach(this, r\'#\$.items\');\n\n final cartWithEntries = select(shoppingCarts).join(\n [\n // Join every referenced item from the json array\n innerJoin(referencedItems, const Constant(true), useColumns: false),\n // And use that to join the items\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(referencedItems.value.cast()),\n ),\n ],\n );\n\n return cartWithEntries.watch().map((rows) {\n final entriesByCart = <ShoppingCart, List<BuyableItem>>{};\n\n for (final row in rows) {\n final cart = row.readTable(shoppingCarts);\n final item = row.readTable(buyableItems);\n\n entriesByCart.putIfAbsent(cart, () => []).add(item);\n }\n\n return [\n for (final entry in entriesByCart.entries)\n (cart: entry.key, items: entry.value)\n ];\n });\n }\n}\n','tables': '@DataClassName(\'ShoppingCart\')\nclass ShoppingCarts extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get entries => text().map(ShoppingCartEntries.converter)();\n\n // we could also store some further information about the user creating\n // this cart etc.\n}\n\n@JsonSerializable()\nclass ShoppingCartEntries {\n final List<int> items;\n\n ShoppingCartEntries({required this.items});\n\n factory ShoppingCartEntries.fromJson(Map<String, Object?> json) =>\n _\$ShoppingCartEntriesFromJson(json);\n\n Map<String, Object?> toJson() {\n return _\$ShoppingCartEntriesToJson(this);\n }\n\n static final converter = TypeConverter.json2(\n fromJson: (json) =>\n ShoppingCartEntries.fromJson(json as Map<String, Object?>),\n toJson: (entries) => entries.toJson(),\n );\n}\n\n','createEmptyCart': ' Future<ShoppingCartWithItems> createEmptyCart() async {\n final cart = await into(shoppingCarts)\n .insertReturning(const ShoppingCartsCompanion());\n\n // we set the items property to [] because we\'ve just created the cart - it\n // will be empty\n return (cart: cart, items: <BuyableItem>[]);\n }\n','updateCart': ' Future<void> updateCart(ShoppingCartWithItems entry) async {\n await update(shoppingCarts).replace(entry.cart.copyWith(\n entries: ShoppingCartEntries(items: [\n for (final item in entry.items) item.id,\n ])));\n }\n','watchCart': ' Stream<ShoppingCartWithItems> watchCart(int id) {\n final referencedItems = shoppingCarts.entries.jsonEach(this, r\'#\$.items\');\n\n final cartWithEntries = select(shoppingCarts).join(\n [\n // Join every referenced item from the json array\n innerJoin(referencedItems, const Constant(true), useColumns: false),\n // And use that to join the items\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(referencedItems.value.cast()),\n ),\n ],\n )..where(shoppingCarts.id.equals(id));\n\n return cartWithEntries.watch().map((rows) {\n late ShoppingCart cart;\n final entries = <BuyableItem>[];\n\n for (final row in rows) {\n cart = row.readTable(shoppingCarts);\n entries.add(row.readTable(buyableItems));\n }\n\n return (cart: cart, items: entries);\n });\n }\n','watchAllCarts': ' Stream<List<ShoppingCartWithItems>> watchAllCarts() {\n final referencedItems = shoppingCarts.entries.jsonEach(this, r\'#\$.items\');\n\n final cartWithEntries = select(shoppingCarts).join(\n [\n // Join every referenced item from the json array\n innerJoin(referencedItems, const Constant(true), useColumns: false),\n // And use that to join the items\n innerJoin(\n buyableItems,\n buyableItems.id.equalsExp(referencedItems.value.cast()),\n ),\n ],\n );\n\n return cartWithEntries.watch().map((rows) {\n final entriesByCart = <ShoppingCart, List<BuyableItem>>{};\n\n for (final row in rows) {\n final cart = row.readTable(shoppingCarts);\n final item = row.readTable(buyableItems);\n\n entriesByCart.putIfAbsent(cart, () => []).add(item);\n }\n\n return [\n for (final entry in entriesByCart.entries)\n (cart: entry.key, items: entry.value)\n ];\n });\n }\n',}, 'lib/src/snippets/modular/custom_types/type.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nclass DurationType implements CustomSqlType<Duration> {\n const DurationType();\n\n @override\n String mapToSqlLiteral(Duration dartValue) {\n return "interval \'\${dartValue.inMicroseconds} microseconds\'";\n }\n\n @override\n Object mapToSqlParameter(Duration dartValue) => dartValue;\n\n @override\n Duration read(Object fromSql) => fromSql as Duration;\n\n @override\n String sqlTypeName(GenerationContext context) => \'interval\';\n}\n\nclass _FallbackDurationType implements CustomSqlType<Duration> {\n const _FallbackDurationType();\n\n @override\n String mapToSqlLiteral(Duration dartValue) {\n return dartValue.inMicroseconds.toString();\n }\n\n @override\n Object mapToSqlParameter(Duration dartValue) {\n return dartValue.inMicroseconds;\n }\n\n @override\n Duration read(Object fromSql) {\n return Duration(microseconds: fromSql as int);\n }\n\n @override\n String sqlTypeName(GenerationContext context) {\n return \'integer\';\n }\n}\n\nconst durationType = DialectAwareSqlType<Duration>.via(\n fallback: _FallbackDurationType(),\n overrides: {\n SqlDialect.postgres: DurationType(),\n },\n);\n','duration': 'import \'package:drift/drift.dart\';\n\nclass DurationType implements CustomSqlType<Duration> {\n const DurationType();\n\n @override\n String mapToSqlLiteral(Duration dartValue) {\n return "interval \'\${dartValue.inMicroseconds} microseconds\'";\n }\n\n @override\n Object mapToSqlParameter(Duration dartValue) => dartValue;\n\n @override\n Duration read(Object fromSql) => fromSql as Duration;\n\n @override\n String sqlTypeName(GenerationContext context) => \'interval\';\n}\n','fallback': 'class _FallbackDurationType implements CustomSqlType<Duration> {\n const _FallbackDurationType();\n\n @override\n String mapToSqlLiteral(Duration dartValue) {\n return dartValue.inMicroseconds.toString();\n }\n\n @override\n Object mapToSqlParameter(Duration dartValue) {\n return dartValue.inMicroseconds;\n }\n\n @override\n Duration read(Object fromSql) {\n return Duration(microseconds: fromSql as int);\n }\n\n @override\n String sqlTypeName(GenerationContext context) {\n return \'integer\';\n }\n}\n\nconst durationType = DialectAwareSqlType<Duration>.via(\n fallback: _FallbackDurationType(),\n overrides: {\n SqlDialect.postgres: DurationType(),\n },\n);\n',}, +'lib/src/snippets/modular/custom_types/table.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'type.dart\';\n\nclass PeriodicReminders extends Table {\n IntColumn get id => integer().autoIncrement()();\n Column<Duration> get frequency => customType(const DurationType())\n .clientDefault(() => Duration(minutes: 15))();\n TextColumn get reminder => text()();\n}\n',}, +'lib/src/snippets/modular/custom_types/drift_table.drift.snippet.json': {'(full)': 'import \'type.dart\';\n\nCREATE TABLE periodic_reminders (\n id INTEGER NOT NULL PRIMARY KEY,\n frequency `const DurationType()` NOT NULL,\n reminder TEXT NOT NULL\n);\n',}, 'lib/src/snippets/modular/drift/example.drift.snippet.json': {'(full)': 'CREATE TABLE todos (\n id INT NOT NULL PRIMARY KEY AUTOINCREMENT,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n category INTEGER REFERENCES categories(id)\n);\n\nCREATE TABLE categories (\n id INT NOT NULL PRIMARY KEY AUTOINCREMENT,\n description TEXT NOT NULL\n) AS Category;\n\nfilterTodos: SELECT * FROM todos WHERE \$predicate;\ngetTodos (\$predicate = TRUE): SELECT * FROM todos WHERE \$predicate;\n','filterTodos': 'filterTodos: SELECT * FROM todos WHERE \$predicate;\n','getTodos': 'getTodos (\$predicate = TRUE): SELECT * FROM todos WHERE \$predicate;\n',}, 'lib/src/snippets/modular/drift/dart_example.dart.snippet.json': {'(full)': 'import \'example.drift.dart\';\n\nclass DartExample extends ExampleDrift {\n DartExample(super.attachedDatabase);\n\n Stream<List<Todo>> watchInCategory(int category) {\n return filterTodos((todos) => todos.category.equals(category)).watch();\n }\n}\n','watchInCategory': ' Stream<List<Todo>> watchInCategory(int category) {\n return filterTodos((todos) => todos.category.equals(category)).watch();\n }\n',}, 'lib/src/snippets/modular/drift/with_existing.drift.snippet.json': {'(full)': 'import \'row_class.dart\'; --import for where the row class is defined\n\nCREATE TABLE users (\n id INTEGER NOT NULL PRIMARY KEY,\n name TEXT NOT NULL\n) WITH User; -- This tells drift to use the existing Dart class\n\n-- table to demonstrate a more complex select query below.\n-- also, remember to add the import for `UserWithFriends` to your drift file.\nCREATE TABLE friends (\n user_a INTEGER NOT NULL REFERENCES users(id),\n user_b INTEGER NOT NULL REFERENCES users(id),\n PRIMARY KEY (user_a, user_b)\n);\n\nallFriendsOf WITH UserWithFriends: SELECT users.** AS user, LIST(\n SELECT * FROM users a INNER JOIN friends ON user_a = a.id WHERE user_b = users.id OR user_a = users.id\n) AS friends FROM users WHERE id = :id;\n','users': 'import \'row_class.dart\'; --import for where the row class is defined\n\nCREATE TABLE users (\n id INTEGER NOT NULL PRIMARY KEY,\n name TEXT NOT NULL\n) WITH User; -- This tells drift to use the existing Dart class\n','friends': '-- table to demonstrate a more complex select query below.\n-- also, remember to add the import for `UserWithFriends` to your drift file.\nCREATE TABLE friends (\n user_a INTEGER NOT NULL REFERENCES users(id),\n user_b INTEGER NOT NULL REFERENCES users(id),\n PRIMARY KEY (user_a, user_b)\n);\n\nallFriendsOf WITH UserWithFriends: SELECT users.** AS user, LIST(\n SELECT * FROM users a INNER JOIN friends ON user_a = a.id WHERE user_b = users.id OR user_a = users.id\n) AS friends FROM users WHERE id = :id;\n',}, 'lib/src/snippets/modular/drift/row_class.dart.snippet.json': {'(full)': 'class User {\n final int id;\n final String name;\n\n User(this.id, this.name);\n}\n\nclass UserWithFriends {\n final User user;\n final List<User> friends;\n\n UserWithFriends(this.user, {this.friends = const []});\n}\n','user': 'class User {\n final int id;\n final String name;\n\n User(this.id, this.name);\n}\n','userwithfriends': 'class UserWithFriends {\n final User user;\n final List<User> friends;\n\n UserWithFriends(this.user, {this.friends = const []});\n}\n',}, +'lib/src/snippets/modular/aliases.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'aliases.drift.dart\';\n\nclass GeoPoints extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n TextColumn get latitude => text()();\n TextColumn get longitude => text()();\n}\n\nclass Routes extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n\n // contains the id for the start and destination geopoint.\n IntColumn get start => integer()();\n IntColumn get destination => integer()();\n}\n\n\nclass RouteWithPoints {\n final Route route;\n final GeoPoint start;\n final GeoPoint destination;\n\n RouteWithPoints({\n required this.route,\n required this.start,\n required this.destination,\n });\n}\n\nextension FakeDatabase on GeneratedDatabase {\n \$GeoPointsTable get geoPoints => throw \'\';\n \$RoutesTable get routes => throw \'\';\n\n // inside the database class:\n Future<List<RouteWithPoints>> loadRoutes() async {\n // create aliases for the geoPoints table so that we can reference it twice\n final start = alias(geoPoints, \'s\');\n final destination = alias(geoPoints, \'d\');\n\n final rows = await select(routes).join([\n innerJoin(start, start.id.equalsExp(routes.start)),\n innerJoin(destination, destination.id.equalsExp(routes.destination)),\n ]).get();\n\n return rows.map((resultRow) {\n return RouteWithPoints(\n route: resultRow.readTable(routes),\n start: resultRow.readTable(start),\n destination: resultRow.readTable(destination),\n );\n }).toList();\n }\n\n}\n','tables': 'class GeoPoints extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n TextColumn get latitude => text()();\n TextColumn get longitude => text()();\n}\n\nclass Routes extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n\n // contains the id for the start and destination geopoint.\n IntColumn get start => integer()();\n IntColumn get destination => integer()();\n}\n\n','query': 'class RouteWithPoints {\n final Route route;\n final GeoPoint start;\n final GeoPoint destination;\n\n RouteWithPoints({\n required this.route,\n required this.start,\n required this.destination,\n });\n}\n\n // inside the database class:\n Future<List<RouteWithPoints>> loadRoutes() async {\n // create aliases for the geoPoints table so that we can reference it twice\n final start = alias(geoPoints, \'s\');\n final destination = alias(geoPoints, \'d\');\n\n final rows = await select(routes).join([\n innerJoin(start, start.id.equalsExp(routes.start)),\n innerJoin(destination, destination.id.equalsExp(routes.destination)),\n ]).get();\n\n return rows.map((resultRow) {\n return RouteWithPoints(\n route: resultRow.readTable(routes),\n start: resultRow.readTable(start),\n destination: resultRow.readTable(destination),\n );\n }).toList();\n }\n\n',}, 'lib/src/snippets/modular/schema_inspection.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'drift/example.drift.dart\';\n\nextension FindById<Table extends HasResultSet, Row>\n on ResultSetImplementation<Table, Row> {\n Selectable<Row> findById(int id) {\n return select()\n ..where((row) {\n final idColumn = columnsByName[\'id\'];\n\n if (idColumn == null) {\n throw ArgumentError.value(\n this, \'this\', \'Must be a table with an id column\');\n }\n\n if (idColumn.type != DriftSqlType.int) {\n throw ArgumentError(\'Column `id` is not an integer\');\n }\n\n return idColumn.equals(id);\n });\n }\n}\n\nextension UpdateTitle on DatabaseConnectionUser {\n Future<Row?> updateTitle<T extends TableInfo<Table, Row>, Row>(\n T table, int id, String newTitle) async {\n final columnsByName = table.columnsByName;\n final stmt = update(table)\n ..where((tbl) {\n final idColumn = columnsByName[\'id\'];\n\n if (idColumn == null) {\n throw ArgumentError.value(\n this, \'this\', \'Must be a table with an id column\');\n }\n\n if (idColumn.type != DriftSqlType.int) {\n throw ArgumentError(\'Column `id` is not an integer\');\n }\n\n return idColumn.equals(id);\n });\n\n final rows = await stmt.writeReturning(RawValuesInsertable({\n \'title\': Variable<String>(newTitle),\n }));\n\n return rows.singleOrNull;\n }\n}\n\nextension FindTodoEntryById on GeneratedDatabase {\n Todos get todos => Todos(this);\n\n Selectable<Todo> findTodoEntryById(int id) {\n return select(todos)..where((row) => row.id.equals(id));\n }\n\n Future<Todo?> updateTodoTitle(int id, String newTitle) {\n return updateTitle(todos, id, newTitle);\n }\n}\n','findById': 'extension FindById<Table extends HasResultSet, Row>\n on ResultSetImplementation<Table, Row> {\n Selectable<Row> findById(int id) {\n return select()\n ..where((row) {\n final idColumn = columnsByName[\'id\'];\n\n if (idColumn == null) {\n throw ArgumentError.value(\n this, \'this\', \'Must be a table with an id column\');\n }\n\n if (idColumn.type != DriftSqlType.int) {\n throw ArgumentError(\'Column `id` is not an integer\');\n }\n\n return idColumn.equals(id);\n });\n }\n}\n','updateTitle': 'extension UpdateTitle on DatabaseConnectionUser {\n Future<Row?> updateTitle<T extends TableInfo<Table, Row>, Row>(\n T table, int id, String newTitle) async {\n final columnsByName = table.columnsByName;\n final stmt = update(table)\n ..where((tbl) {\n final idColumn = columnsByName[\'id\'];\n\n if (idColumn == null) {\n throw ArgumentError.value(\n this, \'this\', \'Must be a table with an id column\');\n }\n\n if (idColumn.type != DriftSqlType.int) {\n throw ArgumentError(\'Column `id` is not an integer\');\n }\n\n return idColumn.equals(id);\n });\n\n final rows = await stmt.writeReturning(RawValuesInsertable({\n \'title\': Variable<String>(newTitle),\n }));\n\n return rows.singleOrNull;\n }\n}\n','findTodoEntryById': ' Selectable<Todo> findTodoEntryById(int id) {\n return select(todos)..where((row) => row.id.equals(id));\n }\n','updateTodo': ' Future<Todo?> updateTodoTitle(int id, String newTitle) {\n return updateTitle(todos, id, newTitle);\n }\n',}, 'lib/src/snippets/modular/upserts.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/internal/modular.dart\';\n\nimport \'upserts.drift.dart\';\n\nclass Words extends Table {\n TextColumn get word => text()();\n IntColumn get usages => integer().withDefault(const Constant(1))();\n\n @override\n Set<Column> get primaryKey => {word};\n}\n\nclass MatchResults extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get teamA => text()();\n TextColumn get teamB => text()();\n BoolColumn get teamAWon => boolean()();\n\n @override\n List<Set<Column<Object>>>? get uniqueKeys => [\n {teamA, teamB}\n ];\n}\n\nextension DocumentationSnippets on ModularAccessor {\n \$WordsTable get words => throw \'stub\';\n \$MatchResultsTable get matches => throw \'stub\';\n\n Future<void> trackWord(String word) {\n return into(words).insert(\n WordsCompanion.insert(word: word),\n onConflict: DoUpdate(\n (old) => WordsCompanion.custom(usages: old.usages + Constant(1))),\n );\n }\n\n Future<void> insertMatch(String teamA, String teamB, bool teamAWon) {\n final data = MatchResultsCompanion.insert(\n teamA: teamA, teamB: teamB, teamAWon: teamAWon);\n\n return into(matches).insert(data,\n onConflict:\n DoUpdate((old) => data, target: [matches.teamA, matches.teamB]));\n }\n}\n','words-table': 'class Words extends Table {\n TextColumn get word => text()();\n IntColumn get usages => integer().withDefault(const Constant(1))();\n\n @override\n Set<Column> get primaryKey => {word};\n}\n','upsert-target': 'class MatchResults extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get teamA => text()();\n TextColumn get teamB => text()();\n BoolColumn get teamAWon => boolean()();\n\n @override\n List<Set<Column<Object>>>? get uniqueKeys => [\n {teamA, teamB}\n ];\n}\n Future<void> insertMatch(String teamA, String teamB, bool teamAWon) {\n final data = MatchResultsCompanion.insert(\n teamA: teamA, teamB: teamB, teamAWon: teamAWon);\n\n return into(matches).insert(data,\n onConflict:\n DoUpdate((old) => data, target: [matches.teamA, matches.teamB]));\n }\n','track-word': ' Future<void> trackWord(String word) {\n return into(words).insert(\n WordsCompanion.insert(word: word),\n onConflict: DoUpdate(\n (old) => WordsCompanion.custom(usages: old.usages + Constant(1))),\n );\n }\n',}, +'lib/src/snippets/drift_files/tables.drift.snippet.json': {'(full)': 'CREATE TABLE todos (\n id INT NOT NULL PRIMARY KEY AUTOINCREMENT,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n category INTEGER REFERENCES categories(id)\n);\n\nCREATE TABLE categories (\n id INT NOT NULL PRIMARY KEY AUTOINCREMENT,\n description TEXT NOT NULL\n) AS Category; -- the AS xyz after the table defines the data class name\n\n-- You can also create an index or triggers with drift files\nCREATE INDEX categories_description ON categories(description);\n\n-- we can put named SQL queries in here as well:\ncreateEntry: INSERT INTO todos (title, content) VALUES (:title, :content);\ndeleteById: DELETE FROM todos WHERE id = :id;\nallTodos: SELECT * FROM todos;\n',}, 'lib/src/snippets/drift_files/custom_queries.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'../_shared/todo_tables.dart\';\nimport \'../_shared/todo_tables.drift.dart\';\nimport \'custom_queries.drift.dart\';\n\nclass CategoryWithCount {\n final Category category;\n final int count; // amount of entries in this category\n\n CategoryWithCount({required this.category, required this.count});\n}\n\n\n@DriftDatabase(\n tables: [TodoItems, Categories],\n queries: {\n \'categoriesWithCount\': \'SELECT *, \'\n \'(SELECT COUNT(*) FROM todo_items WHERE category = c.id) AS "amount" \'\n \'FROM categories c;\'\n },\n)\nclass MyDatabase extends \$MyDatabase {\n // rest of class stays the same\n @override\n int get schemaVersion => 1;\n\n MyDatabase(super.e);\n\n Stream<int> amountOfTodosInCategory(int id) {\n return customSelect(\n \'SELECT COUNT(*) AS c FROM todo_items WHERE category = ?\',\n variables: [Variable.withInt(id)],\n readsFrom: {todoItems},\n ).map((row) => row.read<int>(\'c\')).watchSingle();\n }\n\n Future<void> useGeneratedQuery() async {\n // The generated query can be run once as a future:\n await categoriesWithCount().get();\n\n // Or multiple times as a stream\n await for (final snapshot in categoriesWithCount().watch()) {\n print(\'Found \${snapshot.length} category results\');\n }\n }\n\n // then, in the database class:\n Stream<List<CategoryWithCount>> allCategoriesWithCount() {\n // select all categories and load how many associated entries there are for\n // each category\n return customSelect(\n \'SELECT *, (SELECT COUNT(*) FROM todos WHERE category = c.id) AS "amount"\'\n \' FROM categories c;\',\n // used for the stream: the stream will update when either table changes\n readsFrom: {todoItems, categories},\n ).watch().map((rows) {\n // we get list of rows here. We just have to turn the raw data from the\n // row into a CategoryWithCount instnace. As we defined the Category table\n // earlier, drift knows how to parse a category. The only thing left to do\n // manually is extracting the amount.\n return rows\n .map((row) => CategoryWithCount(\n category: categories.map(row.data),\n count: row.read<int>(\'amount\'),\n ))\n .toList();\n });\n }\n\n\n}\n','manual': 'class CategoryWithCount {\n final Category category;\n final int count; // amount of entries in this category\n\n CategoryWithCount({required this.category, required this.count});\n}\n\n // then, in the database class:\n Stream<List<CategoryWithCount>> allCategoriesWithCount() {\n // select all categories and load how many associated entries there are for\n // each category\n return customSelect(\n \'SELECT *, (SELECT COUNT(*) FROM todos WHERE category = c.id) AS "amount"\'\n \' FROM categories c;\',\n // used for the stream: the stream will update when either table changes\n readsFrom: {todoItems, categories},\n ).watch().map((rows) {\n // we get list of rows here. We just have to turn the raw data from the\n // row into a CategoryWithCount instnace. As we defined the Category table\n // earlier, drift knows how to parse a category. The only thing left to do\n // manually is extracting the amount.\n return rows\n .map((row) => CategoryWithCount(\n category: categories.map(row.data),\n count: row.read<int>(\'amount\'),\n ))\n .toList();\n });\n }\n\n','setup': '@DriftDatabase(\n tables: [TodoItems, Categories],\n queries: {\n \'categoriesWithCount\': \'SELECT *, \'\n \'(SELECT COUNT(*) FROM todo_items WHERE category = c.id) AS "amount" \'\n \'FROM categories c;\'\n },\n)\nclass MyDatabase extends \$MyDatabase {\n // rest of class stays the same\n}\n','amountOfTodosInCategory': ' Stream<int> amountOfTodosInCategory(int id) {\n return customSelect(\n \'SELECT COUNT(*) AS c FROM todo_items WHERE category = ?\',\n variables: [Variable.withInt(id)],\n readsFrom: {todoItems},\n ).map((row) => row.read<int>(\'c\')).watchSingle();\n }\n','run': ' Future<void> useGeneratedQuery() async {\n // The generated query can be run once as a future:\n await categoriesWithCount().get();\n\n // Or multiple times as a stream\n await for (final snapshot in categoriesWithCount().watch()) {\n print(\'Found \${snapshot.length} category results\');\n }\n }\n\n',}, 'lib/src/snippets/drift_files/nested.drift.snippet.json': {'(full)': 'CREATE TABLE coordinates (\n id INTEGER NOT NULL PRIMARY KEY,\n lat REAL NOT NULL,\n long REAL NOT NULL\n);\n\nCREATE TABLE saved_routes (\n id INTEGER NOT NULL PRIMARY KEY,\n name TEXT NOT NULL,\n "from" INTEGER NOT NULL REFERENCES coordinates (id),\n "to" INTEGER NOT NULL REFERENCES coordinates (id)\n);\n\nCREATE TABLE route_points (\n route INTEGER NOT NULL REFERENCES saved_routes (id),\n point INTEGER NOT NULL REFERENCES coordinates (id),\n index_on_route INTEGER,\n PRIMARY KEY (route, point)\n);\n\nroutesWithPoints: SELECT r.id, r.name, f.*, t.* FROM saved_routes r\n INNER JOIN coordinates f ON f.id = r."from"\n INNER JOIN coordinates t ON t.id = r."to";\nroutesWithNestedPoints: SELECT r.id, r.name, f.** AS "from", t.** AS "to" FROM saved_routes r\n INNER JOIN coordinates f ON f.id = r."from"\n INNER JOIN coordinates t ON t.id = r."to";\nrouteWithPoints: SELECT\n route.**,\n LIST(SELECT coordinates.* FROM route_points\n INNER JOIN coordinates ON id = point\n WHERE route = route.id\n ORDER BY index_on_route\n ) AS points\n FROM saved_routes route;\n','overview': 'CREATE TABLE coordinates (\n id INTEGER NOT NULL PRIMARY KEY,\n lat REAL NOT NULL,\n long REAL NOT NULL\n);\n\nCREATE TABLE saved_routes (\n id INTEGER NOT NULL PRIMARY KEY,\n name TEXT NOT NULL,\n "from" INTEGER NOT NULL REFERENCES coordinates (id),\n "to" INTEGER NOT NULL REFERENCES coordinates (id)\n);\n\nroutesWithPoints: SELECT r.id, r.name, f.*, t.* FROM saved_routes r\n INNER JOIN coordinates f ON f.id = r."from"\n INNER JOIN coordinates t ON t.id = r."to";\n','route_points': 'CREATE TABLE route_points (\n route INTEGER NOT NULL REFERENCES saved_routes (id),\n point INTEGER NOT NULL REFERENCES coordinates (id),\n index_on_route INTEGER,\n PRIMARY KEY (route, point)\n);\n','nested': 'routesWithNestedPoints: SELECT r.id, r.name, f.** AS "from", t.** AS "to" FROM saved_routes r\n INNER JOIN coordinates f ON f.id = r."from"\n INNER JOIN coordinates t ON t.id = r."to";\n','list': 'routeWithPoints: SELECT\n route.**,\n LIST(SELECT coordinates.* FROM route_points\n INNER JOIN coordinates ON id = point\n WHERE route = route.id\n ORDER BY index_on_route\n ) AS points\n FROM saved_routes route;\n',}, 'lib/src/snippets/drift_files/database.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\n\npart \'database.g.dart\';\n\n@DriftDatabase(\n include: {\'tables.drift\'},\n)\nclass MyDb extends _\$MyDb {\n // This example creates a simple in-memory database (without actual\n // persistence).\n // To store data, see the database setups from other "Getting started" guides.\n MyDb() : super(NativeDatabase.memory());\n\n @override\n int get schemaVersion => 1;\n}\n\nextension MoreSnippets on MyDb {\n Future<void> insert(TodosCompanion companion) async {\n await into(todos).insert(companion);\n }\n}\n','overview': 'import \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\n\npart \'database.g.dart\';\n\n@DriftDatabase(\n include: {\'tables.drift\'},\n)\nclass MyDb extends _\$MyDb {\n // This example creates a simple in-memory database (without actual\n // persistence).\n // To store data, see the database setups from other "Getting started" guides.\n MyDb() : super(NativeDatabase.memory());\n\n @override\n int get schemaVersion => 1;\n}\n','dart_interop_insert': ' Future<void> insert(TodosCompanion companion) async {\n await into(todos).insert(companion);\n }\n',}, 'lib/src/snippets/drift_files/small_snippets.drift.snippet.json': {'(full)': 'import \'tables.drift\'; -- single quotes are required for imports\n\nmyQuery(:variable AS TEXT): SELECT :variable;\nmyNullableQuery(:variable AS TEXT OR NULL): SELECT :variable;\nmyRequiredQuery(REQUIRED :variable AS TEXT OR NULL): SELECT :variable;\nentriesWithId: SELECT * FROM todos WHERE id IN ?;\n_filterTodos: SELECT * FROM todos WHERE \$predicate;\n','import': 'import \'tables.drift\'; -- single quotes are required for imports\n','q1': 'myQuery(:variable AS TEXT): SELECT :variable;\n','q2': 'myNullableQuery(:variable AS TEXT OR NULL): SELECT :variable;\n','q3': 'myRequiredQuery(REQUIRED :variable AS TEXT OR NULL): SELECT :variable;\n','entries': 'entriesWithId: SELECT * FROM todos WHERE id IN ?;\n','filter': '_filterTodos: SELECT * FROM todos WHERE \$predicate;\n',}, +'lib/src/snippets/drift_files/getting_started/tables.drift.snippet.json': {'(full)': '-- this is the tables.drift file\nCREATE TABLE todos (\n id INT NOT NULL PRIMARY KEY AUTOINCREMENT,\n title TEXT,\n body TEXT,\n category INT REFERENCES categories (id)\n);\n\nCREATE TABLE categories (\n id INT NOT NULL PRIMARY KEY AUTOINCREMENT,\n description TEXT\n) AS Category; -- see the explanation on "AS Category" below\n\n/* after declaring your tables, you can put queries in here. Just\n write the name of the query, a colon (:) and the SQL: */\ntodosInCategory: SELECT * FROM todos WHERE category = ?;\n\n/* Here\'s a more complex query: It counts the amount of entries per\ncategory, including those entries which aren\'t in any category at all. */\ncountEntries:\n SELECT\n c.description,\n (SELECT COUNT(*) FROM todos WHERE category = c.id) AS amount\n FROM categories c\n UNION ALL\n SELECT null, (SELECT COUNT(*) FROM todos WHERE category IS NULL);\n',}, +'lib/src/snippets/drift_files/getting_started/database.dart.snippet.json': {'(full)': 'import \'dart:io\';\n\nimport \'package:drift/drift.dart\';\n// These imports are used to open the database\nimport \'package:drift/native.dart\';\nimport \'package:path_provider/path_provider.dart\';\nimport \'package:path/path.dart\' as p;\n\npart \'database.g.dart\';\n\n@DriftDatabase(\n // relative import for the drift file. Drift also supports `package:`\n // imports\n include: {\'tables.drift\'},\n)\nclass AppDb extends _\$AppDb {\n AppDb() : super(_openConnection());\n\n @override\n int get schemaVersion => 1;\n}\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 return NativeDatabase.createInBackground(file);\n });\n}\n',}, +'lib/src/snippets/dart_api/old_name.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nclass EnabledCategories extends Table {\n IntColumn get parentCategory => integer()();\n}\n',}, 'lib/src/snippets/dart_api/select.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'../_shared/todo_tables.dart\';\nimport \'../_shared/todo_tables.drift.dart\';\n\n// We define a data class to contain both a todo entry and the associated\n// category.\nclass EntryWithCategory {\n EntryWithCategory(this.entry, this.category);\n\n // The classes are generated by drift for each of the tables involved in the\n // join.\n final TodoItem entry;\n final Category? category;\n}\n\n\nextension SelectExamples on CanUseCommonTables {\n Future<List<TodoItem>> limitTodos(int limit, {int? offset}) {\n return (select(todoItems)..limit(limit, offset: offset)).get();\n }\n\n Future<List<TodoItem>> sortEntriesAlphabetically() {\n return (select(todoItems)\n ..orderBy([(t) => OrderingTerm(expression: t.title)]))\n .get();\n }\n\n Stream<TodoItem> entryById(int id) {\n return (select(todoItems)..where((t) => t.id.equals(id))).watchSingle();\n }\n\n Stream<List<String>> contentWithLongTitles() {\n final query = select(todoItems)\n ..where((t) => t.title.length.isBiggerOrEqualValue(16));\n\n return query.map((row) => row.content).watch();\n }\n\n // Exposes `get` and `watch`\n MultiSelectable<TodoItem> pageOfTodos(int page, {int pageSize = 10}) {\n return select(todoItems)..limit(pageSize, offset: page);\n }\n\n // Exposes `getSingle` and `watchSingle`\n SingleSelectable<TodoItem> selectableEntryById(int id) {\n return select(todoItems)..where((t) => t.id.equals(id));\n }\n\n // Exposes `getSingleOrNull` and `watchSingleOrNull`\n SingleOrNullSelectable<TodoItem> entryFromExternalLink(int id) {\n return select(todoItems)..where((t) => t.id.equals(id));\n }\n\n // in the database class, we can then load the category for each entry\n Stream<List<EntryWithCategory>> entriesWithCategory() {\n final query = select(todoItems).join([\n leftOuterJoin(categories, categories.id.equalsExp(todoItems.category)),\n ]);\n\n return query.watch().map((rows) {\n return rows.map((row) {\n return EntryWithCategory(\n row.readTable(todoItems),\n row.readTableOrNull(categories),\n );\n }).toList();\n });\n }\n\n /// Searches for todo entries in the same category as the ones having\n /// `titleQuery` in their titles.\n Future<List<TodoItem>> otherTodosInSameCategory(String titleQuery) async {\n // Since we\'re adding the same table twice (once to filter for the title,\n // and once to find other todos in same category), we need a way to\n // distinguish the two tables. So, we\'re giving one of them a special name:\n final otherTodos = alias(todoItems, \'inCategory\');\n\n final query = select(otherTodos).join([\n // In joins, `useColumns: false` tells drift to not add columns of the\n // joined table to the result set. This is useful here, since we only join\n // the tables so that we can refer to them in the where clause.\n innerJoin(categories, categories.id.equalsExp(otherTodos.category),\n useColumns: false),\n innerJoin(todoItems, todoItems.category.equalsExp(categories.id),\n useColumns: false),\n ])\n ..where(todoItems.title.contains(titleQuery));\n\n return query.map((row) => row.readTable(otherTodos)).get();\n }\n\n Future<void> countTodosInCategories() async {\n final amountOfTodos = todoItems.id.count();\n\n final query = select(categories).join([\n innerJoin(\n todoItems,\n todoItems.category.equalsExp(categories.id),\n useColumns: false,\n )\n ]);\n query\n ..addColumns([amountOfTodos])\n ..groupBy([categories.id]);\n\n final result = await query.get();\n\n for (final row in result) {\n print(\'there are \${row.read(amountOfTodos)} entries in\'\n \'\${row.readTable(categories)}\');\n }\n }\n\n Stream<double> averageItemLength() {\n final avgLength = todoItems.content.length.avg();\n final query = selectOnly(todoItems)..addColumns([avgLength]);\n\n return query.map((row) => row.read(avgLength)!).watchSingle();\n }\n\n Future<void> createCategoryForUnassignedTodoEntries() async {\n final newDescription = Variable<String>(\'category for: \') + todoItems.title;\n final query = selectOnly(todoItems)\n ..where(todoItems.category.isNull())\n ..addColumns([newDescription]);\n\n await into(categories).insertFromSelect(query, columns: {\n categories.name: newDescription,\n });\n }\n\n Future<List<(Category, int)>> amountOfLengthyTodoItemsPerCategory() async {\n final longestTodos = Subquery(\n select(todoItems)\n ..orderBy([(row) => OrderingTerm.desc(row.title.length)])\n ..limit(10),\n \'s\',\n );\n\n // In the main query, we want to count how many entries in longestTodos were\n // found for each category. But we can\'t access todos.title directly since\n // we\'re not selecting from `todos`. Instead, we\'ll use Subquery.ref to read\n // from a column in a subquery.\n final itemCount = longestTodos.ref(todoItems.title).count();\n final query = select(categories).join(\n [\n innerJoin(\n longestTodos,\n // Again using .ref() here to access the category in the outer select\n // statement.\n longestTodos.ref(todoItems.category).equalsExp(categories.id),\n useColumns: false,\n )\n ],\n )\n ..addColumns([itemCount])\n ..groupBy([categories.id]);\n\n final rows = await query.get();\n\n return [\n for (final row in rows) (row.readTable(categories), row.read(itemCount)!),\n ];\n }\n\n Future<List<(TodoItem, bool)>> loadEntries() {\n // assume that an entry is important if it has the string "important" somewhere in its content\n final isImportant = todoItems.content.like(\'%important%\');\n\n return select(todoItems).addColumns([isImportant]).map((row) {\n final entry = row.readTable(todoItems);\n final entryIsImportant = row.read(isImportant)!;\n\n return (entry, entryIsImportant);\n }).get();\n }\n\n Future<bool> hasTodoItem() async {\n final todoItemExists = existsQuery(select(todoItems));\n final row = await selectExpressions([todoItemExists]).getSingle();\n return row.read(todoItemExists)!;\n }\n\n Future<List<(String?, int)>> todoItemsInCategory() async {\n final countWithCategory = subqueryExpression<int>(selectOnly(todoItems)\n ..addColumns([countAll()])\n ..where(todoItems.category.equalsExp(categories.id)));\n\n final countWithoutCategory = subqueryExpression<int>(selectOnly(todoItems)\n ..addColumns([countAll()])\n ..where(todoItems.category.isNull()));\n\n final query = db.selectOnly(categories)\n ..addColumns([categories.name, countWithoutCategory])\n ..groupBy([categories.id]);\n query.unionAll(db.selectExpressions(\n [const Constant<String>(null), countWithoutCategory]));\n\n return query\n .map((row) => (row.read(categories.name), row.read(countWithCategory)!))\n .get();\n }\n}\n','joinIntro': '// We define a data class to contain both a todo entry and the associated\n// category.\nclass EntryWithCategory {\n EntryWithCategory(this.entry, this.category);\n\n // The classes are generated by drift for each of the tables involved in the\n // join.\n final TodoItem entry;\n final Category? category;\n}\n\n // in the database class, we can then load the category for each entry\n Stream<List<EntryWithCategory>> entriesWithCategory() {\n final query = select(todoItems).join([\n leftOuterJoin(categories, categories.id.equalsExp(todoItems.category)),\n ]);\n\n return query.watch().map((rows) {\n return rows.map((row) {\n return EntryWithCategory(\n row.readTable(todoItems),\n row.readTableOrNull(categories),\n );\n }).toList();\n });\n }\n','limit': ' Future<List<TodoItem>> limitTodos(int limit, {int? offset}) {\n return (select(todoItems)..limit(limit, offset: offset)).get();\n }\n','order-by': ' Future<List<TodoItem>> sortEntriesAlphabetically() {\n return (select(todoItems)\n ..orderBy([(t) => OrderingTerm(expression: t.title)]))\n .get();\n }\n','single': ' Stream<TodoItem> entryById(int id) {\n return (select(todoItems)..where((t) => t.id.equals(id))).watchSingle();\n }\n','mapping': ' Stream<List<String>> contentWithLongTitles() {\n final query = select(todoItems)\n ..where((t) => t.title.length.isBiggerOrEqualValue(16));\n\n return query.map((row) => row.content).watch();\n }\n','selectable': ' // Exposes `get` and `watch`\n MultiSelectable<TodoItem> pageOfTodos(int page, {int pageSize = 10}) {\n return select(todoItems)..limit(pageSize, offset: page);\n }\n\n // Exposes `getSingle` and `watchSingle`\n SingleSelectable<TodoItem> selectableEntryById(int id) {\n return select(todoItems)..where((t) => t.id.equals(id));\n }\n\n // Exposes `getSingleOrNull` and `watchSingleOrNull`\n SingleOrNullSelectable<TodoItem> entryFromExternalLink(int id) {\n return select(todoItems)..where((t) => t.id.equals(id));\n }\n','results': ' return query.watch().map((rows) {\n return rows.map((row) {\n return EntryWithCategory(\n row.readTable(todoItems),\n row.readTableOrNull(categories),\n );\n }).toList();\n });\n','otherTodosInSameCategory': ' /// Searches for todo entries in the same category as the ones having\n /// `titleQuery` in their titles.\n Future<List<TodoItem>> otherTodosInSameCategory(String titleQuery) async {\n // Since we\'re adding the same table twice (once to filter for the title,\n // and once to find other todos in same category), we need a way to\n // distinguish the two tables. So, we\'re giving one of them a special name:\n final otherTodos = alias(todoItems, \'inCategory\');\n\n final query = select(otherTodos).join([\n // In joins, `useColumns: false` tells drift to not add columns of the\n // joined table to the result set. This is useful here, since we only join\n // the tables so that we can refer to them in the where clause.\n innerJoin(categories, categories.id.equalsExp(otherTodos.category),\n useColumns: false),\n innerJoin(todoItems, todoItems.category.equalsExp(categories.id),\n useColumns: false),\n ])\n ..where(todoItems.title.contains(titleQuery));\n\n return query.map((row) => row.readTable(otherTodos)).get();\n }\n','countTodosInCategories': ' Future<void> countTodosInCategories() async {\n final amountOfTodos = todoItems.id.count();\n\n final query = select(categories).join([\n innerJoin(\n todoItems,\n todoItems.category.equalsExp(categories.id),\n useColumns: false,\n )\n ]);\n query\n ..addColumns([amountOfTodos])\n ..groupBy([categories.id]);\n\n final result = await query.get();\n\n for (final row in result) {\n print(\'there are \${row.read(amountOfTodos)} entries in\'\n \'\${row.readTable(categories)}\');\n }\n }\n','averageItemLength': ' Stream<double> averageItemLength() {\n final avgLength = todoItems.content.length.avg();\n final query = selectOnly(todoItems)..addColumns([avgLength]);\n\n return query.map((row) => row.read(avgLength)!).watchSingle();\n }\n','createCategoryForUnassignedTodoEntries': ' Future<void> createCategoryForUnassignedTodoEntries() async {\n final newDescription = Variable<String>(\'category for: \') + todoItems.title;\n final query = selectOnly(todoItems)\n ..where(todoItems.category.isNull())\n ..addColumns([newDescription]);\n\n await into(categories).insertFromSelect(query, columns: {\n categories.name: newDescription,\n });\n }\n','subquery': ' Future<List<(Category, int)>> amountOfLengthyTodoItemsPerCategory() async {\n final longestTodos = Subquery(\n select(todoItems)\n ..orderBy([(row) => OrderingTerm.desc(row.title.length)])\n ..limit(10),\n \'s\',\n );\n\n // In the main query, we want to count how many entries in longestTodos were\n // found for each category. But we can\'t access todos.title directly since\n // we\'re not selecting from `todos`. Instead, we\'ll use Subquery.ref to read\n // from a column in a subquery.\n final itemCount = longestTodos.ref(todoItems.title).count();\n final query = select(categories).join(\n [\n innerJoin(\n longestTodos,\n // Again using .ref() here to access the category in the outer select\n // statement.\n longestTodos.ref(todoItems.category).equalsExp(categories.id),\n useColumns: false,\n )\n ],\n )\n ..addColumns([itemCount])\n ..groupBy([categories.id]);\n\n final rows = await query.get();\n\n return [\n for (final row in rows) (row.readTable(categories), row.read(itemCount)!),\n ];\n }\n','custom-columns': ' Future<List<(TodoItem, bool)>> loadEntries() {\n // assume that an entry is important if it has the string "important" somewhere in its content\n final isImportant = todoItems.content.like(\'%important%\');\n\n return select(todoItems).addColumns([isImportant]).map((row) {\n final entry = row.readTable(todoItems);\n final entryIsImportant = row.read(isImportant)!;\n\n return (entry, entryIsImportant);\n }).get();\n }\n','hasTodoItem': ' Future<bool> hasTodoItem() async {\n final todoItemExists = existsQuery(select(todoItems));\n final row = await selectExpressions([todoItemExists]).getSingle();\n return row.read(todoItemExists)!;\n }\n','compound': ' Future<List<(String?, int)>> todoItemsInCategory() async {\n final countWithCategory = subqueryExpression<int>(selectOnly(todoItems)\n ..addColumns([countAll()])\n ..where(todoItems.category.equalsExp(categories.id)));\n\n final countWithoutCategory = subqueryExpression<int>(selectOnly(todoItems)\n ..addColumns([countAll()])\n ..where(todoItems.category.isNull()));\n\n final query = db.selectOnly(categories)\n ..addColumns([categories.name, countWithoutCategory])\n ..groupBy([categories.id]);\n query.unionAll(db.selectExpressions(\n [const Constant<String>(null), countWithoutCategory]));\n\n return query\n .map((row) => (row.read(categories.name), row.read(countWithCategory)!))\n .get();\n }\n',}, 'lib/src/snippets/dart_api/tables.dart.snippet.json': {'(full)': '// ignore_for_file: unused_local_variable, unused_element\n\nimport \'package:drift/drift.dart\';\n\npart \'tables.g.dart\';\n\nclass TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()(); // (1)!\n TextColumn get title => text()();\n DateTimeColumn get createdAt => dateTime().nullable()(); // (2)!\n}\n\n@DriftDatabase(tables: [TodoItems])\nclass Database extends _\$Database {\n Database(super.e);\n\n @override\n int get schemaVersion => 1;\n}\n\nclass Albums extends Table {\n late final id = integer().autoIncrement()();\n late final name = text()();\n late final artist = integer().references(Artists, #id)();\n}\n\nclass Artists extends Table {\n late final id = integer().autoIncrement()();\n late final name = text()();\n}\n\nbool isInDarkMode() => false;\n\nclass Table1 extends Table {\n late final useDarkMode = boolean().clientDefault(() => false)();\n late final creationTime = dateTime().withDefault(currentDateAndTime)();\n late final age = integer().nullable()();\n late final username = text().unique()();\n late final name = text().withLength(min: 1, max: 50)();\n late final isAdmin = boolean().named(\'admin\')();\n}\n\nclass Table2 extends Table {\n late final Column<int> age = integer().check(age.isBiggerOrEqualValue(0))();\n}\n\nclass Squares extends Table {\n late final length = integer()();\n late final width = integer()();\n late final area = integer().generatedAs(length * width)();\n}\n\nclass Boxes extends Table {\n late final length = integer()();\n late final width = integer()();\n late final area = integer().generatedAs(length * width, stored: true)();\n}\n\nclass Products extends Table {\n @override\n String get tableName => \'product_table\';\n}\n\nclass TableWithCustomConstraints extends Table {\n late final foo = integer()();\n late final bar = integer()();\n\n @override\n List<String> get customConstraints => [\n \'FOREIGN KEY (foo, bar) REFERENCES group_memberships ("group", user)\',\n ];\n}\n\nclass GroupMemberships extends Table {\n late final group = integer()();\n late final user = integer()();\n}\n\nmixin TableMixin on Table {\n // Primary key column\n late final id = integer().autoIncrement()();\n\n // Column for created at timestamp\n late final createdAt = dateTime().withDefault(currentDateAndTime)();\n}\n\nclass Posts extends Table with TableMixin {\n late final content = text()();\n}\n\nclass ColumnConstraint extends Table {\n late final name = text().nullable().customConstraint(\'COLLATE BINARY\')();\n\n late final username = text().customConstraint(\'NOT NULL COLLATE BINARY\')();\n}\n\nclass Profiles extends Table {\n late final email = text()();\n\n @override\n Set<Column<Object>> get primaryKey => {email};\n}\n\nclass Reservations extends Table {\n late final reservationId = integer().autoIncrement()();\n\n late final room = text()();\n late final onDay = dateTime()();\n\n @override\n List<Set<Column>> get uniqueKeys => [\n {room, onDay}\n ];\n}\n\nclass Items extends Table {\n late final id = integer().autoIncrement()();\n late final title = text()();\n}\n\nFuture<void> insertWithAutoIncrement(CatDatabase database) async {\n await database.items.insertAll([\n // Only the title is required here\n ItemsCompanion.insert(title: \'First entry\'),\n ItemsCompanion.insert(title: \'Another item\'),\n ]);\n\n final items = await database.items.all().get();\n // This prints [(id: 1, title: First entry), (id: 2, title: Another item)].\n // The id has been chosen by the database.\n print(items);\n}\n\nFuture<void> insertWithAutoIncrementManager(CatDatabase database) async {\n await database.managers.items.bulkCreate((c) => [\n c(title: \'First entry\'),\n c(title: \'Another item\'),\n ]);\n\n final items = await database.managers.items.get();\n // This prints [(id: 1, title: First entry), (id: 2, title: Another item)].\n // The id has been chosen by the database.\n print(items);\n}\n\n@DriftDatabase(tables: [Reservations, Items])\nclass CatDatabase extends _\$CatDatabase {\n CatDatabase(super.e);\n\n @override\n int get schemaVersion => 1;\n}\n\n@TableIndex(name: \'user_name\', columns: {#name})\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n\n@TableIndex.sql(\'\'\'\n CREATE INDEX pending_orders ON orders (creation_time)\n WHERE status == \'pending\';\n\'\'\')\nclass Orders extends Table {\n IntColumn get id => integer().autoIncrement()();\n IntColumn get totalAmount => integer()();\n DateTimeColumn get creationTime => dateTime()();\n TextColumn get status => text()();\n}\n\nclass Preferences extends Table {\n TextColumn get key => text()();\n AnyColumn get value => sqliteAny().nullable()();\n\n @override\n Set<Column<Object>>? get primaryKey => {key};\n\n @override\n bool get isStrict => true;\n}\n','simple_schema': 'class TodoItems extends Table {\n IntColumn get id => integer().autoIncrement()(); // (1)!\n TextColumn get title => text()();\n DateTimeColumn get createdAt => dateTime().nullable()(); // (2)!\n}\n','simple_schema_db': '@DriftDatabase(tables: [TodoItems])\nclass Database extends _\$Database {\n Database(super.e);\n\n @override\n int get schemaVersion => 1;\n}\n','references': 'class Albums extends Table {\n late final id = integer().autoIncrement()();\n late final name = text()();\n late final artist = integer().references(Artists, #id)();\n}\n\nclass Artists extends Table {\n late final id = integer().autoIncrement()();\n late final name = text()();\n}\n','client_default': ' late final useDarkMode = boolean().clientDefault(() => false)();\n','db_default': ' late final creationTime = dateTime().withDefault(currentDateAndTime)();\n','optional_columns': ' late final age = integer().nullable()();\n','unique_columns': ' late final username = text().unique()();\n','withLength': ' late final name = text().withLength(min: 1, max: 50)();\n','named_column': ' late final isAdmin = boolean().named(\'admin\')();\n','check_column': ' late final Column<int> age = integer().check(age.isBiggerOrEqualValue(0))();\n','generated_column': 'class Squares extends Table {\n late final length = integer()();\n late final width = integer()();\n late final area = integer().generatedAs(length * width)();\n}\n','generated_column_stored': 'class Boxes extends Table {\n late final length = integer()();\n late final width = integer()();\n late final area = integer().generatedAs(length * width, stored: true)();\n}\n','custom_table_name': 'class Products extends Table {\n @override\n String get tableName => \'product_table\';\n}\n','custom-constraint-table': 'class TableWithCustomConstraints extends Table {\n late final foo = integer()();\n late final bar = integer()();\n\n @override\n List<String> get customConstraints => [\n \'FOREIGN KEY (foo, bar) REFERENCES group_memberships ("group", user)\',\n ];\n}\n','table_mixin': 'mixin TableMixin on Table {\n // Primary key column\n late final id = integer().autoIncrement()();\n\n // Column for created at timestamp\n late final createdAt = dateTime().withDefault(currentDateAndTime)();\n}\n\nclass Posts extends Table with TableMixin {\n late final content = text()();\n}\n','custom_column_constraint': ' late final name = text().nullable().customConstraint(\'COLLATE BINARY\')();\n','custom_column_constraint_not_nullable': ' late final username = text().customConstraint(\'NOT NULL COLLATE BINARY\')();\n','custom_pk': 'class Profiles extends Table {\n late final email = text()();\n\n @override\n Set<Column<Object>> get primaryKey => {email};\n}\n','unique-table': 'class Reservations extends Table {\n late final reservationId = integer().autoIncrement()();\n\n late final room = text()();\n late final onDay = dateTime()();\n\n @override\n List<Set<Column>> get uniqueKeys => [\n {room, onDay}\n ];\n}\n','autoIncrement': 'class Items extends Table {\n late final id = integer().autoIncrement()();\n late final title = text()();\n}\n','autoIncrementUse': ' await database.items.insertAll([\n // Only the title is required here\n ItemsCompanion.insert(title: \'First entry\'),\n ItemsCompanion.insert(title: \'Another item\'),\n ]);\n\n final items = await database.items.all().get();\n // This prints [(id: 1, title: First entry), (id: 2, title: Another item)].\n // The id has been chosen by the database.\n print(items);\n','autoIncrementUseManager': ' await database.managers.items.bulkCreate((c) => [\n c(title: \'First entry\'),\n c(title: \'Another item\'),\n ]);\n\n final items = await database.managers.items.get();\n // This prints [(id: 1, title: First entry), (id: 2, title: Another item)].\n // The id has been chosen by the database.\n print(items);\n','index': '@TableIndex(name: \'user_name\', columns: {#name})\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n','indexsql': '@TableIndex.sql(\'\'\'\n CREATE INDEX pending_orders ON orders (creation_time)\n WHERE status == \'pending\';\n\'\'\')\nclass Orders extends Table {\n IntColumn get id => integer().autoIncrement()();\n IntColumn get totalAmount => integer()();\n DateTimeColumn get creationTime => dateTime()();\n TextColumn get status => text()();\n}\n','strict': 'class Preferences extends Table {\n TextColumn get key => text()();\n AnyColumn get value => sqliteAny().nullable()();\n\n @override\n Set<Column<Object>>? get primaryKey => {key};\n\n @override\n bool get isStrict => true;\n}\n',}, 'lib/src/snippets/dart_api/views.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nclass Todos 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 IntColumn get category => integer().nullable()();\n}\n\n@DataClassName(\'Category\')\nclass Categories extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get description => text()();\n}\n\nabstract class CategoryTodoCount extends View {\n // Getters define the tables that this view is reading from.\n Todos get todos;\n Categories get categories;\n\n // Custom expressions can be given a name by defining them as a getter:.\n Expression<int> get itemCount => todos.id.count();\n\n @override\n Query as() =>\n // Views can select columns defined as expression getters on the class, or\n // they can reference columns from other tables.\n select([categories.description, itemCount])\n .from(categories)\n .join([innerJoin(todos, todos.category.equalsExp(categories.id))]);\n}\n','view': 'abstract class CategoryTodoCount extends View {\n // Getters define the tables that this view is reading from.\n Todos get todos;\n Categories get categories;\n\n // Custom expressions can be given a name by defining them as a getter:.\n Expression<int> get itemCount => todos.id.count();\n\n @override\n Query as() =>\n // Views can select columns defined as expression getters on the class, or\n // they can reference columns from other tables.\n select([categories.description, itemCount])\n .from(categories)\n .join([innerJoin(todos, todos.category.equalsExp(categories.id))]);\n}\n',}, @@ -34,6 +42,8 @@ const generatedSnippets = { 'lib/src/snippets/dart_api/manager.dart.snippet.json': {'(full)': '// ignore_for_file: invalid_use_of_internal_member, unused_local_variable, unused_element\n\nimport \'package:drift/drift.dart\';\n\npart \'manager.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 IntColumn get category =>\n integer().nullable().references(TodoCategory, #id)();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\nclass TodoCategory extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get description => text()();\n IntColumn get user => integer().nullable().references(Users, #id)();\n}\n\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n\nclass Groups extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n @ReferenceName("administeredGroups")\n IntColumn get admin => integer().nullable().references(Users, #id)();\n @ReferenceName("ownedGroups")\n IntColumn get owner => integer().references(Users, #id)();\n}\n\n\n@DriftDatabase(tables: [TodoItems, TodoCategory, Groups, Users])\nclass AppDatabase extends _\$AppDatabase {\n AppDatabase(super.e);\n @override\n int get schemaVersion => 1;\n}\n\nextension ManagerExamples on AppDatabase {\n Future<void> createTodoItem() async {\n // Create a new item\n await managers.todoItems\n .create((o) => o(title: \'Title\', content: \'Content\'));\n\n // We can also use `mode` and `onConflict` parameters, just\n // like in the `[InsertStatement.insert]` method on the table\n await managers.todoItems.create(\n (o) => o(title: \'Title\', content: \'New Content\'),\n mode: InsertMode.replace);\n\n // We can also create multiple items at once\n await managers.todoItems.bulkCreate(\n (o) => [\n o(title: \'Title 1\', content: \'Content 1\'),\n o(title: \'Title 2\', content: \'Content 2\'),\n ],\n );\n }\n\n Future<void> updateTodoItems() async {\n // Update all items\n await managers.todoItems.update((o) => o(content: Value(\'New Content\')));\n\n // Update multiple items\n await managers.todoItems\n .filter((f) => f.id.isIn([1, 2, 3]))\n .update((o) => o(content: Value(\'New Content\')));\n }\n\n Future<void> replaceTodoItems() async {\n // Replace a single item\n var obj = await managers.todoItems.filter((o) => o.id(1)).getSingle();\n obj = obj.copyWith(content: \'New Content\');\n await managers.todoItems.replace(obj);\n\n // Replace multiple items\n var objs =\n await managers.todoItems.filter((o) => o.id.isIn([1, 2, 3])).get();\n objs = objs.map((o) => o.copyWith(content: \'New Content\')).toList();\n await managers.todoItems.bulkReplace(objs);\n }\n\n Future<void> deleteTodoItems() async {\n // Delete all items\n await managers.todoItems.delete();\n\n // Delete a single item\n await managers.todoItems.filter((f) => f.id(5)).delete();\n }\n\n Future<void> selectTodoItems() async {\n // Get all items\n managers.todoItems.get();\n\n // A stream of all the todo items, updated in real-time\n managers.todoItems.watch();\n\n // To get a single item, apply a filter and call `getSingle`\n await managers.todoItems.filter((f) => f.id(1)).getSingle();\n }\n\n Future<void> filterTodoItems() async {\n // All items with a title of "Title"\n managers.todoItems.filter((f) => f.title("Title"));\n\n // All items with a title of "Title" and content of "Content"\n managers.todoItems.filter((f) => f.title("Title") & f.content("Content"));\n\n // All items with a title of "Title" or content that is not null\n managers.todoItems.filter((f) => f.title("Title") | f.content.not.isNull());\n }\n\n Future<void> filterWithType() async {\n // Filter all items created since 7 days ago\n managers.todoItems.filter(\n (f) => f.createdAt.isAfter(DateTime.now().subtract(Duration(days: 7))));\n\n // Filter all items with a title that starts with "Title"\n managers.todoItems.filter((f) => f.title.startsWith(\'Title\'));\n }\n\n Future<void> orderWithType() async {\n // Order all items by their creation date in ascending order\n managers.todoItems.orderBy((o) => o.createdAt.asc());\n\n // Order all items by their title in ascending order and then by their content in ascending order\n managers.todoItems.orderBy((o) => o.title.asc() & o.content.asc());\n }\n\n Future<void> count() async {\n // Count all items\n await managers.todoItems.count();\n\n // Count all items with a title of "Title"\n await managers.todoItems.filter((f) => f.title("Title")).count();\n }\n\n Future<void> exists() async {\n // Check if any items exist\n await managers.todoItems.exists();\n\n // Check if any items with a title of "Title" exist\n await managers.todoItems.filter((f) => f.title("Title")).exists();\n }\n\n Future<void> relationalFilter() async {\n // Get all items with a category description of "School"\n managers.todoItems.filter((f) => f.category.description("School"));\n\n // These can be combined with other filters\n // For example, get all items with a title of "Title" or a category description of "School"\n await managers.todoItems\n .filter(\n (f) => f.title("Title") | f.category.description("School"),\n )\n .exists();\n }\n\n Future<void> reverseRelationalFilter() async {\n // Get the category that has a todo item with an id of 1\n managers.todoCategory.filter((f) => f.todoItemsRefs((f) => f.id(1)));\n\n // These can be combined with other filters\n // For example, get all categories with a description of "School" or a todo item with an id of 1\n managers.todoCategory.filter(\n (f) => f.description("School") | f.todoItemsRefs((f) => f.id(1)),\n );\n }\n\n Future<void> reverseNamedRelationalFilter() async {\n // Get all users who are administrators of a group with a name containing "Business"\n // or who own a group with an id of 1, 2, 4, or 5\n managers.users.filter(\n (f) =>\n f.administeredGroups((f) => f.name.contains("Business")) |\n f.ownedGroups((f) => f.id.isIn([1, 2, 4, 5])),\n );\n }\n\n Future<void> references() async {\n /// Get each todo, along with a its categories\n final todosWithRefs = await managers.todoItems.withReferences().get();\n for (final (todo, refs) in todosWithRefs) {\n final category = await refs.category?.getSingle();\n }\n\n /// This also works in the reverse\n final categoriesWithRefs =\n await managers.todoCategory.withReferences().get();\n for (final (category, refs) in categoriesWithRefs) {\n final todos = await refs.todoItemsRefs.get();\n }\n }\n\n Future<void> referencesPrefetch() async {\n /// Get each todo, along with a its categories\n final todosWithRefs = await managers.todoItems\n .withReferences(\n (prefetch) => prefetch(category: true),\n )\n .get();\n for (final (todo, refs) in todosWithRefs) {\n final category = refs.category?.prefetchedData?.firstOrNull;\n // No longer needed\n // final category = await refs.category?.getSingle();\n }\n\n /// This also works in the reverse\n final categoriesWithRefs = await managers.todoCategory\n .withReferences((prefetch) => prefetch(todoItemsRefs: true))\n .get();\n for (final (category, refs) in categoriesWithRefs) {\n final todos = refs.todoItemsRefs.prefetchedData;\n // No longer needed\n //final todos = await refs.todoItemsRefs.get();\n }\n }\n\n Future<void> referencesPrefetchStream() async {\n /// Get each todo, along with a its categories\n managers.todoCategory\n .withReferences((prefetch) => prefetch(todoItemsRefs: true, user: true))\n .watch()\n .listen(\n (catWithRefs) {\n for (final (cat, refs) in catWithRefs) {\n // Updates to the user table will trigger a query\n final users = refs.user?.prefetchedData;\n\n // However, updates to the TodoItems table will not trigger a query\n final todos = refs.todoItemsRefs.prefetchedData;\n }\n },\n );\n }\n}\n\n// Extend drifts built-in filters by combining the existing filters to create a new one\n// or by creating a new filter from scratch\nextension After2000Filter on ColumnFilters<DateTime> {\n // Create a new filter by combining existing filters\n Expression<bool> after2000orBefore1900() =>\n isAfter(DateTime(2000)) | isBefore(DateTime(1900));\n\n // Create a new filter from scratch using the `column` property\n Expression<bool> filterOnUnixEpoch(int value) =>\n \$composableFilter(column.unixepoch.equals(value));\n}\n\nFuture<void> filterWithExtension(AppDatabase db) async {\n // Use the custom filters on any column that is of type DateTime\n db.managers.todoItems.filter((f) => f.createdAt.after2000orBefore1900());\n\n // Use the custom filter on the `unixepoch` column\n db.managers.todoItems.filter((f) => f.createdAt.filterOnUnixEpoch(0));\n}\n\n// Extend drifts built-in orderings by create a new ordering from scratch\nextension After2000Ordering on ColumnOrderings<DateTime> {\n ComposableOrdering byUnixEpoch() => ColumnOrderings(column.unixepoch).asc();\n}\n\nFuture<void> orderingWithExtension(AppDatabase db) async {\n // Use the custom orderings on any column that is of type DateTime\n db.managers.todoItems.orderBy((f) => f.createdAt.byUnixEpoch());\n}\n\n// Extend the generated table filter composer to add a custom filter\nextension NoContentOrBefore2000FilterX on \$\$TodoItemsTableFilterComposer {\n Expression<bool> noContentOrBefore2000() =>\n (content.isNull() | createdAt.isBefore(DateTime(2000)));\n}\n\nFuture<void> customFilter(AppDatabase db) async {\n // Use the custom filter on the `TodoItems` table\n db.managers.todoItems.filter((f) => f.noContentOrBefore2000());\n}\n\n// Extend the generated table filter composer to add a custom filter\nextension ContentThenCreationDataX on \$\$TodoItemsTableOrderingComposer {\n ComposableOrdering contentThenCreatedAt() => content.asc() & createdAt.asc();\n}\n\nFuture<void> customOrdering(AppDatabase db) async {\n // Use the custom ordering on the `TodoItems` table\n db.managers.todoItems.orderBy((f) => f.contentThenCreatedAt());\n}\n\nvoid _managerAnnotations(AppDatabase db) async {\n // First create an computed field with an expression you want to use\n final titleLengthField =\n db.managers.todoItems.computedField((o) => o.title.length);\n\n /// Create a copy of the manager with the computed fields you want to use\n final manager = db.managers.todoItems.withFields([titleLengthField]);\n\n // Then use the computed field in a filter\n // This will filter all items whose title has exactly 10 characters\n manager.filter((f) => titleLengthField.filter(10));\n\n // You can also use the computed field in an ordering\n // This will order all items by the length of their title in ascending order\n manager.orderBy((o) => titleLengthField.order.asc());\n\n /// You can read the result of the computed field too\n for (final (item, refs) in await manager.get()) {\n final titleLength = titleLengthField.read(refs);\n print(\'Item \${item.id} has a title length of \$titleLength\');\n }\n}\n\nvoid _managerReferencedAnnotations(AppDatabase db) async {\n // This computed field will get the name of the user of this todo\n final todoUserName =\n db.managers.todoItems.computedField((o) => o.category.user.name);\n\n /// Create a copy of the manager with the computed fields you want to use\n final manager = db.managers.todoItems.withFields([todoUserName]);\n\n /// You can read the result of the computed field too\n for (final (item, refs) in await manager.get()) {\n final userName = todoUserName.read(refs);\n print(\'Item \${item.id} has a user with the name \$userName\');\n }\n}\n\nvoid _managerAggregatedAnnotations(AppDatabase db) async {\n // You can aggregate over multiple rows in a related table\n // to perform calculations on them\n final todoCountcomputedField = db.managers.todoCategory\n .computedField((o) => o.todoItemsRefs((o) => o.id).count());\n\n /// Create a copy of the manager with the computed fields you want to use\n final manager = db.managers.todoCategory.withFields([todoCountcomputedField]);\n\n /// Read the result of the computed field\n for (final (category, refs) in await manager.get()) {\n final todoCount = todoCountcomputedField.read(refs);\n print(\'Category \${category.id} has \$todoCount todos\');\n }\n}\n','tables': '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 IntColumn get category =>\n integer().nullable().references(TodoCategory, #id)();\n DateTimeColumn get createdAt => dateTime().nullable()();\n}\n\nclass TodoCategory extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get description => text()();\n IntColumn get user => integer().nullable().references(Users, #id)();\n}\n','user_group_tables': 'class Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n\nclass Groups extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n @ReferenceName("administeredGroups")\n IntColumn get admin => integer().nullable().references(Users, #id)();\n @ReferenceName("ownedGroups")\n IntColumn get owner => integer().references(Users, #id)();\n}\n\n','manager_create': ' Future<void> createTodoItem() async {\n // Create a new item\n await managers.todoItems\n .create((o) => o(title: \'Title\', content: \'Content\'));\n\n // We can also use `mode` and `onConflict` parameters, just\n // like in the `[InsertStatement.insert]` method on the table\n await managers.todoItems.create(\n (o) => o(title: \'Title\', content: \'New Content\'),\n mode: InsertMode.replace);\n\n // We can also create multiple items at once\n await managers.todoItems.bulkCreate(\n (o) => [\n o(title: \'Title 1\', content: \'Content 1\'),\n o(title: \'Title 2\', content: \'Content 2\'),\n ],\n );\n }\n','manager_update': ' Future<void> updateTodoItems() async {\n // Update all items\n await managers.todoItems.update((o) => o(content: Value(\'New Content\')));\n\n // Update multiple items\n await managers.todoItems\n .filter((f) => f.id.isIn([1, 2, 3]))\n .update((o) => o(content: Value(\'New Content\')));\n }\n','manager_replace': ' Future<void> replaceTodoItems() async {\n // Replace a single item\n var obj = await managers.todoItems.filter((o) => o.id(1)).getSingle();\n obj = obj.copyWith(content: \'New Content\');\n await managers.todoItems.replace(obj);\n\n // Replace multiple items\n var objs =\n await managers.todoItems.filter((o) => o.id.isIn([1, 2, 3])).get();\n objs = objs.map((o) => o.copyWith(content: \'New Content\')).toList();\n await managers.todoItems.bulkReplace(objs);\n }\n','manager_delete': ' Future<void> deleteTodoItems() async {\n // Delete all items\n await managers.todoItems.delete();\n\n // Delete a single item\n await managers.todoItems.filter((f) => f.id(5)).delete();\n }\n','manager_select': ' Future<void> selectTodoItems() async {\n // Get all items\n managers.todoItems.get();\n\n // A stream of all the todo items, updated in real-time\n managers.todoItems.watch();\n\n // To get a single item, apply a filter and call `getSingle`\n await managers.todoItems.filter((f) => f.id(1)).getSingle();\n }\n','manager_filter': ' Future<void> filterTodoItems() async {\n // All items with a title of "Title"\n managers.todoItems.filter((f) => f.title("Title"));\n\n // All items with a title of "Title" and content of "Content"\n managers.todoItems.filter((f) => f.title("Title") & f.content("Content"));\n\n // All items with a title of "Title" or content that is not null\n managers.todoItems.filter((f) => f.title("Title") | f.content.not.isNull());\n }\n','manager_type_specific_filter': ' Future<void> filterWithType() async {\n // Filter all items created since 7 days ago\n managers.todoItems.filter(\n (f) => f.createdAt.isAfter(DateTime.now().subtract(Duration(days: 7))));\n\n // Filter all items with a title that starts with "Title"\n managers.todoItems.filter((f) => f.title.startsWith(\'Title\'));\n }\n','manager_ordering': ' Future<void> orderWithType() async {\n // Order all items by their creation date in ascending order\n managers.todoItems.orderBy((o) => o.createdAt.asc());\n\n // Order all items by their title in ascending order and then by their content in ascending order\n managers.todoItems.orderBy((o) => o.title.asc() & o.content.asc());\n }\n','manager_count': ' Future<void> count() async {\n // Count all items\n await managers.todoItems.count();\n\n // Count all items with a title of "Title"\n await managers.todoItems.filter((f) => f.title("Title")).count();\n }\n','manager_exists': ' Future<void> exists() async {\n // Check if any items exist\n await managers.todoItems.exists();\n\n // Check if any items with a title of "Title" exist\n await managers.todoItems.filter((f) => f.title("Title")).exists();\n }\n','manager_filter_forward_references': ' Future<void> relationalFilter() async {\n // Get all items with a category description of "School"\n managers.todoItems.filter((f) => f.category.description("School"));\n\n // These can be combined with other filters\n // For example, get all items with a title of "Title" or a category description of "School"\n await managers.todoItems\n .filter(\n (f) => f.title("Title") | f.category.description("School"),\n )\n .exists();\n }\n','manager_filter_back_references': ' Future<void> reverseRelationalFilter() async {\n // Get the category that has a todo item with an id of 1\n managers.todoCategory.filter((f) => f.todoItemsRefs((f) => f.id(1)));\n\n // These can be combined with other filters\n // For example, get all categories with a description of "School" or a todo item with an id of 1\n managers.todoCategory.filter(\n (f) => f.description("School") | f.todoItemsRefs((f) => f.id(1)),\n );\n }\n','manager_filter_custom_back_references': ' Future<void> reverseNamedRelationalFilter() async {\n // Get all users who are administrators of a group with a name containing "Business"\n // or who own a group with an id of 1, 2, 4, or 5\n managers.users.filter(\n (f) =>\n f.administeredGroups((f) => f.name.contains("Business")) |\n f.ownedGroups((f) => f.id.isIn([1, 2, 4, 5])),\n );\n }\n','manager_references': ' Future<void> references() async {\n /// Get each todo, along with a its categories\n final todosWithRefs = await managers.todoItems.withReferences().get();\n for (final (todo, refs) in todosWithRefs) {\n final category = await refs.category?.getSingle();\n }\n\n /// This also works in the reverse\n final categoriesWithRefs =\n await managers.todoCategory.withReferences().get();\n for (final (category, refs) in categoriesWithRefs) {\n final todos = await refs.todoItemsRefs.get();\n }\n }\n\n','manager_prefetch_references': ' Future<void> referencesPrefetch() async {\n /// Get each todo, along with a its categories\n final todosWithRefs = await managers.todoItems\n .withReferences(\n (prefetch) => prefetch(category: true),\n )\n .get();\n for (final (todo, refs) in todosWithRefs) {\n final category = refs.category?.prefetchedData?.firstOrNull;\n // No longer needed\n // final category = await refs.category?.getSingle();\n }\n\n /// This also works in the reverse\n final categoriesWithRefs = await managers.todoCategory\n .withReferences((prefetch) => prefetch(todoItemsRefs: true))\n .get();\n for (final (category, refs) in categoriesWithRefs) {\n final todos = refs.todoItemsRefs.prefetchedData;\n // No longer needed\n //final todos = await refs.todoItemsRefs.get();\n }\n }\n','manager_prefetch_references_stream': ' /// Get each todo, along with a its categories\n managers.todoCategory\n .withReferences((prefetch) => prefetch(todoItemsRefs: true, user: true))\n .watch()\n .listen(\n (catWithRefs) {\n for (final (cat, refs) in catWithRefs) {\n // Updates to the user table will trigger a query\n final users = refs.user?.prefetchedData;\n\n // However, updates to the TodoItems table will not trigger a query\n final todos = refs.todoItemsRefs.prefetchedData;\n }\n },\n );\n','manager_filter_extensions': '// Extend drifts built-in filters by combining the existing filters to create a new one\n// or by creating a new filter from scratch\nextension After2000Filter on ColumnFilters<DateTime> {\n // Create a new filter by combining existing filters\n Expression<bool> after2000orBefore1900() =>\n isAfter(DateTime(2000)) | isBefore(DateTime(1900));\n\n // Create a new filter from scratch using the `column` property\n Expression<bool> filterOnUnixEpoch(int value) =>\n \$composableFilter(column.unixepoch.equals(value));\n}\n\nFuture<void> filterWithExtension(AppDatabase db) async {\n // Use the custom filters on any column that is of type DateTime\n db.managers.todoItems.filter((f) => f.createdAt.after2000orBefore1900());\n\n // Use the custom filter on the `unixepoch` column\n db.managers.todoItems.filter((f) => f.createdAt.filterOnUnixEpoch(0));\n}\n','manager_ordering_extensions': '// Extend drifts built-in orderings by create a new ordering from scratch\nextension After2000Ordering on ColumnOrderings<DateTime> {\n ComposableOrdering byUnixEpoch() => ColumnOrderings(column.unixepoch).asc();\n}\n\nFuture<void> orderingWithExtension(AppDatabase db) async {\n // Use the custom orderings on any column that is of type DateTime\n db.managers.todoItems.orderBy((f) => f.createdAt.byUnixEpoch());\n}\n','manager_custom_filter': '// Extend the generated table filter composer to add a custom filter\nextension NoContentOrBefore2000FilterX on \$\$TodoItemsTableFilterComposer {\n Expression<bool> noContentOrBefore2000() =>\n (content.isNull() | createdAt.isBefore(DateTime(2000)));\n}\n\nFuture<void> customFilter(AppDatabase db) async {\n // Use the custom filter on the `TodoItems` table\n db.managers.todoItems.filter((f) => f.noContentOrBefore2000());\n}\n','manager_custom_ordering': '// Extend the generated table filter composer to add a custom filter\nextension ContentThenCreationDataX on \$\$TodoItemsTableOrderingComposer {\n ComposableOrdering contentThenCreatedAt() => content.asc() & createdAt.asc();\n}\n\nFuture<void> customOrdering(AppDatabase db) async {\n // Use the custom ordering on the `TodoItems` table\n db.managers.todoItems.orderBy((f) => f.contentThenCreatedAt());\n}\n','manager_annotations': ' // First create an computed field with an expression you want to use\n final titleLengthField =\n db.managers.todoItems.computedField((o) => o.title.length);\n\n /// Create a copy of the manager with the computed fields you want to use\n final manager = db.managers.todoItems.withFields([titleLengthField]);\n\n // Then use the computed field in a filter\n // This will filter all items whose title has exactly 10 characters\n manager.filter((f) => titleLengthField.filter(10));\n\n // You can also use the computed field in an ordering\n // This will order all items by the length of their title in ascending order\n manager.orderBy((o) => titleLengthField.order.asc());\n\n /// You can read the result of the computed field too\n for (final (item, refs) in await manager.get()) {\n final titleLength = titleLengthField.read(refs);\n print(\'Item \${item.id} has a title length of \$titleLength\');\n }\n','referenced_annotations': ' // This computed field will get the name of the user of this todo\n final todoUserName =\n db.managers.todoItems.computedField((o) => o.category.user.name);\n\n /// Create a copy of the manager with the computed fields you want to use\n final manager = db.managers.todoItems.withFields([todoUserName]);\n\n /// You can read the result of the computed field too\n for (final (item, refs) in await manager.get()) {\n final userName = todoUserName.read(refs);\n print(\'Item \${item.id} has a user with the name \$userName\');\n }\n','aggregated_annotations': ' // You can aggregate over multiple rows in a related table\n // to perform calculations on them\n final todoCountcomputedField = db.managers.todoCategory\n .computedField((o) => o.todoItemsRefs((o) => o.id).count());\n\n /// Create a copy of the manager with the computed fields you want to use\n final manager = db.managers.todoCategory.withFields([todoCountcomputedField]);\n\n /// Read the result of the computed field\n for (final (category, refs) in await manager.get()) {\n final todoCount = todoCountcomputedField.read(refs);\n print(\'Category \${category.id} has \$todoCount todos\');\n }\n',}, 'lib/src/snippets/platforms/postgres.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift_postgres/drift_postgres.dart\';\nimport \'package:postgres/postgres.dart\';\n\npart \'postgres.g.dart\';\n\nclass Users extends Table {\n UuidColumn get id => customType(PgTypes.uuid).withDefault(genRandomUuid())();\n TextColumn get name => text()();\n Column<PgDate> get birthDate => customType(PgTypes.date).nullable()();\n}\n\n@DriftDatabase(tables: [Users])\nclass MyDatabase extends _\$MyDatabase {\n MyDatabase(super.e);\n\n @override\n int get schemaVersion => 1;\n}\n\nvoid main() async {\n final pgDatabase = PgDatabase(\n endpoint: Endpoint(\n host: \'localhost\',\n database: \'postgres\',\n username: \'postgres\',\n password: \'postgres\',\n ),\n settings: ConnectionSettings(\n // If you expect to talk to a Postgres database over a public connection,\n // please use SslMode.verifyFull instead.\n sslMode: SslMode.disable,\n ),\n );\n\n final driftDatabase = MyDatabase(pgDatabase);\n\n // Insert a new user\n await driftDatabase.users.insertOne(UsersCompanion.insert(name: \'Simon\'));\n\n // Print all of them\n print(await driftDatabase.users.all().get());\n\n await driftDatabase.close();\n}\n\nList<Endpoint> get yourListOfEndpoints => throw \'stub\';\n\nFuture<void> openWithPool() async {\n final pool = Pool.withEndpoints(yourListOfEndpoints);\n\n final driftDatabase = MyDatabase(PgDatabase.opened(pool));\n await driftDatabase.users.select().get();\n\n // Note that PgDatabase.opened() doesn\'t close the underlying connection when\n // the drift database is closed.\n await driftDatabase.close();\n await pool.close();\n}\n\n// This table uses proper postgres types to store date/time values.\nclass TimeStore extends Table {\n Column<PgDate> get date => customType(PgTypes.date)();\n Column<PgDateTime> get timestampWithTimezone =>\n customType(PgTypes.timestampWithTimezone)();\n Column<PgDateTime> get timestampWithoutTimezone =>\n customType(PgTypes.timestampNoTimezone)();\n Column<Interval> get interval => customType(PgTypes.interval)();\n}\n\nclass _DialectAwareDateTimeType implements DialectAwareSqlType<PgDateTime> {\n /// The underlying type used when this dialect-aware type is used on postgres\n /// databases.\n static const _postgres = PgTypes.timestampWithTimezone;\n\n /// The fallback type used when we\'re not talking to postgres.\n static const _other = DriftSqlType.dateTime;\n\n const _DialectAwareDateTimeType();\n\n @override\n String mapToSqlLiteral(GenerationContext context, PgDateTime dartValue) {\n return switch (context.dialect) {\n SqlDialect.postgres => _postgres.mapToSqlLiteral(dartValue),\n _ => context.typeMapping.mapToSqlLiteral(dartValue.dateTime),\n };\n }\n\n @override\n Object mapToSqlParameter(GenerationContext context, PgDateTime dartValue) {\n return switch (context.dialect) {\n SqlDialect.postgres => _postgres.mapToSqlParameter(dartValue),\n _ => context.typeMapping.mapToSqlVariable(dartValue.dateTime)!,\n };\n }\n\n @override\n PgDateTime read(SqlTypes typeSystem, Object fromSql) {\n return switch (typeSystem.dialect) {\n SqlDialect.postgres => _postgres.read(fromSql),\n _ => PgDateTime(typeSystem.read(_other, fromSql)!),\n };\n }\n\n @override\n String sqlTypeName(GenerationContext context) {\n return switch (context.dialect) {\n SqlDialect.postgres => _postgres.sqlTypeName(context),\n _ => _other.sqlTypeName(context),\n };\n }\n}\n\nconst dateTime = _DialectAwareDateTimeType();\n\nclass DialectAwareTime extends Table {\n // This will use `timestamp with timezone` on postgres, and fall back to the\n // default date type (integer or text) on sqlite databases.\n Column<PgDateTime> get timeValue => customType(dateTime)();\n}\n','setup': 'import \'package:drift/drift.dart\';\nimport \'package:drift_postgres/drift_postgres.dart\';\nimport \'package:postgres/postgres.dart\';\n\npart \'postgres.g.dart\';\n\nclass Users extends Table {\n UuidColumn get id => customType(PgTypes.uuid).withDefault(genRandomUuid())();\n TextColumn get name => text()();\n Column<PgDate> get birthDate => customType(PgTypes.date).nullable()();\n}\n\n@DriftDatabase(tables: [Users])\nclass MyDatabase extends _\$MyDatabase {\n MyDatabase(super.e);\n\n @override\n int get schemaVersion => 1;\n}\n\nvoid main() async {\n final pgDatabase = PgDatabase(\n endpoint: Endpoint(\n host: \'localhost\',\n database: \'postgres\',\n username: \'postgres\',\n password: \'postgres\',\n ),\n settings: ConnectionSettings(\n // If you expect to talk to a Postgres database over a public connection,\n // please use SslMode.verifyFull instead.\n sslMode: SslMode.disable,\n ),\n );\n\n final driftDatabase = MyDatabase(pgDatabase);\n\n // Insert a new user\n await driftDatabase.users.insertOne(UsersCompanion.insert(name: \'Simon\'));\n\n // Print all of them\n print(await driftDatabase.users.all().get());\n\n await driftDatabase.close();\n}\n','pool': 'Future<void> openWithPool() async {\n final pool = Pool.withEndpoints(yourListOfEndpoints);\n\n final driftDatabase = MyDatabase(PgDatabase.opened(pool));\n await driftDatabase.users.select().get();\n\n // Note that PgDatabase.opened() doesn\'t close the underlying connection when\n // the drift database is closed.\n await driftDatabase.close();\n await pool.close();\n}\n','time': '// This table uses proper postgres types to store date/time values.\nclass TimeStore extends Table {\n Column<PgDate> get date => customType(PgTypes.date)();\n Column<PgDateTime> get timestampWithTimezone =>\n customType(PgTypes.timestampWithTimezone)();\n Column<PgDateTime> get timestampWithoutTimezone =>\n customType(PgTypes.timestampNoTimezone)();\n Column<Interval> get interval => customType(PgTypes.interval)();\n}\n','time-dialectaware': 'class _DialectAwareDateTimeType implements DialectAwareSqlType<PgDateTime> {\n /// The underlying type used when this dialect-aware type is used on postgres\n /// databases.\n static const _postgres = PgTypes.timestampWithTimezone;\n\n /// The fallback type used when we\'re not talking to postgres.\n static const _other = DriftSqlType.dateTime;\n\n const _DialectAwareDateTimeType();\n\n @override\n String mapToSqlLiteral(GenerationContext context, PgDateTime dartValue) {\n return switch (context.dialect) {\n SqlDialect.postgres => _postgres.mapToSqlLiteral(dartValue),\n _ => context.typeMapping.mapToSqlLiteral(dartValue.dateTime),\n };\n }\n\n @override\n Object mapToSqlParameter(GenerationContext context, PgDateTime dartValue) {\n return switch (context.dialect) {\n SqlDialect.postgres => _postgres.mapToSqlParameter(dartValue),\n _ => context.typeMapping.mapToSqlVariable(dartValue.dateTime)!,\n };\n }\n\n @override\n PgDateTime read(SqlTypes typeSystem, Object fromSql) {\n return switch (typeSystem.dialect) {\n SqlDialect.postgres => _postgres.read(fromSql),\n _ => PgDateTime(typeSystem.read(_other, fromSql)!),\n };\n }\n\n @override\n String sqlTypeName(GenerationContext context) {\n return switch (context.dialect) {\n SqlDialect.postgres => _postgres.sqlTypeName(context),\n _ => _other.sqlTypeName(context),\n };\n }\n}\n\nconst dateTime = _DialectAwareDateTimeType();\n\nclass DialectAwareTime extends Table {\n // This will use `timestamp with timezone` on postgres, and fall back to the\n // default date type (integer or text) on sqlite databases.\n Column<PgDateTime> get timeValue => customType(dateTime)();\n}\n',}, 'lib/src/snippets/platforms/vm.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\n\nimport \'dart:ffi\';\nimport \'dart:io\';\nimport \'package:sqlite3/sqlite3.dart\';\nimport \'package:sqlite3/open.dart\';\n\nvoid main() {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n\n final db = sqlite3.openInMemory();\n db.dispose();\n}\n\nDynamicLibrary _openOnLinux() {\n final script = File(Platform.script.toFilePath());\n final libraryNextToScript = File(\'\${script.path}/sqlite3.so\');\n return DynamicLibrary.open(libraryNextToScript.path);\n}\n// _openOnWindows could be implemented similarly by opening `sqlite3.dll`\n\nQueryExecutor openDatabase() {\n return NativeDatabase.createInBackground(\n File(\'path/to/database.db\'),\n isolateSetup: () {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n },\n );\n}\n\nQueryExecutor openMultiThreadedDatabase() {\n return NativeDatabase.createInBackground(\n File(\'path/to/database.db\'),\n isolateSetup: () {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n },\n setup: (database) {\n // This is important, as accessing the database across threads otherwise\n // causes "database locked" errors.\n // With write-ahead logging (WAL) enabled, a single writer and multiple\n // readers can operate on the database in parallel.\n database.execute(\'pragma journal_mode = WAL;\');\n },\n readPool: 4,\n );\n}\n','setup': 'import \'dart:ffi\';\nimport \'dart:io\';\nimport \'package:sqlite3/sqlite3.dart\';\nimport \'package:sqlite3/open.dart\';\n\nvoid main() {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n\n final db = sqlite3.openInMemory();\n db.dispose();\n}\n\nDynamicLibrary _openOnLinux() {\n final script = File(Platform.script.toFilePath());\n final libraryNextToScript = File(\'\${script.path}/sqlite3.so\');\n return DynamicLibrary.open(libraryNextToScript.path);\n}\n// _openOnWindows could be implemented similarly by opening `sqlite3.dll`\n','background-simple': 'QueryExecutor openDatabase() {\n return NativeDatabase.createInBackground(\n File(\'path/to/database.db\'),\n isolateSetup: () {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n },\n );\n}\n','background-pool': 'QueryExecutor openMultiThreadedDatabase() {\n return NativeDatabase.createInBackground(\n File(\'path/to/database.db\'),\n isolateSetup: () {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n },\n setup: (database) {\n // This is important, as accessing the database across threads otherwise\n // causes "database locked" errors.\n // With write-ahead logging (WAL) enabled, a single writer and multiple\n // readers can operate on the database in parallel.\n database.execute(\'pragma journal_mode = WAL;\');\n },\n readPool: 4,\n );\n}\n',}, +'lib/src/snippets/platforms/stable_worker.dart.snippet.json': {'(full)': 'import \'package:drift/wasm.dart\';\n\n// When compiled with dart2js, this file defines a dedicated or shared web\n// worker used by drift.\nvoid main() => WasmDatabase.workerMainForOpen();\n',}, +'lib/src/snippets/platforms/platforms.dart.snippet.json': {'(full)': 'import \'dart:ffi\';\nimport \'dart:io\';\nimport \'package:sqlite3/open.dart\';\n\nvoid main() {\n open.overrideFor(OperatingSystem.linux, _openOnLinux);\n\n // After setting all the overrides, you can use drift!\n}\n\nDynamicLibrary _openOnLinux() {\n final scriptDir = File(Platform.script.toFilePath()).parent;\n final libraryNextToScript = File(\'\${scriptDir.path}/sqlite3.so\');\n return DynamicLibrary.open(libraryNextToScript.path);\n}\n// _openOnWindows could be implemented similarly by opening `sqlite3.dll`\n',}, 'lib/src/snippets/platforms/web.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/wasm.dart\';\n// ignore: deprecated_member_use\nimport \'package:drift/web.dart\';\nimport \'package:drift_flutter/drift_flutter.dart\';\nimport \'package:flutter/services.dart\';\nimport \'package:sqlite3/wasm.dart\';\n\ntypedef _\$MyWebDatabase = GeneratedDatabase;\n\nDatabaseConnection connectOnWeb() {\n return DatabaseConnection.delayed(Future(() async {\n final result = await WasmDatabase.open(\n databaseName: \'my_app_db\', // prefer to only use valid identifiers here\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n );\n\n if (result.missingFeatures.isNotEmpty) {\n // Depending how central local persistence is to your app, you may want\n // to show a warning to the user if only unrealiable implemetentations\n // are available.\n print(\'Using \${result.chosenImplementation} due to missing browser \'\n \'features: \${result.missingFeatures}\');\n }\n\n return result.resolvedExecutor;\n }));\n}\n\n// You can then use this method to open your database:\nclass MyWebDatabase extends _\$MyWebDatabase {\n MyWebDatabase._(super.e);\n\n factory MyWebDatabase() => MyWebDatabase._(connectOnWeb());\n // ...\n\n @override\n Iterable<TableInfo<Table, dynamic>> get allTables =>\n throw UnimplementedError();\n\n @override\n int get schemaVersion => throw UnimplementedError();\n}\n\nQueryExecutor connectWithDriftFlutter() {\n return driftDatabase(\n name: \'my_app_db\',\n web: DriftWebOptions(\n sqlite3Wasm: Uri.parse(\'sqlite3.wasm\'),\n driftWorker: Uri.parse(\'drift_worker.dart.js\'),\n ),\n );\n}\n\nDatabaseConnection connectWithExisting() {\n return DatabaseConnection.delayed(Future(() async {\n final result = await WasmDatabase.open(\n databaseName: \'my_app_db\', // prefer to only use valid identifiers here\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n initializeDatabase: () async {\n final data = await rootBundle.load(\'my_database\');\n return data.buffer.asUint8List();\n },\n );\n\n // ...\n return result.resolvedExecutor;\n }));\n}\n\n// If you\'ve previously opened your database like this\nFuture<WasmDatabase> customDatabase() async {\n final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse(\'/sqlite3.wasm\'));\n final fs = await IndexedDbFileSystem.open(dbName: \'my_app\');\n sqlite3.registerVirtualFileSystem(fs, makeDefault: true);\n\n return WasmDatabase(\n sqlite3: sqlite3,\n path: \'/app.db\',\n );\n}\n\nDatabaseConnection migrateAndConnect() {\n return DatabaseConnection.delayed(Future(() async {\n // Then you can migrate like this\n final result = await WasmDatabase.open(\n databaseName: \'my_app\',\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n initializeDatabase: () async {\n // Manually open the file system previously used\n final fs = await IndexedDbFileSystem.open(dbName: \'my_app\');\n const oldPath = \'/app.db\'; // The path passed to WasmDatabase before\n\n Uint8List? oldDatabase;\n\n // Check if the old database exists\n if (fs.xAccess(oldPath, 0) != 0) {\n // It does, then copy the old file\n final (file: file, outFlags: _) =\n fs.xOpen(Sqlite3Filename(oldPath), 0);\n final blob = Uint8List(file.xFileSize());\n file.xRead(blob, 0);\n file.xClose();\n fs.xDelete(oldPath, 0);\n\n oldDatabase = blob;\n }\n\n await fs.close();\n return oldDatabase;\n },\n );\n\n return result.resolvedExecutor;\n }));\n}\n\nDatabaseConnection migrateFromLegacy() {\n return DatabaseConnection.delayed(Future(() async {\n final result = await WasmDatabase.open(\n databaseName: \'my_app\',\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n initializeDatabase: () async {\n final storage = await DriftWebStorage.indexedDbIfSupported(\'old_db\');\n await storage.open();\n\n final blob = await storage.restore();\n await storage.close();\n\n return blob;\n },\n );\n\n return result.resolvedExecutor;\n }));\n}\n\nvoid setupDatabase(CommonDatabase database) {\n database.createFunction(\n functionName: \'my_function\',\n function: (args) => args.length,\n );\n}\n\nvoid main() {\n WasmDatabase.workerMainForOpen(\n setupAllDatabases: setupDatabase,\n );\n}\n\nvoid withSetup() async {\n final result = await WasmDatabase.open(\n databaseName: \'my_app_db\', // prefer to only use valid identifiers here\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'my_drift_worker.dart.js\'),\n localSetup: setupDatabase,\n );\n print(result);\n}\n','connect': 'DatabaseConnection connectOnWeb() {\n return DatabaseConnection.delayed(Future(() async {\n final result = await WasmDatabase.open(\n databaseName: \'my_app_db\', // prefer to only use valid identifiers here\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n );\n\n if (result.missingFeatures.isNotEmpty) {\n // Depending how central local persistence is to your app, you may want\n // to show a warning to the user if only unrealiable implemetentations\n // are available.\n print(\'Using \${result.chosenImplementation} due to missing browser \'\n \'features: \${result.missingFeatures}\');\n }\n\n return result.resolvedExecutor;\n }));\n}\n\n// You can then use this method to open your database:\nclass MyWebDatabase extends _\$MyWebDatabase {\n MyWebDatabase._(super.e);\n\n factory MyWebDatabase() => MyWebDatabase._(connectOnWeb());\n // ...\n}\n','flutter': 'QueryExecutor connectWithDriftFlutter() {\n return driftDatabase(\n name: \'my_app_db\',\n web: DriftWebOptions(\n sqlite3Wasm: Uri.parse(\'sqlite3.wasm\'),\n driftWorker: Uri.parse(\'drift_worker.dart.js\'),\n ),\n );\n}\n','existing': ' return DatabaseConnection.delayed(Future(() async {\n final result = await WasmDatabase.open(\n databaseName: \'my_app_db\', // prefer to only use valid identifiers here\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n initializeDatabase: () async {\n final data = await rootBundle.load(\'my_database\');\n return data.buffer.asUint8List();\n },\n );\n\n // ...\n return result.resolvedExecutor;\n }));\n','migrate-wasm': '// If you\'ve previously opened your database like this\nFuture<WasmDatabase> customDatabase() async {\n final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse(\'/sqlite3.wasm\'));\n final fs = await IndexedDbFileSystem.open(dbName: \'my_app\');\n sqlite3.registerVirtualFileSystem(fs, makeDefault: true);\n\n return WasmDatabase(\n sqlite3: sqlite3,\n path: \'/app.db\',\n );\n}\n // Then you can migrate like this\n final result = await WasmDatabase.open(\n databaseName: \'my_app\',\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n initializeDatabase: () async {\n // Manually open the file system previously used\n final fs = await IndexedDbFileSystem.open(dbName: \'my_app\');\n const oldPath = \'/app.db\'; // The path passed to WasmDatabase before\n\n Uint8List? oldDatabase;\n\n // Check if the old database exists\n if (fs.xAccess(oldPath, 0) != 0) {\n // It does, then copy the old file\n final (file: file, outFlags: _) =\n fs.xOpen(Sqlite3Filename(oldPath), 0);\n final blob = Uint8List(file.xFileSize());\n file.xRead(blob, 0);\n file.xClose();\n fs.xDelete(oldPath, 0);\n\n oldDatabase = blob;\n }\n\n await fs.close();\n return oldDatabase;\n },\n );\n','migrate-legacy': ' final result = await WasmDatabase.open(\n databaseName: \'my_app\',\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'drift_worker.dart.js\'),\n initializeDatabase: () async {\n final storage = await DriftWebStorage.indexedDbIfSupported(\'old_db\');\n await storage.open();\n\n final blob = await storage.restore();\n await storage.close();\n\n return blob;\n },\n );\n','setupAll': 'void setupDatabase(CommonDatabase database) {\n database.createFunction(\n functionName: \'my_function\',\n function: (args) => args.length,\n );\n}\n\nvoid main() {\n WasmDatabase.workerMainForOpen(\n setupAllDatabases: setupDatabase,\n );\n}\n','setupLocal': ' final result = await WasmDatabase.open(\n databaseName: \'my_app_db\', // prefer to only use valid identifiers here\n sqlite3Uri: Uri.parse(\'sqlite3.wasm\'),\n driftWorkerUri: Uri.parse(\'my_drift_worker.dart.js\'),\n localSetup: setupDatabase,\n );\n',}, 'lib/src/snippets/platforms/workers.dart.snippet.json': {'(full)': '// Note: This snippet describes a legacy API! Please consider migrating to\n// `package:drift/wasm.dart`, which has builtin support for web workers!\nimport \'dart:html\'; // ignore: deprecated_member_use\n\nimport \'package:drift/drift.dart\';\nimport \'package:drift/web.dart\'; // ignore: deprecated_member_use\nimport \'package:drift/web/worker.dart\'; // ignore: deprecated_member_use\n\nvoid main() {\n // Load sql.js library in the worker\n WorkerGlobalScope.instance.importScripts(\'sql-wasm.js\');\n\n // Call drift function that will set up this worker\n driftWorkerMain(() {\n return WebDatabase.withStorage(DriftWebStorage.indexedDb(\'worker\',\n migrateFromLocalStorage: false, inWebWorker: true));\n });\n}\n\nDatabaseConnection connectToWorker() {\n return DatabaseConnection.delayed(connectToDriftWorker(\n \'worker.dart.js\',\n // Note that SharedWorkers may not be available on all browsers and platforms.\n mode: DriftWorkerMode.shared,\n ));\n}\n','worker': '// Note: This snippet describes a legacy API! Please consider migrating to\n// `package:drift/wasm.dart`, which has builtin support for web workers!\nimport \'dart:html\'; // ignore: deprecated_member_use\n\nimport \'package:drift/drift.dart\';\nimport \'package:drift/web.dart\'; // ignore: deprecated_member_use\nimport \'package:drift/web/worker.dart\'; // ignore: deprecated_member_use\n\nvoid main() {\n // Load sql.js library in the worker\n WorkerGlobalScope.instance.importScripts(\'sql-wasm.js\');\n\n // Call drift function that will set up this worker\n driftWorkerMain(() {\n return WebDatabase.withStorage(DriftWebStorage.indexedDb(\'worker\',\n migrateFromLocalStorage: false, inWebWorker: true));\n });\n}\n','client': 'DatabaseConnection connectToWorker() {\n return DatabaseConnection.delayed(connectToDriftWorker(\n \'worker.dart.js\',\n // Note that SharedWorkers may not be available on all browsers and platforms.\n mode: DriftWorkerMode.shared,\n ));\n}\n',}, 'lib/src/snippets/platforms/new_connect.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n// ignore: deprecated_member_use\nimport \'package:drift/web/worker.dart\';\n\nclass Approach1 {\n Future<DatabaseConnection> connectToWorker() async {\n return await connectToDriftWorker(\'/database_worker.dart.js\',\n mode: DriftWorkerMode.dedicatedInShared);\n }\n}\n','approach1': ' Future<DatabaseConnection> connectToWorker() async {\n return await connectToDriftWorker(\'/database_worker.dart.js\',\n mode: DriftWorkerMode.dedicatedInShared);\n }\n',}, @@ -41,10 +51,37 @@ const generatedSnippets = { 'lib/src/snippets/type_converters/converters.dart.snippet.json': {'(full)': 'import \'dart:convert\';\n\nimport \'package:drift/drift.dart\';\nimport \'package:json_annotation/json_annotation.dart\' as j;\n\npart \'converters.g.dart\';\n\n@j.JsonSerializable()\nclass Preferences {\n bool receiveEmails;\n String selectedTheme;\n\n Preferences(this.receiveEmails, this.selectedTheme);\n\n factory Preferences.fromJson(Map<String, dynamic> json) =>\n _\$PreferencesFromJson(json);\n\n Map<String, dynamic> toJson() => _\$PreferencesToJson(this);\n\n static JsonTypeConverter2<Preferences, String, Object?> converter =\n TypeConverter.json2(\n fromJson: (json) => Preferences.fromJson(json as Map<String, Object?>),\n toJson: (pref) => pref.toJson(),\n );\n static JsonTypeConverter2<Preferences, Uint8List, Object?> binaryConverter =\n TypeConverter.jsonb(\n fromJson: (json) => Preferences.fromJson(json as Map<String, Object?>),\n toJson: (pref) => pref.toJson(),\n );\n}\n\n// stores preferences as strings\nclass PreferenceConverter extends TypeConverter<Preferences, String>\n with\n // (1)!\n JsonTypeConverter2<Preferences, String, Map<String, Object?>> {\n const PreferenceConverter();\n\n @override\n Preferences fromSql(String fromDb) {\n return fromJson(json.decode(fromDb) as Map<String, dynamic>);\n }\n\n @override\n String toSql(Preferences value) {\n return json.encode(toJson(value));\n }\n\n @override\n Preferences fromJson(Map<String, Object?> json) {\n return Preferences.fromJson(json);\n }\n\n @override\n Map<String, Object?> toJson(Preferences value) {\n return value.toJson();\n }\n}\n\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n\n TextColumn get preferences =>\n text().map(const PreferenceConverter()).nullable()();\n}\n','start': 'import \'dart:convert\';\n\nimport \'package:drift/drift.dart\';\nimport \'package:json_annotation/json_annotation.dart\' as j;\n\npart \'converters.g.dart\';\n\n@j.JsonSerializable()\nclass Preferences {\n bool receiveEmails;\n String selectedTheme;\n\n Preferences(this.receiveEmails, this.selectedTheme);\n\n factory Preferences.fromJson(Map<String, dynamic> json) =>\n _\$PreferencesFromJson(json);\n\n Map<String, dynamic> toJson() => _\$PreferencesToJson(this);\n}\n','simplified': ' static JsonTypeConverter2<Preferences, String, Object?> converter =\n TypeConverter.json2(\n fromJson: (json) => Preferences.fromJson(json as Map<String, Object?>),\n toJson: (pref) => pref.toJson(),\n );\n','jsonb': ' static JsonTypeConverter2<Preferences, Uint8List, Object?> binaryConverter =\n TypeConverter.jsonb(\n fromJson: (json) => Preferences.fromJson(json as Map<String, Object?>),\n toJson: (pref) => pref.toJson(),\n );\n','converter': '// stores preferences as strings\nclass PreferenceConverter extends TypeConverter<Preferences, String>\n with\n // (1)!\n JsonTypeConverter2<Preferences, String, Map<String, Object?>> {\n const PreferenceConverter();\n\n @override\n Preferences fromSql(String fromDb) {\n return fromJson(json.decode(fromDb) as Map<String, dynamic>);\n }\n\n @override\n String toSql(Preferences value) {\n return json.encode(toJson(value));\n }\n\n @override\n Preferences fromJson(Map<String, Object?> json) {\n return Preferences.fromJson(json);\n }\n\n @override\n Map<String, Object?> toJson(Preferences value) {\n return value.toJson();\n }\n}\n','table': 'class Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n\n TextColumn get preferences =>\n text().map(const PreferenceConverter()).nullable()();\n}\n',}, 'lib/src/snippets/log_interceptor.dart.snippet.json': {'(full)': 'import \'dart:async\';\nimport \'dart:io\';\n\nimport \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\n\nimport \'dart_api/manager.dart\';\n\nclass LogInterceptor extends QueryInterceptor {\n Future<T> _run<T>(\n String description, FutureOr<T> Function() operation) async {\n final stopwatch = Stopwatch()..start();\n print(\'Running \$description\');\n\n try {\n final result = await operation();\n print(\' => succeeded after \${stopwatch.elapsedMilliseconds}ms\');\n return result;\n } on Object catch (e) {\n print(\' => failed after \${stopwatch.elapsedMilliseconds}ms (\$e)\');\n rethrow;\n }\n }\n\n @override\n TransactionExecutor beginTransaction(QueryExecutor parent) {\n print(\'begin\');\n return super.beginTransaction(parent);\n }\n\n @override\n Future<void> commitTransaction(TransactionExecutor inner) {\n return _run(\'commit\', () => inner.send());\n }\n\n @override\n Future<void> rollbackTransaction(TransactionExecutor inner) {\n return _run(\'rollback\', () => inner.rollback());\n }\n\n @override\n Future<void> runBatched(\n QueryExecutor executor, BatchedStatements statements) {\n return _run(\n \'batch with \$statements\', () => executor.runBatched(statements));\n }\n\n @override\n Future<int> runInsert(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runInsert(statement, args));\n }\n\n @override\n Future<int> runUpdate(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runUpdate(statement, args));\n }\n\n @override\n Future<int> runDelete(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runDelete(statement, args));\n }\n\n @override\n Future<void> runCustom(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runCustom(statement, args));\n }\n\n @override\n Future<List<Map<String, Object?>>> runSelect(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runSelect(statement, args));\n }\n}\n\nvoid use() {\n final myDatabaseFile = File(\'/dev/null\');\n\n NativeDatabase.createInBackground(\n myDatabaseFile,\n ).interceptWith(LogInterceptor());\n}\n\nvoid useScoped() async {\n final database = AppDatabase(NativeDatabase.memory());\n\n final interceptor = LogInterceptor();\n await database.runWithInterceptor(interceptor: interceptor, () async {\n // Only database operations in this block will reach the interceptor.\n });\n}\n','class': 'class LogInterceptor extends QueryInterceptor {\n Future<T> _run<T>(\n String description, FutureOr<T> Function() operation) async {\n final stopwatch = Stopwatch()..start();\n print(\'Running \$description\');\n\n try {\n final result = await operation();\n print(\' => succeeded after \${stopwatch.elapsedMilliseconds}ms\');\n return result;\n } on Object catch (e) {\n print(\' => failed after \${stopwatch.elapsedMilliseconds}ms (\$e)\');\n rethrow;\n }\n }\n\n @override\n TransactionExecutor beginTransaction(QueryExecutor parent) {\n print(\'begin\');\n return super.beginTransaction(parent);\n }\n\n @override\n Future<void> commitTransaction(TransactionExecutor inner) {\n return _run(\'commit\', () => inner.send());\n }\n\n @override\n Future<void> rollbackTransaction(TransactionExecutor inner) {\n return _run(\'rollback\', () => inner.rollback());\n }\n\n @override\n Future<void> runBatched(\n QueryExecutor executor, BatchedStatements statements) {\n return _run(\n \'batch with \$statements\', () => executor.runBatched(statements));\n }\n\n @override\n Future<int> runInsert(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runInsert(statement, args));\n }\n\n @override\n Future<int> runUpdate(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runUpdate(statement, args));\n }\n\n @override\n Future<int> runDelete(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runDelete(statement, args));\n }\n\n @override\n Future<void> runCustom(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runCustom(statement, args));\n }\n\n @override\n Future<List<Map<String, Object?>>> runSelect(\n QueryExecutor executor, String statement, List<Object?> args) {\n return _run(\n \'\$statement with \$args\', () => executor.runSelect(statement, args));\n }\n}\n','use': ' NativeDatabase.createInBackground(\n myDatabaseFile,\n ).interceptWith(LogInterceptor());\n','runWithInterceptor': ' final interceptor = LogInterceptor();\n await database.runWithInterceptor(interceptor: interceptor, () async {\n // Only database operations in this block will reach the interceptor.\n });\n',}, 'lib/src/snippets/migrations/migrations.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'schema_versions.dart\';\n\npart \'migrations.g.dart\';\n\nconst kDebugMode = false;\n\nclass Todos extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 10)();\n TextColumn get content => text().named(\'body\')();\n IntColumn get category => integer().nullable()();\n DateTimeColumn get dueDate =>\n dateTime().nullable()(); // new, added column in v2\n IntColumn get priority => integer().nullable()(); // new, added column in v3\n}\n\n@DriftDatabase(tables: [Todos])\nclass MyDatabase extends _\$MyDatabase {\n MyDatabase(super.e);\n\n @override\n int get schemaVersion => 3; // bump because the tables have changed.\n\n @override\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (Migrator m) async {\n await m.createAll();\n },\n onUpgrade: (Migrator m, int from, int to) async {\n if (from < 2) {\n // we added the dueDate property in the change from version 1 to\n // version 2\n await m.addColumn(todos, todos.dueDate);\n }\n if (from < 3) {\n // we added the priority property in the change from version 1 or 2\n // to version 3\n await m.addColumn(todos, todos.priority);\n }\n },\n );\n }\n // The rest of the class can stay the same\n\n MigrationStrategy get withForeignKeyCheck {\n return MigrationStrategy(\n onUpgrade: (m, from, to) async {\n // disable foreign_keys before migrations\n await customStatement(\'PRAGMA foreign_keys = OFF\');\n\n await transaction(() async {\n // put your migration logic here\n });\n\n // Assert that the schema is valid after migrations\n if (kDebugMode) {\n final wrongForeignKeys =\n await customSelect(\'PRAGMA foreign_key_check\').get();\n assert(wrongForeignKeys.isEmpty,\n \'\${wrongForeignKeys.map((e) => e.data)}\');\n }\n },\n beforeOpen: (details) async {\n await customStatement(\'PRAGMA foreign_keys = ON\');\n // ....\n },\n );\n }\n\n Future<void> changeTypeSnippet() async {\n stepByStep(\n from1To2: (m, schema) async {\n await m.alterTable(\n TableMigration(schema.todos, columnTransformer: {\n todos.category: schema.todos.category.cast<int>(),\n }),\n );\n },\n from2To3: (m, schema) async {},\n );\n }\n}\n','table': 'class Todos extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get title => text().withLength(min: 6, max: 10)();\n TextColumn get content => text().named(\'body\')();\n IntColumn get category => integer().nullable()();\n DateTimeColumn get dueDate =>\n dateTime().nullable()(); // new, added column in v2\n IntColumn get priority => integer().nullable()(); // new, added column in v3\n}\n','start': ' @override\n int get schemaVersion => 3; // bump because the tables have changed.\n\n @override\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (Migrator m) async {\n await m.createAll();\n },\n onUpgrade: (Migrator m, int from, int to) async {\n if (from < 2) {\n // we added the dueDate property in the change from version 1 to\n // version 2\n await m.addColumn(todos, todos.dueDate);\n }\n if (from < 3) {\n // we added the priority property in the change from version 1 or 2\n // to version 3\n await m.addColumn(todos, todos.priority);\n }\n },\n );\n }\n // The rest of the class can stay the same\n','structured': ' return MigrationStrategy(\n onUpgrade: (m, from, to) async {\n // disable foreign_keys before migrations\n await customStatement(\'PRAGMA foreign_keys = OFF\');\n\n await transaction(() async {\n // put your migration logic here\n });\n\n // Assert that the schema is valid after migrations\n if (kDebugMode) {\n final wrongForeignKeys =\n await customSelect(\'PRAGMA foreign_key_check\').get();\n assert(wrongForeignKeys.isEmpty,\n \'\${wrongForeignKeys.map((e) => e.data)}\');\n }\n },\n beforeOpen: (details) async {\n await customStatement(\'PRAGMA foreign_keys = ON\');\n // ....\n },\n );\n','change_type': ' from1To2: (m, schema) async {\n await m.alterTable(\n TableMigration(schema.todos, columnTransformer: {\n todos.category: schema.todos.category.cast<int>(),\n }),\n );\n },\n',}, +'lib/src/snippets/migrations/schema_versions.dart.snippet.json': {'(full)': '// dart format width=80\nimport \'package:drift/internal/versioned_schema.dart\' as i0;\nimport \'package:drift/drift.dart\' as i1;\nimport \'package:drift/drift.dart\'; // ignore_for_file: type=lint,unused_import\n\n// GENERATED BY drift_dev, DO NOT MODIFY.\nfinal class Schema2 extends i0.VersionedSchema {\n Schema2({required super.database}) : super(version: 2);\n @override\n late final List<i1.DatabaseSchemaEntity> entities = [\n todos,\n ];\n late final Shape0 todos = Shape0(\n source: i0.VersionedTable(\n entityName: \'todos\',\n withoutRowId: false,\n isStrict: false,\n tableConstraints: [],\n columns: [\n _column_0,\n _column_1,\n _column_2,\n _column_3,\n _column_4,\n ],\n attachedDatabase: database,\n ),\n alias: null);\n}\n\nclass Shape0 extends i0.VersionedTable {\n Shape0({required super.source, required super.alias}) : super.aliased();\n i1.GeneratedColumn<int> get id =>\n columnsByName[\'id\']! as i1.GeneratedColumn<int>;\n i1.GeneratedColumn<String> get title =>\n columnsByName[\'title\']! as i1.GeneratedColumn<String>;\n i1.GeneratedColumn<String> get content =>\n columnsByName[\'body\']! as i1.GeneratedColumn<String>;\n i1.GeneratedColumn<int> get category =>\n columnsByName[\'category\']! as i1.GeneratedColumn<int>;\n i1.GeneratedColumn<DateTime> get dueDate =>\n columnsByName[\'due_date\']! as i1.GeneratedColumn<DateTime>;\n}\n\ni1.GeneratedColumn<int> _column_0(String aliasedName) =>\n i1.GeneratedColumn<int>(\'id\', aliasedName, false,\n hasAutoIncrement: true,\n type: i1.DriftSqlType.int,\n defaultConstraints:\n i1.GeneratedColumn.constraintIsAlways(\'PRIMARY KEY AUTOINCREMENT\'));\ni1.GeneratedColumn<String> _column_1(String aliasedName) =>\n i1.GeneratedColumn<String>(\'title\', aliasedName, false,\n additionalChecks: i1.GeneratedColumn.checkTextLength(\n minTextLength: 6, maxTextLength: 10),\n type: i1.DriftSqlType.string);\ni1.GeneratedColumn<String> _column_2(String aliasedName) =>\n i1.GeneratedColumn<String>(\'body\', aliasedName, false,\n type: i1.DriftSqlType.string);\ni1.GeneratedColumn<int> _column_3(String aliasedName) =>\n i1.GeneratedColumn<int>(\'category\', aliasedName, true,\n type: i1.DriftSqlType.int);\ni1.GeneratedColumn<DateTime> _column_4(String aliasedName) =>\n i1.GeneratedColumn<DateTime>(\'due_date\', aliasedName, true,\n type: i1.DriftSqlType.dateTime);\n\nfinal class Schema3 extends i0.VersionedSchema {\n Schema3({required super.database}) : super(version: 3);\n @override\n late final List<i1.DatabaseSchemaEntity> entities = [\n todos,\n ];\n late final Shape1 todos = Shape1(\n source: i0.VersionedTable(\n entityName: \'todos\',\n withoutRowId: false,\n isStrict: false,\n tableConstraints: [],\n columns: [\n _column_0,\n _column_1,\n _column_2,\n _column_3,\n _column_4,\n _column_5,\n ],\n attachedDatabase: database,\n ),\n alias: null);\n}\n\nclass Shape1 extends i0.VersionedTable {\n Shape1({required super.source, required super.alias}) : super.aliased();\n i1.GeneratedColumn<int> get id =>\n columnsByName[\'id\']! as i1.GeneratedColumn<int>;\n i1.GeneratedColumn<String> get title =>\n columnsByName[\'title\']! as i1.GeneratedColumn<String>;\n i1.GeneratedColumn<String> get content =>\n columnsByName[\'body\']! as i1.GeneratedColumn<String>;\n i1.GeneratedColumn<int> get category =>\n columnsByName[\'category\']! as i1.GeneratedColumn<int>;\n i1.GeneratedColumn<DateTime> get dueDate =>\n columnsByName[\'due_date\']! as i1.GeneratedColumn<DateTime>;\n i1.GeneratedColumn<int> get priority =>\n columnsByName[\'priority\']! as i1.GeneratedColumn<int>;\n}\n\ni1.GeneratedColumn<int> _column_5(String aliasedName) =>\n i1.GeneratedColumn<int>(\'priority\', aliasedName, true,\n type: i1.DriftSqlType.int);\ni0.MigrationStepWithVersion migrationSteps({\n required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,\n required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,\n}) {\n return (currentVersion, database) async {\n switch (currentVersion) {\n case 1:\n final schema = Schema2(database: database);\n final migrator = i1.Migrator(database, schema);\n await from1To2(migrator, schema);\n return 2;\n case 2:\n final schema = Schema3(database: database);\n final migrator = i1.Migrator(database, schema);\n await from2To3(migrator, schema);\n return 3;\n default:\n throw ArgumentError.value(\'Unknown migration from \$currentVersion\');\n }\n };\n}\n\ni1.OnUpgrade stepByStep({\n required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,\n required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,\n}) =>\n i0.VersionedSchema.stepByStepHelper(\n step: migrationSteps(\n from1To2: from1To2,\n from2To3: from2To3,\n ));\n',}, 'lib/src/snippets/migrations/step_by_step.dart.snippet.json': {'(full)': 'import \'dart:math\' as math;\n\nimport \'package:drift/drift.dart\';\n\nimport \'migrations.dart\';\n\n// This file was generated by `drift_dev schema steps drift_schemas/ lib/database/schema_versions.dart`\nimport \'schema_versions.dart\';\n\n\nclass StepByStep {\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (Migrator m) async {\n await m.createAll();\n },\n onUpgrade: stepByStep(\n from1To2: (m, schema) async {\n // we added the dueDate property in the change from version 1 to\n // version 2\n await m.addColumn(schema.todos, schema.todos.dueDate);\n },\n from2To3: (m, schema) async {\n // we added the priority property in the change from version 1 or 2\n // to version 3\n await m.addColumn(schema.todos, schema.todos.priority);\n },\n ),\n );\n }\n}\n\nextension StepByStep2 on GeneratedDatabase {\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (Migrator m) async {\n await m.createAll();\n },\n onUpgrade: (m, from, to) async {\n // Run migration steps without foreign keys and re-enable them later\n // (https://drift.simonbinder.eu/docs/advanced-features/migrations/#tips)\n await customStatement(\'PRAGMA foreign_keys = OFF\');\n\n await m.runMigrationSteps(\n from: from,\n to: to,\n steps: migrationSteps(\n from1To2: (m, schema) async {\n // we added the dueDate property in the change from version 1 to\n // version 2\n await m.addColumn(schema.todos, schema.todos.dueDate);\n },\n from2To3: (m, schema) async {\n // we added the priority property in the change from version 1 or 2\n // to version 3\n await m.addColumn(schema.todos, schema.todos.priority);\n },\n ),\n );\n\n if (kDebugMode) {\n // Fail if the migration broke foreign keys\n final wrongForeignKeys =\n await customSelect(\'PRAGMA foreign_key_check\').get();\n assert(wrongForeignKeys.isEmpty,\n \'\${wrongForeignKeys.map((e) => e.data)}\');\n }\n\n await customStatement(\'PRAGMA foreign_keys = ON;\');\n },\n );\n }\n}\n\nextension StepByStep3 on MyDatabase {\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (Migrator m) async {\n await m.createAll();\n },\n onUpgrade: (m, from, to) async {\n // Run migration steps without foreign keys and re-enable them later\n // (https://drift.simonbinder.eu/docs/advanced-features/migrations/#tips)\n await customStatement(\'PRAGMA foreign_keys = OFF\');\n\n // Manually running migrations up to schema version 2, after which we\'ve\n // enabled step-by-step migrations.\n if (from < 2) {\n // we added the dueDate property in the change from version 1 to\n // version 2 - before switching to step-by-step migrations.\n await m.addColumn(todos, todos.dueDate);\n }\n\n // At this point, we should be migrated to schema 3. For future schema\n // changes, we will "start" at schema 3.\n await m.runMigrationSteps(\n from: math.max(2, from),\n to: to,\n steps: migrationSteps(\n from1To2: (m, schema) async {\n throw \'users would not have this as v2 would be their first schema\';\n },\n from2To3: (m, schema) async {\n // we added the priority property in the change from version 1 or\n // 2 to version 3\n await m.addColumn(schema.todos, schema.todos.priority);\n },\n ),\n );\n\n if (kDebugMode) {\n // Fail if the migration broke foreign keys\n final wrongForeignKeys =\n await customSelect(\'PRAGMA foreign_key_check\').get();\n assert(wrongForeignKeys.isEmpty,\n \'\${wrongForeignKeys.map((e) => e.data)}\');\n }\n\n await customStatement(\'PRAGMA foreign_keys = ON;\');\n },\n );\n }\n}\n','stepbystep': '// This file was generated by `drift_dev schema steps drift_schemas/ lib/database/schema_versions.dart`\nimport \'schema_versions.dart\';\n\n MigrationStrategy get migration {\n return MigrationStrategy(\n onCreate: (Migrator m) async {\n await m.createAll();\n },\n onUpgrade: stepByStep(\n from1To2: (m, schema) async {\n // we added the dueDate property in the change from version 1 to\n // version 2\n await m.addColumn(schema.todos, schema.todos.dueDate);\n },\n from2To3: (m, schema) async {\n // we added the priority property in the change from version 1 or 2\n // to version 3\n await m.addColumn(schema.todos, schema.todos.priority);\n },\n ),\n );\n }\n','stepbystep2': ' onUpgrade: (m, from, to) async {\n // Run migration steps without foreign keys and re-enable them later\n // (https://drift.simonbinder.eu/docs/advanced-features/migrations/#tips)\n await customStatement(\'PRAGMA foreign_keys = OFF\');\n\n await m.runMigrationSteps(\n from: from,\n to: to,\n steps: migrationSteps(\n from1To2: (m, schema) async {\n // we added the dueDate property in the change from version 1 to\n // version 2\n await m.addColumn(schema.todos, schema.todos.dueDate);\n },\n from2To3: (m, schema) async {\n // we added the priority property in the change from version 1 or 2\n // to version 3\n await m.addColumn(schema.todos, schema.todos.priority);\n },\n ),\n );\n\n if (kDebugMode) {\n // Fail if the migration broke foreign keys\n final wrongForeignKeys =\n await customSelect(\'PRAGMA foreign_key_check\').get();\n assert(wrongForeignKeys.isEmpty,\n \'\${wrongForeignKeys.map((e) => e.data)}\');\n }\n\n await customStatement(\'PRAGMA foreign_keys = ON;\');\n },\n','stepbystep3': ' onUpgrade: (m, from, to) async {\n // Run migration steps without foreign keys and re-enable them later\n // (https://drift.simonbinder.eu/docs/advanced-features/migrations/#tips)\n await customStatement(\'PRAGMA foreign_keys = OFF\');\n\n // Manually running migrations up to schema version 2, after which we\'ve\n // enabled step-by-step migrations.\n if (from < 2) {\n // we added the dueDate property in the change from version 1 to\n // version 2 - before switching to step-by-step migrations.\n await m.addColumn(todos, todos.dueDate);\n }\n\n // At this point, we should be migrated to schema 3. For future schema\n // changes, we will "start" at schema 3.\n await m.runMigrationSteps(\n from: math.max(2, from),\n to: to,\n steps: migrationSteps(\n from2To3: (m, schema) async {\n // we added the priority property in the change from version 1 or\n // 2 to version 3\n await m.addColumn(schema.todos, schema.todos.priority);\n },\n ),\n );\n\n if (kDebugMode) {\n // Fail if the migration broke foreign keys\n final wrongForeignKeys =\n await customSelect(\'PRAGMA foreign_key_check\').get();\n assert(wrongForeignKeys.isEmpty,\n \'\${wrongForeignKeys.map((e) => e.data)}\');\n }\n\n await customStatement(\'PRAGMA foreign_keys = ON;\');\n },\n',}, 'lib/src/snippets/migrations/tests/schema_test.dart.snippet.json': {'(full)': 'import \'package:test/test.dart\';\nimport \'package:drift_dev/api/migrations_native.dart\';\n\n// The generated directory from before.\nimport \'generated_migrations/schema.dart\';\n\nimport \'../migrations.dart\';\n\nvoid main() {\n late SchemaVerifier verifier;\n\n setUpAll(() {\n // GeneratedHelper() was generated by drift, the verifier is an api\n // provided by drift_dev.\n verifier = SchemaVerifier(GeneratedHelper());\n });\n\n test(\'upgrade from v1 to v2\', () async {\n // Use startAt(1) to obtain a database connection with all tables\n // from the v1 schema.\n final connection = await verifier.startAt(1);\n final db = MyDatabase(connection);\n\n // Use this to run a migration to v2 and then validate that the\n // database has the expected schema.\n await verifier.migrateAndValidate(db, 2);\n });\n}\n','setup': 'import \'package:test/test.dart\';\nimport \'package:drift_dev/api/migrations_native.dart\';\n\n// The generated directory from before.\nimport \'generated_migrations/schema.dart\';\n\n\nvoid main() {\n late SchemaVerifier verifier;\n\n setUpAll(() {\n // GeneratedHelper() was generated by drift, the verifier is an api\n // provided by drift_dev.\n verifier = SchemaVerifier(GeneratedHelper());\n });\n\n test(\'upgrade from v1 to v2\', () async {\n // Use startAt(1) to obtain a database connection with all tables\n // from the v1 schema.\n final connection = await verifier.startAt(1);\n final db = MyDatabase(connection);\n\n // Use this to run a migration to v2 and then validate that the\n // database has the expected schema.\n await verifier.migrateAndValidate(db, 2);\n });\n}\n',}, 'lib/src/snippets/migrations/tests/verify_data_integrity_test.dart.snippet.json': {'(full)': 'import \'package:test/test.dart\';\nimport \'package:drift_dev/api/migrations_native.dart\';\n\nimport \'../migrations.dart\';\nimport \'generated_migrations/schema.dart\';\n\nimport \'generated_migrations/schema_v1.dart\' as v1;\nimport \'generated_migrations/schema_v2.dart\' as v2;\n\nvoid main() {\n late SchemaVerifier verifier;\n\n setUpAll(() {\n // GeneratedHelper() was generated by drift, the verifier is an api\n // provided by drift_dev.\n verifier = SchemaVerifier(GeneratedHelper());\n });\n\n // ...\n test(\'upgrade from v1 to v2\', () async {\n final schema = await verifier.schemaAt(1);\n\n // Add some data to the table being migrated\n final oldDb = v1.DatabaseAtV1(schema.newConnection());\n await oldDb.into(oldDb.todos).insert(v1.TodosCompanion.insert(\n title: \'my first todo entry\',\n content: \'should still be there after the migration\',\n ));\n await oldDb.close();\n\n // Run the migration and verify that it adds the name column.\n final db = MyDatabase(schema.newConnection());\n await verifier.migrateAndValidate(db, 2);\n await db.close();\n\n // Make sure the entry is still here\n final migratedDb = v2.DatabaseAtV2(schema.newConnection());\n final entry = await migratedDb.select(migratedDb.todos).getSingle();\n expect(entry.id, 1);\n expect(entry.dueDate, isNull); // default from the migration\n await migratedDb.close();\n });\n}\n','imports': 'import \'generated_migrations/schema_v1.dart\' as v1;\nimport \'generated_migrations/schema_v2.dart\' as v2;\n','main': 'void main() {\n // ...\n test(\'upgrade from v1 to v2\', () async {\n final schema = await verifier.schemaAt(1);\n\n // Add some data to the table being migrated\n final oldDb = v1.DatabaseAtV1(schema.newConnection());\n await oldDb.into(oldDb.todos).insert(v1.TodosCompanion.insert(\n title: \'my first todo entry\',\n content: \'should still be there after the migration\',\n ));\n await oldDb.close();\n\n // Run the migration and verify that it adds the name column.\n final db = MyDatabase(schema.newConnection());\n await verifier.migrateAndValidate(db, 2);\n await db.close();\n\n // Make sure the entry is still here\n final migratedDb = v2.DatabaseAtV2(schema.newConnection());\n final entry = await migratedDb.select(migratedDb.todos).getSingle();\n expect(entry.id, 1);\n expect(entry.dueDate, isNull); // default from the migration\n await migratedDb.close();\n });\n}\n',}, +'lib/src/snippets/migrations/tests/generated_migrations/schema.dart.snippet.json': {'(full)': '// dart format width=80\n// GENERATED CODE, DO NOT EDIT BY HAND.\n// ignore_for_file: type=lint\nimport \'package:drift/drift.dart\';\nimport \'package:drift/internal/migrations.dart\';\nimport \'schema_v1.dart\' as v1;\nimport \'schema_v2.dart\' as v2;\nimport \'schema_v3.dart\' as v3;\n\nclass GeneratedHelper implements SchemaInstantiationHelper {\n @override\n GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {\n switch (version) {\n case 1:\n return v1.DatabaseAtV1(db);\n case 2:\n return v2.DatabaseAtV2(db);\n case 3:\n return v3.DatabaseAtV3(db);\n default:\n throw MissingSchemaException(version, versions);\n }\n }\n\n static const versions = const [1, 2, 3];\n}\n',}, +'lib/src/snippets/migrations/tests/generated_migrations/schema_v2.dart.snippet.json': {'(full)': '// dart format width=80\n// GENERATED CODE, DO NOT EDIT BY HAND.\n// ignore_for_file: type=lint\nimport \'package:drift/drift.dart\';\n\nclass Todos extends Table with TableInfo<Todos, TodosData> {\n @override\n final GeneratedDatabase attachedDatabase;\n final String? _alias;\n Todos(this.attachedDatabase, [this._alias]);\n late final GeneratedColumn<int> id = GeneratedColumn<int>(\n \'id\', aliasedName, false,\n hasAutoIncrement: true,\n type: DriftSqlType.int,\n requiredDuringInsert: false,\n defaultConstraints:\n GeneratedColumn.constraintIsAlways(\'PRIMARY KEY AUTOINCREMENT\'));\n late final GeneratedColumn<String> title = GeneratedColumn<String>(\n \'title\', aliasedName, false,\n additionalChecks:\n GeneratedColumn.checkTextLength(minTextLength: 6, maxTextLength: 10),\n type: DriftSqlType.string,\n requiredDuringInsert: true);\n late final GeneratedColumn<String> content = GeneratedColumn<String>(\n \'body\', aliasedName, false,\n type: DriftSqlType.string, requiredDuringInsert: true);\n late final GeneratedColumn<int> category = GeneratedColumn<int>(\n \'category\', aliasedName, true,\n type: DriftSqlType.int, requiredDuringInsert: false);\n late final GeneratedColumn<DateTime> dueDate = GeneratedColumn<DateTime>(\n \'due_date\', aliasedName, true,\n type: DriftSqlType.dateTime, requiredDuringInsert: false);\n @override\n List<GeneratedColumn> get \$columns => [id, title, content, category, dueDate];\n @override\n String get aliasedName => _alias ?? actualTableName;\n @override\n String get actualTableName => \$name;\n static const String \$name = \'todos\';\n @override\n Set<GeneratedColumn> get \$primaryKey => {id};\n @override\n TodosData map(Map<String, dynamic> data, {String? tablePrefix}) {\n final effectivePrefix = tablePrefix != null ? \'\$tablePrefix.\' : \'\';\n return TodosData(\n id: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}id\'])!,\n title: attachedDatabase.typeMapping\n .read(DriftSqlType.string, data[\'\${effectivePrefix}title\'])!,\n content: attachedDatabase.typeMapping\n .read(DriftSqlType.string, data[\'\${effectivePrefix}body\'])!,\n category: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}category\']),\n dueDate: attachedDatabase.typeMapping\n .read(DriftSqlType.dateTime, data[\'\${effectivePrefix}due_date\']),\n );\n }\n\n @override\n Todos createAlias(String alias) {\n return Todos(attachedDatabase, alias);\n }\n}\n\nclass TodosData extends DataClass implements Insertable<TodosData> {\n final int id;\n final String title;\n final String content;\n final int? category;\n final DateTime? dueDate;\n const TodosData(\n {required this.id,\n required this.title,\n required this.content,\n this.category,\n this.dueDate});\n @override\n Map<String, Expression> toColumns(bool nullToAbsent) {\n final map = <String, Expression>{};\n map[\'id\'] = Variable<int>(id);\n map[\'title\'] = Variable<String>(title);\n map[\'body\'] = Variable<String>(content);\n if (!nullToAbsent || category != null) {\n map[\'category\'] = Variable<int>(category);\n }\n if (!nullToAbsent || dueDate != null) {\n map[\'due_date\'] = Variable<DateTime>(dueDate);\n }\n return map;\n }\n\n TodosCompanion toCompanion(bool nullToAbsent) {\n return TodosCompanion(\n id: Value(id),\n title: Value(title),\n content: Value(content),\n category: category == null && nullToAbsent\n ? const Value.absent()\n : Value(category),\n dueDate: dueDate == null && nullToAbsent\n ? const Value.absent()\n : Value(dueDate),\n );\n }\n\n factory TodosData.fromJson(Map<String, dynamic> json,\n {ValueSerializer? serializer}) {\n serializer ??= driftRuntimeOptions.defaultSerializer;\n return TodosData(\n id: serializer.fromJson<int>(json[\'id\']),\n title: serializer.fromJson<String>(json[\'title\']),\n content: serializer.fromJson<String>(json[\'content\']),\n category: serializer.fromJson<int?>(json[\'category\']),\n dueDate: serializer.fromJson<DateTime?>(json[\'dueDate\']),\n );\n }\n @override\n Map<String, dynamic> toJson({ValueSerializer? serializer}) {\n serializer ??= driftRuntimeOptions.defaultSerializer;\n return <String, dynamic>{\n \'id\': serializer.toJson<int>(id),\n \'title\': serializer.toJson<String>(title),\n \'content\': serializer.toJson<String>(content),\n \'category\': serializer.toJson<int?>(category),\n \'dueDate\': serializer.toJson<DateTime?>(dueDate),\n };\n }\n\n TodosData copyWith(\n {int? id,\n String? title,\n String? content,\n Value<int?> category = const Value.absent(),\n Value<DateTime?> dueDate = const Value.absent()}) =>\n TodosData(\n id: id ?? this.id,\n title: title ?? this.title,\n content: content ?? this.content,\n category: category.present ? category.value : this.category,\n dueDate: dueDate.present ? dueDate.value : this.dueDate,\n );\n TodosData copyWithCompanion(TodosCompanion data) {\n return TodosData(\n id: data.id.present ? data.id.value : this.id,\n title: data.title.present ? data.title.value : this.title,\n content: data.content.present ? data.content.value : this.content,\n category: data.category.present ? data.category.value : this.category,\n dueDate: data.dueDate.present ? data.dueDate.value : this.dueDate,\n );\n }\n\n @override\n String toString() {\n return (StringBuffer(\'TodosData(\')\n ..write(\'id: \$id, \')\n ..write(\'title: \$title, \')\n ..write(\'content: \$content, \')\n ..write(\'category: \$category, \')\n ..write(\'dueDate: \$dueDate\')\n ..write(\')\'))\n .toString();\n }\n\n @override\n int get hashCode => Object.hash(id, title, content, category, dueDate);\n @override\n bool operator ==(Object other) =>\n identical(this, other) ||\n (other is TodosData &&\n other.id == this.id &&\n other.title == this.title &&\n other.content == this.content &&\n other.category == this.category &&\n other.dueDate == this.dueDate);\n}\n\nclass TodosCompanion extends UpdateCompanion<TodosData> {\n final Value<int> id;\n final Value<String> title;\n final Value<String> content;\n final Value<int?> category;\n final Value<DateTime?> dueDate;\n const TodosCompanion({\n this.id = const Value.absent(),\n this.title = const Value.absent(),\n this.content = const Value.absent(),\n this.category = const Value.absent(),\n this.dueDate = const Value.absent(),\n });\n TodosCompanion.insert({\n this.id = const Value.absent(),\n required String title,\n required String content,\n this.category = const Value.absent(),\n this.dueDate = const Value.absent(),\n }) : title = Value(title),\n content = Value(content);\n static Insertable<TodosData> custom({\n Expression<int>? id,\n Expression<String>? title,\n Expression<String>? content,\n Expression<int>? category,\n Expression<DateTime>? dueDate,\n }) {\n return RawValuesInsertable({\n if (id != null) \'id\': id,\n if (title != null) \'title\': title,\n if (content != null) \'body\': content,\n if (category != null) \'category\': category,\n if (dueDate != null) \'due_date\': dueDate,\n });\n }\n\n TodosCompanion copyWith(\n {Value<int>? id,\n Value<String>? title,\n Value<String>? content,\n Value<int?>? category,\n Value<DateTime?>? dueDate}) {\n return TodosCompanion(\n id: id ?? this.id,\n title: title ?? this.title,\n content: content ?? this.content,\n category: category ?? this.category,\n dueDate: dueDate ?? this.dueDate,\n );\n }\n\n @override\n Map<String, Expression> toColumns(bool nullToAbsent) {\n final map = <String, Expression>{};\n if (id.present) {\n map[\'id\'] = Variable<int>(id.value);\n }\n if (title.present) {\n map[\'title\'] = Variable<String>(title.value);\n }\n if (content.present) {\n map[\'body\'] = Variable<String>(content.value);\n }\n if (category.present) {\n map[\'category\'] = Variable<int>(category.value);\n }\n if (dueDate.present) {\n map[\'due_date\'] = Variable<DateTime>(dueDate.value);\n }\n return map;\n }\n\n @override\n String toString() {\n return (StringBuffer(\'TodosCompanion(\')\n ..write(\'id: \$id, \')\n ..write(\'title: \$title, \')\n ..write(\'content: \$content, \')\n ..write(\'category: \$category, \')\n ..write(\'dueDate: \$dueDate\')\n ..write(\')\'))\n .toString();\n }\n}\n\nclass DatabaseAtV2 extends GeneratedDatabase {\n DatabaseAtV2(QueryExecutor e) : super(e);\n late final Todos todos = Todos(this);\n @override\n Iterable<TableInfo<Table, Object?>> get allTables =>\n allSchemaEntities.whereType<TableInfo<Table, Object?>>();\n @override\n List<DatabaseSchemaEntity> get allSchemaEntities => [todos];\n @override\n int get schemaVersion => 2;\n}\n',}, +'lib/src/snippets/migrations/tests/generated_migrations/schema_v3.dart.snippet.json': {'(full)': '// dart format width=80\n// GENERATED CODE, DO NOT EDIT BY HAND.\n// ignore_for_file: type=lint\nimport \'package:drift/drift.dart\';\n\nclass Todos extends Table with TableInfo<Todos, TodosData> {\n @override\n final GeneratedDatabase attachedDatabase;\n final String? _alias;\n Todos(this.attachedDatabase, [this._alias]);\n late final GeneratedColumn<int> id = GeneratedColumn<int>(\n \'id\', aliasedName, false,\n hasAutoIncrement: true,\n type: DriftSqlType.int,\n requiredDuringInsert: false,\n defaultConstraints:\n GeneratedColumn.constraintIsAlways(\'PRIMARY KEY AUTOINCREMENT\'));\n late final GeneratedColumn<String> title = GeneratedColumn<String>(\n \'title\', aliasedName, false,\n additionalChecks:\n GeneratedColumn.checkTextLength(minTextLength: 6, maxTextLength: 10),\n type: DriftSqlType.string,\n requiredDuringInsert: true);\n late final GeneratedColumn<String> content = GeneratedColumn<String>(\n \'body\', aliasedName, false,\n type: DriftSqlType.string, requiredDuringInsert: true);\n late final GeneratedColumn<int> category = GeneratedColumn<int>(\n \'category\', aliasedName, true,\n type: DriftSqlType.int, requiredDuringInsert: false);\n late final GeneratedColumn<DateTime> dueDate = GeneratedColumn<DateTime>(\n \'due_date\', aliasedName, true,\n type: DriftSqlType.dateTime, requiredDuringInsert: false);\n late final GeneratedColumn<int> priority = GeneratedColumn<int>(\n \'priority\', aliasedName, true,\n type: DriftSqlType.int, requiredDuringInsert: false);\n @override\n List<GeneratedColumn> get \$columns =>\n [id, title, content, category, dueDate, priority];\n @override\n String get aliasedName => _alias ?? actualTableName;\n @override\n String get actualTableName => \$name;\n static const String \$name = \'todos\';\n @override\n Set<GeneratedColumn> get \$primaryKey => {id};\n @override\n TodosData map(Map<String, dynamic> data, {String? tablePrefix}) {\n final effectivePrefix = tablePrefix != null ? \'\$tablePrefix.\' : \'\';\n return TodosData(\n id: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}id\'])!,\n title: attachedDatabase.typeMapping\n .read(DriftSqlType.string, data[\'\${effectivePrefix}title\'])!,\n content: attachedDatabase.typeMapping\n .read(DriftSqlType.string, data[\'\${effectivePrefix}body\'])!,\n category: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}category\']),\n dueDate: attachedDatabase.typeMapping\n .read(DriftSqlType.dateTime, data[\'\${effectivePrefix}due_date\']),\n priority: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}priority\']),\n );\n }\n\n @override\n Todos createAlias(String alias) {\n return Todos(attachedDatabase, alias);\n }\n}\n\nclass TodosData extends DataClass implements Insertable<TodosData> {\n final int id;\n final String title;\n final String content;\n final int? category;\n final DateTime? dueDate;\n final int? priority;\n const TodosData(\n {required this.id,\n required this.title,\n required this.content,\n this.category,\n this.dueDate,\n this.priority});\n @override\n Map<String, Expression> toColumns(bool nullToAbsent) {\n final map = <String, Expression>{};\n map[\'id\'] = Variable<int>(id);\n map[\'title\'] = Variable<String>(title);\n map[\'body\'] = Variable<String>(content);\n if (!nullToAbsent || category != null) {\n map[\'category\'] = Variable<int>(category);\n }\n if (!nullToAbsent || dueDate != null) {\n map[\'due_date\'] = Variable<DateTime>(dueDate);\n }\n if (!nullToAbsent || priority != null) {\n map[\'priority\'] = Variable<int>(priority);\n }\n return map;\n }\n\n TodosCompanion toCompanion(bool nullToAbsent) {\n return TodosCompanion(\n id: Value(id),\n title: Value(title),\n content: Value(content),\n category: category == null && nullToAbsent\n ? const Value.absent()\n : Value(category),\n dueDate: dueDate == null && nullToAbsent\n ? const Value.absent()\n : Value(dueDate),\n priority: priority == null && nullToAbsent\n ? const Value.absent()\n : Value(priority),\n );\n }\n\n factory TodosData.fromJson(Map<String, dynamic> json,\n {ValueSerializer? serializer}) {\n serializer ??= driftRuntimeOptions.defaultSerializer;\n return TodosData(\n id: serializer.fromJson<int>(json[\'id\']),\n title: serializer.fromJson<String>(json[\'title\']),\n content: serializer.fromJson<String>(json[\'content\']),\n category: serializer.fromJson<int?>(json[\'category\']),\n dueDate: serializer.fromJson<DateTime?>(json[\'dueDate\']),\n priority: serializer.fromJson<int?>(json[\'priority\']),\n );\n }\n @override\n Map<String, dynamic> toJson({ValueSerializer? serializer}) {\n serializer ??= driftRuntimeOptions.defaultSerializer;\n return <String, dynamic>{\n \'id\': serializer.toJson<int>(id),\n \'title\': serializer.toJson<String>(title),\n \'content\': serializer.toJson<String>(content),\n \'category\': serializer.toJson<int?>(category),\n \'dueDate\': serializer.toJson<DateTime?>(dueDate),\n \'priority\': serializer.toJson<int?>(priority),\n };\n }\n\n TodosData copyWith(\n {int? id,\n String? title,\n String? content,\n Value<int?> category = const Value.absent(),\n Value<DateTime?> dueDate = const Value.absent(),\n Value<int?> priority = const Value.absent()}) =>\n TodosData(\n id: id ?? this.id,\n title: title ?? this.title,\n content: content ?? this.content,\n category: category.present ? category.value : this.category,\n dueDate: dueDate.present ? dueDate.value : this.dueDate,\n priority: priority.present ? priority.value : this.priority,\n );\n TodosData copyWithCompanion(TodosCompanion data) {\n return TodosData(\n id: data.id.present ? data.id.value : this.id,\n title: data.title.present ? data.title.value : this.title,\n content: data.content.present ? data.content.value : this.content,\n category: data.category.present ? data.category.value : this.category,\n dueDate: data.dueDate.present ? data.dueDate.value : this.dueDate,\n priority: data.priority.present ? data.priority.value : this.priority,\n );\n }\n\n @override\n String toString() {\n return (StringBuffer(\'TodosData(\')\n ..write(\'id: \$id, \')\n ..write(\'title: \$title, \')\n ..write(\'content: \$content, \')\n ..write(\'category: \$category, \')\n ..write(\'dueDate: \$dueDate, \')\n ..write(\'priority: \$priority\')\n ..write(\')\'))\n .toString();\n }\n\n @override\n int get hashCode =>\n Object.hash(id, title, content, category, dueDate, priority);\n @override\n bool operator ==(Object other) =>\n identical(this, other) ||\n (other is TodosData &&\n other.id == this.id &&\n other.title == this.title &&\n other.content == this.content &&\n other.category == this.category &&\n other.dueDate == this.dueDate &&\n other.priority == this.priority);\n}\n\nclass TodosCompanion extends UpdateCompanion<TodosData> {\n final Value<int> id;\n final Value<String> title;\n final Value<String> content;\n final Value<int?> category;\n final Value<DateTime?> dueDate;\n final Value<int?> priority;\n const TodosCompanion({\n this.id = const Value.absent(),\n this.title = const Value.absent(),\n this.content = const Value.absent(),\n this.category = const Value.absent(),\n this.dueDate = const Value.absent(),\n this.priority = const Value.absent(),\n });\n TodosCompanion.insert({\n this.id = const Value.absent(),\n required String title,\n required String content,\n this.category = const Value.absent(),\n this.dueDate = const Value.absent(),\n this.priority = const Value.absent(),\n }) : title = Value(title),\n content = Value(content);\n static Insertable<TodosData> custom({\n Expression<int>? id,\n Expression<String>? title,\n Expression<String>? content,\n Expression<int>? category,\n Expression<DateTime>? dueDate,\n Expression<int>? priority,\n }) {\n return RawValuesInsertable({\n if (id != null) \'id\': id,\n if (title != null) \'title\': title,\n if (content != null) \'body\': content,\n if (category != null) \'category\': category,\n if (dueDate != null) \'due_date\': dueDate,\n if (priority != null) \'priority\': priority,\n });\n }\n\n TodosCompanion copyWith(\n {Value<int>? id,\n Value<String>? title,\n Value<String>? content,\n Value<int?>? category,\n Value<DateTime?>? dueDate,\n Value<int?>? priority}) {\n return TodosCompanion(\n id: id ?? this.id,\n title: title ?? this.title,\n content: content ?? this.content,\n category: category ?? this.category,\n dueDate: dueDate ?? this.dueDate,\n priority: priority ?? this.priority,\n );\n }\n\n @override\n Map<String, Expression> toColumns(bool nullToAbsent) {\n final map = <String, Expression>{};\n if (id.present) {\n map[\'id\'] = Variable<int>(id.value);\n }\n if (title.present) {\n map[\'title\'] = Variable<String>(title.value);\n }\n if (content.present) {\n map[\'body\'] = Variable<String>(content.value);\n }\n if (category.present) {\n map[\'category\'] = Variable<int>(category.value);\n }\n if (dueDate.present) {\n map[\'due_date\'] = Variable<DateTime>(dueDate.value);\n }\n if (priority.present) {\n map[\'priority\'] = Variable<int>(priority.value);\n }\n return map;\n }\n\n @override\n String toString() {\n return (StringBuffer(\'TodosCompanion(\')\n ..write(\'id: \$id, \')\n ..write(\'title: \$title, \')\n ..write(\'content: \$content, \')\n ..write(\'category: \$category, \')\n ..write(\'dueDate: \$dueDate, \')\n ..write(\'priority: \$priority\')\n ..write(\')\'))\n .toString();\n }\n}\n\nclass DatabaseAtV3 extends GeneratedDatabase {\n DatabaseAtV3(QueryExecutor e) : super(e);\n late final Todos todos = Todos(this);\n @override\n Iterable<TableInfo<Table, Object?>> get allTables =>\n allSchemaEntities.whereType<TableInfo<Table, Object?>>();\n @override\n List<DatabaseSchemaEntity> get allSchemaEntities => [todos];\n @override\n int get schemaVersion => 3;\n}\n',}, +'lib/src/snippets/migrations/tests/generated_migrations/schema_v1.dart.snippet.json': {'(full)': '// dart format width=80\n// GENERATED CODE, DO NOT EDIT BY HAND.\n// ignore_for_file: type=lint\nimport \'package:drift/drift.dart\';\n\nclass Todos extends Table with TableInfo<Todos, TodosData> {\n @override\n final GeneratedDatabase attachedDatabase;\n final String? _alias;\n Todos(this.attachedDatabase, [this._alias]);\n late final GeneratedColumn<int> id = GeneratedColumn<int>(\n \'id\', aliasedName, false,\n hasAutoIncrement: true,\n type: DriftSqlType.int,\n requiredDuringInsert: false,\n defaultConstraints:\n GeneratedColumn.constraintIsAlways(\'PRIMARY KEY AUTOINCREMENT\'));\n late final GeneratedColumn<String> title = GeneratedColumn<String>(\n \'title\', aliasedName, false,\n additionalChecks:\n GeneratedColumn.checkTextLength(minTextLength: 6, maxTextLength: 10),\n type: DriftSqlType.string,\n requiredDuringInsert: true);\n late final GeneratedColumn<String> content = GeneratedColumn<String>(\n \'body\', aliasedName, false,\n type: DriftSqlType.string, requiredDuringInsert: true);\n late final GeneratedColumn<int> category = GeneratedColumn<int>(\n \'category\', aliasedName, true,\n type: DriftSqlType.int, requiredDuringInsert: false);\n @override\n List<GeneratedColumn> get \$columns => [id, title, content, category];\n @override\n String get aliasedName => _alias ?? actualTableName;\n @override\n String get actualTableName => \$name;\n static const String \$name = \'todos\';\n @override\n Set<GeneratedColumn> get \$primaryKey => {id};\n @override\n TodosData map(Map<String, dynamic> data, {String? tablePrefix}) {\n final effectivePrefix = tablePrefix != null ? \'\$tablePrefix.\' : \'\';\n return TodosData(\n id: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}id\'])!,\n title: attachedDatabase.typeMapping\n .read(DriftSqlType.string, data[\'\${effectivePrefix}title\'])!,\n content: attachedDatabase.typeMapping\n .read(DriftSqlType.string, data[\'\${effectivePrefix}body\'])!,\n category: attachedDatabase.typeMapping\n .read(DriftSqlType.int, data[\'\${effectivePrefix}category\']),\n );\n }\n\n @override\n Todos createAlias(String alias) {\n return Todos(attachedDatabase, alias);\n }\n}\n\nclass TodosData extends DataClass implements Insertable<TodosData> {\n final int id;\n final String title;\n final String content;\n final int? category;\n const TodosData(\n {required this.id,\n required this.title,\n required this.content,\n this.category});\n @override\n Map<String, Expression> toColumns(bool nullToAbsent) {\n final map = <String, Expression>{};\n map[\'id\'] = Variable<int>(id);\n map[\'title\'] = Variable<String>(title);\n map[\'body\'] = Variable<String>(content);\n if (!nullToAbsent || category != null) {\n map[\'category\'] = Variable<int>(category);\n }\n return map;\n }\n\n TodosCompanion toCompanion(bool nullToAbsent) {\n return TodosCompanion(\n id: Value(id),\n title: Value(title),\n content: Value(content),\n category: category == null && nullToAbsent\n ? const Value.absent()\n : Value(category),\n );\n }\n\n factory TodosData.fromJson(Map<String, dynamic> json,\n {ValueSerializer? serializer}) {\n serializer ??= driftRuntimeOptions.defaultSerializer;\n return TodosData(\n id: serializer.fromJson<int>(json[\'id\']),\n title: serializer.fromJson<String>(json[\'title\']),\n content: serializer.fromJson<String>(json[\'content\']),\n category: serializer.fromJson<int?>(json[\'category\']),\n );\n }\n @override\n Map<String, dynamic> toJson({ValueSerializer? serializer}) {\n serializer ??= driftRuntimeOptions.defaultSerializer;\n return <String, dynamic>{\n \'id\': serializer.toJson<int>(id),\n \'title\': serializer.toJson<String>(title),\n \'content\': serializer.toJson<String>(content),\n \'category\': serializer.toJson<int?>(category),\n };\n }\n\n TodosData copyWith(\n {int? id,\n String? title,\n String? content,\n Value<int?> category = const Value.absent()}) =>\n TodosData(\n id: id ?? this.id,\n title: title ?? this.title,\n content: content ?? this.content,\n category: category.present ? category.value : this.category,\n );\n TodosData copyWithCompanion(TodosCompanion data) {\n return TodosData(\n id: data.id.present ? data.id.value : this.id,\n title: data.title.present ? data.title.value : this.title,\n content: data.content.present ? data.content.value : this.content,\n category: data.category.present ? data.category.value : this.category,\n );\n }\n\n @override\n String toString() {\n return (StringBuffer(\'TodosData(\')\n ..write(\'id: \$id, \')\n ..write(\'title: \$title, \')\n ..write(\'content: \$content, \')\n ..write(\'category: \$category\')\n ..write(\')\'))\n .toString();\n }\n\n @override\n int get hashCode => Object.hash(id, title, content, category);\n @override\n bool operator ==(Object other) =>\n identical(this, other) ||\n (other is TodosData &&\n other.id == this.id &&\n other.title == this.title &&\n other.content == this.content &&\n other.category == this.category);\n}\n\nclass TodosCompanion extends UpdateCompanion<TodosData> {\n final Value<int> id;\n final Value<String> title;\n final Value<String> content;\n final Value<int?> category;\n const TodosCompanion({\n this.id = const Value.absent(),\n this.title = const Value.absent(),\n this.content = const Value.absent(),\n this.category = const Value.absent(),\n });\n TodosCompanion.insert({\n this.id = const Value.absent(),\n required String title,\n required String content,\n this.category = const Value.absent(),\n }) : title = Value(title),\n content = Value(content);\n static Insertable<TodosData> custom({\n Expression<int>? id,\n Expression<String>? title,\n Expression<String>? content,\n Expression<int>? category,\n }) {\n return RawValuesInsertable({\n if (id != null) \'id\': id,\n if (title != null) \'title\': title,\n if (content != null) \'body\': content,\n if (category != null) \'category\': category,\n });\n }\n\n TodosCompanion copyWith(\n {Value<int>? id,\n Value<String>? title,\n Value<String>? content,\n Value<int?>? category}) {\n return TodosCompanion(\n id: id ?? this.id,\n title: title ?? this.title,\n content: content ?? this.content,\n category: category ?? this.category,\n );\n }\n\n @override\n Map<String, Expression> toColumns(bool nullToAbsent) {\n final map = <String, Expression>{};\n if (id.present) {\n map[\'id\'] = Variable<int>(id.value);\n }\n if (title.present) {\n map[\'title\'] = Variable<String>(title.value);\n }\n if (content.present) {\n map[\'body\'] = Variable<String>(content.value);\n }\n if (category.present) {\n map[\'category\'] = Variable<int>(category.value);\n }\n return map;\n }\n\n @override\n String toString() {\n return (StringBuffer(\'TodosCompanion(\')\n ..write(\'id: \$id, \')\n ..write(\'title: \$title, \')\n ..write(\'content: \$content, \')\n ..write(\'category: \$category\')\n ..write(\')\'))\n .toString();\n }\n}\n\nclass DatabaseAtV1 extends GeneratedDatabase {\n DatabaseAtV1(QueryExecutor e) : super(e);\n late final Todos todos = Todos(this);\n @override\n Iterable<TableInfo<Table, Object?>> get allTables =>\n allSchemaEntities.whereType<TableInfo<Table, Object?>>();\n @override\n List<DatabaseSchemaEntity> get allSchemaEntities => [todos];\n @override\n int get schemaVersion => 1;\n}\n',}, 'lib/src/snippets/migrations/runtime_verification.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\n// import the migrations tooling\nimport \'package:drift_dev/api/migrations_native.dart\';\n\nconst kDebugMode = true;\n\nabstract class _\$MyDatabase extends GeneratedDatabase {\n _\$MyDatabase(super.executor);\n}\n\n\nclass MyDatabase extends _\$MyDatabase {\n MyDatabase(super.executor);\n\n @override\n Iterable<TableInfo<Table, dynamic>> get allTables =>\n throw UnimplementedError();\n\n @override\n int get schemaVersion => throw UnimplementedError();\n\n @override\n MigrationStrategy get migration => MigrationStrategy(\n onCreate: (m) async {/* ... */},\n onUpgrade: (m, from, to) async {/* your existing migration logic */},\n beforeOpen: (details) async {\n // your existing beforeOpen callback, enable foreign keys, etc.\n\n if (kDebugMode) {\n // This check pulls in a fair amount of code that\'s not needed\n // anywhere else, so we recommend only doing it in debug builds.\n await validateDatabaseSchema();\n }\n },\n );\n}\n','native': '// import the migrations tooling\nimport \'package:drift_dev/api/migrations_native.dart\';\n\nclass MyDatabase extends _\$MyDatabase {\n @override\n MigrationStrategy get migration => MigrationStrategy(\n onCreate: (m) async {/* ... */},\n onUpgrade: (m, from, to) async {/* your existing migration logic */},\n beforeOpen: (details) async {\n // your existing beforeOpen callback, enable foreign keys, etc.\n\n if (kDebugMode) {\n // This check pulls in a fair amount of code that\'s not needed\n // anywhere else, so we recommend only doing it in debug builds.\n await validateDatabaseSchema();\n }\n },\n );\n}\n',}, 'lib/src/snippets/migrations/runtime_verification_web.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\n// import the migrations tooling\nimport \'package:drift_dev/api/migrations_web.dart\';\nimport \'package:sqlite3/wasm.dart\';\n\nconst kDebugMode = true;\n\nabstract class _\$MyDatabase extends GeneratedDatabase {\n _\$MyDatabase(super.executor);\n}\n\n\nclass MyDatabase extends _\$MyDatabase {\n MyDatabase(super.executor);\n\n @override\n Iterable<TableInfo<Table, dynamic>> get allTables =>\n throw UnimplementedError();\n\n @override\n int get schemaVersion => throw UnimplementedError();\n\n @override\n MigrationStrategy get migration => MigrationStrategy(\n onCreate: (m) async {/* ... */},\n onUpgrade: (m, from, to) async {/* your existing migration logic */},\n beforeOpen: (details) async {\n // your existing beforeOpen callback, enable foreign keys, etc.\n\n // This check pulls in a fair amount of code that\'s not needed\n // anywhere else, so we recommend only doing it in debug builds.\n if (kDebugMode) {\n // The web schema verifier needs a sqlite3 instance to open another\n // version of your database so that the two can be compared.\n final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse(\'/\'));\n sqlite3.registerVirtualFileSystem(InMemoryFileSystem(),\n makeDefault: true);\n await validateDatabaseSchema(sqlite3: sqlite3);\n }\n },\n );\n}\n','web': '// import the migrations tooling\nimport \'package:drift_dev/api/migrations_web.dart\';\nimport \'package:sqlite3/wasm.dart\';\n\nclass MyDatabase extends _\$MyDatabase {\n @override\n MigrationStrategy get migration => MigrationStrategy(\n onCreate: (m) async {/* ... */},\n onUpgrade: (m, from, to) async {/* your existing migration logic */},\n beforeOpen: (details) async {\n // your existing beforeOpen callback, enable foreign keys, etc.\n\n // This check pulls in a fair amount of code that\'s not needed\n // anywhere else, so we recommend only doing it in debug builds.\n if (kDebugMode) {\n // The web schema verifier needs a sqlite3 instance to open another\n // version of your database so that the two can be compared.\n final sqlite3 = await WasmSqlite3.loadFromUrl(Uri.parse(\'/\'));\n sqlite3.registerVirtualFileSystem(InMemoryFileSystem(),\n makeDefault: true);\n await validateDatabaseSchema(sqlite3: sqlite3);\n }\n },\n );\n}\n',}, +'lib/src/snippets/_shared/common_database.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\n\nimport \'todo_tables.dart\';\n\nimport \'common_database.drift.dart\';\nimport \'todo_tables.drift.dart\';\n\n// To hide the fact that this is using the modular builder...\ntypedef _\$MyDatabase = \$MyDatabase;\n\n@DriftDatabase(tables: [TodoItems, Categories])\nclass MyDatabase extends _\$MyDatabase {\n // the schemaVersion getter and the constructor from the previous page\n // have been omitted.\n MyDatabase(super.e);\n @override\n int get schemaVersion => throw UnimplementedError();\n\n // loads all todo entries\n Future<List<TodoItem>> get allTodoItems => select(todoItems).get();\n\n // watches all todo entries in a given category. The stream will automatically\n // emit new items whenever the underlying data changes.\n Stream<List<TodoItem>> watchEntriesInCategory(Category c) {\n return (select(todoItems)..where((t) => t.category.equals(c.id))).watch();\n }\n}\n\n','db': '@DriftDatabase(tables: [TodoItems, Categories])\nclass MyDatabase extends _\$MyDatabase {\n // the schemaVersion getter and the constructor from the previous page\n // have been omitted.\n\n // loads all todo entries\n Future<List<TodoItem>> get allTodoItems => select(todoItems).get();\n\n // watches all todo entries in a given category. The stream will automatically\n // emit new items whenever the underlying data changes.\n Stream<List<TodoItem>> watchEntriesInCategory(Category c) {\n return (select(todoItems)..where((t) => t.category.equals(c.id))).watch();\n }\n}\n\n',}, 'lib/src/snippets/_shared/todo_tables.dart.snippet.json': {'(full)': 'import \'package:drift/drift.dart\';\nimport \'package:drift/internal/modular.dart\';\n\nimport \'todo_tables.drift.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 IntColumn get category => integer().nullable().references(Categories, #id)();\n DateTimeColumn get dueDate => dateTime().nullable()();\n}\n\n@DataClassName(\'Category\')\nclass Categories extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n\nclass Users extends Table {\n IntColumn get id => integer().autoIncrement()();\n DateTimeColumn get birthDate => dateTime()();\n}\n\nclass CanUseCommonTables extends ModularAccessor {\n CanUseCommonTables(super.attachedDatabase);\n\n \$TodoItemsTable get todoItems => resultSet(\'todo_items\');\n \$CategoriesTable get categories => resultSet(\'categories\');\n \$UsersTable get users => resultSet(\'users\');\n}\n','tables': '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 IntColumn get category => integer().nullable().references(Categories, #id)();\n}\n\n@DataClassName(\'Category\')\nclass Categories extends Table {\n IntColumn get id => integer().autoIncrement()();\n TextColumn get name => text()();\n}\n',}, +'lib/src/snippets/examples/existing_databases_flutter.dart.snippet.json': {'(full)': 'import \'dart:io\';\n\nimport \'package:drift/drift.dart\';\n\nimport \'package:drift_flutter/drift_flutter.dart\';\nimport \'package:flutter/services.dart\' show rootBundle;\nimport \'package:path/path.dart\' as p;\nimport \'package:path_provider/path_provider.dart\';\n\nQueryExecutor openConnection() {\n return driftDatabase(\n // By default, drift creates a file named app.sqlite based on the name here.\n // Because we need to interact with the underlying file, we add the\n // `databasePath` option to specify the exact path here.\n name: \'app\',\n native: DriftNativeOptions(\n databasePath: () async {\n // put the database file, called db.sqlite here, into the documents\n // folder for your app.\n final dbFolder = await getApplicationDocumentsDirectory();\n final file = File(p.join(dbFolder.path, \'app.db\'));\n\n if (!await file.exists()) {\n // Extract the pre-populated database file from assets\n final blob = await rootBundle.load(\'assets/my_database.db\');\n final buffer = blob.buffer;\n await file.writeAsBytes(\n buffer.asUint8List(blob.offsetInBytes, blob.lengthInBytes));\n }\n\n return file.path;\n },\n ),\n );\n}\n',}, +'lib/src/snippets/examples/existing_databases_native.dart.snippet.json': {'(full)': 'import \'dart:io\';\n\nimport \'package:drift/drift.dart\';\nimport \'package:drift/native.dart\';\nimport \'package:flutter/services.dart\' show rootBundle;\nimport \'package:path/path.dart\' as p;\nimport \'package:path_provider/path_provider.dart\';\nimport \'package:sqlite3/sqlite3.dart\';\nimport \'package:sqlite3_flutter_libs/sqlite3_flutter_libs.dart\';\n\nQueryExecutor openConnection() {\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, \'app.db\'));\n\n if (!await file.exists()) {\n // Extract the pre-populated database file from assets\n final blob = await rootBundle.load(\'assets/my_database.db\');\n final buffer = blob.buffer;\n await file.writeAsBytes(\n buffer.asUint8List(blob.offsetInBytes, blob.lengthInBytes));\n }\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',}, +'lib/src/snippets/setup/migrate_to_drift/schema.expr.temp.dart.snippet.json': {'(full)': '\n',}, +'lib/src/snippets/custom_row_classes/employees_sql.expr.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/custom_row_classes/employee.dart\';\n',}, +'lib/src/snippets/modular/custom_types/drift_table.expr.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/modular/custom_types/type.dart\';\nvar expr_0 = const DurationType();\n',}, +'lib/src/snippets/modular/drift/example.expr.temp.dart.snippet.json': {'(full)': '\n',}, +'lib/src/snippets/modular/drift/with_existing.expr.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/modular/drift/row_class.dart\';\n',}, +'lib/src/snippets/drift_files/tables.expr.temp.dart.snippet.json': {'(full)': '\n',}, +'lib/src/snippets/drift_files/nested.expr.temp.dart.snippet.json': {'(full)': '\n',}, +'lib/src/snippets/drift_files/small_snippets.expr.temp.dart.snippet.json': {'(full)': '\n',}, +'lib/src/snippets/drift_files/getting_started/tables.expr.temp.dart.snippet.json': {'(full)': '\n',}, +'lib/src/snippets/custom_row_classes/employees_sql.drift.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/custom_row_classes/employee.dart\' as i0;\ntypedef T0 = i0.EmployeeWithStaff;\n',}, +'lib/src/snippets/custom_row_classes/named.dart.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/custom_row_classes/named.dart\' as i0;\ntypedef T0 = i0.User;\n',}, +'lib/src/snippets/custom_row_classes/default.dart.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/custom_row_classes/default.dart\' as i0;\ntypedef T0 = i0.User;\ntypedef T1 = ({int id, String name});\ntypedef T2 = ({int author, String content, int id});\n',}, +'lib/src/snippets/dart_api/json.dart.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/dart_api/json.dart\' as i0;\ntypedef T0 = i0.ContactData;\n',}, +'lib/src/snippets/platforms/postgres.dart.types.temp.dart.snippet.json': {'(full)': 'import \'package:uuid/uuid_value.dart\' as i0;\nimport \'package:drift_postgres/drift_postgres.dart\' as i1;\nimport \'package:postgres/src/types.dart\' as i2;\ntypedef T0 = i0.UuidValue;\ntypedef T1 = i1.PgDate;\ntypedef T2 = i1.PgDate;\ntypedef T3 = i1.PgDateTime;\ntypedef T4 = i1.PgDateTime;\ntypedef T5 = i2.Interval;\ntypedef T6 = i1.PgDateTime;\n',}, +'lib/src/snippets/type_converters/converters.dart.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/type_converters/converters.dart\' as i0;\ntypedef T0 = i0.Preferences;\ntypedef T1 = Map<String, Object?>;\n',}, +'lib/src/snippets/modular/many_to_many/json.dart.types.temp.dart.snippet.json': {'(full)': 'import \'package:drift_website/src/snippets/modular/many_to_many/json.dart\' as i0;\ntypedef T0 = i0.ShoppingCartEntries;\ntypedef T1 = Object?;\n',}, +'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',}, }; diff --git a/drift_website/lib/src/snippets/_shared/common_database.dart b/drift_website/lib/src/snippets/_shared/common_database.dart new file mode 100644 index 000000000..79ae8c16e --- /dev/null +++ b/drift_website/lib/src/snippets/_shared/common_database.dart @@ -0,0 +1,32 @@ +import 'package:drift/drift.dart'; + +import 'todo_tables.dart'; + +import 'common_database.drift.dart'; +import 'todo_tables.drift.dart'; + +// To hide the fact that this is using the modular builder... +typedef _$MyDatabase = $MyDatabase; + +// #docregion db +@DriftDatabase(tables: [TodoItems, Categories]) +class MyDatabase extends _$MyDatabase { + // the schemaVersion getter and the constructor from the previous page + // have been omitted. + // #enddocregion db + MyDatabase(super.e); + @override + int get schemaVersion => throw UnimplementedError(); + // #docregion db + + // loads all todo entries + Future> get allTodoItems => select(todoItems).get(); + + // watches all todo entries in a given category. The stream will automatically + // emit new items whenever the underlying data changes. + Stream> watchEntriesInCategory(Category c) { + return (select(todoItems)..where((t) => t.category.equals(c.id))).watch(); + } +} + +// #enddocregion db diff --git a/drift_website/lib/src/snippets/_shared/common_database.drift.dart b/drift_website/lib/src/snippets/_shared/common_database.drift.dart new file mode 100644 index 000000000..389ec40e1 --- /dev/null +++ b/drift_website/lib/src/snippets/_shared/common_database.drift.dart @@ -0,0 +1,29 @@ +// dart format width=80 +// ignore_for_file: type=lint +import 'package:drift/drift.dart' as i0; +import 'package:drift_website/src/snippets/_shared/todo_tables.drift.dart' + as i1; + +abstract class $MyDatabase extends i0.GeneratedDatabase { + $MyDatabase(i0.QueryExecutor e) : super(e); + $MyDatabaseManager get managers => $MyDatabaseManager(this); + late final i1.$CategoriesTable categories = i1.$CategoriesTable(this); + late final i1.$TodoItemsTable todoItems = i1.$TodoItemsTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [ + categories, + todoItems, + ]; +} + +class $MyDatabaseManager { + final $MyDatabase _db; + $MyDatabaseManager(this._db); + i1.$$CategoriesTableTableManager get categories => + i1.$$CategoriesTableTableManager(_db, _db.categories); + i1.$$TodoItemsTableTableManager get todoItems => + i1.$$TodoItemsTableTableManager(_db, _db.todoItems); +} diff --git a/drift_website/lib/src/snippets/modular/aliases.dart b/drift_website/lib/src/snippets/modular/aliases.dart new file mode 100644 index 000000000..9130f0787 --- /dev/null +++ b/drift_website/lib/src/snippets/modular/aliases.dart @@ -0,0 +1,64 @@ +import 'package:drift/drift.dart'; + +import 'aliases.drift.dart'; + +// #docregion tables +class GeoPoints extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text()(); + TextColumn get latitude => text()(); + TextColumn get longitude => text()(); +} + +class Routes extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text()(); + + // contains the id for the start and destination geopoint. + IntColumn get start => integer()(); + IntColumn get destination => integer()(); +} + +// #enddocregion tables + +// #docregion query +class RouteWithPoints { + final Route route; + final GeoPoint start; + final GeoPoint destination; + + RouteWithPoints({ + required this.route, + required this.start, + required this.destination, + }); +} + +// #enddocregion query +extension FakeDatabase on GeneratedDatabase { + $GeoPointsTable get geoPoints => throw ''; + $RoutesTable get routes => throw ''; + + // #docregion query + // inside the database class: + Future> loadRoutes() async { + // create aliases for the geoPoints table so that we can reference it twice + final start = alias(geoPoints, 's'); + final destination = alias(geoPoints, 'd'); + + final rows = await select(routes).join([ + innerJoin(start, start.id.equalsExp(routes.start)), + innerJoin(destination, destination.id.equalsExp(routes.destination)), + ]).get(); + + return rows.map((resultRow) { + return RouteWithPoints( + route: resultRow.readTable(routes), + start: resultRow.readTable(start), + destination: resultRow.readTable(destination), + ); + }).toList(); + } + + // #enddocregion query +} diff --git a/drift_website/lib/src/snippets/modular/aliases.drift.dart b/drift_website/lib/src/snippets/modular/aliases.drift.dart new file mode 100644 index 000000000..a66c4a732 --- /dev/null +++ b/drift_website/lib/src/snippets/modular/aliases.drift.dart @@ -0,0 +1,968 @@ +// dart format width=80 +// ignore_for_file: type=lint +import 'package:drift/drift.dart' as i0; +import 'package:drift_website/src/snippets/modular/aliases.drift.dart' as i1; +import 'package:drift_website/src/snippets/modular/aliases.dart' as i2; + +typedef $$GeoPointsTableCreateCompanionBuilder = + i1.GeoPointsCompanion Function({ + i0.Value id, + required String name, + required String latitude, + required String longitude, + }); +typedef $$GeoPointsTableUpdateCompanionBuilder = + i1.GeoPointsCompanion Function({ + i0.Value id, + i0.Value name, + i0.Value latitude, + i0.Value longitude, + }); + +class $$GeoPointsTableFilterComposer + extends i0.Composer { + $$GeoPointsTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get name => $composableBuilder( + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get latitude => $composableBuilder( + column: $table.latitude, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get longitude => $composableBuilder( + column: $table.longitude, + builder: (column) => i0.ColumnFilters(column), + ); +} + +class $$GeoPointsTableOrderingComposer + extends i0.Composer { + $$GeoPointsTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get name => $composableBuilder( + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get latitude => $composableBuilder( + column: $table.latitude, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get longitude => $composableBuilder( + column: $table.longitude, + builder: (column) => i0.ColumnOrderings(column), + ); +} + +class $$GeoPointsTableAnnotationComposer + extends i0.Composer { + $$GeoPointsTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + i0.GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + i0.GeneratedColumn get latitude => + $composableBuilder(column: $table.latitude, builder: (column) => column); + + i0.GeneratedColumn get longitude => + $composableBuilder(column: $table.longitude, builder: (column) => column); +} + +class $$GeoPointsTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$GeoPointsTable, + i1.GeoPoint, + i1.$$GeoPointsTableFilterComposer, + i1.$$GeoPointsTableOrderingComposer, + i1.$$GeoPointsTableAnnotationComposer, + $$GeoPointsTableCreateCompanionBuilder, + $$GeoPointsTableUpdateCompanionBuilder, + ( + i1.GeoPoint, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$GeoPointsTable, + i1.GeoPoint + >, + ), + i1.GeoPoint, + i0.PrefetchHooks Function() + > { + $$GeoPointsTableTableManager( + i0.GeneratedDatabase db, + i1.$GeoPointsTable table, + ) : super( + i0.TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + i1.$$GeoPointsTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + i1.$$GeoPointsTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + i1.$$GeoPointsTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value name = const i0.Value.absent(), + i0.Value latitude = const i0.Value.absent(), + i0.Value longitude = const i0.Value.absent(), + }) => i1.GeoPointsCompanion( + id: id, + name: name, + latitude: latitude, + longitude: longitude, + ), + createCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + required String name, + required String latitude, + required String longitude, + }) => i1.GeoPointsCompanion.insert( + id: id, + name: name, + latitude: latitude, + longitude: longitude, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$GeoPointsTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$GeoPointsTable, + i1.GeoPoint, + i1.$$GeoPointsTableFilterComposer, + i1.$$GeoPointsTableOrderingComposer, + i1.$$GeoPointsTableAnnotationComposer, + $$GeoPointsTableCreateCompanionBuilder, + $$GeoPointsTableUpdateCompanionBuilder, + ( + i1.GeoPoint, + i0.BaseReferences< + i0.GeneratedDatabase, + i1.$GeoPointsTable, + i1.GeoPoint + >, + ), + i1.GeoPoint, + i0.PrefetchHooks Function() + >; +typedef $$RoutesTableCreateCompanionBuilder = + i1.RoutesCompanion Function({ + i0.Value id, + required String name, + required int start, + required int destination, + }); +typedef $$RoutesTableUpdateCompanionBuilder = + i1.RoutesCompanion Function({ + i0.Value id, + i0.Value name, + i0.Value start, + i0.Value destination, + }); + +class $$RoutesTableFilterComposer + extends i0.Composer { + $$RoutesTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get name => $composableBuilder( + column: $table.name, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get start => $composableBuilder( + column: $table.start, + builder: (column) => i0.ColumnFilters(column), + ); + + i0.ColumnFilters get destination => $composableBuilder( + column: $table.destination, + builder: (column) => i0.ColumnFilters(column), + ); +} + +class $$RoutesTableOrderingComposer + extends i0.Composer { + $$RoutesTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get name => $composableBuilder( + column: $table.name, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get start => $composableBuilder( + column: $table.start, + builder: (column) => i0.ColumnOrderings(column), + ); + + i0.ColumnOrderings get destination => $composableBuilder( + column: $table.destination, + builder: (column) => i0.ColumnOrderings(column), + ); +} + +class $$RoutesTableAnnotationComposer + extends i0.Composer { + $$RoutesTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + i0.GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + i0.GeneratedColumn get name => + $composableBuilder(column: $table.name, builder: (column) => column); + + i0.GeneratedColumn get start => + $composableBuilder(column: $table.start, builder: (column) => column); + + i0.GeneratedColumn get destination => $composableBuilder( + column: $table.destination, + builder: (column) => column, + ); +} + +class $$RoutesTableTableManager + extends + i0.RootTableManager< + i0.GeneratedDatabase, + i1.$RoutesTable, + i1.Route, + i1.$$RoutesTableFilterComposer, + i1.$$RoutesTableOrderingComposer, + i1.$$RoutesTableAnnotationComposer, + $$RoutesTableCreateCompanionBuilder, + $$RoutesTableUpdateCompanionBuilder, + ( + i1.Route, + i0.BaseReferences, + ), + i1.Route, + i0.PrefetchHooks Function() + > { + $$RoutesTableTableManager(i0.GeneratedDatabase db, i1.$RoutesTable table) + : super( + i0.TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + i1.$$RoutesTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + i1.$$RoutesTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + i1.$$RoutesTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + i0.Value name = const i0.Value.absent(), + i0.Value start = const i0.Value.absent(), + i0.Value destination = const i0.Value.absent(), + }) => i1.RoutesCompanion( + id: id, + name: name, + start: start, + destination: destination, + ), + createCompanionCallback: + ({ + i0.Value id = const i0.Value.absent(), + required String name, + required int start, + required int destination, + }) => i1.RoutesCompanion.insert( + id: id, + name: name, + start: start, + destination: destination, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), i0.BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$RoutesTableProcessedTableManager = + i0.ProcessedTableManager< + i0.GeneratedDatabase, + i1.$RoutesTable, + i1.Route, + i1.$$RoutesTableFilterComposer, + i1.$$RoutesTableOrderingComposer, + i1.$$RoutesTableAnnotationComposer, + $$RoutesTableCreateCompanionBuilder, + $$RoutesTableUpdateCompanionBuilder, + ( + i1.Route, + i0.BaseReferences, + ), + i1.Route, + i0.PrefetchHooks Function() + >; + +class $GeoPointsTable extends i2.GeoPoints + with i0.TableInfo<$GeoPointsTable, i1.GeoPoint> { + @override + final i0.GeneratedDatabase attachedDatabase; + final String? _alias; + $GeoPointsTable(this.attachedDatabase, [this._alias]); + static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); + @override + late final i0.GeneratedColumn id = i0.GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); + @override + late final i0.GeneratedColumn name = i0.GeneratedColumn( + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _latitudeMeta = const i0.VerificationMeta( + 'latitude', + ); + @override + late final i0.GeneratedColumn latitude = i0.GeneratedColumn( + 'latitude', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _longitudeMeta = const i0.VerificationMeta( + 'longitude', + ); + @override + late final i0.GeneratedColumn longitude = i0.GeneratedColumn( + 'longitude', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, name, latitude, longitude]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'geo_points'; + @override + i0.VerificationContext validateIntegrity( + i0.Insertable instance, { + bool isInserting = false, + }) { + final context = i0.VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('latitude')) { + context.handle( + _latitudeMeta, + latitude.isAcceptableOrUnknown(data['latitude']!, _latitudeMeta), + ); + } else if (isInserting) { + context.missing(_latitudeMeta); + } + if (data.containsKey('longitude')) { + context.handle( + _longitudeMeta, + longitude.isAcceptableOrUnknown(data['longitude']!, _longitudeMeta), + ); + } else if (isInserting) { + context.missing(_longitudeMeta); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + i1.GeoPoint map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return i1.GeoPoint( + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + latitude: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}latitude'], + )!, + longitude: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}longitude'], + )!, + ); + } + + @override + $GeoPointsTable createAlias(String alias) { + return $GeoPointsTable(attachedDatabase, alias); + } +} + +class GeoPoint extends i0.DataClass implements i0.Insertable { + final int id; + final String name; + final String latitude; + final String longitude; + const GeoPoint({ + required this.id, + required this.name, + required this.latitude, + required this.longitude, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = i0.Variable(id); + map['name'] = i0.Variable(name); + map['latitude'] = i0.Variable(latitude); + map['longitude'] = i0.Variable(longitude); + return map; + } + + i1.GeoPointsCompanion toCompanion(bool nullToAbsent) { + return i1.GeoPointsCompanion( + id: i0.Value(id), + name: i0.Value(name), + latitude: i0.Value(latitude), + longitude: i0.Value(longitude), + ); + } + + factory GeoPoint.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return GeoPoint( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + latitude: serializer.fromJson(json['latitude']), + longitude: serializer.fromJson(json['longitude']), + ); + } + @override + Map toJson({i0.ValueSerializer? serializer}) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'latitude': serializer.toJson(latitude), + 'longitude': serializer.toJson(longitude), + }; + } + + i1.GeoPoint copyWith({ + int? id, + String? name, + String? latitude, + String? longitude, + }) => i1.GeoPoint( + id: id ?? this.id, + name: name ?? this.name, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + ); + GeoPoint copyWithCompanion(i1.GeoPointsCompanion data) { + return GeoPoint( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + latitude: data.latitude.present ? data.latitude.value : this.latitude, + longitude: data.longitude.present ? data.longitude.value : this.longitude, + ); + } + + @override + String toString() { + return (StringBuffer('GeoPoint(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, latitude, longitude); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is i1.GeoPoint && + other.id == this.id && + other.name == this.name && + other.latitude == this.latitude && + other.longitude == this.longitude); +} + +class GeoPointsCompanion extends i0.UpdateCompanion { + final i0.Value id; + final i0.Value name; + final i0.Value latitude; + final i0.Value longitude; + const GeoPointsCompanion({ + this.id = const i0.Value.absent(), + this.name = const i0.Value.absent(), + this.latitude = const i0.Value.absent(), + this.longitude = const i0.Value.absent(), + }); + GeoPointsCompanion.insert({ + this.id = const i0.Value.absent(), + required String name, + required String latitude, + required String longitude, + }) : name = i0.Value(name), + latitude = i0.Value(latitude), + longitude = i0.Value(longitude); + static i0.Insertable custom({ + i0.Expression? id, + i0.Expression? name, + i0.Expression? latitude, + i0.Expression? longitude, + }) { + return i0.RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (latitude != null) 'latitude': latitude, + if (longitude != null) 'longitude': longitude, + }); + } + + i1.GeoPointsCompanion copyWith({ + i0.Value? id, + i0.Value? name, + i0.Value? latitude, + i0.Value? longitude, + }) { + return i1.GeoPointsCompanion( + id: id ?? this.id, + name: name ?? this.name, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = i0.Variable(id.value); + } + if (name.present) { + map['name'] = i0.Variable(name.value); + } + if (latitude.present) { + map['latitude'] = i0.Variable(latitude.value); + } + if (longitude.present) { + map['longitude'] = i0.Variable(longitude.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('GeoPointsCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('latitude: $latitude, ') + ..write('longitude: $longitude') + ..write(')')) + .toString(); + } +} + +class $RoutesTable extends i2.Routes with i0.TableInfo<$RoutesTable, i1.Route> { + @override + final i0.GeneratedDatabase attachedDatabase; + final String? _alias; + $RoutesTable(this.attachedDatabase, [this._alias]); + static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); + @override + late final i0.GeneratedColumn id = i0.GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: i0.GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const i0.VerificationMeta _nameMeta = const i0.VerificationMeta( + 'name', + ); + @override + late final i0.GeneratedColumn name = i0.GeneratedColumn( + 'name', + aliasedName, + false, + type: i0.DriftSqlType.string, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _startMeta = const i0.VerificationMeta( + 'start', + ); + @override + late final i0.GeneratedColumn start = i0.GeneratedColumn( + 'start', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); + static const i0.VerificationMeta _destinationMeta = const i0.VerificationMeta( + 'destination', + ); + @override + late final i0.GeneratedColumn destination = i0.GeneratedColumn( + 'destination', + aliasedName, + false, + type: i0.DriftSqlType.int, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, name, start, destination]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'routes'; + @override + i0.VerificationContext validateIntegrity( + i0.Insertable instance, { + bool isInserting = false, + }) { + final context = i0.VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, + name.isAcceptableOrUnknown(data['name']!, _nameMeta), + ); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('start')) { + context.handle( + _startMeta, + start.isAcceptableOrUnknown(data['start']!, _startMeta), + ); + } else if (isInserting) { + context.missing(_startMeta); + } + if (data.containsKey('destination')) { + context.handle( + _destinationMeta, + destination.isAcceptableOrUnknown( + data['destination']!, + _destinationMeta, + ), + ); + } else if (isInserting) { + context.missing(_destinationMeta); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + i1.Route map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return i1.Route( + id: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + name: attachedDatabase.typeMapping.read( + i0.DriftSqlType.string, + data['${effectivePrefix}name'], + )!, + start: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}start'], + )!, + destination: attachedDatabase.typeMapping.read( + i0.DriftSqlType.int, + data['${effectivePrefix}destination'], + )!, + ); + } + + @override + $RoutesTable createAlias(String alias) { + return $RoutesTable(attachedDatabase, alias); + } +} + +class Route extends i0.DataClass implements i0.Insertable { + final int id; + final String name; + final int start; + final int destination; + const Route({ + required this.id, + required this.name, + required this.start, + required this.destination, + }); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = i0.Variable(id); + map['name'] = i0.Variable(name); + map['start'] = i0.Variable(start); + map['destination'] = i0.Variable(destination); + return map; + } + + i1.RoutesCompanion toCompanion(bool nullToAbsent) { + return i1.RoutesCompanion( + id: i0.Value(id), + name: i0.Value(name), + start: i0.Value(start), + destination: i0.Value(destination), + ); + } + + factory Route.fromJson( + Map json, { + i0.ValueSerializer? serializer, + }) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return Route( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + start: serializer.fromJson(json['start']), + destination: serializer.fromJson(json['destination']), + ); + } + @override + Map toJson({i0.ValueSerializer? serializer}) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'start': serializer.toJson(start), + 'destination': serializer.toJson(destination), + }; + } + + i1.Route copyWith({int? id, String? name, int? start, int? destination}) => + i1.Route( + id: id ?? this.id, + name: name ?? this.name, + start: start ?? this.start, + destination: destination ?? this.destination, + ); + Route copyWithCompanion(i1.RoutesCompanion data) { + return Route( + id: data.id.present ? data.id.value : this.id, + name: data.name.present ? data.name.value : this.name, + start: data.start.present ? data.start.value : this.start, + destination: data.destination.present + ? data.destination.value + : this.destination, + ); + } + + @override + String toString() { + return (StringBuffer('Route(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('start: $start, ') + ..write('destination: $destination') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, start, destination); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is i1.Route && + other.id == this.id && + other.name == this.name && + other.start == this.start && + other.destination == this.destination); +} + +class RoutesCompanion extends i0.UpdateCompanion { + final i0.Value id; + final i0.Value name; + final i0.Value start; + final i0.Value destination; + const RoutesCompanion({ + this.id = const i0.Value.absent(), + this.name = const i0.Value.absent(), + this.start = const i0.Value.absent(), + this.destination = const i0.Value.absent(), + }); + RoutesCompanion.insert({ + this.id = const i0.Value.absent(), + required String name, + required int start, + required int destination, + }) : name = i0.Value(name), + start = i0.Value(start), + destination = i0.Value(destination); + static i0.Insertable custom({ + i0.Expression? id, + i0.Expression? name, + i0.Expression? start, + i0.Expression? destination, + }) { + return i0.RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (start != null) 'start': start, + if (destination != null) 'destination': destination, + }); + } + + i1.RoutesCompanion copyWith({ + i0.Value? id, + i0.Value? name, + i0.Value? start, + i0.Value? destination, + }) { + return i1.RoutesCompanion( + id: id ?? this.id, + name: name ?? this.name, + start: start ?? this.start, + destination: destination ?? this.destination, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = i0.Variable(id.value); + } + if (name.present) { + map['name'] = i0.Variable(name.value); + } + if (start.present) { + map['start'] = i0.Variable(start.value); + } + if (destination.present) { + map['destination'] = i0.Variable(destination.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('RoutesCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('start: $start, ') + ..write('destination: $destination') + ..write(')')) + .toString(); + } +} diff --git a/drift_website/lib/src/styles/_admonition.scss b/drift_website/lib/src/styles/_admonition.scss index ae9b7eaa2..c13e75cbd 100644 --- a/drift_website/lib/src/styles/_admonition.scss +++ b/drift_website/lib/src/styles/_admonition.scss @@ -11,17 +11,17 @@ /// Admonition flavours $admonitions: ( "note": pencil-circle $clr-blue-a200, - "abstract": clipboard-text $clr-light-blue-a400, - "info": information $clr-cyan-a700, + //"abstract": clipboard-text $clr-light-blue-a400, + //"info": information $clr-cyan-a700, "tip": fire $clr-teal-a700, - "success": check $clr-green-a700, - "question": help-circle $clr-light-green-a700, - "warning": alert $clr-orange-a400, - "failure": close $clr-red-a200, - "danger": lightning-bolt-circle $clr-red-a400, - "bug": shield-bug $clr-pink-a400, - "example": test-tube $clr-deep-purple-a200, - "quote": format-quote-close $clr-grey + "success": check $clr-green-a700 + //"question": help-circle $clr-light-green-a700, + //"warning": alert $clr-orange-a400, + //"failure": close $clr-red-a200, + //"danger": lightning-bolt-circle $clr-red-a400, + //"bug": shield-bug $clr-pink-a400, + //"example": test-tube $clr-deep-purple-a200, + //"quote": format-quote-close $clr-grey ) !default; // ---------------------------------------------------------------------------- @@ -45,7 +45,7 @@ $admonitions: ( display: flow-root; line-height: 1.35rem; padding: 0 px2rem(12px); - margin: px2em(20px, 12.8px) 0; + margin: px2rem(20px) px2rem(12.8px); font-size: px2rem(12.8px); background-color: var(--background-card); border: px2rem(1.5px) solid $clr-blue-a200; @@ -94,6 +94,7 @@ $admonitions: ( // Adjust spacing on last child html & > :last-child { + margin-top: px2rem(12px); margin-bottom: px2rem(12px); } } diff --git a/drift_website/lib/src/styles/_details.scss b/drift_website/lib/src/styles/_details.scss index 8e35b0e65..e547c862e 100644 --- a/drift_website/lib/src/styles/_details.scss +++ b/drift_website/lib/src/styles/_details.scss @@ -1,5 +1,6 @@ // https://github.com/squidfunk/mkdocs-material/blob/c68fac7fb3071fa4f45cc823e2ca2ea82fd67b43/src/templates/assets/stylesheets/main/extensions/pymdownx/_details.scss#L4 +@use "constants" as *; @use "admonition"; // Details @@ -65,7 +66,7 @@ height: px2rem(20px); content: ""; background-color: currentcolor; - mask-image: var(--md-details-icon); + mask-image: url("/images/chevron-right.svg"); mask-repeat: no-repeat; mask-position: center; mask-size: contain; diff --git a/drift_website/pubspec.yaml b/drift_website/pubspec.yaml index cbc769f25..8f9ca3532 100644 --- a/drift_website/pubspec.yaml +++ b/drift_website/pubspec.yaml @@ -25,6 +25,7 @@ dependencies: rxdart: ^0.28.0 jaspr_content_snippets: ^0.1.1 glob: ^2.1.3 + markdown: ^7.3.0 dev_dependencies: build_runner: ^2.6.0 diff --git a/drift_website/test/markdown_test.dart b/drift_website/test/markdown_test.dart new file mode 100644 index 000000000..e80116ccc --- /dev/null +++ b/drift_website/test/markdown_test.dart @@ -0,0 +1,49 @@ +import 'package:drift_website/src/common.dart'; +import 'package:markdown/markdown.dart'; +import 'package:test/test.dart'; + +void main() { + test('parses admonitions', () { + final docs = driftMarkdownDocumentBuilder(); + final parsed = docs.parse(''' +!!! note + + Content +'''); + + expect(renderToHtml(parsed), ''' +
+

Note

+

Content

+
'''); + }); + + test('can set a custom title', () { + final docs = driftMarkdownDocumentBuilder(); + final parsed = docs.parse(''' +!!! tip "Custom title" + + Content +'''); + + expect(renderToHtml(parsed), ''' +
+

Custom title

+

Content

+
'''); + }); + + test('can generate collapsible', () { + final docs = driftMarkdownDocumentBuilder(); + final parsed = docs.parse(''' +??? note + + Content +'''); + + expect(renderToHtml(parsed), ''' +
Note +

Content

+
'''); + }); +} diff --git a/drift_website/web/images/check.svg b/drift_website/web/images/check.svg new file mode 100644 index 000000000..ba4cd0714 --- /dev/null +++ b/drift_website/web/images/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/drift_website/web/images/chevron-right.svg b/drift_website/web/images/chevron-right.svg new file mode 100644 index 000000000..fbbfb9c20 --- /dev/null +++ b/drift_website/web/images/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/drift_website/web/images/fire.svg b/drift_website/web/images/fire.svg new file mode 100644 index 000000000..7c29f0770 --- /dev/null +++ b/drift_website/web/images/fire.svg @@ -0,0 +1 @@ + \ No newline at end of file