示例说明
Kysely 是无实体类的查询构建器——数据库形态用接口描述而非装饰器类,SQL 的每个片段都带类型。动态筛选是最见功力的场景:条件按需链式追加,query 变量的类型随之演进,拼错列名或比较了不兼容的值都过不了编译;select 的列别名直接成为结果对象的键类型。
技术要点
- 接口声明表结构避免实体类负担
- 动态 where 保持类型连贯性
- select 别名决定结果行形状
代码解读
searchArticles 以可选字段表达筛选条件:作者名存在时追加等值过滤,仅发布标志为真时追加布尔条件。select 同时取文章列与作者名别名,rows 的元素类型即 id、title、author 三字段对象。Generated 类型标记自增列,插入时省略。
使用建议
原生片段用 sql 模板包裹保持参数化。迁移用 Kysely 自带迁移器管理。连接池大小与语句超时按生产负载配置。
代码示例
import { Kysely, PostgresDialect, Generated, sql } from 'kysely';
import { Pool } from 'pg';
interface Database {
articles: {
id: Generated<number>;
title: string;
authorId: number;
published: boolean;
};
authors: {
id: Generated<number>;
name: string;
};
}
const db = new Kysely<Database>({
dialect: new PostgresDialect({
pool: new Pool({ connectionString: process.env.DATABASE_URL }),
}),
});
type Filter = { author?: string; onlyPublished?: boolean };
async function searchArticles(filter: Filter) {
let query = db
.selectFrom('articles')
.innerJoin('authors', 'authors.id', 'articles.authorId')
.select(['articles.id', 'articles.title', 'authors.name as author']);
if (filter.author !== undefined) {
query = query.where('authors.name', '=', filter.author);
}
if (filter.onlyPublished) {
query = query.where('articles.published', '=', true);
}
const rows = await query
.orderBy('articles.id', 'desc')
.limit(25)
.execute();
return rows;
}
const fresh = await searchArticles({ onlyPublished: true });
console.log('typed author column:', fresh[0]?.author.length ?? 0);
await db.destroy();