diff --git a/drift/CHANGELOG.md b/drift/CHANGELOG.md index ee8e207ea..bb28b6586 100644 --- a/drift/CHANGELOG.md +++ b/drift/CHANGELOG.md @@ -2,6 +2,7 @@ - To infer whether serialization is required for inter-isolate communication, drift now sends a test message instead serializing by default. +- The DevTools extension can now clear drift databases. ## 2.20.2 diff --git a/drift/lib/src/runtime/devtools/service_extension.dart b/drift/lib/src/runtime/devtools/service_extension.dart index 9a6f5cf21..91dee1ea6 100644 --- a/drift/lib/src/runtime/devtools/service_extension.dart +++ b/drift/lib/src/runtime/devtools/service_extension.dart @@ -73,6 +73,28 @@ class DriftServiceExtension { }); return executor.statements; + case 'clear': + final database = tracked.database; + await database.exclusively(() async { + // https://stackoverflow.com/a/65743498/25690041 + await database.customStatement('PRAGMA writable_schema = 1;'); + await database.customStatement('DELETE FROM sqlite_master;'); + await database.customStatement('VACUUM;'); + await database.customStatement('PRAGMA writable_schema = 0;'); + await database.customStatement('PRAGMA integrity_check'); + + await database.customStatement('PRAGMA user_version = 0'); + await database.beforeOpen(database.resolvedEngine.executor, + OpeningDetails(null, database.schemaVersion)); + await database.customStatement( + 'PRAGMA user_version = ${database.schemaVersion}'); + + // Refresh all stream queries + database.notifyUpdates({ + for (final table in database.allTables) TableUpdate.onTable(table) + }); + }); + return true; default: throw UnsupportedError('Method $action'); } diff --git a/extras/drift_devtools_extension/lib/src/clear_button.dart b/extras/drift_devtools_extension/lib/src/clear_button.dart new file mode 100644 index 000000000..8904b5314 --- /dev/null +++ b/extras/drift_devtools_extension/lib/src/clear_button.dart @@ -0,0 +1,60 @@ +import 'package:devtools_app_shared/ui.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'details.dart'; + +class ClearDatabaseButton extends ConsumerStatefulWidget { + const ClearDatabaseButton({super.key}); + + @override + ConsumerState createState() => + _ClearDatabaseButtonState(); +} + +class _ClearDatabaseButtonState extends ConsumerState { + Future? _pendingClear = null; + + @override + Widget build(BuildContext context) { + return DevToolsButton( + onPressed: () { + showDevToolsDialog( + context: context, + title: 'Confirm deletion', + content: const Text( + 'This will delete contents of the database and then re-create it. ' + 'All current database data will be lost. Continue?', + ), + actions: [ + DevToolsButton( + onPressed: _pendingClear != null + ? null + : () { + setState(() { + _pendingClear = Future(() async { + final database = ref.read(loadedDatabase); + await database.value!.clear(); + }) + .whenComplete( + () => setState(() => _pendingClear = null)) + .then((_) { + if (mounted) { + // ignore: use_build_context_synchronously + Navigator.pop(context); + } + }); + }); + }, + label: 'Confirm deletion', + color: Colors.redAccent, + ), + ], + ); + }, + label: 'Clear database', + color: Colors.redAccent, + icon: Icons.delete, + ); + } +} diff --git a/extras/drift_devtools_extension/lib/src/details.dart b/extras/drift_devtools_extension/lib/src/details.dart index 9c9acabd4..4a9134c42 100644 --- a/extras/drift_devtools_extension/lib/src/details.dart +++ b/extras/drift_devtools_extension/lib/src/details.dart @@ -3,6 +3,7 @@ import 'package:drift_devtools_extension/src/schema_validator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'clear_button.dart'; import 'db_viewer/viewer.dart'; import 'list.dart'; import 'remote_database.dart'; @@ -65,6 +66,14 @@ class _DatabaseDetailsState extends ConsumerState { padding: EdgeInsets.all(8), child: DatabaseSchemaCheck(), ), + const Padding( + padding: EdgeInsets.all(8), + child: Row( + children: [ + ClearDatabaseButton(), + ], + ), + ), Padding( padding: const EdgeInsets.all(8.0), child: Column( diff --git a/extras/drift_devtools_extension/lib/src/remote_database.dart b/extras/drift_devtools_extension/lib/src/remote_database.dart index 4209714c5..71c1442da 100644 --- a/extras/drift_devtools_extension/lib/src/remote_database.dart +++ b/extras/drift_devtools_extension/lib/src/remote_database.dart @@ -77,6 +77,10 @@ class RemoteDatabase { return (res as List).cast(); } + Future clear() async { + await _driftRequest('clear'); + } + Future _newTableSubscription() async { final result = await _driftRequest('subscribe-to-tables'); return result as int;