修复表写入问题,同时增加对读库动作的log可视化

This commit is contained in:
2026-08-27 22:32:38 +08:00
parent e58be9c17f
commit 2a29e30940
+127 -27
View File
@@ -1,4 +1,5 @@
// lib/database/song_database.dart
import 'package:flutter/foundation.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
@@ -10,6 +11,9 @@ class SongDatabase {
static Database? _database;
// ⭐ 开启/关闭日志(开发阶段开启)
static bool enableLog = true;
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
@@ -19,15 +23,34 @@ class SongDatabase {
Future<Database> _initDatabase() async {
final dir = await getApplicationDocumentsDirectory();
final path = join(dir.path, 'qingting_songs.db');
_log('📂 数据库路径: $path');
return await openDatabase(
path,
version: 2,
version: 3,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
}
// ⭐ 新增:检查表是否存在
// ════════════════════════════════════════════════════════════
// 日志工具
// ════════════════════════════════════════════════════════════
void _log(String message) {
if (enableLog) {
debugPrint('📦 [DB] $message');
}
}
void _logQuery(String table, String operation, {Map<String, dynamic>? args}) {
if (enableLog) {
final argsStr = args != null && args.isNotEmpty ? ' $args' : '';
debugPrint('📦 [DB] $table$operation$argsStr');
}
}
// ════════════════════════════════════════════════════════════
// 辅助方法
// ════════════════════════════════════════════════════════════
Future<bool> _tableExists(Database db, String tableName) async {
final result = await db.query(
'sqlite_master',
@@ -37,33 +60,24 @@ class SongDatabase {
return result.isNotEmpty;
}
Future<bool> _columnExists(
Database db, String tableName, String columnName) async {
final result = await db.rawQuery('PRAGMA table_info($tableName)');
return result.any((col) => col['name'] == columnName);
}
// ════════════════════════════════════════════════════════════
// 创建表
// ════════════════════════════════════════════════════════════
Future<void> _onCreate(Database db, int version) async {
_log('🆕 创建数据库 (version $version)');
await _createSongsTable(db);
await _createMetadataCacheTable(db);
await _createPlaylistsTable(db);
await _createPlaylistSongsTable(db);
await _createFavoritesTable(db);
await _createIndexes(db);
}
// ⭐ 升级逻辑(从版本 1 升级到 2)
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
// 检查 playlists 表是否存在
final playlistsExists = await _tableExists(db, 'playlists');
if (!playlistsExists) {
// 表不存在 → 创建所有新表
await _createPlaylistsTable(db);
await _createPlaylistSongsTable(db);
await _createFavoritesTable(db);
await _createIndexes(db);
} else {
// 表已存在 → 只添加新字段
await db.execute(
'ALTER TABLE playlists ADD COLUMN play_mode TEXT DEFAULT "sequential"');
}
}
_log('✅ 数据库创建完成');
}
Future<void> _createSongsTable(Database db) async {
@@ -87,6 +101,7 @@ class SongDatabase {
metadata_status TEXT DEFAULT 'pending'
)
''');
_log('📋 表创建: songs');
}
Future<void> _createMetadataCacheTable(Database db) async {
@@ -99,6 +114,7 @@ class SongDatabase {
FOREIGN KEY (song_key) REFERENCES songs(song_key) ON DELETE CASCADE
)
''');
_log('📋 表创建: metadata_cache');
}
Future<void> _createPlaylistsTable(Database db) async {
@@ -111,6 +127,7 @@ class SongDatabase {
updated_at INTEGER
)
''');
_log('📋 表创建: playlists');
}
Future<void> _createPlaylistSongsTable(Database db) async {
@@ -124,6 +141,7 @@ class SongDatabase {
FOREIGN KEY (playlist_id) REFERENCES playlists(id) ON DELETE CASCADE
)
''');
_log('📋 表创建: playlist_songs');
}
Future<void> _createFavoritesTable(Database db) async {
@@ -134,6 +152,7 @@ class SongDatabase {
FOREIGN KEY (song_id) REFERENCES songs(remote_path) ON DELETE CASCADE
)
''');
_log('📋 表创建: favorites');
}
Future<void> _createIndexes(Database db) async {
@@ -147,12 +166,65 @@ class SongDatabase {
'CREATE INDEX IF NOT EXISTS idx_playlist_songs_playlist ON playlist_songs(playlist_id)');
await db.execute(
'CREATE INDEX IF NOT EXISTS idx_playlist_songs_order ON playlist_songs(order_index)');
_log('📋 索引创建完成');
}
// ════════════════════════════════════════════════════════════
// 查询方法(保持不变)
// 升级逻辑
// ════════════════════════════════════════════════════════════
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
_log('⬆️ 数据库升级: $oldVersion$newVersion');
if (oldVersion < 2) {
if (!await _columnExists(db, 'songs', 'content_hash')) {
await db.execute('ALTER TABLE songs ADD COLUMN content_hash TEXT');
_log('🔧 添加列: songs.content_hash');
}
final playlistsExists = await _tableExists(db, 'playlists');
if (!playlistsExists) {
await _createPlaylistsTable(db);
await _createPlaylistSongsTable(db);
await _createFavoritesTable(db);
} else {
if (!await _columnExists(db, 'playlists', 'play_mode')) {
await db.execute(
'ALTER TABLE playlists ADD COLUMN play_mode TEXT DEFAULT "sequential"');
_log('🔧 添加列: playlists.play_mode');
}
}
await _createIndexes(db);
}
if (oldVersion < 3) {
if (!await _columnExists(db, 'songs', 'content_hash')) {
await db.execute('ALTER TABLE songs ADD COLUMN content_hash TEXT');
_log('🔧 添加列: songs.content_hash');
}
final playlistsExists = await _tableExists(db, 'playlists');
if (!playlistsExists) {
await _createPlaylistsTable(db);
await _createPlaylistSongsTable(db);
await _createFavoritesTable(db);
} else {
if (!await _columnExists(db, 'playlists', 'play_mode')) {
await db.execute(
'ALTER TABLE playlists ADD COLUMN play_mode TEXT DEFAULT "sequential"');
_log('🔧 添加列: playlists.play_mode');
}
}
await _createIndexes(db);
}
_log('✅ 数据库升级完成');
}
// ════════════════════════════════════════════════════════════
// 查询方法(带日志)
// ════════════════════════════════════════════════════════════
Future<Map<String, dynamic>?> getSong(String songKey) async {
_logQuery('songs', 'get', args: {'song_key': songKey});
final db = await database;
final result =
await db.query('songs', where: 'song_key = ?', whereArgs: [songKey]);
@@ -160,6 +232,7 @@ class SongDatabase {
}
Future<Map<String, dynamic>?> getSongByPath(String remotePath) async {
_logQuery('songs', 'getByPath', args: {'remote_path': remotePath});
final db = await database;
final result = await db
.query('songs', where: 'remote_path = ?', whereArgs: [remotePath]);
@@ -167,6 +240,7 @@ class SongDatabase {
}
Future<Map<String, dynamic>?> getSongByHash(String contentHash) async {
_logQuery('songs', 'getByHash', args: {'content_hash': contentHash});
final db = await database;
final result = await db
.query('songs', where: 'content_hash = ?', whereArgs: [contentHash]);
@@ -175,6 +249,7 @@ class SongDatabase {
Future<List<Map<String, dynamic>>> getSongsByArtist(String artist,
{int limit = 20}) async {
_logQuery('songs', 'getByArtist', args: {'artist': artist, 'limit': limit});
if (artist.isEmpty) return [];
final db = await database;
return await db.query(
@@ -186,14 +261,16 @@ class SongDatabase {
}
// ════════════════════════════════════════════════════════════
// 播放列表 CRUD保持不变
// 播放列表 CRUD带日志
// ════════════════════════════════════════════════════════════
Future<List<Map<String, dynamic>>> getAllPlaylists() async {
_logQuery('playlists', 'getAll');
final db = await database;
return await db.query('playlists', orderBy: 'created_at DESC');
}
Future<Map<String, dynamic>?> getPlaylist(String id) async {
_logQuery('playlists', 'get', args: {'id': id});
final db = await database;
final result =
await db.query('playlists', where: 'id = ?', whereArgs: [id]);
@@ -201,25 +278,30 @@ class SongDatabase {
}
Future<void> insertPlaylist(Map<String, dynamic> playlist) async {
_logQuery('playlists', 'insert', args: {'name': playlist['name']});
final db = await database;
await db.insert('playlists', playlist,
conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<void> updatePlaylist(String id, Map<String, dynamic> updates) async {
_logQuery('playlists', 'update',
args: {'id': id, 'updates': updates.keys.join(',')});
final db = await database;
await db.update('playlists', updates, where: 'id = ?', whereArgs: [id]);
}
Future<void> deletePlaylist(String id) async {
_logQuery('playlists', 'delete', args: {'id': id});
final db = await database;
await db.delete('playlists', where: 'id = ?', whereArgs: [id]);
}
// ════════════════════════════════════════════════════════════
// 播放列表歌曲操作(保持不变
// 播放列表歌曲(带日志
// ════════════════════════════════════════════════════════════
Future<List<Map<String, dynamic>>> getPlaylistSongs(String playlistId) async {
_logQuery('playlist_songs', 'get', args: {'playlist_id': playlistId});
final db = await database;
return await db.query(
'playlist_songs',
@@ -231,6 +313,8 @@ class SongDatabase {
Future<void> addSongToPlaylist(String playlistId, String songId,
{int? orderIndex}) async {
_logQuery('playlist_songs', 'add',
args: {'playlist_id': playlistId, 'song_id': songId});
final db = await database;
int finalOrder = orderIndex ?? 0;
if (orderIndex == null) {
@@ -257,6 +341,8 @@ class SongDatabase {
}
Future<void> removeSongFromPlaylist(String playlistId, String songId) async {
_logQuery('playlist_songs', 'remove',
args: {'playlist_id': playlistId, 'song_id': songId});
final db = await database;
await db.delete(
'playlist_songs',
@@ -266,20 +352,23 @@ class SongDatabase {
}
Future<void> clearPlaylist(String playlistId) async {
_logQuery('playlist_songs', 'clear', args: {'playlist_id': playlistId});
final db = await database;
await db.delete('playlist_songs',
where: 'playlist_id = ?', whereArgs: [playlistId]);
}
// ════════════════════════════════════════════════════════════
// 收藏操作(保持不变
// 收藏(带日志
// ════════════════════════════════════════════════════════════
Future<List<Map<String, dynamic>>> getFavorites() async {
_logQuery('favorites', 'getAll');
final db = await database;
return await db.query('favorites', orderBy: 'favorited_at DESC');
}
Future<bool> isFavorite(String songId) async {
_logQuery('favorites', 'isFavorite', args: {'song_id': songId});
final db = await database;
final result =
await db.query('favorites', where: 'song_id = ?', whereArgs: [songId]);
@@ -287,6 +376,7 @@ class SongDatabase {
}
Future<void> addFavorite(String songId) async {
_logQuery('favorites', 'add', args: {'song_id': songId});
final db = await database;
await db.insert(
'favorites',
@@ -299,6 +389,7 @@ class SongDatabase {
}
Future<void> removeFavorite(String songId) async {
_logQuery('favorites', 'remove', args: {'song_id': songId});
final db = await database;
await db.delete('favorites', where: 'song_id = ?', whereArgs: [songId]);
}
@@ -312,38 +403,46 @@ class SongDatabase {
}
// ════════════════════════════════════════════════════════════
// 原有写入/删除方法(保持不变
// 原有方法(带日志
// ════════════════════════════════════════════════════════════
Future<void> insertSong(Map<String, dynamic> song) async {
_logQuery('songs', 'insert', args: {'title': song['title']});
final db = await database;
await db.insert('songs', song,
conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<void> updateSong(String songKey, Map<String, dynamic> updates) async {
_logQuery('songs', 'update',
args: {'song_key': songKey, 'fields': updates.keys.join(',')});
final db = await database;
await db
.update('songs', updates, where: 'song_key = ?', whereArgs: [songKey]);
}
Future<void> deleteSong(String songKey) async {
_logQuery('songs', 'delete', args: {'song_key': songKey});
final db = await database;
await db.delete('songs', where: 'song_key = ?', whereArgs: [songKey]);
}
Future<void> deleteCache(String songKey) async {
_logQuery('metadata_cache', 'delete', args: {'song_key': songKey});
final db = await database;
await db
.delete('metadata_cache', where: 'song_key = ?', whereArgs: [songKey]);
}
Future<void> insertCache(Map<String, dynamic> cache) async {
_logQuery('metadata_cache', 'insert',
args: {'song_key': cache['song_key']});
final db = await database;
await db.insert('metadata_cache', cache,
conflictAlgorithm: ConflictAlgorithm.replace);
}
Future<Map<String, dynamic>?> getCache(String songKey) async {
_logQuery('metadata_cache', 'get', args: {'song_key': songKey});
final db = await database;
final result = await db
.query('metadata_cache', where: 'song_key = ?', whereArgs: [songKey]);
@@ -351,6 +450,7 @@ class SongDatabase {
}
Future<void> close() async {
_log('🔒 关闭数据库连接');
final db = await database;
await db.close();
_database = null;