Skip to content

Commit fd9cd2e

Browse files
fix(openworkflow): only transform PG column names, not JSON value object keys (#368)
1 parent d914cc7 commit fd9cd2e

2 files changed

Lines changed: 100 additions & 1 deletion

File tree

packages/openworkflow/postgres/backend.test.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,98 @@ describe("BackendPostgres schema option", () => {
172172
});
173173
});
174174

175+
describe("BackendPostgres JSON key preservation", () => {
176+
test("preserves uppercase snake case keys in workflow run input", async () => {
177+
const namespaceId = randomUUID();
178+
const backend = await BackendPostgres.connect(DEFAULT_POSTGRES_URL, {
179+
namespaceId,
180+
});
181+
182+
// https://github.com/openworkflowdev/openworkflow/issues/367
183+
const input = {
184+
env: {
185+
OPENAI_MODEL: "gpt-5.3-codex",
186+
OPENAI_BASE_URL: "http://127.0.0.1:8090/...",
187+
OPENAI_REASONING_EFFORT: "medium",
188+
},
189+
};
190+
const transformedModelKey = "OPENAI_MODEL".replaceAll("_", "");
191+
const transformedBaseUrlKey = "OPENAI_BASE_URL".replaceAll("_", "");
192+
const transformedReasoningEffortKey = "OPENAI_REASONING_EFFORT".replaceAll(
193+
"_",
194+
"",
195+
);
196+
197+
try {
198+
const workflowRun = await backend.createWorkflowRun({
199+
workflowName: "json-key-preservation",
200+
version: null,
201+
idempotencyKey: null,
202+
input,
203+
config: {},
204+
context: null,
205+
parentStepAttemptNamespaceId: null,
206+
parentStepAttemptId: null,
207+
availableAt: null,
208+
deadlineAt: null,
209+
});
210+
211+
if (
212+
!workflowRun.input ||
213+
typeof workflowRun.input !== "object" ||
214+
Array.isArray(workflowRun.input)
215+
) {
216+
throw new Error("Expected workflow run input object");
217+
}
218+
219+
const createEnv = (workflowRun.input as { env?: Record<string, string> })
220+
.env;
221+
if (!createEnv) throw new Error("Expected workflow run input env");
222+
expect(createEnv["OPENAI_MODEL"]).toBe(input.env.OPENAI_MODEL);
223+
expect(createEnv["OPENAI_BASE_URL"]).toBe(input.env.OPENAI_BASE_URL);
224+
expect(createEnv["OPENAI_REASONING_EFFORT"]).toBe(
225+
input.env.OPENAI_REASONING_EFFORT,
226+
);
227+
expect(createEnv[transformedModelKey]).toBeUndefined();
228+
expect(createEnv[transformedBaseUrlKey]).toBeUndefined();
229+
expect(createEnv[transformedReasoningEffortKey]).toBeUndefined();
230+
231+
const pg = newPostgresMaxOne(DEFAULT_POSTGRES_URL);
232+
try {
233+
const workflowRunsTable = pg`${pg(DEFAULT_SCHEMA)}.${pg("workflow_runs")}`;
234+
const [record] = await pg<
235+
{
236+
input: {
237+
env?: Record<string, string>;
238+
};
239+
}[]
240+
>`
241+
SELECT "input"
242+
FROM ${workflowRunsTable}
243+
WHERE "namespace_id" = ${namespaceId}
244+
AND "id" = ${workflowRun.id}
245+
LIMIT 1
246+
`;
247+
248+
const persistedEnv = record?.input.env;
249+
if (!persistedEnv) throw new Error("Expected persisted workflow input");
250+
expect(persistedEnv["OPENAI_MODEL"]).toBe(input.env.OPENAI_MODEL);
251+
expect(persistedEnv["OPENAI_BASE_URL"]).toBe(input.env.OPENAI_BASE_URL);
252+
expect(persistedEnv["OPENAI_REASONING_EFFORT"]).toBe(
253+
input.env.OPENAI_REASONING_EFFORT,
254+
);
255+
expect(persistedEnv[transformedModelKey]).toBeUndefined();
256+
expect(persistedEnv[transformedBaseUrlKey]).toBeUndefined();
257+
expect(persistedEnv[transformedReasoningEffortKey]).toBeUndefined();
258+
} finally {
259+
await pg.end();
260+
}
261+
} finally {
262+
await backend.stop();
263+
}
264+
});
265+
});
266+
175267
describe("BackendPostgres cancel fallback", () => {
176268
test("throws generic cancel error for non-standard workflow status", async () => {
177269
const backend = await BackendPostgres.connect(DEFAULT_POSTGRES_URL, {

packages/openworkflow/postgres/postgres.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@ const MAX_POSTGRES_IDENTIFIER_BYTES = 63;
1919
* @returns A Postgres client
2020
*/
2121
export function newPostgres(url: string, options?: PostgresOptions) {
22-
return postgres(url, { ...options, transform: postgres.toCamel });
22+
return postgres(url, {
23+
...options,
24+
transform: {
25+
column: {
26+
from: postgres.toCamel,
27+
},
28+
},
29+
});
2330
}
2431

2532
/**

0 commit comments

Comments
 (0)