mirror of
https://github.com/theoludwig/kysely-typegen.git
synced 2026-05-22 16:23:25 +02:00
feat: add SQLite support
Adds `KyselyTypegenSQLiteDialect`, exported from `kysely-typegen/sqlite`.
This commit is contained in:
@@ -16,7 +16,7 @@ Why `kysely-typegen` if there is already `kysely-codegen`? Comparison:
|
||||
| **Dependencies** | 35 total | 0 (no runtime dependencies) |
|
||||
| **Type** | CLI | Library/Programmatic Usage |
|
||||
| **Code Size/Maintainability** | Heavy | Lightweight/Simple and straightforward (string manipulation instead of complex AST) |
|
||||
| **Database Support** | PostgreSQL, MySQL, SQLite, MSSQL, LibSQL | PostgreSQL, MySQL (**can be easily extended to more**) |
|
||||
| **Database Support** | PostgreSQL, MySQL, SQLite, MSSQL, LibSQL | PostgreSQL, MySQL, SQLite (**can be easily extended to more**) |
|
||||
|
||||
`kysely-typegen` is a **library** (not a CLI), which means you are in control of where and how to run it, and is designed to be **extensible**, easy to add support for more database dialects.
|
||||
|
||||
@@ -107,6 +107,28 @@ export const database = new Kysely<DB>({ dialect })
|
||||
export const databaseTypegen = new KyselyTypegenMySQLDialect({ database })
|
||||
```
|
||||
|
||||
#### SQLite
|
||||
|
||||
```sh
|
||||
npm install better-sqlite3
|
||||
```
|
||||
|
||||
```ts
|
||||
// database.ts
|
||||
import Database from "better-sqlite3"
|
||||
import { Kysely, SqliteDialect } from "kysely"
|
||||
import { KyselyTypegenSQLiteDialect } from "kysely-typegen/sqlite"
|
||||
|
||||
import type { DB } from "./codegen.ts"
|
||||
|
||||
const dialect = new SqliteDialect({
|
||||
database: new Database(process.env["DATABASE_PATH"] ?? "database.sqlite"),
|
||||
})
|
||||
|
||||
export const database = new Kysely<DB>({ dialect })
|
||||
export const databaseTypegen = new KyselyTypegenSQLiteDialect({ database })
|
||||
```
|
||||
|
||||
### Generate the type definitions
|
||||
|
||||
Create a script that uses `databaseTypegen` to introspect your database and write the generated types to a file. This script is the same regardless of the underlying database:
|
||||
@@ -148,7 +170,7 @@ Fully type-safe queries derived from your actual database schema.
|
||||
|
||||
## Extending to other database dialects
|
||||
|
||||
`kysely-typegen` ships with `KyselyTypegenPostgresDialect` and `KyselyTypegenMySQLDialect`, but you can add support for any database by extending the abstract `KyselyTypegenDialect` class.
|
||||
`kysely-typegen` ships with `KyselyTypegenPostgresDialect`, `KyselyTypegenMySQLDialect`, and `KyselyTypegenSQLiteDialect`, but you can add support for any database by extending the abstract `KyselyTypegenDialect` class.
|
||||
|
||||
Only one thing is required:
|
||||
|
||||
@@ -189,6 +211,8 @@ protected override async introspectEnums(): Promise<IntrospectedEnums> {
|
||||
}
|
||||
```
|
||||
|
||||
If your database needs to normalize column type spellings before scalar lookup (e.g. strip `VARCHAR(255)` → `VARCHAR`, or uppercase keys), override the optional `normalizeDataType(dataType: string): string` hook.
|
||||
|
||||
The base class handles introspection (via Kysely's `database.introspection.getTables()`), sorting, and the final type generation. Contributions of new dialects are welcome!
|
||||
|
||||
## Contributing
|
||||
|
||||
Generated
+253
@@ -11,8 +11,10 @@
|
||||
"devDependencies": {
|
||||
"@testcontainers/mysql": "12.0.0",
|
||||
"@testcontainers/postgresql": "12.0.0",
|
||||
"@types/better-sqlite3": "7.6.13",
|
||||
"@types/node": "25.9.1",
|
||||
"@types/pg": "8.20.0",
|
||||
"better-sqlite3": "12.10.0",
|
||||
"kysely": "0.29.2",
|
||||
"kysely-postgres-js": "3.0.0",
|
||||
"mysql2": "3.22.3",
|
||||
@@ -2288,6 +2290,16 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/better-sqlite3": {
|
||||
"version": "7.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz",
|
||||
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/docker-modem": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/docker-modem/-/docker-modem-3.0.6.tgz",
|
||||
@@ -2867,6 +2879,31 @@
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/better-sqlite3": {
|
||||
"version": "12.10.0",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.10.0.tgz",
|
||||
"integrity": "sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"prebuild-install": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20.x || 22.x || 23.x || 24.x || 25.x || 26.x"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/birpc": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/birpc/-/birpc-4.0.0.tgz",
|
||||
@@ -3659,6 +3696,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
@@ -3686,6 +3739,16 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@@ -4147,6 +4210,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR WTFPL)",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz",
|
||||
@@ -4187,6 +4260,13 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
@@ -4385,6 +4465,13 @@
|
||||
"traverse": "0.6.8"
|
||||
}
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "10.5.0",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
|
||||
@@ -5189,6 +5276,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
@@ -5311,6 +5411,13 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/napi-build-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/neo-async": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||
@@ -5325,6 +5432,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.92.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz",
|
||||
"integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-emoji": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz",
|
||||
@@ -7939,6 +8059,79 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
|
||||
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
|
||||
"deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.0",
|
||||
"expand-template": "^2.0.3",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp-classic": "^0.5.3",
|
||||
"napi-build-utils": "^2.0.0",
|
||||
"node-abi": "^3.3.0",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"simple-get": "^4.0.0",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"prebuild-install": "bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/tar-fs": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
|
||||
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/prebuild-install/node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-ms": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz",
|
||||
@@ -8572,6 +8765,53 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-concat": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/simple-get": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
|
||||
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"decompress-response": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/skin-tone": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz",
|
||||
@@ -9311,6 +9551,19 @@
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
".": "./dist/index.mjs",
|
||||
"./mysql": "./dist/mysql.mjs",
|
||||
"./postgres": "./dist/postgres.mjs",
|
||||
"./sqlite": "./dist/sqlite.mjs",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"publishConfig": {
|
||||
@@ -42,8 +43,10 @@
|
||||
"devDependencies": {
|
||||
"@testcontainers/mysql": "12.0.0",
|
||||
"@testcontainers/postgresql": "12.0.0",
|
||||
"@types/better-sqlite3": "7.6.13",
|
||||
"@types/node": "25.9.1",
|
||||
"@types/pg": "8.20.0",
|
||||
"better-sqlite3": "12.10.0",
|
||||
"kysely": "0.29.2",
|
||||
"kysely-postgres-js": "3.0.0",
|
||||
"mysql2": "3.22.3",
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
exports[`typegen SQLite > generate types matching snapshot 1`] = `
|
||||
{
|
||||
"lines": [
|
||||
"// This file was automatically generated by \`kysely-typegen\`.",
|
||||
"// Do not edit this file manually.",
|
||||
"",
|
||||
"import type { ColumnType } from \\"kysely\\"",
|
||||
"",
|
||||
"export type Generated<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>",
|
||||
"",
|
||||
"export type Timestamp = ColumnType<Date, Date | string, Date | string>",
|
||||
"",
|
||||
"export type Numeric = ColumnType<string, number | string, number | string>",
|
||||
"",
|
||||
"export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>",
|
||||
"",
|
||||
"export type Json = JsonValue",
|
||||
"",
|
||||
"export type JsonArray = JsonValue[]",
|
||||
"",
|
||||
"export interface JsonObject {",
|
||||
" [x: string]: JsonValue | undefined",
|
||||
"}",
|
||||
"",
|
||||
"export type JsonPrimitive = boolean | number | string | null",
|
||||
"",
|
||||
"export type JsonValue = JsonArray | JsonObject | JsonPrimitive",
|
||||
"",
|
||||
"export interface AllTypes {",
|
||||
" colBlob: Buffer",
|
||||
" colBoolean: Generated<number>",
|
||||
" colDatetime: string",
|
||||
" colInteger: number",
|
||||
" colJson: Json",
|
||||
" colNumeric: Numeric",
|
||||
" colReal: number",
|
||||
" colText: string",
|
||||
" colTextNullable: string | null",
|
||||
" colVarchar: string",
|
||||
" id: Generated<number>",
|
||||
"}",
|
||||
"",
|
||||
"export interface Orders {",
|
||||
" amountCents: number",
|
||||
" createdAt: Generated<string>",
|
||||
" id: Generated<number>",
|
||||
" note: string | null",
|
||||
" userId: number",
|
||||
"}",
|
||||
"",
|
||||
"export interface Users {",
|
||||
" createdAt: Generated<string>",
|
||||
" email: string | null",
|
||||
" id: Generated<number>",
|
||||
" isActive: Generated<number>",
|
||||
" username: string",
|
||||
"}",
|
||||
"",
|
||||
"export interface DB {",
|
||||
" AllTypes: AllTypes",
|
||||
" Orders: Orders",
|
||||
" Users: Users",
|
||||
"}"
|
||||
],
|
||||
"tablesCount": 3,
|
||||
"enumsCount": 0,
|
||||
"inlineEnumsCount": 0
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,110 @@
|
||||
import Database from "better-sqlite3"
|
||||
import { Kysely, sql, SqliteDialect } from "kysely"
|
||||
import { after, before, describe, it } from "node:test"
|
||||
|
||||
import { KyselyTypegenSQLiteDialect } from "../sqlite.ts"
|
||||
import "./_setup.ts"
|
||||
|
||||
const createSchema = async (database: Kysely<any>): Promise<void> => {
|
||||
await database.schema
|
||||
.createTable("AllTypes")
|
||||
.addColumn("id", "integer", (column) => {
|
||||
return column.notNull().primaryKey()
|
||||
})
|
||||
.addColumn("colInteger", "integer", (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colReal", "real", (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colText", "text", (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colBlob", "blob", (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colNumeric", sql`NUMERIC`, (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colBoolean", sql`BOOLEAN`, (column) => {
|
||||
return column.notNull().defaultTo(0)
|
||||
})
|
||||
.addColumn("colDatetime", sql`DATETIME`, (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colVarchar", sql`VARCHAR(255)`, (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colJson", sql`JSON`, (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("colTextNullable", "text")
|
||||
.execute()
|
||||
|
||||
await database.schema
|
||||
.createTable("Users")
|
||||
.addColumn("id", "integer", (column) => {
|
||||
return column.notNull().primaryKey()
|
||||
})
|
||||
.addColumn("username", sql`VARCHAR(50)`, (column) => {
|
||||
return column.notNull().unique()
|
||||
})
|
||||
.addColumn("email", "text")
|
||||
.addColumn("isActive", sql`BOOLEAN`, (column) => {
|
||||
return column.notNull().defaultTo(1)
|
||||
})
|
||||
.addColumn("createdAt", sql`DATETIME`, (column) => {
|
||||
return column.notNull().defaultTo(sql`CURRENT_TIMESTAMP`)
|
||||
})
|
||||
.execute()
|
||||
|
||||
await database.schema
|
||||
.createTable("Orders")
|
||||
.addColumn("id", "integer", (column) => {
|
||||
return column.notNull().primaryKey()
|
||||
})
|
||||
.addColumn("userId", "integer", (column) => {
|
||||
return column.notNull().references("Users.id")
|
||||
})
|
||||
.addColumn("amountCents", "integer", (column) => {
|
||||
return column.notNull()
|
||||
})
|
||||
.addColumn("note", "text")
|
||||
.addColumn("createdAt", sql`DATETIME`, (column) => {
|
||||
return column.notNull().defaultTo(sql`CURRENT_TIMESTAMP`)
|
||||
})
|
||||
.execute()
|
||||
}
|
||||
|
||||
describe("typegen SQLite", () => {
|
||||
let database: Kysely<any>
|
||||
|
||||
before(async () => {
|
||||
database = new Kysely<any>({
|
||||
dialect: new SqliteDialect({
|
||||
database: new Database(":memory:"),
|
||||
}),
|
||||
})
|
||||
await createSchema(database)
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
await database.destroy()
|
||||
})
|
||||
|
||||
it("generate types matching snapshot", async (testContext) => {
|
||||
// Arrange - Given
|
||||
const databaseTypegen = new KyselyTypegenSQLiteDialect({ database })
|
||||
|
||||
// Act - When
|
||||
const result = await databaseTypegen.typegen()
|
||||
|
||||
// Assert - Then
|
||||
testContext.assert.snapshot({
|
||||
lines: result.lines,
|
||||
tablesCount: result.tables.length,
|
||||
enumsCount: result.enums.length,
|
||||
inlineEnumsCount: result.inlineEnums.size,
|
||||
})
|
||||
})
|
||||
})
|
||||
+6
-1
@@ -55,6 +55,10 @@ export abstract class KyselyTypegenDialect {
|
||||
})
|
||||
}
|
||||
|
||||
protected normalizeDataType(dataType: string): string {
|
||||
return dataType
|
||||
}
|
||||
|
||||
protected resolveColumnType(
|
||||
table: TableMetadata,
|
||||
column: ColumnMetadata,
|
||||
@@ -65,7 +69,8 @@ export abstract class KyselyTypegenDialect {
|
||||
if (inlineUnion != null) {
|
||||
return inlineUnion
|
||||
}
|
||||
return scalars[column.dataType] ?? "unknown"
|
||||
const dataType = this.normalizeDataType(column.dataType)
|
||||
return scalars[dataType] ?? "unknown"
|
||||
}
|
||||
|
||||
public getTablesTypegen(
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { KyselyTypegenDialect } from "./index.ts"
|
||||
|
||||
export class KyselyTypegenSQLiteDialect extends KyselyTypegenDialect {
|
||||
// SQLite is dynamically typed and pragma_table_info preserves the declared
|
||||
// type spelling verbatim. Lookups are normalized to uppercase, so keys here
|
||||
// must be uppercase. Covers the five storage classes plus popular aliases.
|
||||
public override readonly scalars: Record<string, string> = {
|
||||
BIGINT: "Int8",
|
||||
BLOB: "Buffer",
|
||||
BOOLEAN: "number",
|
||||
CHAR: "string",
|
||||
DATE: "string",
|
||||
DATETIME: "string",
|
||||
DECIMAL: "Numeric",
|
||||
DOUBLE: "number",
|
||||
FLOAT: "number",
|
||||
INTEGER: "number",
|
||||
JSON: "Json",
|
||||
NUMERIC: "Numeric",
|
||||
REAL: "number",
|
||||
TEXT: "string",
|
||||
TIMESTAMP: "string",
|
||||
VARCHAR: "string",
|
||||
}
|
||||
|
||||
protected override normalizeDataType(dataType: string): string {
|
||||
const parenIndex = dataType.indexOf("(")
|
||||
const stripped = parenIndex === -1 ? dataType : dataType.slice(0, parenIndex)
|
||||
return stripped.toUpperCase()
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { defineConfig } from "tsdown"
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["./src/index.ts", "./src/mysql.ts", "./src/postgres.ts"],
|
||||
entry: ["./src/index.ts", "./src/mysql.ts", "./src/postgres.ts", "./src/sqlite.ts"],
|
||||
dts: true,
|
||||
exports: true,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user