You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Drizzle:带分页与总计数的通用查询函数如何实现类型安全?

分页查询的类型安全实现方案

一、为查询函数添加泛型约束

如果要保留query函数的复用方式,可以通过泛型结合ORM的内置类型来恢复类型安全。以Drizzle ORM为例:

import type { SelectQueryBuilder, Selectable } from 'drizzle-orm';
import { hotels, cities, eq, count } from './schema';

// 定义关联查询的结果类型
type HotelCityRecord = typeof hotels.$inferSelect & { cityId: typeof cities.id.$type };

// 泛型函数:F约束传入的字段结构,R指定查询结果类型
function query<F extends Record<string, any>, R = Selectable<F>>(fields: F): SelectQueryBuilder<typeof db, R> {
  return db
    .select(fields)
    .from(hotels)
    .innerJoin(cities, eq(cities.id, hotels.city_id))
    .where(eq(hotels.locale, 'cs')) as SelectQueryBuilder<typeof db, R>;
}

// 计数查询,自动推断返回类型为Array<{ count: number }>
const total = await query({ count: count() });

// 数据查询,指定泛型后自动获得类型提示
const rows = await query<HotelCityRecord>({
  id: hotels.id,
  cityId: cities.id,
  name: hotels.name,
})
  .orderBy(hotels.id)
  .limit(limit)
  .offset(offset);

二、复用基础查询构建器(更简洁)

直接拆分核心逻辑为不带select的基础查询,再分别扩展计数和分页逻辑,完全保留ORM的原生类型支持:

import { hotels, cities, eq, count } from './schema';

// 构建核心查询逻辑(不带select,复用关联、过滤条件)
const baseQuery = db
  .from(hotels)
  .innerJoin(cities, eq(cities.id, hotels.city_id))
  .where(eq(hotels.locale, 'cs'));

// 执行计数查询
const total = await baseQuery.select({ count: count() });

// 执行分页数据查询
const rows = await baseQuery
  .select({
    id: hotels.id,
    cityId: cities.id,
    name: hotels.name,
  })
  .orderBy(hotels.id)
  .limit(limit)
  .offset(offset);

这种方式无需额外封装函数,代码更直观,且类型安全完全由ORM原生保障,是最推荐的方案。

三、使用ORM原生分页工具

如果使用的ORM支持原生分页(如Drizzle的分页插件、Prisma的findMany),可以直接借助官方工具简化实现:

以Drizzle分页插件为例:

import { paginate } from 'drizzle-orm/pagination';
import { hotels, cities, eq } from './schema';

const baseQuery = db
  .from(hotels)
  .innerJoin(cities, eq(cities.id, hotels.city_id))
  .where(eq(hotels.locale, 'cs'));

// 一次调用同时获取分页数据和总条数
const { data: rows, totalCount } = await paginate(baseQuery, {
  limit,
  offset,
  select: {
    id: hotels.id,
    cityId: cities.id,
    name: hotels.name,
  },
});

内容的提问来源于stack exchange,提问作者romario333

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 17:33:21