fix: init sql

This commit is contained in:
shinya
2025-07-14 10:30:14 +08:00
parent 8afbc0e0af
commit dee31005e7
2 changed files with 90 additions and 80 deletions

View File

@@ -37,83 +37,6 @@ interface D1ExecResult {
duration: number;
}
// 数据库初始化 SQL
const INIT_SQL = `
CREATE TABLE IF NOT EXISTS users (
username TEXT PRIMARY KEY,
password TEXT NOT NULL,
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
);
CREATE TABLE IF NOT EXISTS play_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
key TEXT NOT NULL,
title TEXT NOT NULL,
source_name TEXT NOT NULL,
cover TEXT NOT NULL,
year TEXT NOT NULL,
index_episode INTEGER NOT NULL,
total_episodes INTEGER NOT NULL,
play_time INTEGER NOT NULL,
total_time INTEGER NOT NULL,
save_time INTEGER NOT NULL,
search_title TEXT,
UNIQUE(username, key)
);
CREATE TABLE IF NOT EXISTS favorites (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
key TEXT NOT NULL,
title TEXT NOT NULL,
source_name TEXT NOT NULL,
cover TEXT NOT NULL,
year TEXT NOT NULL,
total_episodes INTEGER NOT NULL,
save_time INTEGER NOT NULL,
UNIQUE(username, key)
);
CREATE TABLE IF NOT EXISTS search_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
keyword TEXT NOT NULL,
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
UNIQUE(username, keyword)
);
CREATE TABLE IF NOT EXISTS admin_config (
id INTEGER PRIMARY KEY DEFAULT 1,
config TEXT NOT NULL,
updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
);
-- 基本索引
CREATE INDEX IF NOT EXISTS idx_play_records_username ON play_records(username);
CREATE INDEX IF NOT EXISTS idx_favorites_username ON favorites(username);
CREATE INDEX IF NOT EXISTS idx_search_history_username ON search_history(username);
-- 复合索引优化查询性能
-- 播放记录:用户名+键值的复合索引,用于快速查找特定记录
CREATE INDEX IF NOT EXISTS idx_play_records_username_key ON play_records(username, key);
-- 播放记录:用户名+保存时间的复合索引,用于按时间排序的查询
CREATE INDEX IF NOT EXISTS idx_play_records_username_save_time ON play_records(username, save_time DESC);
-- 收藏:用户名+键值的复合索引,用于快速查找特定收藏
CREATE INDEX IF NOT EXISTS idx_favorites_username_key ON favorites(username, key);
-- 收藏:用户名+保存时间的复合索引,用于按时间排序的查询
CREATE INDEX IF NOT EXISTS idx_favorites_username_save_time ON favorites(username, save_time DESC);
-- 搜索历史:用户名+关键词的复合索引,用于快速查找/删除特定搜索记录
CREATE INDEX IF NOT EXISTS idx_search_history_username_keyword ON search_history(username, keyword);
-- 搜索历史:用户名+创建时间的复合索引,用于按时间排序的查询
CREATE INDEX IF NOT EXISTS idx_search_history_username_created_at ON search_history(username, created_at DESC);
-- 搜索历史清理查询的优化索引
CREATE INDEX IF NOT EXISTS idx_search_history_username_id_created_at ON search_history(username, id, created_at DESC);
`;
// 获取全局D1数据库实例
function getD1Database(): D1Database {
return (process.env as any).DB as D1Database;
@@ -136,9 +59,96 @@ export class D1Storage implements IStorage {
private async initDatabase() {
try {
if (this.db) {
await this.db.exec(INIT_SQL);
if (!this.db) {
throw new Error('D1 database instance not available');
}
console.log('Executing D1 database initialization SQL...');
// 将初始化SQL分解为单独的语句
const statements = [
`CREATE TABLE IF NOT EXISTS users (
username TEXT PRIMARY KEY,
password TEXT NOT NULL,
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
)`,
`CREATE TABLE IF NOT EXISTS play_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
key TEXT NOT NULL,
title TEXT NOT NULL,
source_name TEXT NOT NULL,
cover TEXT NOT NULL,
year TEXT NOT NULL,
index_episode INTEGER NOT NULL,
total_episodes INTEGER NOT NULL,
play_time INTEGER NOT NULL,
total_time INTEGER NOT NULL,
save_time INTEGER NOT NULL,
search_title TEXT,
UNIQUE(username, key)
)`,
`CREATE TABLE IF NOT EXISTS favorites (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
key TEXT NOT NULL,
title TEXT NOT NULL,
source_name TEXT NOT NULL,
cover TEXT NOT NULL,
year TEXT NOT NULL,
total_episodes INTEGER NOT NULL,
save_time INTEGER NOT NULL,
UNIQUE(username, key)
)`,
`CREATE TABLE IF NOT EXISTS search_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
keyword TEXT NOT NULL,
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
UNIQUE(username, keyword)
)`,
`CREATE TABLE IF NOT EXISTS admin_config (
id INTEGER PRIMARY KEY DEFAULT 1,
config TEXT NOT NULL,
updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
)`,
// 基本索引
`CREATE INDEX IF NOT EXISTS idx_play_records_username ON play_records(username)`,
`CREATE INDEX IF NOT EXISTS idx_favorites_username ON favorites(username)`,
`CREATE INDEX IF NOT EXISTS idx_search_history_username ON search_history(username)`,
// 复合索引
`CREATE INDEX IF NOT EXISTS idx_play_records_username_key ON play_records(username, key)`,
`CREATE INDEX IF NOT EXISTS idx_play_records_username_save_time ON play_records(username, save_time DESC)`,
`CREATE INDEX IF NOT EXISTS idx_favorites_username_key ON favorites(username, key)`,
`CREATE INDEX IF NOT EXISTS idx_favorites_username_save_time ON favorites(username, save_time DESC)`,
`CREATE INDEX IF NOT EXISTS idx_search_history_username_keyword ON search_history(username, keyword)`,
`CREATE INDEX IF NOT EXISTS idx_search_history_username_created_at ON search_history(username, created_at DESC)`,
`CREATE INDEX IF NOT EXISTS idx_search_history_username_id_created_at ON search_history(username, id, created_at DESC)`,
];
// 逐个执行每个SQL语句
for (let i = 0; i < statements.length; i++) {
const statement = statements[i];
try {
console.log(
`Executing SQL statement ${i + 1}/${statements.length}:`,
statement.substring(0, 50) + '...'
);
await this.db.prepare(statement).run();
} catch (err) {
console.error(`Failed to execute statement ${i + 1}:`, statement);
console.error('Error:', err);
throw err;
}
}
console.log('D1 database initialization completed successfully');
} catch (err) {
console.error('Failed to initialize D1 database:', err);
throw err;

View File

@@ -128,6 +128,6 @@ function shouldSkipAuth(pathname: string): boolean {
// 配置middleware匹配规则
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|api/detail|api/search|api/image-proxy|api/douban).*)',
'/((?!_next/static|_next/image|favicon.ico|api/detail|api/search|api/image-proxy|api/douban|api/cron|api/server-config).*)',
],
};