From harness-claude
Execute type-safe raw SQL in Prisma using $queryRaw, $executeRaw, and Prisma.sql template tag. Use for CTEs, window functions, complex joins, bulk operations, data migrations, and database-specific features.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Execute type-safe raw SQL with $queryRaw, $executeRaw, and Prisma.sql template tag
Executes raw SQL safely in Drizzle ORM using sql template tags, db.execute(), and placeholders. Use for CTEs, window functions, recursive queries, database-specific functions, and embedding SQL fragments.
Provides expert guidance on Prisma ORM schema design, migrations, query optimization, relations modeling, and database operations for PostgreSQL, MySQL, SQLite.
Provides expert guidance on Prisma ORM for TypeScript apps: schema design, migrations, Prisma Client queries, relations, edge deployment, and performance optimization.
Share bugs, ideas, or general feedback.
Execute type-safe raw SQL with $queryRaw, $executeRaw, and Prisma.sql template tag
$queryRaw with a tagged template literal. Always parameterize inputs:const users = await prisma.$queryRaw<User[]>`
SELECT id, email, name FROM "User" WHERE role = ${role}
`;
The template tag automatically parameterizes ${role} as a prepared statement parameter — never string-interpolated.
$executeRaw for INSERT, UPDATE, DELETE. Returns the affected row count:const count = await prisma.$executeRaw`
UPDATE "Post" SET "viewCount" = "viewCount" + 1 WHERE id = ${postId}
`;
Prisma.raw() for identifiers that cannot be parameterized:import { Prisma } from '@prisma/client';
const column = Prisma.raw(`"${columnName}"`);
const result = await prisma.$queryRaw`
SELECT ${column} FROM "User" WHERE id = ${userId}
`;
Validate columnName against an allowlist before using Prisma.raw() to prevent SQL injection.
Prisma.sql and Prisma.join:const ids = [1, 2, 3];
const result = await prisma.$queryRaw`
SELECT * FROM "User" WHERE id IN (${Prisma.join(ids)})
`;
Prisma.sql:const where = searchTerm ? Prisma.sql`WHERE name ILIKE ${'%' + searchTerm + '%'}` : Prisma.empty;
const users = await prisma.$queryRaw`SELECT * FROM "User" ${where}`;
$queryRaw returns unknown[] by default. Pass a generic type or validate with Zod:import { z } from 'zod';
const UserRow = z.object({ id: z.string(), email: z.string() });
const raw = await prisma.$queryRaw`SELECT id, email FROM "User"`;
const users = z.array(UserRow).parse(raw);
await prisma.$transaction(async (tx) => {
await tx.$executeRaw`LOCK TABLE "Inventory" IN EXCLUSIVE MODE`;
const [item] = await tx.$queryRaw<Inventory[]>`
SELECT * FROM "Inventory" WHERE sku = ${sku} FOR UPDATE
`;
await tx.$executeRaw`
UPDATE "Inventory" SET quantity = quantity - ${qty} WHERE sku = ${sku}
`;
});
Raw queries bypass Prisma's query engine and type generation. The SQL runs directly against the database connection, but parameter binding still uses prepared statements for safety.
Table and column naming: Prisma maps model names to table names via @@map and field names to column names via @map. In raw SQL, you must use the actual database names, not the Prisma model names. Check with prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script to see the real table names.
Return type caveats:
$queryRaw returns rows with exact database column names (not Prisma field names)BigInt columns return JavaScript BigInt, which is not JSON-serializable — convert to Number or String before sending to clientsDecimal columns return Prisma.Decimal objects, not numberDateTime columns return Date objects$queryRawUnsafe / $executeRawUnsafe: Accept a plain string instead of a tagged template. These do NOT parameterize — you are responsible for preventing SQL injection. Avoid unless you are building a query builder that handles parameterization itself.
Performance advantages of raw SQL:
INSERT ... ON CONFLICT (upsert) on multiple rows is significantly faster than looping prisma.model.upsert()update callshttps://prisma.io/docs/orm/prisma-client/queries/raw-database-access