跳转到内容

查询构建器

VentoStack 的查询构建器基于模型定义自动推导 TypeScript 类型,从 db.query(Model).get() 到返回结果的每一个字段都有完整类型提示。

使用 defineModelcolumn 定义数据模型,列类型会自动映射到 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()bigint64 位整数
column.int()number32 位整数
column.varchar()string变长字符串
column.text()string长文本
column.boolean()boolean布尔值
column.timestamp()Date时间戳
column.json<T>()TJSON 列,可指定泛型
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 }
const db = createDatabase({ url: process.env.DATABASE_URL! });
// 查询全部 — 返回完整类型数组
const users = await db.query(UserModel).list();
// users: { id: bigint; email: string; ... }[]
// 单条查询 — 返回完整类型或 undefined
const 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 }[]
// 等值
const admin = await db.query(UserModel).where("role", "=", "admin").get();
// 比较
const adults = await db.query(UserModel).where("age", ">=", 18).list();
// LIKE
const matched = await db.query(UserModel).where("email", "LIKE", "%@example.com").list();
// IN
const selected = await db.query(UserModel).where("id", "IN", [1, 2, 3]).list();
// IS NULL
const 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: number
// 插入并返回完整记录
const newUser = await db.query(UserModel).insert(
{ email: "alice@example.com", name: "Alice", role: "user" },
{ returning: true },
);
// newUser: { id: bigint; email: string; name: string; ... } | undefined
// 更新并返回更新后的记录
const updated = await db
.query(UserModel)
.where("id", "=", 1)
.update({ name: "Alice Smith" }, { returning: true });
// updated: { id: bigint; email: string; name: string; ... } | undefined
// 硬删除
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:

const rows = await db.raw("SELECT * FROM users WHERE age > $1", [18]);
// rows: unknown[] — 需自行断言类型