87 lines
3.0 KiB
JavaScript
87 lines
3.0 KiB
JavaScript
/**
|
||
* 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();
|