mirror of https://github.com/AMT-Cheif/drift.git
Merge branch 'simple-schema-versions' into develop
This commit is contained in:
commit
2420c8d7c6
|
@ -0,0 +1 @@
|
|||
{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.0.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"todos","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"title","getter_name":"title","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[{"allowed-lengths":{"min":6,"max":10}}]},{"name":"body","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"category","getter_name":"category","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}}]}
|
|
@ -0,0 +1 @@
|
|||
{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.0.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"todos","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"title","getter_name":"title","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[{"allowed-lengths":{"min":6,"max":10}}]},{"name":"body","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"category","getter_name":"category","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"due_date","getter_name":"dueDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}}]}
|
|
@ -0,0 +1 @@
|
|||
{"_meta":{"description":"This file contains a serialized version of schema entities for drift.","version":"1.0.0"},"options":{"store_date_time_values_as_text":false},"entities":[{"id":0,"references":[],"type":"table","data":{"name":"todos","was_declared_in_moor":false,"columns":[{"name":"id","getter_name":"id","moor_type":"int","nullable":false,"customConstraints":null,"defaultConstraints":"PRIMARY KEY AUTOINCREMENT","default_dart":null,"default_client_dart":null,"dsl_features":["auto-increment"]},{"name":"title","getter_name":"title","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[{"allowed-lengths":{"min":6,"max":10}}]},{"name":"body","getter_name":"content","moor_type":"string","nullable":false,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"category","getter_name":"category","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"due_date","getter_name":"dueDate","moor_type":"dateTime","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]},{"name":"priority","getter_name":"priority","moor_type":"int","nullable":true,"customConstraints":null,"default_dart":null,"default_client_dart":null,"dsl_features":[]}],"is_virtual":false,"without_rowid":false,"constraints":[]}}]}
|
|
@ -1,5 +1,11 @@
|
|||
import 'package:drift/drift.dart';
|
||||
|
||||
// #docregion stepbystep
|
||||
// This file was generated by `drift_dev schema steps drift_schemas lib/database/schema_versions.dart
|
||||
import 'schema_versions.dart';
|
||||
|
||||
// #enddocregion stepbystep
|
||||
|
||||
part 'migrations.g.dart';
|
||||
|
||||
const kDebugMode = false;
|
||||
|
@ -91,3 +97,27 @@ class Example extends _$Example {
|
|||
// #enddocregion change_type
|
||||
}
|
||||
}
|
||||
|
||||
class StepByStep {
|
||||
// #docregion stepbystep
|
||||
MigrationStrategy get migration {
|
||||
return MigrationStrategy(
|
||||
onCreate: (Migrator m) async {
|
||||
await m.createAll();
|
||||
},
|
||||
onUpgrade: stepByStep(
|
||||
from1To2: (m, schema) async {
|
||||
// we added the dueDate property in the change from version 1 to
|
||||
// version 2
|
||||
await m.addColumn(schema.todos, schema.todos.dueDate);
|
||||
},
|
||||
from2To3: (m, schema) async {
|
||||
// we added the priority property in the change from version 1 or 2
|
||||
// to version 3
|
||||
await m.addColumn(schema.todos, schema.todos.priority);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
// #enddocregion stepbystep
|
||||
}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
import 'package:drift/internal/versioned_schema.dart' as i0;
|
||||
import 'package:drift/drift.dart' as i1;
|
||||
import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import
|
||||
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
final class _S2 extends i0.VersionedSchema {
|
||||
_S2({required super.database}) : super(version: 2);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
todos,
|
||||
];
|
||||
late final Shape0 todos = Shape0(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'todos',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape0 extends i0.VersionedTable {
|
||||
Shape0({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get title =>
|
||||
columnsByName['title']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<String> get content =>
|
||||
columnsByName['body']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<int> get category =>
|
||||
columnsByName['category']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<DateTime> get dueDate =>
|
||||
columnsByName['due_date']! as i1.GeneratedColumn<DateTime>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_0(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i1.DriftSqlType.int,
|
||||
defaultConstraints:
|
||||
i1.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
i1.GeneratedColumn<String> _column_1(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('title', aliasedName, false,
|
||||
additionalChecks: i1.GeneratedColumn.checkTextLength(
|
||||
minTextLength: 6, maxTextLength: 10),
|
||||
type: i1.DriftSqlType.string);
|
||||
i1.GeneratedColumn<String> _column_2(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('body', aliasedName, false,
|
||||
type: i1.DriftSqlType.string);
|
||||
i1.GeneratedColumn<int> _column_3(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('category', aliasedName, true,
|
||||
type: i1.DriftSqlType.int);
|
||||
i1.GeneratedColumn<DateTime> _column_4(String aliasedName) =>
|
||||
i1.GeneratedColumn<DateTime>('due_date', aliasedName, true,
|
||||
type: i1.DriftSqlType.dateTime);
|
||||
|
||||
final class _S3 extends i0.VersionedSchema {
|
||||
_S3({required super.database}) : super(version: 3);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
todos,
|
||||
];
|
||||
late final Shape1 todos = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'todos',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape1 extends i0.VersionedTable {
|
||||
Shape1({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get title =>
|
||||
columnsByName['title']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<String> get content =>
|
||||
columnsByName['body']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<int> get category =>
|
||||
columnsByName['category']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<DateTime> get dueDate =>
|
||||
columnsByName['due_date']! as i1.GeneratedColumn<DateTime>;
|
||||
i1.GeneratedColumn<int> get priority =>
|
||||
columnsByName['priority']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_5(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('priority', aliasedName, true,
|
||||
type: i1.DriftSqlType.int);
|
||||
i1.OnUpgrade stepByStep({
|
||||
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
||||
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
||||
}) {
|
||||
return i1.Migrator.stepByStepHelper(step: (currentVersion, database) async {
|
||||
switch (currentVersion) {
|
||||
case 1:
|
||||
final schema = _S2(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from1To2(migrator, schema);
|
||||
return 2;
|
||||
case 2:
|
||||
final schema = _S3(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from2To3(migrator, schema);
|
||||
return 3;
|
||||
default:
|
||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||
}
|
||||
});
|
||||
}
|
|
@ -13,11 +13,13 @@ New features need new columns or tables, and outdated columns may have to be alt
|
|||
removed altogether.
|
||||
When making changes to your database schema, you need to write migrations enabling users with
|
||||
an old version of your app to convert to the database expected by the latest version.
|
||||
Drift provides a set of APIs to make writing migrations easy.
|
||||
With incorrect migrations, your database ends up in an inconsistent state which can cause crashes
|
||||
or data loss. This is why drift provides dedicated test tools and APIs to make writing migrations
|
||||
easy and safe.
|
||||
|
||||
{% assign snippets = 'package:drift_docs/snippets/migrations/migrations.dart.excerpt.json' | readString | json_decode %}
|
||||
|
||||
## Basics
|
||||
## Manual setup {#basics}
|
||||
|
||||
Drift provides a migration API that can be used to gradually apply schema changes after bumping
|
||||
the `schemaVersion` getter inside the `Database` class. To use it, override the `migration`
|
||||
|
@ -43,7 +45,7 @@ you've actually added the column. In general, try to avoid running queries in mi
|
|||
`sqlite` can feel a bit limiting when it comes to migrations - there only are methods to create tables and columns.
|
||||
Existing columns can't be altered or removed. A workaround is described [here](https://stackoverflow.com/a/805508), it
|
||||
can be used together with `customStatement` to run the statements.
|
||||
Alternatively, [complex migrations](#complex-migrations) help automating this.
|
||||
Alternatively, [complex migrations](#complex-migrations) described on this page help automating this.
|
||||
|
||||
### Tips
|
||||
|
||||
|
@ -60,6 +62,241 @@ With all of this combined, a migration callback can look like this:
|
|||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'structured' %}
|
||||
|
||||
## Migration workflow
|
||||
|
||||
While migrations can be written manually without additional help from drift, dedicated tools testing your migrations help
|
||||
to ensure that they are correct and aren't loosing any data.
|
||||
|
||||
Drift's migration tooling consists of the following steps:
|
||||
|
||||
1. After each change to your schema, use a tool to export the current schema into a separate file.
|
||||
2. Use a drift tool to generate test code able to verify that your migrations are bringing the database
|
||||
into the expected schema.
|
||||
3. Use generated code to make writing schema migrations easier.
|
||||
|
||||
### Setup
|
||||
|
||||
As described by the first step, you can export the schema of your database into a JSON file.
|
||||
It is recommended to do this once intially, and then again each time you change your schema
|
||||
and increase the `schemaVersion` getter in the database.
|
||||
|
||||
You should store these exported files in your repository and include them in source control.
|
||||
This guide assumes a top-level `drift_schemas/` folder in your project, like this:
|
||||
|
||||
```
|
||||
my_app
|
||||
.../
|
||||
lib/
|
||||
database/
|
||||
database.dart
|
||||
database.g.dart
|
||||
test/
|
||||
generated_migrations/
|
||||
schema.dart
|
||||
schema_v1.dart
|
||||
schema_v2.dart
|
||||
drift_schemas/
|
||||
drift_schema_v1.json
|
||||
drift_schema_v2.json
|
||||
pubspec.yaml
|
||||
```
|
||||
|
||||
Of course, you can also use another folder or a subfolder somewhere if that suits your workflow
|
||||
better.
|
||||
|
||||
{% block "blocks/alert" title="Examples available" %}
|
||||
Exporting schemas and generating code for them can't be done with `build_runner` alone, which is
|
||||
why this setup described here is necessary.
|
||||
|
||||
We hope it's worth it though! Verifying migrations can give you confidence that you won't run
|
||||
into issues after changing your database.
|
||||
If you get stuck along the way, don't hesitate to [open a discussion about it](https://github.com/simolus3/drift/discussions).
|
||||
|
||||
Also there are two examples in the drift repository which may be useful as a reference:
|
||||
|
||||
- A [Flutter app](https://github.com/simolus3/drift/tree/latest-release/examples/app)
|
||||
- An [example specific to migrations](https://github.com/simolus3/drift/tree/latest-release/examples/migrations_example).
|
||||
{% endblock %}
|
||||
|
||||
#### Exporting the schema
|
||||
|
||||
To begin, lets create the first schema representation:
|
||||
|
||||
```
|
||||
$ mkdir drift_schemas
|
||||
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/
|
||||
```
|
||||
|
||||
This instructs the generator to look at the database defined in `lib/database/database.dart` and extract
|
||||
its schema into the new folder.
|
||||
|
||||
After making a change to your database schema, you can run the command again. For instance, let's say we
|
||||
made a change to our tables and increased the `schemaVersion` to `2`. To dump the new schema, just run the
|
||||
command again:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/
|
||||
```
|
||||
|
||||
You'll need to run this command every time you change the schema of your database and increment the `schemaVersion`.
|
||||
|
||||
Drift will name the files in the folder `drift_schema_vX.json`, where `X` is the current `schemaVersion` of your
|
||||
database.
|
||||
If drift is unable to extract the version from your `schemaVersion` getter, provide the full path explicitly:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/drift_schema_v3.json
|
||||
```
|
||||
|
||||
{% block "blocks/alert" title='<i class="fas fa-lightbulb"></i> Dumping a database' color="success" %}
|
||||
If, instead of exporting the schema of a database class, you want to export the schema of an existing sqlite3
|
||||
database file, you can do that as well! `drift_dev schema dump` recognizes a sqlite3 database file as its first
|
||||
argument and can extract the relevant schema from there.
|
||||
{% endblock %}
|
||||
|
||||
### Generating step-by-step migrations {#step-by-step}
|
||||
|
||||
With all your database schemas exported into a folder, drift can generate code that makes it much
|
||||
easier to write schema migrations "step-by-step" (incrementally from each version to the next one).
|
||||
|
||||
This code is stored in a single-file, which you can generate like this:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema steps drift_schemas/ lib/database/schema_versions.dart
|
||||
```
|
||||
|
||||
The generated code contains a `stepByStep` method which you can use as a callback to the `onUpgrade`
|
||||
parameter of your `MigrationStrategy`.
|
||||
As an example, here is the [initial](#basics) migration shown at the top of this page, but rewritten using
|
||||
the generated `stepByStep` function:
|
||||
|
||||
{% include "blocks/snippet" snippets = snippets name = 'stepbystep' %}
|
||||
|
||||
`stepByStep` expects a callback for each schema upgrade responsible for running the partial migration.
|
||||
That callback receives two parameters: A migrator `m` (similar to the regular migrator you'd get for
|
||||
`onUpgrade` callbacks) and a `schema` parameter that gives you access to the schema at the version you're
|
||||
migrating to.
|
||||
For instance, in the `from1To2` function, `schema` provides getters for the database schema at version 2.
|
||||
The migrator passed to the function is also set up to consider that specific version by default.
|
||||
A call to `m.recreateAllViews()` would re-create views at the expected state of schema version 2, for instance.
|
||||
|
||||
### Writing tests
|
||||
|
||||
After you've exported the database schemas into a folder, you can generate old versions of your database class
|
||||
based on those schema files.
|
||||
For verifications, drift will generate a much smaller database implementation that can only be used to
|
||||
test migrations.
|
||||
|
||||
You can put this test code whereever you want, but it makes sense to put it in a subfolder of `test/`.
|
||||
If we wanted to write them to `test/generated_migrations/`, we could use
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema generate drift_schemas/ test/generated_migrations/
|
||||
```
|
||||
|
||||
After that setup, it's finally time to write some tests! For instance, a test could look like this:
|
||||
|
||||
```dart
|
||||
import 'package:my_app/database/database.dart';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:drift_dev/api/migrations.dart';
|
||||
|
||||
// The generated directory from before.
|
||||
import 'generated_migrations/schema.dart';
|
||||
|
||||
void main() {
|
||||
late SchemaVerifier verifier;
|
||||
|
||||
setUpAll(() {
|
||||
// GeneratedHelper() was generated by drift, the verifier is an api
|
||||
// provided by drift_dev.
|
||||
verifier = SchemaVerifier(GeneratedHelper());
|
||||
});
|
||||
|
||||
test('upgrade from v1 to v2', () async {
|
||||
// Use startAt(1) to obtain a database connection with all tables
|
||||
// from the v1 schema.
|
||||
final connection = await verifier.startAt(1);
|
||||
final db = MyDatabase(connection);
|
||||
|
||||
// Use this to run a migration to v2 and then validate that the
|
||||
// database has the expected schema.
|
||||
await verifier.migrateAndValidate(db, 2);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In general, a test looks like this:
|
||||
|
||||
1. Use `verifier.startAt()` to obtain a [connection](https://drift.simonbinder.eu/api/drift/databaseconnection-class)
|
||||
to a database with an initial schema.
|
||||
This database contains all your tables, indices and triggers from that version, created by using `Migrator.createAll`.
|
||||
2. Create your application database with that connection - you can forward the `DatabaseConnection` to the
|
||||
`GeneratedDatabase.connect()` constructor on the parent class for this.
|
||||
3. Call `verifier.migrateAndValidate(db, version)`. This will initiate a migration towards the target version (here, `2`).
|
||||
Unlike the database created by `startAt`, this uses the migration logic you wrote for your database.
|
||||
|
||||
`migrateAndValidate` will extract all `CREATE` statement from the `sqlite_schema` table and semantically compare them.
|
||||
If it sees anything unexpected, it will throw a `SchemaMismatch` exception to fail your test.
|
||||
|
||||
{% block "blocks/alert" title="Writing testable migrations" %}
|
||||
To test migrations _towards_ an old schema version (e.g. from `v1` to `v2` if your current version is `v3`),
|
||||
you're `onUpgrade` handler must be capable of upgrading to a version older than the current `schemaVersion`.
|
||||
For this, check the `to` parameter of the `onUpgrade` callback to run a different migration if necessary.
|
||||
{% endblock %}
|
||||
|
||||
#### Verifying data integrity
|
||||
|
||||
In addition to the changes made in your table structure, its useful to ensure that data that was present before a migration
|
||||
is still there after it ran.
|
||||
You can use `schemaAt` to obtain a raw `Database` from the `sqlite3` package in addition to a connection.
|
||||
This can be used to insert data before a migration. After the migration ran, you can then check that the data is still there.
|
||||
|
||||
Note that you can't use the regular database class from you app for this, since its data classes always expect the latest
|
||||
schema. However, you can instruct drift to generate older snapshots of your data classes and companions for this purpose.
|
||||
To enable this feature, pass the `--data-classes` and `--companions` command-line arguments to the `drift_dev schema generate`
|
||||
command:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema generate --data-classes --companions drift_schemas/ test/generated_migrations/
|
||||
```
|
||||
|
||||
Then, you can import the generated classes with an alias:
|
||||
|
||||
```dart
|
||||
import 'generated_migrations/schema_v1.dart' as v1;
|
||||
import 'generated_migrations/schema_v2.dart' as v2;
|
||||
```
|
||||
|
||||
This can then be used to manually create and verify data at a specific version:
|
||||
|
||||
```dart
|
||||
void main() {
|
||||
// ...
|
||||
test('upgrade from v1 to v2', () async {
|
||||
final schema = await verifier.schemaAt(1);
|
||||
|
||||
// Add some data to the users table, which only has an id column at v1
|
||||
final oldDb = v1.DatabaseAtV1.connect(schema.newConnection());
|
||||
await oldDb.into(oldDb.users).insert(const v1.UsersCompanion(id: Value(1)));
|
||||
await oldDb.close();
|
||||
|
||||
// Run the migration and verify that it adds the name column.
|
||||
final db = Database(schema.newConnection());
|
||||
await verifier.migrateAndValidate(db, 2);
|
||||
await db.close();
|
||||
|
||||
// Make sure the user is still here
|
||||
final migratedDb = v2.DatabaseAtV2.connect(schema.newConnection());
|
||||
final user = await migratedDb.select(migratedDb.users).getSingle();
|
||||
expect(user.id, 1);
|
||||
expect(user.name, 'no name'); // default from the migration
|
||||
await migratedDb.close();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Complex migrations
|
||||
|
||||
Sqlite has builtin statements for simple changes, like adding columns or dropping entire tables.
|
||||
|
@ -235,208 +472,6 @@ the database file and will re-create it when installing the app again.
|
|||
You can also delete and re-create all tables every time your app is opened, see [this comment](https://github.com/simolus3/drift/issues/188#issuecomment-542682912)
|
||||
on how that can be achieved.
|
||||
|
||||
## Verifying migrations
|
||||
|
||||
Drift contains **experimental** support to verify the integrity of your migrations in unit tests.
|
||||
|
||||
To support this feature, drift can help you generate
|
||||
|
||||
- a json representation of your database schema
|
||||
- test databases operating on an older schema version
|
||||
|
||||
By using those test databases, drift can help you test migrations from and to any schema version.
|
||||
|
||||
{% block "blocks/alert" title="Complex topic ahead" %}
|
||||
> Writing schema tests is an advanced topic that requires a fairly complex setup described here.
|
||||
If you get stuck along the way, don't hesitate to [open a discussion about it](https://github.com/simolus3/drift/discussions).
|
||||
Also, there's a working example [in the drift repository](https://github.com/simolus3/drift/tree/latest-release/examples/migrations_example).
|
||||
{% endblock %}
|
||||
|
||||
### Setup
|
||||
|
||||
To use this feature, drift needs to know all schemas of your database. A schema is the set of all tables, triggers
|
||||
and indices that you use in your database.
|
||||
|
||||
You can use the [CLI tools]({{ "../CLI.md" | pageUrl }}) to export a json representation of your schema.
|
||||
In this guide, we'll assume a file layout like the following, where `my_app` is the root folder of your project:
|
||||
|
||||
```
|
||||
my_app
|
||||
.../
|
||||
lib/
|
||||
database/
|
||||
database.dart
|
||||
database.g.dart
|
||||
test/
|
||||
generated_migrations/
|
||||
schema.dart
|
||||
schema_v1.dart
|
||||
schema_v2.dart
|
||||
drift_schemas/
|
||||
drift_schema_v1.json
|
||||
drift_schema_v2.json
|
||||
pubspec.yaml
|
||||
```
|
||||
|
||||
The generated migrations implementation and the schema jsons will be generated by drift.
|
||||
To start writing schemas, create an empty folder named `drift_schemas` in your project.
|
||||
Of course, you can also choose a different name or use a nested subfolder if you want to.
|
||||
|
||||
#### Exporting the schema
|
||||
|
||||
To begin, let's create the first schema representation:
|
||||
|
||||
```
|
||||
$ mkdir drift_schemas
|
||||
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/
|
||||
```
|
||||
|
||||
This instructs the generator to look at the database defined in `lib/database/database.dart` and extract
|
||||
its schema into the new folder.
|
||||
|
||||
After making a change to your database schema, you can run the command again. For instance, let's say we
|
||||
made a change to our tables and increased the `schemaVersion` to `2`. To dump the new schema, just run the
|
||||
command again:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/
|
||||
```
|
||||
|
||||
You'll need to run this command every time you change the schema of your database and increment the `schemaVersion`.
|
||||
|
||||
Drift will name the files in the folder `drift_schema_vX.json`, where `X` is the current `schemaVersion` of your
|
||||
database.
|
||||
If drift is unable to extract the version from your `schemaVersion` getter, provide the full path explicitly:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema dump lib/database/database.dart drift_schemas/drift_schema_v3.json
|
||||
```
|
||||
|
||||
{% block "blocks/alert" title='<i class="fas fa-lightbulb"></i> Dumping a database' color="success" %}
|
||||
If, instead of exporting the schema of a database class, you want to export the schema of an existing sqlite3
|
||||
database file, you can do that as well! `drift_dev schema dump` recognizes a sqlite3 database file as its first
|
||||
argument and can extract the relevant schema from there.
|
||||
{% endblock %}
|
||||
|
||||
#### Generating test code
|
||||
|
||||
After you exported the database schema into a folder, you can generate old versions of your database class
|
||||
based on those schema files.
|
||||
For verifications, drift will generate a much smaller database implementation that can only be used to
|
||||
test migrations.
|
||||
|
||||
You can put this test code whereever you want, but it makes sense to put it in a subfolder of `test/`.
|
||||
If we wanted to write them to `test/generated_migrations/`, we could use
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema generate drift_schemas/ test/generated_migrations/
|
||||
```
|
||||
|
||||
### Writing tests
|
||||
|
||||
After that setup, it's finally time to write some tests! For instance, a test could look like this:
|
||||
|
||||
```dart
|
||||
import 'package:my_app/database/database.dart';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
import 'package:drift_dev/api/migrations.dart';
|
||||
|
||||
// The generated directory from before.
|
||||
import 'generated_migrations/schema.dart';
|
||||
|
||||
void main() {
|
||||
late SchemaVerifier verifier;
|
||||
|
||||
setUpAll(() {
|
||||
// GeneratedHelper() was generated by drift, the verifier is an api
|
||||
// provided by drift_dev.
|
||||
verifier = SchemaVerifier(GeneratedHelper());
|
||||
});
|
||||
|
||||
test('upgrade from v1 to v2', () async {
|
||||
// Use startAt(1) to obtain a database connection with all tables
|
||||
// from the v1 schema.
|
||||
final connection = await verifier.startAt(1);
|
||||
final db = MyDatabase.connect(connection);
|
||||
|
||||
// Use this to run a migration to v2 and then validate that the
|
||||
// database has the expected schema.
|
||||
await verifier.migrateAndValidate(db, 2);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In general, a test looks like this:
|
||||
|
||||
1. Use `verifier.startAt()` to obtain a [connection](https://drift.simonbinder.eu/api/drift/databaseconnection-class)
|
||||
to a database with an initial schema.
|
||||
This database contains all your tables, indices and triggers from that version, created by using `Migrator.createAll`.
|
||||
2. Create your application database with that connection - you can forward the `DatabaseConnection` to the
|
||||
`GeneratedDatabase.connect()` constructor on the parent class for this.
|
||||
3. Call `verifier.migrateAndValidate(db, version)`. This will initiate a migration towards the target version (here, `2`).
|
||||
Unlike the database created by `startAt`, this uses the migration logic you wrote for your database.
|
||||
|
||||
`migrateAndValidate` will extract all `CREATE` statement from the `sqlite_schema` table and semantically compare them.
|
||||
If it sees anything unexpected, it will throw a `SchemaMismatch` exception to fail your test.
|
||||
|
||||
{% block "blocks/alert" title="Writing testable migrations" %}
|
||||
To test migrations _towards_ an old schema version (e.g. from `v1` to `v2` if your current version is `v3`),
|
||||
you're `onUpgrade` handler must be capable of upgrading to a version older than the current `schemaVersion`.
|
||||
For this, check the `to` parameter of the `onUpgrade` callback to run a different migration if necessary.
|
||||
{% endblock %}
|
||||
|
||||
#### Verifying data integrity
|
||||
|
||||
In addition to the changes made in your table structure, its useful to ensure that data that was present before a migration
|
||||
is still there after it ran.
|
||||
You can use `schemaAt` to obtain a raw `Database` from the `sqlite3` package in addition to a connection.
|
||||
This can be used to insert data before a migration. After the migration ran, you can then check that the data is still there.
|
||||
|
||||
Note that you can't use the regular database class from you app for this, since its data classes always expect the latest
|
||||
schema. However, you can instruct drift to generate older snapshots of your data classes and companions for this purpose.
|
||||
To enable this feature, pass the `--data-classes` and `--companions` command-line arguments to the `drift_dev schema generate`
|
||||
command:
|
||||
|
||||
```
|
||||
$ dart run drift_dev schema generate --data-classes --companions drift_schemas/ test/generated_migrations/
|
||||
```
|
||||
|
||||
Then, you can import the generated classes with an alias:
|
||||
|
||||
```dart
|
||||
import 'generated_migrations/schema_v1.dart' as v1;
|
||||
import 'generated_migrations/schema_v2.dart' as v2;
|
||||
```
|
||||
|
||||
This can then be used to manually create and verify data at a specific version:
|
||||
|
||||
```dart
|
||||
void main() {
|
||||
// ...
|
||||
test('upgrade from v1 to v2', () async {
|
||||
final schema = await verifier.schemaAt(1);
|
||||
|
||||
// Add some data to the users table, which only has an id column at v1
|
||||
final oldDb = v1.DatabaseAtV1.connect(schema.newConnection());
|
||||
await oldDb.into(oldDb.users).insert(const v1.UsersCompanion(id: Value(1)));
|
||||
await oldDb.close();
|
||||
|
||||
// Run the migration and verify that it adds the name column.
|
||||
final db = Database(schema.newConnection());
|
||||
await verifier.migrateAndValidate(db, 2);
|
||||
await db.close();
|
||||
|
||||
// Make sure the user is still here
|
||||
final migratedDb = v2.DatabaseAtV2.connect(schema.newConnection());
|
||||
final user = await migratedDb.select(migratedDb.users).getSingle();
|
||||
expect(user.id, 1);
|
||||
expect(user.name, 'no name'); // default from the migration
|
||||
await migratedDb.close();
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Verifying a database schema at runtime
|
||||
|
||||
Instead (or in addition to) [writing tests](#verifying-migrations) to ensure your migrations work as they should,
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
## 2.10.0
|
||||
|
||||
- Adds the `schema steps` command to `drift_dev`. It generates an API making it
|
||||
easier to write safe schema migrations ([docs](https://drift.simonbinder.eu/docs/advanced-features/migrations/#step-by-step)).
|
||||
|
||||
## 2.9.0
|
||||
|
||||
- Forbid `schemaVersion` returning `0`, as this causes issues in the migrator.
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/// Defines base classes to generate lightweight tables and views. This library
|
||||
/// is used by code generated via `drift_dev schema steps` to generate snapshots
|
||||
/// of every schema version of your database without much overhead.
|
||||
///
|
||||
/// For more information on how to use that feature, see
|
||||
/// https://drift.simonbinder.eu/docs/advanced-features/migrations/#step-by-step
|
||||
///
|
||||
/// __Warning:__ This library is not meant to be imported into user-written
|
||||
/// code, and classes defined in this library are not part of drift's stable
|
||||
/// API.
|
||||
library;
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
/// A snapshot of a database schema at a previous version.
|
||||
///
|
||||
/// This class is meant to be extended by generated code.
|
||||
abstract base class VersionedSchema {
|
||||
/// The generated database instance, used to create [TableInfo] instances.
|
||||
final DatabaseConnectionUser database;
|
||||
|
||||
/// The [GeneratedDatabase.schemaVersion] at the time this schema was active.
|
||||
final int version;
|
||||
|
||||
/// Default constructor taking the database and the schema version.
|
||||
VersionedSchema({required this.database, required this.version});
|
||||
|
||||
/// All drift schema entities at the time of the set [version].
|
||||
Iterable<DatabaseSchemaEntity> get entities;
|
||||
}
|
||||
|
||||
/// A drift table implementation that, instead of being generated, is constructed
|
||||
/// from individual fields
|
||||
///
|
||||
/// This allows the code generated for step-by-step migrations to be a lot
|
||||
/// smaller than the code typically generated by drift. Features like type
|
||||
/// converters or information about unique/primary keys are not present in these
|
||||
/// tables.
|
||||
class VersionedTable extends Table with TableInfo<Table, QueryRow> {
|
||||
@override
|
||||
final String entityName;
|
||||
final String? _alias;
|
||||
@override
|
||||
final bool isStrict;
|
||||
|
||||
@override
|
||||
final bool withoutRowId;
|
||||
|
||||
@override
|
||||
final DatabaseConnectionUser attachedDatabase;
|
||||
|
||||
@override
|
||||
final List<GeneratedColumn> $columns;
|
||||
|
||||
/// List of columns, represented as a function that returns the generated
|
||||
/// column when given the resolved table name.
|
||||
final List<GeneratedColumn Function(String)> _columnFactories;
|
||||
|
||||
@override
|
||||
final List<String> customConstraints;
|
||||
|
||||
/// Create a table from the individual fields.
|
||||
///
|
||||
/// [columns] is a list of functions returning a [GeneratedColumn] when given
|
||||
/// the alias (or original name) of this table.
|
||||
VersionedTable({
|
||||
required this.entityName,
|
||||
required this.isStrict,
|
||||
required this.withoutRowId,
|
||||
required this.attachedDatabase,
|
||||
required List<GeneratedColumn Function(String)> columns,
|
||||
required List<String> tableConstraints,
|
||||
String? alias,
|
||||
}) : _columnFactories = columns,
|
||||
customConstraints = tableConstraints,
|
||||
$columns = [for (final column in columns) column(alias ?? entityName)],
|
||||
_alias = alias;
|
||||
|
||||
/// Create a table by copying fields from [source] and applying an [alias].
|
||||
VersionedTable.aliased({
|
||||
required VersionedTable source,
|
||||
required String? alias,
|
||||
}) : entityName = source.entityName,
|
||||
isStrict = source.isStrict,
|
||||
withoutRowId = source.withoutRowId,
|
||||
attachedDatabase = source.attachedDatabase,
|
||||
customConstraints = source.customConstraints,
|
||||
_columnFactories = source._columnFactories,
|
||||
$columns = [
|
||||
for (final column in source._columnFactories)
|
||||
column(alias ?? source.entityName)
|
||||
],
|
||||
_alias = alias;
|
||||
|
||||
@override
|
||||
String get actualTableName => entityName;
|
||||
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
|
||||
@override
|
||||
QueryRow map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
return QueryRow(data, attachedDatabase);
|
||||
}
|
||||
|
||||
@override
|
||||
VersionedTable createAlias(String alias) {
|
||||
return VersionedTable.aliased(source: this, alias: alias);
|
||||
}
|
||||
}
|
||||
|
||||
/// The version of [VersionedTable] for virtual tables.
|
||||
class VersionedVirtualTable extends VersionedTable
|
||||
with VirtualTableInfo<Table, QueryRow> {
|
||||
@override
|
||||
final String moduleAndArgs;
|
||||
|
||||
/// Create a small virtual table from the individual fields.
|
||||
VersionedVirtualTable({
|
||||
required super.entityName,
|
||||
required super.attachedDatabase,
|
||||
required super.columns,
|
||||
required this.moduleAndArgs,
|
||||
super.alias,
|
||||
}) : super(
|
||||
isStrict: false,
|
||||
withoutRowId: false,
|
||||
tableConstraints: [],
|
||||
);
|
||||
|
||||
/// Create a virtual table by copying fields from [source] and applying a
|
||||
/// [alias] to columns.
|
||||
VersionedVirtualTable.aliased(
|
||||
{required VersionedVirtualTable source, required String? alias})
|
||||
: moduleAndArgs = source.moduleAndArgs,
|
||||
super.aliased(source: source, alias: alias);
|
||||
|
||||
@override
|
||||
VersionedVirtualTable createAlias(String alias) {
|
||||
return VersionedVirtualTable.aliased(
|
||||
source: this,
|
||||
alias: alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A constructed from individual fields instead of being generated with a
|
||||
/// dedicated class.
|
||||
class VersionedView implements ViewInfo<HasResultSet, QueryRow>, HasResultSet {
|
||||
@override
|
||||
final String entityName;
|
||||
final String? _alias;
|
||||
|
||||
@override
|
||||
final String createViewStmt;
|
||||
|
||||
@override
|
||||
final List<GeneratedColumn> $columns;
|
||||
|
||||
@override
|
||||
late final Map<String, GeneratedColumn> columnsByName = {
|
||||
for (final column in $columns) column.name: column,
|
||||
};
|
||||
|
||||
/// List of columns, represented as a function that returns the generated
|
||||
/// column when given the resolved table name.
|
||||
final List<GeneratedColumn Function(String)> _columnFactories;
|
||||
|
||||
@override
|
||||
final DatabaseConnectionUser attachedDatabase;
|
||||
|
||||
/// Create a view from the individual fields on [ViewInfo].
|
||||
VersionedView({
|
||||
required this.entityName,
|
||||
required this.attachedDatabase,
|
||||
required this.createViewStmt,
|
||||
required List<GeneratedColumn Function(String)> columns,
|
||||
String? alias,
|
||||
}) : _columnFactories = columns,
|
||||
$columns = [for (final column in columns) column(alias ?? entityName)],
|
||||
_alias = alias;
|
||||
|
||||
/// Copy an alias to a [source] view.
|
||||
VersionedView.aliased({required VersionedView source, required String? alias})
|
||||
: entityName = source.entityName,
|
||||
attachedDatabase = source.attachedDatabase,
|
||||
createViewStmt = source.createViewStmt,
|
||||
_columnFactories = source._columnFactories,
|
||||
$columns = [
|
||||
for (final column in source._columnFactories)
|
||||
column(alias ?? source.entityName)
|
||||
],
|
||||
_alias = alias;
|
||||
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
|
||||
@override
|
||||
HasResultSet get asDslTable => this;
|
||||
|
||||
@override
|
||||
VersionedView createAlias(String alias) {
|
||||
return VersionedView.aliased(source: this, alias: alias);
|
||||
}
|
||||
|
||||
@override
|
||||
QueryRow map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
return QueryRow(data, attachedDatabase);
|
||||
}
|
||||
|
||||
@override
|
||||
Query<HasResultSet, dynamic>? get query => null;
|
||||
|
||||
@override
|
||||
Set<String> get readTables => const {};
|
||||
}
|
|
@ -49,14 +49,22 @@ class MigrationStrategy {
|
|||
/// Runs migrations declared by a [MigrationStrategy].
|
||||
class Migrator {
|
||||
final GeneratedDatabase _db;
|
||||
final VersionedSchema? _fixedVersion;
|
||||
|
||||
/// Used internally by drift when opening the database.
|
||||
Migrator(this._db);
|
||||
Migrator(this._db, [this._fixedVersion]);
|
||||
|
||||
Iterable<DatabaseSchemaEntity> get _allSchemaEntities {
|
||||
return switch (_fixedVersion) {
|
||||
null => _db.allSchemaEntities,
|
||||
var fixed => fixed.entities,
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates all tables specified for the database, if they don't exist
|
||||
@Deprecated('Use createAll() instead')
|
||||
Future<void> createAllTables() async {
|
||||
for (final table in _db.allTables) {
|
||||
for (final table in _allSchemaEntities.whereType<TableInfo>()) {
|
||||
await createTable(table);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +72,7 @@ class Migrator {
|
|||
/// Creates all tables, triggers, views, indexes and everything else defined
|
||||
/// in the database, if they don't exist.
|
||||
Future<void> createAll() async {
|
||||
for (final entity in _db.allSchemaEntities) {
|
||||
for (final entity in _allSchemaEntities) {
|
||||
await create(entity);
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +102,7 @@ class Migrator {
|
|||
/// a view reads from may also warrant re-creating the view to make sure it's
|
||||
/// still valid.
|
||||
Future<void> recreateAllViews() async {
|
||||
for (final entity in _db.allSchemaEntities) {
|
||||
for (final entity in _allSchemaEntities) {
|
||||
if (entity is ViewInfo) {
|
||||
await drop(entity);
|
||||
await createView(entity);
|
||||
|
@ -119,7 +127,7 @@ class Migrator {
|
|||
return _issueCustomQuery(context.sql, context.boundVariables);
|
||||
}
|
||||
|
||||
/// Experimental utility method to alter columns of an existing table.
|
||||
/// Alter columns of an existing tabe.
|
||||
///
|
||||
/// Since sqlite does not provide a way to alter the type or constraint of an
|
||||
/// individual column, one needs to write a fairly complex migration procedure
|
||||
|
@ -141,7 +149,6 @@ class Migrator {
|
|||
///
|
||||
/// [other alter]: https://www.sqlite.org/lang_altertable.html#otheralter
|
||||
/// [drift docs]: https://drift.simonbinder.eu/docs/advanced-features/migrations/#complex-migrations
|
||||
@experimental
|
||||
Future<void> alterTable(TableMigration migration) async {
|
||||
final foreignKeysEnabled =
|
||||
(await _db.customSelect('PRAGMA foreign_keys').getSingle())
|
||||
|
@ -474,6 +481,31 @@ class Migrator {
|
|||
Future<void> _issueCustomQuery(String sql, [List<dynamic>? args]) {
|
||||
return _db.customStatement(sql, args);
|
||||
}
|
||||
|
||||
/// A helper used by drift internally to implement the [step-by-step](https://drift.simonbinder.eu/docs/advanced-features/migrations/#step-by-step)
|
||||
/// migration feature.
|
||||
///
|
||||
/// This method implements an [OnUpgrade] callback by repeatedly invoking
|
||||
/// [step] with the current version, assuming that [step] will perform an
|
||||
/// upgrade from that version to the version returned by the callback.
|
||||
@experimental
|
||||
static OnUpgrade stepByStepHelper({
|
||||
required Future<int> Function(
|
||||
int currentVersion,
|
||||
GeneratedDatabase database,
|
||||
) step,
|
||||
}) {
|
||||
return (m, from, to) async {
|
||||
final database = m._db;
|
||||
|
||||
for (var target = from; target < to;) {
|
||||
final newVersion = await step(target, database);
|
||||
assert(newVersion > target);
|
||||
|
||||
target = newVersion;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides information about whether migrations ran before opening the
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:collection';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:drift/internal/versioned_schema.dart';
|
||||
import 'package:drift/src/dsl/dsl.dart';
|
||||
import 'package:drift/src/runtime/api/options.dart';
|
||||
import 'package:drift/src/runtime/api/runtime_api.dart';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/internal/versioned_schema.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
|
@ -211,6 +212,78 @@ void main() {
|
|||
// https://github.com/simolus3/drift/discussions/1936
|
||||
verify(executor.runCustom(argThat(contains('CHECK("foo" < 3)')), []));
|
||||
});
|
||||
|
||||
group('respects schema version', () {
|
||||
late MockExecutor executor;
|
||||
late _DefaultDb db;
|
||||
|
||||
setUp(() async {
|
||||
executor = MockExecutor();
|
||||
db = _DefaultDb(executor);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('in createAll', () async {
|
||||
final defaultMigrator = db.createMigrator();
|
||||
await defaultMigrator.createAll();
|
||||
verifyNever(executor.runCustom(any));
|
||||
|
||||
final fixedMigrator =
|
||||
Migrator(db, _FakeSchemaVersion(database: db, version: 2));
|
||||
await fixedMigrator.createAll();
|
||||
verify(executor.runCustom(
|
||||
'CREATE TABLE IF NOT EXISTS "my_table" ("foo" INTEGER NOT NULL);',
|
||||
[],
|
||||
));
|
||||
verify(executor.runCustom(
|
||||
'CREATE VIEW my_view AS SELECT 2',
|
||||
[],
|
||||
));
|
||||
});
|
||||
|
||||
test('in recreateViews', () async {
|
||||
final defaultMigrator = db.createMigrator();
|
||||
await defaultMigrator.recreateAllViews();
|
||||
verifyNever(executor.runCustom(any));
|
||||
|
||||
final fixedMigrator =
|
||||
Migrator(db, _FakeSchemaVersion(database: db, version: 2));
|
||||
await fixedMigrator.recreateAllViews();
|
||||
|
||||
verify(executor.runCustom(
|
||||
'CREATE VIEW my_view AS SELECT 2',
|
||||
[],
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
final class _FakeSchemaVersion extends VersionedSchema {
|
||||
_FakeSchemaVersion({required super.database, required super.version});
|
||||
|
||||
@override
|
||||
Iterable<DatabaseSchemaEntity> get entities => [
|
||||
VersionedTable(
|
||||
entityName: 'my_table',
|
||||
attachedDatabase: database,
|
||||
columns: [
|
||||
(name) => GeneratedColumn<int>('foo', name, false,
|
||||
type: DriftSqlType.int),
|
||||
],
|
||||
tableConstraints: [],
|
||||
isStrict: false,
|
||||
withoutRowId: false,
|
||||
),
|
||||
VersionedView(
|
||||
entityName: 'my_view',
|
||||
attachedDatabase: database,
|
||||
createViewStmt: 'CREATE VIEW my_view AS SELECT $version',
|
||||
columns: [],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
class _DefaultDb extends GeneratedDatabase {
|
||||
|
@ -219,6 +292,9 @@ class _DefaultDb extends GeneratedDatabase {
|
|||
@override
|
||||
List<TableInfo<Table, DataClass>> get allTables => [];
|
||||
|
||||
@override
|
||||
Iterable<DatabaseSchemaEntity> get allSchemaEntities => [];
|
||||
|
||||
@override
|
||||
int get schemaVersion => 2;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class DriftTable extends DriftElementWithResultSet {
|
|||
/// when creating the `CREATE TABLE` statement at runtime.
|
||||
final bool writeDefaultConstraints;
|
||||
|
||||
/// When non-null, the generated table class will override the
|
||||
/// When non-empty, the generated table class will override the
|
||||
/// `customConstraints` getter in the table class with this value.
|
||||
final List<String> overrideTableConstraints;
|
||||
|
||||
|
@ -169,21 +169,21 @@ class DriftTable extends DriftElementWithResultSet {
|
|||
'\$${className}Table';
|
||||
}
|
||||
|
||||
abstract class DriftTableConstraint {}
|
||||
sealed class DriftTableConstraint {}
|
||||
|
||||
class UniqueColumns extends DriftTableConstraint {
|
||||
final class UniqueColumns extends DriftTableConstraint {
|
||||
final Set<DriftColumn> uniqueSet;
|
||||
|
||||
UniqueColumns(this.uniqueSet);
|
||||
}
|
||||
|
||||
class PrimaryKeyColumns extends DriftTableConstraint {
|
||||
final class PrimaryKeyColumns extends DriftTableConstraint {
|
||||
final Set<DriftColumn> primaryKey;
|
||||
|
||||
PrimaryKeyColumns(this.primaryKey);
|
||||
}
|
||||
|
||||
class ForeignKeyTable extends DriftTableConstraint {
|
||||
final class ForeignKeyTable extends DriftTableConstraint {
|
||||
final List<DriftColumn> localColumns;
|
||||
final DriftTable otherTable;
|
||||
|
||||
|
@ -214,6 +214,12 @@ class VirtualTableData {
|
|||
|
||||
final RecognizedVirtualTableModule? recognized;
|
||||
|
||||
/// The module and the arguments in a single string, suitable for `CREATE
|
||||
/// VIRTUAL TABLE` statements.
|
||||
String get moduleAndArgs {
|
||||
return '$module(${moduleArguments.join(', ')})';
|
||||
}
|
||||
|
||||
VirtualTableData(this.module, this.moduleArguments, this.recognized);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import 'commands/schema.dart';
|
|||
import 'logging.dart';
|
||||
|
||||
Future run(List<String> args) async {
|
||||
final cli = MoorCli();
|
||||
final cli = DriftDevCli();
|
||||
try {
|
||||
return await cli.run(args);
|
||||
} on UsageException catch (e) {
|
||||
|
@ -21,14 +21,14 @@ Future run(List<String> args) async {
|
|||
}
|
||||
}
|
||||
|
||||
class MoorCli {
|
||||
class DriftDevCli {
|
||||
Logger get logger => Logger.root;
|
||||
late final CommandRunner _runner;
|
||||
late final MoorProject project;
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
MoorCli() {
|
||||
DriftDevCli() {
|
||||
_runner = CommandRunner(
|
||||
'dart run drift_dev',
|
||||
'CLI utilities for the drift package, currently in an experimental state.',
|
||||
|
@ -72,7 +72,7 @@ class MoorCli {
|
|||
}
|
||||
|
||||
abstract class MoorCommand extends Command {
|
||||
final MoorCli cli;
|
||||
final DriftDevCli cli;
|
||||
|
||||
MoorCommand(this.cli);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:io';
|
|||
import '../cli.dart';
|
||||
|
||||
class AnalyzeCommand extends MoorCommand {
|
||||
AnalyzeCommand(MoorCli cli) : super(cli);
|
||||
AnalyzeCommand(DriftDevCli cli) : super(cli);
|
||||
|
||||
@override
|
||||
String get description => 'Analyze and lint drift database code';
|
||||
|
|
|
@ -7,7 +7,7 @@ import '../../analysis/results/results.dart';
|
|||
import '../cli.dart';
|
||||
|
||||
class IdentifyDatabases extends MoorCommand {
|
||||
IdentifyDatabases(MoorCli cli) : super(cli);
|
||||
IdentifyDatabases(DriftDevCli cli) : super(cli);
|
||||
|
||||
@override
|
||||
String get description =>
|
||||
|
|
|
@ -23,7 +23,7 @@ class MigrateCommand extends MoorCommand {
|
|||
|
||||
late final AnalysisContext context;
|
||||
|
||||
MigrateCommand(MoorCli cli) : super(cli);
|
||||
MigrateCommand(DriftDevCli cli) : super(cli);
|
||||
|
||||
@override
|
||||
String get description => 'Migrate a project from moor to drift';
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import 'package:args/command_runner.dart';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import '../../analysis/results/results.dart';
|
||||
import '../../services/schema/schema_files.dart';
|
||||
import 'schema/dump.dart';
|
||||
import 'schema/generate_utils.dart';
|
||||
|
||||
import '../cli.dart';
|
||||
import 'schema/steps.dart';
|
||||
|
||||
class SchemaCommand extends Command {
|
||||
@override
|
||||
|
@ -12,8 +19,37 @@ class SchemaCommand extends Command {
|
|||
@override
|
||||
String get name => 'schema';
|
||||
|
||||
SchemaCommand(MoorCli cli) {
|
||||
SchemaCommand(DriftDevCli cli) {
|
||||
addSubcommand(DumpSchemaCommand(cli));
|
||||
addSubcommand(GenerateUtilsCommand(cli));
|
||||
addSubcommand(WriteVersions(cli));
|
||||
}
|
||||
}
|
||||
|
||||
class ExportedSchema {
|
||||
final List<DriftElement> schema;
|
||||
final Map<String, Object?> options;
|
||||
|
||||
ExportedSchema(this.schema, this.options);
|
||||
}
|
||||
|
||||
final _filenames = RegExp(r'(?:moor|drift)_schema_v(\d+)\.json');
|
||||
|
||||
Future<Map<int, ExportedSchema>> parseSchema(Directory directory) async {
|
||||
final results = <int, ExportedSchema>{};
|
||||
|
||||
await for (final entity in directory.list()) {
|
||||
final basename = p.basename(entity.path);
|
||||
final match = _filenames.firstMatch(basename);
|
||||
|
||||
if (match == null || entity is! File) continue;
|
||||
|
||||
final version = int.parse(match.group(1)!);
|
||||
final rawData = json.decode(await entity.readAsString());
|
||||
|
||||
final schema = SchemaReader.readJson(rawData as Map<String, dynamic>);
|
||||
results[version] = ExportedSchema(schema.entities.toList(), schema.options);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class DumpSchemaCommand extends Command {
|
|||
return '${runner!.executableName} schema dump [arguments] <input> <output>';
|
||||
}
|
||||
|
||||
final MoorCli cli;
|
||||
final DriftDevCli cli;
|
||||
|
||||
DumpSchemaCommand(this.cli) {
|
||||
argParser.addSeparator("It's recommended to run this commend from the "
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
|
@ -13,9 +12,10 @@ import '../../../writer/database_writer.dart';
|
|||
import '../../../writer/import_manager.dart';
|
||||
import '../../../writer/writer.dart';
|
||||
import '../../cli.dart';
|
||||
import '../schema.dart';
|
||||
|
||||
class GenerateUtilsCommand extends Command {
|
||||
final MoorCli cli;
|
||||
final DriftDevCli cli;
|
||||
|
||||
GenerateUtilsCommand(this.cli) {
|
||||
argParser.addFlag(
|
||||
|
@ -61,7 +61,7 @@ class GenerateUtilsCommand extends Command {
|
|||
await outputDir.create();
|
||||
}
|
||||
|
||||
final schema = await _parseSchema(inputDir);
|
||||
final schema = await parseSchema(inputDir);
|
||||
for (final versionAndEntities in schema.entries) {
|
||||
final version = versionAndEntities.key;
|
||||
final entities = versionAndEntities.value;
|
||||
|
@ -81,30 +81,10 @@ class GenerateUtilsCommand extends Command {
|
|||
'Wrote ${schema.length + 1} files into ${p.relative(outputDir.path)}');
|
||||
}
|
||||
|
||||
Future<Map<int, _ExportedSchema>> _parseSchema(Directory directory) async {
|
||||
final results = <int, _ExportedSchema>{};
|
||||
|
||||
await for (final entity in directory.list()) {
|
||||
final basename = p.basename(entity.path);
|
||||
final match = _filenames.firstMatch(basename);
|
||||
|
||||
if (match == null || entity is! File) continue;
|
||||
|
||||
final version = int.parse(match.group(1)!);
|
||||
final rawData = json.decode(await entity.readAsString());
|
||||
|
||||
final schema = SchemaReader.readJson(rawData as Map<String, dynamic>);
|
||||
results[version] =
|
||||
_ExportedSchema(schema.entities.toList(), schema.options);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
Future<void> _writeSchemaFile(
|
||||
Directory output,
|
||||
int version,
|
||||
_ExportedSchema schema,
|
||||
ExportedSchema schema,
|
||||
bool dataClasses,
|
||||
bool companions,
|
||||
) {
|
||||
|
@ -184,15 +164,7 @@ class GenerateUtilsCommand extends Command {
|
|||
|
||||
String _filenameForVersion(int version) => 'schema_v$version.dart';
|
||||
|
||||
static final _filenames = RegExp(r'(?:moor|drift)_schema_v(\d+)\.json');
|
||||
static final _dartfmt = DartFormatter();
|
||||
static const _prefix = '// GENERATED CODE, DO NOT EDIT BY HAND.\n'
|
||||
'// ignore_for_file: type=lint';
|
||||
}
|
||||
|
||||
class _ExportedSchema {
|
||||
final List<DriftElement> schema;
|
||||
final Map<String, Object?> options;
|
||||
|
||||
_ExportedSchema(this.schema, this.options);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:args/command_runner.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
|
||||
import '../../../analysis/options.dart';
|
||||
import '../../../analysis/results/element.dart';
|
||||
import '../../../writer/import_manager.dart';
|
||||
import '../../../writer/schema_version_writer.dart';
|
||||
import '../../../writer/writer.dart';
|
||||
import '../../cli.dart';
|
||||
import '../schema.dart';
|
||||
|
||||
class WriteVersions extends Command {
|
||||
final DriftDevCli cli;
|
||||
|
||||
WriteVersions(this.cli);
|
||||
|
||||
@override
|
||||
String get name => 'steps';
|
||||
|
||||
@override
|
||||
String get description =>
|
||||
'Write a Dart file helping with incremental migrations between schema versions.';
|
||||
|
||||
@override
|
||||
String get invocation {
|
||||
return '${runner!.executableName} schema steps <schema directory> <output file>';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> run() async {
|
||||
final rest = argResults!.rest;
|
||||
if (rest.length != 2) {
|
||||
usageException('Expected input and output directories');
|
||||
}
|
||||
|
||||
final inputDirectory = Directory(rest[0]);
|
||||
final outputFile = File(rest[1]);
|
||||
final outputDirectory = outputFile.parent;
|
||||
|
||||
if (!await inputDirectory.exists()) {
|
||||
cli.exit('The provided input directory does not exist.');
|
||||
}
|
||||
|
||||
if (!await outputDirectory.exists()) {
|
||||
await outputDirectory.create();
|
||||
}
|
||||
|
||||
final imports = LibraryImportManager();
|
||||
final writer = Writer(
|
||||
const DriftOptions.defaults(),
|
||||
generationOptions: GenerationOptions(imports: imports),
|
||||
);
|
||||
imports.linkToWriter(writer);
|
||||
|
||||
final schema = await parseSchema(inputDirectory);
|
||||
final byVersion = [
|
||||
for (final MapEntry(key: version, value: schema) in schema.entries)
|
||||
SchemaVersion(
|
||||
version,
|
||||
schema.schema.whereType<DriftSchemaElement>().toList(),
|
||||
schema.options,
|
||||
),
|
||||
];
|
||||
byVersion.sortBy<num>((s) => s.version);
|
||||
|
||||
writer.leaf().write("import 'package:drift/drift.dart';");
|
||||
SchemaVersionWriter(byVersion, writer.child()).write();
|
||||
|
||||
var code = writer.writeGenerated();
|
||||
try {
|
||||
code = DartFormatter().format(code);
|
||||
} on FormatterException {
|
||||
// Ignore. Probably a bug in drift_dev, the user will notice.
|
||||
}
|
||||
|
||||
await outputFile.writeAsString(code);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,398 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:drift/drift.dart' show DriftSqlType;
|
||||
import 'package:sqlparser/sqlparser.dart' as sql;
|
||||
import 'package:sqlparser/utils/node_to_text.dart';
|
||||
|
||||
import '../analysis/results/results.dart';
|
||||
import '../utils/string_escaper.dart';
|
||||
import 'tables/table_writer.dart';
|
||||
import 'writer.dart';
|
||||
|
||||
class SchemaVersion {
|
||||
final int version;
|
||||
final List<DriftSchemaElement> schema;
|
||||
final Map<String, Object?> options;
|
||||
|
||||
SchemaVersion(this.version, this.schema, this.options);
|
||||
}
|
||||
|
||||
enum _ResultSetKind {
|
||||
table,
|
||||
virtualTable,
|
||||
view,
|
||||
}
|
||||
|
||||
final class _TableShape {
|
||||
final _ResultSetKind kind;
|
||||
|
||||
// Map from Dart getter names to column names in SQL and the SQL type.
|
||||
final Map<String, (String, DriftSqlType)> columnTypes;
|
||||
|
||||
_TableShape(this.kind, this.columnTypes);
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(kind, _equality.hash(columnTypes));
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is _TableShape &&
|
||||
other.kind == kind &&
|
||||
_equality.equals(other.columnTypes, columnTypes);
|
||||
}
|
||||
|
||||
static const _equality = MapEquality<String, (String, DriftSqlType)>();
|
||||
|
||||
static Map<String, (String, DriftSqlType)> columnsFrom(
|
||||
DriftElementWithResultSet e) {
|
||||
return {
|
||||
for (final column in e.columns)
|
||||
column.nameInDart: (column.nameInSql, column.sqlType),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// A writer that writes schema code for all schema versions known to us.
|
||||
///
|
||||
/// While other tools to generate code for a specific schema version exists
|
||||
/// (we use it to generate test code), the generated code is very large since
|
||||
/// it can contain data classes and all information known to drift.
|
||||
/// Code generated by this writer is optimized to be compact by hiding table
|
||||
/// metadata not strictly necessary for migrations and by re-using column
|
||||
/// definitions where possible.
|
||||
class SchemaVersionWriter {
|
||||
static final Uri _schemaLibrary =
|
||||
Uri.parse('package:drift/internal/versioned_schema.dart');
|
||||
|
||||
/// All schema versions, sorted by [SchemaVersion.version].
|
||||
final List<SchemaVersion> versions;
|
||||
final Scope libraryScope;
|
||||
|
||||
final Map<String, String> _columnCodeToFactory = {};
|
||||
final Map<_TableShape, String> _shapes = {};
|
||||
|
||||
SchemaVersionWriter(this.versions, this.libraryScope) {
|
||||
assert(versions.isSortedBy<num>((element) => element.version));
|
||||
}
|
||||
|
||||
/// Since not every column changes in every schema version, we prefer to re-use
|
||||
/// columns with an identical definition across tables and schema versions.
|
||||
///
|
||||
/// We do this by generating a method constructing the column which can be
|
||||
/// called in different places. This method looks up or creates a method for
|
||||
/// the given [column], returning it if doesn't exist.
|
||||
String _referenceColumn(DriftColumn column) {
|
||||
final text = libraryScope.leaf();
|
||||
final (type, code) = TableOrViewWriter.instantiateColumn(column, text);
|
||||
|
||||
return _columnCodeToFactory.putIfAbsent(code, () {
|
||||
final methodName = '_column_${_columnCodeToFactory.length}';
|
||||
text.writeln('$type $methodName(String aliasedName) => $code;');
|
||||
return methodName;
|
||||
});
|
||||
}
|
||||
|
||||
void _writeColumnsArgument(List<DriftColumn> columns, TextEmitter writer) {
|
||||
writer.write('columns: [');
|
||||
|
||||
for (final column in columns) {
|
||||
writer
|
||||
..write(_referenceColumn(column))
|
||||
..write(',');
|
||||
}
|
||||
|
||||
writer.write('],');
|
||||
}
|
||||
|
||||
/// Finds a class to use for [resultSet].
|
||||
///
|
||||
/// When only minor details like column or table constraints change, we don't
|
||||
/// want to introduce a new class. The interface of a class is only determined
|
||||
/// by its kind (since we need to subclass from VersionedTable,
|
||||
/// VersionedVirtualTable or VersionedView) and its public getters used to
|
||||
/// access columns.
|
||||
///
|
||||
/// This looks up a suitable class for the existing [resultSet] or creates a
|
||||
/// new one, returning its name.
|
||||
String _shapeClass(DriftElementWithResultSet resultSet) {
|
||||
final (kind, superclass) = switch (resultSet) {
|
||||
DriftTable(virtualTableData: null) => (
|
||||
_ResultSetKind.table,
|
||||
'VersionedTable'
|
||||
),
|
||||
DriftTable() => (_ResultSetKind.virtualTable, 'VersionedVirtualTable'),
|
||||
DriftView() => (_ResultSetKind.view, 'VersionedView'),
|
||||
_ => throw ArgumentError.value(resultSet, 'resultSet', 'Unknown type'),
|
||||
};
|
||||
|
||||
final shape = _TableShape(kind, _TableShape.columnsFrom(resultSet));
|
||||
return _shapes.putIfAbsent(shape, () {
|
||||
final className = 'Shape${_shapes.length}';
|
||||
final classWriter = libraryScope.leaf();
|
||||
|
||||
classWriter
|
||||
..write('class $className extends ')
|
||||
..writeUriRef(_schemaLibrary, superclass)
|
||||
..writeln('{')
|
||||
..writeln(
|
||||
'$className({required super.source, required super.alias}) : super.aliased();');
|
||||
|
||||
for (final MapEntry(key: getterName, value: (sqlName, type))
|
||||
in shape.columnTypes.entries) {
|
||||
final columnType = AnnotatedDartCode([dartTypeNames[type]!]);
|
||||
|
||||
classWriter
|
||||
..writeDriftRef('GeneratedColumn<')
|
||||
..writeDart(columnType)
|
||||
..write('> get ')
|
||||
..write(getterName)
|
||||
..write(' => columnsByName[${asDartLiteral(sqlName)}]! as ')
|
||||
..writeDriftRef('GeneratedColumn<')
|
||||
..writeDart(columnType)
|
||||
..writeln('>;');
|
||||
}
|
||||
|
||||
classWriter.writeln('}');
|
||||
|
||||
return className;
|
||||
});
|
||||
}
|
||||
|
||||
String _writeWithResultSet(
|
||||
DriftElementWithResultSet entity, TextEmitter writer) {
|
||||
final getterName = entity.dbGetterName;
|
||||
final shape = _shapeClass(entity);
|
||||
writer
|
||||
..write('late final $shape $getterName = ')
|
||||
..write('$shape(source: ');
|
||||
|
||||
switch (entity) {
|
||||
case DriftTable():
|
||||
if (entity.isVirtual) {
|
||||
final info = entity.virtualTableData!;
|
||||
|
||||
writer
|
||||
..writeUriRef(_schemaLibrary, 'VersionedVirtualTable(')
|
||||
..write('entityName: ${asDartLiteral(entity.schemaName)},')
|
||||
..write('moduleAndArgs: ${asDartLiteral(info.moduleAndArgs)},');
|
||||
} else {
|
||||
final tableConstraints = <String>[];
|
||||
|
||||
if (entity.writeDefaultConstraints) {
|
||||
// We don't override primaryKey and uniqueKey in generated table
|
||||
// classes to keep the code shorter. The migrator would use those
|
||||
// getters to generate SQL at runtime, which means that this burden
|
||||
// now falls onto the generator.
|
||||
for (final constraint in entity.tableConstraints) {
|
||||
final astNode = switch (constraint) {
|
||||
PrimaryKeyColumns(primaryKey: var columns) => sql.KeyClause(
|
||||
null,
|
||||
isPrimaryKey: true,
|
||||
columns: [
|
||||
for (final column in columns)
|
||||
sql.IndexedColumn(
|
||||
sql.Reference(columnName: column.nameInSql))
|
||||
],
|
||||
),
|
||||
UniqueColumns(uniqueSet: var columns) => sql.KeyClause(
|
||||
null,
|
||||
isPrimaryKey: false,
|
||||
columns: [
|
||||
for (final column in columns)
|
||||
sql.IndexedColumn(
|
||||
sql.Reference(columnName: column.nameInSql))
|
||||
],
|
||||
),
|
||||
ForeignKeyTable() => sql.ForeignKeyTableConstraint(
|
||||
null,
|
||||
columns: [
|
||||
for (final column in constraint.localColumns)
|
||||
sql.Reference(columnName: column.nameInSql)
|
||||
],
|
||||
clause: sql.ForeignKeyClause(
|
||||
foreignTable:
|
||||
sql.TableReference(constraint.otherTable.schemaName),
|
||||
columnNames: [
|
||||
for (final column in constraint.otherColumns)
|
||||
sql.Reference(columnName: column.nameInSql)
|
||||
],
|
||||
onUpdate: constraint.onUpdate,
|
||||
onDelete: constraint.onDelete,
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
tableConstraints.add(astNode.toSql());
|
||||
}
|
||||
}
|
||||
tableConstraints.addAll(entity.overrideTableConstraints.toList());
|
||||
|
||||
writer
|
||||
..writeUriRef(_schemaLibrary, 'VersionedTable(')
|
||||
..write('entityName: ${asDartLiteral(entity.schemaName)},')
|
||||
..write('withoutRowId: ${entity.withoutRowId},')
|
||||
..write('isStrict: ${entity.strict},')
|
||||
..write('tableConstraints: [');
|
||||
|
||||
for (final constraint in tableConstraints) {
|
||||
writer
|
||||
..write(asDartLiteral(constraint))
|
||||
..write(',');
|
||||
}
|
||||
|
||||
writer.write('],');
|
||||
}
|
||||
break;
|
||||
case DriftView():
|
||||
final source = entity.source as SqlViewSource;
|
||||
|
||||
writer
|
||||
..writeUriRef(_schemaLibrary, 'VersionedView(')
|
||||
..write('entityName: ${asDartLiteral(entity.schemaName)},')
|
||||
..write(
|
||||
'createViewStmt: ${asDartLiteral(source.sqlCreateViewStmt)},');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_writeColumnsArgument(entity.columns, writer);
|
||||
writer.write('attachedDatabase: database,');
|
||||
writer.write('), alias: null)');
|
||||
|
||||
return getterName!;
|
||||
}
|
||||
|
||||
String _writeEntity({
|
||||
required DriftSchemaElement element,
|
||||
required TextEmitter definition,
|
||||
}) {
|
||||
String name;
|
||||
|
||||
if (element is DriftElementWithResultSet) {
|
||||
name = _writeWithResultSet(element, definition);
|
||||
} else if (element is DriftIndex) {
|
||||
name = element.dbGetterName;
|
||||
final index = definition.drift('Index');
|
||||
|
||||
definition
|
||||
..write('final $index $name = $index(')
|
||||
..write(asDartLiteral(element.schemaName))
|
||||
..write(',')
|
||||
..write(asDartLiteral(element.createStmt))
|
||||
..write(')');
|
||||
} else if (element is DriftTrigger) {
|
||||
name = element.dbGetterName;
|
||||
final trigger = definition.drift('Trigger');
|
||||
|
||||
definition
|
||||
..write('final $trigger $name = $trigger(')
|
||||
..write(asDartLiteral(element.createStmt))
|
||||
..write(',')
|
||||
..write(asDartLiteral(element.schemaName))
|
||||
..write(')');
|
||||
} else {
|
||||
throw ArgumentError('Unhandled element type $element');
|
||||
}
|
||||
|
||||
definition.write(';');
|
||||
return name;
|
||||
}
|
||||
|
||||
void write() {
|
||||
libraryScope.leaf()
|
||||
..writeln('// ignore_for_file: type=lint,unused_import')
|
||||
..writeln('// GENERATED BY drift_dev, DO NOT MODIFY.');
|
||||
|
||||
// There is no need to generate schema classes for the first version, we
|
||||
// only need them for versions targeted by migrations.
|
||||
for (final version in versions.skip(1)) {
|
||||
final versionNo = version.version;
|
||||
final versionClass = '_S$versionNo';
|
||||
final versionScope = libraryScope.child();
|
||||
|
||||
// Write an _S<x> class for each schema version x.
|
||||
versionScope.leaf()
|
||||
..write('final class $versionClass extends ')
|
||||
..writeUriRef(_schemaLibrary, 'VersionedSchema')
|
||||
..writeln('{')
|
||||
..writeln('$versionClass({required super.database}): '
|
||||
'super(version: $versionNo);');
|
||||
|
||||
// Override the allEntities getters by VersionedSchema
|
||||
final allEntitiesWriter = versionScope.leaf()
|
||||
..write('@override late final ')
|
||||
..writeUriRef(AnnotatedDartCode.dartCore, 'List')
|
||||
..write('<')
|
||||
..writeDriftRef('DatabaseSchemaEntity')
|
||||
..write('> entities = [');
|
||||
|
||||
for (final entity in version.schema) {
|
||||
// Creata field for the entity and include it in the list
|
||||
final fieldName =
|
||||
_writeEntity(element: entity, definition: versionScope.leaf());
|
||||
|
||||
allEntitiesWriter.write('$fieldName,');
|
||||
}
|
||||
|
||||
allEntitiesWriter.write('];');
|
||||
versionScope.leaf().writeln('}');
|
||||
}
|
||||
|
||||
// Write a stepByStep migration function that takes a callback doing a step
|
||||
// for each schema to the next. We supply a special migrator that only
|
||||
// considers entities from that version, as well as a typed reference to the
|
||||
// _S<x> class used to lookup elements.
|
||||
final stepByStep = libraryScope.leaf()
|
||||
..writeDriftRef('OnUpgrade')
|
||||
..write(' stepByStep({');
|
||||
|
||||
for (final (current, next) in versions.withNext) {
|
||||
stepByStep
|
||||
..write('required Future<void> Function(')
|
||||
..writeDriftRef('Migrator')
|
||||
..write(' m, _S${next.version} schema)')
|
||||
..writeln('from${current.version}To${next.version},');
|
||||
}
|
||||
|
||||
stepByStep
|
||||
..writeln('}) {')
|
||||
..write('return ')
|
||||
..writeDriftRef('Migrator')
|
||||
..writeln('.stepByStepHelper(step: (currentVersion, database) async {')
|
||||
..writeln('switch (currentVersion) {');
|
||||
|
||||
for (final (current, next) in versions.withNext) {
|
||||
stepByStep
|
||||
..writeln('case ${current.version}:')
|
||||
..write('final schema = _S${next.version}(database: database);')
|
||||
..write('final migrator = ')
|
||||
..writeDriftRef('Migrator')
|
||||
..writeln('(database, schema);')
|
||||
..writeln(
|
||||
'await from${current.version}To${next.version}(migrator, schema);')
|
||||
..writeln('return ${next.version};');
|
||||
}
|
||||
|
||||
stepByStep
|
||||
..writeln(
|
||||
r"default: throw ArgumentError.value('Unknown migration from $currentVersion');")
|
||||
..writeln('}') // End of switch
|
||||
..writeln('}') // End of stepByStepHelper function
|
||||
..writeln(');') // End of stepByStepHelper call
|
||||
..writeln('}'); // End of method
|
||||
}
|
||||
}
|
||||
|
||||
extension<T> on Iterable<T> {
|
||||
Iterable<(T, T)> get withNext sync* {
|
||||
final iterator = this.iterator;
|
||||
if (!iterator.moveNext()) return;
|
||||
|
||||
var a = iterator.current;
|
||||
while (iterator.moveNext()) {
|
||||
var b = iterator.current;
|
||||
yield (a, b);
|
||||
|
||||
a = b;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,140 +16,24 @@ abstract class TableOrViewWriter {
|
|||
StringBuffer get buffer => emitter.buffer;
|
||||
|
||||
void writeColumnGetter(DriftColumn column, bool isOverride) {
|
||||
final isNullable = column.nullable;
|
||||
final additionalParams = <String, String>{};
|
||||
final expressionBuffer = StringBuffer();
|
||||
final constraints = defaultConstraints(column);
|
||||
|
||||
for (final constraint in column.constraints) {
|
||||
if (constraint is LimitingTextLength) {
|
||||
final buffer =
|
||||
StringBuffer(emitter.drift('GeneratedColumn.checkTextLength('));
|
||||
|
||||
if (constraint.minLength != null) {
|
||||
buffer.write('minTextLength: ${constraint.minLength},');
|
||||
}
|
||||
if (constraint.maxLength != null) {
|
||||
buffer.write('maxTextLength: ${constraint.maxLength}');
|
||||
}
|
||||
buffer.write(')');
|
||||
|
||||
additionalParams['additionalChecks'] = buffer.toString();
|
||||
}
|
||||
|
||||
if (constraint is DartCheckExpression) {
|
||||
final dartCheck = emitter.dartCode(constraint.dartExpression);
|
||||
additionalParams['check'] = '() => $dartCheck';
|
||||
}
|
||||
|
||||
if (constraint is ColumnGeneratedAs) {
|
||||
final dartCode = emitter.dartCode(constraint.dartExpression);
|
||||
|
||||
additionalParams['generatedAs'] =
|
||||
'${emitter.drift('GeneratedAs')}($dartCode, ${constraint.stored})';
|
||||
}
|
||||
|
||||
if (constraint is PrimaryKeyColumn && constraint.isAutoIncrement) {
|
||||
additionalParams['hasAutoIncrement'] = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
additionalParams['type'] = emitter.drift(column.sqlType.toString());
|
||||
bool? isRequiredForInsert;
|
||||
|
||||
if (tableOrView is DriftTable) {
|
||||
additionalParams['requiredDuringInsert'] = (tableOrView as DriftTable)
|
||||
.isColumnRequiredForInsert(column)
|
||||
.toString();
|
||||
isRequiredForInsert =
|
||||
(tableOrView as DriftTable).isColumnRequiredForInsert(column);
|
||||
}
|
||||
|
||||
if (column.customConstraints != null) {
|
||||
additionalParams['\$customConstraints'] =
|
||||
asDartLiteral(column.customConstraints!);
|
||||
} else if (constraints.values.any((constraint) => constraint.isNotEmpty)) {
|
||||
// Use the default constraints supported by drift
|
||||
|
||||
if (constraints.values.any(
|
||||
(value) => value != constraints.values.first,
|
||||
)) {
|
||||
// One or more constraints are different depending on dialect, generate
|
||||
// per-dialect constraints
|
||||
|
||||
final literalEntries = [
|
||||
for (final entry in constraints.entries)
|
||||
'${emitter.drift('SqlDialect.${entry.key.name}')}: ${asDartLiteral(entry.value)},',
|
||||
];
|
||||
|
||||
additionalParams['defaultConstraints'] =
|
||||
'${emitter.drift('GeneratedColumn.constraintsDependsOnDialect')}({${literalEntries.join('\n')}})';
|
||||
} else {
|
||||
// Constraints are the same regardless of dialect, only generate one set
|
||||
// of them
|
||||
|
||||
final constraint = asDartLiteral(constraints.values.first);
|
||||
|
||||
additionalParams['defaultConstraints'] =
|
||||
'${emitter.drift('GeneratedColumn.constraintIsAlways')}($constraint)';
|
||||
}
|
||||
}
|
||||
|
||||
if (column.defaultArgument != null) {
|
||||
additionalParams['defaultValue'] =
|
||||
emitter.dartCode(column.defaultArgument!);
|
||||
}
|
||||
|
||||
if (column.clientDefaultCode != null) {
|
||||
additionalParams['clientDefault'] =
|
||||
emitter.dartCode(column.clientDefaultCode!);
|
||||
}
|
||||
|
||||
final innerType = emitter.innerColumnType(column);
|
||||
var type =
|
||||
'${emitter.drift('GeneratedColumn')}<${emitter.dartCode(innerType)}>';
|
||||
expressionBuffer
|
||||
..write(type)
|
||||
..write(
|
||||
'(${asDartLiteral(column.nameInSql)}, aliasedName, $isNullable, ');
|
||||
|
||||
var first = true;
|
||||
additionalParams.forEach((name, value) {
|
||||
if (!first) {
|
||||
expressionBuffer.write(', ');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
expressionBuffer
|
||||
..write(name)
|
||||
..write(': ')
|
||||
..write(value);
|
||||
});
|
||||
|
||||
expressionBuffer.write(')');
|
||||
|
||||
final converter = column.typeConverter;
|
||||
if (converter != null) {
|
||||
// Generate a GeneratedColumnWithTypeConverter instance, as it has
|
||||
// additional methods to check for equality against a mapped value.
|
||||
final mappedType = emitter.dartCode(emitter.writer.dartType(column));
|
||||
|
||||
final converterCode = emitter.dartCode(emitter.writer
|
||||
.readConverter(converter, forNullable: column.nullable));
|
||||
|
||||
type = '${emitter.drift('GeneratedColumnWithTypeConverter')}'
|
||||
'<$mappedType, ${emitter.dartCode(innerType)}>';
|
||||
expressionBuffer
|
||||
..write('.withConverter<')
|
||||
..write(mappedType)
|
||||
..write('>(')
|
||||
..write(converterCode)
|
||||
..write(')');
|
||||
}
|
||||
final (type, expression) = instantiateColumn(
|
||||
column,
|
||||
emitter,
|
||||
isRequiredForInsert: isRequiredForInsert,
|
||||
);
|
||||
|
||||
writeMemoizedGetter(
|
||||
buffer: buffer,
|
||||
getterName: column.nameInDart,
|
||||
returnType: type,
|
||||
code: expressionBuffer.toString(),
|
||||
code: expression,
|
||||
hasOverride: isOverride,
|
||||
);
|
||||
}
|
||||
|
@ -276,6 +160,143 @@ abstract class TableOrViewWriter {
|
|||
buffer.write(
|
||||
'@override\n${tableOrView.entityInfoName} get asDslTable => this;\n');
|
||||
}
|
||||
|
||||
/// Returns the Dart type and the Dart expression creating a `GeneratedColumn`
|
||||
/// instance in drift for the givne [column].
|
||||
static (String, String) instantiateColumn(
|
||||
DriftColumn column,
|
||||
TextEmitter emitter, {
|
||||
bool? isRequiredForInsert,
|
||||
}) {
|
||||
final isNullable = column.nullable;
|
||||
final additionalParams = <String, String>{};
|
||||
final expressionBuffer = StringBuffer();
|
||||
final constraints = defaultConstraints(column);
|
||||
|
||||
for (final constraint in column.constraints) {
|
||||
if (constraint is LimitingTextLength) {
|
||||
final buffer =
|
||||
StringBuffer(emitter.drift('GeneratedColumn.checkTextLength('));
|
||||
|
||||
if (constraint.minLength != null) {
|
||||
buffer.write('minTextLength: ${constraint.minLength},');
|
||||
}
|
||||
if (constraint.maxLength != null) {
|
||||
buffer.write('maxTextLength: ${constraint.maxLength}');
|
||||
}
|
||||
buffer.write(')');
|
||||
|
||||
additionalParams['additionalChecks'] = buffer.toString();
|
||||
}
|
||||
|
||||
if (constraint is DartCheckExpression) {
|
||||
final dartCheck = emitter.dartCode(constraint.dartExpression);
|
||||
additionalParams['check'] = '() => $dartCheck';
|
||||
}
|
||||
|
||||
if (constraint is ColumnGeneratedAs) {
|
||||
final dartCode = emitter.dartCode(constraint.dartExpression);
|
||||
|
||||
additionalParams['generatedAs'] =
|
||||
'${emitter.drift('GeneratedAs')}($dartCode, ${constraint.stored})';
|
||||
}
|
||||
|
||||
if (constraint is PrimaryKeyColumn && constraint.isAutoIncrement) {
|
||||
additionalParams['hasAutoIncrement'] = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
additionalParams['type'] = emitter.drift(column.sqlType.toString());
|
||||
|
||||
if (isRequiredForInsert != null) {
|
||||
additionalParams['requiredDuringInsert'] = isRequiredForInsert.toString();
|
||||
}
|
||||
|
||||
if (column.customConstraints != null) {
|
||||
additionalParams['\$customConstraints'] =
|
||||
asDartLiteral(column.customConstraints!);
|
||||
} else if (constraints.values.any((constraint) => constraint.isNotEmpty)) {
|
||||
// Use the default constraints supported by drift
|
||||
|
||||
if (constraints.values.any(
|
||||
(value) => value != constraints.values.first,
|
||||
)) {
|
||||
// One or more constraints are different depending on dialect, generate
|
||||
// per-dialect constraints
|
||||
|
||||
final literalEntries = [
|
||||
for (final entry in constraints.entries)
|
||||
'${emitter.drift('SqlDialect.${entry.key.name}')}: ${asDartLiteral(entry.value)},',
|
||||
];
|
||||
|
||||
additionalParams['defaultConstraints'] =
|
||||
'${emitter.drift('GeneratedColumn.constraintsDependsOnDialect')}({${literalEntries.join('\n')}})';
|
||||
} else {
|
||||
// Constraints are the same regardless of dialect, only generate one set
|
||||
// of them
|
||||
|
||||
final constraint = asDartLiteral(constraints.values.first);
|
||||
|
||||
additionalParams['defaultConstraints'] =
|
||||
'${emitter.drift('GeneratedColumn.constraintIsAlways')}($constraint)';
|
||||
}
|
||||
}
|
||||
|
||||
if (column.defaultArgument != null) {
|
||||
additionalParams['defaultValue'] =
|
||||
emitter.dartCode(column.defaultArgument!);
|
||||
}
|
||||
|
||||
if (column.clientDefaultCode != null) {
|
||||
additionalParams['clientDefault'] =
|
||||
emitter.dartCode(column.clientDefaultCode!);
|
||||
}
|
||||
|
||||
final innerType = emitter.innerColumnType(column);
|
||||
var type =
|
||||
'${emitter.drift('GeneratedColumn')}<${emitter.dartCode(innerType)}>';
|
||||
expressionBuffer
|
||||
..write(type)
|
||||
..write(
|
||||
'(${asDartLiteral(column.nameInSql)}, aliasedName, $isNullable, ');
|
||||
|
||||
var first = true;
|
||||
additionalParams.forEach((name, value) {
|
||||
if (!first) {
|
||||
expressionBuffer.write(', ');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
expressionBuffer
|
||||
..write(name)
|
||||
..write(': ')
|
||||
..write(value);
|
||||
});
|
||||
|
||||
expressionBuffer.write(')');
|
||||
|
||||
final converter = column.typeConverter;
|
||||
if (converter != null) {
|
||||
// Generate a GeneratedColumnWithTypeConverter instance, as it has
|
||||
// additional methods to check for equality against a mapped value.
|
||||
final mappedType = emitter.dartCode(emitter.writer.dartType(column));
|
||||
|
||||
final converterCode = emitter.dartCode(emitter.writer
|
||||
.readConverter(converter, forNullable: column.nullable));
|
||||
|
||||
type = '${emitter.drift('GeneratedColumnWithTypeConverter')}'
|
||||
'<$mappedType, ${emitter.dartCode(innerType)}>';
|
||||
expressionBuffer
|
||||
..write('.withConverter<')
|
||||
..write(mappedType)
|
||||
..write('>(')
|
||||
..write(converterCode)
|
||||
..write(')');
|
||||
}
|
||||
|
||||
return (type, expressionBuffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
class TableWriter extends TableOrViewWriter {
|
||||
|
@ -577,8 +598,7 @@ class TableWriter extends TableOrViewWriter {
|
|||
|
||||
if (table.isVirtual) {
|
||||
final stmt = table.virtualTableData!;
|
||||
final moduleAndArgs =
|
||||
asDartLiteral('${stmt.module}(${stmt.moduleArguments.join(', ')})');
|
||||
final moduleAndArgs = asDartLiteral(stmt.moduleAndArgs);
|
||||
buffer
|
||||
..write('@override\n')
|
||||
..write('String get moduleAndArgs => $moduleAndArgs;\n');
|
||||
|
|
|
@ -11,7 +11,7 @@ topics:
|
|||
- database
|
||||
|
||||
environment:
|
||||
sdk: '>=2.17.0 <4.0.0'
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
charcode: ^1.2.0
|
||||
|
|
|
@ -13,7 +13,7 @@ class TestDriftProject {
|
|||
|
||||
Future<void> runDriftCli(Iterable<String> args) {
|
||||
return IOOverrides.runZoned(
|
||||
() => MoorCli().run(args),
|
||||
() => DriftDevCli().run(args),
|
||||
getCurrentDirectory: () => root,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ Drift databases don't depend on platform-channels or Flutter-specific features
|
|||
by default. This means that they can easily be used in unit tests.
|
||||
One such test is in `test/database_test.dart`
|
||||
|
||||
#### Testing migrations
|
||||
### Migration
|
||||
|
||||
After changing the structure of your database schema, for instance by adding
|
||||
new tables or altering columns, you need to write a migration to ensure that
|
||||
|
@ -57,4 +57,11 @@ you can use to write unit tests for schema migrations:
|
|||
dart run drift_dev schema generate drift_schemas/ test/generated_migrations/
|
||||
```
|
||||
|
||||
To make migrations easier, this command updates the `lib/database/schema_versions.dart`
|
||||
file containing snapshots of older database schema:
|
||||
|
||||
```
|
||||
dart run drift_dev schema steps drift_schemas/ lib/database/schema_versions.dart
|
||||
```
|
||||
|
||||
An example for a schema test is in `test/migration_test.dart`.
|
||||
|
|
|
@ -4,6 +4,10 @@ import 'package:riverpod/riverpod.dart';
|
|||
|
||||
import 'connection/connection.dart' as impl;
|
||||
import 'tables.dart';
|
||||
// Manually generated by `drift_dev schema steps` - this file makes writing
|
||||
// migrations easier. See this for details:
|
||||
// https://drift.simonbinder.eu/docs/advanced-features/migrations/#step-by-step
|
||||
import 'schema_versions.dart';
|
||||
|
||||
// Generated by drift_dev when running `build_runner build`
|
||||
part 'database.g.dart';
|
||||
|
@ -20,26 +24,22 @@ class AppDatabase extends _$AppDatabase {
|
|||
@override
|
||||
MigrationStrategy get migration {
|
||||
return MigrationStrategy(
|
||||
onUpgrade: ((m, from, to) async {
|
||||
for (var step = from + 1; step <= to; step++) {
|
||||
switch (step) {
|
||||
case 2:
|
||||
// The todoEntries.dueDate column was added in version 2.
|
||||
await m.addColumn(todoEntries, todoEntries.dueDate);
|
||||
break;
|
||||
case 3:
|
||||
// New triggers were added in version 3:
|
||||
await m.create(todosDelete);
|
||||
await m.create(todosUpdate);
|
||||
onUpgrade: stepByStep(
|
||||
from1To2: (m, schema) async {
|
||||
// The todoEntries.dueDate column was added in version 2.
|
||||
await m.addColumn(schema.todoEntries, schema.todoEntries.dueDate);
|
||||
},
|
||||
from2To3: (m, schema) async {
|
||||
// New triggers were added in version 3:
|
||||
await m.create(schema.todosDelete);
|
||||
await m.create(schema.todosUpdate);
|
||||
|
||||
// Also, the `REFERENCES` constraint was added to
|
||||
// [TodoEntries.category]. Run a table migration to rebuild all
|
||||
// column constraints without loosing data.
|
||||
await m.alterTable(TableMigration(todoEntries));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}),
|
||||
// Also, the `REFERENCES` constraint was added to
|
||||
// [TodoEntries.category]. Run a table migration to rebuild all
|
||||
// column constraints without loosing data.
|
||||
await m.alterTable(TableMigration(schema.todoEntries));
|
||||
},
|
||||
),
|
||||
beforeOpen: (details) async {
|
||||
// Make sure that foreign keys are enabled
|
||||
await customStatement('PRAGMA foreign_keys = ON');
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
import 'package:drift/internal/versioned_schema.dart' as i0;
|
||||
import 'package:drift/drift.dart' as i1;
|
||||
import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import
|
||||
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
final class _S2 extends i0.VersionedSchema {
|
||||
_S2({required super.database}) : super(version: 2);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
categories,
|
||||
todoEntries,
|
||||
textEntries,
|
||||
todosInsert,
|
||||
];
|
||||
late final Shape0 categories = Shape0(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'categories',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 todoEntries = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'todo_entries',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape2 textEntries = Shape2(
|
||||
source: i0.VersionedVirtualTable(
|
||||
entityName: 'text_entries',
|
||||
moduleAndArgs:
|
||||
'fts5(description, content=todo_entries, content_rowid=id)',
|
||||
columns: [
|
||||
_column_6,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
final i1.Trigger todosInsert = i1.Trigger(
|
||||
'CREATE TRIGGER todos_insert AFTER INSERT ON todo_entries BEGIN\n INSERT INTO text_entries(rowid, description) VALUES (new.id, new.description);\nEND;',
|
||||
'todos_insert');
|
||||
}
|
||||
|
||||
class Shape0 extends i0.VersionedTable {
|
||||
Shape0({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get name =>
|
||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<int> get color =>
|
||||
columnsByName['color']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_0(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i1.DriftSqlType.int,
|
||||
defaultConstraints:
|
||||
i1.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
i1.GeneratedColumn<String> _column_1(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('name', aliasedName, false,
|
||||
type: i1.DriftSqlType.string);
|
||||
i1.GeneratedColumn<int> _column_2(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('color', aliasedName, false,
|
||||
type: i1.DriftSqlType.int);
|
||||
|
||||
class Shape1 extends i0.VersionedTable {
|
||||
Shape1({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get description =>
|
||||
columnsByName['description']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<int> get category =>
|
||||
columnsByName['category']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<DateTime> get dueDate =>
|
||||
columnsByName['due_date']! as i1.GeneratedColumn<DateTime>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<String> _column_3(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('description', aliasedName, false,
|
||||
type: i1.DriftSqlType.string);
|
||||
i1.GeneratedColumn<int> _column_4(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('category', aliasedName, true,
|
||||
type: i1.DriftSqlType.int);
|
||||
i1.GeneratedColumn<DateTime> _column_5(String aliasedName) =>
|
||||
i1.GeneratedColumn<DateTime>('due_date', aliasedName, true,
|
||||
type: i1.DriftSqlType.dateTime);
|
||||
|
||||
class Shape2 extends i0.VersionedVirtualTable {
|
||||
Shape2({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<String> get description =>
|
||||
columnsByName['description']! as i1.GeneratedColumn<String>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<String> _column_6(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('description', aliasedName, false,
|
||||
type: i1.DriftSqlType.string, $customConstraints: '');
|
||||
|
||||
final class _S3 extends i0.VersionedSchema {
|
||||
_S3({required super.database}) : super(version: 3);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
categories,
|
||||
todoEntries,
|
||||
textEntries,
|
||||
todosInsert,
|
||||
todosDelete,
|
||||
todosUpdate,
|
||||
];
|
||||
late final Shape0 categories = Shape0(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'categories',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
_column_2,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 todoEntries = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'todo_entries',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_3,
|
||||
_column_7,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape2 textEntries = Shape2(
|
||||
source: i0.VersionedVirtualTable(
|
||||
entityName: 'text_entries',
|
||||
moduleAndArgs:
|
||||
'fts5(description, content=todo_entries, content_rowid=id)',
|
||||
columns: [
|
||||
_column_6,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
final i1.Trigger todosInsert = i1.Trigger(
|
||||
'CREATE TRIGGER todos_insert AFTER INSERT ON todo_entries BEGIN INSERT INTO text_entries ("rowid", description) VALUES (new.id, new.description);END',
|
||||
'todos_insert');
|
||||
final i1.Trigger todosDelete = i1.Trigger(
|
||||
'CREATE TRIGGER todos_delete AFTER DELETE ON todo_entries BEGIN INSERT INTO text_entries (text_entries, "rowid", description) VALUES (\'delete\', old.id, old.description);END',
|
||||
'todos_delete');
|
||||
final i1.Trigger todosUpdate = i1.Trigger(
|
||||
'CREATE TRIGGER todos_update AFTER UPDATE ON todo_entries BEGIN INSERT INTO text_entries (text_entries, "rowid", description) VALUES (\'delete\', new.id, new.description);INSERT INTO text_entries ("rowid", description) VALUES (new.id, new.description);END',
|
||||
'todos_update');
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_7(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('category', aliasedName, true,
|
||||
type: i1.DriftSqlType.int,
|
||||
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES categories (id)'));
|
||||
i1.OnUpgrade stepByStep({
|
||||
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
||||
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
||||
}) {
|
||||
return i1.Migrator.stepByStepHelper(step: (currentVersion, database) async {
|
||||
switch (currentVersion) {
|
||||
case 1:
|
||||
final schema = _S2(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from1To2(migrator, schema);
|
||||
return 2;
|
||||
case 2:
|
||||
final schema = _S3(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from2To3(migrator, schema);
|
||||
return 3;
|
||||
default:
|
||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||
}
|
||||
});
|
||||
}
|
|
@ -5,7 +5,7 @@ publish_to: 'none'
|
|||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.16.1 <3.0.0"
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
@ -15,9 +15,8 @@ dependencies:
|
|||
file_picker: ^5.2.5
|
||||
flutter_colorpicker: ^1.0.3
|
||||
flutter_riverpod: ^2.3.0
|
||||
go_router: ^6.2.0
|
||||
go_router: ^9.0.0
|
||||
intl: ^0.18.0
|
||||
http: ^0.13.4 # used to load sqlite3 wasm files on the web
|
||||
sqlite3_flutter_libs: ^0.5.5
|
||||
sqlite3: ^2.0.0
|
||||
path_provider: ^2.0.9
|
||||
|
@ -34,7 +33,7 @@ dev_dependencies:
|
|||
# web workers for drift AND want to compile those web workers through `build_runner`.
|
||||
# Either way, using this package with Flutter requires a delicate setup described in
|
||||
# `build.yaml`.
|
||||
build_web_compilers: ^3.2.2
|
||||
build_web_compilers: ^4.0.0
|
||||
build: ^2.2.1
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -20,9 +20,9 @@ Run
|
|||
dart run drift_dev schema generate drift_migrations/ test/generated/ --data-classes --companions
|
||||
```
|
||||
|
||||
We're also using test code inside `lib/` to run migrations with older definitions of tables.
|
||||
This isn't required for all migrations, but can be useful in some cases.
|
||||
Since we're using the step-by-step generator to make writing migrations easier, this command
|
||||
is used to generate a helper file in `lib/`:
|
||||
|
||||
```
|
||||
dart run drift_dev schema generate drift_migrations/ lib/src/generated
|
||||
dart run drift_dev schema steps drift_migrations/ lib/src/versions.dart
|
||||
```
|
||||
|
|
|
@ -2,9 +2,7 @@ import 'package:drift/drift.dart';
|
|||
import 'package:drift_dev/api/migrations.dart';
|
||||
|
||||
import 'tables.dart';
|
||||
import 'src/generated/schema_v2.dart' as v2;
|
||||
import 'src/generated/schema_v4.dart' as v4;
|
||||
import 'src/generated/schema_v8.dart' as v8;
|
||||
import 'src/versions.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
|
||||
|
@ -20,59 +18,7 @@ class Database extends _$Database {
|
|||
@override
|
||||
MigrationStrategy get migration {
|
||||
return MigrationStrategy(
|
||||
onUpgrade: (m, before, now) async {
|
||||
for (var target = before + 1; target <= now; target++) {
|
||||
switch (target) {
|
||||
case 2:
|
||||
// Migration from 1 to 2: Add name column in users. Use "no name"
|
||||
// as a default value.
|
||||
final usersAtV2 = v2.Users(this);
|
||||
|
||||
await m.alterTable(
|
||||
TableMigration(
|
||||
usersAtV2,
|
||||
columnTransformer: {
|
||||
users.name: const Constant<String>('no name'),
|
||||
},
|
||||
newColumns: [usersAtV2.name],
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 3:
|
||||
// Migration from 2 to 3: We added the groups table
|
||||
await m.createTable(groups);
|
||||
break;
|
||||
case 4:
|
||||
// Migration from 3 to 4: users.name now has a default value
|
||||
// No need to transform any data, just re-create the table
|
||||
final usersAtV4 = v4.Users(this);
|
||||
|
||||
await m.alterTable(TableMigration(usersAtV4));
|
||||
break;
|
||||
case 5:
|
||||
// Just add a new column that was added in version 5;
|
||||
await m.addColumn(users, users.nextUser);
|
||||
|
||||
// And create the view on users
|
||||
await m.createView(groupCount);
|
||||
break;
|
||||
case 6:
|
||||
await m.addColumn(users, users.birthday);
|
||||
break;
|
||||
case 7:
|
||||
await m.createTable(notes);
|
||||
break;
|
||||
case 8:
|
||||
// Added a unique key to the users table
|
||||
await m.alterTable(TableMigration(v8.Users(this)));
|
||||
break;
|
||||
case 9:
|
||||
// Added a check to the users table
|
||||
await m.alterTable(TableMigration(users));
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
onUpgrade: _upgrade,
|
||||
beforeOpen: (details) async {
|
||||
// For Flutter apps, this should be wrapped in an if (kDebugMode) as
|
||||
// suggested here: https://drift.simonbinder.eu/docs/advanced-features/migrations/#verifying-a-database-schema-at-runtime
|
||||
|
@ -80,4 +26,50 @@ class Database extends _$Database {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
static final _upgrade = stepByStep(
|
||||
from1To2: (m, schema) async {
|
||||
// Migration from 1 to 2: Add name column in users. Use "no name"
|
||||
// as a default value.
|
||||
|
||||
await m.alterTable(
|
||||
TableMigration(
|
||||
schema.users,
|
||||
columnTransformer: {
|
||||
schema.users.name: const Constant<String>('no name'),
|
||||
},
|
||||
newColumns: [schema.users.name],
|
||||
),
|
||||
);
|
||||
},
|
||||
from2To3: (m, schema) async => m.createTable(schema.groups),
|
||||
from3To4: (m, schema) async {
|
||||
// Migration from 3 to 4: users.name now has a default value
|
||||
// No need to transform any data, just re-create the table
|
||||
final usersAtV4 = schema.users;
|
||||
|
||||
await m.alterTable(TableMigration(usersAtV4));
|
||||
},
|
||||
from4To5: (m, schema) async {
|
||||
// Just add a new column that was added in version 5;
|
||||
await m.addColumn(schema.users, schema.users.nextUser);
|
||||
|
||||
// And create the view on users
|
||||
await m.createView(schema.groupCount);
|
||||
},
|
||||
from5To6: (m, schema) async {
|
||||
await m.addColumn(schema.users, schema.users.birthday);
|
||||
},
|
||||
from6To7: (m, schema) async {
|
||||
await m.createTable(schema.notes);
|
||||
},
|
||||
from7To8: (m, schema) async {
|
||||
// Added a unique key to the users table
|
||||
await m.alterTable(TableMigration(schema.users));
|
||||
},
|
||||
from8To9: (m, schema) async {
|
||||
// Added a check to the users table
|
||||
await m.alterTable(TableMigration(schema.users));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -874,7 +874,7 @@ class GroupCount extends ViewInfo<GroupCount, GroupCountData>
|
|||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {'groups', 'users'};
|
||||
Set<String> get readTables => const {'users', 'groups'};
|
||||
}
|
||||
|
||||
abstract class _$Database extends GeneratedDatabase {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/internal/migrations.dart';
|
||||
import 'schema_v1.dart' as v1;
|
||||
import 'schema_v2.dart' as v2;
|
||||
import 'schema_v3.dart' as v3;
|
||||
import 'schema_v4.dart' as v4;
|
||||
import 'schema_v5.dart' as v5;
|
||||
import 'schema_v6.dart' as v6;
|
||||
import 'schema_v7.dart' as v7;
|
||||
import 'schema_v8.dart' as v8;
|
||||
import 'schema_v9.dart' as v9;
|
||||
|
||||
class GeneratedHelper implements SchemaInstantiationHelper {
|
||||
@override
|
||||
GeneratedDatabase databaseForVersion(QueryExecutor db, int version) {
|
||||
switch (version) {
|
||||
case 1:
|
||||
return v1.DatabaseAtV1(db);
|
||||
case 2:
|
||||
return v2.DatabaseAtV2(db);
|
||||
case 3:
|
||||
return v3.DatabaseAtV3(db);
|
||||
case 4:
|
||||
return v4.DatabaseAtV4(db);
|
||||
case 5:
|
||||
return v5.DatabaseAtV5(db);
|
||||
case 6:
|
||||
return v6.DatabaseAtV6(db);
|
||||
case 7:
|
||||
return v7.DatabaseAtV7(db);
|
||||
case 8:
|
||||
return v8.DatabaseAtV8(db);
|
||||
case 9:
|
||||
return v9.DatabaseAtV9(db);
|
||||
default:
|
||||
throw MissingSchemaException(
|
||||
version, const {1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class DatabaseAtV1 extends GeneratedDatabase {
|
||||
DatabaseAtV1(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [users];
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class DatabaseAtV2 extends GeneratedDatabase {
|
||||
DatabaseAtV2(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [users];
|
||||
@override
|
||||
int get schemaVersion => 2;
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string, requiredDuringInsert: true);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class DatabaseAtV3 extends GeneratedDatabase {
|
||||
DatabaseAtV3(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [users, groups];
|
||||
@override
|
||||
int get schemaVersion => 3;
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant('name'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class DatabaseAtV4 extends GeneratedDatabase {
|
||||
DatabaseAtV4(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities => [users, groups];
|
||||
@override
|
||||
int get schemaVersion => 4;
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant('name'));
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('REFERENCES users (id)'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class GroupCount extends ViewInfo<GroupCount, Never> implements HasResultSet {
|
||||
final String? _alias;
|
||||
@override
|
||||
final DatabaseAtV5 attachedDatabase;
|
||||
GroupCount(this.attachedDatabase, [this._alias]);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, nextUser, groupCount];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@override
|
||||
String get entityName => 'group_count';
|
||||
@override
|
||||
String get createViewStmt =>
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users';
|
||||
@override
|
||||
GroupCount get asDslTable => this;
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
late final GeneratedColumn<int> id =
|
||||
GeneratedColumn<int>('id', aliasedName, false, type: DriftSqlType.int);
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int);
|
||||
late final GeneratedColumn<int> groupCount = GeneratedColumn<int>(
|
||||
'group_count', aliasedName, false,
|
||||
type: DriftSqlType.int);
|
||||
@override
|
||||
GroupCount createAlias(String alias) {
|
||||
return GroupCount(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {};
|
||||
}
|
||||
|
||||
class DatabaseAtV5 extends GeneratedDatabase {
|
||||
DatabaseAtV5(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
late final GroupCount groupCount = GroupCount(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||
[users, groups, groupCount];
|
||||
@override
|
||||
int get schemaVersion => 5;
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant('name'));
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime, requiredDuringInsert: false);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('REFERENCES users (id)'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class GroupCount extends ViewInfo<GroupCount, Never> implements HasResultSet {
|
||||
final String? _alias;
|
||||
@override
|
||||
final DatabaseAtV6 attachedDatabase;
|
||||
GroupCount(this.attachedDatabase, [this._alias]);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns =>
|
||||
[id, name, birthday, nextUser, groupCount];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@override
|
||||
String get entityName => 'group_count';
|
||||
@override
|
||||
String get createViewStmt =>
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users';
|
||||
@override
|
||||
GroupCount get asDslTable => this;
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
late final GeneratedColumn<int> id =
|
||||
GeneratedColumn<int>('id', aliasedName, false, type: DriftSqlType.int);
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string);
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int);
|
||||
late final GeneratedColumn<int> groupCount = GeneratedColumn<int>(
|
||||
'group_count', aliasedName, false,
|
||||
type: DriftSqlType.int);
|
||||
@override
|
||||
GroupCount createAlias(String alias) {
|
||||
return GroupCount(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {};
|
||||
}
|
||||
|
||||
class DatabaseAtV6 extends GeneratedDatabase {
|
||||
DatabaseAtV6(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
late final GroupCount groupCount = GroupCount(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||
[users, groups, groupCount];
|
||||
@override
|
||||
int get schemaVersion => 6;
|
||||
@override
|
||||
DriftDatabaseOptions get options =>
|
||||
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant('name'));
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime, requiredDuringInsert: false);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('REFERENCES users (id)'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class GroupCount extends ViewInfo<GroupCount, Never> implements HasResultSet {
|
||||
final String? _alias;
|
||||
@override
|
||||
final DatabaseAtV7 attachedDatabase;
|
||||
GroupCount(this.attachedDatabase, [this._alias]);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns =>
|
||||
[id, name, birthday, nextUser, groupCount];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@override
|
||||
String get entityName => 'group_count';
|
||||
@override
|
||||
String get createViewStmt =>
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users';
|
||||
@override
|
||||
GroupCount get asDslTable => this;
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
late final GeneratedColumn<int> id =
|
||||
GeneratedColumn<int>('id', aliasedName, false, type: DriftSqlType.int);
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string);
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int);
|
||||
late final GeneratedColumn<int> groupCount = GeneratedColumn<int>(
|
||||
'group_count', aliasedName, false,
|
||||
type: DriftSqlType.int);
|
||||
@override
|
||||
GroupCount createAlias(String alias) {
|
||||
return GroupCount(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {};
|
||||
}
|
||||
|
||||
class Notes extends Table with TableInfo, VirtualTableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Notes(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
late final GeneratedColumn<String> content = GeneratedColumn<String>(
|
||||
'content', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
late final GeneratedColumn<String> searchTerms = GeneratedColumn<String>(
|
||||
'search_terms', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Notes createAlias(String alias) {
|
||||
return Notes(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
String get moduleAndArgs =>
|
||||
'fts5(title, content, search_terms, tokenize = "unicode61 tokenchars \'.\'")';
|
||||
}
|
||||
|
||||
class DatabaseAtV7 extends GeneratedDatabase {
|
||||
DatabaseAtV7(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
late final GroupCount groupCount = GroupCount(this);
|
||||
late final Notes notes = Notes(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||
[users, groups, groupCount, notes];
|
||||
@override
|
||||
int get schemaVersion => 7;
|
||||
@override
|
||||
DriftDatabaseOptions get options =>
|
||||
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant('name'));
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime, requiredDuringInsert: false);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('REFERENCES "users" ("id")'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
List<Set<GeneratedColumn>> get uniqueKeys => [
|
||||
{name, birthday},
|
||||
];
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY (id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class GroupCount extends ViewInfo<GroupCount, Never> implements HasResultSet {
|
||||
final String? _alias;
|
||||
@override
|
||||
final DatabaseAtV8 attachedDatabase;
|
||||
GroupCount(this.attachedDatabase, [this._alias]);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns =>
|
||||
[id, name, birthday, nextUser, groupCount];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@override
|
||||
String get entityName => 'group_count';
|
||||
@override
|
||||
String get createViewStmt =>
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users';
|
||||
@override
|
||||
GroupCount get asDslTable => this;
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
late final GeneratedColumn<int> id =
|
||||
GeneratedColumn<int>('id', aliasedName, false, type: DriftSqlType.int);
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string);
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int);
|
||||
late final GeneratedColumn<int> groupCount = GeneratedColumn<int>(
|
||||
'group_count', aliasedName, false,
|
||||
type: DriftSqlType.int);
|
||||
@override
|
||||
GroupCount createAlias(String alias) {
|
||||
return GroupCount(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {};
|
||||
}
|
||||
|
||||
class Notes extends Table with TableInfo, VirtualTableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Notes(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
late final GeneratedColumn<String> content = GeneratedColumn<String>(
|
||||
'content', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
late final GeneratedColumn<String> searchTerms = GeneratedColumn<String>(
|
||||
'search_terms', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Notes createAlias(String alias) {
|
||||
return Notes(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
String get moduleAndArgs =>
|
||||
'fts5(title, content, search_terms, tokenize = "unicode61 tokenchars \'.\'")';
|
||||
}
|
||||
|
||||
class DatabaseAtV8 extends GeneratedDatabase {
|
||||
DatabaseAtV8(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
late final GroupCount groupCount = GroupCount(this);
|
||||
late final Notes notes = Notes(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||
[users, groups, groupCount, notes];
|
||||
@override
|
||||
int get schemaVersion => 8;
|
||||
@override
|
||||
DriftDatabaseOptions get options =>
|
||||
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
// GENERATED CODE, DO NOT EDIT BY HAND.
|
||||
// ignore_for_file: type=lint
|
||||
//@dart=2.12
|
||||
import 'package:drift/drift.dart';
|
||||
|
||||
class Users extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Users(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultValue: const Constant('name'));
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime, requiredDuringInsert: false);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
GeneratedColumn.constraintIsAlways('REFERENCES users (id)'));
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, name, birthday, nextUser];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'users';
|
||||
@override
|
||||
String get actualTableName => 'users';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
List<Set<GeneratedColumn>> get uniqueKeys => [
|
||||
{name, birthday},
|
||||
];
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Users createAlias(String alias) {
|
||||
return Users(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['CHECK (LENGTH(name) < 10)'];
|
||||
}
|
||||
|
||||
class Groups extends Table with TableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Groups(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<int> id = GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
late final GeneratedColumn<bool> deleted = GeneratedColumn<bool>(
|
||||
'deleted', aliasedName, true,
|
||||
type: DriftSqlType.bool,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression('FALSE'));
|
||||
late final GeneratedColumn<int> owner = GeneratedColumn<int>(
|
||||
'owner', aliasedName, false,
|
||||
type: DriftSqlType.int,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL REFERENCES users(id)');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [id, title, deleted, owner];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'groups';
|
||||
@override
|
||||
String get actualTableName => 'groups';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Groups createAlias(String alias) {
|
||||
return Groups(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => const ['PRIMARY KEY(id)'];
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class Notes extends Table with TableInfo, VirtualTableInfo {
|
||||
@override
|
||||
final GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Notes(this.attachedDatabase, [this._alias]);
|
||||
late final GeneratedColumn<String> title = GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
late final GeneratedColumn<String> content = GeneratedColumn<String>(
|
||||
'content', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
late final GeneratedColumn<String> searchTerms = GeneratedColumn<String>(
|
||||
'search_terms', aliasedName, false,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: '');
|
||||
@override
|
||||
List<GeneratedColumn> get $columns => [title, content, searchTerms];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'notes';
|
||||
@override
|
||||
String get actualTableName => 'notes';
|
||||
@override
|
||||
Set<GeneratedColumn> get $primaryKey => const {};
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
@override
|
||||
Notes createAlias(String alias) {
|
||||
return Notes(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
String get moduleAndArgs =>
|
||||
'fts5(title, content, search_terms, tokenize = "unicode61 tokenchars \'.\'")';
|
||||
}
|
||||
|
||||
class GroupCount extends ViewInfo<GroupCount, Never> implements HasResultSet {
|
||||
final String? _alias;
|
||||
@override
|
||||
final DatabaseAtV9 attachedDatabase;
|
||||
GroupCount(this.attachedDatabase, [this._alias]);
|
||||
@override
|
||||
List<GeneratedColumn> get $columns =>
|
||||
[id, name, birthday, nextUser, groupCount];
|
||||
@override
|
||||
String get aliasedName => _alias ?? entityName;
|
||||
@override
|
||||
String get entityName => 'group_count';
|
||||
@override
|
||||
String get createViewStmt =>
|
||||
'CREATE VIEW group_count AS SELECT\n users.*,\n (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count\n FROM users;';
|
||||
@override
|
||||
GroupCount get asDslTable => this;
|
||||
@override
|
||||
Never map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
throw UnsupportedError('TableInfo.map in schema verification code');
|
||||
}
|
||||
|
||||
late final GeneratedColumn<int> id =
|
||||
GeneratedColumn<int>('id', aliasedName, false, type: DriftSqlType.int);
|
||||
late final GeneratedColumn<String> name = GeneratedColumn<String>(
|
||||
'name', aliasedName, false,
|
||||
type: DriftSqlType.string);
|
||||
late final GeneratedColumn<DateTime> birthday = GeneratedColumn<DateTime>(
|
||||
'birthday', aliasedName, true,
|
||||
type: DriftSqlType.dateTime);
|
||||
late final GeneratedColumn<int> nextUser = GeneratedColumn<int>(
|
||||
'next_user', aliasedName, true,
|
||||
type: DriftSqlType.int);
|
||||
late final GeneratedColumn<int> groupCount = GeneratedColumn<int>(
|
||||
'group_count', aliasedName, false,
|
||||
type: DriftSqlType.int);
|
||||
@override
|
||||
GroupCount createAlias(String alias) {
|
||||
return GroupCount(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
Query? get query => null;
|
||||
@override
|
||||
Set<String> get readTables => const {};
|
||||
}
|
||||
|
||||
class DatabaseAtV9 extends GeneratedDatabase {
|
||||
DatabaseAtV9(QueryExecutor e) : super(e);
|
||||
late final Users users = Users(this);
|
||||
late final Groups groups = Groups(this);
|
||||
late final Notes notes = Notes(this);
|
||||
late final GroupCount groupCount = GroupCount(this);
|
||||
@override
|
||||
Iterable<TableInfo<Table, Object?>> get allTables =>
|
||||
allSchemaEntities.whereType<TableInfo<Table, Object?>>();
|
||||
@override
|
||||
List<DatabaseSchemaEntity> get allSchemaEntities =>
|
||||
[users, groups, notes, groupCount];
|
||||
@override
|
||||
int get schemaVersion => 9;
|
||||
@override
|
||||
DriftDatabaseOptions get options =>
|
||||
const DriftDatabaseOptions(storeDateTimeAsText: true);
|
||||
}
|
|
@ -0,0 +1,644 @@
|
|||
import 'package:drift/internal/versioned_schema.dart' as i0;
|
||||
import 'package:drift/drift.dart' as i1;
|
||||
import 'package:drift/drift.dart'; // ignore_for_file: type=lint
|
||||
|
||||
// GENERATED BY drift_dev, DO NOT MODIFY.
|
||||
final class _S2 extends i0.VersionedSchema {
|
||||
_S2({required super.database}) : super(version: 2);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
];
|
||||
late final Shape0 users = Shape0(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape0 extends i0.VersionedTable {
|
||||
Shape0({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get name =>
|
||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_0(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i1.DriftSqlType.int,
|
||||
defaultConstraints:
|
||||
i1.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
i1.GeneratedColumn<String> _column_1(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('name', aliasedName, false,
|
||||
type: i1.DriftSqlType.string);
|
||||
|
||||
final class _S3 extends i0.VersionedSchema {
|
||||
_S3({required super.database}) : super(version: 3);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
];
|
||||
late final Shape0 users = Shape0(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_1,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY (id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape1 extends i0.VersionedTable {
|
||||
Shape1({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get title =>
|
||||
columnsByName['title']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<bool> get deleted =>
|
||||
columnsByName['deleted']! as i1.GeneratedColumn<bool>;
|
||||
i1.GeneratedColumn<int> get owner =>
|
||||
columnsByName['owner']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_2(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('id', aliasedName, false,
|
||||
type: i1.DriftSqlType.int, $customConstraints: 'NOT NULL');
|
||||
i1.GeneratedColumn<String> _column_3(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('title', aliasedName, false,
|
||||
type: i1.DriftSqlType.string, $customConstraints: 'NOT NULL');
|
||||
i1.GeneratedColumn<bool> _column_4(String aliasedName) =>
|
||||
i1.GeneratedColumn<bool>('deleted', aliasedName, true,
|
||||
type: i1.DriftSqlType.bool,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression<bool>('FALSE'));
|
||||
i1.GeneratedColumn<int> _column_5(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('owner', aliasedName, false,
|
||||
type: i1.DriftSqlType.int,
|
||||
$customConstraints: 'NOT NULL REFERENCES users (id)');
|
||||
|
||||
final class _S4 extends i0.VersionedSchema {
|
||||
_S4({required super.database}) : super(version: 4);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
];
|
||||
late final Shape0 users = Shape0(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_6,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY (id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<String> _column_6(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('name', aliasedName, false,
|
||||
type: i1.DriftSqlType.string, defaultValue: const Constant('name'));
|
||||
|
||||
final class _S5 extends i0.VersionedSchema {
|
||||
_S5({required super.database}) : super(version: 5);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
groupCount,
|
||||
];
|
||||
late final Shape2 users = Shape2(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_6,
|
||||
_column_7,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY (id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape3 groupCount = Shape3(
|
||||
source: i0.VersionedView(
|
||||
entityName: 'group_count',
|
||||
createViewStmt:
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users',
|
||||
columns: [
|
||||
_column_8,
|
||||
_column_1,
|
||||
_column_9,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape2 extends i0.VersionedTable {
|
||||
Shape2({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get name =>
|
||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<int> get nextUser =>
|
||||
columnsByName['next_user']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_7(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('next_user', aliasedName, true,
|
||||
type: i1.DriftSqlType.int,
|
||||
defaultConstraints:
|
||||
i1.GeneratedColumn.constraintIsAlways('REFERENCES users (id)'));
|
||||
|
||||
class Shape3 extends i0.VersionedView {
|
||||
Shape3({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get name =>
|
||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<int> get nextUser =>
|
||||
columnsByName['next_user']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get groupCount =>
|
||||
columnsByName['group_count']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_8(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('id', aliasedName, false,
|
||||
type: i1.DriftSqlType.int);
|
||||
i1.GeneratedColumn<int> _column_9(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('next_user', aliasedName, true,
|
||||
type: i1.DriftSqlType.int);
|
||||
i1.GeneratedColumn<int> _column_10(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('group_count', aliasedName, false,
|
||||
type: i1.DriftSqlType.int);
|
||||
|
||||
final class _S6 extends i0.VersionedSchema {
|
||||
_S6({required super.database}) : super(version: 6);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
groupCount,
|
||||
];
|
||||
late final Shape4 users = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_6,
|
||||
_column_11,
|
||||
_column_7,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY (id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 groupCount = Shape5(
|
||||
source: i0.VersionedView(
|
||||
entityName: 'group_count',
|
||||
createViewStmt:
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users',
|
||||
columns: [
|
||||
_column_8,
|
||||
_column_1,
|
||||
_column_11,
|
||||
_column_9,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape4 extends i0.VersionedTable {
|
||||
Shape4({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get name =>
|
||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<DateTime> get birthday =>
|
||||
columnsByName['birthday']! as i1.GeneratedColumn<DateTime>;
|
||||
i1.GeneratedColumn<int> get nextUser =>
|
||||
columnsByName['next_user']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<DateTime> _column_11(String aliasedName) =>
|
||||
i1.GeneratedColumn<DateTime>('birthday', aliasedName, true,
|
||||
type: i1.DriftSqlType.dateTime);
|
||||
|
||||
class Shape5 extends i0.VersionedView {
|
||||
Shape5({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<int> get id =>
|
||||
columnsByName['id']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<String> get name =>
|
||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<DateTime> get birthday =>
|
||||
columnsByName['birthday']! as i1.GeneratedColumn<DateTime>;
|
||||
i1.GeneratedColumn<int> get nextUser =>
|
||||
columnsByName['next_user']! as i1.GeneratedColumn<int>;
|
||||
i1.GeneratedColumn<int> get groupCount =>
|
||||
columnsByName['group_count']! as i1.GeneratedColumn<int>;
|
||||
}
|
||||
|
||||
final class _S7 extends i0.VersionedSchema {
|
||||
_S7({required super.database}) : super(version: 7);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
groupCount,
|
||||
notes,
|
||||
];
|
||||
late final Shape4 users = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_6,
|
||||
_column_11,
|
||||
_column_7,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY (id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 groupCount = Shape5(
|
||||
source: i0.VersionedView(
|
||||
entityName: 'group_count',
|
||||
createViewStmt:
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users',
|
||||
columns: [
|
||||
_column_8,
|
||||
_column_1,
|
||||
_column_11,
|
||||
_column_9,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape6 notes = Shape6(
|
||||
source: i0.VersionedVirtualTable(
|
||||
entityName: 'notes',
|
||||
moduleAndArgs:
|
||||
'fts5(title, content, search_terms, tokenize = "unicode61 tokenchars \'.\'")',
|
||||
columns: [
|
||||
_column_12,
|
||||
_column_13,
|
||||
_column_14,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
class Shape6 extends i0.VersionedVirtualTable {
|
||||
Shape6({required super.source, required super.alias}) : super.aliased();
|
||||
i1.GeneratedColumn<String> get title =>
|
||||
columnsByName['title']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<String> get content =>
|
||||
columnsByName['content']! as i1.GeneratedColumn<String>;
|
||||
i1.GeneratedColumn<String> get searchTerms =>
|
||||
columnsByName['search_terms']! as i1.GeneratedColumn<String>;
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<String> _column_12(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('title', aliasedName, false,
|
||||
type: i1.DriftSqlType.string, $customConstraints: '');
|
||||
i1.GeneratedColumn<String> _column_13(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('content', aliasedName, false,
|
||||
type: i1.DriftSqlType.string, $customConstraints: '');
|
||||
i1.GeneratedColumn<String> _column_14(String aliasedName) =>
|
||||
i1.GeneratedColumn<String>('search_terms', aliasedName, false,
|
||||
type: i1.DriftSqlType.string, $customConstraints: '');
|
||||
|
||||
final class _S8 extends i0.VersionedSchema {
|
||||
_S8({required super.database}) : super(version: 8);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
groupCount,
|
||||
notes,
|
||||
];
|
||||
late final Shape4 users = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'UNIQUE(name, birthday)',
|
||||
],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_6,
|
||||
_column_11,
|
||||
_column_15,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY (id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_4,
|
||||
_column_5,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 groupCount = Shape5(
|
||||
source: i0.VersionedView(
|
||||
entityName: 'group_count',
|
||||
createViewStmt:
|
||||
'CREATE VIEW group_count AS SELECT users.*, (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count FROM users',
|
||||
columns: [
|
||||
_column_8,
|
||||
_column_1,
|
||||
_column_11,
|
||||
_column_9,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape6 notes = Shape6(
|
||||
source: i0.VersionedVirtualTable(
|
||||
entityName: 'notes',
|
||||
moduleAndArgs:
|
||||
'fts5(title, content, search_terms, tokenize = "unicode61 tokenchars \'.\'")',
|
||||
columns: [
|
||||
_column_12,
|
||||
_column_13,
|
||||
_column_14,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<int> _column_15(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('next_user', aliasedName, true,
|
||||
type: i1.DriftSqlType.int,
|
||||
defaultConstraints:
|
||||
i1.GeneratedColumn.constraintIsAlways('REFERENCES "users" ("id")'));
|
||||
|
||||
final class _S9 extends i0.VersionedSchema {
|
||||
_S9({required super.database}) : super(version: 9);
|
||||
@override
|
||||
late final List<i1.DatabaseSchemaEntity> entities = [
|
||||
users,
|
||||
groups,
|
||||
notes,
|
||||
groupCount,
|
||||
];
|
||||
late final Shape4 users = Shape4(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'users',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'UNIQUE(name, birthday)',
|
||||
'CHECK (LENGTH(name) < 10)',
|
||||
],
|
||||
columns: [
|
||||
_column_0,
|
||||
_column_6,
|
||||
_column_11,
|
||||
_column_7,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape1 groups = Shape1(
|
||||
source: i0.VersionedTable(
|
||||
entityName: 'groups',
|
||||
withoutRowId: false,
|
||||
isStrict: false,
|
||||
tableConstraints: [
|
||||
'PRIMARY KEY(id)',
|
||||
],
|
||||
columns: [
|
||||
_column_2,
|
||||
_column_3,
|
||||
_column_16,
|
||||
_column_17,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape6 notes = Shape6(
|
||||
source: i0.VersionedVirtualTable(
|
||||
entityName: 'notes',
|
||||
moduleAndArgs:
|
||||
'fts5(title, content, search_terms, tokenize = "unicode61 tokenchars \'.\'")',
|
||||
columns: [
|
||||
_column_12,
|
||||
_column_13,
|
||||
_column_14,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
late final Shape5 groupCount = Shape5(
|
||||
source: i0.VersionedView(
|
||||
entityName: 'group_count',
|
||||
createViewStmt:
|
||||
'CREATE VIEW group_count AS SELECT\n users.*,\n (SELECT COUNT(*) FROM "groups" WHERE owner = users.id) AS group_count\n FROM users;',
|
||||
columns: [
|
||||
_column_8,
|
||||
_column_1,
|
||||
_column_11,
|
||||
_column_9,
|
||||
_column_10,
|
||||
],
|
||||
attachedDatabase: database,
|
||||
),
|
||||
alias: null);
|
||||
}
|
||||
|
||||
i1.GeneratedColumn<bool> _column_16(String aliasedName) =>
|
||||
i1.GeneratedColumn<bool>('deleted', aliasedName, true,
|
||||
type: i1.DriftSqlType.bool,
|
||||
$customConstraints: 'DEFAULT FALSE',
|
||||
defaultValue: const CustomExpression('FALSE'));
|
||||
i1.GeneratedColumn<int> _column_17(String aliasedName) =>
|
||||
i1.GeneratedColumn<int>('owner', aliasedName, false,
|
||||
type: i1.DriftSqlType.int,
|
||||
$customConstraints: 'NOT NULL REFERENCES users(id)');
|
||||
i1.OnUpgrade stepByStep({
|
||||
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
||||
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
||||
required Future<void> Function(i1.Migrator m, _S4 schema) from3To4,
|
||||
required Future<void> Function(i1.Migrator m, _S5 schema) from4To5,
|
||||
required Future<void> Function(i1.Migrator m, _S6 schema) from5To6,
|
||||
required Future<void> Function(i1.Migrator m, _S7 schema) from6To7,
|
||||
required Future<void> Function(i1.Migrator m, _S8 schema) from7To8,
|
||||
required Future<void> Function(i1.Migrator m, _S9 schema) from8To9,
|
||||
}) {
|
||||
return i1.Migrator.stepByStepHelper(step: (currentVersion, database) async {
|
||||
switch (currentVersion) {
|
||||
case 1:
|
||||
final schema = _S2(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from1To2(migrator, schema);
|
||||
return 2;
|
||||
case 2:
|
||||
final schema = _S3(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from2To3(migrator, schema);
|
||||
return 3;
|
||||
case 3:
|
||||
final schema = _S4(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from3To4(migrator, schema);
|
||||
return 4;
|
||||
case 4:
|
||||
final schema = _S5(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from4To5(migrator, schema);
|
||||
return 5;
|
||||
case 5:
|
||||
final schema = _S6(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from5To6(migrator, schema);
|
||||
return 6;
|
||||
case 6:
|
||||
final schema = _S7(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from6To7(migrator, schema);
|
||||
return 7;
|
||||
case 7:
|
||||
final schema = _S8(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from7To8(migrator, schema);
|
||||
return 8;
|
||||
case 8:
|
||||
final schema = _S9(database: database);
|
||||
final migrator = i1.Migrator(database, schema);
|
||||
await from8To9(migrator, schema);
|
||||
return 9;
|
||||
default:
|
||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||
}
|
||||
});
|
||||
}
|
|
@ -3,7 +3,7 @@ publish_to: none
|
|||
version: 1.0.0
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
drift:
|
||||
|
|
32
pubspec.lock
32
pubspec.lock
|
@ -13,10 +13,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
|
||||
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -53,10 +53,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c"
|
||||
sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.5"
|
||||
version: "0.4.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -85,18 +85,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
|
||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "772db3d53d23361d4ffcf5a9bb091cf3ee9b22f2be52cd107cd7a2683a89ba0e"
|
||||
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.1"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -133,18 +133,18 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
|
||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.15"
|
||||
version: "0.12.16"
|
||||
melos:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: melos
|
||||
sha256: "993ac467e7a36bd832a6cdabbe18a0487c30bc52b5cca14e476a824679ebdce0"
|
||||
sha256: ccbb6ecd8bb3f08ae8f9ce22920d816bff325a98940c845eda0257cd395503ac
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "3.1.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -253,10 +253,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -277,10 +277,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: daadc9baabec998b062c9091525aa95786508b1c48e9c30f1f891b8bf6ff2e64
|
||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.2"
|
||||
version: "0.6.0"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
Loading…
Reference in New Issue