diff --git a/scripts/runTests.ts b/scripts/runTests.ts index ced3df9..9110fbe 100644 --- a/scripts/runTests.ts +++ b/scripts/runTests.ts @@ -37,6 +37,7 @@ const program = Effect.gen(function* () { yield* run("./tests", "prisma", "db", "push"); } yield* run("./tests", "prisma", "generate", "--sql"); + yield* run("./tests/no-typedsql", "prisma", "generate"); yield* run("./tests", "tsc", "--noEmit"); yield* run("./tests", "vitest", "run"); }).pipe( diff --git a/src/index.ts b/src/index.ts index 2d1f021..e1b1b67 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,14 +37,27 @@ generatorHandler({ throw new Error("effect-prisma-generator: outputPath must be a ts file"); } + const hasTypedSql = [options.generator, ...options.otherGenerators] + .some(g => g.previewFeatures.includes("typedSql")); + const outputDir = path.dirname(outputPath); await fs.mkdir(outputDir, { recursive: true }); - await generateUnifiedService([...models], outputPath, clientImportPath); + await generateUnifiedService([...models], outputPath, clientImportPath, hasTypedSql); }, }); -function generateRawSqlOperations() { +function generateRawSqlOperations(hasTypedSql: boolean) { + const typedSqlOperation = hasTypedSql ? ` + + $queryRawTyped: (typedQuery: runtime.TypedSql) => + Effect.flatMap(clientOrTx(client), client => + Effect.tryPromise({ + try: () => client.$queryRawTyped(typedQuery), + catch: (error) => mapError(error, "$queryRawTyped", "Prisma") + }), + ),` : ''; + return ` $executeRaw: (args: Prisma.Sql | [Prisma.Sql, ...any[]]) => Effect.flatMap(clientOrTx(client), client => @@ -76,15 +89,7 @@ function generateRawSqlOperations() { try: () => client.$queryRawUnsafe(query, ...values), catch: (error) => mapError(error, "$queryRawUnsafe", "Prisma") }), - ), - - $queryRawTyped: (typedQuery: runtime.TypedSql) => - Effect.flatMap(clientOrTx(client), client => - Effect.tryPromise({ - try: () => client.$queryRawTyped(typedQuery), - catch: (error) => mapError(error, "$queryRawTyped", "Prisma") - }), - ),`; + ),${typedSqlOperation}`; } function generateModelOperations(models: DMMF.Model[]) { @@ -310,15 +315,17 @@ async function generateUnifiedService( models: DMMF.Model[], outputPath: string, clientImportPath: string, + hasTypedSql: boolean, ) { - const rawSqlOperations = generateRawSqlOperations(); + const rawSqlOperations = generateRawSqlOperations(hasTypedSql); const modelOperations = generateModelOperations(models); + const runtimeImport = hasTypedSql ? `\nimport * as runtime from "@prisma/client/runtime/client"` : ''; + const serviceContent = `${header} import { Cause, Context, Data, Effect, Exit, Option, Runtime } from "effect" import { Service } from "effect/Effect" -import { Prisma, PrismaClient } from "${clientImportPath}" -import * as runtime from "@prisma/client/runtime/client" +import { Prisma, PrismaClient } from "${clientImportPath}"${runtimeImport} export class PrismaClientService extends Context.Tag("PrismaClientService")< PrismaClientService, diff --git a/tests/integration.test.ts b/tests/integration.test.ts index 5bd7ba7..aa6b05d 100644 --- a/tests/integration.test.ts +++ b/tests/integration.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "@effect/vitest"; import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3"; import { Data, Effect, Layer } from "effect"; +import * as fs from "fs"; import { PrismaClient } from "./prisma/generated/client"; import { PrismaClientService, @@ -290,4 +291,16 @@ describe("Prisma Effect Generator", () => { yield* prisma.user.delete({ where: { email } }); }).pipe(Effect.provide(MainLayer)), ); + + it("should include $queryRawTyped when typedSql preview feature is enabled", () => { + const generated = fs.readFileSync("prisma/generated/effect.ts", "utf-8"); + expect(generated).toContain("$queryRawTyped"); + expect(generated).toContain('import * as runtime from "@prisma/client/runtime/client"'); + }); + + it("should not include $queryRawTyped when typedSql preview feature is not enabled", () => { + const generated = fs.readFileSync("no-typedsql/generated/effect.ts", "utf-8"); + expect(generated).not.toContain("$queryRawTyped"); + expect(generated).not.toContain('import * as runtime from "@prisma/client/runtime/client"'); + }); }); diff --git a/tests/no-typedsql/prisma.config.ts b/tests/no-typedsql/prisma.config.ts new file mode 100644 index 0000000..621ec3a --- /dev/null +++ b/tests/no-typedsql/prisma.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "prisma/config"; + +export default defineConfig({ + datasource: { + url: "file:dev.db", + }, +}); diff --git a/tests/no-typedsql/schema.prisma b/tests/no-typedsql/schema.prisma new file mode 100644 index 0000000..46d54fc --- /dev/null +++ b/tests/no-typedsql/schema.prisma @@ -0,0 +1,19 @@ +datasource db { + provider = "sqlite" +} + +generator client { + provider = "prisma-client" + output = "./generated" +} + +generator effect { + provider = "node ../../dist/index.js" + output = "./generated/effect.ts" + clientImportPath = "./client" +} + +model User { + id Int @id @default(autoincrement()) + email String @unique +}