Skip to content

Commit 13d5364

Browse files
committed
feat(run-store): add full-row read overload to the run store
Add a no-args overload to findRun, findRunOrThrow and findRuns that returns the whole TaskRun row, for callers that read a run without a select or include.
1 parent c5226a2 commit 13d5364

3 files changed

Lines changed: 159 additions & 4 deletions

File tree

internal-packages/run-store/src/PostgresRunStore.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,4 +1683,92 @@ describe("PostgresRunStore — read", () => {
16831683
expect(run?.id).toBe(runId);
16841684
expect(run?.status).toBe("PENDING");
16851685
});
1686+
1687+
postgresTest("findRun by id with no projection returns the whole row", async ({ prisma }) => {
1688+
const { organization, project, environment } = await seedEnvironment(prisma);
1689+
1690+
const store = new PostgresRunStore({ prisma, readOnlyPrisma: prisma });
1691+
const runId = "run_find_full_row_1";
1692+
1693+
await store.createRun(
1694+
buildCreateRunInput({
1695+
runId,
1696+
organizationId: organization.id,
1697+
projectId: project.id,
1698+
runtimeEnvironmentId: environment.id,
1699+
})
1700+
);
1701+
1702+
const run = await store.findRun({ id: runId });
1703+
1704+
expect(run?.id).toBe(runId);
1705+
expect(run?.friendlyId).toBe("run_friendly_1");
1706+
expect(run?.status).toBe("PENDING");
1707+
expect(run?.taskIdentifier).toBe("my-task");
1708+
// The whole-row variant returns the full scalar set, not a projection.
1709+
expect(run?.payload).toBe("{}");
1710+
expect(run?.payloadType).toBe("application/json");
1711+
});
1712+
1713+
postgresTest("findRunOrThrow with no projection throws when no row matches", async ({ prisma }) => {
1714+
await seedEnvironment(prisma);
1715+
1716+
const store = new PostgresRunStore({ prisma, readOnlyPrisma: prisma });
1717+
1718+
await expect(store.findRunOrThrow({ id: "missing" })).rejects.toThrow();
1719+
});
1720+
1721+
postgresTest("findRuns with no projection returns whole rows", async ({ prisma }) => {
1722+
const { organization, project, environment } = await seedEnvironment(prisma);
1723+
1724+
const store = new PostgresRunStore({ prisma, readOnlyPrisma: prisma });
1725+
1726+
const earliest = new Date("2026-07-01T00:00:00.000Z");
1727+
const latest = new Date("2026-07-02T00:00:00.000Z");
1728+
1729+
const rows: Array<{ id: string; createdAt: Date }> = [
1730+
{ id: "run_find_full_many_earliest", createdAt: earliest },
1731+
{ id: "run_find_full_many_latest", createdAt: latest },
1732+
];
1733+
1734+
for (const row of rows) {
1735+
await prisma.taskRun.create({
1736+
data: {
1737+
id: row.id,
1738+
engine: "V2",
1739+
status: "PENDING",
1740+
friendlyId: `${row.id}_friendly`,
1741+
runtimeEnvironmentId: environment.id,
1742+
environmentType: "DEVELOPMENT",
1743+
organizationId: organization.id,
1744+
projectId: project.id,
1745+
taskIdentifier: "my-task",
1746+
payload: "{}",
1747+
payloadType: "application/json",
1748+
traceContext: {},
1749+
traceId: `trace_${row.id}`,
1750+
spanId: `span_${row.id}`,
1751+
queue: "task/my-task",
1752+
isTest: false,
1753+
taskEventStore: "taskEvent",
1754+
depth: 0,
1755+
createdAt: row.createdAt,
1756+
},
1757+
});
1758+
}
1759+
1760+
const found = await store.findRuns({
1761+
where: { projectId: project.id },
1762+
orderBy: { createdAt: "desc" },
1763+
});
1764+
1765+
expect(found).toHaveLength(2);
1766+
expect(found.map((r) => r.id)).toEqual([
1767+
"run_find_full_many_latest",
1768+
"run_find_full_many_earliest",
1769+
]);
1770+
// Whole rows include full scalar columns.
1771+
expect(found[0]?.taskIdentifier).toBe("my-task");
1772+
expect(found[0]?.payloadType).toBe("application/json");
1773+
});
16861774
});

internal-packages/run-store/src/PostgresRunStore.ts

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -628,12 +628,16 @@ export class PostgresRunStore implements RunStore {
628628
args: { include: I },
629629
client?: PrismaClientOrTransaction
630630
): Promise<Prisma.TaskRunGetPayload<{ include: I }> | null>;
631+
findRun(
632+
where: Prisma.TaskRunWhereInput,
633+
client?: PrismaClientOrTransaction
634+
): Promise<TaskRun | null>;
631635
async findRun(
632636
where: Prisma.TaskRunWhereInput,
633-
args: { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude },
637+
argsOrClient?: { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude } | PrismaClientOrTransaction,
634638
client?: PrismaClientOrTransaction
635639
): Promise<unknown> {
636-
const prisma = client ?? this.readOnlyPrisma;
640+
const { args, prisma } = this.#resolveReadArgs(argsOrClient, client);
637641

638642
return prisma.taskRun.findFirst({
639643
where,
@@ -651,12 +655,16 @@ export class PostgresRunStore implements RunStore {
651655
args: { include: I },
652656
client?: PrismaClientOrTransaction
653657
): Promise<Prisma.TaskRunGetPayload<{ include: I }>>;
658+
findRunOrThrow(
659+
where: Prisma.TaskRunWhereInput,
660+
client?: PrismaClientOrTransaction
661+
): Promise<TaskRun>;
654662
async findRunOrThrow(
655663
where: Prisma.TaskRunWhereInput,
656-
args: { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude },
664+
argsOrClient?: { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude } | PrismaClientOrTransaction,
657665
client?: PrismaClientOrTransaction
658666
): Promise<unknown> {
659-
const prisma = client ?? this.readOnlyPrisma;
667+
const { args, prisma } = this.#resolveReadArgs(argsOrClient, client);
660668

661669
return prisma.taskRun.findFirstOrThrow({
662670
where,
@@ -686,6 +694,16 @@ export class PostgresRunStore implements RunStore {
686694
},
687695
client?: PrismaClientOrTransaction
688696
): Promise<Prisma.TaskRunGetPayload<{ include: I }>[]>;
697+
findRuns(
698+
args: {
699+
where: Prisma.TaskRunWhereInput;
700+
orderBy?: Prisma.TaskRunOrderByWithRelationInput | Prisma.TaskRunOrderByWithRelationInput[];
701+
take?: number;
702+
skip?: number;
703+
cursor?: Prisma.TaskRunWhereUniqueInput;
704+
},
705+
client?: PrismaClientOrTransaction
706+
): Promise<TaskRun[]>;
689707
async findRuns(
690708
args: {
691709
where: Prisma.TaskRunWhereInput;
@@ -702,4 +720,41 @@ export class PostgresRunStore implements RunStore {
702720

703721
return prisma.taskRun.findMany(args);
704722
}
723+
724+
/**
725+
* The single-row read methods (`findRun`, `findRunOrThrow`) accept either
726+
* `(where, { select | include }, client?)` or the full-row `(where, client?)`.
727+
* Disambiguate the second positional arg: a `{ select }` / `{ include }`
728+
* projection object vs. a Prisma client. A projection object always carries a
729+
* `select` or `include` key; a Prisma client never does. Anything else (e.g.
730+
* `undefined`) is treated as "no projection, no explicit client".
731+
*/
732+
#resolveReadArgs(
733+
argsOrClient:
734+
| { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude }
735+
| PrismaClientOrTransaction
736+
| undefined,
737+
client: PrismaClientOrTransaction | undefined
738+
): {
739+
args: { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude };
740+
prisma: PrismaClientOrTransaction | PrismaReplicaClient;
741+
} {
742+
const isProjection =
743+
typeof argsOrClient === "object" &&
744+
argsOrClient !== null &&
745+
("select" in argsOrClient || "include" in argsOrClient);
746+
747+
if (isProjection) {
748+
return {
749+
args: argsOrClient as { select?: Prisma.TaskRunSelect; include?: Prisma.TaskRunInclude },
750+
prisma: client ?? this.readOnlyPrisma,
751+
};
752+
}
753+
754+
// No projection: the second positional arg, when present, is the client.
755+
return {
756+
args: {},
757+
prisma: (argsOrClient as PrismaClientOrTransaction | undefined) ?? this.readOnlyPrisma,
758+
};
759+
}
705760
}

internal-packages/run-store/src/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ export interface RunStore {
331331
args: { include: I },
332332
client?: PrismaClientOrTransaction
333333
): Promise<Prisma.TaskRunGetPayload<{ include: I }> | null>;
334+
findRun(where: Prisma.TaskRunWhereInput, client?: PrismaClientOrTransaction): Promise<TaskRun | null>;
334335

335336
findRunOrThrow<S extends Prisma.TaskRunSelect>(
336337
where: Prisma.TaskRunWhereInput,
@@ -342,6 +343,7 @@ export interface RunStore {
342343
args: { include: I },
343344
client?: PrismaClientOrTransaction
344345
): Promise<Prisma.TaskRunGetPayload<{ include: I }>>;
346+
findRunOrThrow(where: Prisma.TaskRunWhereInput, client?: PrismaClientOrTransaction): Promise<TaskRun>;
345347

346348
findRuns<S extends Prisma.TaskRunSelect>(
347349
args: {
@@ -365,4 +367,14 @@ export interface RunStore {
365367
},
366368
client?: PrismaClientOrTransaction
367369
): Promise<Prisma.TaskRunGetPayload<{ include: I }>[]>;
370+
findRuns(
371+
args: {
372+
where: Prisma.TaskRunWhereInput;
373+
orderBy?: Prisma.TaskRunOrderByWithRelationInput | Prisma.TaskRunOrderByWithRelationInput[];
374+
take?: number;
375+
skip?: number;
376+
cursor?: Prisma.TaskRunWhereUniqueInput;
377+
},
378+
client?: PrismaClientOrTransaction
379+
): Promise<TaskRun[]>;
368380
}

0 commit comments

Comments
 (0)