fix: migration error handling for legacy DBs, fallback rejection query

This commit is contained in:
null 2026-06-04 20:52:50 -05:00
parent 910febae63
commit 803e91da28
2 changed files with 33 additions and 15 deletions

View File

@ -2893,12 +2893,18 @@ function runMigrations() {
const { normalizeMerchant } = require('../services/subscriptionService');
// Re-normalize bill_merchant_rules stored under old normalization ("at t" → "att")
let billFixed = 0;
try {
const rules = db.prepare('SELECT id, merchant FROM bill_merchant_rules').all();
const updBill = db.prepare('UPDATE bill_merchant_rules SET merchant=? WHERE id=?');
let billFixed = 0;
for (const r of rules) {
try {
const fixed = normalizeMerchant(r.merchant);
if (fixed !== r.merchant) { updBill.run(fixed, r.id); billFixed++; }
if (fixed && fixed !== r.merchant) { updBill.run(fixed, r.id); billFixed++; }
} catch { /* skip invalid entries */ }
}
} catch (err) {
console.warn('[v0.90] bill_merchant_rules re-normalize skipped:', err.message);
}
// Re-normalize spending_category_rules

View File

@ -119,9 +119,11 @@ function addDateScore(score, reasons, transaction, bill) {
function wordBoundaryIncludes(a, b) {
if (!a || !b) return false;
if (a === b) return true;
try {
const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const wb = s => new RegExp(`(^|\\s)${esc(s)}(\\s|$)`);
return wb(b).test(a) || wb(a).test(b);
} catch { return false; }
}
function addNameScore(score, reasons, transaction, bill) {
@ -224,6 +226,7 @@ function loadBills(db, userId) {
}
function loadRejections(db, userId) {
try {
const rows = db.prepare(`
SELECT transaction_id, bill_id
FROM match_suggestion_rejections
@ -231,6 +234,15 @@ function loadRejections(db, userId) {
AND created_at > datetime('now', '-90 days')
`).all(userId);
return new Set(rows.map(row => suggestionId(row.transaction_id, row.bill_id)));
} catch {
// Fall back to all rejections if created_at column doesn't exist yet
try {
const rows = db.prepare(`
SELECT transaction_id, bill_id FROM match_suggestion_rejections WHERE user_id = ?
`).all(userId);
return new Set(rows.map(row => suggestionId(row.transaction_id, row.bill_id)));
} catch { return new Set(); }
}
}
function loadPriorMatchKeys(db, userId) {