Skip to content

Commit 0becd95

Browse files
committed
db: Start generating schemas versions for migrations
Generating schema_versions.g.dart is crucial because we otherwise only have access to the latest schema when running migrations. Migrations that require dropping columns will be problematic because the latest schema will then have no information about the dropped column. --- An alternative to using all these commands for generating files is `dart run drift_dev make-migrations`, which is essentially a wrapper for the `schema {dump,generate,steps}` subcommands. `make-migrations` let us manage multiple database schemas by configuring them with `build.yaml`, and it dictates the which subdirectories the generated files will be created at. Because `make-migrations` does not offer the same level of customizations to designate exactly where the output files will be, opting out from it for now. We can revisit this if it starts to offer features that are not available with the subcommands, or that we find the need for managing multiple databases. See also: https://drift.simonbinder.eu/migrations/step_by_step/#manual-generation Signed-off-by: Zixuan James Li <[email protected]>
1 parent 61366a2 commit 0becd95

File tree

3 files changed

+124
-4
lines changed

3 files changed

+124
-4
lines changed

lib/model/database.dart

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import 'package:drift/drift.dart';
22
import 'package:drift/remote.dart';
33
import 'package:sqlite3/common.dart';
44

5+
import 'schema_versions.g.dart';
6+
57
part 'database.g.dart';
68

79
/// The table of [Account] records in the app's database.
@@ -85,7 +87,8 @@ class AppDatabase extends _$AppDatabase {
8587
assert(1 <= from && from <= to && to <= schemaVersion);
8688

8789
if (from < 2 && 2 <= to) {
88-
await m.addColumn(accounts, accounts.ackedPushToken);
90+
final schema = Schema2(database: m.database);
91+
await m.addColumn(schema.accounts, schema.accounts.ackedPushToken);
8992
}
9093
// New migrations go here.
9194
}

lib/model/schema_versions.g.dart

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// dart format width=80
2+
import 'package:drift/internal/versioned_schema.dart' as i0;
3+
import 'package:drift/drift.dart' as i1;
4+
import 'package:drift/drift.dart'; // ignore_for_file: type=lint,unused_import
5+
6+
// GENERATED BY drift_dev, DO NOT MODIFY.
7+
final class Schema2 extends i0.VersionedSchema {
8+
Schema2({required super.database}) : super(version: 2);
9+
@override
10+
late final List<i1.DatabaseSchemaEntity> entities = [
11+
accounts,
12+
];
13+
late final Shape0 accounts = Shape0(
14+
source: i0.VersionedTable(
15+
entityName: 'accounts',
16+
withoutRowId: false,
17+
isStrict: false,
18+
tableConstraints: [
19+
'UNIQUE(realm_url, user_id)',
20+
'UNIQUE(realm_url, email)',
21+
],
22+
columns: [
23+
_column_0,
24+
_column_1,
25+
_column_2,
26+
_column_3,
27+
_column_4,
28+
_column_5,
29+
_column_6,
30+
_column_7,
31+
_column_8,
32+
],
33+
attachedDatabase: database,
34+
),
35+
alias: null);
36+
}
37+
38+
class Shape0 extends i0.VersionedTable {
39+
Shape0({required super.source, required super.alias}) : super.aliased();
40+
i1.GeneratedColumn<int> get id =>
41+
columnsByName['id']! as i1.GeneratedColumn<int>;
42+
i1.GeneratedColumn<String> get realmUrl =>
43+
columnsByName['realm_url']! as i1.GeneratedColumn<String>;
44+
i1.GeneratedColumn<int> get userId =>
45+
columnsByName['user_id']! as i1.GeneratedColumn<int>;
46+
i1.GeneratedColumn<String> get email =>
47+
columnsByName['email']! as i1.GeneratedColumn<String>;
48+
i1.GeneratedColumn<String> get apiKey =>
49+
columnsByName['api_key']! as i1.GeneratedColumn<String>;
50+
i1.GeneratedColumn<String> get zulipVersion =>
51+
columnsByName['zulip_version']! as i1.GeneratedColumn<String>;
52+
i1.GeneratedColumn<String> get zulipMergeBase =>
53+
columnsByName['zulip_merge_base']! as i1.GeneratedColumn<String>;
54+
i1.GeneratedColumn<int> get zulipFeatureLevel =>
55+
columnsByName['zulip_feature_level']! as i1.GeneratedColumn<int>;
56+
i1.GeneratedColumn<String> get ackedPushToken =>
57+
columnsByName['acked_push_token']! as i1.GeneratedColumn<String>;
58+
}
59+
60+
i1.GeneratedColumn<int> _column_0(String aliasedName) =>
61+
i1.GeneratedColumn<int>('id', aliasedName, false,
62+
hasAutoIncrement: true,
63+
type: i1.DriftSqlType.int,
64+
defaultConstraints:
65+
i1.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
66+
i1.GeneratedColumn<String> _column_1(String aliasedName) =>
67+
i1.GeneratedColumn<String>('realm_url', aliasedName, false,
68+
type: i1.DriftSqlType.string);
69+
i1.GeneratedColumn<int> _column_2(String aliasedName) =>
70+
i1.GeneratedColumn<int>('user_id', aliasedName, false,
71+
type: i1.DriftSqlType.int);
72+
i1.GeneratedColumn<String> _column_3(String aliasedName) =>
73+
i1.GeneratedColumn<String>('email', aliasedName, false,
74+
type: i1.DriftSqlType.string);
75+
i1.GeneratedColumn<String> _column_4(String aliasedName) =>
76+
i1.GeneratedColumn<String>('api_key', aliasedName, false,
77+
type: i1.DriftSqlType.string);
78+
i1.GeneratedColumn<String> _column_5(String aliasedName) =>
79+
i1.GeneratedColumn<String>('zulip_version', aliasedName, false,
80+
type: i1.DriftSqlType.string);
81+
i1.GeneratedColumn<String> _column_6(String aliasedName) =>
82+
i1.GeneratedColumn<String>('zulip_merge_base', aliasedName, true,
83+
type: i1.DriftSqlType.string);
84+
i1.GeneratedColumn<int> _column_7(String aliasedName) =>
85+
i1.GeneratedColumn<int>('zulip_feature_level', aliasedName, false,
86+
type: i1.DriftSqlType.int);
87+
i1.GeneratedColumn<String> _column_8(String aliasedName) =>
88+
i1.GeneratedColumn<String>('acked_push_token', aliasedName, true,
89+
type: i1.DriftSqlType.string);
90+
i0.MigrationStepWithVersion migrationSteps({
91+
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
92+
}) {
93+
return (currentVersion, database) async {
94+
switch (currentVersion) {
95+
case 1:
96+
final schema = Schema2(database: database);
97+
final migrator = i1.Migrator(database, schema);
98+
await from1To2(migrator, schema);
99+
return 2;
100+
default:
101+
throw ArgumentError.value('Unknown migration from $currentVersion');
102+
}
103+
};
104+
}
105+
106+
i1.OnUpgrade stepByStep({
107+
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
108+
}) =>
109+
i0.VersionedSchema.stepByStepHelper(
110+
step: migrationSteps(
111+
from1To2: from1To2,
112+
));

tools/check

+8-3
Original file line numberDiff line numberDiff line change
@@ -378,13 +378,15 @@ run_l10n() {
378378

379379
run_drift() {
380380
local schema_dir=test/model/schemas/
381+
local migration_helper_path=lib/model/schema_versions.g.dart
382+
local outputs=( "${schema_dir}" "${migration_helper_path}" )
381383

382384
# Omitted from this check:
383385
# pubspec.{yaml,lock} tools/check
384-
files_check lib/model/database{,.g}.dart "${schema_dir}" \
386+
files_check lib/model/database{,.g}.dart "${outputs[@]}" \
385387
|| return 0
386388

387-
check_no_uncommitted_or_untracked "${schema_dir}" \
389+
check_no_uncommitted_or_untracked "${outputs[@]}" \
388390
|| return
389391

390392
dart run drift_dev schema dump \
@@ -393,8 +395,11 @@ run_drift() {
393395
dart run drift_dev schema generate --data-classes --companions \
394396
"${schema_dir}" "${schema_dir}" \
395397
|| return
398+
dart run drift_dev schema steps \
399+
"${schema_dir}" "${migration_helper_path}" \
400+
|| return
396401

397-
check_no_changes "schema updates" "${schema_dir}"
402+
check_no_changes "schema or migration helper updates" "${outputs[@]}"
398403
}
399404

400405
filter_flutter_pub_run_output() {

0 commit comments

Comments
 (0)