kysely-gen 0.9.1 → 0.10.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/README.md +48 -0
- package/dist/cli.js +420 -12
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -51,6 +51,54 @@ npx kysely-gen --dialect mysql --url mysql://user:pass@localhost:3306/db
|
|
|
51
51
|
| `--camel-case` | Convert names to camelCase |
|
|
52
52
|
| `--include-pattern <glob>` | Only include matching tables |
|
|
53
53
|
| `--exclude-pattern <glob>` | Exclude matching tables |
|
|
54
|
+
| `--zod` | Generate Zod schemas instead of TypeScript interfaces |
|
|
55
|
+
|
|
56
|
+
## Zod Schema Generation
|
|
57
|
+
|
|
58
|
+
Generate Zod validation schemas with inferred types instead of TypeScript interfaces. Requires Zod v4+:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
npm install zod@4
|
|
62
|
+
npx kysely-gen --zod
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This generates `db-schemas.ts` with Zod schemas and inferred types:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { z } from 'zod';
|
|
69
|
+
|
|
70
|
+
export const userSchema = z.object({
|
|
71
|
+
id: z.number(),
|
|
72
|
+
email: z.string(),
|
|
73
|
+
name: z.string().nullable(),
|
|
74
|
+
createdAt: z.date(),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
export const newUserSchema = z.object({
|
|
78
|
+
id: z.number().optional(),
|
|
79
|
+
email: z.string(),
|
|
80
|
+
name: z.string().nullable().optional(),
|
|
81
|
+
createdAt: z.union([z.date(), z.string()]).optional(),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export const userUpdateSchema = z.object({
|
|
85
|
+
id: z.number().optional(),
|
|
86
|
+
email: z.string().optional(),
|
|
87
|
+
name: z.string().nullable().optional(),
|
|
88
|
+
createdAt: z.union([z.date(), z.string()]).optional(),
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export type User = z.infer<typeof userSchema>;
|
|
92
|
+
export type NewUser = z.infer<typeof newUserSchema>;
|
|
93
|
+
export type UserUpdate = z.infer<typeof userUpdateSchema>;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Three schemas are generated per table:
|
|
97
|
+
- **Select schema** (`userSchema`): What you get from queries
|
|
98
|
+
- **Insert schema** (`newUserSchema`): For inserts - auto-increment/default columns are optional
|
|
99
|
+
- **Update schema** (`userUpdateSchema`): For updates - all columns are optional
|
|
100
|
+
|
|
101
|
+
The `--zod` flag replaces TypeScript interface generation. Types are inferred from schemas via `z.infer<>`, ensuring they never drift.
|
|
54
102
|
|
|
55
103
|
## Example
|
|
56
104
|
|
package/dist/cli.js
CHANGED
|
@@ -111124,9 +111124,404 @@ function detectDialect(connectionString) {
|
|
|
111124
111124
|
}
|
|
111125
111125
|
}
|
|
111126
111126
|
|
|
111127
|
+
// src/zod/type-mapper.ts
|
|
111128
|
+
function mapPostgresTypeToZod(dataType, options) {
|
|
111129
|
+
const { isNullable, isArray, isOptional, mode } = options;
|
|
111130
|
+
if (isArray || dataType.endsWith("[]")) {
|
|
111131
|
+
const baseTypeName = dataType.endsWith("[]") ? dataType.slice(0, -2) : dataType;
|
|
111132
|
+
const elementSchema = mapPostgresTypeToZod(baseTypeName, {
|
|
111133
|
+
isNullable: false,
|
|
111134
|
+
isArray: false,
|
|
111135
|
+
isOptional: false,
|
|
111136
|
+
mode
|
|
111137
|
+
});
|
|
111138
|
+
return applyModifiers({ kind: "zod-array", element: elementSchema }, isNullable, isOptional);
|
|
111139
|
+
}
|
|
111140
|
+
const baseSchema = mapScalarType(dataType, mode);
|
|
111141
|
+
return applyModifiers(baseSchema, isNullable, isOptional);
|
|
111142
|
+
}
|
|
111143
|
+
function applyModifiers(schema, isNullable, isOptional) {
|
|
111144
|
+
const modifiers = [];
|
|
111145
|
+
if (isNullable)
|
|
111146
|
+
modifiers.push("nullable");
|
|
111147
|
+
if (isOptional)
|
|
111148
|
+
modifiers.push("optional");
|
|
111149
|
+
if (modifiers.length > 0) {
|
|
111150
|
+
return { kind: "zod-modified", schema, modifiers };
|
|
111151
|
+
}
|
|
111152
|
+
return schema;
|
|
111153
|
+
}
|
|
111154
|
+
function mapScalarType(dataType, mode) {
|
|
111155
|
+
switch (dataType) {
|
|
111156
|
+
case "int2":
|
|
111157
|
+
case "int4":
|
|
111158
|
+
case "smallint":
|
|
111159
|
+
case "integer":
|
|
111160
|
+
case "float4":
|
|
111161
|
+
case "float8":
|
|
111162
|
+
case "real":
|
|
111163
|
+
case "double precision":
|
|
111164
|
+
return { kind: "zod-primitive", method: "number" };
|
|
111165
|
+
case "int8":
|
|
111166
|
+
case "bigint":
|
|
111167
|
+
if (mode === "select") {
|
|
111168
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111169
|
+
}
|
|
111170
|
+
return {
|
|
111171
|
+
kind: "zod-union",
|
|
111172
|
+
schemas: [
|
|
111173
|
+
{ kind: "zod-primitive", method: "string" },
|
|
111174
|
+
{ kind: "zod-primitive", method: "number" },
|
|
111175
|
+
{ kind: "zod-primitive", method: "bigint" }
|
|
111176
|
+
]
|
|
111177
|
+
};
|
|
111178
|
+
case "numeric":
|
|
111179
|
+
case "decimal":
|
|
111180
|
+
if (mode === "select") {
|
|
111181
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111182
|
+
}
|
|
111183
|
+
return {
|
|
111184
|
+
kind: "zod-union",
|
|
111185
|
+
schemas: [
|
|
111186
|
+
{ kind: "zod-primitive", method: "string" },
|
|
111187
|
+
{ kind: "zod-primitive", method: "number" }
|
|
111188
|
+
]
|
|
111189
|
+
};
|
|
111190
|
+
case "varchar":
|
|
111191
|
+
case "char":
|
|
111192
|
+
case "text":
|
|
111193
|
+
case "citext":
|
|
111194
|
+
case "uuid":
|
|
111195
|
+
case "money":
|
|
111196
|
+
case "time":
|
|
111197
|
+
case "timetz":
|
|
111198
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111199
|
+
case "bool":
|
|
111200
|
+
case "boolean":
|
|
111201
|
+
return { kind: "zod-primitive", method: "boolean" };
|
|
111202
|
+
case "timestamp":
|
|
111203
|
+
case "timestamptz":
|
|
111204
|
+
case "date":
|
|
111205
|
+
if (mode === "select") {
|
|
111206
|
+
return { kind: "zod-primitive", method: "date" };
|
|
111207
|
+
}
|
|
111208
|
+
return {
|
|
111209
|
+
kind: "zod-union",
|
|
111210
|
+
schemas: [
|
|
111211
|
+
{ kind: "zod-primitive", method: "date" },
|
|
111212
|
+
{ kind: "zod-primitive", method: "string" }
|
|
111213
|
+
]
|
|
111214
|
+
};
|
|
111215
|
+
case "interval":
|
|
111216
|
+
return { kind: "zod-primitive", method: "unknown" };
|
|
111217
|
+
case "json":
|
|
111218
|
+
case "jsonb":
|
|
111219
|
+
return { kind: "zod-primitive", method: "unknown" };
|
|
111220
|
+
case "bytea":
|
|
111221
|
+
return { kind: "zod-custom", typeReference: "Buffer" };
|
|
111222
|
+
case "point":
|
|
111223
|
+
return {
|
|
111224
|
+
kind: "zod-object",
|
|
111225
|
+
properties: [
|
|
111226
|
+
{ name: "x", schema: { kind: "zod-primitive", method: "number" } },
|
|
111227
|
+
{ name: "y", schema: { kind: "zod-primitive", method: "number" } }
|
|
111228
|
+
]
|
|
111229
|
+
};
|
|
111230
|
+
case "circle":
|
|
111231
|
+
return {
|
|
111232
|
+
kind: "zod-object",
|
|
111233
|
+
properties: [
|
|
111234
|
+
{ name: "x", schema: { kind: "zod-primitive", method: "number" } },
|
|
111235
|
+
{ name: "y", schema: { kind: "zod-primitive", method: "number" } },
|
|
111236
|
+
{ name: "radius", schema: { kind: "zod-primitive", method: "number" } }
|
|
111237
|
+
]
|
|
111238
|
+
};
|
|
111239
|
+
case "int4range":
|
|
111240
|
+
case "int8range":
|
|
111241
|
+
case "numrange":
|
|
111242
|
+
case "daterange":
|
|
111243
|
+
case "tsrange":
|
|
111244
|
+
case "tstzrange":
|
|
111245
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111246
|
+
default:
|
|
111247
|
+
return { kind: "zod-primitive", method: "unknown" };
|
|
111248
|
+
}
|
|
111249
|
+
}
|
|
111250
|
+
|
|
111251
|
+
// src/zod/transform.ts
|
|
111252
|
+
function uncapitalize(str) {
|
|
111253
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
111254
|
+
}
|
|
111255
|
+
function getSchemaName(baseName, mode) {
|
|
111256
|
+
const uncap = uncapitalize(baseName);
|
|
111257
|
+
switch (mode) {
|
|
111258
|
+
case "select":
|
|
111259
|
+
return `${uncap}Schema`;
|
|
111260
|
+
case "insert":
|
|
111261
|
+
return `new${baseName}Schema`;
|
|
111262
|
+
case "update":
|
|
111263
|
+
return `${uncap}UpdateSchema`;
|
|
111264
|
+
}
|
|
111265
|
+
}
|
|
111266
|
+
function getTypeName(baseName, mode) {
|
|
111267
|
+
switch (mode) {
|
|
111268
|
+
case "select":
|
|
111269
|
+
return baseName;
|
|
111270
|
+
case "insert":
|
|
111271
|
+
return `New${baseName}`;
|
|
111272
|
+
case "update":
|
|
111273
|
+
return `${baseName}Update`;
|
|
111274
|
+
}
|
|
111275
|
+
}
|
|
111276
|
+
function transformEnumToZod(enumMeta, resolver) {
|
|
111277
|
+
const name = resolver.getName(enumMeta);
|
|
111278
|
+
return {
|
|
111279
|
+
kind: "zod-schema-declaration",
|
|
111280
|
+
name: `${uncapitalize(name)}Schema`,
|
|
111281
|
+
schema: {
|
|
111282
|
+
kind: "zod-enum",
|
|
111283
|
+
values: enumMeta.values
|
|
111284
|
+
},
|
|
111285
|
+
exported: true
|
|
111286
|
+
};
|
|
111287
|
+
}
|
|
111288
|
+
function transformColumnToZod(column, enums, enumResolver, mode, options) {
|
|
111289
|
+
const columnName = options?.camelCase ? toCamelCase(column.name) : column.name;
|
|
111290
|
+
const matchingEnum = enums.find((e) => e.name === column.dataType && e.schema === (column.dataTypeSchema ?? "public"));
|
|
111291
|
+
let schema;
|
|
111292
|
+
if (matchingEnum) {
|
|
111293
|
+
const enumName = enumResolver.getName(matchingEnum);
|
|
111294
|
+
schema = { kind: "zod-reference", name: `${uncapitalize(enumName)}Schema` };
|
|
111295
|
+
const modifiers = [];
|
|
111296
|
+
if (column.isNullable)
|
|
111297
|
+
modifiers.push("nullable");
|
|
111298
|
+
const isOptional = mode === "update" || mode === "insert" && (column.isAutoIncrement || column.hasDefaultValue);
|
|
111299
|
+
if (isOptional)
|
|
111300
|
+
modifiers.push("optional");
|
|
111301
|
+
if (modifiers.length > 0) {
|
|
111302
|
+
schema = { kind: "zod-modified", schema, modifiers };
|
|
111303
|
+
}
|
|
111304
|
+
} else {
|
|
111305
|
+
const isOptional = mode === "update" || mode === "insert" && (column.isAutoIncrement || column.hasDefaultValue);
|
|
111306
|
+
schema = mapPostgresTypeToZod(column.dataType, {
|
|
111307
|
+
isNullable: column.isNullable,
|
|
111308
|
+
isArray: column.isArray,
|
|
111309
|
+
isOptional,
|
|
111310
|
+
mode
|
|
111311
|
+
});
|
|
111312
|
+
}
|
|
111313
|
+
return { name: columnName, schema };
|
|
111314
|
+
}
|
|
111315
|
+
function transformTableToZod(table, enums, enumResolver, mode, options) {
|
|
111316
|
+
const baseName = toPascalCase(singularize(table.name));
|
|
111317
|
+
const schemaName = getSchemaName(baseName, mode);
|
|
111318
|
+
const properties = table.columns.map((col) => transformColumnToZod(col, enums, enumResolver, mode, options));
|
|
111319
|
+
return {
|
|
111320
|
+
kind: "zod-schema-declaration",
|
|
111321
|
+
name: schemaName,
|
|
111322
|
+
schema: { kind: "zod-object", properties },
|
|
111323
|
+
exported: true
|
|
111324
|
+
};
|
|
111325
|
+
}
|
|
111326
|
+
function createInferExport(baseName, mode) {
|
|
111327
|
+
return {
|
|
111328
|
+
kind: "zod-infer-export",
|
|
111329
|
+
typeName: getTypeName(baseName, mode),
|
|
111330
|
+
schemaName: getSchemaName(baseName, mode)
|
|
111331
|
+
};
|
|
111332
|
+
}
|
|
111333
|
+
function transformDatabaseToZod(metadata, options) {
|
|
111334
|
+
const declarations = [];
|
|
111335
|
+
declarations.push({ kind: "zod-import" });
|
|
111336
|
+
const enumResolver = new EnumNameResolver(metadata.enums);
|
|
111337
|
+
for (const enumMeta of metadata.enums) {
|
|
111338
|
+
declarations.push(transformEnumToZod(enumMeta, enumResolver));
|
|
111339
|
+
}
|
|
111340
|
+
for (const table of metadata.tables) {
|
|
111341
|
+
const baseName = toPascalCase(singularize(table.name));
|
|
111342
|
+
declarations.push(transformTableToZod(table, metadata.enums, enumResolver, "select", options));
|
|
111343
|
+
declarations.push(transformTableToZod(table, metadata.enums, enumResolver, "insert", options));
|
|
111344
|
+
declarations.push(transformTableToZod(table, metadata.enums, enumResolver, "update", options));
|
|
111345
|
+
declarations.push(createInferExport(baseName, "select"));
|
|
111346
|
+
declarations.push(createInferExport(baseName, "insert"));
|
|
111347
|
+
declarations.push(createInferExport(baseName, "update"));
|
|
111348
|
+
}
|
|
111349
|
+
return { declarations };
|
|
111350
|
+
}
|
|
111351
|
+
|
|
111352
|
+
// src/zod/serialize.ts
|
|
111353
|
+
var RESERVED_WORDS2 = new Set([
|
|
111354
|
+
"break",
|
|
111355
|
+
"case",
|
|
111356
|
+
"catch",
|
|
111357
|
+
"class",
|
|
111358
|
+
"const",
|
|
111359
|
+
"continue",
|
|
111360
|
+
"debugger",
|
|
111361
|
+
"default",
|
|
111362
|
+
"delete",
|
|
111363
|
+
"do",
|
|
111364
|
+
"else",
|
|
111365
|
+
"enum",
|
|
111366
|
+
"export",
|
|
111367
|
+
"extends",
|
|
111368
|
+
"false",
|
|
111369
|
+
"finally",
|
|
111370
|
+
"for",
|
|
111371
|
+
"function",
|
|
111372
|
+
"if",
|
|
111373
|
+
"import",
|
|
111374
|
+
"in",
|
|
111375
|
+
"instanceof",
|
|
111376
|
+
"new",
|
|
111377
|
+
"null",
|
|
111378
|
+
"return",
|
|
111379
|
+
"super",
|
|
111380
|
+
"switch",
|
|
111381
|
+
"this",
|
|
111382
|
+
"throw",
|
|
111383
|
+
"true",
|
|
111384
|
+
"try",
|
|
111385
|
+
"typeof",
|
|
111386
|
+
"var",
|
|
111387
|
+
"void",
|
|
111388
|
+
"while",
|
|
111389
|
+
"with",
|
|
111390
|
+
"yield",
|
|
111391
|
+
"let",
|
|
111392
|
+
"static",
|
|
111393
|
+
"implements",
|
|
111394
|
+
"interface",
|
|
111395
|
+
"package",
|
|
111396
|
+
"private",
|
|
111397
|
+
"protected",
|
|
111398
|
+
"public",
|
|
111399
|
+
"await",
|
|
111400
|
+
"abstract",
|
|
111401
|
+
"as",
|
|
111402
|
+
"async",
|
|
111403
|
+
"declare",
|
|
111404
|
+
"from",
|
|
111405
|
+
"get",
|
|
111406
|
+
"is",
|
|
111407
|
+
"module",
|
|
111408
|
+
"namespace",
|
|
111409
|
+
"of",
|
|
111410
|
+
"require",
|
|
111411
|
+
"set",
|
|
111412
|
+
"type"
|
|
111413
|
+
]);
|
|
111414
|
+
function escapeString2(value) {
|
|
111415
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
111416
|
+
}
|
|
111417
|
+
function needsQuotes2(name) {
|
|
111418
|
+
if (RESERVED_WORDS2.has(name))
|
|
111419
|
+
return true;
|
|
111420
|
+
if (/^\d/.test(name))
|
|
111421
|
+
return true;
|
|
111422
|
+
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))
|
|
111423
|
+
return true;
|
|
111424
|
+
return false;
|
|
111425
|
+
}
|
|
111426
|
+
function serializePropertyName2(name) {
|
|
111427
|
+
return needsQuotes2(name) ? `'${escapeString2(name)}'` : name;
|
|
111428
|
+
}
|
|
111429
|
+
function serializeZodSchema(node) {
|
|
111430
|
+
switch (node.kind) {
|
|
111431
|
+
case "zod-primitive":
|
|
111432
|
+
return serializeZodPrimitive(node);
|
|
111433
|
+
case "zod-literal":
|
|
111434
|
+
return serializeZodLiteral(node);
|
|
111435
|
+
case "zod-union":
|
|
111436
|
+
return serializeZodUnion(node);
|
|
111437
|
+
case "zod-enum":
|
|
111438
|
+
return serializeZodEnum(node);
|
|
111439
|
+
case "zod-array":
|
|
111440
|
+
return serializeZodArray(node);
|
|
111441
|
+
case "zod-object":
|
|
111442
|
+
return serializeZodObject(node);
|
|
111443
|
+
case "zod-modified":
|
|
111444
|
+
return serializeZodModified(node);
|
|
111445
|
+
case "zod-reference":
|
|
111446
|
+
return serializeZodReference(node);
|
|
111447
|
+
case "zod-custom":
|
|
111448
|
+
return serializeZodCustom(node);
|
|
111449
|
+
}
|
|
111450
|
+
}
|
|
111451
|
+
function serializeZodPrimitive(node) {
|
|
111452
|
+
return `z.${node.method}()`;
|
|
111453
|
+
}
|
|
111454
|
+
function serializeZodLiteral(node) {
|
|
111455
|
+
if (typeof node.value === "string") {
|
|
111456
|
+
return `z.literal('${escapeString2(node.value)}')`;
|
|
111457
|
+
}
|
|
111458
|
+
return `z.literal(${node.value})`;
|
|
111459
|
+
}
|
|
111460
|
+
function serializeZodUnion(node) {
|
|
111461
|
+
const schemas = node.schemas.map(serializeZodSchema).join(", ");
|
|
111462
|
+
return `z.union([${schemas}])`;
|
|
111463
|
+
}
|
|
111464
|
+
function serializeZodEnum(node) {
|
|
111465
|
+
const values = node.values.map((v) => `'${escapeString2(v)}'`).join(", ");
|
|
111466
|
+
return `z.enum([${values}])`;
|
|
111467
|
+
}
|
|
111468
|
+
function serializeZodArray(node) {
|
|
111469
|
+
return `z.array(${serializeZodSchema(node.element)})`;
|
|
111470
|
+
}
|
|
111471
|
+
function serializeZodObject(node) {
|
|
111472
|
+
if (node.properties.length === 0) {
|
|
111473
|
+
return "z.object({})";
|
|
111474
|
+
}
|
|
111475
|
+
const props = node.properties.map((p) => serializeZodProperty(p)).join(`,
|
|
111476
|
+
`);
|
|
111477
|
+
return `z.object({
|
|
111478
|
+
${props},
|
|
111479
|
+
})`;
|
|
111480
|
+
}
|
|
111481
|
+
function serializeZodProperty(node) {
|
|
111482
|
+
const name = serializePropertyName2(node.name);
|
|
111483
|
+
return ` ${name}: ${serializeZodSchema(node.schema)}`;
|
|
111484
|
+
}
|
|
111485
|
+
function serializeZodModified(node) {
|
|
111486
|
+
let result = serializeZodSchema(node.schema);
|
|
111487
|
+
for (const mod of node.modifiers) {
|
|
111488
|
+
result += `.${mod}()`;
|
|
111489
|
+
}
|
|
111490
|
+
return result;
|
|
111491
|
+
}
|
|
111492
|
+
function serializeZodReference(node) {
|
|
111493
|
+
return node.name;
|
|
111494
|
+
}
|
|
111495
|
+
function serializeZodCustom(node) {
|
|
111496
|
+
return `z.custom<${node.typeReference}>()`;
|
|
111497
|
+
}
|
|
111498
|
+
function serializeZodDeclaration(node) {
|
|
111499
|
+
switch (node.kind) {
|
|
111500
|
+
case "zod-import":
|
|
111501
|
+
return "import { z } from 'zod';";
|
|
111502
|
+
case "zod-schema-declaration":
|
|
111503
|
+
return serializeZodSchemaDeclaration(node);
|
|
111504
|
+
case "zod-infer-export":
|
|
111505
|
+
return serializeZodInferExport(node);
|
|
111506
|
+
}
|
|
111507
|
+
}
|
|
111508
|
+
function serializeZodSchemaDeclaration(node) {
|
|
111509
|
+
const exported = node.exported ? "export " : "";
|
|
111510
|
+
return `${exported}const ${node.name} = ${serializeZodSchema(node.schema)};`;
|
|
111511
|
+
}
|
|
111512
|
+
function serializeZodInferExport(node) {
|
|
111513
|
+
return `export type ${node.typeName} = z.infer<typeof ${node.schemaName}>;`;
|
|
111514
|
+
}
|
|
111515
|
+
function serializeZod(program2) {
|
|
111516
|
+
return program2.declarations.map(serializeZodDeclaration).join(`
|
|
111517
|
+
|
|
111518
|
+
`) + `
|
|
111519
|
+
`;
|
|
111520
|
+
}
|
|
111521
|
+
|
|
111127
111522
|
// src/cli.ts
|
|
111128
111523
|
var program2 = new Command;
|
|
111129
|
-
program2.name("kysely-gen").description("Generate Kysely types from your database").version("0.1.0").option("-o, --out <path>", "Output file path", "./db.d.ts").option("-s, --schema <name>", "Schema to introspect (can be specified multiple times)", collect, []).option("--url <connection-string>", "Database connection string (overrides DATABASE_URL env)").option("-d, --dialect <name>", "Database dialect (postgres, mysql, sqlite). Auto-detected from URL if not specified").option("--camel-case", "Convert column and table names to camelCase (use with Kysely CamelCasePlugin)").option("--include-pattern <pattern>", "Only include tables matching glob pattern (schema.table format)", collect, []).option("--exclude-pattern <pattern>", "Exclude tables matching glob pattern (schema.table format)", collect, []).option("--print", "Output to stdout instead of writing to file").option("--verify", "Verify types match existing file (exit 1 if different)").action(async (options) => {
|
|
111524
|
+
program2.name("kysely-gen").description("Generate Kysely types from your database").version("0.1.0").option("-o, --out <path>", "Output file path", "./db.d.ts").option("-s, --schema <name>", "Schema to introspect (can be specified multiple times)", collect, []).option("--url <connection-string>", "Database connection string (overrides DATABASE_URL env)").option("-d, --dialect <name>", "Database dialect (postgres, mysql, sqlite). Auto-detected from URL if not specified").option("--camel-case", "Convert column and table names to camelCase (use with Kysely CamelCasePlugin)").option("--include-pattern <pattern>", "Only include tables matching glob pattern (schema.table format)", collect, []).option("--exclude-pattern <pattern>", "Exclude tables matching glob pattern (schema.table format)", collect, []).option("--print", "Output to stdout instead of writing to file").option("--verify", "Verify types match existing file (exit 1 if different)").option("--zod", "Generate Zod schemas with inferred types instead of TypeScript interfaces").action(async (options) => {
|
|
111130
111525
|
try {
|
|
111131
111526
|
await generate(options);
|
|
111132
111527
|
} catch (error2) {
|
|
@@ -111176,7 +111571,8 @@ async function generate(options) {
|
|
|
111176
111571
|
dialectName = detected;
|
|
111177
111572
|
}
|
|
111178
111573
|
const dialect = getDialect2(dialectName);
|
|
111179
|
-
const
|
|
111574
|
+
const defaultOutputPath = options.zod ? "./db-schemas.ts" : "./db.d.ts";
|
|
111575
|
+
const outputPath = options.out === "./db.d.ts" && options.zod ? defaultOutputPath : options.out;
|
|
111180
111576
|
const defaultSchema = dialectName === "sqlite" ? "main" : dialectName === "mssql" ? "dbo" : "public";
|
|
111181
111577
|
const schemas = options.schema.length > 0 ? options.schema : [defaultSchema];
|
|
111182
111578
|
log("");
|
|
@@ -111212,14 +111608,25 @@ async function generate(options) {
|
|
|
111212
111608
|
return;
|
|
111213
111609
|
}
|
|
111214
111610
|
spinner.succeed(`Found ${source_default.bold(tableCount)} tables and ${source_default.bold(enumCount)} enums`);
|
|
111215
|
-
|
|
111216
|
-
|
|
111217
|
-
|
|
111218
|
-
|
|
111219
|
-
|
|
111220
|
-
|
|
111221
|
-
|
|
111222
|
-
|
|
111611
|
+
let code;
|
|
111612
|
+
let warnings = [];
|
|
111613
|
+
if (options.zod) {
|
|
111614
|
+
spinner.start("Generating Zod schemas...");
|
|
111615
|
+
const zodProgram = transformDatabaseToZod(metadata, {
|
|
111616
|
+
camelCase: options.camelCase
|
|
111617
|
+
});
|
|
111618
|
+
code = serializeZod(zodProgram);
|
|
111619
|
+
} else {
|
|
111620
|
+
spinner.start("Generating TypeScript types...");
|
|
111621
|
+
const { program: astProgram, warnings: tsWarnings } = transformDatabase(metadata, {
|
|
111622
|
+
dialectName,
|
|
111623
|
+
camelCase: options.camelCase,
|
|
111624
|
+
includePattern: options.includePattern.length > 0 ? options.includePattern : undefined,
|
|
111625
|
+
excludePattern: options.excludePattern.length > 0 ? options.excludePattern : undefined
|
|
111626
|
+
});
|
|
111627
|
+
code = serialize(astProgram);
|
|
111628
|
+
warnings = tsWarnings;
|
|
111629
|
+
}
|
|
111223
111630
|
if (options.verify) {
|
|
111224
111631
|
const absolutePath = resolve(outputPath);
|
|
111225
111632
|
const existing = await readFile(absolutePath, "utf-8").catch(() => null);
|
|
@@ -111240,13 +111647,14 @@ async function generate(options) {
|
|
|
111240
111647
|
await db.destroy();
|
|
111241
111648
|
process.exit(1);
|
|
111242
111649
|
}
|
|
111650
|
+
const outputLabel = options.zod ? "Zod schemas" : "Types";
|
|
111243
111651
|
if (printMode) {
|
|
111244
|
-
spinner.succeed(
|
|
111652
|
+
spinner.succeed(`${outputLabel} generated`);
|
|
111245
111653
|
process.stdout.write(code);
|
|
111246
111654
|
} else {
|
|
111247
111655
|
const absolutePath = resolve(outputPath);
|
|
111248
111656
|
await writeFile(absolutePath, code, "utf-8");
|
|
111249
|
-
spinner.succeed(
|
|
111657
|
+
spinner.succeed(`${outputLabel} written to ${source_default.cyan(absolutePath)}`);
|
|
111250
111658
|
}
|
|
111251
111659
|
if (warnings.length > 0) {
|
|
111252
111660
|
log("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kysely-gen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Database type generator for Kysely - Supports PostgreSQL, MySQL, SQLite, and MSSQL",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
"typegen",
|
|
27
27
|
"type-generator",
|
|
28
28
|
"database",
|
|
29
|
-
"sql"
|
|
29
|
+
"sql",
|
|
30
|
+
"zod",
|
|
31
|
+
"validation"
|
|
30
32
|
],
|
|
31
33
|
"engines": {
|
|
32
34
|
"node": ">=20.0.0",
|
|
@@ -73,7 +75,8 @@
|
|
|
73
75
|
"mysql2": "^3.11.0",
|
|
74
76
|
"tarn": "^3.0.2",
|
|
75
77
|
"tedious": "^18.0.0",
|
|
76
|
-
"typescript": "^5.6.3"
|
|
78
|
+
"typescript": "^5.6.3",
|
|
79
|
+
"zod": "^4.3.5"
|
|
77
80
|
},
|
|
78
81
|
"peerDependencies": {
|
|
79
82
|
"kysely": ">=0.27.0 <1.0.0",
|
|
@@ -81,7 +84,8 @@
|
|
|
81
84
|
"mysql2": ">=3.0.0 <4.0.0",
|
|
82
85
|
"better-sqlite3": ">=9.0.0 <13.0.0",
|
|
83
86
|
"tedious": ">=16.0.0 <19.0.0",
|
|
84
|
-
"tarn": ">=3.0.0 <4.0.0"
|
|
87
|
+
"tarn": ">=3.0.0 <4.0.0",
|
|
88
|
+
"zod": ">=4.0.0 <5.0.0"
|
|
85
89
|
},
|
|
86
90
|
"peerDependenciesMeta": {
|
|
87
91
|
"pg": {
|
|
@@ -98,6 +102,9 @@
|
|
|
98
102
|
},
|
|
99
103
|
"tarn": {
|
|
100
104
|
"optional": true
|
|
105
|
+
},
|
|
106
|
+
"zod": {
|
|
107
|
+
"optional": true
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
}
|