Show HN: Bun-sqlgen – 适用于 Bun 的类型安全原生 SQL 工具,无需 ORM
Show HN: Bun-sqlgen – Type-safe raw SQL for Bun, no ORM

原始链接: https://github.com/ilbertt/bun-sqlgen

**@ilbertt/bun-sqlgen** 为 Bun 提供了类型安全的原生 SQL 支持,且无需 ORM 的额外开销。通过对 SQL 查询进行标记(例如 `sql.GetUser`),该工具可以根据您的数据库迁移文件,自动生成完全类型化且支持空安全的返回类型。 **主要特性:** * **编译时安全:** 代码生成器会根据您的 Postgres 或 SQLite 模式进行检查,在构建过程中检测无效 SQL 或列错误,从而防止运行时故障。 * **零 ORM:** 无需泛型或手动编写类型。查询结果为标准的 JavaScript 对象,TypeScript 会立即对其进行校验。 * **简洁的工作流:** 以迁移文件作为真值来源,使用 `withTypes` 包装您的 SQL 客户端,并运行生成器以生成本地 `.d.ts` 文件。 * **原生性能:** 保持 100% 的 Bun 原生运行时性能。 若要开始使用,请通过 `bun add @ilbertt/bun-sqlgen` 安装该包,并针对您的代码库运行生成器。这种方法可确保您的数据库模式与应用程序代码保持完美同步,同时让您的 SQL 保持原生、可读,并由标准的 `tsc` 进行类型检查。

**Bun-sqlgen** 是一款新工具,无需 ORM 即可为 Bun 中的原生 SQL 查询提供类型安全。尽管开发者通常更倾向于使用原生 SQL 而非 Drizzle 或 Kysely 等 ORM 抽象,但他们往往会失去类型安全,导致返回类型变为不可靠的 `any[]`。 Bun-sqlgen 通过代码生成步骤解决了这一问题:它解析您的 SQL 迁移文件,并针对临时的 PGlite (Postgres) 或 SQLite 实例执行标记查询。随后,它会生成一个 `.d.ts` 文件,将查询结果映射为具体的 TypeScript 类型,从而确保在编译时验证可空性和字段名称。 主要功能包括: * **无需 Docker:** 使用 PGlite 进行本地查询准备。 * **纯 SQL:** 在保持您对原生 SQL 的偏好的同时,获得 `tsc` 错误检查的好处。 * **易于集成:** 生成的类型文件是一个简单的构建产物,可以提交到您的代码仓库中。 该项目目前处于 v0.1 版本。社区讨论已探讨了对 Node.js 的潜在支持、与 `porsager-postgres` 的兼容性,以及通过 PGlite 配置处理 PostGIS 扩展的可能性。
相关文章

原文

Type-safe SQL for Bun, no ORM — raw Bun.sql, live-checked against your schema.

Tag a query with a name — sql.GetUser`...` — and its fully-typed, null-safe row appears right at the call site: no ORM, no generics, no hand-written types. Codegen plans every query against a real Postgres or SQLite database (no Docker needed), so wrong columns and bad SQL fail the build, not production — fast enough to rerun on every save. The runtime stays 100% Bun-native.

Published as @ilbertt/bun-sqlgen — its README is the full guide: both dialects, nullability overrides, transactions, and configuration.

bun add @ilbertt/bun-sqlgen
  1. Migrations are the source of truth for your schema — put them in any folder:

    -- db/migrations/0001_init.sql
    CREATE TABLE users (
      id           bigint PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
      email        text NOT NULL,
      display_name text
    );
  2. Wrap your client with withTypes and tag each query with its name:

    import { withTypes } from '@ilbertt/bun-sqlgen';
    import { SQL } from 'bun';
    
    const sql = withTypes(new SQL(Bun.env.DATABASE_URL!));
    
    export async function getUser(id: number) {
      const [user] = await sql.GetUser`
        SELECT id, email, display_name FROM users WHERE id = ${id}
      `;
      return user; // typed { id: string; email: string; display_name: string | null }
    }
  3. Generate the types:

    bun bun-sqlgen generate 'src/**/*.ts' --migrations db/migrations

    This writes src/queries.gen.d.ts — commit it. With it in place, user.emial is a compile error and user.display_name.length is flagged as possibly-null, all by plain tsc.

Runnable projects live in the examples/ folder.

Development setup and conventions are in CONTRIBUTING.md.

联系我们 contact @ memedata.com