1
1
import 'package:drift/drift.dart' ;
2
+ import 'package:drift/internal/versioned_schema.dart' ;
2
3
import 'package:drift/remote.dart' ;
3
4
import 'package:sqlite3/common.dart' ;
4
5
6
+ import '../log.dart' ;
5
7
import 'schema_versions.g.dart' ;
6
8
7
9
part 'database.g.dart' ;
@@ -49,6 +51,19 @@ class UriConverter extends TypeConverter<Uri, String> {
49
51
@override Uri fromSql (String fromDb) => Uri .parse (fromDb);
50
52
}
51
53
54
+ // TODO(drift): generate this
55
+ VersionedSchema _getSchema ({
56
+ required DatabaseConnectionUser database,
57
+ required int schemaVersion,
58
+ }) {
59
+ switch (schemaVersion) {
60
+ case 2 :
61
+ return Schema2 (database: database);
62
+ default :
63
+ throw Exception ('unknown schema version: $schemaVersion ' );
64
+ }
65
+ }
66
+
52
67
@DriftDatabase (tables: [Accounts ])
53
68
class AppDatabase extends _$AppDatabase {
54
69
AppDatabase (super .e);
@@ -60,11 +75,37 @@ class AppDatabase extends _$AppDatabase {
60
75
// and generate database code with build_runner.
61
76
// See ../../README.md#generated-files for more
62
77
// information on using the build_runner.
78
+ // * Update [_getSchema] to handle the new schemaVersion.
63
79
// * Write a migration in `onUpgrade` below.
64
80
// * Write tests.
65
81
@override
66
82
int get schemaVersion => 2 ; // See note.
67
83
84
+ Future <void > _dropAndCreateAll (Migrator m, {
85
+ required int schemaVersion,
86
+ }) async {
87
+ await m.database.transaction (() async {
88
+ final query = m.database.customSelect (
89
+ "SELECT name FROM sqlite_master WHERE type='table'" );
90
+ for (final row in await query.get ()) {
91
+ final data = row.data;
92
+ final tableName = data['name' ] as String ;
93
+ // Skip sqlite-internal tables. See for comparison:
94
+ // https://www.sqlite.org/fileformat2.html#intschema
95
+ // https://github.com/simolus3/drift/blob/0901c984a/drift_dev/lib/src/services/schema/verifier_common.dart#L9-L22
96
+ if (tableName.startsWith ('sqlite_' )) continue ;
97
+ // No need to worry about SQL injection; this table name
98
+ // was already a table name in the database, not something
99
+ // that should be affected by user data.
100
+ await m.database.customStatement ('DROP TABLE $tableName ' );
101
+ }
102
+ final schema = _getSchema (database: m.database, schemaVersion: schemaVersion);
103
+ for (final entity in schema.entities) {
104
+ await m.create (entity);
105
+ }
106
+ });
107
+ }
108
+
68
109
@override
69
110
MigrationStrategy get migration {
70
111
return MigrationStrategy (
@@ -73,15 +114,11 @@ class AppDatabase extends _$AppDatabase {
73
114
},
74
115
onUpgrade: (Migrator m, int from, int to) async {
75
116
if (from > to) {
76
- // TODO(log): log schema downgrade as an error
77
117
// This should only ever happen in dev. As a dev convenience,
78
118
// drop everything from the database and start over.
79
- for (final entity in allSchemaEntities) {
80
- // This will miss any entire tables (or indexes, etc.) that
81
- // don't exist at this version. For a dev-only feature, that's OK.
82
- await m.drop (entity);
83
- }
84
- await m.createAll ();
119
+ // TODO(log): log schema downgrade as an error
120
+ assert (debugLog ('Downgrading schema from v$from to v$to .' ));
121
+ await _dropAndCreateAll (m, schemaVersion: to);
85
122
return ;
86
123
}
87
124
assert (1 <= from && from <= to && to <= schemaVersion);
0 commit comments