1import { rewriteEmittedTypes, runPrismaCli } from "@/Prisma/ORM/internal.ts";
2import * as NodeServices from "@effect/platform-node/NodeServices";
3import { expect, layer } from "alchemy-test";
4import * as Effect from "effect/Effect";
5import * as FileSystem from "effect/FileSystem";
6import * as Path from "effect/Path";
7import * as Result from "effect/Result";
8
9const describe = layer(NodeServices.layer);
10
11const writeDts = (contents: string) =>
12 Effect.gen(function* () {
13 const fs = yield* FileSystem.FileSystem;
14 const path = yield* Path.Path;
15 const dir = yield* fs.makeTempDirectory({
16 prefix: "alchemy-prisma-rewrite-",
17 });
18 const dtsPath = path.join(dir, "contract.d.ts");
19 yield* fs.writeFileString(dtsPath, contents);
20 return dtsPath;
21 });
22
23describe("runPrismaCli", (it) => {
24 it.effect(
25 "omits database arguments from CLI error messages",
26 () =>
27 Effect.gen(function* () {
28 const fs = yield* FileSystem.FileSystem;
29 const path = yield* Path.Path;
30 const cwd = yield* fs.makeTempDirectoryScoped({
31 prefix: "alchemy-prisma-cli-",
32 });
33 const result = yield* Effect.result(
34 runPrismaCli(
35 [
36 "db",
37 "verify",
38 "--config",
39 path.join(cwd, "missing.config.ts"),
40 "--db",
41 "postgresql://test:private-test-password@127.0.0.1:1/test",
42 ],
43 { cwd },
44 ),
45 );
46 expect(Result.isFailure(result)).toBe(true);
47 if (Result.isFailure(result)) {
48 expect(JSON.stringify(result.failure)).not.toContain(
49 "private-test-password",
50 );
51 expect(result.failure.message).toContain("prisma db verify failed");
52 }
53 }).pipe(Effect.scoped),
54 { tags: ["unit", "provider:prisma", "provider:prisma:orm", "local"] },
55 );
56});
57
58describe("rewriteEmittedTypes", (it) => {
59 it.effect(
60 "maps leaked @internal/extension-* specifiers to @prisma/orm-extension-*",
61 () =>
62 Effect.gen(function* () {
63 const fs = yield* FileSystem.FileSystem;
64 // Imports already use the public package. Prisma still writes the
65 // unpublished @internal/extension-* name as a string in the type
66 // body (through 8.0.0-rc.8).
67 const dtsPath = yield* writeDts(`
68import type { Vector } from "@prisma/orm-extension-pgvector/codec-types";
69type Pgvector = { package: "@internal/extension-pgvector/codec-types" };
70type Parade = { package: "@internal/extension-paradedb/pack" };
71`);
72 yield* rewriteEmittedTypes(dtsPath);
73 const dts = yield* fs.readFileString(dtsPath);
74 expect(dts).not.toContain("@internal/");
75 expect(dts).toContain('"@prisma/orm-extension-pgvector/codec-types"');
76 expect(dts).toContain('"@prisma/orm-extension-paradedb/pack"');
77 }),
78 { tags: ["unit", "provider:prisma", "provider:prisma:orm", "local"] },
79 );
80
81 it.effect(
82 "still maps postgres @internal/* prefixes when an extension specifier is present",
83 () =>
84 Effect.gen(function* () {
85 const fs = yield* FileSystem.FileSystem;
86 const dtsPath = yield* writeDts(`
87import type { X } from "@internal/adapter-postgres/operation-types";
88import type { Y } from "@internal/contract/types";
89type Pack = { package: "@internal/extension-pgvector/pack" };
90`);
91 yield* rewriteEmittedTypes(dtsPath);
92 const dts = yield* fs.readFileString(dtsPath);
93 expect(dts).not.toContain("@internal/");
94 expect(dts).toContain("@prisma/orm-postgres/adapter/operation-types");
95 expect(dts).toContain("@prisma/orm-postgres/contract/types");
96 expect(dts).toContain("@prisma/orm-extension-pgvector/pack");
97 }),
98 { tags: ["unit", "provider:prisma", "provider:prisma:orm", "local"] },
99 );
100
101 it.effect(
102 "fails when an unmapped @internal/* specifier remains",
103 () =>
104 Effect.gen(function* () {
105 const dtsPath = yield* writeDts(
106 `type Leak = { package: "@internal/unknown-pkg/types" };\n`,
107 );
108 const result = yield* Effect.result(rewriteEmittedTypes(dtsPath));
109 expect(Result.isFailure(result)).toBe(true);
110 if (Result.isFailure(result)) {
111 expect(String(result.failure)).toContain("@internal/unknown-pkg/");
112 }
113 }),
114 { tags: ["unit", "provider:prisma", "provider:prisma:orm", "local"] },
115 );
116});