11import  'package:drift/drift.dart' ;
2+ import  'package:drift/internal/versioned_schema.dart' ;
23import  'package:drift/remote.dart' ;
34import  'package:sqlite3/common.dart' ;
45
6+ import  '../log.dart' ;
57import  'schema_versions.g.dart' ;
68
79part  'database.g.dart' ;
@@ -49,6 +51,19 @@ class UriConverter extends TypeConverter<Uri, String> {
4951  @override  Uri  fromSql (String  fromDb) =>  Uri .parse (fromDb);
5052}
5153
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+ 
5267@DriftDatabase (tables:  [Accounts ])
5368class  AppDatabase  extends  _$AppDatabase  {
5469  AppDatabase (super .e);
@@ -65,6 +80,31 @@ class AppDatabase extends _$AppDatabase {
6580  @override 
6681  int  get  schemaVersion =>  2 ; // See note. 
6782
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+ 
68108  @override 
69109  MigrationStrategy  get  migration {
70110    return  MigrationStrategy (
@@ -73,15 +113,11 @@ class AppDatabase extends _$AppDatabase {
73113      },
74114      onUpgrade:  (Migrator  m, int  from, int  to) async  {
75115        if  (from >  to) {
76-           // TODO(log): log schema downgrade as an error 
77116          // This should only ever happen in dev.  As a dev convenience, 
78117          // 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);
85121          return ;
86122        }
87123        assert (1  <=  from &&  from <=  to &&  to <=  schemaVersion);
0 commit comments