@@ -2,6 +2,7 @@ import { createClient } from "@clickhouse/client";
22import { PostgreSqlContainer , StartedPostgreSqlContainer } from "@testcontainers/postgresql" ;
33import { RedisContainer , StartedRedisContainer } from "@testcontainers/redis" ;
44import { tryCatch } from "@trigger.dev/core" ;
5+ import { PrismaClient } from "@trigger.dev/database" ;
56import Redis from "ioredis" ;
67import path from "path" ;
78import { isDebug } from "std-env" ;
@@ -48,9 +49,50 @@ export async function pushDatabaseSchema(databaseUrl: string) {
4849 }
4950 ) ;
5051
52+ await dropRunForeignKeys ( databaseUrl ) ;
53+
5154 return result ;
5255}
5356
57+ /**
58+ * Production drops every foreign key that sits on, or points at, the run tables (`TaskRun` and
59+ * `task_run_v2`) — a run's id is just a scalar that may live in either physical table, so the FKs
60+ * can't be enforced. `prisma db push` doesn't know that: it recreates a constraint for every
61+ * relation still declared in schema.prisma, so the template DB ends up with run FKs production
62+ * doesn't have. That makes tests diverge — e.g. inserting a child row (a `TaskRunExecutionSnapshot`
63+ * whose `runId` is a `task_run_v2` id) trips a `..._runId_fkey -> TaskRun` constraint that doesn't
64+ * exist in prod. So after the push we strip those FKs to match production exactly.
65+ *
66+ * This is done dynamically (rather than naming each constraint) so any relation added to the schema
67+ * later has its test-only run FK stripped automatically. It only removes FK constraints, so it
68+ * cannot corrupt valid data — it makes the template DB strictly more faithful to production.
69+ */
70+ async function dropRunForeignKeys ( databaseUrl : string ) {
71+ const prisma = new PrismaClient ( {
72+ datasources : { db : { url : databaseUrl } } ,
73+ } ) ;
74+
75+ try {
76+ await prisma . $executeRawUnsafe ( `
77+ DO $$
78+ DECLARE r record;
79+ BEGIN
80+ FOR r IN
81+ SELECT conrelid::regclass::text AS tbl, conname
82+ FROM pg_constraint
83+ WHERE contype = 'f'
84+ AND (confrelid IN ('"TaskRun"'::regclass, 'task_run_v2'::regclass)
85+ OR conrelid IN ('"TaskRun"'::regclass, 'task_run_v2'::regclass))
86+ LOOP
87+ EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %I', r.tbl, r.conname);
88+ END LOOP;
89+ END $$;
90+ ` ) ;
91+ } finally {
92+ await prisma . $disconnect ( ) ;
93+ }
94+ }
95+
5496/**
5597 * Caps each container's CPU/memory to approximate the 2-core CI runner locally (for timing + flake
5698 * reproduction). Set TESTCONTAINERS_CPU (cores per container, e.g. "2") and/or
0 commit comments