diff --git a/docs/lib/snippets/setup/database.dart b/docs/lib/snippets/setup/database.dart index cb330e8b5..f62c83c83 100644 --- a/docs/lib/snippets/setup/database.dart +++ b/docs/lib/snippets/setup/database.dart @@ -12,6 +12,7 @@ import 'package:drift/native.dart'; // #enddocregion sqlite3 // #docregion postgres import 'package:drift_postgres/drift_postgres.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:postgres/postgres.dart' as pg; // #enddocregion postgres @@ -51,9 +52,14 @@ class AppDatabase extends _$AppDatabase { class OpenFlutter { // #docregion flutter static QueryExecutor _openConnection() { - // `driftDatabase` from `package:drift_flutter` stores the database in - // `getApplicationDocumentsDirectory()`. - return driftDatabase(name: 'my_database'); + return driftDatabase( + name: 'my_database', + native: DriftNativeOptions( + // By default, `driftDatabase` from `package:drift_flutter` stores the + // database files in `getApplicationDocumentsDirectory()`. + databaseDirectory: getApplicationSupportDirectory, + ), + ); } } // #enddocregion flutter diff --git a/drift_flutter/CHANGELOG.md b/drift_flutter/CHANGELOG.md index 7f8bb3be8..393eda3d5 100644 --- a/drift_flutter/CHANGELOG.md +++ b/drift_flutter/CHANGELOG.md @@ -1,6 +1,8 @@ ## 0.2.4-dev - Allow providing a custom temporary directory. +- Allow providing a custom database directory, making it easier to swap out the + default `getApplicationDocumentsDirectory()`. ## 0.2.3 diff --git a/drift_flutter/lib/src/connect.dart b/drift_flutter/lib/src/connect.dart index 3a5248cb6..2a207718e 100644 --- a/drift_flutter/lib/src/connect.dart +++ b/drift_flutter/lib/src/connect.dart @@ -65,8 +65,26 @@ final class DriftNativeOptions { /// /// This function, which can be asynchronous for convenience, allows using /// a custom database path in another directory. + /// + /// At most one of [databasePath] or [databaseDirectory] may be used. Using + /// [databasePath] allows more control over the file name, while + /// [databaseDirectory] can be used to select another directory from + /// `path_provider` more easily. final Future Function()? databasePath; + /// An optional function returning either a string or a `Directory` that will + /// be used as a directory to store the database. + /// + /// By default, drift will use `getApplicationDocumentsDirectory()` function + /// from `package:path_provider` as a directory an `$name.sqlite` as a file + /// name in that directory. + /// + /// At most one of [databasePath] or [databaseDirectory] may be used. Using + /// [databasePath] allows more control over the file name, while + /// [databaseDirectory] can be used to select another directory from + /// `path_provider` more easily. + final Future Function()? databaseDirectory; + /// An optional callback returning a temporary directory. /// /// For larger queries, sqlite3 might store intermediate results in memory. @@ -88,6 +106,10 @@ final class DriftNativeOptions { const DriftNativeOptions({ this.shareAcrossIsolates = false, this.databasePath, + this.databaseDirectory, this.tempDirectoryPath, - }); + }) : assert( + databasePath == null || databaseDirectory == null, + 'databasePath and databaseDirectory must not both be set.', + ); } diff --git a/drift_flutter/lib/src/native.dart b/drift_flutter/lib/src/native.dart index ebbc9b6ac..dd9f4f88e 100644 --- a/drift_flutter/lib/src/native.dart +++ b/drift_flutter/lib/src/native.dart @@ -34,8 +34,22 @@ QueryExecutor driftDatabase({ if (native?.databasePath case final lookupPath?) { return File(await lookupPath()); } else { - final dbFolder = await getApplicationDocumentsDirectory(); - return File(p.join(dbFolder.path, '$name.sqlite')); + final resolvedDirectory = await (native?.databaseDirectory ?? + getApplicationDocumentsDirectory)(); + + return File(p.join( + switch (resolvedDirectory) { + Directory(:final path) => path, + final String path => path, + final other => throw ArgumentError.value( + other, + 'other', + 'databaseDirectory on DriftNativeOptions must resolve to a ' + 'directory or a path as string.', + ) + }, + '$name.sqlite', + )); } } diff --git a/drift_flutter/pubspec.yaml b/drift_flutter/pubspec.yaml index cc85b7f8b..4618b3091 100644 --- a/drift_flutter/pubspec.yaml +++ b/drift_flutter/pubspec.yaml @@ -1,6 +1,6 @@ name: drift_flutter description: Easily set up drift databases across platforms in Flutter apps. -version: 0.2.3 +version: 0.2.4-dev repository: https://github.com/simolus3/drift homepage: https://drift.simonbinder.eu/ issue_tracker: https://github.com/simolus3/drift/issues diff --git a/drift_flutter/test/native_test.dart b/drift_flutter/test/native_test.dart index a9546629a..86aea9612 100644 --- a/drift_flutter/test/native_test.dart +++ b/drift_flutter/test/native_test.dart @@ -14,6 +14,7 @@ import 'package:drift_flutter/src/native.dart' show PingWithTimeout, hasConfiguredSqlite, portName; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:sqlite3/sqlite3.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; @@ -28,6 +29,7 @@ void main() { return switch (call.method) { 'getTemporaryDirectory' => d.sandbox, 'getApplicationDocumentsDirectory' => d.path('applications'), + 'getApplicationSupportDirectory' => d.path('support'), _ => throw UnsupportedError('Unexpected path provider call: $call') }; }); @@ -69,6 +71,35 @@ void main() { await database.close(); }); + test('can use custom database directory', () async { + final database = SimpleDatabase(driftDatabase( + name: 'database', + native: DriftNativeOptions( + databaseDirectory: getApplicationSupportDirectory, + ), + )); + await database.customSelect('SELECT 1').get(); + + expect(sqlite3.tempDirectory, d.sandbox); + await d.dir('support', [ + d.FileDescriptor.binaryMatcher('database.sqlite', anything), + ]).validate(); + await database.close(); + }); + + test('forbids passing custom directory and custom path', () async { + expect( + () => SimpleDatabase(driftDatabase( + name: 'database', + native: DriftNativeOptions( + databasePath: () async => d.path('my_dir/custom_file'), + databaseDirectory: getApplicationSupportDirectory, + ), + )), + throwsAssertionError, + ); + }); + test('can use custom temporary directory', () async { final database = SimpleDatabase(driftDatabase( name: 'database', @@ -147,6 +178,7 @@ void main() { final isolate = await Isolate.spawn((_) {}, ''); isolate.kill(); + await pumpEventQueue(times: 1); expect(await isolate.pingWithTimeout(), false); });