prisma-effect-kysely 5.9.0 → 6.0.0-next.1
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.
- package/CHANGELOG.md +33 -141
- package/README.md +76 -43
- package/dist/effect/enum.d.ts +2 -2
- package/dist/effect/enum.d.ts.map +1 -1
- package/dist/effect/enum.js +9 -6
- package/dist/effect/enum.js.map +1 -1
- package/dist/effect/generator.d.ts +2 -1
- package/dist/effect/generator.d.ts.map +1 -1
- package/dist/effect/generator.js +20 -10
- package/dist/effect/generator.js.map +1 -1
- package/dist/effect/join-table.d.ts +5 -3
- package/dist/effect/join-table.d.ts.map +1 -1
- package/dist/effect/join-table.js +13 -8
- package/dist/effect/join-table.js.map +1 -1
- package/dist/effect/type.d.ts.map +1 -1
- package/dist/effect/type.js +24 -2
- package/dist/effect/type.js.map +1 -1
- package/dist/error/index.d.ts +55 -0
- package/dist/error/index.d.ts.map +1 -0
- package/dist/error/index.js +38 -0
- package/dist/error/index.js.map +1 -0
- package/dist/generator/config.d.ts +6 -6
- package/dist/generator/config.js +1 -1
- package/dist/generator/config.js.map +1 -1
- package/dist/generator/contract-scaffolder.d.ts +5 -5
- package/dist/generator/contract-scaffolder.js +2 -2
- package/dist/generator/contract-scaffolder.js.map +1 -1
- package/dist/kysely/helpers.d.ts +29 -39
- package/dist/kysely/helpers.d.ts.map +1 -1
- package/dist/kysely/helpers.js +183 -169
- package/dist/kysely/helpers.js.map +1 -1
- package/dist/kysely/type.d.ts +20 -27
- package/dist/kysely/type.d.ts.map +1 -1
- package/dist/kysely/type.js +21 -36
- package/dist/kysely/type.js.map +1 -1
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/utils/type-mappings.d.ts +8 -13
- package/dist/utils/type-mappings.d.ts.map +1 -1
- package/dist/utils/type-mappings.js +7 -12
- package/dist/utils/type-mappings.js.map +1 -1
- package/package.json +12 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,152 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 6.0.0-next.1
|
|
4
4
|
|
|
5
|
-
###
|
|
6
|
-
|
|
7
|
-
- 5f07c8f: fix: regular tables in DB interface use `Schema.Schema.Type`, join tables use `Schema.Schema.Encoded`
|
|
8
|
-
|
|
9
|
-
5.7.0 flipped the DB interface to `Schema.Schema.Encoded` for **all** tables to fix the join-table column-name bug (`_product_tags.product_id` was decoded-name; SQL needs `A`). That was the right fix for join tables but accidentally **stripped branded IDs** for regular tables — `Schema.Schema.Encoded<typeof X>` strips `Schema.brand(...)` because brands live on the Type side.
|
|
10
|
-
|
|
11
|
-
Concrete consequence: every Kysely consumer queried `result.seller_id: string` instead of `result.seller_id: string & Brand<"SellerId">`. Branded ID type safety silently disabled across the entire monorepo.
|
|
12
|
-
|
|
13
|
-
Fix: the two table categories need different treatment.
|
|
14
|
-
- **Regular tables**: `Schema.Schema.Type<typeof X>` — preserves branded IDs (`string & Brand<"SellerId">`) and the `ColumnType<S, I, U>` `__select__`/`__insert__`/`__update__` phantoms. Type === Encoded for column names anyway because regular tables don't use `Schema.fromKey`.
|
|
15
|
-
- **Join tables**: `Schema.Schema.Encoded<typeof X>` — only join tables use `Schema.fromKey('A')` to remap DB columns `A`/`B` to semantic names. Type would expose the decoded names that Kysely passes to SQL verbatim → "column does not exist". Encoded preserves real column names.
|
|
16
|
-
|
|
17
|
-
Effectively: pick the side that matches the _intended consumer view_. For non-`fromKey` tables, that's the Type side (richer info, brand info preserved). For `fromKey` tables, that's the Encoded side (matches DB).
|
|
18
|
-
|
|
19
|
-
**Migration**: regular-table consumers regain `Brand<...>` IDs immediately. Join-table consumers (`_product_tags.A`/`B` queries) unchanged from 5.7.0 — those still expose real DB column names.
|
|
20
|
-
|
|
21
|
-
## 5.8.0
|
|
22
|
-
|
|
23
|
-
### Minor Changes
|
|
5
|
+
### Patch Changes
|
|
24
6
|
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
yields `Date`. _"TypeScript is a compile-time concept and cannot
|
|
44
|
-
alter runtime JavaScript types. If your TypeScript definition for a
|
|
45
|
-
column differs from the database's actual return type, the runtime
|
|
46
|
-
type will not change automatically."_
|
|
47
|
-
- **Effect Schema docs (Doc 10944)**: _"schemas should be defined such
|
|
48
|
-
that encode + decode return the original value"_ — one Type, one
|
|
49
|
-
Encoded per schema. The dual-boundary problem (DA Date ↔ Date vs
|
|
50
|
-
RPC string ↔ Date) is solved by **two schemas** (one per boundary),
|
|
51
|
-
not one Union. Doc 4312 (`@effect/sql/Model.Class`) shows this
|
|
52
|
-
canonical variant pattern (`select`/`insert`/`update` vs
|
|
53
|
-
`json`/`jsonCreate`/`jsonUpdate`).
|
|
54
|
-
|
|
55
|
-
**For RPC/HTTP wire boundaries**: define a contract-layer schema that
|
|
56
|
-
overrides date columns with `Schema.Date` (Encoded = string) before the
|
|
57
|
-
RPC framework calls `Schema.decode`. This is the same pattern as
|
|
58
|
-
`@effect/sql`'s `json` variants — one schema per boundary.
|
|
59
|
-
|
|
60
|
-
**`DateFromInput` is still exported** from the package for consumers that
|
|
61
|
-
specifically want the dual-input behavior at a single call site. The
|
|
62
|
-
codegen just no longer auto-emits it for every DateTime column.
|
|
63
|
-
|
|
64
|
-
**The Schema.Schema.Encoded fix in 5.7.0 stays** — that's still correct
|
|
65
|
-
for join-table column exposure (`_product_tags.A`/`B`).
|
|
66
|
-
|
|
67
|
-
**Migration**: most consumers benefit immediately (DA mappers stop
|
|
68
|
-
seeing `Date | string`). For RPC contracts that previously didn't have
|
|
69
|
-
a Date override (because they relied on `DateFromInput`), re-add a
|
|
70
|
-
`Schema.extend` with `Schema.Date` overrides for date columns to keep
|
|
71
|
-
wire decode working.
|
|
72
|
-
|
|
73
|
-
## 5.7.0
|
|
7
|
+
- 5722a22: Fix Insertable/Updateable semantics surfaced by validation of the Effect 4 beta line:
|
|
8
|
+
- **`Insertable` now accepts an explicit `null` for nullable columns.** A
|
|
9
|
+
`Schema.NullOr(T)` field is optional on insert and retains `null` in its type,
|
|
10
|
+
so `{ col: null }` (set the column to NULL) decodes successfully — matching SQL
|
|
11
|
+
and Kysely's `Insertable`, which permit omit / value / explicit null. Previously
|
|
12
|
+
`null` was stripped and an explicit `null` was rejected at decode.
|
|
13
|
+
- **Implicit many-to-many join-table FK columns are now insertable.** They emit
|
|
14
|
+
`columnType(Id, Id, Never)` instead of `columnType(Id, Never, Never)`: the
|
|
15
|
+
foreign keys are provided on INSERT (you supply both keys when linking a row)
|
|
16
|
+
and read-only on UPDATE (a composite-PK join row is inserted/deleted, not
|
|
17
|
+
updated). Previously `Insertable<JoinTable>` resolved to an empty `{}`, making
|
|
18
|
+
join rows impossible to insert through the generated types.
|
|
19
|
+
- **Internal robustness:** Generated-field detection is gated on the `GeneratedId`
|
|
20
|
+
annotation rather than a bare `.from` property, so a `Schema.encodeKeys(...)`
|
|
21
|
+
transform nested as a struct field (which also exposes `.from`) is no longer
|
|
22
|
+
misclassified as a generated field.
|
|
23
|
+
|
|
24
|
+
## 6.0.0-next.0
|
|
74
25
|
|
|
75
|
-
###
|
|
26
|
+
### Major Changes
|
|
76
27
|
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
The generated `interface DB` previously emitted
|
|
80
|
-
`<table>: Schema.Schema.Type<typeof X>`. For tables using `Schema.fromKey`
|
|
81
|
-
(Prisma implicit M:N join tables, where TS field `product_id` maps to DB
|
|
82
|
-
column `A`), the Type side has the **decoded** names. Kysely uses the TS
|
|
83
|
-
interface as the SQL contract — it does not run the Effect schema decoder.
|
|
84
|
-
So queries like `db.selectFrom('_product_tags').where('product_id', ...)`
|
|
85
|
-
generated `WHERE product_id = ...` and Postgres rejected with
|
|
86
|
-
`column _product_tags.product_id does not exist`.
|
|
87
|
-
|
|
88
|
-
Fix: emit `Schema.Schema.Encoded<typeof X>` for every DB interface entry.
|
|
89
|
-
Encoded is the on-the-wire / on-disk shape that matches Postgres. For
|
|
90
|
-
regular tables `Type === Encoded`, no behavior change. For join tables,
|
|
91
|
-
Kysely now sees `A`/`B` and emits valid SQL. Application code that wants
|
|
92
|
-
the semantic field names runs the row through `Schema.decode(X)`.
|
|
93
|
-
|
|
94
|
-
`ColumnType<S, I, U>` brand preserves `__select__`/`__insert__`/`__update__`
|
|
95
|
-
phantoms on both sides, so `Insertable<X>`/`Updateable<X>` inference is
|
|
96
|
-
unchanged.
|
|
97
|
-
|
|
98
|
-
Adds `db-interface-sql-contract.test.ts` with three regression checks:
|
|
99
|
-
1. String-grep — every DB entry uses Encoded, none use Type.
|
|
100
|
-
2. Encoded-side preserves real Postgres column names for implicit M:N.
|
|
101
|
-
3. Kysely SQL compile — emitted SQL references the real `"A"` column,
|
|
102
|
-
not the `product_id` decoded name. This catches the original bug
|
|
103
|
-
structurally without needing a live database.
|
|
104
|
-
|
|
105
|
-
**Migration**: most consumers need no changes. If a consumer overrode
|
|
106
|
-
the generated DB interface entry to expose `A`/`B` directly (workaround
|
|
107
|
-
for this bug), the override can now be removed and the generator will
|
|
108
|
-
do the right thing.
|
|
109
|
-
|
|
110
|
-
## 5.6.0
|
|
28
|
+
- fde013c: Migrate to Effect 4 (beta).
|
|
111
29
|
|
|
112
|
-
|
|
30
|
+
**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`.
|
|
113
31
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
AND ISO strings (RPC/HTTP wire layer — JSON.parse output). One primitive
|
|
125
|
-
serves both consumer boundaries; consumers no longer need parallel
|
|
126
|
-
schemas or `Schema.extend` overrides for date columns.
|
|
127
|
-
|
|
128
|
-
**Why minor (not major)**: existing public API behavior is preserved.
|
|
129
|
-
`Selectable<T>` / `Insertable<T>` / `Updateable<T>` Type sides unchanged.
|
|
130
|
-
Decode accepts MORE inputs (Date AND string), not fewer. Encode picks
|
|
131
|
-
the first union member (`DateFromSelf`, identity) so Kysely-bound
|
|
132
|
-
encode still produces Date instances — existing call sites keep working.
|
|
133
|
-
|
|
134
|
-
**Why the change**: `DateFromSelf` optimized for the in-memory Kysely
|
|
135
|
-
boundary; `Schema.Date` optimizes for the JSON wire boundary. Modern
|
|
136
|
-
apps cross both with the same generated schemas. Picking either single
|
|
137
|
-
primitive forced consumers to patch around it at one boundary.
|
|
138
|
-
`DateFromInput` accepts both encoded shapes natively. Mirrors the
|
|
139
|
-
`JsonValue` dual-boundary discipline already in this package
|
|
140
|
-
(`Schema<JsonValue, JsonValue>` is wire-safe by construction).
|
|
141
|
-
|
|
142
|
-
**Migration**: no code changes for typical consumers. If you imported
|
|
143
|
-
`Schema.DateFromSelf` directly from generated `types.ts` in a way that
|
|
144
|
-
depended on the literal symbol, switch to `DateFromInput` imported from
|
|
145
|
-
`prisma-effect-kysely`.
|
|
146
|
-
|
|
147
|
-
**Internal**: consolidated duplicated `PRISMA_TO_EFFECT_SCHEMA` /
|
|
148
|
-
`PRISMA_SCALAR_MAP` constants. `src/effect/type.ts` now imports the
|
|
149
|
-
canonical map from `src/utils/type-mappings.ts`.
|
|
32
|
+
What changed:
|
|
33
|
+
- **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.
|
|
34
|
+
- **Generated output** now emits Effect-4 schema source:
|
|
35
|
+
- `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`).
|
|
36
|
+
- UUID fields → `Schema.String.check(Schema.isUUID())` (Effect 4 removed `Schema.UUID`).
|
|
37
|
+
- BigInt → `Schema.BigInt` (native bigint encoding; replaces `Schema.BigIntFromSelf`).
|
|
38
|
+
- 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).
|
|
39
|
+
- `@map` / implicit-M:N `A`/`B` column renames → struct-level `Schema.encodeKeys({ tsName: "db_name" })` (Effect 4 removed `Schema.propertySignature(...).pipe(Schema.fromKey(...))`).
|
|
40
|
+
- Scaffolded contract libraries now declare `effect: ^4.0.0-beta` as their peer dependency.
|
|
41
|
+
- Added a generator-output compile guard (`bun run test:emit`) that type-checks the emitted code against the installed Effect version.
|
|
150
42
|
|
|
151
43
|
## 5.5.0
|
|
152
44
|
|
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
|
|
30
|
-
import { columnType,
|
|
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.
|
|
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(
|
|
62
|
+
id: columnType(UserId, Schema.Never, Schema.Never),
|
|
39
63
|
email: Schema.String,
|
|
40
|
-
createdAt: generated(
|
|
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 | `
|
|
84
|
-
| Json | `JsonValue`
|
|
85
|
-
| Bytes | `Schema.Uint8Array`
|
|
86
|
-
| Enum | `Schema.
|
|
87
|
-
| UUID | `Schema.
|
|
88
|
-
|
|
89
|
-
Arrays → `Schema.Array(t)`. Nullable → `Schema.NullOr(t)`.
|
|
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.
|
|
129
|
+
/// @customType(Schema.String.check(Schema.isMinLength(3)))
|
|
106
130
|
email String @unique
|
|
107
|
-
/// @customType(Schema.Number.
|
|
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.
|
|
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.
|
|
121
|
-
|
|
122
|
-
|
|
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, ProductId, Schema.Never),
|
|
145
|
+
product_tag_id: columnType(ProductTagId, ProductTagId, 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`, `
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
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
|
|
package/dist/effect/enum.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { DMMF } from '@prisma/generator-helper';
|
|
2
2
|
/**
|
|
3
|
-
* Generate TypeScript enum + Effect Schema.
|
|
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.
|
|
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,
|
|
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"}
|
package/dist/effect/enum.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
//
|
|
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.
|
|
34
|
+
export const ${pascalName} = Schema.Enum(${enumName});
|
|
32
35
|
export type ${pascalName} = Schema.Schema.Type<typeof ${pascalName}>;`;
|
|
33
36
|
}
|
|
34
37
|
/**
|
package/dist/effect/enum.js.map
CHANGED
|
@@ -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,
|
|
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.
|
|
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
|
|
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"}
|
package/dist/effect/generator.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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)
|
|
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
|
-
//
|
|
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":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../src/effect/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,14 +5,16 @@ 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.
|
|
9
|
-
* - Uses columnType
|
|
8
|
+
* - Maps TypeScript names to database A/B columns using Schema.encodeKeys
|
|
9
|
+
* - Uses columnType(Id, Id, Never) for the FK columns: provided on INSERT (you
|
|
10
|
+
* supply both foreign keys when linking a row) but read-only on UPDATE — a
|
|
11
|
+
* composite-PK join row is inserted or deleted, never updated in place
|
|
10
12
|
* - No type exports - consumers use type utilities: Selectable<JoinTable>
|
|
11
13
|
*
|
|
12
14
|
* Example:
|
|
13
15
|
* - Database columns: A, B (Prisma requirement for implicit many-to-many)
|
|
14
16
|
* - TypeScript fields: product_id, product_tag_id (semantic names)
|
|
15
|
-
* - Types: columnType(ProductId,
|
|
17
|
+
* - Types: columnType(ProductId, ProductId, Schema.Never) (insertable, read-only on update, branded)
|
|
16
18
|
*/
|
|
17
19
|
export declare function generateJoinTableSchema(joinTable: JoinTableInfo, _dmmf: DMMF.Document): string;
|
|
18
20
|
//# sourceMappingURL=join-table.d.ts.map
|
|
@@ -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
|
|
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;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,UAgCrF"}
|
|
@@ -4,14 +4,16 @@ 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.
|
|
8
|
-
* - Uses columnType
|
|
7
|
+
* - Maps TypeScript names to database A/B columns using Schema.encodeKeys
|
|
8
|
+
* - Uses columnType(Id, Id, Never) for the FK columns: provided on INSERT (you
|
|
9
|
+
* supply both foreign keys when linking a row) but read-only on UPDATE — a
|
|
10
|
+
* composite-PK join row is inserted or deleted, never updated in place
|
|
9
11
|
* - No type exports - consumers use type utilities: Selectable<JoinTable>
|
|
10
12
|
*
|
|
11
13
|
* Example:
|
|
12
14
|
* - Database columns: A, B (Prisma requirement for implicit many-to-many)
|
|
13
15
|
* - TypeScript fields: product_id, product_tag_id (semantic names)
|
|
14
|
-
* - Types: columnType(ProductId,
|
|
16
|
+
* - Types: columnType(ProductId, ProductId, Schema.Never) (insertable, read-only on update, branded)
|
|
15
17
|
*/
|
|
16
18
|
export function generateJoinTableSchema(joinTable, _dmmf) {
|
|
17
19
|
const { tableName, relationName, modelA, modelB } = joinTable;
|
|
@@ -22,10 +24,13 @@ export function generateJoinTableSchema(joinTable, _dmmf) {
|
|
|
22
24
|
// Reference branded ID schemas (e.g., ProductId, SellerId) generated earlier in the output
|
|
23
25
|
const modelASchemaType = `${toPascalCase(modelA)}Id`;
|
|
24
26
|
const modelBSchemaType = `${toPascalCase(modelB)}Id`;
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
// columnType(Id, Id, Never): the FK is supplied on INSERT and read-only on
|
|
28
|
+
// UPDATE (composite-PK join rows are inserted/deleted, not updated).
|
|
29
|
+
// The struct uses semantic field names; Schema.encodeKeys renames them to the
|
|
30
|
+
// database A/B columns on the encoded side (Effect 4 replacement for the old
|
|
31
|
+
// Schema.propertySignature(...).pipe(Schema.fromKey(...)) pattern).
|
|
32
|
+
const columnAField = ` ${columnAFieldName}: columnType(${modelASchemaType}, ${modelASchemaType}, Schema.Never)`;
|
|
33
|
+
const columnBField = ` ${columnBFieldName}: columnType(${modelBSchemaType}, ${modelBSchemaType}, Schema.Never)`;
|
|
29
34
|
// Use PascalCase for exported name (consistent with regular models)
|
|
30
35
|
const pascalName = toPascalCase(relationName);
|
|
31
36
|
// Generate schema with semantic names mapped to A/B
|
|
@@ -35,7 +40,7 @@ export function generateJoinTableSchema(joinTable, _dmmf) {
|
|
|
35
40
|
export const ${pascalName} = Schema.Struct({
|
|
36
41
|
${columnAField},
|
|
37
42
|
${columnBField},
|
|
38
|
-
});
|
|
43
|
+
}).pipe(Schema.encodeKeys({ ${columnAFieldName}: "A", ${columnBFieldName}: "B" }));
|
|
39
44
|
export type ${pascalName} = typeof ${pascalName};`;
|
|
40
45
|
}
|
|
41
46
|
//# 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
|
|
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;;;;;;;;;;;;;;;GAeG;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,2EAA2E;IAC3E,qEAAqE;IACrE,8EAA8E;IAC9E,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,YAAY,GAAG,KAAK,gBAAgB,gBAAgB,gBAAgB,KAAK,gBAAgB,iBAAiB,CAAC;IACjH,MAAM,YAAY,GAAG,KAAK,gBAAgB,gBAAgB,gBAAgB,KAAK,gBAAgB,iBAAiB,CAAC;IAEjH,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"}
|