Files
vps-management-bot/aff-monitor/db/migrate-004-pid-slug.js

87 lines
3.0 KiB
JavaScript
Raw Normal View History

2026-03-21 01:10:53 +08:00
/**
* Migration 004 PID & Slug 字段
*
* - internal_pid: 系统内部编号 VPS-000001唯一自动生成
* - provider_pid: 商家产品 ID从购买链接自动解析 pid=28
* - slug: 前台友好 URL唯一
*/
const Database = require('better-sqlite3');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const dbPath = path.resolve(__dirname, '..', process.env.DB_PATH || 'db/monitor.sqlite');
const db = new Database(dbPath);
db.pragma('journal_mode = WAL');
function ensureColumn(table, column, sql) {
const cols = db.prepare(`PRAGMA table_info(${table})`).all().map(c => c.name);
if (!cols.includes(column)) {
db.exec(`ALTER TABLE ${table} ADD COLUMN ${sql}`);
console.log(`+ ${table}.${column}`);
} else {
console.log(` ${table}.${column} (already exists)`);
}
}
// 添加新字段
ensureColumn('products', 'internal_pid', 'internal_pid TEXT');
ensureColumn('products', 'provider_pid', 'provider_pid TEXT');
ensureColumn('products', 'slug', 'slug TEXT');
// 创建唯一索引(如果尚不存在)
try {
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_products_internal_pid ON products(internal_pid) WHERE internal_pid IS NOT NULL');
console.log('+ index: idx_products_internal_pid');
} catch (e) {
console.log(' index idx_products_internal_pid:', e.message);
}
try {
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_products_slug ON products(slug) WHERE slug IS NOT NULL');
console.log('+ index: idx_products_slug');
} catch (e) {
console.log(' index idx_products_slug:', e.message);
}
// 为已有产品回填 internal_pid 和 slug
const { generateInternalPid, generateSlug, parseProviderPid } = require('../src/utils/pidHelper');
const products = db.prepare('SELECT id, name, merchant_id, url, buy_url, internal_pid, slug, provider_pid FROM products').all();
const updateStmt = db.prepare('UPDATE products SET internal_pid = ?, slug = ?, provider_pid = ? WHERE id = ?');
const getMerchantName = db.prepare('SELECT name FROM merchants WHERE id = ?');
const existingSlugs = new Set(
db.prepare("SELECT slug FROM products WHERE slug IS NOT NULL AND slug != ''").all().map(r => r.slug)
);
db.transaction(() => {
for (const p of products) {
let ipid = p.internal_pid;
let slug = p.slug;
let ppid = p.provider_pid;
// 生成 internal_pid
if (!ipid) {
ipid = generateInternalPid(db);
}
// 生成 slug
if (!slug) {
const merchant = getMerchantName.get(p.merchant_id);
const merchantName = merchant ? merchant.name : '';
slug = generateSlug(p.name, merchantName, existingSlugs);
existingSlugs.add(slug);
}
// 解析 provider_pid
if (!ppid) {
ppid = parseProviderPid(p.buy_url) || parseProviderPid(p.url) || null;
}
updateStmt.run(ipid, slug, ppid, p.id);
console.log(` product #${p.id}: internal_pid=${ipid}, slug=${slug}, provider_pid=${ppid || '(none)'}`);
}
})();
console.log('✅ migration-004 done:', dbPath);
db.close();