import { decryptText } from '../../src/crypto.js'; import type { AppConfig } from '../../src/config.js'; import type pg from 'pg'; // Stateful test database; scope, unique keys, orphan joins and backfill are all exercised. export function progressMemory(config: AppConfig) { const owners = new Map(); const records: Record[] = [], tasks: Record[] = []; const answer = (rows: Record[] = []) => ({ rowCount: rows.length, rows }); const query = async (sql: string, p: any[] = []) => { const owner = `${p[0]}/${p[1]}`, scoped = records.filter(r => r.organization_id === p[0] && r.owner_user_id === p[1]); if (sql.includes('INSERT INTO team_progress_owners')) { if (!owners.has(owner)) owners.set(owner,false); return answer(); } if (sql.includes('SELECT backfilled_at FROM team_progress_owners')) return answer([{backfilled_at:owners.get(owner)?'done':null}]); if (sql.includes('UPDATE team_progress_owners')) { owners.set(owner,true); return answer(); } if (sql.includes('FROM tasks t JOIN task_attempts') && sql.includes('COALESCE')) return answer(tasks.filter(t => t.organization_id === p[0] && t.assigned_user_id === p[1] && ['completed','blocked','failed','reconciliation_pending'].includes(t.status) && t.task_id > p[2] && t.execution_id === t.execution_result.execution_id).sort((a,b) => a.task_id.localeCompare(b.task_id)).slice(0,200)); if (sql.includes('INSERT INTO team_progress_events')) { if (!scoped.some(r => r.execution_id === p[7] && r.event_key === p[5])) records.push({organization_id:p[0],owner_user_id:p[1],group_key:p[2],subject_key:p[3], subject_kind:p[4],event_key:p[5],source_task_id:p[6],execution_id:p[7],effective_at:p[8],recorded_at:p[9],detail_ciphertext:p[10],source_task_deleted_at:null}); return answer(); } if (sql.includes('SELECT detail_ciphertext FROM team_progress_events')) return answer(scoped.filter(r => r.subject_key === p[2] && r.subject_kind === 'child' && r.group_key)); if (sql.includes('SELECT e.detail_ciphertext')) return answer(scoped.filter(r => r.group_key === p[2] || (!r.group_key && r.subject_kind === 'child' && scoped.some(link => link.subject_key === r.subject_key && link.group_key === p[2]) && !scoped.some(link => link.subject_key === r.subject_key && link.group_key && link.group_key !== p[2])))); if (sql.includes('UPDATE team_progress_events')) { scoped.filter(r => p[2].includes(r.source_task_id)).forEach(r => r.source_task_deleted_at = new Date()); return answer(); } throw new Error(`Unexpected progress SQL: ${sql}`); }; return {query: query as unknown as pg.PoolClient['query'],records,tasks,owners,decode:() => records.map(r => JSON.parse(decryptText(config,r.detail_ciphertext)))}; }