diff --git a/lib/database/database.dart b/lib/database/database.dart index 2d3bc2b..e7ae304 100644 --- a/lib/database/database.dart +++ b/lib/database/database.dart @@ -9,11 +9,13 @@ import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import '../log.dart'; import '../models/music.dart'; import '../models/query.dart'; import '../models/settings.dart'; import '../models/support.dart'; import 'converters.dart'; +import 'error_logging_database.dart'; part 'database.g.dart'; @@ -435,7 +437,11 @@ LazyDatabase _openConnection() { final dbFolder = await getApplicationDocumentsDirectory(); final file = File(p.join(dbFolder.path, 'subtracks.sqlite')); // return NativeDatabase.createInBackground(file, logStatements: true); - return NativeDatabase.createInBackground(file); + + return ErrorLoggingDatabase( + NativeDatabase.createInBackground(file), + (e, s) => log.severe('SQL Error', e, s), + ); }); } diff --git a/lib/database/error_logging_database.dart b/lib/database/error_logging_database.dart new file mode 100644 index 0000000..6789bd0 --- /dev/null +++ b/lib/database/error_logging_database.dart @@ -0,0 +1,94 @@ +import 'dart:async'; + +import 'package:drift/drift.dart'; +import 'package:drift/isolate.dart'; + +/// https://github.com/simolus3/drift/issues/2326#issuecomment-1445138730 +class ErrorLoggingDatabase implements QueryExecutor { + final QueryExecutor inner; + final void Function(Object, StackTrace) onError; + + ErrorLoggingDatabase(this.inner, this.onError); + + Future _handleErrors(Future Function() body) { + return Future.sync(body) + .onError((error, stackTrace) { + onError(error, error.trace ?? stackTrace); + throw error; + }).onError((error, stackTrace) { + onError(error, error.remoteStackTrace ?? stackTrace); + throw error; + }); + } + + @override + TransactionExecutor beginTransaction() { + return _ErrorLoggingTransactionExecutor(inner.beginTransaction(), onError); + } + + @override + Future close() { + return _handleErrors(inner.close); + } + + @override + SqlDialect get dialect => inner.dialect; + + @override + Future ensureOpen(QueryExecutorUser user) { + return _handleErrors(() => inner.ensureOpen(user)); + } + + @override + Future runBatched(BatchedStatements statements) { + return _handleErrors(() => inner.runBatched(statements)); + } + + @override + Future runCustom(String statement, [List? args]) { + return _handleErrors(() => inner.runCustom(statement, args)); + } + + @override + Future runDelete(String statement, List args) { + return _handleErrors(() => inner.runDelete(statement, args)); + } + + @override + Future runInsert(String statement, List args) { + return _handleErrors(() => inner.runInsert(statement, args)); + } + + @override + Future>> runSelect( + String statement, List args) { + return _handleErrors(() => inner.runSelect(statement, args)); + } + + @override + Future runUpdate(String statement, List args) { + return _handleErrors(() => inner.runUpdate(statement, args)); + } +} + +class _ErrorLoggingTransactionExecutor extends ErrorLoggingDatabase + implements TransactionExecutor { + final TransactionExecutor transaction; + + _ErrorLoggingTransactionExecutor( + this.transaction, void Function(Object, StackTrace) onError) + : super(transaction, onError); + + @override + Future rollback() { + return _handleErrors(transaction.rollback); + } + + @override + Future send() { + return _handleErrors(transaction.send); + } + + @override + bool get supportsNestedTransactions => transaction.supportsNestedTransactions; +}