Add option to disable migrations

This commit is contained in:
Simon Binder 2024-01-13 12:14:29 +01:00
parent b214f2c661
commit a683408897
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 90 additions and 3 deletions

View File

@ -6,6 +6,8 @@
supported by drift (like UUIDs) on databases that support it while falling supported by drift (like UUIDs) on databases that support it while falling
back to a text type on sqlite3. back to a text type on sqlite3.
- Close wasm databases hosted in workers after the last client disconnects. - Close wasm databases hosted in workers after the last client disconnects.
- Add `enableMigrations` parameter to `NativeDatabase` which can be used to
optionally disable database migrations when opening databases.
## 2.14.1 ## 2.14.1

View File

@ -67,17 +67,27 @@ class NativeDatabase extends DelegatedDatabase {
/// the database is opened, before drift is fully ready. This can be used to /// the database is opened, before drift is fully ready. This can be used to
/// add custom user-defined sql functions or to provide encryption keys in /// add custom user-defined sql functions or to provide encryption keys in
/// SQLCipher implementations. /// SQLCipher implementations.
///
/// By default, drift runs migrations defined in your database class to create
/// tables when the database is first opened or to alter when when your schema
/// changes. This uses the `user_version` sqlite3 pragma, which is compared
/// against the `schemaVersion` getter of the database.
/// If you want to manage migrations independently or don't need them at all,
/// you can disable migrations in drift with the [enableMigrations]
/// parameter.
/// {@endtemplate} /// {@endtemplate}
factory NativeDatabase( factory NativeDatabase(
File file, { File file, {
bool logStatements = false, bool logStatements = false,
DatabaseSetup? setup, DatabaseSetup? setup,
bool enableMigrations = true,
bool cachePreparedStatements = _cacheStatementsByDefault, bool cachePreparedStatements = _cacheStatementsByDefault,
}) { }) {
return NativeDatabase._( return NativeDatabase._(
_NativeDelegate( _NativeDelegate(
file, file,
setup, setup,
enableMigrations,
cachePreparedStatements, cachePreparedStatements,
), ),
logStatements); logStatements);
@ -105,6 +115,7 @@ class NativeDatabase extends DelegatedDatabase {
bool logStatements = false, bool logStatements = false,
bool cachePreparedStatements = _cacheStatementsByDefault, bool cachePreparedStatements = _cacheStatementsByDefault,
DatabaseSetup? setup, DatabaseSetup? setup,
bool enableMigrations = true,
IsolateSetup? isolateSetup, IsolateSetup? isolateSetup,
}) { }) {
return createBackgroundConnection( return createBackgroundConnection(
@ -112,6 +123,7 @@ class NativeDatabase extends DelegatedDatabase {
logStatements: logStatements, logStatements: logStatements,
setup: setup, setup: setup,
isolateSetup: isolateSetup, isolateSetup: isolateSetup,
enableMigrations: enableMigrations,
cachePreparedStatements: cachePreparedStatements, cachePreparedStatements: cachePreparedStatements,
); );
} }
@ -126,6 +138,7 @@ class NativeDatabase extends DelegatedDatabase {
bool logStatements = false, bool logStatements = false,
DatabaseSetup? setup, DatabaseSetup? setup,
IsolateSetup? isolateSetup, IsolateSetup? isolateSetup,
bool enableMigrations = true,
bool cachePreparedStatements = _cacheStatementsByDefault, bool cachePreparedStatements = _cacheStatementsByDefault,
}) { }) {
return DatabaseConnection.delayed(Future.sync(() async { return DatabaseConnection.delayed(Future.sync(() async {
@ -136,6 +149,7 @@ class NativeDatabase extends DelegatedDatabase {
file.absolute.path, file.absolute.path,
logStatements, logStatements,
cachePreparedStatements, cachePreparedStatements,
enableMigrations,
setup, setup,
isolateSetup, isolateSetup,
receiveIsolate.sendPort, receiveIsolate.sendPort,
@ -159,7 +173,15 @@ class NativeDatabase extends DelegatedDatabase {
bool cachePreparedStatements = _cacheStatementsByDefault, bool cachePreparedStatements = _cacheStatementsByDefault,
}) { }) {
return NativeDatabase._( return NativeDatabase._(
_NativeDelegate(null, setup, cachePreparedStatements), _NativeDelegate(
null,
setup,
// Disabling migrations makes no sense for in-memory databases, which
// would always be empty otherwise. They will also not be read-only, so
// what's the point...
true,
cachePreparedStatements,
),
logStatements, logStatements,
); );
} }
@ -181,6 +203,7 @@ class NativeDatabase extends DelegatedDatabase {
bool logStatements = false, bool logStatements = false,
DatabaseSetup? setup, DatabaseSetup? setup,
bool closeUnderlyingOnClose = true, bool closeUnderlyingOnClose = true,
bool enableMigrations = true,
bool cachePreparedStatements = _cacheStatementsByDefault, bool cachePreparedStatements = _cacheStatementsByDefault,
}) { }) {
return NativeDatabase._( return NativeDatabase._(
@ -189,6 +212,7 @@ class NativeDatabase extends DelegatedDatabase {
setup, setup,
closeUnderlyingOnClose, closeUnderlyingOnClose,
cachePreparedStatements, cachePreparedStatements,
enableMigrations,
), ),
logStatements); logStatements);
} }
@ -246,9 +270,11 @@ class NativeDatabase extends DelegatedDatabase {
class _NativeDelegate extends Sqlite3Delegate<Database> { class _NativeDelegate extends Sqlite3Delegate<Database> {
final File? file; final File? file;
_NativeDelegate(this.file, DatabaseSetup? setup, bool cachePreparedStatements) _NativeDelegate(this.file, DatabaseSetup? setup, bool enableMigrations,
bool cachePreparedStatements)
: super( : super(
setup, setup,
enableMigrations: enableMigrations,
cachePreparedStatements: cachePreparedStatements, cachePreparedStatements: cachePreparedStatements,
); );
@ -257,9 +283,11 @@ class _NativeDelegate extends Sqlite3Delegate<Database> {
super.setup, super.setup,
super.closeUnderlyingWhenClosed, super.closeUnderlyingWhenClosed,
bool cachePreparedStatements, bool cachePreparedStatements,
bool enableMigrations,
) : file = null, ) : file = null,
super.opened( super.opened(
cachePreparedStatements: cachePreparedStatements, cachePreparedStatements: cachePreparedStatements,
enableMigrations: enableMigrations,
); );
@override @override
@ -334,6 +362,7 @@ class _NativeIsolateStartup {
final String path; final String path;
final bool enableLogs; final bool enableLogs;
final bool cachePreparedStatements; final bool cachePreparedStatements;
final bool enableMigrations;
final DatabaseSetup? setup; final DatabaseSetup? setup;
final IsolateSetup? isolateSetup; final IsolateSetup? isolateSetup;
final SendPort sendServer; final SendPort sendServer;
@ -342,6 +371,7 @@ class _NativeIsolateStartup {
this.path, this.path,
this.enableLogs, this.enableLogs,
this.cachePreparedStatements, this.cachePreparedStatements,
this.enableMigrations,
this.setup, this.setup,
this.isolateSetup, this.isolateSetup,
this.sendServer, this.sendServer,
@ -354,6 +384,7 @@ class _NativeIsolateStartup {
File(startup.path), File(startup.path),
logStatements: startup.enableLogs, logStatements: startup.enableLogs,
cachePreparedStatements: startup.cachePreparedStatements, cachePreparedStatements: startup.cachePreparedStatements,
enableMigrations: startup.enableMigrations,
setup: startup.setup, setup: startup.setup,
)); ));
}); });

View File

@ -28,6 +28,9 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
/// Whether prepared statements should be cached. /// Whether prepared statements should be cached.
final bool cachePreparedStatements; final bool cachePreparedStatements;
/// Whether migrations are enabled (they are by default).
final bool enableMigrations;
/// Whether the [database] should be closed when [close] is called on this /// Whether the [database] should be closed when [close] is called on this
/// instance. /// instance.
/// ///
@ -40,6 +43,7 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
/// A delegate that will call [openDatabase] to open the database. /// A delegate that will call [openDatabase] to open the database.
Sqlite3Delegate( Sqlite3Delegate(
this._setup, { this._setup, {
this.enableMigrations = true,
required this.cachePreparedStatements, required this.cachePreparedStatements,
}) : closeUnderlyingWhenClosed = true; }) : closeUnderlyingWhenClosed = true;
@ -49,6 +53,7 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
this._database, this._database,
this._setup, this._setup,
this.closeUnderlyingWhenClosed, { this.closeUnderlyingWhenClosed, {
this.enableMigrations = true,
required this.cachePreparedStatements, required this.cachePreparedStatements,
}) { }) {
_initializeDatabase(); _initializeDatabase();
@ -98,7 +103,9 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
database.useNativeFunctions(); database.useNativeFunctions();
_setup?.call(database); _setup?.call(database);
versionDelegate = _SqliteVersionDelegate(database); versionDelegate = enableMigrations
? _SqliteVersionDelegate(database)
: const NoVersionDelegate();
_hasInitializedDatabase = true; _hasInitializedDatabase = true;
} }

View File

@ -184,6 +184,53 @@ void main() {
await db.close(); await db.close();
expect(underlying.activeStatementCount, isZero); expect(underlying.activeStatementCount, isZero);
}); });
group('can disable migrations', () {
Future<void> runTest(QueryExecutor executor) async {
final db = TodoDb(executor);
db.migration = MigrationStrategy(
onCreate: (_) => fail('should not call onCreate'),
onUpgrade: (_, __, ___) => fail('should not call onUpgrade'),
beforeOpen: expectAsync1((details) async {}),
);
addTearDown(db.close);
await db.customSelect('select 1').get(); // open database
}
test(
'with native database',
() => runTest(NativeDatabase(
File(d.path('test.db')),
enableMigrations: false,
)),
);
test(
'createInBackground',
() => runTest(NativeDatabase.createInBackground(
File(d.path('test.db')),
enableMigrations: false,
)),
);
test(
'createBackgroundConnection',
() => runTest(NativeDatabase.createBackgroundConnection(
File(d.path('test.db')),
enableMigrations: false,
)),
);
test(
'opened',
() => runTest(NativeDatabase.opened(
sqlite3.openInMemory(),
enableMigrations: false,
closeUnderlyingOnClose: true,
)),
);
});
} }
class _FakeExecutorUser extends QueryExecutorUser { class _FakeExecutorUser extends QueryExecutorUser {