import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); async function main() { const projectId = process.argv[2]; if (!projectId) { throw new Error('Usage: npx tsx scripts/analyze_missing_equery_context.ts '); } const reasonStats = await prisma.$queryRawUnsafe>(` WITH missing AS ( SELECT e.id, e.record_id, e.category, e.field_name, e.event_id, e.form_name, e.created_at FROM iit_schema.equery e WHERE e.project_id = $1 AND (COALESCE(e.event_id, '') = '' OR COALESCE(e.form_name, '') = '') ), flags AS ( SELECT m.*, EXISTS ( SELECT 1 FROM iit_schema.qc_field_status fs WHERE fs.project_id = $1 AND fs.record_id = m.record_id ) AS has_record_match, EXISTS ( SELECT 1 FROM iit_schema.qc_field_status fs WHERE fs.project_id = $1 AND fs.record_id = m.record_id AND COALESCE(fs.rule_name, '') = COALESCE(m.category, '') ) AS has_rule_match, EXISTS ( SELECT 1 FROM iit_schema.qc_field_status fs WHERE fs.project_id = $1 AND fs.record_id = m.record_id AND COALESCE(fs.rule_name, '') = COALESCE(m.category, '') AND COALESCE(fs.field_name, '') = COALESCE(m.field_name, '') ) AS has_rule_field_match FROM missing m ) SELECT CASE WHEN has_rule_field_match THEN 'A_RULE_FIELD_MATCH_BUT_EVENT_FORM_EMPTY' WHEN has_rule_match THEN 'B_RULE_MATCH_FIELD_MISMATCH' WHEN has_record_match THEN 'C_RECORD_MATCH_ONLY' ELSE 'D_NO_RECORD_MATCH' END AS reason, COUNT(*)::bigint AS cnt FROM flags GROUP BY 1 ORDER BY 2 DESC `, projectId); const sample = await prisma.$queryRawUnsafe>(` SELECT id, record_id, category, field_name, event_id, form_name, created_at FROM iit_schema.equery WHERE project_id = $1 AND (COALESCE(event_id, '') = '' OR COALESCE(form_name, '') = '') ORDER BY created_at DESC LIMIT 20 `, projectId); console.log(JSON.stringify({ projectId, reasonStats: reasonStats.map((r) => ({ reason: r.reason, cnt: Number(r.cnt) })), sample, }, null, 2)); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });