This commit is contained in:
Deep Koluguri 2026-04-05 15:58:40 -04:00
parent ca9548bfea
commit 08cf18537b
1 changed files with 66 additions and 0 deletions

View File

@ -100,6 +100,63 @@ async function tableExists(sqlite, name) {
return Array.isArray(rows) && rows.length > 0; return Array.isArray(rows) && rows.length > 0;
} }
function colSetKey(cols) {
return [...cols].sort().join(',');
}
/** Detect old/broken SQLite schemas (e.g. UNIQUE(group_id) only → one row per group). */
async function groupMembersSqliteNeedsRepair(sqlite) {
const list = await sqlite.query(`PRAGMA index_list('group_members')`, { type: QueryTypes.SELECT });
let hasGroupUser = false;
let hasGroupMemberNum = false;
let badGroupIdOnly = false;
for (const row of list) {
const unique = row.unique === 1 || row.unique === true;
if (!unique) continue;
const info = await sqlite.query(`PRAGMA index_info('${String(row.name).replace(/'/g, "''")}')`, {
type: QueryTypes.SELECT,
});
const cols = info
.slice()
.sort((a, b) => (a.seqno ?? 0) - (b.seqno ?? 0))
.map((i) => i.name)
.filter(Boolean);
if (cols.length === 1 && cols[0] === 'group_id') {
badGroupIdOnly = true;
}
if (colSetKey(cols) === 'group_id,user_id') hasGroupUser = true;
if (colSetKey(cols) === 'group_id,member_number') hasGroupMemberNum = true;
}
return badGroupIdOnly || !hasGroupUser || !hasGroupMemberNum;
}
/** Must match `src/models/GroupMember.js` + Sequelize SQLite DDL (table is empty). */
async function recreateGroupMembersTable(sqlite) {
await sqlite.query('DROP TABLE IF EXISTS `group_members`');
await sqlite.query(`
CREATE TABLE \`group_members\` (
\`id\` UUID PRIMARY KEY,
\`group_id\` UUID NOT NULL REFERENCES \`chit_groups\` (\`id\`) ON DELETE CASCADE ON UPDATE CASCADE,
\`user_id\` UUID NOT NULL REFERENCES \`users\` (\`id\`) ON DELETE CASCADE ON UPDATE CASCADE,
\`member_number\` INTEGER NOT NULL,
\`joined_date\` DATETIME NOT NULL,
\`status\` TEXT DEFAULT 'active',
\`total_paid\` DECIMAL(15,2) DEFAULT 0,
\`total_won\` DECIMAL(15,2) DEFAULT 0,
\`created_at\` DATETIME NOT NULL,
\`updated_at\` DATETIME NOT NULL
)
`);
await sqlite.query(
'CREATE UNIQUE INDEX `group_members_group_id_user_id` ON `group_members` (`group_id`, `user_id`)'
);
await sqlite.query(
'CREATE UNIQUE INDEX `group_members_group_id_member_number` ON `group_members` (`group_id`, `member_number`)'
);
}
async function fetchPostgresTable(pg, table) { async function fetchPostgresTable(pg, table) {
try { try {
return await pg.query(`SELECT * FROM "${table}"`, { type: QueryTypes.SELECT }); return await pg.query(`SELECT * FROM "${table}"`, { type: QueryTypes.SELECT });
@ -187,6 +244,15 @@ async function main() {
} }
console.log(' Done.\n'); console.log(' Done.\n');
if (await groupMembersSqliteNeedsRepair(sqlite)) {
console.log(
'🔧 Fixing `group_members` SQLite schema (wrong UNIQUE on `group_id` or missing composite indexes).\n' +
' Recreating empty table to match current Sequelize model…\n'
);
await recreateGroupMembersTable(sqlite);
console.log(' Done.\n');
}
console.log('📥 Copying from PostgreSQL → SQLite…\n'); console.log('📥 Copying from PostgreSQL → SQLite…\n');
for (const table of TABLES_ORDER) { for (const table of TABLES_ORDER) {
const rows = await fetchPostgresTable(pg, table); const rows = await fetchPostgresTable(pg, table);