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

如何扩展@Query()的PageOptionsDto以支持未知过滤属性?

解决方案

要在保持PageOptionsDto通用性的同时,通过URL查询参数传递类型安全的过滤条件,推荐用交叉类型结合业务实体专属的过滤Dto来实现,具体步骤如下:

1. 为每个业务实体定义专属过滤Dto

针对每个需要过滤的表格(比如Player表格),单独创建一个过滤Dto,定义该实体的过滤字段及验证规则:

import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsOptional, IsString, IsInt } from 'class-validator';
import { Type } from 'class-transformer';

export class PlayerFilterDto {
  @ApiPropertyOptional({ description: '玩家名称模糊匹配' })
  @IsOptional()
  @IsString()
  readonly name?: string;

  @ApiPropertyOptional({ description: '玩家年龄精确匹配' })
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  readonly age?: number;

  // 其他需要过滤的字段都在这里定义
}

2. 在控制器中使用交叉类型组合Dto

在你的控制器方法里,将通用的PageOptionsDto与业务专属的PlayerFilterDto通过交叉类型&组合,作为Query参数的类型:

@Get('player/table')
async getPlayerTable(
  @Query() pageOptionsAndFilters: PageOptionsDto<PlayerSortColumn> & PlayerFilterDto,
) {
  // 直接访问分页排序参数:pageOptionsAndFilters.page、pageOptionsAndFilters.take等
  // 同时类型安全地访问过滤参数:pageOptionsAndFilters.name、pageOptionsAndFilters.age等
  
  // 示例:提取参数处理业务逻辑
  const { skip, take, order, orderColumn, name, age } = pageOptionsAndFilters;
  const filterConditions = {};
  if (name) filterConditions['name'] = new RegExp(name, 'i'); // 模糊匹配
  if (age) filterConditions['age'] = age; // 精确匹配

  // 执行查询:分页+排序+过滤
  const result = await this.playerRepository.find({
    where: filterConditions,
    skip,
    take,
    order: { [orderColumn]: order },
  });
  // ...返回结果
}

3. 保持PageOptionsDto的通用性

你的原始PageOptionsDto完全不需要修改,依然可以复用在所有表格的分页排序场景中,每个表格只需要新增对应的过滤Dto即可。

方案优势

  • 类型安全:避免使用any,过滤字段的类型、验证规则都能通过Dto严格约束
  • 通用性保留:PageOptionsDto无需硬编码任何业务字段,依然是通用的分页排序工具
  • 符合URL查询参数习惯:过滤参数直接以平级的方式放在URL中(比如?name=ni&age=20),和你现有的分页参数格式统一

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 11:06:29