@chax-at/prisma-filter (英语)
此软件包提供了 网点JS 变形管
REST 查询参数为 findOptions 用于 普里斯马。 。 。 .
查询参数使用与 制表符。 。 。 .
QQ 为巢穴11+发出警告
使用 NestJS 11+,您必须启用扩展查询解析器,否则过滤解析器将无法工作(参见 移徙指南:
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule); // <-- Make sure to use <NestExpressApplication>
app.set('query parser', 'extended'); // <-- Add this line
await app.listen(3000);
}
用法 - 前端
首先,通过运行安装所有需要的类型
npm i @chax-at/prisma-filter-common
然后,如果您想要过滤 + pagination 某个请求的结果,您可以发送符合
页:1 IFilter 界面.
http://localhost:3000/api/admin/orders?offset=10&limit=10&filter[0][field]=id&filter[0][type]==&filter[0][value]=2&filter[1][field]=name&filter[1][type]=like&filter[1][value]=%Must%&order[0][field]=name&order[0][dir]=asc
检查 FilterOperationType 显示所有可能的过滤类型 。 请注意,默认情况下,所有过滤值都是
a. 被作为《公约》 string, (中文(简体) ), number (或 string[]编号 :number[] 页:1 in- 过滤器。 如果你想通过过滤 null 换成
联 合 国 'null',然后使用 EqNull编号 :NeNull 过滤器类型( 此处忽略给定的值) .
建立过滤器
此软件包提供了 FilterBuilder<T> 用于创建过滤器的类 :
import { FilterBuilder, FilterOperationType } from '@chax-at/prisma-filter-common';
const filterBuilder = new FilterBuilder<User>() // create a new filter builder for User entities..
.addFilter('name', FilterOperationType.Ilike, '%Max%') // ...filter by name ilike '%Max%'
.addOrderBy('name', 'asc') // ...order by name, asc
.setPageSize(40) // ...paginate with a pagesize of 40
.requestPage(3); // ...return the third page
const filter = filterBuilder.toFilter(); // get the resulting IFilter<User>
const queryString = filterBuilder.toQueryString(); // get the resulting query string (as described below)
// Note that you can also re-use the same filter if you just want to request a different page without changing filter or ordering:
const firstPageFilter = filterBuilder.requestPage(1).toFilter();
构建查询字符串
归根结底,需要一个查询字符串,将发送给后端服务器。 要构建此查询字符串,
您可以使用 FilterBuilder.toQueryString() 使用上述过滤器构建过滤器时.
然而,也可以将现有的过滤器转换为查询字符串:
const queryString = FilterBuilder.buildFilterQueryString({
limit: 20,
offset: 30,
filter: [
{ field: 'field1', type: FilterOperationType.NeNull, value: 'val1' },
{ field: 'field2', type: FilterOperationType.InStrings, value: ['str1', 'str2'] },
],
order: [
{ field: 'field1', dir: 'asc' },
{ field: 'field2', dir: 'desc' },
],
});
// queryString is
// ?offset=30&limit=20&filter[0][field]=field1&filter[0][type]=nenull&filter[0][value]=val1&filter[1][field]=field2&filter[1][type]=instrings&filter[1][value][]=str1&filter[1][value][]=str2&order[0][field]=field1&order[0][dir]=asc&order[1][field]=field2&order[1][dir]=desc
过滤类型
Eq, (中文(简体) ),Ne检查严格的(不平等)平等。 用于数字和布林斯.EqString, (中文(简体) ),NeString字符串( in) 平等检查字符串 。 不转换数字或布尔 与Eq财务报告和审定财务报表Ne。 。 。 .Lt, (中文(简体) ),Lte, (中文(简体) ),Gt, (中文(简体) ),Gte用于通过检查数字是否大于/小于(或等于)值来过滤数字Contains转换为 Prismacontains,用于筛选字符串。 使用%作为通配符,例如:.%Max%查找部分匹配.IContains就像是Contains但是对大小写不敏感StartsWith, (中文(简体) ),EndsWith, (中文(简体) ),Search匹配相应的 Prisma 操作。这些过滤器的前缀为I如果您想要过滤大小写不敏感( 例如) .IStartsWith(中文(简体) )In检查值是否在给定的数字数组中。 使用InStrings用于字符串阵列.InStrings检查值是否在给定的字符串数组中.NotIn检查该值是否不在给定的数字数组中。 使用NotInStrings用于字符串阵列.NotInStrings检查值是否不在给定的字符串数组中.EqNull, (中文(简体) ),NeNull检查该值是否无效。 必须使用代替Eq, (中文(简体) ),Ne因为不然null将被视为字符串ArrayContains, (中文(简体) ),ArrayStartsWith, (中文(简体) ),ArrayEndsWith可用于 Prisma 阵列Has, (中文(简体) ),HasString, (中文(简体) ),HasSome, (中文(简体) ),HasSomeString, (中文(简体) ),HasEvery, (中文(简体) ),HasEveryString
过滤值类型
由于过滤器是通过查询参数传输的,所以所有东西都会被转换为字符串. 这个图书馆会 根据这些规则自动转换过滤值 :
- 如果过滤器类型是
Eq, (中文(简体) ),Ne值是“ 真” 或“ 假” , 然后转换成布尔- 使用
EqString, (中文(简体) ),NeString如果您想要过滤字符串而不转换它
- 使用
- 如果过滤器类型不是
Like或者说...String,其值为数字(或数字数组)In),然后转换为数字(或数字数组) - 否则,该值将被视为字符串
对于字符串过滤器 Like 或者说 Ilike 筛选类型被推荐,因为通常需要部分搜索.
但是,如果想要对字符串使用不同的过滤器,请确保使用 ...String 备选案文
瑞秋真爱 不能通过她的名字过滤.
用法 - 后端
此套件输出 二 管道,则 DirectFilterPipe (在大多数情况下都使用)
较普通 FilterPipe。也可以使用导出 FilterParser 要转换的类
人工查询参数.
先决条件
首先,通过运行安装软件包
npm i @chax-at/prisma-filter
你还需要 @nestjs/common 已安装,目前支持6-10版本.
此套件还输出所有来自 prisma-filter-common 因此,不需要安装两个软件包.
要验证用户查询输入,您可能需要提供附加注释的自己的接口执行 验证限制。 如果你使用类验证器和类转换器, 这个定义可以像这样 (为您的工程设定抵消+限制的制约和默认值):
import { FilterOperationType, FilterOrder, GeneratedFindOptions, IFilter, IGeneratedFilter, ISingleFilter, ISingleOrder } from '@chax-at/prisma-filter';
import { Type } from 'class-transformer';
import { IsArray, IsDefined, IsEnum, IsIn, IsInt, IsOptional, IsString, Max, Min, ValidateNested } from 'class-validator';
// The fields are also validated in filter.parser.ts to make sure that only correct fields are used to filter
export class SingleFilter<T> implements ISingleFilter<T> {
@IsString()
field!: keyof T & string;
@IsEnum(FilterOperationType)
type!: FilterOperationType;
@IsDefined()
value: any;
}
export class SingleFilterOrder<T> implements ISingleOrder<T> {
@IsString()
field!: keyof T & string;
@IsIn(['asc', 'desc'])
dir!: FilterOrder;
}
export class Filter<T = any> implements IFilter<T> {
@IsArray()
@ValidateNested({ each: true })
@Type(() => SingleFilter)
@IsOptional()
filter?: Array<SingleFilter<T>>;
@IsArray()
@ValidateNested({ each: true })
@Type(() => SingleFilterOrder)
@IsOptional()
order?: Array<SingleFilterOrder<T>>;
@Type(() => Number)
@IsInt()
@Min(0)
offset = 0;
@Type(() => Number)
@IsInt()
@Min(1)
@Max(500)
limit = 100;
}
export class FilterDto<TWhereInput> extends Filter implements IGeneratedFilter<TWhereInput> {
// This will be set by filter pipe
findOptions!: GeneratedFindOptions<TWhereInput>;
}
这个readme假设您正在使用上面的文件,但您可以根据需要调整下面示例中使用的类型.
直肠管
从查询参数 1:1 到数据库字段的直接过滤管映射字段. 这通常是你的管子 想要使用。 .
要启用过滤, 您可以导入并使用 DirectFilterPipe<TDto, TWhereInput>(keys, compoundKeys?)。完整的例子:
// Controller
import { Prisma } from '@prisma/client';
// ...
@Controller('/some/path')
export class SomeController {
constructor(private readonly someService: SomeService) {}
@Get()
public async getOrders(
@Query(new DirectFilterPipe<any, Prisma.OrderWhereInput>(
['id', 'status', 'createdAt', 'refundStatus', 'refundedPrice', 'paymentDate', 'totalPrice', 'paymentMethod'],
['event.title', 'user.email', 'user.firstname', 'user.lastname', 'contactAddress.firstName', 'contactAddress.lastName'],
)) filterDto: FilterDto<Prisma.OrderWhereInput>,
) {
return this.someService.getOrders(filterDto.findOptions);
}
}
// Service
@Injectable()
export class SomeService {
constructor(private readonly prismaService: PrismaService) {}
public async getOrders(findOptions: Prisma.OrderFindManyArgs) {
return this.prismaService.order.findMany({
...findOptions,
// Is is now possible, to add custom options like include
include: {
user: true,
},
// Note that you cannot simply add `where` here, because you would override the definition from the findOptions
// Change findOptions.where instead if you want to add additional conditions
})
}
}
一般类型
TDto是描述过滤查询参数的类型。 可以设定为any由于名字是地图1: 1TWhereInput是目标棱镜类型并键入可过滤键.
参数
keys是第一个参数,是所有可以直接在顺序输入中过滤的密钥的列表, 不包括任何关系。 这些类型已检查 .compoundKeys(可选)可用于查询相关字段,例如,如果您Order模型有关系user,然后可以过滤user.email如果关系为1:n或n:n类似articles在一个Order,然后你可以使用 相应的棱镜语法 ,比如说.articles.some.title以过滤含有至少一条带有给定标题的命令. 未检查这些类型 .
默认排序顺序
特别是在使用平面图时,你应该总是定义排序顺序,这样平面图就稳定了. 您可以定义默认排序顺序
创建时 DirectFilterPipe 除非同一密钥已经定义,否则将总是添加.
export class SomeController {
@Get()
public async getOrders(
@Query(new DirectFilterPipe<any, Prisma.OrderWhereInput>(
['id', 'status', 'createdAt', 'refundStatus', 'refundedPrice', 'paymentDate', 'totalPrice', 'paymentMethod'],
['event.title', 'user.email', 'user.firstname', 'user.lastname', 'contactAddress.firstName', 'contactAddress.lastName'],
// Always add sort by `createdAt` ascending. Use the id as 2nd sorting criteria if the createdAt is equal.
[{ createdAt: 'asc' }, { id: 'asc' }],
)) filterDto: FilterDto<Prisma.OrderWhereInput>,
) {
// ...
}
}
根据上述代码,可以提出下列请求:
| 请求令 | 产生顺序 |
|---|---|
| 无排序顺序 | 创建At(asc) - > id(asc) |
| 总价( asc) | 总价(asc) - > 创建At(asc) - > id(asc) |
| 代码( desc) | id( desc) - > 创建At( asc) |
虚拟字段
如果您在组合键前加了前缀 !,然后被过滤管所忽略。 你可以用这个,如果你
如果设置了某个过滤器, 则想要执行一些自定义逻辑, 例如 .
export class SomeController {
@Get()
public async getOrders(
@Query(new DirectFilterPipe<any, Prisma.OrderWhereInput>(
[],
['!paymentInAdvance'],
)) filterDto: FilterDto<Prisma.OrderWhereInput>,
) {
if(filterDto.filter?.some(f => f.field === '!paymentInAdvance')) {
console.log('The paymentInAdvance filter is set, now I can do whatever I want!');
}
}
}
万事无虞
这个 AllFilterPipeUnsafe 是一种管道,如果您想要允许过滤模型的所有字段,它可以更方便地使用.
复合键仍需要如上所描述的具体说明.
: 警告: 这允许用户读取模型的所有密钥, 即使您不返回数据 (例如,通过发送像过滤器一样的多重,直到用户知道全部值).
确定您的模型不包含字段中的任何敏感数据( 例如, 不使用此管 )
users表格为 (单位:千美元)password页:1.
export class SomeController {
constructor(private readonly someService: SomeService) {}
@Get()
public async getOrders(
@Query(new AllFilterPipeUnsafe<any, Prisma.OrderWhereInput>(
['event.title', 'user.email', 'user.firstname', 'user.lastname', 'contactAddress.firstName', 'contactAddress.lastName', '!paymentInAdvance'],
)) filterDto: FilterDto<Prisma.OrderWhereInput>,
) {
return this.someService.getOrders(filterDto.findOptions);
}
}
过滤管道
这个 FilterPipe 工作像一个 DirectFilterPipe,但参数是一个可以映射某些
查询对象的不同密钥名称的参数名称,例如:.
{
// the query parameter is frontendUsernameFilterName, but will filter on the name field of the object
'frontendUsernameFilterName': 'name',
}
过滤器
你可以用这个 FilterParser 生成 prisma 选项而不使用管道.