Skip to content

Commit 1735f11

Browse files
dmealingclaude
andcommitted
fix(codegen-ts): drop prepared-statement pattern from renderFindByIdFn (FR2 followup)
The prepared-statement shape only made sense when the Base/Prepared constants were hoisted to module scope and prepared once at import time. With FR2's parameter-passed `db`, the constants moved inside the function body — so .prepare() now runs on every call. On Postgres that issues PREPARE round trips per call and risks collisions on the named prepared statement; on SQLite it allocates a fresh statement handle each call. Strictly worse than a plain select(). Simplify to the same shape the other helpers use: const [x] = await db.select().from(table).where(eq(...)).limit(1); return x ?? null; Removes the unused prepareName() helper, the dialect branch on prepArg, the sql@drizzle-orm import in this function, and the corresponding prepared-shape tests. Goldens regenerate. If a future adopter measures a real cost on hot-path find-by-id, the runtime-ts package can offer a "prepared statement cache" factory — that's a separate FR. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent f991369 commit 1735f11

24 files changed

Lines changed: 89 additions & 192 deletions

server/typescript/packages/codegen-ts/src/templates/queries.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ import { code, imp, type Code } from "ts-poet";
55
import type { MetaObject } from "@metaobjectsdev/metadata";
66
import { IDENTITY_ATTR_FIELDS } from "@metaobjectsdev/metadata";
77
import type { RenderContext } from "../render-context.js";
8-
import { variableNameFromEntity, toSnakeCase, pluralize } from "../naming.js";
9-
10-
/** Derive a stable prepared statement name. Deterministic from entity + field names. */
11-
function prepareName(prefix: string, entitySnakeName: string, fieldDbName: string): string {
12-
return `${prefix}_${entitySnakeName}_by_${fieldDbName}`;
13-
}
8+
import { variableNameFromEntity, pluralize } from "../naming.js";
149

1510
/** Get the PK field name and its TS type for a given entity. */
1611
function getPkInfo(entity: MetaObject, ctx: RenderContext): { fieldName: string; tsType: string } {
@@ -34,29 +29,13 @@ export function renderFindByIdFn(entity: MetaObject, ctx: RenderContext): Code {
3429
const varName = variableNameFromEntity(entity.name);
3530
const entityName = entity.name;
3631
const singularVar = entityName.charAt(0).toLowerCase() + entityName.slice(1);
37-
const entitySnakeName = toSnakeCase(entityName);
3832
const { fieldName: pkField, tsType: pkType } = getPkInfo(entity, ctx);
39-
const pkSnakeName = toSnakeCase(pkField);
40-
const prepName = prepareName("find", entitySnakeName, pkSnakeName);
4133
const fnName = `find${entityName}ById`;
42-
const baseVarName = `${fnName}Base`;
43-
const prepVarName = `${fnName}Prepared`;
4434
const eqSym = imp("eq@drizzle-orm");
45-
const sqlSym = imp("sql@drizzle-orm");
46-
47-
// Drizzle's `.prepare()` signature differs by dialect:
48-
// - Postgres: prepare(name) — the name is used by the pg driver to cache the plan
49-
// - SQLite: prepare() — no name; the name arg was removed in drizzle-orm 0.41+
50-
const prepArg = ctx.dialect === "postgres" ? `"${prepName}"` : "";
5135

5236
return code`
5337
export async function ${fnName}(db: Db, ${pkField}: ${pkType}): Promise<${entityName} | null> {
54-
const ${baseVarName} = db
55-
.select()
56-
.from(${varName})
57-
.where(${eqSym}(${varName}.${pkField}, ${sqlSym}.placeholder(${JSON.stringify(pkField)})));
58-
const ${prepVarName} = ${baseVarName}.prepare(${prepArg});
59-
const [${singularVar}] = await ${prepVarName}.execute({ ${pkField} });
38+
const [${singularVar}] = await db.select().from(${varName}).where(${eqSym}(${varName}.${pkField}, ${pkField})).limit(1);
6039
return ${singularVar} ?? null;
6140
}
6241
`;

server/typescript/packages/codegen-ts/test/golden/__snapshots__/package/Tag.queries.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Tag (Tag)
33
// Customize via Tag.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
77
type Db = BaseSQLiteDatabase<"async", Record<string, never>>;
88

99
import { type Tag, TagInsertSchema, tags } from "./Tag";
1010
export async function findTagById(db: Db, id: number): Promise<Tag | null> {
11-
const findTagByIdBase = db
12-
.select()
13-
.from(tags)
14-
.where(eq(tags.id, sql.placeholder("id")));
15-
const findTagByIdPrepared = findTagByIdBase.prepare();
16-
const [tag] = await findTagByIdPrepared.execute({ id });
11+
const [tag] = await db.select().from(tags).where(eq(tags.id, id)).limit(1);
1712
return tag ?? null;
1813
}
1914
export async function listTags(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/package/shop/commerce/Order.queries.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Order (shop::commerce::Order)
33
// Customize via Order.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
77
type Db = BaseSQLiteDatabase<"async", Record<string, never>>;
88

99
import { type Order, OrderInsertSchema, orders } from "./Order";
1010
export async function findOrderById(db: Db, id: number): Promise<Order | null> {
11-
const findOrderByIdBase = db
11+
const [order] = await db
1212
.select()
1313
.from(orders)
14-
.where(eq(orders.id, sql.placeholder("id")));
15-
const findOrderByIdPrepared = findOrderByIdBase.prepare();
16-
const [order] = await findOrderByIdPrepared.execute({ id });
14+
.where(eq(orders.id, id))
15+
.limit(1);
1716
return order ?? null;
1817
}
1918
export async function listOrders(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/package/shop/commerce/Product.queries.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Product (shop::commerce::Product)
33
// Customize via Product.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
77
type Db = BaseSQLiteDatabase<"async", Record<string, never>>;
@@ -11,12 +11,11 @@ export async function findProductById(
1111
db: Db,
1212
id: number,
1313
): Promise<Product | null> {
14-
const findProductByIdBase = db
14+
const [product] = await db
1515
.select()
1616
.from(products)
17-
.where(eq(products.id, sql.placeholder("id")));
18-
const findProductByIdPrepared = findProductByIdBase.prepare();
19-
const [product] = await findProductByIdPrepared.execute({ id });
17+
.where(eq(products.id, id))
18+
.limit(1);
2019
return product ?? null;
2120
}
2221
export async function listProducts(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/package/shop/users/Customer.queries.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Customer (shop::users::Customer)
33
// Customize via Customer.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
77
type Db = BaseSQLiteDatabase<"async", Record<string, never>>;
@@ -11,12 +11,11 @@ export async function findCustomerById(
1111
db: Db,
1212
id: number,
1313
): Promise<Customer | null> {
14-
const findCustomerByIdBase = db
14+
const [customer] = await db
1515
.select()
1616
.from(customers)
17-
.where(eq(customers.id, sql.placeholder("id")));
18-
const findCustomerByIdPrepared = findCustomerByIdBase.prepare();
19-
const [customer] = await findCustomerByIdPrepared.execute({ id });
17+
.where(eq(customers.id, id))
18+
.limit(1);
2019
return customer ?? null;
2120
}
2221
export async function listCustomers(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/postgres/Exercise.queries.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Exercise (Exercise)
33
// Customize via Exercise.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
77
type Db = NodePgDatabase<Record<string, never>>;
@@ -11,14 +11,11 @@ export async function findExerciseById(
1111
db: Db,
1212
id: number,
1313
): Promise<Exercise | null> {
14-
const findExerciseByIdBase = db
14+
const [exercise] = await db
1515
.select()
1616
.from(exercises)
17-
.where(eq(exercises.id, sql.placeholder("id")));
18-
const findExerciseByIdPrepared = findExerciseByIdBase.prepare(
19-
"find_exercise_by_id",
20-
);
21-
const [exercise] = await findExerciseByIdPrepared.execute({ id });
17+
.where(eq(exercises.id, id))
18+
.limit(1);
2219
return exercise ?? null;
2320
}
2421
export async function listExercises(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/postgres/Program.queries.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Program (Program)
33
// Customize via Program.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
77
type Db = NodePgDatabase<Record<string, never>>;
@@ -11,13 +11,11 @@ export async function findProgramById(
1111
db: Db,
1212
id: number,
1313
): Promise<Program | null> {
14-
const findProgramByIdBase = db
14+
const [program] = await db
1515
.select()
1616
.from(programs)
17-
.where(eq(programs.id, sql.placeholder("id")));
18-
const findProgramByIdPrepared =
19-
findProgramByIdBase.prepare("find_program_by_id");
20-
const [program] = await findProgramByIdPrepared.execute({ id });
17+
.where(eq(programs.id, id))
18+
.limit(1);
2119
return program ?? null;
2220
}
2321
export async function listPrograms(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/postgres/Purchase.queries.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Purchase (Purchase)
33
// Customize via Purchase.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
77
type Db = NodePgDatabase<Record<string, never>>;
@@ -11,14 +11,11 @@ export async function findPurchaseById(
1111
db: Db,
1212
id: number,
1313
): Promise<Purchase | null> {
14-
const findPurchaseByIdBase = db
14+
const [purchase] = await db
1515
.select()
1616
.from(purchases)
17-
.where(eq(purchases.id, sql.placeholder("id")));
18-
const findPurchaseByIdPrepared = findPurchaseByIdBase.prepare(
19-
"find_purchase_by_id",
20-
);
21-
const [purchase] = await findPurchaseByIdPrepared.execute({ id });
17+
.where(eq(purchases.id, id))
18+
.limit(1);
2219
return purchase ?? null;
2320
}
2421
export async function listPurchases(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/postgres/Subscriber.queries.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Subscriber (Subscriber)
33
// Customize via Subscriber.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
77
type Db = NodePgDatabase<Record<string, never>>;
@@ -15,14 +15,11 @@ export async function findSubscriberById(
1515
db: Db,
1616
id: number,
1717
): Promise<Subscriber | null> {
18-
const findSubscriberByIdBase = db
18+
const [subscriber] = await db
1919
.select()
2020
.from(subscribers)
21-
.where(eq(subscribers.id, sql.placeholder("id")));
22-
const findSubscriberByIdPrepared = findSubscriberByIdBase.prepare(
23-
"find_subscriber_by_id",
24-
);
25-
const [subscriber] = await findSubscriberByIdPrepared.execute({ id });
21+
.where(eq(subscribers.id, id))
22+
.limit(1);
2623
return subscriber ?? null;
2724
}
2825
export async function listSubscribers(

server/typescript/packages/codegen-ts/test/golden/__snapshots__/postgres/Tag.queries.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
// @generated by @metaobjectsdev/codegen-ts — DO NOT EDIT.
22
// Source metadata: Tag (Tag)
33
// Customize via Tag.extra.ts in this directory (additional queries, custom logic).
4-
import { eq, sql } from "drizzle-orm";
4+
import { eq } from "drizzle-orm";
55

66
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
77
type Db = NodePgDatabase<Record<string, never>>;
88

99
import { type Tag, TagInsertSchema, tags } from "./Tag";
1010
export async function findTagById(db: Db, id: number): Promise<Tag | null> {
11-
const findTagByIdBase = db
12-
.select()
13-
.from(tags)
14-
.where(eq(tags.id, sql.placeholder("id")));
15-
const findTagByIdPrepared = findTagByIdBase.prepare("find_tag_by_id");
16-
const [tag] = await findTagByIdPrepared.execute({ id });
11+
const [tag] = await db.select().from(tags).where(eq(tags.id, id)).limit(1);
1712
return tag ?? null;
1813
}
1914
export async function listTags(

0 commit comments

Comments
 (0)