diff --git a/README.md b/README.md index 5798b73..d94ec1c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ sql: ## Supported engines and drivers -- PostgreSQL via [pg](https://www.npmjs.com/package/pg) or [postgres](https://www.npmjs.com/package/postgres). +- PostgreSQL via [pg](https://www.npmjs.com/package/pg), [postgres](https://www.npmjs.com/package/postgres) or [Bun SQL](https://bun.sh/docs/api/sql). - MySQL via [mysql2](https://www.npmjs.com/package/mysql2). - SQLite via [sqlite3](https://www.npmjs.com/package/better-sqlite3). @@ -291,6 +291,26 @@ sql: driver: postgres # npm package name ``` +### PostgreSQL and Bun SQL + +```yaml +version: '2' +plugins: +- name: ts + wasm: + url: https://downloads.sqlc.dev/plugin/sqlc-gen-typescript_0.1.4.wasm + sha256: 9b2f4eca095a3ba1f0f5e971e371ae52f991396efdb63728fc3e8df92c31ff5f +sql: +- schema: "schema.sql" + queries: "query.sql" + engine: postgresql + codegen: + - out: db + plugin: ts + options: + runtime: bun + driver: bun-sql # to use native SQL library of Bun 1.2 +``` ### MySQL and mysql2 @@ -334,6 +354,27 @@ sql: driver: better-sqlite3 # npm package name ``` +### SQLite and Bun SQLite + +```yaml +version: '2' +plugins: +- name: ts + wasm: + url: https://downloads.sqlc.dev/plugin/sqlc-gen-typescript_0.1.4.wasm + sha256: 9b2f4eca095a3ba1f0f5e971e371ae52f991396efdb63728fc3e8df92c31ff5f +sql: +- schema: "schema.sql" + queries: "query.sql" + engine: sqlite + codegen: + - out: db + plugin: ts + options: + runtime: bun + driver: bun-sqlite # to use native SQLite library of Bun +``` + ## Development If you want to build and test sqlc-gen-typescript locally, follow these steps: @@ -390,4 +431,4 @@ Check the `Makefile` for details. ``` For more details on sqlc development, refer to the sqlc core development guide. This guide provides additional information on setting up and working with sqlc in general, which may be useful for contributors to this project. -https://docs.sqlc.dev/en/latest/guides/development.html \ No newline at end of file +https://docs.sqlc.dev/en/latest/guides/development.html diff --git a/examples/bun-sql/.gitignore b/examples/bun-sql/.gitignore new file mode 100644 index 0000000..ab5afb2 --- /dev/null +++ b/examples/bun-sql/.gitignore @@ -0,0 +1,176 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + diff --git a/examples/bun-sql/README.md b/examples/bun-sql/README.md new file mode 100644 index 0000000..ca7d54c --- /dev/null +++ b/examples/bun-sql/README.md @@ -0,0 +1,15 @@ +# bun-postgres + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run src/main.ts +``` + +This project was created using `bun init` in bun v1.0.11. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/examples/bun-sql/bun.lock b/examples/bun-sql/bun.lock new file mode 100644 index 0000000..5cdc8ee --- /dev/null +++ b/examples/bun-sql/bun.lock @@ -0,0 +1,25 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "bun-postgres", + "devDependencies": { + "bun-types": "latest", + }, + "peerDependencies": { + "typescript": "^5.0.0", + }, + }, + }, + "packages": { + "@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="], + + "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], + + "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="], + + "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], + + "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + } +} diff --git a/examples/bun-sql/package.json b/examples/bun-sql/package.json new file mode 100644 index 0000000..2fe9069 --- /dev/null +++ b/examples/bun-sql/package.json @@ -0,0 +1,11 @@ +{ + "name": "bun-sql", + "module": "src/main.ts", + "type": "module", + "devDependencies": { + "bun-types": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/examples/bun-sql/src/db/query_sql.ts b/examples/bun-sql/src/db/query_sql.ts new file mode 100644 index 0000000..fa977f5 --- /dev/null +++ b/examples/bun-sql/src/db/query_sql.ts @@ -0,0 +1,99 @@ +// Code generated by sqlc. DO NOT EDIT. + +import { SQL } from "bun"; + +export const getAuthorQuery = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = $1 LIMIT 1`; + +export interface GetAuthorArgs { + id: string; +} + +export interface GetAuthorRow { + id: string; + name: string; + bio: string | null; +} + +export async function getAuthor(sql: SQL, args: GetAuthorArgs): Promise { + const rows = await sql.unsafe(getAuthorQuery, [args.id]).values(); + if (rows.length !== 1) { + return null; + } + const row = rows[0]; + if (!row) { + return null; + } + return { + id: row[0], + name: row[1], + bio: row[2] + }; +} + +export const listAuthorsQuery = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name`; + +export interface ListAuthorsRow { + id: string; + name: string; + bio: string | null; +} + +export async function listAuthors(sql: SQL): Promise { + return (await sql.unsafe(listAuthorsQuery, []).values()).map(row => ({ + id: row[0], + name: row[1], + bio: row[2] + })); +} + +export const createAuthorQuery = `-- name: CreateAuthor :one +INSERT INTO authors ( + name, bio +) VALUES ( + $1, $2 +) +RETURNING id, name, bio`; + +export interface CreateAuthorArgs { + name: string; + bio: string | null; +} + +export interface CreateAuthorRow { + id: string; + name: string; + bio: string | null; +} + +export async function createAuthor(sql: SQL, args: CreateAuthorArgs): Promise { + const rows = await sql.unsafe(createAuthorQuery, [args.name, args.bio]).values(); + if (rows.length !== 1) { + return null; + } + const row = rows[0]; + if (!row) { + return null; + } + return { + id: row[0], + name: row[1], + bio: row[2] + }; +} + +export const deleteAuthorQuery = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = $1`; + +export interface DeleteAuthorArgs { + id: string; +} + +export async function deleteAuthor(sql: SQL, args: DeleteAuthorArgs): Promise { + await sql.unsafe(deleteAuthorQuery, [args.id]); +} + diff --git a/examples/bun-sql/src/main.ts b/examples/bun-sql/src/main.ts new file mode 100644 index 0000000..eca4612 --- /dev/null +++ b/examples/bun-sql/src/main.ts @@ -0,0 +1,46 @@ +import { SQL } from "bun"; + +import { + createAuthor, + deleteAuthor, + getAuthor, + listAuthors, +} from "./db/query_sql"; + +async function main() { + const sql = new SQL(); // You can also specify connection options here + + // Create an author + const author = await createAuthor(sql, { + name: "Seal", + bio: "Kissed from a rose", + }); + if (author === null) { + throw new Error("author not created"); + } + console.log(author); + + // List the authors + const authors = await listAuthors(sql); + console.log(authors); + + // Get that author + const seal = await getAuthor(sql, { id: author.id }); + if (seal === null) { + throw new Error("seal not found"); + } + console.log(seal); + + // Delete the author + await deleteAuthor(sql, { id: seal.id }); +} + +(async () => { + try { + await main(); + process.exit(0); + } catch (e) { + console.error(e); + process.exit(1); + } +})(); diff --git a/examples/bun-sql/tsconfig.json b/examples/bun-sql/tsconfig.json new file mode 100644 index 0000000..7556e1d --- /dev/null +++ b/examples/bun-sql/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" // add Bun global + ] + } +} diff --git a/examples/bun-sqlite/.gitignore b/examples/bun-sqlite/.gitignore new file mode 100644 index 0000000..ab5afb2 --- /dev/null +++ b/examples/bun-sqlite/.gitignore @@ -0,0 +1,176 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +\*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +\*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +\*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +\*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.cache +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +.cache/ + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp +.cache + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.\* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + diff --git a/examples/bun-sqlite/README.md b/examples/bun-sqlite/README.md new file mode 100644 index 0000000..ca7d54c --- /dev/null +++ b/examples/bun-sqlite/README.md @@ -0,0 +1,15 @@ +# bun-postgres + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run src/main.ts +``` + +This project was created using `bun init` in bun v1.0.11. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/examples/bun-sqlite/bun.lock b/examples/bun-sqlite/bun.lock new file mode 100644 index 0000000..39a4371 --- /dev/null +++ b/examples/bun-sqlite/bun.lock @@ -0,0 +1,25 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "bun-sqlite", + "devDependencies": { + "bun-types": "latest", + }, + "peerDependencies": { + "typescript": "^5.0.0", + }, + }, + }, + "packages": { + "@types/node": ["@types/node@22.13.5", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg=="], + + "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], + + "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="], + + "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="], + + "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], + } +} diff --git a/examples/bun-sqlite/package.json b/examples/bun-sqlite/package.json new file mode 100644 index 0000000..2190fd6 --- /dev/null +++ b/examples/bun-sqlite/package.json @@ -0,0 +1,11 @@ +{ + "name": "bun-sqlite", + "module": "src/main.ts", + "type": "module", + "devDependencies": { + "bun-types": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/examples/bun-sqlite/src/db/query_sql.ts b/examples/bun-sqlite/src/db/query_sql.ts new file mode 100644 index 0000000..351ba9c --- /dev/null +++ b/examples/bun-sqlite/src/db/query_sql.ts @@ -0,0 +1,85 @@ +// Code generated by sqlc. DO NOT EDIT. + +import { Database } from "bun:sqlite"; + +export const getAuthorQuery = `-- name: GetAuthor :one +SELECT id, name, bio FROM authors +WHERE id = ? LIMIT 1`; + +export interface GetAuthorArgs { + id: number; +} + +export interface GetAuthorRow { + id: number; + name: string; + bio: string | null; +} + +export async function getAuthor(database: Database, args: GetAuthorArgs): Promise { + const stmt = database.prepare(getAuthorQuery); + const rows = stmt.values(args.id); + if (rows.length !== 1) { + return null; + } + const row = rows[0]; + if (!row) { + return null; + } + return { + id: row[0] as number, + name: row[1] as string, + bio: row[2] as string | null + }; +} + +export const listAuthorsQuery = `-- name: ListAuthors :many +SELECT id, name, bio FROM authors +ORDER BY name`; + +export interface ListAuthorsRow { + id: number; + name: string; + bio: string | null; +} + +export async function listAuthors(database: Database): Promise { + const stmt = database.prepare(listAuthorsQuery); + const rows = stmt.values(); + return rows.map(row => ({ + id: row[0] as number, + name: row[1] as string, + bio: row[2] as string | null + })); +} + +export const createAuthorQuery = `-- name: CreateAuthor :exec +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +)`; + +export interface CreateAuthorArgs { + name: string; + bio: string | null; +} + +export async function createAuthor(database: Database, args: CreateAuthorArgs): Promise { + const stmt = database.prepare(createAuthorQuery); + stmt.run(args.name, args.bio); +} + +export const deleteAuthorQuery = `-- name: DeleteAuthor :exec +DELETE FROM authors +WHERE id = ?`; + +export interface DeleteAuthorArgs { + id: number; +} + +export async function deleteAuthor(database: Database, args: DeleteAuthorArgs): Promise { + const stmt = database.prepare(deleteAuthorQuery); + stmt.run(args.id); +} + diff --git a/examples/bun-sqlite/src/main.ts b/examples/bun-sqlite/src/main.ts new file mode 100644 index 0000000..c01bc08 --- /dev/null +++ b/examples/bun-sqlite/src/main.ts @@ -0,0 +1,46 @@ +import { Database } from "bun:sqlite"; + +import { + createAuthor, + deleteAuthor, + getAuthor, + listAuthors, +} from "./db/query_sql"; + +async function main() { + const ddl = await Bun.file(`${import.meta.dir}/../../authors/sqlite/schema.sql`).text(); + const database = new Database(":memory:"); + + // Create tables + database.exec(ddl); + + // Create an author + await createAuthor(database, { + name: "Seal", + bio: "Kissed from a rose", + }); + + // List the authors + const authors = await listAuthors(database); + console.log(authors); + + // Get that author + const seal = await getAuthor(database, { id: authors[0].id }); + if (seal === null) { + throw new Error("seal not found"); + } + console.log(seal); + + // Delete the author + await deleteAuthor(database, { id: seal.id }); +} + +(async () => { + try { + await main(); + process.exit(0); + } catch (e) { + console.error(e); + process.exit(1); + } +})(); diff --git a/examples/bun-sqlite/tsconfig.json b/examples/bun-sqlite/tsconfig.json new file mode 100644 index 0000000..7556e1d --- /dev/null +++ b/examples/bun-sqlite/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" // add Bun global + ] + } +} diff --git a/examples/node-better-sqlite3/src/main.ts b/examples/node-better-sqlite3/src/main.ts index 5ee0ee4..191c31c 100644 --- a/examples/node-better-sqlite3/src/main.ts +++ b/examples/node-better-sqlite3/src/main.ts @@ -9,12 +9,6 @@ import { listAuthors, } from "./db/query_sql"; -interface Author { - id: string; - name: string; - bio: string | null; -} - async function main() { const ddl = await readFile(join(__dirname, "../../authors/sqlite/schema.sql"), { encoding: 'utf-8' }); const database = new Database(":memory:"); diff --git a/examples/sqlc.dev.yaml b/examples/sqlc.dev.yaml index f622ec1..5219967 100644 --- a/examples/sqlc.dev.yaml +++ b/examples/sqlc.dev.yaml @@ -40,6 +40,15 @@ sql: options: runtime: bun driver: postgres +- schema: "authors/postgresql/schema.sql" + queries: "authors/postgresql/query.sql" + engine: "postgresql" + codegen: + - plugin: ts + out: bun-sql/src/db + options: + runtime: bun + driver: bun-sql - schema: "authors/mysql/schema.sql" queries: "authors/mysql/query.sql" engine: "mysql" @@ -70,3 +79,12 @@ sql: options: runtime: node driver: better-sqlite3 +- schema: "authors/sqlite/schema.sql" + queries: "authors/sqlite/query.sql" + engine: "sqlite" + codegen: + - plugin: ts + out: bun-sqlite/src/db + options: + runtime: bun + driver: bun-sqlite diff --git a/examples/sqlc.yaml b/examples/sqlc.yaml index e02996d..57bb3ed 100644 --- a/examples/sqlc.yaml +++ b/examples/sqlc.yaml @@ -3,7 +3,7 @@ plugins: - name: ts wasm: url: https://downloads.sqlc.dev/plugin/sqlc-gen-typescript_0.1.3.wasm - sha256: 287df8f6cc06377d67ad5ba02c9e0f00c585509881434d15ea8bd9fc751a9368 + sha256: fc0595e9eb137800bf863de769cd57abd8630ef5ef92f2c9d6faec271ca96d1e sql: - schema: "authors/postgresql/schema.sql" queries: "authors/postgresql/query.sql" @@ -41,6 +41,15 @@ sql: options: runtime: bun driver: postgres +- schema: "authors/postgresql/schema.sql" + queries: "authors/postgresql/query.sql" + engine: "postgresql" + codegen: + - plugin: ts + out: bun-sql/src/db + options: + runtime: bun + driver: bun-sql - schema: "authors/mysql/schema.sql" queries: "authors/mysql/query.sql" engine: "mysql" @@ -58,4 +67,13 @@ sql: out: bun-mysql2/src/db options: runtime: bun - driver: mysql2 \ No newline at end of file + driver: mysql2 +- schema: "authors/sqlite/schema.sql" + queries: "authors/sqlite/query.sql" + engine: "sqlite" + codegen: + - plugin: ts + out: bun-sqlite/src/db + options: + runtime: bun + driver: bun-sqlite diff --git a/src/app.ts b/src/app.ts index e3a077c..a12fb9b 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,7 +5,6 @@ import { readFileSync, writeFileSync, STDIO } from "javy/fs"; import { EmitHint, - FunctionDeclaration, NewLineKind, TypeNode, ScriptKind, @@ -32,6 +31,8 @@ import { Driver as Sqlite3Driver } from "./drivers/better-sqlite3"; import { Driver as PgDriver } from "./drivers/pg"; import { Driver as PostgresDriver } from "./drivers/postgres"; import { Mysql2Options, Driver as MysqlDriver } from "./drivers/mysql2"; +import { Driver as BunSqlDriver } from "./drivers/bun-sql"; +import { Driver as BunSqliteDriver } from "./drivers/bun-sqlite"; // Read input from stdin const input = readInput(); @@ -90,6 +91,12 @@ function createNodeGenerator(options: Options): Driver { case "postgres": { return new PostgresDriver(); } + case "bun-sql": { + return new BunSqlDriver(); + } + case "bun-sqlite": { + return new BunSqliteDriver(); + } case "better-sqlite3": { return new Sqlite3Driver(); } diff --git a/src/drivers/bun-sql.ts b/src/drivers/bun-sql.ts new file mode 100644 index 0000000..240b2c8 --- /dev/null +++ b/src/drivers/bun-sql.ts @@ -0,0 +1,622 @@ +import { + SyntaxKind, + NodeFlags, + TypeNode, + factory, + FunctionDeclaration, +} from "typescript"; + +import { Parameter, Column } from "../gen/plugin/codegen_pb"; +import { argName, colName } from "./utlis"; +import { log } from "../logger"; + +function funcParamsDecl(iface: string | undefined, params: Parameter[]) { + let funcParams = [ + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("sql"), + undefined, + factory.createTypeReferenceNode( + factory.createIdentifier("SQL"), + undefined + ), + undefined + ), + ]; + + if (iface && params.length > 0) { + funcParams.push( + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("args"), + undefined, + factory.createTypeReferenceNode( + factory.createIdentifier(iface), + undefined + ), + undefined + ) + ); + } + + return funcParams; +} + +export class Driver { + columnType(column?: Column): TypeNode { + if (column === undefined || column.type === undefined) { + return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + } + // Some of the type names have the `pgcatalog.` prefix. Remove this. + let typeName = column.type.name; + const pgCatalog = "pg_catalog."; + if (typeName.startsWith(pgCatalog)) { + typeName = typeName.slice(pgCatalog.length); + } + let typ: TypeNode = factory.createKeywordTypeNode(SyntaxKind.StringKeyword); + switch (typeName) { + case "aclitem": { + // string + break; + } + case "bigserial": { + // string + break; + } + case "bit": { + // string + break; + } + case "bool": { + typ = factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword); + break; + } + case "box": { + // string + break; + } + case "bpchar": { + // string + break; + } + case "bytea": { + // TODO: Is this correct or node-specific? + typ = factory.createTypeReferenceNode( + factory.createIdentifier("Buffer"), + undefined + ); + break; + } + case "cid": { + // string + break; + } + case "cidr": { + // string + break; + } + case "circle": { + // string + break; + } + case "date": { + typ = factory.createTypeReferenceNode( + factory.createIdentifier("Date"), + undefined + ); + break; + } + case "float4": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "float8": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "inet": { + // string + break; + } + case "int2": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "int4": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "int8": { + // string + break; + } + case "interval": { + // string + break; + } + case "json": { + typ = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + break; + } + case "jsonb": { + typ = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + break; + } + case "line": { + // string + break; + } + case "lseg": { + // string + break; + } + case "madaddr": { + // string + break; + } + case "madaddr8": { + // string + break; + } + case "money": { + // string + break; + } + case "oid": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "path": { + // string + break; + } + case "pg_node_tree": { + // string + break; + } + case "pg_snapshot": { + // string + break; + } + case "point": { + // string + break; + } + case "polygon": { + // string + break; + } + case "regproc": { + // string + break; + } + case "regrole": { + // string + break; + } + case "serial": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "serial2": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "serial4": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "serial8": { + // string + break; + } + case "smallserial": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "tid": { + // string + break; + } + case "text": { + // string + break; + } + case "time": { + // string + break; + } + case "timetz": { + // string + break; + } + case "timestamp": { + typ = factory.createTypeReferenceNode( + factory.createIdentifier("Date"), + undefined + ); + break; + } + case "timestamptz": { + typ = factory.createTypeReferenceNode( + factory.createIdentifier("Date"), + undefined + ); + break; + } + case "tsquery": { + // string + break; + } + case "tsvector": { + // string + break; + } + case "txid_snapshot": { + // string + break; + } + case "uuid": { + // string + break; + } + case "varbit": { + // string + break; + } + case "varchar": { + // string + break; + } + case "xid": { + // string + break; + } + case "xml": { + // string + break; + } + default: { + log(`unknown type ${column.type?.name}`); + break; + } + } + if (column.isArray || column.arrayDims > 0) { + let dims = Math.max(column.arrayDims || 1); + for (let i = 0; i < dims; i++) { + typ = factory.createArrayTypeNode(typ); + } + } + if (column.notNull) { + return typ; + } + return factory.createUnionTypeNode([ + typ, + factory.createLiteralTypeNode(factory.createNull()), + ]); + } + + preamble(_queries: unknown) { + return [ + factory.createImportDeclaration( + undefined, + factory.createImportClause( + false, + undefined, + factory.createNamedImports([ + factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier("SQL") + ), + ]) + ), + factory.createStringLiteral("bun"), + undefined + ), + ]; + } + + execDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] + ) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createKeywordTypeNode(SyntaxKind.VoidKeyword), + ]), + factory.createBlock( + [ + factory.createExpressionStatement( + factory.createAwaitExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("sql"), + factory.createIdentifier("unsafe") + ), + undefined, + [ + factory.createIdentifier(queryName), + factory.createArrayLiteralExpression( + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier(argName(i, param.column)) + ) + ), + false + ), + ] + ) + ) + ), + ], + true + ) + ); + } + + manyDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + returnIface: string, + params: Parameter[], + columns: Column[] + ) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createArrayTypeNode( + factory.createTypeReferenceNode( + factory.createIdentifier(returnIface), + undefined + ) + ), + ]), + factory.createBlock( + [ + factory.createReturnStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createAwaitExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("sql"), + factory.createIdentifier("unsafe") + ), + undefined, + [ + factory.createIdentifier(queryName), + factory.createArrayLiteralExpression( + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier( + argName(i, param.column) + ) + ) + ), + false + ), + ] + ), + factory.createIdentifier("values") + ), + undefined, + undefined + ) + ), + factory.createIdentifier("map") + ), + undefined, + [ + factory.createArrowFunction( + undefined, + undefined, + [ + factory.createParameterDeclaration( + undefined, + undefined, + "row" + ), + ], + undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + factory.createObjectLiteralExpression( + columns.map((col, i) => + factory.createPropertyAssignment( + factory.createIdentifier(colName(i, col)), + factory.createElementAccessExpression( + factory.createIdentifier("row"), + factory.createNumericLiteral(`${i}`) + ) + ) + ), + true + ) + ), + ] + ) + ), + ], + true + ) + ); + } + + oneDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + returnIface: string, + params: Parameter[], + columns: Column[] + ) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createUnionTypeNode([ + factory.createTypeReferenceNode( + factory.createIdentifier(returnIface), + undefined + ), + factory.createLiteralTypeNode(factory.createNull()), + ]), + ]), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("rows"), + undefined, + undefined, + factory.createAwaitExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("sql"), + factory.createIdentifier("unsafe") + ), + undefined, + [ + factory.createIdentifier(queryName), + factory.createArrayLiteralExpression( + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier( + argName(i, param.column) + ) + ) + ), + false + ), + ] + ), + factory.createIdentifier("values") + ), + undefined, + undefined + ) + ) + ), + ], + NodeFlags.Const | + // ts.NodeFlags.Constant | + NodeFlags.AwaitContext | + // ts.NodeFlags.Constant | + NodeFlags.ContextFlags | + NodeFlags.TypeExcludesFlags + ) + ), + factory.createIfStatement( + factory.createBinaryExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("rows"), + factory.createIdentifier("length") + ), + factory.createToken(SyntaxKind.ExclamationEqualsEqualsToken), + factory.createNumericLiteral("1") + ), + factory.createBlock( + [factory.createReturnStatement(factory.createNull())], + true + ), + undefined + ), + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + "row", + undefined, + undefined, + factory.createElementAccessExpression( + factory.createIdentifier("rows"), + factory.createNumericLiteral("0") + ) + ), + ], + NodeFlags.Const + ) + ), + factory.createIfStatement( + factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createIdentifier("row") + ), + factory.createBlock( + [factory.createReturnStatement(factory.createNull())], + true + ), + undefined + ), + factory.createReturnStatement( + factory.createObjectLiteralExpression( + columns.map((col, i) => + factory.createPropertyAssignment( + factory.createIdentifier(colName(i, col)), + factory.createElementAccessExpression( + factory.createIdentifier("row"), + factory.createNumericLiteral(`${i}`) + ) + ) + ), + true + ) + ), + ], + true + ) + ); + } + + execlastidDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] + ): FunctionDeclaration { + throw new Error("Bun sql driver currently does not support :execlastid"); + } +} diff --git a/src/drivers/bun-sqlite.ts b/src/drivers/bun-sqlite.ts new file mode 100644 index 0000000..c12275e --- /dev/null +++ b/src/drivers/bun-sqlite.ts @@ -0,0 +1,475 @@ +import { + SyntaxKind, + NodeFlags, + Node, + TypeNode, + factory, + FunctionDeclaration, +} from "typescript"; + +import { Parameter, Column, Query } from "../gen/plugin/codegen_pb"; +import { argName, colName } from "./utlis"; + +function funcParamsDecl(iface: string | undefined, params: Parameter[]) { + let funcParams = [ + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("database"), + undefined, + factory.createTypeReferenceNode( + factory.createIdentifier("Database"), + undefined + ), + undefined + ), + ]; + + if (iface && params.length > 0) { + funcParams.push( + factory.createParameterDeclaration( + undefined, + undefined, + factory.createIdentifier("args"), + undefined, + factory.createTypeReferenceNode( + factory.createIdentifier(iface), + undefined + ), + undefined + ) + ); + } + + return funcParams; +} + +export class Driver { + columnType(column?: Column): TypeNode { + if (column === undefined || column.type === undefined) { + return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + } + + let typ: TypeNode = factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + switch (column.type.name.toLowerCase()) { + case "int": + case "integer": + case "tinyint": + case "smallint": + case "mediumint": + case "bigint": + case "unsignedbigint": + case "int2": + case "int8": { + // TODO: Improve `BigInt` handling (https://github.com/WiseLibs/better-sqlite3/blob/v9.4.1/docs/integer.md) + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "varchar": + case "text": { + typ = factory.createKeywordTypeNode(SyntaxKind.StringKeyword); + break; + } + case "blob": { + typ = factory.createTypeReferenceNode( + factory.createIdentifier("Buffer"), + undefined + ); + break; + } + case "real": + case "double": + case "doubleprecision": + case "float": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + case "date": + case "datetime": { + typ = factory.createKeywordTypeNode(SyntaxKind.StringKeyword); + break; + } + case "boolean": + case "bool": + case "timestamp": { + typ = factory.createKeywordTypeNode(SyntaxKind.NumberKeyword); + break; + } + } + + if (column.notNull) { + return typ; + } + + return factory.createUnionTypeNode([ + typ, + factory.createLiteralTypeNode(factory.createNull()), + ]); + } + + preamble(queries: Query[]) { + const imports: Node[] = [ + factory.createImportDeclaration( + undefined, + factory.createImportClause( + false, + undefined, + factory.createNamedImports([ + factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier("Database") + ), + ]) + ), + factory.createStringLiteral("bun:sqlite"), + undefined + ), + ]; + + return imports; + } + + execDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] + ) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createKeywordTypeNode(SyntaxKind.VoidKeyword), + ]), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("stmt"), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("database"), + factory.createIdentifier("prepare") + ), + undefined, + [factory.createIdentifier(queryName)] + ) + ), + ], + NodeFlags.Const | NodeFlags.TypeExcludesFlags + ) + ), + factory.createExpressionStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("stmt"), + factory.createIdentifier("run") + ), + undefined, + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier(argName(i, param.column)) + ) + ) + ) + ), + ], + true + ) + ); + } + + oneDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + returnIface: string, + params: Parameter[], + columns: Column[] + ) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createUnionTypeNode([ + factory.createTypeReferenceNode( + factory.createIdentifier(returnIface), + undefined + ), + factory.createLiteralTypeNode(factory.createNull()), + ]), + ]), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("stmt"), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("database"), + factory.createIdentifier("prepare") + ), + undefined, + [factory.createIdentifier(queryName)] + ) + ), + ], + NodeFlags.Const | NodeFlags.TypeExcludesFlags + ) + ), + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("rows"), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("stmt"), + factory.createIdentifier("values") + ), + undefined, + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier(argName(i, param.column)) + ) + ) + ) + ), + ], + NodeFlags.Const | + NodeFlags.ContextFlags | + NodeFlags.TypeExcludesFlags + ) + ), + factory.createIfStatement( + factory.createBinaryExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("rows"), + factory.createIdentifier("length") + ), + factory.createToken(SyntaxKind.ExclamationEqualsEqualsToken), + factory.createNumericLiteral("1") + ), + factory.createBlock( + [factory.createReturnStatement(factory.createNull())], + true + ), + undefined + ), + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + "row", + undefined, + undefined, + factory.createElementAccessExpression( + factory.createIdentifier("rows"), + factory.createNumericLiteral("0") + ) + ), + ], + NodeFlags.Const + ) + ), + factory.createIfStatement( + factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createIdentifier("row") + ), + factory.createBlock( + [factory.createReturnStatement(factory.createNull())], + true + ), + undefined + ), + factory.createReturnStatement( + factory.createObjectLiteralExpression( + columns.map((col, i) => + factory.createPropertyAssignment( + factory.createIdentifier(colName(i, col)), + factory.createAsExpression( + factory.createElementAccessExpression( + factory.createIdentifier("row"), + factory.createNumericLiteral(`${i}`) + ), + this.columnType(col) + ) + ) + ), + true + ) + ), + ], + true + ) + ); + } + + manyDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + returnIface: string, + params: Parameter[], + columns: Column[] + ) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createArrayTypeNode( + factory.createTypeReferenceNode( + factory.createIdentifier(returnIface), + undefined + ) + ), + ]), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("stmt"), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("database"), + factory.createIdentifier("prepare") + ), + undefined, + [factory.createIdentifier(queryName)] + ) + ), + ], + NodeFlags.Const | NodeFlags.TypeExcludesFlags + ) + ), + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier("rows"), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("stmt"), + factory.createIdentifier("values") + ), + undefined, + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier(argName(i, param.column)) + ) + ) + ) + ), + ], + NodeFlags.Const | + NodeFlags.ContextFlags | + NodeFlags.TypeExcludesFlags + ) + ), + factory.createReturnStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("rows"), + factory.createIdentifier("map") + ), + undefined, + [ + factory.createArrowFunction( + undefined, + undefined, + [ + factory.createParameterDeclaration( + undefined, + undefined, + "row" + ), + ], + undefined, + factory.createToken(SyntaxKind.EqualsGreaterThanToken), + factory.createObjectLiteralExpression( + columns.map((col, i) => + factory.createPropertyAssignment( + factory.createIdentifier(colName(i, col)), + factory.createAsExpression( + factory.createElementAccessExpression( + factory.createIdentifier("row"), + factory.createNumericLiteral(`${i}`) + ), + this.columnType(col) + ) + ) + ), + true + ) + ), + ] + ) + ), + ], + true + ) + ); + } + + execlastidDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] + ): FunctionDeclaration { + throw new Error( + "Bun sqlite driver currently does not support :execlastid" + ); + } +}