查询构建器
VentoStack 的查询构建器基于模型定义自动推导 TypeScript 类型,从 db.query(Model).get() 到返回结果的每一个字段都有完整类型提示。
使用 defineModel 和 column 定义数据模型,列类型会自动映射到 TypeScript 类型:
import { defineModel, column } from "@ventostack/database";
const UserModel = defineModel("users", { id: column.bigint({ primary: true, autoIncrement: true }), email: column.varchar({ length: 255, unique: true }), name: column.varchar({ length: 255 }), age: column.int({ nullable: true }), active: column.boolean({ default: true }), role: column.enum({ values: ["admin", "user"] as const }), metadata: column.json<{ tags: string[] }>(), createdAt: column.timestamp(),});
// 推导出的用户类型:// {// id: bigint;// email: string;// name: string;// age: number | null;// active: boolean;// role: "admin" | "user";// metadata: { tags: string[] };// createdAt: Date;// }| 列方法 | TypeScript 类型 | 说明 |
|---|---|---|
column.bigint() | bigint | 64 位整数 |
column.int() | number | 32 位整数 |
column.varchar() | string | 变长字符串 |
column.text() | string | 长文本 |
column.boolean() | boolean | 布尔值 |
column.timestamp() | Date | 时间戳 |
column.json<T>() | T | JSON 列,可指定泛型 |
column.enum({ values }) | 字面量联合 | 枚举值 |
column.decimal() | string | 高精度小数(字符串存储避免精度丢失) |
nullable: true 会自动在 TypeScript 类型中加上 | null:
const PostModel = defineModel("posts", { id: column.bigint({ primary: true, autoIncrement: true }), title: column.varchar({ length: 200 }), // publishedAt 可以是 null publishedAt: column.timestamp({ nullable: true }),});
// 推导类型:{ id: bigint; title: string; publishedAt: Date | null }SELECT 查询
Section titled “SELECT 查询”const db = createDatabase({ url: process.env.DATABASE_URL! });
// 查询全部 — 返回完整类型数组const users = await db.query(UserModel).list();// users: { id: bigint; email: string; ... }[]
// 单条查询 — 返回完整类型或 undefinedconst user = await db.query(UserModel).where("email", "=", "alice@example.com").get();// user: { id: bigint; email: string; ... } | undefined
// 指定字段 — 返回部分类型const names = await db.query(UserModel).select("id", "name").list();// names: { id: bigint; name: string }[]WHERE 条件
Section titled “WHERE 条件”// 等值const admin = await db.query(UserModel).where("role", "=", "admin").get();
// 比较const adults = await db.query(UserModel).where("age", ">=", 18).list();
// LIKEconst matched = await db.query(UserModel).where("email", "LIKE", "%@example.com").list();
// INconst selected = await db.query(UserModel).where("id", "IN", [1, 2, 3]).list();
// IS NULLconst unaged = await db.query(UserModel).where("age", "IS NULL").list();const users = await db .query(UserModel) .where("active", "=", true) .orderBy("createdAt", "desc") .limit(20) .offset(40) .list();const total = await db.query(UserModel).where("active", "=", true).count();// total: number
const avgAge = await db.query(UserModel).where("age", "IS NOT NULL").avg("age");// avgAge: numberINSERT
Section titled “INSERT”// 插入并返回完整记录const newUser = await db.query(UserModel).insert( { email: "alice@example.com", name: "Alice", role: "user" }, { returning: true },);// newUser: { id: bigint; email: string; name: string; ... } | undefinedUPDATE
Section titled “UPDATE”// 更新并返回更新后的记录const updated = await db .query(UserModel) .where("id", "=", 1) .update({ name: "Alice Smith" }, { returning: true });// updated: { id: bigint; email: string; name: string; ... } | undefinedDELETE
Section titled “DELETE”// 硬删除await db.query(UserModel).where("id", "=", 1).hardDelete();
// 软删除(模型需开启 softDelete: true)await db.query(UserModel).where("id", "=", 1).delete();
// 恢复软删除记录await db.query(UserModel).where("id", "=", 1).restore();await db.transaction(async (tx) => { const user = await tx.query(UserModel).insert({ email: "a@b.com", name: "A", role: "user" }); await tx.query(PostModel).insert({ title: "Hello", userId: user!.id });});原始 SQL
Section titled “原始 SQL”当查询构建器无法表达复杂查询时,可回退到原始 SQL:
const rows = await db.raw("SELECT * FROM users WHERE age > $1", [18]);// rows: unknown[] — 需自行断言类型