import {test} from 'node:test'; import assert from 'node:assert/strict'; import {readFileSync} from 'node:fs'; import {PGlite} from '@electric-sql/pglite'; test('read recovery preserves corrected receipts, tenant fields and function results; rerun is safe',async()=>{ const db=new PGlite();try{ const rewards=readFileSync(new URL('../sql/review-rewards.sql',import.meta.url),'utf8'); const table=name=>rewards.match(new RegExp('CREATE TABLE IF NOT EXISTS "'+name+'" \\([^]*?\\n\\);'))[0]; await db.exec(table('ReviewReward')+`;ALTER TABLE "ReviewReward" ADD COLUMN "ineligibleReason" text NOT NULL DEFAULT '';`); await db.exec(table('ReviewRewardCorrection')); await db.exec(`CREATE FUNCTION xs_payroll_sources(text) RETURNS SETOF jsonb LANGUAGE sql STABLE AS $$ SELECT '{"amount":1}'::jsonb $$; CREATE FUNCTION xs_payroll_source_version(text) RETURNS text LANGUAGE sql STABLE AS $$ SELECT 'unchanged'::text $$; CREATE FUNCTION xs_payroll_cutoff_snapshot(text,text) RETURNS jsonb LANGUAGE sql STABLE AS $$ SELECT '{"approved":false}'::jsonb $$; INSERT INTO "ReviewReward" ("objectId",company,"taskId","coachId","completedAt","incomeMonth",status,amount,"ineligibleReason") VALUES ('earned','a','t1',1,now(),'2026-10','earned',1,''),('corrected','a','t2',1,now(),'2026-10','earned',1,''), ('overdue','a','t3',1,now(),'2026-09','ineligible',0,'overdue'),('other','b','t4',2,now(),'2026-10','earned',1,''); INSERT INTO "ReviewRewardCorrection" ("objectId",company,"rewardId",amount,reason,actor) VALUES ('fix','a','corrected',-1,'核对逾期','admin'); CREATE VIEW "ReviewRewardIncome" AS SELECT projected.*,r.amount AS "originalAmount",c."objectId" AS "correctionId",c.reason AS "correctionReason",c.amount AS "correctionAmount",c."adjustmentBatchId" FROM "ReviewReward" r LEFT JOIN "ReviewRewardCorrection" c ON c.company=r.company AND c."rewardId"=r."objectId" CROSS JOIN LATERAL jsonb_populate_record(NULL::"ReviewReward",to_jsonb(r)||jsonb_build_object('amount',r.amount+COALESCE(c.amount,0),'status',CASE WHEN c."objectId" IS NULL THEN r.status ELSE 'ineligible' END,'ineligibleReason',CASE WHEN c."objectId" IS NULL THEN r."ineligibleReason" ELSE 'corrected_overdue' END)) projected;`); const sql='SELECT * FROM "ReviewRewardIncome" ORDER BY "objectId"',before=(await db.query(sql)).rows; const patch=readFileSync(new URL('../sql/payroll-read-timeout-recovery.sql',import.meta.url),'utf8'); for(let i=0;i<2;i++){ await db.exec(patch);assert.deepEqual((await db.query(sql)).rows,before); assert.equal((await db.query("SELECT xs_payroll_source_version('a') v")).rows[0].v,'unchanged'); assert.deepEqual((await db.query('SELECT "objectId" FROM "ReviewRewardIncome" WHERE company=$1 AND "incomeMonth"=$2 AND status=\'earned\'',['a','2026-10'])).rows,[{objectId:'earned'}]); const functions=(await db.query("SELECT proconfig FROM pg_proc WHERE proname IN ('xs_payroll_sources','xs_payroll_source_version','xs_payroll_cutoff_snapshot')")).rows; assert.equal(functions.length,3);assert.ok(functions.every(f=>f.proconfig.includes('jit=off'))); } }finally{await db.close();} });