prisma-effect-kysely 1.11.0 → 1.13.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.
- package/CHANGELOG.md +89 -16
- package/dist/effect/join-table.d.ts.map +1 -1
- package/dist/effect/type.d.ts +1 -1
- package/dist/effect/type.d.ts.map +1 -1
- package/dist/effect/type.js +18 -12
- package/dist/effect/type.js.map +1 -1
- package/dist/generator/config.d.ts +58 -0
- package/dist/generator/config.d.ts.map +1 -0
- package/dist/generator/config.js +109 -0
- package/dist/generator/config.js.map +1 -0
- package/dist/generator/contract-scaffolder.d.ts +45 -0
- package/dist/generator/contract-scaffolder.d.ts.map +1 -0
- package/dist/generator/contract-scaffolder.js +244 -0
- package/dist/generator/contract-scaffolder.js.map +1 -0
- package/dist/generator/domain-detector.d.ts +50 -0
- package/dist/generator/domain-detector.d.ts.map +1 -0
- package/dist/generator/domain-detector.js +187 -0
- package/dist/generator/domain-detector.js.map +1 -0
- package/dist/generator/orchestrator.d.ts +24 -4
- package/dist/generator/orchestrator.d.ts.map +1 -1
- package/dist/generator/orchestrator.js +124 -16
- package/dist/generator/orchestrator.js.map +1 -1
- package/dist/kysely/helpers.d.ts +5 -1
- package/dist/kysely/helpers.d.ts.map +1 -1
- package/dist/kysely/helpers.js +54 -27
- package/dist/kysely/helpers.js.map +1 -1
- package/dist/kysely/type.d.ts.map +1 -1
- package/dist/utils/annotations.d.ts.map +1 -1
- package/dist/utils/codegen.d.ts.map +1 -1
- package/dist/utils/naming.d.ts.map +1 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.13.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat: use Schema.DateFromSelf for native Date types
|
|
8
|
+
|
|
9
|
+
BREAKING CHANGE: DateTime fields now use Schema.DateFromSelf instead of Schema.Date
|
|
10
|
+
- DateTime fields now encode to native Date objects instead of ISO strings
|
|
11
|
+
- This enables Kysely to work with native Date objects directly without requiring `.toISOString()` conversions
|
|
12
|
+
- Added Effect Schema validation for generator config and scaffold results
|
|
13
|
+
- Removed type assertions in favor of strict Schema validation
|
|
14
|
+
- Added multi-domain support with contract library scaffolding
|
|
15
|
+
|
|
3
16
|
All notable changes to this project will be documented in this file.
|
|
4
17
|
|
|
5
18
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
@@ -10,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
10
23
|
### Fixed
|
|
11
24
|
|
|
12
25
|
#### Dependency Configuration
|
|
26
|
+
|
|
13
27
|
- **Fixed Effect as peer dependency** to prevent version conflicts and follow best practices
|
|
14
28
|
- **Problem**: `effect` was listed as a regular dependency, causing potential version conflicts in user projects
|
|
15
29
|
- **Solution**: Moved `effect` to `peerDependencies` (required, not optional)
|
|
@@ -23,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
23
37
|
### Removed
|
|
24
38
|
|
|
25
39
|
#### Unused Dependencies
|
|
40
|
+
|
|
26
41
|
- **Removed `@prisma/client` and `@prisma/dmmf`** from dependencies
|
|
27
42
|
- **Analysis**: Code analysis revealed these packages are never imported in the codebase
|
|
28
43
|
- **Impact**: Smaller package size, cleaner dependency tree
|
|
@@ -30,7 +45,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
30
45
|
### Changed
|
|
31
46
|
|
|
32
47
|
#### Package Structure
|
|
48
|
+
|
|
33
49
|
**Before:**
|
|
50
|
+
|
|
34
51
|
```json
|
|
35
52
|
"dependencies": {
|
|
36
53
|
"@prisma/client": "6.16.3",
|
|
@@ -42,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
42
59
|
```
|
|
43
60
|
|
|
44
61
|
**After:**
|
|
62
|
+
|
|
45
63
|
```json
|
|
46
64
|
"dependencies": {
|
|
47
65
|
"@prisma/generator-helper": "^6.17.0",
|
|
@@ -56,14 +74,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
56
74
|
### Migration Guide
|
|
57
75
|
|
|
58
76
|
**For New Users:**
|
|
77
|
+
|
|
59
78
|
- Install Effect explicitly: `npm install effect` or `pnpm install effect`
|
|
60
79
|
|
|
61
80
|
**For Existing Users:**
|
|
81
|
+
|
|
62
82
|
- If you already have `effect` installed: No action needed
|
|
63
83
|
- If you don't have `effect`: Run `npm install effect` or `pnpm install effect`
|
|
64
84
|
- npm 7+ will automatically install peer dependencies
|
|
65
85
|
|
|
66
86
|
**Benefits:**
|
|
87
|
+
|
|
67
88
|
- ✅ Prevents Effect version conflicts between your project and the generator
|
|
68
89
|
- ✅ You control which Effect version to use
|
|
69
90
|
- ✅ Smaller package size (removed unused dependencies)
|
|
@@ -74,6 +95,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
74
95
|
### Fixed
|
|
75
96
|
|
|
76
97
|
#### TypeScript Schema [TypeId] Preservation Bug
|
|
98
|
+
|
|
77
99
|
- **Fixed `generated()` and `columnType()` helpers losing Schema [TypeId] symbol**
|
|
78
100
|
- **Problem**: Helpers returned result of `.annotations()` directly, causing TypeScript compilation errors in generated code: `Property '[TypeId]' is missing in type 'typeof Date$'`
|
|
79
101
|
- **Root Cause**: `.annotations()` doesn't automatically preserve Schema type for TypeScript's type system without explicit wrapping
|
|
@@ -88,6 +110,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
88
110
|
### Added
|
|
89
111
|
|
|
90
112
|
#### Enhanced Test Coverage for Type Safety
|
|
113
|
+
|
|
91
114
|
- **Added TypeScript compile-time validation tests** to prevent future regressions
|
|
92
115
|
- Type assertions that fail at compile-time if Schema types lose [TypeId]
|
|
93
116
|
- Runtime validation using `Schema.isSchema()` checks
|
|
@@ -103,16 +126,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
103
126
|
### Technical Details
|
|
104
127
|
|
|
105
128
|
**Why the Bug Occurred**:
|
|
129
|
+
|
|
106
130
|
- Effect Schema's `.annotations()` method creates a new schema with modified annotations
|
|
107
131
|
- TypeScript's type inference doesn't automatically preserve the `Schema<T>` type with its `[TypeId]` symbol
|
|
108
132
|
- Without `Schema.asSchema()` wrapper, TypeScript sees the result as a plain object losing Schema type information
|
|
109
133
|
|
|
110
134
|
**Prevention Strategy**:
|
|
135
|
+
|
|
111
136
|
- Always use explicit return types for functions returning schemas
|
|
112
137
|
- Always wrap `.annotations()` results with `Schema.asSchema()`
|
|
113
138
|
- Include both compile-time type assertions AND runtime validation in tests
|
|
114
139
|
|
|
115
140
|
**Example Fix**:
|
|
141
|
+
|
|
116
142
|
```typescript
|
|
117
143
|
// Before (incorrect):
|
|
118
144
|
export const generated = <T>(schema: Schema.Schema<T>) => {
|
|
@@ -130,6 +156,7 @@ export const generated = <T>(schema: Schema.Schema<T>): Schema.Schema<T> => {
|
|
|
130
156
|
### Fixed
|
|
131
157
|
|
|
132
158
|
#### TypeScript Type Inference for Generated Fields - Explicit Omit Types
|
|
159
|
+
|
|
133
160
|
- **Generate explicit Insert type definitions using TypeScript's Omit utility for compile-time type safety**
|
|
134
161
|
- **Problem**: v1.8.4 fixed runtime behavior (generated fields correctly omitted from Insertable schema), but TypeScript's `Schema.Schema.Type` inference couldn't see runtime AST field filtering, causing all fields to appear in Insert types
|
|
135
162
|
- **Root Cause**: TypeScript's structural type inference works on static schema structure; runtime AST transformations are invisible to the type system
|
|
@@ -145,6 +172,7 @@ export const generated = <T>(schema: Schema.Schema<T>): Schema.Schema<T> => {
|
|
|
145
172
|
- Non-ID fields with `@default` (e.g., `@default(now())`)
|
|
146
173
|
- Fields with `@updatedAt` directive (auto-managed by database)
|
|
147
174
|
- **Example**:
|
|
175
|
+
|
|
148
176
|
```typescript
|
|
149
177
|
// Prisma schema:
|
|
150
178
|
model User {
|
|
@@ -173,6 +201,7 @@ export const generated = <T>(schema: Schema.Schema<T>): Schema.Schema<T> => {
|
|
|
173
201
|
name: 'John Doe'
|
|
174
202
|
};
|
|
175
203
|
```
|
|
204
|
+
|
|
176
205
|
- **Implementation**:
|
|
177
206
|
- Added `getOmittedInsertFields()` helper in `src/effect/generator.ts` to identify fields during code generation
|
|
178
207
|
- Uses DMMF properties: `hasDefaultValue` and `isUpdatedAt`
|
|
@@ -182,6 +211,7 @@ export const generated = <T>(schema: Schema.Schema<T>): Schema.Schema<T> => {
|
|
|
182
211
|
- Tests: `src/__tests__/type-inference-generated.test.ts` (10 new tests, all passing)
|
|
183
212
|
|
|
184
213
|
### Technical Details
|
|
214
|
+
|
|
185
215
|
- **Architecture**: Explicit type generation (industry standard for code generators)
|
|
186
216
|
- **Rationale**: TypeScript's structural type inference works on static schema structure; runtime AST transformations are invisible to the type system
|
|
187
217
|
- **Not a Workaround**: Standard practice when type inference can't capture runtime behavior (same approach as Prisma Client, Drizzle ORM, tRPC)
|
|
@@ -191,7 +221,9 @@ export const generated = <T>(schema: Schema.Schema<T>): Schema.Schema<T> => {
|
|
|
191
221
|
- **Type Safety Guarantee**: Models without generated fields continue to use plain `Schema.Schema.Type` (no unnecessary `Omit`)
|
|
192
222
|
|
|
193
223
|
### Breaking Changes
|
|
224
|
+
|
|
194
225
|
None - This is a non-breaking enhancement. The change is purely additive at the type level:
|
|
226
|
+
|
|
195
227
|
- Runtime behavior unchanged from v1.8.4
|
|
196
228
|
- Generated schemas remain the same
|
|
197
229
|
- Only TypeScript type definitions become more restrictive (catching bugs earlier)
|
|
@@ -201,6 +233,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
201
233
|
### Fixed
|
|
202
234
|
|
|
203
235
|
#### Native @effect/sql Pattern for Generated Fields
|
|
236
|
+
|
|
204
237
|
- **Implemented native field filtering for `generated()` fields following @effect/sql Model.Generated pattern**
|
|
205
238
|
- **Problem**: Generated fields (those with `@default` in Prisma schema) were incorrectly made optional in Insertable schema using `Union(T, Undefined)`, which doesn't properly reflect TypeScript optionality and doesn't follow Effect ecosystem patterns
|
|
206
239
|
- **Solution**: OMIT generated fields entirely from Insertable schema (not make them optional) following @effect/sql's `Model.Generated` pattern
|
|
@@ -217,6 +250,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
217
250
|
- Respects TypeScript optionality semantics (property optional `?:` vs value optional `| undefined`)
|
|
218
251
|
- Cleaner implementation with fewer special cases
|
|
219
252
|
- **Example**:
|
|
253
|
+
|
|
220
254
|
```typescript
|
|
221
255
|
// Prisma schema:
|
|
222
256
|
model Agent {
|
|
@@ -238,6 +272,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
238
272
|
// Insert only requires 'name' - generated fields completely absent
|
|
239
273
|
const insert: AgentInsert = { name: 'test' };
|
|
240
274
|
```
|
|
275
|
+
|
|
241
276
|
- **Test Coverage**: 15 tests passing including comprehensive runtime validation and AST structure verification
|
|
242
277
|
- Location: `src/kysely/helpers.ts:43-119, 188-224`
|
|
243
278
|
- Tests: `src/__tests__/kysely-helpers.test.ts:186-283`
|
|
@@ -245,21 +280,28 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
245
280
|
### Known Limitations
|
|
246
281
|
|
|
247
282
|
#### TypeScript Type Inference for Insertable Types
|
|
283
|
+
|
|
248
284
|
- **TypeScript's `Schema.Schema.Type` inference still includes all fields in Insert types**
|
|
249
285
|
- **Issue**: While runtime validation correctly omits generated fields, TypeScript type inference from `Schema.Schema.Type<typeof Model.Insertable>` cannot see runtime AST field filtering and still infers all fields as required
|
|
250
286
|
- **Root Cause**: TypeScript's structural type inference works on the base schema structure before runtime transformations
|
|
251
287
|
- **Workaround**: Use explicit type annotations or runtime validation (Effect Schema will filter out extra fields)
|
|
252
288
|
- **Planned Fix**: Update code generator (`src/effect/generator.ts`) to create explicit TypeScript type definitions using `Omit` utility type:
|
|
289
|
+
|
|
253
290
|
```typescript
|
|
254
291
|
// Current:
|
|
255
292
|
export type AgentInsert = Schema.Schema.Type<typeof Agent.Insertable>;
|
|
256
293
|
|
|
257
294
|
// Planned:
|
|
258
|
-
export type AgentInsert = Omit<
|
|
295
|
+
export type AgentInsert = Omit<
|
|
296
|
+
Schema.Schema.Type<typeof Agent.Insertable>,
|
|
297
|
+
'id' | 'session_id'
|
|
298
|
+
>;
|
|
259
299
|
```
|
|
300
|
+
|
|
260
301
|
- **Status**: Code generation fix planned for v1.9.0
|
|
261
302
|
|
|
262
303
|
### Technical Details
|
|
304
|
+
|
|
263
305
|
- **Quality Assurance**: All 15 kysely-helpers tests passing, zero TypeScript errors in implementation
|
|
264
306
|
- **Test Approach**: TDD (Test-Driven Development) - wrote failing tests first, then implemented to make them pass
|
|
265
307
|
- **Research**: Validated approach against @effect/sql's `Model.Generated` pattern (official Effect ecosystem standard)
|
|
@@ -271,6 +313,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
271
313
|
### Added
|
|
272
314
|
|
|
273
315
|
#### Semantic Join Table Column Names
|
|
316
|
+
|
|
274
317
|
- **Generated join tables now use semantic snake_case field names** instead of Prisma's generic A/B columns
|
|
275
318
|
- **Problem**: Prisma's implicit M2M join tables use non-semantic `A` and `B` column names, causing poor developer experience and forcing developers to remember alphabetical model ordering
|
|
276
319
|
- **Solution**: Map semantic names like `product_id`, `product_tag_id` to actual database columns using Effect Schema's `propertySignature` with `fromKey`
|
|
@@ -280,6 +323,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
280
323
|
- Type-safe bidirectional transformation (encode/decode)
|
|
281
324
|
- Follows snake_case convention for database identifiers (Prisma best practice)
|
|
282
325
|
- **Example**:
|
|
326
|
+
|
|
283
327
|
```typescript
|
|
284
328
|
// Before (v1.8.2):
|
|
285
329
|
export const _ProductToProductTag = Schema.Struct({
|
|
@@ -289,16 +333,22 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
289
333
|
|
|
290
334
|
// After (v1.8.3):
|
|
291
335
|
export const _ProductToProductTag = Schema.Struct({
|
|
292
|
-
product_id: Schema.propertySignature(
|
|
293
|
-
|
|
336
|
+
product_id: Schema.propertySignature(
|
|
337
|
+
columnType(Schema.UUID, Schema.Never, Schema.Never)
|
|
338
|
+
).pipe(Schema.fromKey('A')),
|
|
339
|
+
product_tag_id: Schema.propertySignature(
|
|
340
|
+
columnType(Schema.UUID, Schema.Never, Schema.Never)
|
|
341
|
+
).pipe(Schema.fromKey('B')),
|
|
294
342
|
});
|
|
295
343
|
```
|
|
344
|
+
|
|
296
345
|
- Location: `src/effect/join-table.ts:37-69`
|
|
297
346
|
- New utility: `toSnakeCase()` in `src/utils/naming.ts:61-73`
|
|
298
347
|
|
|
299
348
|
### Fixed
|
|
300
349
|
|
|
301
350
|
#### Unused Enum Type Imports
|
|
351
|
+
|
|
302
352
|
- **types.ts now imports only Schema wrappers**: Eliminated TypeScript "declared but never read" warnings
|
|
303
353
|
- **Problem**: Generated `types.ts` imported both plain enum types (e.g., `BudgetStatus`) and schema wrappers (e.g., `BudgetStatusSchema`), but only schema wrappers were used
|
|
304
354
|
- **Solution**: Import generation now only includes `*Schema` wrappers
|
|
@@ -306,6 +356,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
306
356
|
- Location: `src/effect/generator.ts:95-107`
|
|
307
357
|
|
|
308
358
|
### Technical Details
|
|
359
|
+
|
|
309
360
|
- **Quality Assurance**: All 165 tests passing (15 naming tests + 10 join table tests + 140 existing), zero TypeScript errors
|
|
310
361
|
- **Test Coverage**: New comprehensive tests for `toSnakeCase` utility and semantic join table column generation
|
|
311
362
|
- **Documentation**: Updated CLAUDE.md with join table naming behavior explanation
|
|
@@ -320,6 +371,7 @@ None - This is a non-breaking enhancement. The change is purely additive at the
|
|
|
320
371
|
This release transforms the project into an enterprise-ready open source package following 2025 best practices.
|
|
321
372
|
|
|
322
373
|
#### Code Quality & Formatting
|
|
374
|
+
|
|
323
375
|
- **ESLint 9**: Flat config format with TypeScript and Jest support (2025 standard)
|
|
324
376
|
- Comprehensive rules for source and test files
|
|
325
377
|
- Automatic unused import detection
|
|
@@ -338,6 +390,7 @@ This release transforms the project into an enterprise-ready open source package
|
|
|
338
390
|
- `npm run format:check` - Check formatting without changes
|
|
339
391
|
|
|
340
392
|
#### Governance Documentation
|
|
393
|
+
|
|
341
394
|
- **SECURITY.md**: Professional vulnerability reporting process
|
|
342
395
|
- Supported versions table
|
|
343
396
|
- Response timeline SLAs (Critical: 7 days, High: 14 days, Medium: 30 days)
|
|
@@ -357,6 +410,7 @@ This release transforms the project into an enterprise-ready open source package
|
|
|
357
410
|
- **Governance docs added to npm package**: All governance files now distributed with package
|
|
358
411
|
|
|
359
412
|
#### Automated Dependency Management
|
|
413
|
+
|
|
360
414
|
- **renovate.json**: Renovate Cloud (free tier) configuration
|
|
361
415
|
- Weekly automated updates (Mondays at 3am UTC)
|
|
362
416
|
- Auto-merge for patch updates after CI passes
|
|
@@ -369,6 +423,7 @@ This release transforms the project into an enterprise-ready open source package
|
|
|
369
423
|
- Effect package pinned to prevent breaking changes
|
|
370
424
|
|
|
371
425
|
### Changed
|
|
426
|
+
|
|
372
427
|
- **prepublishOnly script**: Now includes linting step (`npm run lint && npm run typecheck && npm run test && npm run build`)
|
|
373
428
|
- **prepare script**: Updated from `npm run build` to `husky` for pre-commit hook initialization
|
|
374
429
|
- **Source code cleanup**: Removed unused imports detected by ESLint
|
|
@@ -378,6 +433,7 @@ This release transforms the project into an enterprise-ready open source package
|
|
|
378
433
|
- `src/effect/join-table.ts`: Prefixed unused parameter with underscore
|
|
379
434
|
|
|
380
435
|
### Technical Details
|
|
436
|
+
|
|
381
437
|
- **Quality Assurance**: All 154 tests passing, zero TypeScript errors
|
|
382
438
|
- **ESLint Status**: Passing with 2 minor warnings in test files (acceptable for test code)
|
|
383
439
|
- **Build**: Clean compilation to dist/ directory
|
|
@@ -385,6 +441,7 @@ This release transforms the project into an enterprise-ready open source package
|
|
|
385
441
|
- **Compliance**: Follows OpenSSF Best Practices baseline
|
|
386
442
|
|
|
387
443
|
### Dependencies
|
|
444
|
+
|
|
388
445
|
- **Added devDependencies**:
|
|
389
446
|
- `@eslint/js@^9.37.0`
|
|
390
447
|
- `typescript-eslint@^8.46.0`
|
|
@@ -421,15 +478,15 @@ This release transforms the project into an enterprise-ready open source package
|
|
|
421
478
|
```typescript
|
|
422
479
|
// Generated from: enum ACTIVE_STATUS { ACTIVE, INACTIVE }
|
|
423
480
|
export enum ACTIVE_STATUS {
|
|
424
|
-
ACTIVE =
|
|
425
|
-
INACTIVE =
|
|
481
|
+
ACTIVE = 'ACTIVE',
|
|
482
|
+
INACTIVE = 'INACTIVE',
|
|
426
483
|
}
|
|
427
484
|
export const ActiveStatusSchema = Schema.Enums(ACTIVE_STATUS);
|
|
428
485
|
export type ActiveStatusType = Schema.Schema.Type<typeof ActiveStatusSchema>;
|
|
429
486
|
|
|
430
487
|
// Usage:
|
|
431
|
-
const status = ACTIVE_STATUS.ACTIVE;
|
|
432
|
-
Schema.decodeSync(ActiveStatusSchema)(input);
|
|
488
|
+
const status = ACTIVE_STATUS.ACTIVE; // Direct enum access
|
|
489
|
+
Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
433
490
|
```
|
|
434
491
|
|
|
435
492
|
## [1.5.3] - 2025-10-12
|
|
@@ -452,6 +509,7 @@ Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
|
452
509
|
- Generates operational schemas (`Selectable`, `Insertable`, `Updateable`) for join tables
|
|
453
510
|
- Both `Type` and `Encoded` exports for complete type coverage
|
|
454
511
|
- Example:
|
|
512
|
+
|
|
455
513
|
```typescript
|
|
456
514
|
// Generated join table schema
|
|
457
515
|
export const _CategoryToPost = Schema.Struct({
|
|
@@ -468,6 +526,7 @@ Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
|
468
526
|
_CategoryToPost: Schema.Schema.Encoded<typeof _CategoryToPost>;
|
|
469
527
|
}
|
|
470
528
|
```
|
|
529
|
+
|
|
471
530
|
- **Benefits**:
|
|
472
531
|
- ✨ Type-safe Kysely queries through intermediate tables
|
|
473
532
|
- ✨ Complete database schema representation
|
|
@@ -515,9 +574,9 @@ Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
|
515
574
|
- ✅ **New Pattern**: Native TypeScript enum + Effect Schema wrapper
|
|
516
575
|
```typescript
|
|
517
576
|
export enum ProductStatus {
|
|
518
|
-
ACTIVE =
|
|
519
|
-
DRAFT =
|
|
520
|
-
ARCHIVED =
|
|
577
|
+
ACTIVE = 'ACTIVE',
|
|
578
|
+
DRAFT = 'DRAFT',
|
|
579
|
+
ARCHIVED = 'ARCHIVED',
|
|
521
580
|
}
|
|
522
581
|
export const ProductStatusSchema = Schema.Enums(ProductStatus);
|
|
523
582
|
export type ProductStatusType = Schema.Schema.Type<typeof ProductStatusSchema>;
|
|
@@ -562,15 +621,18 @@ Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
|
562
621
|
### Technical Details
|
|
563
622
|
|
|
564
623
|
**TDD Implementation**: All changes developed using Test-Driven Development (Red-Green-Refactor)
|
|
624
|
+
|
|
565
625
|
- 18+ new tests covering enum generation, property access, field mapping, and imports
|
|
566
626
|
- All 134 tests passing with strict TypeScript configuration
|
|
567
627
|
- Zero type coercions - maintains full type safety
|
|
568
628
|
|
|
569
629
|
**Expert Validation**:
|
|
630
|
+
|
|
570
631
|
- ✅ Effect Architecture Specialist: Confirmed Schema.Enums is canonical pattern for Effect v3.18+
|
|
571
632
|
- ✅ TypeScript Pro: Validated all optimizations are type-safe with zero runtime overhead
|
|
572
633
|
|
|
573
634
|
**Changed Files**:
|
|
635
|
+
|
|
574
636
|
- `src/effect/enum.ts`: Complete rewrite of enum generation logic
|
|
575
637
|
- `src/effect/type.ts`: Updated to return Schema wrappers for enum fields
|
|
576
638
|
- `src/effect/generator.ts`: Optimized import generation, removed Array.from()
|
|
@@ -579,6 +641,7 @@ Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
|
579
641
|
- `src/__tests__/helpers/dmmf-mocks.ts`: New test helpers without type coercions
|
|
580
642
|
|
|
581
643
|
**Test Coverage**:
|
|
644
|
+
|
|
582
645
|
- `src/__tests__/enum-generation.test.ts`: Tests 1-6 (Schema.Enums pattern)
|
|
583
646
|
- `src/__tests__/enum-property-access.test.ts`: Tests 7-10 (property access validation)
|
|
584
647
|
- `src/__tests__/field-type-generation.test.ts`: Tests 11-12 (field type mapping)
|
|
@@ -588,21 +651,23 @@ Schema.decodeSync(ActiveStatusSchema)(input); // Validation
|
|
|
588
651
|
**Migration Guide**:
|
|
589
652
|
|
|
590
653
|
Before (v1.4.x):
|
|
654
|
+
|
|
591
655
|
```typescript
|
|
592
656
|
// Generated code
|
|
593
|
-
export const PRODUCT_STATUS = Schema.Literal(
|
|
657
|
+
export const PRODUCT_STATUS = Schema.Literal('ACTIVE', 'DRAFT', 'ARCHIVED');
|
|
594
658
|
|
|
595
659
|
// Usage
|
|
596
660
|
const status = PRODUCT_STATUS.literals[0]; // "ACTIVE"
|
|
597
661
|
```
|
|
598
662
|
|
|
599
663
|
After (v1.5.0):
|
|
664
|
+
|
|
600
665
|
```typescript
|
|
601
666
|
// Generated code
|
|
602
667
|
export enum ProductStatus {
|
|
603
|
-
ACTIVE =
|
|
604
|
-
DRAFT =
|
|
605
|
-
ARCHIVED =
|
|
668
|
+
ACTIVE = 'ACTIVE',
|
|
669
|
+
DRAFT = 'DRAFT',
|
|
670
|
+
ARCHIVED = 'ARCHIVED',
|
|
606
671
|
}
|
|
607
672
|
export const ProductStatusSchema = Schema.Enums(ProductStatus);
|
|
608
673
|
|
|
@@ -630,6 +695,7 @@ const status = ProductStatus.ACTIVE; // "ACTIVE"
|
|
|
630
695
|
**Problem**: When TypeScript compiled helper functions to `.d.ts` files, the return types of AST transformation functions (`selectable()`, `insertable()`, `updateable()`) were inferred as `S.Schema<unknown, unknown, never>` instead of preserving the Kysely mapped types. This caused downstream type resolution to fail when consumers used compiled declaration files (dist/ paths) instead of source files.
|
|
631
696
|
|
|
632
697
|
**Solution**: Added explicit return type annotations with type assertions to all helper functions:
|
|
698
|
+
|
|
633
699
|
- `selectable()` → `: S.Schema<Selectable<Type>, Selectable<Encoded>, never>`
|
|
634
700
|
- `insertable()` → `: S.Schema<Insertable<Type>, Insertable<Encoded>, never>`
|
|
635
701
|
- `updateable()` → `: S.Schema<Updateable<Type>, Updateable<Encoded>, never>`
|
|
@@ -640,6 +706,7 @@ const status = ProductStatus.ACTIVE; // "ACTIVE"
|
|
|
640
706
|
**Testing**: Added comprehensive test suite (`declaration-inference.test.ts`) with 7 tests validating type preservation in compiled declarations, following TDD principles (Red-Green-Refactor).
|
|
641
707
|
|
|
642
708
|
**Changed files:**
|
|
709
|
+
|
|
643
710
|
- `src/kysely/helpers.ts`: Added return type annotations (4 functions)
|
|
644
711
|
- `src/__tests__/declaration-inference.test.ts`: New test suite (260 lines)
|
|
645
712
|
|
|
@@ -669,6 +736,7 @@ const status = ProductStatus.ACTIVE; // "ACTIVE"
|
|
|
669
736
|
**Impact**: Projects using `prisma-effect-kysely` v1.4.0 or earlier may have experienced TypeScript compilation errors when using `Schema.decode()` or `Schema.decodeUnknownSync()`. This release resolves those errors without requiring any code changes in consuming projects.
|
|
670
737
|
|
|
671
738
|
**Changed files:**
|
|
739
|
+
|
|
672
740
|
- `src/kysely/helpers.ts`: Added `S.asSchema()` wrappers (6 locations)
|
|
673
741
|
- `src/prisma/enum.ts`: Added return type annotation
|
|
674
742
|
- `src/prisma/generator.ts`: Added return type annotations (3 methods)
|
|
@@ -699,6 +767,7 @@ The generator now converts all model names to PascalCase when creating TypeScrip
|
|
|
699
767
|
**Impact**: Projects using snake_case model names will see different export names (breaking change for those projects). Projects using PascalCase models (recommended Prisma convention) will see no changes.
|
|
700
768
|
|
|
701
769
|
**Changed files:**
|
|
770
|
+
|
|
702
771
|
- `src/utils/naming.ts`: New naming utility
|
|
703
772
|
- `src/effect/generator.ts`: Updated to use PascalCase for all exports
|
|
704
773
|
- `src/__tests__/fixtures/test.prisma`: Added snake_case test model
|
|
@@ -725,20 +794,24 @@ The generator now converts all model names to PascalCase when creating TypeScrip
|
|
|
725
794
|
### Why This Matters
|
|
726
795
|
|
|
727
796
|
Effect Schema has bidirectional transformations:
|
|
797
|
+
|
|
728
798
|
- **Application types** (`Schema.Schema.Type`) - Decoded types with `Date` objects (for repository layer)
|
|
729
799
|
- **Database types** (`Schema.Schema.Encoded`) - Encoded types with ISO strings (for queries layer)
|
|
730
800
|
|
|
731
801
|
Previously, only Application types were exported, forcing queries to use `any` types. Now both sides of the transformation are properly typed.
|
|
732
802
|
|
|
733
803
|
**Example Usage:**
|
|
804
|
+
|
|
734
805
|
```typescript
|
|
735
806
|
import { agentInsertEncoded } from '@libs/types';
|
|
736
807
|
|
|
737
808
|
// Queries layer - uses Encoded types (ISO strings)
|
|
738
|
-
insert: (rowData: agentInsertEncoded) => db.insertInto('agent').values(rowData)
|
|
809
|
+
insert: (rowData: agentInsertEncoded) => db.insertInto('agent').values(rowData);
|
|
739
810
|
|
|
740
811
|
// Repository layer - uses Application types (Date objects)
|
|
741
|
-
const input: CreateAgentInput = {
|
|
812
|
+
const input: CreateAgentInput = {
|
|
813
|
+
/* ... Date objects ... */
|
|
814
|
+
};
|
|
742
815
|
const encoded = Schema.encode(AgentSchemas.Insertable)(input); // Encoded to ISO strings
|
|
743
816
|
```
|
|
744
817
|
|
|
@@ -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,oBAAoB,CAAC;AAGxD;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,SAAS,EAAE,aAAa,
|
|
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,oBAAoB,CAAC;AAGxD;;GAEG;AACH,wBAAgB,gCAAgC,CAAC,SAAS,EAAE,aAAa,UAcxE;AAoBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,UAgDrF"}
|
package/dist/effect/type.d.ts
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AA2BrD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,UA6B1E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,UAcpE"}
|
package/dist/effect/type.js
CHANGED
|
@@ -8,17 +8,23 @@ const naming_1 = require("../utils/naming");
|
|
|
8
8
|
/**
|
|
9
9
|
* Prisma scalar type mapping to Effect Schema types
|
|
10
10
|
* Uses const assertion to avoid type guards
|
|
11
|
+
*
|
|
12
|
+
* Note: DateTime uses Schema.DateFromSelf (not Schema.Date) so that:
|
|
13
|
+
* - Type = Date (runtime)
|
|
14
|
+
* - Encoded = Date (database)
|
|
15
|
+
* This allows Kysely to work with native Date objects directly.
|
|
16
|
+
* Schema.Date would encode to string, requiring ISO string conversions.
|
|
11
17
|
*/
|
|
12
18
|
const PRISMA_SCALAR_MAP = {
|
|
13
|
-
String:
|
|
14
|
-
Int:
|
|
15
|
-
Float:
|
|
16
|
-
BigInt:
|
|
17
|
-
Decimal:
|
|
18
|
-
Boolean:
|
|
19
|
-
DateTime:
|
|
20
|
-
Json:
|
|
21
|
-
Bytes:
|
|
19
|
+
String: 'Schema.String',
|
|
20
|
+
Int: 'Schema.Number',
|
|
21
|
+
Float: 'Schema.Number',
|
|
22
|
+
BigInt: 'Schema.BigInt',
|
|
23
|
+
Decimal: 'Schema.String', // For precision
|
|
24
|
+
Boolean: 'Schema.Boolean',
|
|
25
|
+
DateTime: 'Schema.DateFromSelf', // Native Date type for Kysely compatibility
|
|
26
|
+
Json: 'Schema.Unknown', // Safe unknown type
|
|
27
|
+
Bytes: 'Schema.Uint8Array',
|
|
22
28
|
};
|
|
23
29
|
/**
|
|
24
30
|
* Map Prisma field type to Effect Schema type
|
|
@@ -31,8 +37,8 @@ function mapFieldToEffectType(field, dmmf) {
|
|
|
31
37
|
return typeOverride;
|
|
32
38
|
}
|
|
33
39
|
// PRIORITY 2: Handle String type with UUID detection
|
|
34
|
-
if (field.type ===
|
|
35
|
-
return
|
|
40
|
+
if (field.type === 'String' && (0, type_1.isUuidField)(field)) {
|
|
41
|
+
return 'Schema.UUID';
|
|
36
42
|
}
|
|
37
43
|
// PRIORITY 3: Handle scalar types with const assertion lookup
|
|
38
44
|
const scalarType = PRISMA_SCALAR_MAP[field.type];
|
|
@@ -48,7 +54,7 @@ function mapFieldToEffectType(field, dmmf) {
|
|
|
48
54
|
return (0, naming_1.toPascalCase)(field.type, 'Schema');
|
|
49
55
|
}
|
|
50
56
|
// PRIORITY 5: Fallback to Unknown
|
|
51
|
-
return
|
|
57
|
+
return 'Schema.Unknown';
|
|
52
58
|
}
|
|
53
59
|
/**
|
|
54
60
|
* Build complete field type with array and optional wrapping
|
package/dist/effect/type.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"type.js","sourceRoot":"","sources":["../../src/effect/type.ts"],"names":[],"mappings":";;AA+BA,oDA6BC;AAKD,wCAcC;AA9ED,yCAA4F;AAC5F,sDAAiE;AACjE,4CAA+C;AAE/C;;;;;;;;;GASG;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,qBAAqB,EAAE,4CAA4C;IAC7E,IAAI,EAAE,gBAAgB,EAAE,oBAAoB;IAC5C,KAAK,EAAE,mBAAmB;CAClB,CAAC;AAEX;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,KAAiB,EAAE,IAAmB;IACzE,+CAA+C;IAC/C,MAAM,YAAY,GAAG,IAAA,uCAAyB,EAAC,KAAK,CAAC,CAAC;IACtD,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,qDAAqD;IACrD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAA,kBAAW,EAAC,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,8DAA8D;IAC9D,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,gDAAgD;QAChD,2CAA2C;QAC3C,OAAO,IAAA,qBAAY,EAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,kCAAkC;IAClC,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,KAAiB,EAAE,IAAmB;IACnE,IAAI,QAAQ,GAAG,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAEjD,gBAAgB;IAChB,IAAI,IAAA,kBAAW,EAAC,KAAK,CAAC,EAAE,CAAC;QACvB,QAAQ,GAAG,gBAAgB,QAAQ,GAAG,CAAC;IACzC,CAAC;IAED,4DAA4D;IAC5D,IAAI,CAAC,IAAA,sBAAe,EAAC,KAAK,CAAC,IAAI,CAAC,IAAA,sBAAe,EAAC,KAAK,CAAC,EAAE,CAAC;QACvD,QAAQ,GAAG,sBAAsB,QAAQ,GAAG,CAAC;IAC/C,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generator Configuration
|
|
3
|
+
*
|
|
4
|
+
* Defines configuration options for prisma-effect-kysely generator
|
|
5
|
+
* with support for multi-domain organization and library scaffolding.
|
|
6
|
+
* Uses Effect Schema for strict validation.
|
|
7
|
+
*/
|
|
8
|
+
import { Schema } from 'effect';
|
|
9
|
+
import type { GeneratorOptions } from '@prisma/generator-helper';
|
|
10
|
+
/**
|
|
11
|
+
* Generator configuration schema
|
|
12
|
+
*/
|
|
13
|
+
declare const GeneratorConfigSchema: Schema.Struct<{
|
|
14
|
+
/**
|
|
15
|
+
* Output directory for generated Effect schemas
|
|
16
|
+
*/
|
|
17
|
+
output: typeof Schema.String;
|
|
18
|
+
/**
|
|
19
|
+
* Enable multi-domain detection from schema file structure
|
|
20
|
+
*/
|
|
21
|
+
multiFileDomains: Schema.Literal<["true", "false"]>;
|
|
22
|
+
/**
|
|
23
|
+
* Automatically scaffold contract libraries for detected domains
|
|
24
|
+
*/
|
|
25
|
+
scaffoldLibraries: Schema.Literal<["true", "false"]>;
|
|
26
|
+
/**
|
|
27
|
+
* Path to monorepo-library-generator for library scaffolding
|
|
28
|
+
*/
|
|
29
|
+
libraryGenerator: Schema.optional<typeof Schema.String>;
|
|
30
|
+
/**
|
|
31
|
+
* Preview features to enable
|
|
32
|
+
*/
|
|
33
|
+
previewFeatures: Schema.Array$<typeof Schema.String>;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Generator configuration type derived from schema
|
|
37
|
+
*/
|
|
38
|
+
export type GeneratorConfig = Schema.Schema.Type<typeof GeneratorConfigSchema>;
|
|
39
|
+
/**
|
|
40
|
+
* Parse and validate generator configuration from Prisma options
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseGeneratorConfig(options: GeneratorOptions): {
|
|
43
|
+
readonly output: string;
|
|
44
|
+
readonly multiFileDomains: "true" | "false";
|
|
45
|
+
readonly scaffoldLibraries: "true" | "false";
|
|
46
|
+
readonly libraryGenerator?: string | undefined;
|
|
47
|
+
readonly previewFeatures: readonly string[];
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Check if multi-domain mode is enabled
|
|
51
|
+
*/
|
|
52
|
+
export declare function isMultiDomainEnabled(config: GeneratorConfig): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Check if library scaffolding is enabled
|
|
55
|
+
*/
|
|
56
|
+
export declare function isScaffoldingEnabled(config: GeneratorConfig): boolean;
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/generator/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAOjE;;GAEG;AACH,QAAA,MAAM,qBAAqB;IACzB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEH,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE/E;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,gBAAgB;;;;;;EAwB7D;AAoCD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,WAE3D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,WAE3D"}
|