kysely-gen 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/cli.js +121 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ npx kysely-gen --dialect mysql --url mysql://user:pass@localhost:3306/db
|
|
|
52
52
|
| `--include-pattern <glob>` | Only include matching tables |
|
|
53
53
|
| `--exclude-pattern <glob>` | Exclude matching tables |
|
|
54
54
|
| `--zod` | Generate Zod schemas instead of TypeScript interfaces |
|
|
55
|
+
| `--no-boolean-coerce` | Output `0 \| 1` instead of coercing to `boolean` for CHECK constraints |
|
|
55
56
|
|
|
56
57
|
## Zod Schema Generation
|
|
57
58
|
|
|
@@ -159,6 +160,21 @@ export interface DB {
|
|
|
159
160
|
- All MSSQL types: `uniqueidentifier`, `datetime2`, `datetimeoffset`, `money`, `xml`, `varbinary`, etc.
|
|
160
161
|
- Both URL (`mssql://`) and ADO.NET connection string formats
|
|
161
162
|
|
|
163
|
+
### Boolean Coercion (SQLite/MSSQL)
|
|
164
|
+
|
|
165
|
+
SQLite and MSSQL store booleans as integers (0/1). When a `CHECK(col IN (0, 1))` constraint is detected, kysely-gen generates:
|
|
166
|
+
|
|
167
|
+
**TypeScript:** `boolean`
|
|
168
|
+
**Zod:** `z.union([z.literal(0), z.literal(1)]).transform(v => v === 1)`
|
|
169
|
+
|
|
170
|
+
The Zod transform coerces the raw 0/1 from the database to `true`/`false`, ensuring runtime validation passes.
|
|
171
|
+
|
|
172
|
+
Use `--no-boolean-coerce` to output raw `0 | 1` instead:
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
kysely-gen --zod --no-boolean-coerce
|
|
176
|
+
```
|
|
177
|
+
|
|
162
178
|
## Type Mappings
|
|
163
179
|
|
|
164
180
|
Types are generated to match the default behavior of each database driver. If you customize your driver's type parsers, the generated types may not match.
|
package/dist/cli.js
CHANGED
|
@@ -109669,7 +109669,17 @@ function transformColumn(column, enums, enumResolver, mapType, options, unknownT
|
|
|
109669
109669
|
}
|
|
109670
109670
|
} else if (column.checkConstraint) {
|
|
109671
109671
|
if (column.checkConstraint.type === "boolean") {
|
|
109672
|
-
|
|
109672
|
+
if (options?.noBooleanCoerce) {
|
|
109673
|
+
type = {
|
|
109674
|
+
kind: "union",
|
|
109675
|
+
types: [
|
|
109676
|
+
{ kind: "literal", value: 0 },
|
|
109677
|
+
{ kind: "literal", value: 1 }
|
|
109678
|
+
]
|
|
109679
|
+
};
|
|
109680
|
+
} else {
|
|
109681
|
+
type = { kind: "primitive", value: "boolean" };
|
|
109682
|
+
}
|
|
109673
109683
|
if (column.isNullable) {
|
|
109674
109684
|
type = {
|
|
109675
109685
|
kind: "union",
|
|
@@ -109848,6 +109858,46 @@ function isBooleanPattern(values) {
|
|
|
109848
109858
|
const sorted = [...values].sort((a, b) => a - b);
|
|
109849
109859
|
return sorted[0] === 0 && sorted[1] === 1;
|
|
109850
109860
|
}
|
|
109861
|
+
var MSSQL_IN_REGEX = /\[\w+\]\s+IN\s*\(([^)]+)\)/i;
|
|
109862
|
+
function parseMssqlCheckConstraint(definition) {
|
|
109863
|
+
if (!definition || definition.trim() === "")
|
|
109864
|
+
return null;
|
|
109865
|
+
const inMatch = definition.match(MSSQL_IN_REGEX);
|
|
109866
|
+
if (inMatch) {
|
|
109867
|
+
const valuesPart = inMatch[1];
|
|
109868
|
+
if (!valuesPart || valuesPart.trim() === "")
|
|
109869
|
+
return null;
|
|
109870
|
+
const numericValues = parseNumericArray(valuesPart);
|
|
109871
|
+
if (numericValues !== null) {
|
|
109872
|
+
if (isBooleanPattern(numericValues)) {
|
|
109873
|
+
return { type: "boolean" };
|
|
109874
|
+
}
|
|
109875
|
+
return { type: "number", values: numericValues };
|
|
109876
|
+
}
|
|
109877
|
+
const stringValues = parseStringArray(valuesPart);
|
|
109878
|
+
if (stringValues !== null && stringValues.length > 0) {
|
|
109879
|
+
return { type: "string", values: stringValues };
|
|
109880
|
+
}
|
|
109881
|
+
}
|
|
109882
|
+
if (definition.includes(" OR ")) {
|
|
109883
|
+
const values = parseMssqlOrChain(definition);
|
|
109884
|
+
if (values !== null && values.length > 0) {
|
|
109885
|
+
return { type: "string", values };
|
|
109886
|
+
}
|
|
109887
|
+
}
|
|
109888
|
+
return null;
|
|
109889
|
+
}
|
|
109890
|
+
function parseMssqlOrChain(definition) {
|
|
109891
|
+
const values = [];
|
|
109892
|
+
let match;
|
|
109893
|
+
const regex2 = /\[\w+\]='((?:[^']|'')*)'/g;
|
|
109894
|
+
while ((match = regex2.exec(definition)) !== null) {
|
|
109895
|
+
let value = match[1];
|
|
109896
|
+
value = value.replace(/''/g, "'");
|
|
109897
|
+
values.push(value);
|
|
109898
|
+
}
|
|
109899
|
+
return values.length > 0 ? values : null;
|
|
109900
|
+
}
|
|
109851
109901
|
|
|
109852
109902
|
// src/dialects/postgres/introspect.ts
|
|
109853
109903
|
async function introspectPostgres(db, options) {
|
|
@@ -110857,11 +110907,22 @@ class SqliteDialect2 {
|
|
|
110857
110907
|
|
|
110858
110908
|
// src/dialects/mssql/introspect.ts
|
|
110859
110909
|
async function introspectMssql(db, options) {
|
|
110860
|
-
const [baseTables, views] = await Promise.all([
|
|
110910
|
+
const [baseTables, views, checkConstraints] = await Promise.all([
|
|
110861
110911
|
introspectTables4(db, options.schemas),
|
|
110862
|
-
introspectViews4(db, options.schemas)
|
|
110912
|
+
introspectViews4(db, options.schemas),
|
|
110913
|
+
introspectCheckConstraints3(db, options.schemas)
|
|
110863
110914
|
]);
|
|
110864
|
-
const tables = [...baseTables, ...views]
|
|
110915
|
+
const tables = [...baseTables, ...views].map((table) => ({
|
|
110916
|
+
...table,
|
|
110917
|
+
columns: table.columns.map((column) => {
|
|
110918
|
+
const key = `${table.schema}.${table.name}.${column.name}`;
|
|
110919
|
+
const checkConstraint = checkConstraints.get(key);
|
|
110920
|
+
return {
|
|
110921
|
+
...column,
|
|
110922
|
+
...checkConstraint && { checkConstraint }
|
|
110923
|
+
};
|
|
110924
|
+
})
|
|
110925
|
+
}));
|
|
110865
110926
|
return {
|
|
110866
110927
|
tables,
|
|
110867
110928
|
enums: []
|
|
@@ -110937,6 +110998,35 @@ function buildTableMetadata2(rows, isView) {
|
|
|
110937
110998
|
}
|
|
110938
110999
|
return Array.from(tableMap.values());
|
|
110939
111000
|
}
|
|
111001
|
+
async function introspectCheckConstraints3(db, schemas) {
|
|
111002
|
+
const rawConstraints = await sql`
|
|
111003
|
+
SELECT
|
|
111004
|
+
s.name AS schema_name,
|
|
111005
|
+
t.name AS table_name,
|
|
111006
|
+
c.name AS column_name,
|
|
111007
|
+
cc.definition AS check_definition
|
|
111008
|
+
FROM sys.check_constraints cc
|
|
111009
|
+
JOIN sys.tables t ON cc.parent_object_id = t.object_id
|
|
111010
|
+
JOIN sys.schemas s ON t.schema_id = s.schema_id
|
|
111011
|
+
LEFT JOIN sys.columns c ON cc.parent_column_id = c.column_id AND c.object_id = t.object_id
|
|
111012
|
+
WHERE cc.is_disabled = 0
|
|
111013
|
+
AND cc.parent_column_id > 0
|
|
111014
|
+
AND s.name IN (${sql.join(schemas.map((s) => sql`${s}`))})
|
|
111015
|
+
`.execute(db);
|
|
111016
|
+
const constraintMap = new Map;
|
|
111017
|
+
for (const row of rawConstraints.rows) {
|
|
111018
|
+
if (!row.column_name)
|
|
111019
|
+
continue;
|
|
111020
|
+
const key = `${row.schema_name}.${row.table_name}.${row.column_name}`;
|
|
111021
|
+
if (constraintMap.has(key))
|
|
111022
|
+
continue;
|
|
111023
|
+
const parsed = parseMssqlCheckConstraint(row.check_definition);
|
|
111024
|
+
if (parsed) {
|
|
111025
|
+
constraintMap.set(key, parsed);
|
|
111026
|
+
}
|
|
111027
|
+
}
|
|
111028
|
+
return constraintMap;
|
|
111029
|
+
}
|
|
110940
111030
|
|
|
110941
111031
|
// src/dialects/mssql/type-mapper.ts
|
|
110942
111032
|
function mapMssqlType(dataType, options) {
|
|
@@ -111554,7 +111644,17 @@ function transformColumnToZod(column, enums, enumResolver, mode, options) {
|
|
|
111554
111644
|
}
|
|
111555
111645
|
} else if (column.checkConstraint) {
|
|
111556
111646
|
if (column.checkConstraint.type === "boolean") {
|
|
111557
|
-
|
|
111647
|
+
if (options?.noBooleanCoerce) {
|
|
111648
|
+
schema = {
|
|
111649
|
+
kind: "zod-union",
|
|
111650
|
+
schemas: [
|
|
111651
|
+
{ kind: "zod-literal", value: 0 },
|
|
111652
|
+
{ kind: "zod-literal", value: 1 }
|
|
111653
|
+
]
|
|
111654
|
+
};
|
|
111655
|
+
} else {
|
|
111656
|
+
schema = { kind: "zod-coerce", method: "boolean" };
|
|
111657
|
+
}
|
|
111558
111658
|
} else if (column.checkConstraint.type === "string") {
|
|
111559
111659
|
schema = { kind: "zod-enum", values: column.checkConstraint.values };
|
|
111560
111660
|
} else {
|
|
@@ -111713,6 +111813,10 @@ function serializeZodSchema(node) {
|
|
|
111713
111813
|
return serializeZodReference(node);
|
|
111714
111814
|
case "zod-custom":
|
|
111715
111815
|
return serializeZodCustom(node);
|
|
111816
|
+
case "zod-transform":
|
|
111817
|
+
return serializeZodTransform(node);
|
|
111818
|
+
case "zod-coerce":
|
|
111819
|
+
return serializeZodCoerce(node);
|
|
111716
111820
|
}
|
|
111717
111821
|
}
|
|
111718
111822
|
function serializeZodPrimitive(node) {
|
|
@@ -111762,6 +111866,12 @@ function serializeZodReference(node) {
|
|
|
111762
111866
|
function serializeZodCustom(node) {
|
|
111763
111867
|
return `z.custom<${node.typeReference}>()`;
|
|
111764
111868
|
}
|
|
111869
|
+
function serializeZodTransform(node) {
|
|
111870
|
+
return `${serializeZodSchema(node.schema)}.transform(${node.transformFn})`;
|
|
111871
|
+
}
|
|
111872
|
+
function serializeZodCoerce(node) {
|
|
111873
|
+
return `z.coerce.${node.method}()`;
|
|
111874
|
+
}
|
|
111765
111875
|
function serializeZodDeclaration(node) {
|
|
111766
111876
|
switch (node.kind) {
|
|
111767
111877
|
case "zod-import":
|
|
@@ -111788,7 +111898,7 @@ function serializeZod(program2) {
|
|
|
111788
111898
|
|
|
111789
111899
|
// src/cli.ts
|
|
111790
111900
|
var program2 = new Command;
|
|
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) => {
|
|
111901
|
+
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").option("--no-boolean-coerce", "Output 0 | 1 instead of coercing to boolean for CHECK(col IN (0, 1))").action(async (options) => {
|
|
111792
111902
|
try {
|
|
111793
111903
|
await generate(options);
|
|
111794
111904
|
} catch (error2) {
|
|
@@ -111877,10 +111987,12 @@ async function generate(options) {
|
|
|
111877
111987
|
spinner.succeed(`Found ${source_default.bold(tableCount)} tables and ${source_default.bold(enumCount)} enums`);
|
|
111878
111988
|
let code;
|
|
111879
111989
|
let warnings = [];
|
|
111990
|
+
const noBooleanCoerce = options.booleanCoerce === false;
|
|
111880
111991
|
if (options.zod) {
|
|
111881
111992
|
spinner.start("Generating Zod schemas...");
|
|
111882
111993
|
const zodProgram = transformDatabaseToZod(metadata, {
|
|
111883
|
-
camelCase: options.camelCase
|
|
111994
|
+
camelCase: options.camelCase,
|
|
111995
|
+
noBooleanCoerce
|
|
111884
111996
|
});
|
|
111885
111997
|
code = serializeZod(zodProgram);
|
|
111886
111998
|
} else {
|
|
@@ -111889,7 +112001,8 @@ async function generate(options) {
|
|
|
111889
112001
|
dialectName,
|
|
111890
112002
|
camelCase: options.camelCase,
|
|
111891
112003
|
includePattern: options.includePattern.length > 0 ? options.includePattern : undefined,
|
|
111892
|
-
excludePattern: options.excludePattern.length > 0 ? options.excludePattern : undefined
|
|
112004
|
+
excludePattern: options.excludePattern.length > 0 ? options.excludePattern : undefined,
|
|
112005
|
+
noBooleanCoerce
|
|
111893
112006
|
});
|
|
111894
112007
|
code = serialize(astProgram);
|
|
111895
112008
|
warnings = tsWarnings;
|