import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:spotiflac_android/utils/logger.dart'; import 'package:spotiflac_android/utils/path_match_keys.dart'; import 'package:sqflite/sqflite.dart'; final _log = AppLogger('AppSqlite'); /// Opens a database file in the app documents directory with the shared /// WAL + synchronous=NORMAL configuration. Future openAppDatabase( String fileName, { required int version, required Future Function(Database db, int version) onCreate, required Future Function(Database db, int oldVersion, int newVersion) onUpgrade, bool foreignKeys = false, }) async { final dbPath = await getApplicationDocumentsDirectory(); final path = join(dbPath.path, fileName); _log.i('Initializing database at: $path'); return openDatabase( path, version: version, onConfigure: (db) async { if (foreignKeys) { await db.execute('PRAGMA foreign_keys = ON'); } await db.rawQuery('PRAGMA journal_mode = WAL'); await db.execute('PRAGMA synchronous = NORMAL'); }, onCreate: onCreate, onUpgrade: onUpgrade, ); } String normalizeLookupText(String? value) { return (value ?? '').trim().toLowerCase(); } Future addColumnIfMissing( Database db, String table, String column, String type, ) async { final columns = await db.rawQuery('PRAGMA table_info($table)'); final exists = columns.any( (row) => (row['name']?.toString().toLowerCase() ?? '') == column, ); if (!exists) { await db.execute('ALTER TABLE $table ADD COLUMN $column $type'); } } Future createPathKeyTable(DatabaseExecutor db, String table) async { await db.execute(''' CREATE TABLE IF NOT EXISTS $table ( item_id TEXT NOT NULL, path_key TEXT NOT NULL, PRIMARY KEY (item_id, path_key) ) '''); await db.execute( 'CREATE INDEX IF NOT EXISTS idx_${table}_key ON $table(path_key)', ); } Future backfillPathKeys( Database db, String sourceTable, String keyTable, ) async { final rows = await db.query(sourceTable, columns: ['id', 'file_path']); final batch = db.batch(); for (final row in rows) { putPathKeysInBatch( batch, keyTable, row['id'] as String, row['file_path'] as String?, ); } await batch.commit(noResult: true); } void putPathKeysInBatch( Batch batch, String table, String id, String? filePath, ) { batch.delete(table, where: 'item_id = ?', whereArgs: [id]); for (final key in buildPathMatchKeys(filePath)) { batch.insert(table, { 'item_id': id, 'path_key': key, }, conflictAlgorithm: ConflictAlgorithm.ignore); } }