feat: 添加自动迁移脚本并分离评论的slug和URL字段
- 新增自动数据库迁移脚本,在部署前检查并更新schema - 将post_slug字段拆分为post_slug(仅路径)和post_url(完整URL) - 更新前端widget以仅使用路径作为post_slug - 修改部署脚本以在部署前自动运行迁移
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"name": "cwd-api",
|
"name": "cwd-api",
|
||||||
"version": "0.0.18",
|
"version": "0.0.18",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"deploy": "wrangler deploy",
|
"deploy": "node scripts/auto_migrate.js && wrangler deploy",
|
||||||
"dev": "wrangler dev",
|
"dev": "wrangler dev",
|
||||||
"start": "wrangler dev",
|
"start": "wrangler dev",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
|
|||||||
93
cwd-api/scripts/auto_migrate.js
Normal file
93
cwd-api/scripts/auto_migrate.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
|
function findDatabaseName() {
|
||||||
|
const files = ['wrangler.jsonc', 'wrangler.toml'];
|
||||||
|
const baseDirs = [process.cwd(), path.resolve(__dirname, '..')];
|
||||||
|
for (const base of baseDirs) {
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(base, file);
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const content = fs.readFileSync(filePath, 'utf-8');
|
||||||
|
if (file.endsWith('.jsonc')) {
|
||||||
|
const jsonMatch = content.match(/"database_name"\s*:\s*["'](.*?)["']/);
|
||||||
|
if (jsonMatch) {
|
||||||
|
return jsonMatch[1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const chunks = content.split('[[d1_databases]]');
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
if (chunk.includes('CWD_DB') || chunk.includes('"CWD_DB"')) {
|
||||||
|
const nameMatch = chunk.match(/database_name\s*=\s*["'](.*?)["']/);
|
||||||
|
if (nameMatch) {
|
||||||
|
return nameMatch[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const match = content.match(/database_name\s*=\s*["'](.*?)["']/);
|
||||||
|
if (match) {
|
||||||
|
return match[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 [Auto-Migrate] Detecting D1 database...');
|
||||||
|
const dbName = findDatabaseName();
|
||||||
|
if (!dbName) {
|
||||||
|
console.warn('⚠️ [Auto-Migrate] Could not detect database_name from wrangler config. Skipping.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(`✅ [Auto-Migrate] Found database: ${dbName}`);
|
||||||
|
|
||||||
|
console.log('🔍 [Auto-Migrate] Checking schema status...');
|
||||||
|
try {
|
||||||
|
// Check if post_url column exists
|
||||||
|
const checkCmd = `npx wrangler d1 execute ${dbName} --command "SELECT count(*) as count FROM pragma_table_info('Comment') WHERE name='post_url'" --remote --json`;
|
||||||
|
const output = execSync(checkCmd, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] });
|
||||||
|
|
||||||
|
const result = JSON.parse(output);
|
||||||
|
const count = result[0]?.results?.[0]?.count;
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
console.log('✅ [Auto-Migrate] Schema is up to date.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('⚠️ [Auto-Migrate] Check failed (Database might be new or network error). Skipping migration to be safe.');
|
||||||
|
console.warn(e.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🚀 [Auto-Migrate] Applying migration...');
|
||||||
|
const sql = `
|
||||||
|
ALTER TABLE Comment ADD COLUMN post_url TEXT;
|
||||||
|
UPDATE Comment SET post_url = post_slug;
|
||||||
|
UPDATE Comment
|
||||||
|
SET post_slug = SUBSTR(
|
||||||
|
REPLACE(REPLACE(post_slug, 'https://', ''), 'http://', ''),
|
||||||
|
INSTR(REPLACE(REPLACE(post_slug, 'https://', ''), 'http://', ''), '/')
|
||||||
|
)
|
||||||
|
WHERE post_slug LIKE 'http%' AND INSTR(REPLACE(REPLACE(post_slug, 'https://', ''), 'http://', ''), '/') > 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const flatSql = sql.replace(/\s+/g, ' ').trim();
|
||||||
|
const migrateCmd = `npx wrangler d1 execute ${dbName} --command "${flatSql}" --remote --yes`;
|
||||||
|
|
||||||
|
execSync(migrateCmd, { stdio: 'inherit' });
|
||||||
|
console.log('✅ [Auto-Migrate] Completed successfully.');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ [Auto-Migrate] Failed:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
@@ -159,13 +159,14 @@ export const postComment = async (c: Context<{ Bindings: Bindings }>) => {
|
|||||||
try {
|
try {
|
||||||
const result = await c.env.CWD_DB.prepare(`
|
const result = await c.env.CWD_DB.prepare(`
|
||||||
INSERT INTO Comment (
|
INSERT INTO Comment (
|
||||||
created, post_slug, name, email, url, ip_address,
|
created, post_slug, post_url, name, email, url, ip_address,
|
||||||
os, browser, device, ua, content_text, content_html,
|
os, browser, device, ua, content_text, content_html,
|
||||||
parent_id, status
|
parent_id, status
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`).bind(
|
`).bind(
|
||||||
Date.now(),
|
Date.now(),
|
||||||
post_slug,
|
post_slug,
|
||||||
|
post_url || null,
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
url || null,
|
url || null,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class CWDComments {
|
|||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.config = { ...config };
|
this.config = { ...config };
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
this.config.postSlug = window.location.origin + window.location.pathname;
|
this.config.postSlug = window.location.pathname;
|
||||||
}
|
}
|
||||||
if (typeof document !== 'undefined') {
|
if (typeof document !== 'undefined') {
|
||||||
this.config.postTitle = document.title || this.config.postSlug;
|
this.config.postTitle = document.title || this.config.postSlug;
|
||||||
@@ -572,7 +572,7 @@ export class CWDComments {
|
|||||||
|
|
||||||
Object.assign(this.config, newConfig);
|
Object.assign(this.config, newConfig);
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
this.config.postSlug = window.location.origin + window.location.pathname;
|
this.config.postSlug = window.location.pathname;
|
||||||
}
|
}
|
||||||
if (typeof document !== 'undefined') {
|
if (typeof document !== 'undefined') {
|
||||||
this.config.postTitle = document.title || this.config.postSlug;
|
this.config.postTitle = document.title || this.config.postSlug;
|
||||||
|
|||||||
Reference in New Issue
Block a user