refactor(admin): 提取数据库表创建逻辑为共享函数
重构导出和导入统计数据的 API,将重复的 CREATE TABLE 语句提取为独立的 ensureStatsTables 函数,以消除代码重复并提高可维护性。同时统一代码格式和缩进。
This commit is contained in:
@@ -1,52 +1,39 @@
|
|||||||
import { Context } from 'hono';
|
import { Context } from 'hono';
|
||||||
import { Bindings } from '../../bindings';
|
import { Bindings } from '../../bindings';
|
||||||
|
|
||||||
|
async function ensureStatsTables(env: Bindings) {
|
||||||
|
await env.CWD_DB.prepare(
|
||||||
|
'CREATE TABLE IF NOT EXISTS page_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, post_slug TEXT UNIQUE NOT NULL, post_title TEXT, post_url TEXT, pv INTEGER NOT NULL DEFAULT 0, last_visit_at INTEGER, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)'
|
||||||
|
).run();
|
||||||
|
|
||||||
|
await env.CWD_DB.prepare(
|
||||||
|
'CREATE TABLE IF NOT EXISTS page_visit_daily (id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, domain TEXT, count INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)'
|
||||||
|
).run();
|
||||||
|
|
||||||
|
await env.CWD_DB.prepare(
|
||||||
|
'CREATE TABLE IF NOT EXISTS Likes (id INTEGER PRIMARY KEY AUTOINCREMENT, page_slug TEXT NOT NULL, user_id TEXT NOT NULL, created_at INTEGER NOT NULL, UNIQUE(page_slug, user_id))'
|
||||||
|
).run();
|
||||||
|
}
|
||||||
|
|
||||||
export const getStatsData = async (env: Bindings) => {
|
export const getStatsData = async (env: Bindings) => {
|
||||||
// Ensure tables exist
|
await ensureStatsTables(env);
|
||||||
await env.CWD_DB.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS page_stats (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
post_slug TEXT UNIQUE NOT NULL,
|
|
||||||
post_title TEXT,
|
|
||||||
post_url TEXT,
|
|
||||||
pv INTEGER NOT NULL DEFAULT 0,
|
|
||||||
last_visit_at INTEGER,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS page_visit_daily (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
date TEXT NOT NULL,
|
|
||||||
domain TEXT,
|
|
||||||
count INTEGER NOT NULL DEFAULT 0,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS Likes (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
page_slug TEXT NOT NULL,
|
|
||||||
user_id TEXT NOT NULL,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
UNIQUE(page_slug, user_id)
|
|
||||||
);
|
|
||||||
`);
|
|
||||||
|
|
||||||
const { results: pageStats } = await env.CWD_DB.prepare('SELECT * FROM page_stats').all();
|
const { results: pageStats } = await env.CWD_DB.prepare('SELECT * FROM page_stats').all();
|
||||||
const { results: dailyVisits } = await env.CWD_DB.prepare('SELECT * FROM page_visit_daily').all();
|
const { results: dailyVisits } = await env.CWD_DB.prepare('SELECT * FROM page_visit_daily').all();
|
||||||
const { results: likes } = await env.CWD_DB.prepare('SELECT * FROM Likes').all();
|
const { results: likes } = await env.CWD_DB.prepare('SELECT * FROM Likes').all();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
page_stats: pageStats,
|
page_stats: pageStats,
|
||||||
page_visit_daily: dailyVisits,
|
page_visit_daily: dailyVisits,
|
||||||
likes: likes
|
likes: likes
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const exportStats = async (c: Context<{ Bindings: Bindings }>) => {
|
export const exportStats = async (c: Context<{ Bindings: Bindings }>) => {
|
||||||
try {
|
try {
|
||||||
const data = await getStatsData(c.env);
|
const data = await getStatsData(c.env);
|
||||||
return c.json(data);
|
return c.json(data);
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return c.json({ message: e.message || '导出统计数据失败' }, 500);
|
return c.json({ message: e.message || '导出统计数据失败' }, 500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,125 +1,115 @@
|
|||||||
import { Context } from 'hono';
|
import { Context } from 'hono';
|
||||||
import { Bindings } from '../../bindings';
|
import { Bindings } from '../../bindings';
|
||||||
|
|
||||||
|
async function ensureStatsTables(env: Bindings) {
|
||||||
|
await env.CWD_DB.prepare(
|
||||||
|
'CREATE TABLE IF NOT EXISTS page_stats (id INTEGER PRIMARY KEY AUTOINCREMENT, post_slug TEXT UNIQUE NOT NULL, post_title TEXT, post_url TEXT, pv INTEGER NOT NULL DEFAULT 0, last_visit_at INTEGER, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)'
|
||||||
|
).run();
|
||||||
|
|
||||||
|
await env.CWD_DB.prepare(
|
||||||
|
'CREATE TABLE IF NOT EXISTS page_visit_daily (id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, domain TEXT, count INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)'
|
||||||
|
).run();
|
||||||
|
|
||||||
|
await env.CWD_DB.prepare(
|
||||||
|
'CREATE TABLE IF NOT EXISTS Likes (id INTEGER PRIMARY KEY AUTOINCREMENT, page_slug TEXT NOT NULL, user_id TEXT NOT NULL, created_at INTEGER NOT NULL, UNIQUE(page_slug, user_id))'
|
||||||
|
).run();
|
||||||
|
}
|
||||||
|
|
||||||
export const saveStatsData = async (env: Bindings, data: any) => {
|
export const saveStatsData = async (env: Bindings, data: any) => {
|
||||||
// Ensure tables exist
|
await ensureStatsTables(env);
|
||||||
await env.CWD_DB.exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS page_stats (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
post_slug TEXT UNIQUE NOT NULL,
|
|
||||||
post_title TEXT,
|
|
||||||
post_url TEXT,
|
|
||||||
pv INTEGER NOT NULL DEFAULT 0,
|
|
||||||
last_visit_at INTEGER,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS page_visit_daily (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
date TEXT NOT NULL,
|
|
||||||
domain TEXT,
|
|
||||||
count INTEGER NOT NULL DEFAULT 0,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
updated_at INTEGER NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS Likes (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
page_slug TEXT NOT NULL,
|
|
||||||
user_id TEXT NOT NULL,
|
|
||||||
created_at INTEGER NOT NULL,
|
|
||||||
UNIQUE(page_slug, user_id)
|
|
||||||
);
|
|
||||||
`);
|
|
||||||
|
|
||||||
const stmts: any[] = [];
|
const stmts: any[] = [];
|
||||||
|
|
||||||
// 1. page_stats
|
if (Array.isArray(data.page_stats)) {
|
||||||
if (Array.isArray(data.page_stats)) {
|
for (const item of data.page_stats) {
|
||||||
for (const item of data.page_stats) {
|
const fields = [
|
||||||
const fields = ['post_slug', 'post_title', 'post_url', 'pv', 'last_visit_at', 'created_at', 'updated_at'];
|
'post_slug',
|
||||||
const values = [
|
'post_title',
|
||||||
item.post_slug,
|
'post_url',
|
||||||
item.post_title,
|
'pv',
|
||||||
item.post_url,
|
'last_visit_at',
|
||||||
item.pv,
|
'created_at',
|
||||||
item.last_visit_at,
|
'updated_at'
|
||||||
item.created_at,
|
];
|
||||||
item.updated_at
|
const values = [
|
||||||
];
|
item.post_slug,
|
||||||
if (item.id) {
|
item.post_title,
|
||||||
fields.unshift('id');
|
item.post_url,
|
||||||
values.unshift(item.id);
|
item.pv,
|
||||||
}
|
item.last_visit_at,
|
||||||
const placeholders = fields.map(() => '?').join(', ');
|
item.created_at,
|
||||||
stmts.push(
|
item.updated_at
|
||||||
env.CWD_DB.prepare(`INSERT OR REPLACE INTO page_stats (${fields.join(', ')}) VALUES (${placeholders})`).bind(...values)
|
];
|
||||||
);
|
if (item.id) {
|
||||||
}
|
fields.unshift('id');
|
||||||
}
|
values.unshift(item.id);
|
||||||
|
}
|
||||||
|
const placeholders = fields.map(() => '?').join(', ');
|
||||||
|
stmts.push(
|
||||||
|
env.CWD_DB.prepare(
|
||||||
|
`INSERT OR REPLACE INTO page_stats (${fields.join(', ')}) VALUES (${placeholders})`
|
||||||
|
).bind(...values)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2. page_visit_daily
|
if (Array.isArray(data.page_visit_daily)) {
|
||||||
if (Array.isArray(data.page_visit_daily)) {
|
for (const item of data.page_visit_daily) {
|
||||||
for (const item of data.page_visit_daily) {
|
const fields = ['date', 'domain', 'count', 'created_at', 'updated_at'];
|
||||||
const fields = ['date', 'domain', 'count', 'created_at', 'updated_at'];
|
const values = [item.date, item.domain, item.count, item.created_at, item.updated_at];
|
||||||
const values = [
|
if (item.id) {
|
||||||
item.date,
|
fields.unshift('id');
|
||||||
item.domain,
|
values.unshift(item.id);
|
||||||
item.count,
|
}
|
||||||
item.created_at,
|
const placeholders = fields.map(() => '?').join(', ');
|
||||||
item.updated_at
|
stmts.push(
|
||||||
];
|
env.CWD_DB.prepare(
|
||||||
if (item.id) {
|
`INSERT OR REPLACE INTO page_visit_daily (${fields.join(', ')}) VALUES (${placeholders})`
|
||||||
fields.unshift('id');
|
).bind(...values)
|
||||||
values.unshift(item.id);
|
);
|
||||||
}
|
}
|
||||||
const placeholders = fields.map(() => '?').join(', ');
|
}
|
||||||
stmts.push(
|
|
||||||
env.CWD_DB.prepare(`INSERT OR REPLACE INTO page_visit_daily (${fields.join(', ')}) VALUES (${placeholders})`).bind(...values)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Likes
|
if (Array.isArray(data.likes)) {
|
||||||
if (Array.isArray(data.likes)) {
|
for (const item of data.likes) {
|
||||||
for (const item of data.likes) {
|
const fields = ['page_slug', 'user_id', 'created_at'];
|
||||||
const fields = ['page_slug', 'user_id', 'created_at'];
|
const values = [item.page_slug, item.user_id, item.created_at];
|
||||||
const values = [
|
if (item.id) {
|
||||||
item.page_slug,
|
fields.unshift('id');
|
||||||
item.user_id,
|
values.unshift(item.id);
|
||||||
item.created_at
|
}
|
||||||
];
|
const placeholders = fields.map(() => '?').join(', ');
|
||||||
if (item.id) {
|
stmts.push(
|
||||||
fields.unshift('id');
|
env.CWD_DB.prepare(
|
||||||
values.unshift(item.id);
|
`INSERT OR REPLACE INTO Likes (${fields.join(', ')}) VALUES (${placeholders})`
|
||||||
}
|
).bind(...values)
|
||||||
const placeholders = fields.map(() => '?').join(', ');
|
);
|
||||||
stmts.push(
|
}
|
||||||
env.CWD_DB.prepare(`INSERT OR REPLACE INTO Likes (${fields.join(', ')}) VALUES (${placeholders})`).bind(...values)
|
}
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Batch execute
|
const BATCH_SIZE = 50;
|
||||||
const BATCH_SIZE = 50;
|
for (let i = 0; i < stmts.length; i += BATCH_SIZE) {
|
||||||
for (let i = 0; i < stmts.length; i += BATCH_SIZE) {
|
const batch = stmts.slice(i, i + BATCH_SIZE);
|
||||||
const batch = stmts.slice(i, i + BATCH_SIZE);
|
await env.CWD_DB.batch(batch);
|
||||||
await env.CWD_DB.batch(batch);
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const importStats = async (c: Context<{ Bindings: Bindings }>) => {
|
export const importStats = async (c: Context<{ Bindings: Bindings }>) => {
|
||||||
try {
|
try {
|
||||||
const body = await c.req.json();
|
const body = await c.req.json();
|
||||||
if (!body || typeof body !== 'object') {
|
if (!body || typeof body !== 'object') {
|
||||||
return c.json({ message: '数据格式错误' }, 400);
|
return c.json({ message: '数据格式错误' }, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
await saveStatsData(c.env, body);
|
await saveStatsData(c.env, body);
|
||||||
|
|
||||||
const statsCount = (body.page_stats?.length || 0) + (body.page_visit_daily?.length || 0) + (body.likes?.length || 0);
|
const statsCount =
|
||||||
return c.json({ message: `成功导入 ${statsCount} 条统计数据` });
|
(body.page_stats?.length || 0) +
|
||||||
} catch (e: any) {
|
(body.page_visit_daily?.length || 0) +
|
||||||
console.error(e);
|
(body.likes?.length || 0);
|
||||||
return c.json({ message: e.message || '导入统计数据失败' }, 500);
|
return c.json({ message: `成功导入 ${statsCount} 条统计数据` });
|
||||||
}
|
} catch (e: any) {
|
||||||
|
console.error(e);
|
||||||
|
return c.json({ message: e.message || '导入统计数据失败' }, 500);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user