kysely-gen 0.9.1 → 0.11.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 +698 -23
- 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
|
@@ -109667,6 +109667,25 @@ function transformColumn(column, enums, enumResolver, mapType, options, unknownT
|
|
|
109667
109667
|
types: [type, { kind: "primitive", value: "null" }]
|
|
109668
109668
|
};
|
|
109669
109669
|
}
|
|
109670
|
+
} else if (column.checkConstraint) {
|
|
109671
|
+
if (column.checkConstraint.type === "boolean") {
|
|
109672
|
+
type = { kind: "primitive", value: "boolean" };
|
|
109673
|
+
if (column.isNullable) {
|
|
109674
|
+
type = {
|
|
109675
|
+
kind: "union",
|
|
109676
|
+
types: [type, { kind: "primitive", value: "null" }]
|
|
109677
|
+
};
|
|
109678
|
+
}
|
|
109679
|
+
} else {
|
|
109680
|
+
const literalTypes = column.checkConstraint.values.map((v) => ({
|
|
109681
|
+
kind: "literal",
|
|
109682
|
+
value: v
|
|
109683
|
+
}));
|
|
109684
|
+
if (column.isNullable) {
|
|
109685
|
+
literalTypes.push({ kind: "primitive", value: "null" });
|
|
109686
|
+
}
|
|
109687
|
+
type = { kind: "union", types: literalTypes };
|
|
109688
|
+
}
|
|
109670
109689
|
} else {
|
|
109671
109690
|
type = mapType(column.dataType, {
|
|
109672
109691
|
isNullable: column.isNullable,
|
|
@@ -109723,25 +109742,139 @@ var Result = import_lib.default.Result;
|
|
|
109723
109742
|
var TypeOverrides = import_lib.default.TypeOverrides;
|
|
109724
109743
|
var defaults = import_lib.default.defaults;
|
|
109725
109744
|
|
|
109745
|
+
// src/utils/check-constraint-parser.ts
|
|
109746
|
+
var ANY_ARRAY_REGEX = /= ANY \(\(?ARRAY\[(.*?)\]\)?(?:::[\w\[\]]+)?\)/;
|
|
109747
|
+
function parseCheckConstraint(definition) {
|
|
109748
|
+
const anyArrayMatch = definition.match(ANY_ARRAY_REGEX);
|
|
109749
|
+
if (anyArrayMatch) {
|
|
109750
|
+
const arrayContent = anyArrayMatch[1];
|
|
109751
|
+
if (!arrayContent || arrayContent.trim() === "")
|
|
109752
|
+
return null;
|
|
109753
|
+
const numericValues = parseNumericArray(arrayContent);
|
|
109754
|
+
if (numericValues !== null) {
|
|
109755
|
+
return { type: "number", values: numericValues };
|
|
109756
|
+
}
|
|
109757
|
+
const stringValues = parseStringArray(arrayContent);
|
|
109758
|
+
if (stringValues !== null && stringValues.length > 0) {
|
|
109759
|
+
return { type: "string", values: stringValues };
|
|
109760
|
+
}
|
|
109761
|
+
}
|
|
109762
|
+
const orValues = parseOrChain(definition);
|
|
109763
|
+
if (orValues !== null && orValues.length > 0) {
|
|
109764
|
+
return { type: "string", values: orValues };
|
|
109765
|
+
}
|
|
109766
|
+
return null;
|
|
109767
|
+
}
|
|
109768
|
+
function parseNumericArray(arrayContent) {
|
|
109769
|
+
const isNumeric = /^\s*-?\d+(\s*,\s*-?\d+)*\s*$/.test(arrayContent);
|
|
109770
|
+
if (!isNumeric)
|
|
109771
|
+
return null;
|
|
109772
|
+
const values = arrayContent.split(",").map((v) => parseInt(v.trim(), 10));
|
|
109773
|
+
if (values.some((v) => isNaN(v)))
|
|
109774
|
+
return null;
|
|
109775
|
+
if (values.length === 0)
|
|
109776
|
+
return null;
|
|
109777
|
+
return values;
|
|
109778
|
+
}
|
|
109779
|
+
function parseStringArray(arrayContent) {
|
|
109780
|
+
const values = [];
|
|
109781
|
+
let current = "";
|
|
109782
|
+
let inQuote = false;
|
|
109783
|
+
let i = 0;
|
|
109784
|
+
while (i < arrayContent.length) {
|
|
109785
|
+
const char = arrayContent[i];
|
|
109786
|
+
if (char === "'" && !inQuote) {
|
|
109787
|
+
inQuote = true;
|
|
109788
|
+
i++;
|
|
109789
|
+
continue;
|
|
109790
|
+
}
|
|
109791
|
+
if (char === "'" && inQuote) {
|
|
109792
|
+
if (arrayContent[i + 1] === "'") {
|
|
109793
|
+
current += "'";
|
|
109794
|
+
i += 2;
|
|
109795
|
+
continue;
|
|
109796
|
+
}
|
|
109797
|
+
values.push(current);
|
|
109798
|
+
current = "";
|
|
109799
|
+
inQuote = false;
|
|
109800
|
+
i++;
|
|
109801
|
+
continue;
|
|
109802
|
+
}
|
|
109803
|
+
if (inQuote) {
|
|
109804
|
+
current += char;
|
|
109805
|
+
}
|
|
109806
|
+
i++;
|
|
109807
|
+
}
|
|
109808
|
+
return values.length > 0 ? values : null;
|
|
109809
|
+
}
|
|
109810
|
+
function parseOrChain(definition) {
|
|
109811
|
+
const singleValueRegex = /\([^)]+= '([^']+)'(?:::[\w]+)?\)/g;
|
|
109812
|
+
const values = [];
|
|
109813
|
+
let match;
|
|
109814
|
+
if (!definition.includes(" OR ")) {
|
|
109815
|
+
return null;
|
|
109816
|
+
}
|
|
109817
|
+
while ((match = singleValueRegex.exec(definition)) !== null) {
|
|
109818
|
+
let value = match[1];
|
|
109819
|
+
value = value.replace(/''/g, "'");
|
|
109820
|
+
values.push(value);
|
|
109821
|
+
}
|
|
109822
|
+
return values.length > 0 ? values : null;
|
|
109823
|
+
}
|
|
109824
|
+
var SQLITE_IN_REGEX = /\w+\s+IN\s*\(([^)]+)\)/i;
|
|
109825
|
+
function parseSqliteCheckConstraint(definition) {
|
|
109826
|
+
const match = definition.match(SQLITE_IN_REGEX);
|
|
109827
|
+
if (!match)
|
|
109828
|
+
return null;
|
|
109829
|
+
const valuesPart = match[1];
|
|
109830
|
+
if (!valuesPart || valuesPart.trim() === "")
|
|
109831
|
+
return null;
|
|
109832
|
+
const numericValues = parseNumericArray(valuesPart);
|
|
109833
|
+
if (numericValues !== null) {
|
|
109834
|
+
if (isBooleanPattern(numericValues)) {
|
|
109835
|
+
return { type: "boolean" };
|
|
109836
|
+
}
|
|
109837
|
+
return { type: "number", values: numericValues };
|
|
109838
|
+
}
|
|
109839
|
+
const stringValues = parseStringArray(valuesPart);
|
|
109840
|
+
if (stringValues !== null && stringValues.length > 0) {
|
|
109841
|
+
return { type: "string", values: stringValues };
|
|
109842
|
+
}
|
|
109843
|
+
return null;
|
|
109844
|
+
}
|
|
109845
|
+
function isBooleanPattern(values) {
|
|
109846
|
+
if (values.length !== 2)
|
|
109847
|
+
return false;
|
|
109848
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
109849
|
+
return sorted[0] === 0 && sorted[1] === 1;
|
|
109850
|
+
}
|
|
109851
|
+
|
|
109726
109852
|
// src/dialects/postgres/introspect.ts
|
|
109727
109853
|
async function introspectPostgres(db, options) {
|
|
109728
|
-
const [domains, partitions, baseTables, regularViews, materializedViews, enums] = await Promise.all([
|
|
109854
|
+
const [domains, partitions, baseTables, regularViews, materializedViews, enums, checkConstraints, domainCheckConstraints] = await Promise.all([
|
|
109729
109855
|
introspectDomains(db),
|
|
109730
109856
|
introspectPartitions(db),
|
|
109731
109857
|
introspectTables(db, options.schemas),
|
|
109732
109858
|
introspectViews(db, options.schemas),
|
|
109733
109859
|
introspectMaterializedViews(db, options.schemas),
|
|
109734
|
-
introspectEnums(db, options.schemas)
|
|
109860
|
+
introspectEnums(db, options.schemas),
|
|
109861
|
+
introspectCheckConstraints(db, options.schemas),
|
|
109862
|
+
introspectDomainCheckConstraints(db, options.schemas)
|
|
109735
109863
|
]);
|
|
109736
109864
|
const tables = [...baseTables, ...regularViews, ...materializedViews].map((table) => {
|
|
109737
109865
|
const isPartition = partitions.some((partition) => partition.schema === table.schema && partition.name === table.name);
|
|
109738
109866
|
return {
|
|
109739
109867
|
...table,
|
|
109740
109868
|
isPartition: isPartition || undefined,
|
|
109741
|
-
columns: table.columns.map((column) =>
|
|
109742
|
-
|
|
109743
|
-
|
|
109744
|
-
|
|
109869
|
+
columns: table.columns.map((column) => {
|
|
109870
|
+
const rootType = getRootType(column, domains);
|
|
109871
|
+
const checkConstraint = getCheckConstraint(table.schema, table.name, column, checkConstraints, domainCheckConstraints, domains);
|
|
109872
|
+
return {
|
|
109873
|
+
...column,
|
|
109874
|
+
dataType: rootType,
|
|
109875
|
+
...checkConstraint && { checkConstraint }
|
|
109876
|
+
};
|
|
109877
|
+
})
|
|
109745
109878
|
};
|
|
109746
109879
|
});
|
|
109747
109880
|
return {
|
|
@@ -109761,6 +109894,8 @@ async function introspectTables(db, schemas) {
|
|
|
109761
109894
|
c.is_nullable,
|
|
109762
109895
|
c.is_identity,
|
|
109763
109896
|
c.column_default,
|
|
109897
|
+
c.domain_name,
|
|
109898
|
+
c.domain_schema,
|
|
109764
109899
|
pg_catalog.col_description(
|
|
109765
109900
|
(c.table_schema||'.'||c.table_name)::regclass::oid,
|
|
109766
109901
|
c.ordinal_position
|
|
@@ -109804,6 +109939,10 @@ async function introspectTables(db, schemas) {
|
|
|
109804
109939
|
if (row.column_comment) {
|
|
109805
109940
|
columnMetadata.comment = row.column_comment;
|
|
109806
109941
|
}
|
|
109942
|
+
if (row.domain_name) {
|
|
109943
|
+
columnMetadata.domainName = row.domain_name;
|
|
109944
|
+
columnMetadata.domainSchema = row.domain_schema ?? undefined;
|
|
109945
|
+
}
|
|
109807
109946
|
table.columns.push(columnMetadata);
|
|
109808
109947
|
}
|
|
109809
109948
|
}
|
|
@@ -109821,6 +109960,8 @@ async function introspectViews(db, schemas) {
|
|
|
109821
109960
|
c.is_nullable,
|
|
109822
109961
|
c.is_identity,
|
|
109823
109962
|
c.column_default,
|
|
109963
|
+
c.domain_name,
|
|
109964
|
+
c.domain_schema,
|
|
109824
109965
|
pg_catalog.col_description(
|
|
109825
109966
|
(c.table_schema||'.'||c.table_name)::regclass::oid,
|
|
109826
109967
|
c.ordinal_position
|
|
@@ -109865,6 +110006,10 @@ async function introspectViews(db, schemas) {
|
|
|
109865
110006
|
if (row.column_comment) {
|
|
109866
110007
|
columnMetadata.comment = row.column_comment;
|
|
109867
110008
|
}
|
|
110009
|
+
if (row.domain_name) {
|
|
110010
|
+
columnMetadata.domainName = row.domain_name;
|
|
110011
|
+
columnMetadata.domainSchema = row.domain_schema ?? undefined;
|
|
110012
|
+
}
|
|
109868
110013
|
table.columns.push(columnMetadata);
|
|
109869
110014
|
}
|
|
109870
110015
|
}
|
|
@@ -110007,6 +110152,72 @@ function parsePostgresArray(value) {
|
|
|
110007
110152
|
}
|
|
110008
110153
|
return [value];
|
|
110009
110154
|
}
|
|
110155
|
+
async function introspectCheckConstraints(db, schemas) {
|
|
110156
|
+
const rawConstraints = await sql`
|
|
110157
|
+
SELECT
|
|
110158
|
+
n.nspname AS table_schema,
|
|
110159
|
+
c.relname AS table_name,
|
|
110160
|
+
a.attname AS column_name,
|
|
110161
|
+
pg_get_constraintdef(pgc.oid) AS check_definition
|
|
110162
|
+
FROM pg_constraint pgc
|
|
110163
|
+
JOIN pg_class c ON pgc.conrelid = c.oid
|
|
110164
|
+
JOIN pg_namespace n ON c.relnamespace = n.oid
|
|
110165
|
+
JOIN pg_attribute a ON a.attrelid = pgc.conrelid AND a.attnum = ANY(pgc.conkey)
|
|
110166
|
+
WHERE pgc.contype = 'c'
|
|
110167
|
+
AND array_length(pgc.conkey, 1) = 1
|
|
110168
|
+
AND n.nspname = ANY(${schemas})
|
|
110169
|
+
`.execute(db);
|
|
110170
|
+
const constraintMap = new Map;
|
|
110171
|
+
for (const row of rawConstraints.rows) {
|
|
110172
|
+
const key = `${row.table_schema}.${row.table_name}.${row.column_name}`;
|
|
110173
|
+
if (constraintMap.has(key))
|
|
110174
|
+
continue;
|
|
110175
|
+
const parsed = parseCheckConstraint(row.check_definition);
|
|
110176
|
+
if (parsed) {
|
|
110177
|
+
constraintMap.set(key, parsed);
|
|
110178
|
+
}
|
|
110179
|
+
}
|
|
110180
|
+
return constraintMap;
|
|
110181
|
+
}
|
|
110182
|
+
async function introspectDomainCheckConstraints(db, schemas) {
|
|
110183
|
+
const rawConstraints = await sql`
|
|
110184
|
+
SELECT
|
|
110185
|
+
n.nspname AS domain_schema,
|
|
110186
|
+
t.typname AS domain_name,
|
|
110187
|
+
pg_get_constraintdef(pgc.oid) AS check_definition
|
|
110188
|
+
FROM pg_constraint pgc
|
|
110189
|
+
JOIN pg_type t ON pgc.contypid = t.oid
|
|
110190
|
+
JOIN pg_namespace n ON t.typnamespace = n.oid
|
|
110191
|
+
WHERE pgc.contype = 'c'
|
|
110192
|
+
AND n.nspname = ANY(${schemas})
|
|
110193
|
+
`.execute(db);
|
|
110194
|
+
const constraintMap = new Map;
|
|
110195
|
+
for (const row of rawConstraints.rows) {
|
|
110196
|
+
const key = `${row.domain_schema}.${row.domain_name}`;
|
|
110197
|
+
if (constraintMap.has(key))
|
|
110198
|
+
continue;
|
|
110199
|
+
const parsed = parseCheckConstraint(row.check_definition);
|
|
110200
|
+
if (parsed) {
|
|
110201
|
+
constraintMap.set(key, parsed);
|
|
110202
|
+
}
|
|
110203
|
+
}
|
|
110204
|
+
return constraintMap;
|
|
110205
|
+
}
|
|
110206
|
+
function getCheckConstraint(tableSchema, tableName, column, checkConstraints, domainCheckConstraints, domains) {
|
|
110207
|
+
const columnKey = `${tableSchema}.${tableName}.${column.name}`;
|
|
110208
|
+
const directConstraint = checkConstraints.get(columnKey);
|
|
110209
|
+
if (directConstraint) {
|
|
110210
|
+
return directConstraint;
|
|
110211
|
+
}
|
|
110212
|
+
if (column.domainName && column.domainSchema) {
|
|
110213
|
+
const domainKey = `${column.domainSchema}.${column.domainName}`;
|
|
110214
|
+
const domainConstraint = domainCheckConstraints.get(domainKey);
|
|
110215
|
+
if (domainConstraint) {
|
|
110216
|
+
return domainConstraint;
|
|
110217
|
+
}
|
|
110218
|
+
}
|
|
110219
|
+
return;
|
|
110220
|
+
}
|
|
110010
110221
|
|
|
110011
110222
|
// src/dialects/postgres/type-mapper.ts
|
|
110012
110223
|
function helper(name, options) {
|
|
@@ -110457,10 +110668,27 @@ class MysqlDialect2 {
|
|
|
110457
110668
|
}
|
|
110458
110669
|
}
|
|
110459
110670
|
|
|
110671
|
+
// src/utils/sqlite-ddl-parser.ts
|
|
110672
|
+
function parseSqliteTableDDL(sql2) {
|
|
110673
|
+
const constraints = [];
|
|
110674
|
+
const checkRegex = /CHECK\s*\(\s*(\w+)\s+IN\s*\(([^)]+)\)\s*\)/gi;
|
|
110675
|
+
let match;
|
|
110676
|
+
while ((match = checkRegex.exec(sql2)) !== null) {
|
|
110677
|
+
const columnName = match[1];
|
|
110678
|
+
const valuesPart = match[2];
|
|
110679
|
+
constraints.push({
|
|
110680
|
+
columnName,
|
|
110681
|
+
definition: `${columnName} IN (${valuesPart})`
|
|
110682
|
+
});
|
|
110683
|
+
}
|
|
110684
|
+
return constraints;
|
|
110685
|
+
}
|
|
110686
|
+
|
|
110460
110687
|
// src/dialects/sqlite/introspect.ts
|
|
110461
110688
|
async function introspectSqlite(db, _options) {
|
|
110689
|
+
const checkConstraints = await introspectCheckConstraints2(db);
|
|
110462
110690
|
const [baseTables, views] = await Promise.all([
|
|
110463
|
-
introspectTables3(db),
|
|
110691
|
+
introspectTables3(db, checkConstraints),
|
|
110464
110692
|
introspectViews3(db)
|
|
110465
110693
|
]);
|
|
110466
110694
|
return {
|
|
@@ -110468,7 +110696,7 @@ async function introspectSqlite(db, _options) {
|
|
|
110468
110696
|
enums: []
|
|
110469
110697
|
};
|
|
110470
110698
|
}
|
|
110471
|
-
async function introspectTables3(db) {
|
|
110699
|
+
async function introspectTables3(db, checkConstraints) {
|
|
110472
110700
|
const rawTables = await sql`
|
|
110473
110701
|
SELECT name, type FROM sqlite_master
|
|
110474
110702
|
WHERE type = 'table'
|
|
@@ -110477,7 +110705,7 @@ async function introspectTables3(db) {
|
|
|
110477
110705
|
`.execute(db);
|
|
110478
110706
|
const tables = [];
|
|
110479
110707
|
for (const rawTable of rawTables.rows) {
|
|
110480
|
-
const columns = await introspectColumns(db, rawTable.name, false);
|
|
110708
|
+
const columns = await introspectColumns(db, rawTable.name, false, checkConstraints);
|
|
110481
110709
|
tables.push({
|
|
110482
110710
|
schema: "main",
|
|
110483
110711
|
name: rawTable.name,
|
|
@@ -110504,20 +110732,23 @@ async function introspectViews3(db) {
|
|
|
110504
110732
|
}
|
|
110505
110733
|
return tables;
|
|
110506
110734
|
}
|
|
110507
|
-
async function introspectColumns(db, tableName, isView) {
|
|
110735
|
+
async function introspectColumns(db, tableName, isView, checkConstraints) {
|
|
110508
110736
|
const rawColumns = await sql`
|
|
110509
110737
|
PRAGMA table_info(${sql.raw(`'${tableName}'`)})
|
|
110510
110738
|
`.execute(db);
|
|
110511
110739
|
return rawColumns.rows.map((col) => {
|
|
110512
110740
|
const isIntegerPk = col.pk === 1 && col.type.toUpperCase() === "INTEGER";
|
|
110513
110741
|
const isAutoIncrement = !isView && isIntegerPk;
|
|
110742
|
+
const constraintKey = `${tableName}.${col.name}`;
|
|
110743
|
+
const checkConstraint = checkConstraints?.get(constraintKey);
|
|
110514
110744
|
return {
|
|
110515
110745
|
name: col.name,
|
|
110516
110746
|
dataType: normalizeDataType2(col.type),
|
|
110517
110747
|
dataTypeSchema: "main",
|
|
110518
110748
|
isNullable: col.notnull === 0 && col.pk === 0,
|
|
110519
110749
|
isAutoIncrement,
|
|
110520
|
-
hasDefaultValue: col.dflt_value !== null || isAutoIncrement
|
|
110750
|
+
hasDefaultValue: col.dflt_value !== null || isAutoIncrement,
|
|
110751
|
+
...checkConstraint && { checkConstraint }
|
|
110521
110752
|
};
|
|
110522
110753
|
});
|
|
110523
110754
|
}
|
|
@@ -110528,6 +110759,26 @@ function normalizeDataType2(type) {
|
|
|
110528
110759
|
}
|
|
110529
110760
|
return lowerType;
|
|
110530
110761
|
}
|
|
110762
|
+
async function introspectCheckConstraints2(db) {
|
|
110763
|
+
const result = await sql`
|
|
110764
|
+
SELECT name, sql FROM sqlite_master
|
|
110765
|
+
WHERE type = 'table'
|
|
110766
|
+
AND name NOT LIKE 'sqlite_%'
|
|
110767
|
+
AND sql IS NOT NULL
|
|
110768
|
+
`.execute(db);
|
|
110769
|
+
const constraints = new Map;
|
|
110770
|
+
for (const row of result.rows) {
|
|
110771
|
+
const parsed = parseSqliteTableDDL(row.sql);
|
|
110772
|
+
for (const { columnName, definition } of parsed) {
|
|
110773
|
+
const constraint = parseSqliteCheckConstraint(definition);
|
|
110774
|
+
if (constraint) {
|
|
110775
|
+
const key = `${row.name}.${columnName}`;
|
|
110776
|
+
constraints.set(key, constraint);
|
|
110777
|
+
}
|
|
110778
|
+
}
|
|
110779
|
+
}
|
|
110780
|
+
return constraints;
|
|
110781
|
+
}
|
|
110531
110782
|
|
|
110532
110783
|
// src/dialects/sqlite/type-mapper.ts
|
|
110533
110784
|
function mapSqliteType(dataType, options) {
|
|
@@ -111124,9 +111375,420 @@ function detectDialect(connectionString) {
|
|
|
111124
111375
|
}
|
|
111125
111376
|
}
|
|
111126
111377
|
|
|
111378
|
+
// src/zod/type-mapper.ts
|
|
111379
|
+
function mapPostgresTypeToZod(dataType, options) {
|
|
111380
|
+
const { isNullable, isArray, isOptional, mode } = options;
|
|
111381
|
+
if (isArray || dataType.endsWith("[]")) {
|
|
111382
|
+
const baseTypeName = dataType.endsWith("[]") ? dataType.slice(0, -2) : dataType;
|
|
111383
|
+
const elementSchema = mapPostgresTypeToZod(baseTypeName, {
|
|
111384
|
+
isNullable: false,
|
|
111385
|
+
isArray: false,
|
|
111386
|
+
isOptional: false,
|
|
111387
|
+
mode
|
|
111388
|
+
});
|
|
111389
|
+
return applyModifiers({ kind: "zod-array", element: elementSchema }, isNullable, isOptional);
|
|
111390
|
+
}
|
|
111391
|
+
const baseSchema = mapScalarType(dataType, mode);
|
|
111392
|
+
return applyModifiers(baseSchema, isNullable, isOptional);
|
|
111393
|
+
}
|
|
111394
|
+
function applyModifiers(schema, isNullable, isOptional) {
|
|
111395
|
+
const modifiers = [];
|
|
111396
|
+
if (isNullable)
|
|
111397
|
+
modifiers.push("nullable");
|
|
111398
|
+
if (isOptional)
|
|
111399
|
+
modifiers.push("optional");
|
|
111400
|
+
if (modifiers.length > 0) {
|
|
111401
|
+
return { kind: "zod-modified", schema, modifiers };
|
|
111402
|
+
}
|
|
111403
|
+
return schema;
|
|
111404
|
+
}
|
|
111405
|
+
function mapScalarType(dataType, mode) {
|
|
111406
|
+
switch (dataType) {
|
|
111407
|
+
case "int2":
|
|
111408
|
+
case "int4":
|
|
111409
|
+
case "smallint":
|
|
111410
|
+
case "integer":
|
|
111411
|
+
case "float4":
|
|
111412
|
+
case "float8":
|
|
111413
|
+
case "real":
|
|
111414
|
+
case "double precision":
|
|
111415
|
+
return { kind: "zod-primitive", method: "number" };
|
|
111416
|
+
case "int8":
|
|
111417
|
+
case "bigint":
|
|
111418
|
+
if (mode === "select") {
|
|
111419
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111420
|
+
}
|
|
111421
|
+
return {
|
|
111422
|
+
kind: "zod-union",
|
|
111423
|
+
schemas: [
|
|
111424
|
+
{ kind: "zod-primitive", method: "string" },
|
|
111425
|
+
{ kind: "zod-primitive", method: "number" },
|
|
111426
|
+
{ kind: "zod-primitive", method: "bigint" }
|
|
111427
|
+
]
|
|
111428
|
+
};
|
|
111429
|
+
case "numeric":
|
|
111430
|
+
case "decimal":
|
|
111431
|
+
if (mode === "select") {
|
|
111432
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111433
|
+
}
|
|
111434
|
+
return {
|
|
111435
|
+
kind: "zod-union",
|
|
111436
|
+
schemas: [
|
|
111437
|
+
{ kind: "zod-primitive", method: "string" },
|
|
111438
|
+
{ kind: "zod-primitive", method: "number" }
|
|
111439
|
+
]
|
|
111440
|
+
};
|
|
111441
|
+
case "varchar":
|
|
111442
|
+
case "char":
|
|
111443
|
+
case "text":
|
|
111444
|
+
case "citext":
|
|
111445
|
+
case "uuid":
|
|
111446
|
+
case "money":
|
|
111447
|
+
case "time":
|
|
111448
|
+
case "timetz":
|
|
111449
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111450
|
+
case "bool":
|
|
111451
|
+
case "boolean":
|
|
111452
|
+
return { kind: "zod-primitive", method: "boolean" };
|
|
111453
|
+
case "timestamp":
|
|
111454
|
+
case "timestamptz":
|
|
111455
|
+
case "date":
|
|
111456
|
+
if (mode === "select") {
|
|
111457
|
+
return { kind: "zod-primitive", method: "date" };
|
|
111458
|
+
}
|
|
111459
|
+
return {
|
|
111460
|
+
kind: "zod-union",
|
|
111461
|
+
schemas: [
|
|
111462
|
+
{ kind: "zod-primitive", method: "date" },
|
|
111463
|
+
{ kind: "zod-primitive", method: "string" }
|
|
111464
|
+
]
|
|
111465
|
+
};
|
|
111466
|
+
case "interval":
|
|
111467
|
+
return { kind: "zod-primitive", method: "unknown" };
|
|
111468
|
+
case "json":
|
|
111469
|
+
case "jsonb":
|
|
111470
|
+
return { kind: "zod-primitive", method: "unknown" };
|
|
111471
|
+
case "bytea":
|
|
111472
|
+
return { kind: "zod-custom", typeReference: "Buffer" };
|
|
111473
|
+
case "point":
|
|
111474
|
+
return {
|
|
111475
|
+
kind: "zod-object",
|
|
111476
|
+
properties: [
|
|
111477
|
+
{ name: "x", schema: { kind: "zod-primitive", method: "number" } },
|
|
111478
|
+
{ name: "y", schema: { kind: "zod-primitive", method: "number" } }
|
|
111479
|
+
]
|
|
111480
|
+
};
|
|
111481
|
+
case "circle":
|
|
111482
|
+
return {
|
|
111483
|
+
kind: "zod-object",
|
|
111484
|
+
properties: [
|
|
111485
|
+
{ name: "x", schema: { kind: "zod-primitive", method: "number" } },
|
|
111486
|
+
{ name: "y", schema: { kind: "zod-primitive", method: "number" } },
|
|
111487
|
+
{ name: "radius", schema: { kind: "zod-primitive", method: "number" } }
|
|
111488
|
+
]
|
|
111489
|
+
};
|
|
111490
|
+
case "int4range":
|
|
111491
|
+
case "int8range":
|
|
111492
|
+
case "numrange":
|
|
111493
|
+
case "daterange":
|
|
111494
|
+
case "tsrange":
|
|
111495
|
+
case "tstzrange":
|
|
111496
|
+
return { kind: "zod-primitive", method: "string" };
|
|
111497
|
+
default:
|
|
111498
|
+
return { kind: "zod-primitive", method: "unknown" };
|
|
111499
|
+
}
|
|
111500
|
+
}
|
|
111501
|
+
|
|
111502
|
+
// src/zod/transform.ts
|
|
111503
|
+
function uncapitalize(str) {
|
|
111504
|
+
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
111505
|
+
}
|
|
111506
|
+
function getSchemaName(baseName, mode) {
|
|
111507
|
+
const uncap = uncapitalize(baseName);
|
|
111508
|
+
switch (mode) {
|
|
111509
|
+
case "select":
|
|
111510
|
+
return `${uncap}Schema`;
|
|
111511
|
+
case "insert":
|
|
111512
|
+
return `new${baseName}Schema`;
|
|
111513
|
+
case "update":
|
|
111514
|
+
return `${uncap}UpdateSchema`;
|
|
111515
|
+
}
|
|
111516
|
+
}
|
|
111517
|
+
function getTypeName(baseName, mode) {
|
|
111518
|
+
switch (mode) {
|
|
111519
|
+
case "select":
|
|
111520
|
+
return baseName;
|
|
111521
|
+
case "insert":
|
|
111522
|
+
return `New${baseName}`;
|
|
111523
|
+
case "update":
|
|
111524
|
+
return `${baseName}Update`;
|
|
111525
|
+
}
|
|
111526
|
+
}
|
|
111527
|
+
function transformEnumToZod(enumMeta, resolver) {
|
|
111528
|
+
const name = resolver.getName(enumMeta);
|
|
111529
|
+
return {
|
|
111530
|
+
kind: "zod-schema-declaration",
|
|
111531
|
+
name: `${uncapitalize(name)}Schema`,
|
|
111532
|
+
schema: {
|
|
111533
|
+
kind: "zod-enum",
|
|
111534
|
+
values: enumMeta.values
|
|
111535
|
+
},
|
|
111536
|
+
exported: true
|
|
111537
|
+
};
|
|
111538
|
+
}
|
|
111539
|
+
function transformColumnToZod(column, enums, enumResolver, mode, options) {
|
|
111540
|
+
const columnName = options?.camelCase ? toCamelCase(column.name) : column.name;
|
|
111541
|
+
const matchingEnum = enums.find((e) => e.name === column.dataType && e.schema === (column.dataTypeSchema ?? "public"));
|
|
111542
|
+
let schema;
|
|
111543
|
+
const modifiers = [];
|
|
111544
|
+
if (column.isNullable)
|
|
111545
|
+
modifiers.push("nullable");
|
|
111546
|
+
const isOptional = mode === "update" || mode === "insert" && (column.isAutoIncrement || column.hasDefaultValue);
|
|
111547
|
+
if (isOptional)
|
|
111548
|
+
modifiers.push("optional");
|
|
111549
|
+
if (matchingEnum) {
|
|
111550
|
+
const enumName = enumResolver.getName(matchingEnum);
|
|
111551
|
+
schema = { kind: "zod-reference", name: `${uncapitalize(enumName)}Schema` };
|
|
111552
|
+
if (modifiers.length > 0) {
|
|
111553
|
+
schema = { kind: "zod-modified", schema, modifiers };
|
|
111554
|
+
}
|
|
111555
|
+
} else if (column.checkConstraint) {
|
|
111556
|
+
if (column.checkConstraint.type === "boolean") {
|
|
111557
|
+
schema = { kind: "zod-primitive", method: "boolean" };
|
|
111558
|
+
} else if (column.checkConstraint.type === "string") {
|
|
111559
|
+
schema = { kind: "zod-enum", values: column.checkConstraint.values };
|
|
111560
|
+
} else {
|
|
111561
|
+
schema = {
|
|
111562
|
+
kind: "zod-union",
|
|
111563
|
+
schemas: column.checkConstraint.values.map((v) => ({
|
|
111564
|
+
kind: "zod-literal",
|
|
111565
|
+
value: v
|
|
111566
|
+
}))
|
|
111567
|
+
};
|
|
111568
|
+
}
|
|
111569
|
+
if (modifiers.length > 0) {
|
|
111570
|
+
schema = { kind: "zod-modified", schema, modifiers };
|
|
111571
|
+
}
|
|
111572
|
+
} else {
|
|
111573
|
+
schema = mapPostgresTypeToZod(column.dataType, {
|
|
111574
|
+
isNullable: column.isNullable,
|
|
111575
|
+
isArray: column.isArray,
|
|
111576
|
+
isOptional,
|
|
111577
|
+
mode
|
|
111578
|
+
});
|
|
111579
|
+
}
|
|
111580
|
+
return { name: columnName, schema };
|
|
111581
|
+
}
|
|
111582
|
+
function transformTableToZod(table, enums, enumResolver, mode, options) {
|
|
111583
|
+
const baseName = toPascalCase(singularize(table.name));
|
|
111584
|
+
const schemaName = getSchemaName(baseName, mode);
|
|
111585
|
+
const properties = table.columns.map((col) => transformColumnToZod(col, enums, enumResolver, mode, options));
|
|
111586
|
+
return {
|
|
111587
|
+
kind: "zod-schema-declaration",
|
|
111588
|
+
name: schemaName,
|
|
111589
|
+
schema: { kind: "zod-object", properties },
|
|
111590
|
+
exported: true
|
|
111591
|
+
};
|
|
111592
|
+
}
|
|
111593
|
+
function createInferExport(baseName, mode) {
|
|
111594
|
+
return {
|
|
111595
|
+
kind: "zod-infer-export",
|
|
111596
|
+
typeName: getTypeName(baseName, mode),
|
|
111597
|
+
schemaName: getSchemaName(baseName, mode)
|
|
111598
|
+
};
|
|
111599
|
+
}
|
|
111600
|
+
function transformDatabaseToZod(metadata, options) {
|
|
111601
|
+
const declarations = [];
|
|
111602
|
+
declarations.push({ kind: "zod-import" });
|
|
111603
|
+
const enumResolver = new EnumNameResolver(metadata.enums);
|
|
111604
|
+
for (const enumMeta of metadata.enums) {
|
|
111605
|
+
declarations.push(transformEnumToZod(enumMeta, enumResolver));
|
|
111606
|
+
}
|
|
111607
|
+
for (const table of metadata.tables) {
|
|
111608
|
+
const baseName = toPascalCase(singularize(table.name));
|
|
111609
|
+
declarations.push(transformTableToZod(table, metadata.enums, enumResolver, "select", options));
|
|
111610
|
+
declarations.push(transformTableToZod(table, metadata.enums, enumResolver, "insert", options));
|
|
111611
|
+
declarations.push(transformTableToZod(table, metadata.enums, enumResolver, "update", options));
|
|
111612
|
+
declarations.push(createInferExport(baseName, "select"));
|
|
111613
|
+
declarations.push(createInferExport(baseName, "insert"));
|
|
111614
|
+
declarations.push(createInferExport(baseName, "update"));
|
|
111615
|
+
}
|
|
111616
|
+
return { declarations };
|
|
111617
|
+
}
|
|
111618
|
+
|
|
111619
|
+
// src/zod/serialize.ts
|
|
111620
|
+
var RESERVED_WORDS2 = new Set([
|
|
111621
|
+
"break",
|
|
111622
|
+
"case",
|
|
111623
|
+
"catch",
|
|
111624
|
+
"class",
|
|
111625
|
+
"const",
|
|
111626
|
+
"continue",
|
|
111627
|
+
"debugger",
|
|
111628
|
+
"default",
|
|
111629
|
+
"delete",
|
|
111630
|
+
"do",
|
|
111631
|
+
"else",
|
|
111632
|
+
"enum",
|
|
111633
|
+
"export",
|
|
111634
|
+
"extends",
|
|
111635
|
+
"false",
|
|
111636
|
+
"finally",
|
|
111637
|
+
"for",
|
|
111638
|
+
"function",
|
|
111639
|
+
"if",
|
|
111640
|
+
"import",
|
|
111641
|
+
"in",
|
|
111642
|
+
"instanceof",
|
|
111643
|
+
"new",
|
|
111644
|
+
"null",
|
|
111645
|
+
"return",
|
|
111646
|
+
"super",
|
|
111647
|
+
"switch",
|
|
111648
|
+
"this",
|
|
111649
|
+
"throw",
|
|
111650
|
+
"true",
|
|
111651
|
+
"try",
|
|
111652
|
+
"typeof",
|
|
111653
|
+
"var",
|
|
111654
|
+
"void",
|
|
111655
|
+
"while",
|
|
111656
|
+
"with",
|
|
111657
|
+
"yield",
|
|
111658
|
+
"let",
|
|
111659
|
+
"static",
|
|
111660
|
+
"implements",
|
|
111661
|
+
"interface",
|
|
111662
|
+
"package",
|
|
111663
|
+
"private",
|
|
111664
|
+
"protected",
|
|
111665
|
+
"public",
|
|
111666
|
+
"await",
|
|
111667
|
+
"abstract",
|
|
111668
|
+
"as",
|
|
111669
|
+
"async",
|
|
111670
|
+
"declare",
|
|
111671
|
+
"from",
|
|
111672
|
+
"get",
|
|
111673
|
+
"is",
|
|
111674
|
+
"module",
|
|
111675
|
+
"namespace",
|
|
111676
|
+
"of",
|
|
111677
|
+
"require",
|
|
111678
|
+
"set",
|
|
111679
|
+
"type"
|
|
111680
|
+
]);
|
|
111681
|
+
function escapeString2(value) {
|
|
111682
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
111683
|
+
}
|
|
111684
|
+
function needsQuotes2(name) {
|
|
111685
|
+
if (RESERVED_WORDS2.has(name))
|
|
111686
|
+
return true;
|
|
111687
|
+
if (/^\d/.test(name))
|
|
111688
|
+
return true;
|
|
111689
|
+
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))
|
|
111690
|
+
return true;
|
|
111691
|
+
return false;
|
|
111692
|
+
}
|
|
111693
|
+
function serializePropertyName2(name) {
|
|
111694
|
+
return needsQuotes2(name) ? `'${escapeString2(name)}'` : name;
|
|
111695
|
+
}
|
|
111696
|
+
function serializeZodSchema(node) {
|
|
111697
|
+
switch (node.kind) {
|
|
111698
|
+
case "zod-primitive":
|
|
111699
|
+
return serializeZodPrimitive(node);
|
|
111700
|
+
case "zod-literal":
|
|
111701
|
+
return serializeZodLiteral(node);
|
|
111702
|
+
case "zod-union":
|
|
111703
|
+
return serializeZodUnion(node);
|
|
111704
|
+
case "zod-enum":
|
|
111705
|
+
return serializeZodEnum(node);
|
|
111706
|
+
case "zod-array":
|
|
111707
|
+
return serializeZodArray(node);
|
|
111708
|
+
case "zod-object":
|
|
111709
|
+
return serializeZodObject(node);
|
|
111710
|
+
case "zod-modified":
|
|
111711
|
+
return serializeZodModified(node);
|
|
111712
|
+
case "zod-reference":
|
|
111713
|
+
return serializeZodReference(node);
|
|
111714
|
+
case "zod-custom":
|
|
111715
|
+
return serializeZodCustom(node);
|
|
111716
|
+
}
|
|
111717
|
+
}
|
|
111718
|
+
function serializeZodPrimitive(node) {
|
|
111719
|
+
return `z.${node.method}()`;
|
|
111720
|
+
}
|
|
111721
|
+
function serializeZodLiteral(node) {
|
|
111722
|
+
if (typeof node.value === "string") {
|
|
111723
|
+
return `z.literal('${escapeString2(node.value)}')`;
|
|
111724
|
+
}
|
|
111725
|
+
return `z.literal(${node.value})`;
|
|
111726
|
+
}
|
|
111727
|
+
function serializeZodUnion(node) {
|
|
111728
|
+
const schemas = node.schemas.map(serializeZodSchema).join(", ");
|
|
111729
|
+
return `z.union([${schemas}])`;
|
|
111730
|
+
}
|
|
111731
|
+
function serializeZodEnum(node) {
|
|
111732
|
+
const values = node.values.map((v) => `'${escapeString2(v)}'`).join(", ");
|
|
111733
|
+
return `z.enum([${values}])`;
|
|
111734
|
+
}
|
|
111735
|
+
function serializeZodArray(node) {
|
|
111736
|
+
return `z.array(${serializeZodSchema(node.element)})`;
|
|
111737
|
+
}
|
|
111738
|
+
function serializeZodObject(node) {
|
|
111739
|
+
if (node.properties.length === 0) {
|
|
111740
|
+
return "z.object({})";
|
|
111741
|
+
}
|
|
111742
|
+
const props = node.properties.map((p) => serializeZodProperty(p)).join(`,
|
|
111743
|
+
`);
|
|
111744
|
+
return `z.object({
|
|
111745
|
+
${props},
|
|
111746
|
+
})`;
|
|
111747
|
+
}
|
|
111748
|
+
function serializeZodProperty(node) {
|
|
111749
|
+
const name = serializePropertyName2(node.name);
|
|
111750
|
+
return ` ${name}: ${serializeZodSchema(node.schema)}`;
|
|
111751
|
+
}
|
|
111752
|
+
function serializeZodModified(node) {
|
|
111753
|
+
let result = serializeZodSchema(node.schema);
|
|
111754
|
+
for (const mod of node.modifiers) {
|
|
111755
|
+
result += `.${mod}()`;
|
|
111756
|
+
}
|
|
111757
|
+
return result;
|
|
111758
|
+
}
|
|
111759
|
+
function serializeZodReference(node) {
|
|
111760
|
+
return node.name;
|
|
111761
|
+
}
|
|
111762
|
+
function serializeZodCustom(node) {
|
|
111763
|
+
return `z.custom<${node.typeReference}>()`;
|
|
111764
|
+
}
|
|
111765
|
+
function serializeZodDeclaration(node) {
|
|
111766
|
+
switch (node.kind) {
|
|
111767
|
+
case "zod-import":
|
|
111768
|
+
return "import { z } from 'zod';";
|
|
111769
|
+
case "zod-schema-declaration":
|
|
111770
|
+
return serializeZodSchemaDeclaration(node);
|
|
111771
|
+
case "zod-infer-export":
|
|
111772
|
+
return serializeZodInferExport(node);
|
|
111773
|
+
}
|
|
111774
|
+
}
|
|
111775
|
+
function serializeZodSchemaDeclaration(node) {
|
|
111776
|
+
const exported = node.exported ? "export " : "";
|
|
111777
|
+
return `${exported}const ${node.name} = ${serializeZodSchema(node.schema)};`;
|
|
111778
|
+
}
|
|
111779
|
+
function serializeZodInferExport(node) {
|
|
111780
|
+
return `export type ${node.typeName} = z.infer<typeof ${node.schemaName}>;`;
|
|
111781
|
+
}
|
|
111782
|
+
function serializeZod(program2) {
|
|
111783
|
+
return program2.declarations.map(serializeZodDeclaration).join(`
|
|
111784
|
+
|
|
111785
|
+
`) + `
|
|
111786
|
+
`;
|
|
111787
|
+
}
|
|
111788
|
+
|
|
111127
111789
|
// src/cli.ts
|
|
111128
111790
|
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) => {
|
|
111791
|
+
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
111792
|
try {
|
|
111131
111793
|
await generate(options);
|
|
111132
111794
|
} catch (error2) {
|
|
@@ -111176,7 +111838,8 @@ async function generate(options) {
|
|
|
111176
111838
|
dialectName = detected;
|
|
111177
111839
|
}
|
|
111178
111840
|
const dialect = getDialect2(dialectName);
|
|
111179
|
-
const
|
|
111841
|
+
const defaultOutputPath = options.zod ? "./db-schemas.ts" : "./db.d.ts";
|
|
111842
|
+
const outputPath = options.out === "./db.d.ts" && options.zod ? defaultOutputPath : options.out;
|
|
111180
111843
|
const defaultSchema = dialectName === "sqlite" ? "main" : dialectName === "mssql" ? "dbo" : "public";
|
|
111181
111844
|
const schemas = options.schema.length > 0 ? options.schema : [defaultSchema];
|
|
111182
111845
|
log("");
|
|
@@ -111212,14 +111875,25 @@ async function generate(options) {
|
|
|
111212
111875
|
return;
|
|
111213
111876
|
}
|
|
111214
111877
|
spinner.succeed(`Found ${source_default.bold(tableCount)} tables and ${source_default.bold(enumCount)} enums`);
|
|
111215
|
-
|
|
111216
|
-
|
|
111217
|
-
|
|
111218
|
-
|
|
111219
|
-
|
|
111220
|
-
|
|
111221
|
-
|
|
111222
|
-
|
|
111878
|
+
let code;
|
|
111879
|
+
let warnings = [];
|
|
111880
|
+
if (options.zod) {
|
|
111881
|
+
spinner.start("Generating Zod schemas...");
|
|
111882
|
+
const zodProgram = transformDatabaseToZod(metadata, {
|
|
111883
|
+
camelCase: options.camelCase
|
|
111884
|
+
});
|
|
111885
|
+
code = serializeZod(zodProgram);
|
|
111886
|
+
} else {
|
|
111887
|
+
spinner.start("Generating TypeScript types...");
|
|
111888
|
+
const { program: astProgram, warnings: tsWarnings } = transformDatabase(metadata, {
|
|
111889
|
+
dialectName,
|
|
111890
|
+
camelCase: options.camelCase,
|
|
111891
|
+
includePattern: options.includePattern.length > 0 ? options.includePattern : undefined,
|
|
111892
|
+
excludePattern: options.excludePattern.length > 0 ? options.excludePattern : undefined
|
|
111893
|
+
});
|
|
111894
|
+
code = serialize(astProgram);
|
|
111895
|
+
warnings = tsWarnings;
|
|
111896
|
+
}
|
|
111223
111897
|
if (options.verify) {
|
|
111224
111898
|
const absolutePath = resolve(outputPath);
|
|
111225
111899
|
const existing = await readFile(absolutePath, "utf-8").catch(() => null);
|
|
@@ -111240,13 +111914,14 @@ async function generate(options) {
|
|
|
111240
111914
|
await db.destroy();
|
|
111241
111915
|
process.exit(1);
|
|
111242
111916
|
}
|
|
111917
|
+
const outputLabel = options.zod ? "Zod schemas" : "Types";
|
|
111243
111918
|
if (printMode) {
|
|
111244
|
-
spinner.succeed(
|
|
111919
|
+
spinner.succeed(`${outputLabel} generated`);
|
|
111245
111920
|
process.stdout.write(code);
|
|
111246
111921
|
} else {
|
|
111247
111922
|
const absolutePath = resolve(outputPath);
|
|
111248
111923
|
await writeFile(absolutePath, code, "utf-8");
|
|
111249
|
-
spinner.succeed(
|
|
111924
|
+
spinner.succeed(`${outputLabel} written to ${source_default.cyan(absolutePath)}`);
|
|
111250
111925
|
}
|
|
111251
111926
|
if (warnings.length > 0) {
|
|
111252
111927
|
log("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kysely-gen",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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
|
}
|