prisma-effect-kysely 5.8.0 → 6.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +14 -125
  2. package/README.md +76 -43
  3. package/dist/effect/enum.d.ts +2 -2
  4. package/dist/effect/enum.d.ts.map +1 -1
  5. package/dist/effect/enum.js +9 -6
  6. package/dist/effect/enum.js.map +1 -1
  7. package/dist/effect/generator.d.ts +2 -1
  8. package/dist/effect/generator.d.ts.map +1 -1
  9. package/dist/effect/generator.js +20 -10
  10. package/dist/effect/generator.js.map +1 -1
  11. package/dist/effect/join-table.d.ts +1 -1
  12. package/dist/effect/join-table.d.ts.map +1 -1
  13. package/dist/effect/join-table.js +8 -6
  14. package/dist/effect/join-table.js.map +1 -1
  15. package/dist/effect/type.d.ts.map +1 -1
  16. package/dist/effect/type.js +24 -2
  17. package/dist/effect/type.js.map +1 -1
  18. package/dist/error/index.d.ts +55 -0
  19. package/dist/error/index.d.ts.map +1 -0
  20. package/dist/error/index.js +38 -0
  21. package/dist/error/index.js.map +1 -0
  22. package/dist/generator/config.d.ts +6 -6
  23. package/dist/generator/config.js +1 -1
  24. package/dist/generator/config.js.map +1 -1
  25. package/dist/generator/contract-scaffolder.d.ts +5 -5
  26. package/dist/generator/contract-scaffolder.js +2 -2
  27. package/dist/generator/contract-scaffolder.js.map +1 -1
  28. package/dist/kysely/helpers.d.ts +29 -39
  29. package/dist/kysely/helpers.d.ts.map +1 -1
  30. package/dist/kysely/helpers.js +181 -169
  31. package/dist/kysely/helpers.js.map +1 -1
  32. package/dist/kysely/type.d.ts +20 -25
  33. package/dist/kysely/type.d.ts.map +1 -1
  34. package/dist/kysely/type.js +22 -35
  35. package/dist/kysely/type.js.map +1 -1
  36. package/dist/runtime/index.d.ts +10 -0
  37. package/dist/runtime/index.d.ts.map +1 -0
  38. package/dist/runtime/index.js +10 -0
  39. package/dist/runtime/index.js.map +1 -0
  40. package/dist/utils/type-mappings.d.ts +8 -13
  41. package/dist/utils/type-mappings.d.ts.map +1 -1
  42. package/dist/utils/type-mappings.js +7 -12
  43. package/dist/utils/type-mappings.js.map +1 -1
  44. package/package.json +12 -8
package/CHANGELOG.md CHANGED
@@ -1,134 +1,23 @@
1
1
  # Changelog
2
2
 
3
- ## 5.8.0
3
+ ## 6.0.0-next.0
4
4
 
5
- ### Minor Changes
6
-
7
- - ac42853: fix: DateTime maps back to `Schema.DateFromSelf` (Date ↔ Date) — Prisma+Kysely canonical
8
-
9
- Reverts the 5.6.0 change that mapped `DateTime` to `DateFromInput` (a
10
- `Schema.Union(DateFromSelf, Date)` with `Encoded = Date | string`).
11
-
12
- **Why revert**: the dual-input Union pushed the boundary problem onto
13
- DA-layer consumers. Kysely's pg driver returns native `Date` instances,
14
- but `Selectable<X>.created_at` typed as `Date | string` forced every DA
15
- mapper that copies `result.created_at` into a contract type to either
16
- narrow manually (no cast-free path) or wrap the read in
17
- `Schema.decode(Selectable(X))` (heavy refactor across hundreds of sites).
18
-
19
- **Why DateFromSelf is correct**:
20
- - **Prisma docs**: _"Prisma Client returns all DateTime values as native
21
- JavaScript Date objects. ... DateTime values must be passed as Date
22
- objects, not strings, to avoid runtime errors."_
23
- - **Kysely docs**: idiomatic DateTime column is
24
- `created_at: ColumnType<Date, string | undefined, never>` — SELECT
25
- yields `Date`. _"TypeScript is a compile-time concept and cannot
26
- alter runtime JavaScript types. If your TypeScript definition for a
27
- column differs from the database's actual return type, the runtime
28
- type will not change automatically."_
29
- - **Effect Schema docs (Doc 10944)**: _"schemas should be defined such
30
- that encode + decode return the original value"_ — one Type, one
31
- Encoded per schema. The dual-boundary problem (DA Date ↔ Date vs
32
- RPC string ↔ Date) is solved by **two schemas** (one per boundary),
33
- not one Union. Doc 4312 (`@effect/sql/Model.Class`) shows this
34
- canonical variant pattern (`select`/`insert`/`update` vs
35
- `json`/`jsonCreate`/`jsonUpdate`).
36
-
37
- **For RPC/HTTP wire boundaries**: define a contract-layer schema that
38
- overrides date columns with `Schema.Date` (Encoded = string) before the
39
- RPC framework calls `Schema.decode`. This is the same pattern as
40
- `@effect/sql`'s `json` variants — one schema per boundary.
41
-
42
- **`DateFromInput` is still exported** from the package for consumers that
43
- specifically want the dual-input behavior at a single call site. The
44
- codegen just no longer auto-emits it for every DateTime column.
45
-
46
- **The Schema.Schema.Encoded fix in 5.7.0 stays** — that's still correct
47
- for join-table column exposure (`_product_tags.A`/`B`).
48
-
49
- **Migration**: most consumers benefit immediately (DA mappers stop
50
- seeing `Date | string`). For RPC contracts that previously didn't have
51
- a Date override (because they relied on `DateFromInput`), re-add a
52
- `Schema.extend` with `Schema.Date` overrides for date columns to keep
53
- wire decode working.
54
-
55
- ## 5.7.0
56
-
57
- ### Minor Changes
5
+ ### Major Changes
58
6
 
59
- - d272b99: fix: DB interface uses `Schema.Schema.Encoded` so Kysely sees real DB columns
60
-
61
- The generated `interface DB` previously emitted
62
- `<table>: Schema.Schema.Type<typeof X>`. For tables using `Schema.fromKey`
63
- (Prisma implicit M:N join tables, where TS field `product_id` maps to DB
64
- column `A`), the Type side has the **decoded** names. Kysely uses the TS
65
- interface as the SQL contract — it does not run the Effect schema decoder.
66
- So queries like `db.selectFrom('_product_tags').where('product_id', ...)`
67
- generated `WHERE product_id = ...` and Postgres rejected with
68
- `column _product_tags.product_id does not exist`.
69
-
70
- Fix: emit `Schema.Schema.Encoded<typeof X>` for every DB interface entry.
71
- Encoded is the on-the-wire / on-disk shape that matches Postgres. For
72
- regular tables `Type === Encoded`, no behavior change. For join tables,
73
- Kysely now sees `A`/`B` and emits valid SQL. Application code that wants
74
- the semantic field names runs the row through `Schema.decode(X)`.
75
-
76
- `ColumnType<S, I, U>` brand preserves `__select__`/`__insert__`/`__update__`
77
- phantoms on both sides, so `Insertable<X>`/`Updateable<X>` inference is
78
- unchanged.
79
-
80
- Adds `db-interface-sql-contract.test.ts` with three regression checks:
81
- 1. String-grep — every DB entry uses Encoded, none use Type.
82
- 2. Encoded-side preserves real Postgres column names for implicit M:N.
83
- 3. Kysely SQL compile — emitted SQL references the real `"A"` column,
84
- not the `product_id` decoded name. This catches the original bug
85
- structurally without needing a live database.
86
-
87
- **Migration**: most consumers need no changes. If a consumer overrode
88
- the generated DB interface entry to expose `A`/`B` directly (workaround
89
- for this bug), the override can now be removed and the generator will
90
- do the right thing.
91
-
92
- ## 5.6.0
7
+ - fde013c: Migrate to Effect 4 (beta).
93
8
 
94
- ### Minor Changes
9
+ **Breaking:** the `effect` peer dependency is now `^4.0.0-beta` (Effect 3 is no longer supported). Consumers must upgrade to `effect@^4.0.0-beta`.
95
10
 
96
- - bf7d87c: feat: DateTime columns now map to `DateFromInput` (dual-boundary Date schema)
97
-
98
- `DateTime` columns previously mapped to `Schema.DateFromSelf`
99
- (`Encoded = Date`), which broke RPC/HTTP wire decode where JSON-parsed
100
- input is a string. Now maps to a new exported `DateFromInput` schema:
101
- - **Type** = `Date` (runtime unchanged)
102
- - **Encoded** = `Date | string` (was `Date`)
103
-
104
- Defined as `Schema.Union(Schema.DateFromSelf, Schema.Date)`, so decode
105
- accepts native `Date` instances (Kysely DA layer pg driver returns Date)
106
- AND ISO strings (RPC/HTTP wire layer — JSON.parse output). One primitive
107
- serves both consumer boundaries; consumers no longer need parallel
108
- schemas or `Schema.extend` overrides for date columns.
109
-
110
- **Why minor (not major)**: existing public API behavior is preserved.
111
- `Selectable<T>` / `Insertable<T>` / `Updateable<T>` Type sides unchanged.
112
- Decode accepts MORE inputs (Date AND string), not fewer. Encode picks
113
- the first union member (`DateFromSelf`, identity) so Kysely-bound
114
- encode still produces Date instances — existing call sites keep working.
115
-
116
- **Why the change**: `DateFromSelf` optimized for the in-memory Kysely
117
- boundary; `Schema.Date` optimizes for the JSON wire boundary. Modern
118
- apps cross both with the same generated schemas. Picking either single
119
- primitive forced consumers to patch around it at one boundary.
120
- `DateFromInput` accepts both encoded shapes natively. Mirrors the
121
- `JsonValue` dual-boundary discipline already in this package
122
- (`Schema<JsonValue, JsonValue>` is wire-safe by construction).
123
-
124
- **Migration**: no code changes for typical consumers. If you imported
125
- `Schema.DateFromSelf` directly from generated `types.ts` in a way that
126
- depended on the literal symbol, switch to `DateFromInput` imported from
127
- `prisma-effect-kysely`.
128
-
129
- **Internal**: consolidated duplicated `PRISMA_TO_EFFECT_SCHEMA` /
130
- `PRISMA_SCALAR_MAP` constants. `src/effect/type.ts` now imports the
131
- canonical map from `src/utils/type-mappings.ts`.
11
+ What changed:
12
+ - **Runtime helpers** (`Selectable` / `Insertable` / `Updateable`) were reimplemented on Effect 4's public `Schema.Struct.fields` API instead of the removed `effect/SchemaAST` internals (Effect 4 reworked `SchemaAST`: `PropertySignature` is now 2-arg, structs are `Objects` nodes, `isTypeLiteral` is gone). Public signatures and the derived `Selectable<T>`/`Insertable<T>`/`Updateable<T>` types are unchanged.
13
+ - **Generated output** now emits Effect-4 schema source:
14
+ - `DateTime` → `Schema.Date` (still native `Date` on both sides — Effect 4's `Schema.Date` no longer coerces to string, replacing Effect 3's `Schema.DateFromSelf`).
15
+ - UUID fields → `Schema.String.check(Schema.isUUID())` (Effect 4 removed `Schema.UUID`).
16
+ - BigInt `Schema.BigInt` (native bigint encoding; replaces `Schema.BigIntFromSelf`).
17
+ - Enums `Schema.Enum(...)`; the internal native TS enum is suffixed with `Enum` when its name collides with the PascalCase const (Effect 4 forbids enum/const identifier merging).
18
+ - `@map` / implicit-M:N `A`/`B` column renames → struct-level `Schema.encodeKeys({ tsName: "db_name" })` (Effect 4 removed `Schema.propertySignature(...).pipe(Schema.fromKey(...))`).
19
+ - Scaffolded contract libraries now declare `effect: ^4.0.0-beta` as their peer dependency.
20
+ - Added a generator-output compile guard (`bun run test:emit`) that type-checks the emitted code against the installed Effect version.
132
21
 
133
22
  ## 5.5.0
134
23
 
package/README.md CHANGED
@@ -4,10 +4,34 @@ Prisma generator producing Effect Schema types with Kysely-compatible column met
4
4
 
5
5
  ## Install
6
6
 
7
+ This package's major version tracks the major version of its `effect` peer
8
+ dependency. Pick the line that matches your Effect version:
9
+
10
+ | Your Effect version | Install | npm dist-tag |
11
+ | ------------------- | ----------------------------------- | ------------ |
12
+ | Effect 3 (stable) | `bun add prisma-effect-kysely` | `latest` |
13
+ | Effect 4 (beta) | `bun add prisma-effect-kysely@next` | `next` |
14
+
7
15
  ```bash
16
+ # Effect 3 (current stable line)
8
17
  bun add prisma-effect-kysely
18
+
19
+ # Effect 4 beta — opt-in pre-release
20
+ bun add prisma-effect-kysely@next effect@beta
9
21
  ```
10
22
 
23
+ > **Effect 4 support is a pre-release.** It requires `effect@^4.0.0-beta` and is
24
+ > published under the `next` dist-tag, not `latest`. It is **tested against
25
+ > `effect@4.0.0-beta.68`**; later betas may introduce breaking Schema changes. A
26
+ > generator-output compile check (`bun run test:emit`) guards the emitted code
27
+ > against the installed Effect, but pin `effect` if you need stability during the
28
+ > beta. The `next` line will be promoted to `latest` when Effect 4 goes stable.
29
+ >
30
+ > Effect 4 and Effect 3 are not interchangeable: the generated output uses
31
+ > Effect-4-only Schema APIs (`Schema.Date`, `Schema.String.check(Schema.isUUID())`,
32
+ > `Schema.encodeKeys`, `Schema.Enum`, …). Stay on the `latest` line if you are on
33
+ > Effect 3.
34
+
11
35
  ## Setup
12
36
 
13
37
  ```prisma
@@ -26,18 +50,18 @@ npx prisma generate
26
50
  Three files: `enums.ts`, `types.ts`, `index.ts`.
27
51
 
28
52
  ```typescript
29
- import { Schema } from "effect";
30
- import { columnType, DateFromInput, generated, Selectable } from "prisma-effect-kysely";
53
+ import { Schema } from 'effect';
54
+ import { columnType, generated, Selectable } from 'prisma-effect-kysely';
31
55
 
32
56
  // Branded ID
33
- export const UserId = Schema.UUID.pipe(Schema.brand("UserId"));
57
+ export const UserId = Schema.String.check(Schema.isUUID()).pipe(Schema.brand('UserId'));
34
58
  export type UserId = typeof UserId.Type;
35
59
 
36
60
  // Model schema
37
61
  export const User = Schema.Struct({
38
- id: columnType(Schema.UUID, Schema.Never, Schema.Never),
62
+ id: columnType(UserId, Schema.Never, Schema.Never),
39
63
  email: Schema.String,
40
- createdAt: generated(DateFromInput),
64
+ createdAt: generated(Schema.Date),
41
65
  });
42
66
  export type User = typeof User;
43
67
 
@@ -73,20 +97,20 @@ Schema names are PascalCase regardless of Prisma model name (`session_preference
73
97
 
74
98
  ## Type Mappings
75
99
 
76
- | Prisma | Effect Schema |
77
- | ----------- | --------------------- |
78
- | String | `Schema.String` |
79
- | Int / Float | `Schema.Number` |
80
- | BigInt | `Schema.BigInt` |
81
- | Decimal | `Schema.String` |
82
- | Boolean | `Schema.Boolean` |
83
- | DateTime | `DateFromInput` |
84
- | Json | `JsonValue` |
85
- | Bytes | `Schema.Uint8Array` |
86
- | Enum | `Schema.Literal(...)` |
87
- | UUID | `Schema.UUID` |
88
-
89
- Arrays → `Schema.Array(t)`. Nullable → `Schema.NullOr(t)`. `DateFromInput` accepts `Date | string` on the encoded side; `JsonValue` is `Schema<JsonValue, JsonValue>`. Both are wire-safe (`JSON.parse` output decodes cleanly).
100
+ | Prisma | Effect Schema |
101
+ | ----------- | -------------------------------------- |
102
+ | String | `Schema.String` |
103
+ | Int / Float | `Schema.Number` |
104
+ | BigInt | `Schema.BigInt` |
105
+ | Decimal | `Schema.String` |
106
+ | Boolean | `Schema.Boolean` |
107
+ | DateTime | `Schema.Date` |
108
+ | Json | recursive `JsonValue` |
109
+ | Bytes | `Schema.Uint8Array` |
110
+ | Enum | `Schema.Enum(...)` |
111
+ | UUID | `Schema.String.check(Schema.isUUID())` |
112
+
113
+ Arrays → `Schema.Array(t)`. Nullable → `Schema.NullOr(t)`.
90
114
 
91
115
  ## UUID Detection
92
116
 
@@ -102,9 +126,9 @@ Use `@customType` in field docs to override Effect Schema:
102
126
 
103
127
  ```prisma
104
128
  model User {
105
- /// @customType(Schema.String.pipe(Schema.email()))
129
+ /// @customType(Schema.String.check(Schema.isMinLength(3)))
106
130
  email String @unique
107
- /// @customType(Schema.Number.pipe(Schema.positive()))
131
+ /// @customType(Schema.Number.check(Schema.isGreaterThan(0)))
108
132
  age Int
109
133
  }
110
134
  ```
@@ -113,28 +137,24 @@ Supported on all Prisma scalar types.
113
137
 
114
138
  ## Implicit M2M Join Tables
115
139
 
116
- Prisma columns `A`/`B` map to semantic snake_case fields via `Schema.fromKey`:
140
+ Prisma columns `A`/`B` map to semantic snake_case fields via `Schema.encodeKeys`:
117
141
 
118
142
  ```typescript
119
143
  export const ProductToProductTag = Schema.Struct({
120
- product_id: Schema.propertySignature(
121
- columnType(Schema.UUID, Schema.Never, Schema.Never)
122
- ).pipe(Schema.fromKey("A")),
123
- product_tag_id: Schema.propertySignature(
124
- columnType(Schema.UUID, Schema.Never, Schema.Never)
125
- ).pipe(Schema.fromKey("B")),
126
- });
144
+ product_id: columnType(ProductId, Schema.Never, Schema.Never),
145
+ product_tag_id: columnType(ProductTagId, Schema.Never, Schema.Never),
146
+ }).pipe(Schema.encodeKeys({ product_id: 'A', product_tag_id: 'B' }));
127
147
  ```
128
148
 
129
149
  ## Package Exports
130
150
 
131
- | Entry | Contents |
132
- | -------------------------------- | ----------------------------------------------------- |
133
- | `prisma-effect-kysely` | Type utilities + runtime helpers (default import) |
134
- | `prisma-effect-kysely/generator` | Prisma generator binary entry |
135
- | `prisma-effect-kysely/kysely` | `getSchemas`, `columnType`, `generated`, type utils |
136
- | `prisma-effect-kysely/error` | `NotFoundError`, `QueryError`, `QueryParseError`, ... |
137
- | `prisma-effect-kysely/runtime` | All runtime utilities |
151
+ | Entry | Contents |
152
+ | -------------------------------- | --------------------------------------------------- |
153
+ | `prisma-effect-kysely` | Type utilities + runtime helpers (default import) |
154
+ | `prisma-effect-kysely/generator` | Prisma generator binary entry |
155
+ | `prisma-effect-kysely/kysely` | `getSchemas`, `columnType`, `generated`, type utils |
156
+ | `prisma-effect-kysely/error` | `NotFoundError`, `QueryError`, `DatabaseError` |
157
+ | `prisma-effect-kysely/runtime` | All runtime utilities |
138
158
 
139
159
  ## Development
140
160
 
@@ -148,15 +168,28 @@ bun run prepublishOnly # lint + typecheck + test + build
148
168
 
149
169
  ## Releasing
150
170
 
151
- Uses [Changesets](https://github.com/changesets/changesets).
171
+ Uses [Changesets](https://github.com/changesets/changesets). Two lines run in
172
+ parallel:
152
173
 
153
- ```bash
154
- bun changeset # add changeset
155
- git add .changeset/ && git commit -m "docs: changeset"
156
- git push
157
- ```
174
+ - **Stable (`latest`)** — from `main`. Normal flow:
175
+
176
+ ```bash
177
+ bun changeset # add changeset
178
+ git add .changeset/ && git commit -m "docs: changeset"
179
+ git push # CI opens a "Version Packages" PR; merging publishes
180
+ ```
181
+
182
+ - **Pre-release (`next`)** — from the `release/next` branch, which carries
183
+ `.changeset/pre.json` (changesets pre mode, tag `next`). Pushing there versions
184
+ as `X.Y.Z-next.N` and `changeset publish` auto-routes those to the `next`
185
+ dist-tag (never `latest`). This is where Effect 4 support lives until Effect 4
186
+ is stable. When it stabilizes: run `changeset pre exit` on `release/next`,
187
+ merge into `main`, and the next release promotes it to `latest`.
158
188
 
159
- CI opens a "Version Packages" PR. Merging it publishes to npm, tags, and creates a GitHub release. Requires `NPM_TOKEN` repo secret.
189
+ The CI workflow (`.github/workflows/release.yml`) triggers on both branches and
190
+ uses the changesets action's `version` + `publish` inputs; `changeset publish`
191
+ selects the dist-tag from pre mode. Requires the `NPM_TOKEN` repo secret. Do not
192
+ enter pre mode on `main` — it blocks stable releases until you exit.
160
193
 
161
194
  ## License
162
195
 
@@ -1,9 +1,9 @@
1
1
  import type { DMMF } from '@prisma/generator-helper';
2
2
  /**
3
- * Generate TypeScript enum + Effect Schema.Enums wrapper
3
+ * Generate TypeScript enum + Effect Schema.Enum wrapper
4
4
  *
5
5
  * Output pattern:
6
- * - Native TS enum with SCREAMING_SNAKE_CASE (internal, for Schema.Enums)
6
+ * - Native TS enum with SCREAMING_SNAKE_CASE (internal, for Schema.Enum)
7
7
  * - PascalCase export IS the Schema (so it works in Schema.Struct)
8
8
  * - Type alias with same name (value + type pattern)
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"enum.d.ts","sourceRoot":"","sources":["../../src/effect/enum.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAKrD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,UAuB7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,aAAa,EAAE,UAMrE"}
1
+ {"version":3,"file":"enum.d.ts","sourceRoot":"","sources":["../../src/effect/enum.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAKrD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,UA0B7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,aAAa,EAAE,UAMrE"}
@@ -2,18 +2,21 @@ import { getEnumValueDbName } from '../prisma/enum.js';
2
2
  import { generateFileHeader } from '../utils/codegen.js';
3
3
  import { toPascalCase } from '../utils/naming.js';
4
4
  /**
5
- * Generate TypeScript enum + Effect Schema.Enums wrapper
5
+ * Generate TypeScript enum + Effect Schema.Enum wrapper
6
6
  *
7
7
  * Output pattern:
8
- * - Native TS enum with SCREAMING_SNAKE_CASE (internal, for Schema.Enums)
8
+ * - Native TS enum with SCREAMING_SNAKE_CASE (internal, for Schema.Enum)
9
9
  * - PascalCase export IS the Schema (so it works in Schema.Struct)
10
10
  * - Type alias with same name (value + type pattern)
11
11
  */
12
12
  export function generateEnumSchema(enumDef) {
13
- // Raw enum keeps original name (usually SCREAMING_SNAKE_CASE)
14
- const enumName = enumDef.name;
15
- // PascalCase name is exported as BOTH the Schema value AND the type
13
+ // PascalCase name is exported as BOTH the Schema value AND the type.
16
14
  const pascalName = toPascalCase(enumDef.name);
15
+ // The native TS enum keeps its original Prisma name (usually SCREAMING_SNAKE).
16
+ // But when that already equals the PascalCase const (e.g. `Role` -> `Role`),
17
+ // TypeScript forbids the enum/const identifier from merging, so suffix the
18
+ // enum with `Enum` (`Role` -> internal `RoleEnum`) to keep them distinct.
19
+ const enumName = enumDef.name === pascalName ? `${pascalName}Enum` : enumDef.name;
17
20
  // Generate native TypeScript enum members
18
21
  const enumMembers = enumDef.values
19
22
  .map((v) => {
@@ -28,7 +31,7 @@ export function generateEnumSchema(enumDef) {
28
31
  ${enumMembers}
29
32
  }
30
33
 
31
- export const ${pascalName} = Schema.Enums(${enumName});
34
+ export const ${pascalName} = Schema.Enum(${enumName});
32
35
  export type ${pascalName} = Schema.Schema.Type<typeof ${pascalName}>;`;
33
36
  }
34
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"enum.js","sourceRoot":"","sources":["../../src/effect/enum.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA2B;IAC5D,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9B,oEAAoE;IACpE,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAE9C,0CAA0C;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,KAAK,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,GAAG,CAAC;IACpC,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAC;IAEf,iDAAiD;IACjD,uEAAuE;IACvE,+DAA+D;IAC/D,OAAO,eAAe,QAAQ;EAC9B,WAAW;;;eAGE,UAAU,mBAAmB,QAAQ;cACtC,UAAU,gCAAgC,UAAU,IAAI,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAoC;IACpE,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,kCAAkC,CAAC;IACnD,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE/D,OAAO,GAAG,MAAM,OAAO,OAAO,OAAO,WAAW,EAAE,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"enum.js","sourceRoot":"","sources":["../../src/effect/enum.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA2B;IAC5D,qEAAqE;IACrE,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,+EAA+E;IAC/E,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAElF,0CAA0C;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM;SAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,KAAK,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,GAAG,CAAC;IACpC,CAAC,CAAC;SACD,IAAI,CAAC,KAAK,CAAC,CAAC;IAEf,iDAAiD;IACjD,uEAAuE;IACvE,+DAA+D;IAC/D,OAAO,eAAe,QAAQ;EAC9B,WAAW;;;eAGE,UAAU,kBAAkB,QAAQ;cACrC,UAAU,gCAAgC,UAAU,IAAI,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAoC;IACpE,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,kCAAkC,CAAC;IACnD,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAE/D,OAAO,GAAG,MAAM,OAAO,OAAO,OAAO,WAAW,EAAE,CAAC;AACrD,CAAC"}
@@ -17,7 +17,8 @@ export declare class EffectGenerator {
17
17
  generateBrandedIdSchema(model: DMMF.Model, fields: readonly DMMF.Field[]): string | null;
18
18
  /**
19
19
  * Determine the base Effect Schema type for an ID field.
20
- * UUID strings → Schema.UUID, integers → Schema.Int, bigints → Schema.BigIntFromSelf, all others → Schema.String
20
+ * UUID strings → Schema.String.check(Schema.isUUID()), integers → Schema.Int,
21
+ * bigints → Schema.BigInt, all others → Schema.String
21
22
  */
22
23
  private getIdBaseType;
23
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/effect/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAQ/E;;GAEG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI,CAAC,QAAQ;IAEhD;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,aAAa,EAAE;IAIlD;;;OAGG;IACH,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE;IAcxE;;;OAGG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;OAIG;IACH,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE;IAqBpE;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,OAAO;IAsBrC;;OAEG;IACH,wBAAwB,CAAC,UAAU,EAAE,aAAa,EAAE;CAGrD"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/effect/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAQ/E;;GAEG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI,CAAC,QAAQ;IAEhD;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,IAAI,CAAC,aAAa,EAAE;IAIlD;;;OAGG;IACH,uBAAuB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE;IAcxE;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;OAIG;IACH,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,KAAK,EAAE;IAoCpE;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,OAAO;IAoBrC;;OAEG;IACH,wBAAwB,CAAC,UAAU,EAAE,aAAa,EAAE;CAGrD"}
@@ -1,4 +1,4 @@
1
- import { buildKyselyFieldType } from '../kysely/type.js';
1
+ import { buildKyselyFieldType, fieldKeyMapping } from '../kysely/type.js';
2
2
  import { buildForeignKeyMap } from '../prisma/relation.js';
3
3
  import { isUuidField } from '../prisma/type.js';
4
4
  import { generateFileHeader } from '../utils/codegen.js';
@@ -37,15 +37,16 @@ export type ${name}Id = typeof ${name}Id.Type;`;
37
37
  }
38
38
  /**
39
39
  * Determine the base Effect Schema type for an ID field.
40
- * UUID strings → Schema.UUID, integers → Schema.Int, bigints → Schema.BigIntFromSelf, all others → Schema.String
40
+ * UUID strings → Schema.String.check(Schema.isUUID()), integers → Schema.Int,
41
+ * bigints → Schema.BigInt, all others → Schema.String
41
42
  */
42
43
  getIdBaseType(field) {
43
44
  if (isUuidField(field))
44
- return 'Schema.UUID';
45
+ return 'Schema.String.check(Schema.isUUID())';
45
46
  if (field.type === 'Int')
46
47
  return 'Schema.Int';
47
48
  if (field.type === 'BigInt')
48
- return 'Schema.BigIntFromSelf';
49
+ return 'Schema.BigInt';
49
50
  return 'Schema.String';
50
51
  }
51
52
  /**
@@ -56,19 +57,30 @@ export type ${name}Id = typeof ${name}Id.Type;`;
56
57
  generateModelSchema(model, fields) {
57
58
  const fkMap = buildForeignKeyMap(model, this.dmmf.datamodel.models);
58
59
  const name = toPascalCase(model.name);
60
+ // Collect @map renames; they are applied once as a struct-level encodeKeys
61
+ // (Effect 4 removed the per-field Schema.fromKey pattern).
62
+ const keyMappings = [];
59
63
  const fieldDefinitions = fields
60
64
  .map((field) => {
61
65
  // Get base Effect type
62
66
  const baseType = buildFieldType(field, this.dmmf, fkMap);
63
- // Apply Kysely helpers (columnType, generated) and @map directive
67
+ // Apply Kysely helpers (columnType, generated)
64
68
  // Pass model.name so @id fields use the model's branded ID type
65
69
  const fieldType = buildKyselyFieldType(baseType, field, model.name);
70
+ const mapping = fieldKeyMapping(field);
71
+ if (mapping)
72
+ keyMappings.push(mapping);
66
73
  return ` ${field.name}: ${fieldType}`;
67
74
  })
68
75
  .join(',\n');
76
+ const encodeKeys = keyMappings.length > 0
77
+ ? `.pipe(Schema.encodeKeys({ ${keyMappings
78
+ .map((m) => `${m.tsName}: "${m.dbName}"`)
79
+ .join(', ')} }))`
80
+ : '';
69
81
  return `export const ${name} = Schema.Struct({
70
82
  ${fieldDefinitions}
71
- });
83
+ })${encodeKeys};
72
84
  export type ${name} = typeof ${name};`;
73
85
  }
74
86
  /**
@@ -76,10 +88,8 @@ export type ${name} = typeof ${name};`;
76
88
  */
77
89
  generateTypesHeader(hasEnums) {
78
90
  const header = generateFileHeader();
79
- // Import runtime helpers from prisma-effect-kysely.
80
- // DateTime fields use Schema.DateFromSelf (Date Date), matching
81
- // Prisma's contract that DateTime values are native Date instances.
82
- // Decode through a Schema.Date contract schema at JSON wire boundaries.
91
+ // Import runtime helpers from prisma-effect-kysely
92
+ // columnType and generated are used for field type annotations
83
93
  const imports = [
84
94
  `import { Schema } from "effect";`,
85
95
  `import { columnType, generated, JsonValue } from "prisma-effect-kysely";`,
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/effect/generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/effect/generator.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@ import type { JoinTableInfo } from '../prisma/relation.js';
5
5
  *
6
6
  * Structure:
7
7
  * - Direct export with semantic snake_case field names
8
- * - Maps TypeScript names to database A/B columns using Schema.fromKey
8
+ * - Maps TypeScript names to database A/B columns using Schema.encodeKeys
9
9
  * - Uses columnType for read-only foreign keys (can't insert/update join table rows directly)
10
10
  * - No type exports - consumers use type utilities: Selectable<JoinTable>
11
11
  *
@@ -1 +1 @@
1
- {"version":3,"file":"join-table.d.ts","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,UA6BrF"}
1
+ {"version":3,"file":"join-table.d.ts","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG3D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,UA+BrF"}
@@ -4,7 +4,7 @@ import { toPascalCase, toSnakeCase } from '../utils/naming.js';
4
4
  *
5
5
  * Structure:
6
6
  * - Direct export with semantic snake_case field names
7
- * - Maps TypeScript names to database A/B columns using Schema.fromKey
7
+ * - Maps TypeScript names to database A/B columns using Schema.encodeKeys
8
8
  * - Uses columnType for read-only foreign keys (can't insert/update join table rows directly)
9
9
  * - No type exports - consumers use type utilities: Selectable<JoinTable>
10
10
  *
@@ -22,10 +22,12 @@ export function generateJoinTableSchema(joinTable, _dmmf) {
22
22
  // Reference branded ID schemas (e.g., ProductId, SellerId) generated earlier in the output
23
23
  const modelASchemaType = `${toPascalCase(modelA)}Id`;
24
24
  const modelBSchemaType = `${toPascalCase(modelB)}Id`;
25
- // Use columnType for read-only FK fields (can't insert/update join table rows directly)
26
- // Schema.propertySignature + Schema.fromKey maps TypeScript name to database column
27
- const columnAField = ` ${columnAFieldName}: Schema.propertySignature(columnType(${modelASchemaType}, Schema.Never, Schema.Never)).pipe(Schema.fromKey("A"))`;
28
- const columnBField = ` ${columnBFieldName}: Schema.propertySignature(columnType(${modelBSchemaType}, Schema.Never, Schema.Never)).pipe(Schema.fromKey("B"))`;
25
+ // Use columnType for read-only FK fields (can't insert/update join table rows directly).
26
+ // The struct uses semantic field names; Schema.encodeKeys renames them to the
27
+ // database A/B columns on the encoded side (Effect 4 replacement for the old
28
+ // Schema.propertySignature(...).pipe(Schema.fromKey(...)) pattern).
29
+ const columnAField = ` ${columnAFieldName}: columnType(${modelASchemaType}, Schema.Never, Schema.Never)`;
30
+ const columnBField = ` ${columnBFieldName}: columnType(${modelBSchemaType}, Schema.Never, Schema.Never)`;
29
31
  // Use PascalCase for exported name (consistent with regular models)
30
32
  const pascalName = toPascalCase(relationName);
31
33
  // Generate schema with semantic names mapped to A/B
@@ -35,7 +37,7 @@ export function generateJoinTableSchema(joinTable, _dmmf) {
35
37
  export const ${pascalName} = Schema.Struct({
36
38
  ${columnAField},
37
39
  ${columnBField},
38
- });
40
+ }).pipe(Schema.encodeKeys({ ${columnAFieldName}: "A", ${columnBFieldName}: "B" }));
39
41
  export type ${pascalName} = typeof ${pascalName};`;
40
42
  }
41
43
  //# sourceMappingURL=join-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"join-table.js","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAwB,EAAE,KAAoB;IACpF,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAE9D,4DAA4D;IAC5D,oEAAoE;IACpE,MAAM,gBAAgB,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;IACrD,MAAM,gBAAgB,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;IAErD,2FAA2F;IAC3F,MAAM,gBAAgB,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;IACrD,MAAM,gBAAgB,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;IAErD,wFAAwF;IACxF,oFAAoF;IACpF,MAAM,YAAY,GAAG,KAAK,gBAAgB,yCAAyC,gBAAgB,0DAA0D,CAAC;IAC9J,MAAM,YAAY,GAAG,KAAK,gBAAgB,yCAAyC,gBAAgB,0DAA0D,CAAC;IAE9J,oEAAoE;IACpE,MAAM,UAAU,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAE9C,oDAAoD;IACpD,OAAO,MAAM,SAAS;0BACE,MAAM,SAAS,MAAM;wBACvB,gBAAgB,KAAK,gBAAgB;eAC9C,UAAU;EACvB,YAAY;EACZ,YAAY;;cAEA,UAAU,aAAa,UAAU,GAAG,CAAC;AACnD,CAAC"}
1
+ {"version":3,"file":"join-table.js","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAwB,EAAE,KAAoB;IACpF,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAE9D,4DAA4D;IAC5D,oEAAoE;IACpE,MAAM,gBAAgB,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;IACrD,MAAM,gBAAgB,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;IAErD,2FAA2F;IAC3F,MAAM,gBAAgB,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;IACrD,MAAM,gBAAgB,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC;IAErD,yFAAyF;IACzF,8EAA8E;IAC9E,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,YAAY,GAAG,KAAK,gBAAgB,gBAAgB,gBAAgB,+BAA+B,CAAC;IAC1G,MAAM,YAAY,GAAG,KAAK,gBAAgB,gBAAgB,gBAAgB,+BAA+B,CAAC;IAE1G,oEAAoE;IACpE,MAAM,UAAU,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAE9C,oDAAoD;IACpD,OAAO,MAAM,SAAS;0BACE,MAAM,SAAS,MAAM;wBACvB,gBAAgB,KAAK,gBAAgB;eAC9C,UAAU;EACvB,YAAY;EACZ,YAAY;8BACgB,gBAAgB,UAAU,gBAAgB;cAC1D,UAAU,aAAa,UAAU,GAAG,CAAC;AACnD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAMrD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,EACnB,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,UAmC5B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,EACnB,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,UAgB5B"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AA4BrD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,EACnB,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,UAoC5B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,EACnB,KAAK,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,UAgB5B"}
@@ -1,7 +1,28 @@
1
1
  import { isListField, isRequiredField, isUuidField } from '../prisma/type.js';
2
2
  import { extractEffectTypeOverride } from '../utils/annotations.js';
3
3
  import { toPascalCase } from '../utils/naming.js';
4
- import { PRISMA_TO_EFFECT_SCHEMA as PRISMA_SCALAR_MAP } from '../utils/type-mappings.js';
4
+ /**
5
+ * Prisma scalar type mapping to Effect Schema types
6
+ * Uses const assertion to avoid type guards
7
+ *
8
+ * Note: DateTime uses Schema.Date so that:
9
+ * - Type = Date (runtime)
10
+ * - Encoded = Date (database)
11
+ * This allows Kysely to work with native Date objects directly.
12
+ * (In Effect 4, Schema.Date is the native-Date schema — no ISO string coercion;
13
+ * it replaces Effect 3's Schema.DateFromSelf.)
14
+ */
15
+ const PRISMA_SCALAR_MAP = {
16
+ String: 'Schema.String',
17
+ Int: 'Schema.Number',
18
+ Float: 'Schema.Number',
19
+ BigInt: 'Schema.BigInt',
20
+ Decimal: 'Schema.String', // For precision
21
+ Boolean: 'Schema.Boolean',
22
+ DateTime: 'Schema.Date', // Native Date type for Kysely compatibility
23
+ Json: 'JsonValue', // Recursive JSON type — prevents null absorption in NullOr
24
+ Bytes: 'Schema.Uint8Array',
25
+ };
5
26
  /**
6
27
  * Map Prisma field type to Effect Schema type
7
28
  * Priority order: annotation → FK branded → UUID → scalar → enum → unknown fallback
@@ -23,8 +44,9 @@ export function mapFieldToEffectType(field, dmmf, fkMap) {
23
44
  return `${toPascalCase(targetModel)}Id`;
24
45
  }
25
46
  // PRIORITY 3: Handle String type with UUID detection (non-FK UUIDs)
47
+ // Effect 4 removed Schema.UUID; UUID validation is now a string check.
26
48
  if (field.type === 'String' && isUuidField(field)) {
27
- return 'Schema.UUID';
49
+ return 'Schema.String.check(Schema.isUUID())';
28
50
  }
29
51
  // PRIORITY 4: Handle scalar types with const assertion lookup
30
52
  const scalarType = PRISMA_SCALAR_MAP[field.type];
@@ -1 +1 @@
1
- {"version":3,"file":"type.js","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,uBAAuB,IAAI,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEzF;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAiB,EACjB,IAAmB,EACnB,KAA2B;IAE3B,+CAA+C;IAC/C,MAAM,YAAY,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,8DAA8D;IAC9D,6EAA6E;IAC7E,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAE,CAAC;QAC3C,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED,oEAAoE;IACpE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,8DAA8D;IAC9D,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAsC,CAAC,CAAC;IACnF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,oCAAoC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,OAAO,EAAE,CAAC;QACZ,mDAAmD;QACnD,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,kCAAkC;IAClC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAiB,EACjB,IAAmB,EACnB,KAA2B;IAE3B,IAAI,QAAQ,GAAG,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAExD,gBAAgB;IAChB,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,QAAQ,GAAG,gBAAgB,QAAQ,GAAG,CAAC;IACzC,CAAC;IAED,wEAAwE;IACxE,yFAAyF;IACzF,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,QAAQ,GAAG,iBAAiB,QAAQ,GAAG,CAAC;IAC1C,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"type.js","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD;;;;;;;;;;GAUG;AACH,MAAM,iBAAiB,GAAG;IACxB,MAAM,EAAE,eAAe;IACvB,GAAG,EAAE,eAAe;IACpB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,eAAe;IACvB,OAAO,EAAE,eAAe,EAAE,gBAAgB;IAC1C,OAAO,EAAE,gBAAgB;IACzB,QAAQ,EAAE,aAAa,EAAE,4CAA4C;IACrE,IAAI,EAAE,WAAW,EAAE,2DAA2D;IAC9E,KAAK,EAAE,mBAAmB;CAClB,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAiB,EACjB,IAAmB,EACnB,KAA2B;IAE3B,+CAA+C;IAC/C,MAAM,YAAY,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,8DAA8D;IAC9D,6EAA6E;IAC7E,IAAI,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAE,CAAC;QAC3C,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC;IAC1C,CAAC;IAED,oEAAoE;IACpE,uEAAuE;IACvE,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO,sCAAsC,CAAC;IAChD,CAAC;IAED,8DAA8D;IAC9D,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAsC,CAAC,CAAC;IACnF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,oCAAoC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,OAAO,EAAE,CAAC;QACZ,mDAAmD;QACnD,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,kCAAkC;IAClC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAiB,EACjB,IAAmB,EACnB,KAA2B;IAE3B,IAAI,QAAQ,GAAG,oBAAoB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAExD,gBAAgB;IAChB,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,QAAQ,GAAG,gBAAgB,QAAQ,GAAG,CAAC;IACzC,CAAC;IAED,wEAAwE;IACxE,yFAAyF;IACzF,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,QAAQ,GAAG,iBAAiB,QAAQ,GAAG,CAAC;IAC1C,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}