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
back to a text type on sqlite3.
- 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

View File

@ -67,17 +67,27 @@ class NativeDatabase extends DelegatedDatabase {
/// 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
/// 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}
factory NativeDatabase(
File file, {
bool logStatements = false,
DatabaseSetup? setup,
bool enableMigrations = true,
bool cachePreparedStatements = _cacheStatementsByDefault,
}) {
return NativeDatabase._(
_NativeDelegate(
file,
setup,
enableMigrations,
cachePreparedStatements,
),
logStatements);
@ -105,6 +115,7 @@ class NativeDatabase extends DelegatedDatabase {
bool logStatements = false,
bool cachePreparedStatements = _cacheStatementsByDefault,
DatabaseSetup? setup,
bool enableMigrations = true,
IsolateSetup? isolateSetup,
}) {
return createBackgroundConnection(
@ -112,6 +123,7 @@ class NativeDatabase extends DelegatedDatabase {
logStatements: logStatements,
setup: setup,
isolateSetup: isolateSetup,
enableMigrations: enableMigrations,
cachePreparedStatements: cachePreparedStatements,
);
}
@ -126,6 +138,7 @@ class NativeDatabase extends DelegatedDatabase {
bool logStatements = false,
DatabaseSetup? setup,
IsolateSetup? isolateSetup,
bool enableMigrations = true,
bool cachePreparedStatements = _cacheStatementsByDefault,
}) {
return DatabaseConnection.delayed(Future.sync(() async {
@ -136,6 +149,7 @@ class NativeDatabase extends DelegatedDatabase {
file.absolute.path,
logStatements,
cachePreparedStatements,
enableMigrations,
setup,
isolateSetup,
receiveIsolate.sendPort,
@ -159,7 +173,15 @@ class NativeDatabase extends DelegatedDatabase {
bool cachePreparedStatements = _cacheStatementsByDefault,
}) {
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,
);
}
@ -181,6 +203,7 @@ class NativeDatabase extends DelegatedDatabase {
bool logStatements = false,
DatabaseSetup? setup,
bool closeUnderlyingOnClose = true,
bool enableMigrations = true,
bool cachePreparedStatements = _cacheStatementsByDefault,
}) {
return NativeDatabase._(
@ -189,6 +212,7 @@ class NativeDatabase extends DelegatedDatabase {
setup,
closeUnderlyingOnClose,
cachePreparedStatements,
enableMigrations,
),
logStatements);
}
@ -246,9 +270,11 @@ class NativeDatabase extends DelegatedDatabase {
class _NativeDelegate extends Sqlite3Delegate<Database> {
final File? file;
_NativeDelegate(this.file, DatabaseSetup? setup, bool cachePreparedStatements)
_NativeDelegate(this.file, DatabaseSetup? setup, bool enableMigrations,
bool cachePreparedStatements)
: super(
setup,
enableMigrations: enableMigrations,
cachePreparedStatements: cachePreparedStatements,
);
@ -257,9 +283,11 @@ class _NativeDelegate extends Sqlite3Delegate<Database> {
super.setup,
super.closeUnderlyingWhenClosed,
bool cachePreparedStatements,
bool enableMigrations,
) : file = null,
super.opened(
cachePreparedStatements: cachePreparedStatements,
enableMigrations: enableMigrations,
);
@override
@ -334,6 +362,7 @@ class _NativeIsolateStartup {
final String path;
final bool enableLogs;
final bool cachePreparedStatements;
final bool enableMigrations;
final DatabaseSetup? setup;
final IsolateSetup? isolateSetup;
final SendPort sendServer;
@ -342,6 +371,7 @@ class _NativeIsolateStartup {
this.path,
this.enableLogs,
this.cachePreparedStatements,
this.enableMigrations,
this.setup,
this.isolateSetup,
this.sendServer,
@ -354,6 +384,7 @@ class _NativeIsolateStartup {
File(startup.path),
logStatements: startup.enableLogs,
cachePreparedStatements: startup.cachePreparedStatements,
enableMigrations: startup.enableMigrations,
setup: startup.setup,
));
});

View File

@ -28,6 +28,9 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
/// Whether prepared statements should be cached.
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
/// instance.
///
@ -40,6 +43,7 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
/// A delegate that will call [openDatabase] to open the database.
Sqlite3Delegate(
this._setup, {
this.enableMigrations = true,
required this.cachePreparedStatements,
}) : closeUnderlyingWhenClosed = true;
@ -49,6 +53,7 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
this._database,
this._setup,
this.closeUnderlyingWhenClosed, {
this.enableMigrations = true,
required this.cachePreparedStatements,
}) {
_initializeDatabase();
@ -98,7 +103,9 @@ abstract class Sqlite3Delegate<DB extends CommonDatabase>
database.useNativeFunctions();
_setup?.call(database);
versionDelegate = _SqliteVersionDelegate(database);
versionDelegate = enableMigrations
? _SqliteVersionDelegate(database)
: const NoVersionDelegate();
_hasInitializedDatabase = true;
}

View File

@ -184,6 +184,53 @@ void main() {
await db.close();
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 {