Drizzle-ORM:将查询构建器作为参数传递时应指定何种类型?
问题:Drizzle ORM通用分页函数中查询构建器的类型定义
我正在创建一个通用函数,用于为不同实体生成分页结果。为此,我将查询构建器的一部分用作子查询来获取记录数,并据此设置分页。
主函数代码
const findMany = async (options?: { sort?: AuthorSorting; filters?: AuthorFilter[]; pagination?: QueryStringPagination; }): Promise<{ data: Author[]; pagination: Pagination }> => { const query = db.select().from(authors); if (options?.sort) { const fieldName = options.sort.field; const sortingField = authors[fieldName] ?? authors["name"]; query.orderBy( options.sort.direction === "desc" ? desc(sortingField) : asc(sortingField) ); } if (options?.filters) { const conditions: SQL<Author>[] = []; const filters = options?.filters; filters.forEach((filter: Record<string, any>) => { const field = authors[filter.field as keyof Author]; const op = sql.raw(Operators[filter.operator]); const value = filter.value; if (["like", "ilike"].includes(filter.operator)) { conditions.push(sql`${field} ${op} ${ "%" + value + "%" }`); } else { conditions.push(sql`${field} ${op} ${value}`); } }); if (conditions.length > 0) { const combinedConditions = conditions.reduce( (prev, curr) => sql`${prev} AND ${curr}` ); query.where(combinedConditions); } } return paginateQuery<Author>({ query, QueryStringPagination: options.pagination, }); };
通用分页函数代码
import { sql } from "drizzle-orm"; import { db } from "../db"; import { Pagination, QueryStringPagination } from "../types"; export async function paginateQuery<T>({ query, QueryStringPagination, }: { query: any; // <---- 应设置何种类型? QueryStringPagination: QueryStringPagination; }): Promise<{ data: T[]; pagination: Pagination }> { const subQuery = query.as("sub"); const totalRecordsQuery = db .select({ total: sql<number>`count(*)` }) .from(subQuery); const totalRecordsResult = await totalRecordsQuery.execute(); const totalRecords = Number(totalRecordsResult[0].total); const totalPages = Math.ceil(totalRecords / QueryStringPagination.limit); query .limit(QueryStringPagination.limit) .offset((QueryStringPagination.page - 1) * QueryStringPagination.limit); const results = (await query.execute()) as T[]; return { data: results, pagination: { totalRecords: totalRecords, totalPages: totalPages, currentPage: QueryStringPagination.page, limit: QueryStringPagination.limit, }, }; }
Author实体代码
export const authors = pgTable( "authors", { id: uuid("id").defaultRandom().primaryKey(), name: varchar("name", { length: 256 }).notNull(), bio: text("bio").notNull(), birthdate: date("birthdate", { mode: "date" }).notNull(), createdAt: timestamp("createdAt").defaultNow().notNull(), updatedAt: timestamp("updatedAt").defaultNow().notNull(), }, (authors) => { return { nameIndex: uniqueIndex("name_idx").on(authors.name), }; } );
我尝试了drizzle-orm中的不同类型,但都无法正确匹配。请问将查询构建器作为参数传递给函数时,应设置何种类型?
解决方案
在Drizzle ORM中,你需要使用**SelectQueryBuilder**类型(通用场景),或者对应数据库的具体查询构建器类型(比如PostgreSQL的PgSelectQueryBuilder)来替代any,既能获得类型安全,又能保持函数的通用性。
步骤1:导入正确的类型
从drizzle-orm核心包导入通用的SelectQueryBuilder,如果是特定数据库(如PostgreSQL),也可以从对应核心包导入更具体的类型:
import { sql, SelectQueryBuilder } from "drizzle-orm"; // 针对PostgreSQL的更具体类型(可选): // import { PgSelectQueryBuilder } from "drizzle-orm/pg-core";
步骤2:修改分页函数的参数类型
将query的类型从any替换为SelectQueryBuilder,结合泛型适配不同实体类型:
export async function paginateQuery<T>({ query, QueryStringPagination, }: { query: SelectQueryBuilder<any, T>; QueryStringPagination: QueryStringPagination; }): Promise<{ data: T[]; pagination: Pagination }> { const subQuery = query.as("sub"); const totalRecordsQuery = db .select({ total: sql<number>`count(*)` }) .from(subQuery); const totalRecordsResult = await totalRecordsQuery.execute(); const totalRecords = Number(totalRecordsResult[0].total); const totalPages = Math.ceil(totalRecords / QueryStringPagination.limit); query .limit(QueryStringPagination.limit) .offset((QueryStringPagination.page - 1) * QueryStringPagination.limit); // 无需类型断言,TypeScript会自动推断结果类型为T[] const results = await query.execute(); return { data: results, pagination: { totalRecords, totalPages, currentPage: QueryStringPagination.page, limit: QueryStringPagination.limit, }, }; }
更严格的类型定义(可选)
如果需要区分表类型和查询结果类型(比如查询只返回部分字段时),可以使用双泛型:
export async function paginateQuery<TTable, TResult>({ query, QueryStringPagination, }: { query: SelectQueryBuilder<TTable, TResult>; QueryStringPagination: QueryStringPagination; }): Promise<{ data: TResult[]; pagination: Pagination }> { // 函数逻辑保持不变 }
这样修改后,TypeScript能正确校验查询构建器的方法调用,同时保持函数对不同实体的通用性。
内容的提问来源于stack exchange,提问作者Cleber Gasparoto
相关产品推荐
相关产品推荐

