import 'dart:io'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; part 'app_database.g.dart'; @DataClassName('DbNote') class Notes extends Table { IntColumn get id => integer().autoIncrement()(); TextColumn get title => text()(); TextColumn get body => text()(); DateTimeColumn get createdAt => dateTime()(); DateTimeColumn get updatedAt => dateTime()(); IntColumn get sortIndex => integer().named('sort_index')(); } @DriftDatabase(tables: [Notes]) class AppDatabase extends _$AppDatabase { AppDatabase({required String encryptionKey}) : super(_openConnection(encryptionKey)); @override int get schemaVersion => 1; Future> getAllNotes() { return (select(notes)..orderBy([ (note) => OrderingTerm(expression: note.sortIndex), ])).get(); } Future insertNoteAtTop(NotesCompanion note) { return transaction(() async { await customStatement('UPDATE notes SET sort_index = sort_index + 1'); return into(notes).insert(note.copyWith(sortIndex: const Value(0))); }); } Future replaceAllNotes(List noteList) { return transaction(() async { await delete(notes).go(); for (final NotesCompanion note in noteList) { await into(notes).insert(note); } }); } Future updateNoteRow(DbNote note) { return update(notes).replace(note); } Future deleteNoteAndShift({ required int id, required int removedIndex, }) { return transaction(() async { await (delete(notes)..where((note) => note.id.equals(id))).go(); await customStatement( 'UPDATE notes SET sort_index = sort_index - 1 WHERE sort_index > ?', [removedIndex], ); }); } Future moveNote({ required int id, required int oldIndex, required int newIndex, }) { if (oldIndex == newIndex) { return Future.value(); } return transaction(() async { if (oldIndex < newIndex) { await customStatement( 'UPDATE notes SET sort_index = sort_index - 1 WHERE sort_index > ? AND sort_index <= ?', [oldIndex, newIndex], ); } else { await customStatement( 'UPDATE notes SET sort_index = sort_index + 1 WHERE sort_index >= ? AND sort_index < ?', [newIndex, oldIndex], ); } await customStatement( 'UPDATE notes SET sort_index = ? WHERE id = ?', [newIndex, id], ); }); } } LazyDatabase _openConnection(String encryptionKey) { return LazyDatabase(() async { final Directory supportDir = await getApplicationSupportDirectory(); final File file = File(p.join(supportDir.path, 'notes.sqlite')); return NativeDatabase( file, setup: (database) { final String escapedKey = encryptionKey.replaceAll("'", "''"); // sqlite3mc can emulate SQLCipher file format for compatibility. database.execute("PRAGMA cipher = 'sqlcipher'"); database.execute('PRAGMA legacy = 4'); database.execute("PRAGMA key = '$escapedKey'"); }, ); }); }