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(upstream): 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);
@@ -65,6 +80,31 @@ class AppDatabase extends _$AppDatabase {
65
80
@override
66
81
int get schemaVersion => 2 ; // See note.
67
82
83
+ Future <void > _dropAndCreateAll (Migrator m, {
84
+ required int schemaVersion,
85
+ }) async {
86
+ await m.database.transaction (() async {
87
+ final query = m.database.customSelect (
88
+ "SELECT name FROM sqlite_master WHERE type='table'" );
89
+ for (final row in await query.get ()) {
90
+ final data = row.data;
91
+ final tableName = data['name' ] as String ;
92
+ // Skip sqlite-internal tables. See for comparison:
93
+ // https://www.sqlite.org/fileformat2.html#intschema
94
+ // https://github.com/simolus3/drift/blob/0901c984a/drift_dev/lib/src/services/schema/verifier_common.dart#L9-L22
95
+ if (tableName.startsWith ('sqlite_' )) continue ;
96
+ // No need to worry about SQL injection; this table name
97
+ // was already a table name in the database, not something
98
+ // that should be affected by user data.
99
+ await m.database.customStatement ('DROP TABLE $tableName ' );
100
+ }
101
+ final schema = _getSchema (database: m.database, schemaVersion: schemaVersion);
102
+ for (final entity in schema.entities) {
103
+ await m.create (entity);
104
+ }
105
+ });
106
+ }
107
+
68
108
@override
69
109
MigrationStrategy get migration {
70
110
return MigrationStrategy (
@@ -73,15 +113,11 @@ class AppDatabase extends _$AppDatabase {
73
113
},
74
114
onUpgrade: (Migrator m, int from, int to) async {
75
115
if (from > to) {
76
- // TODO(log): log schema downgrade as an error
77
116
// This should only ever happen in dev. As a dev convenience,
78
117
// 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 ();
118
+ // TODO(log): log schema downgrade as an error
119
+ assert (debugLog ('Downgrading schema from v$from to v$to .' ));
120
+ await _dropAndCreateAll (m, schemaVersion: to);
85
121
return ;
86
122
}
87
123
assert (1 <= from && from <= to && to <= schemaVersion);
0 commit comments