Prisma 扩展嵌入操作
Prisma 扩展库允许在 Prisma 查询中修改嵌入关系上的操作 .
Vanilla Prisma 扩展对修改顶级查询很有帮助,但是
当它们必须处理时仍然难以使用
筑巢写作, (中文(简体) ), includes, (中文(简体) ), selects, (中文(简体) ),
或修改 where 对象的参考关系.
更深入地讨论这个问题 关于嵌入式中间软件的问题,则
同样的问题也适用于扩展.
此库输出 a withNestedOperations() 拆分一个 $allOperations() 钩入 $rootOperation() 财务报告和审定财务报表
$allNestedOperations() 钩子.
目录
安装
此模块通过 无 与 节点 财务报告和审定财务报表 应当安装为您的项目依赖性之一 :
npm install @candoimage/prisma-extension-nested-operations
@prisma/client 是此库的对等依赖, 因此您需要
如果您还没有安装它 :
npm install @prisma/client
您必须至少安装了 @ prisma/ 客户端的7. 0.0 版本 .
使用量
这个 withNestedOperations() 函数取用和反对两个属性, $rootOperation() 财务报告和审定财务报表 $allNestedOperations()。 。 。 .
返回值为 $allOperations 钩子,可以直接传递到扩展 $allOperations 钩.
import { Prisma } from "@prisma/client";
import { withNestedOperations } from "@candoimage/prisma-extension-nested-operations";
client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
// update root params here
const result = params.query(params.args);
// update root result here
return result;
},
async $allNestedOperations(params) {
// update nested params here
const result = await params.query(params.args);
// update nested result here
return result;
},
}),
},
},
});
$rootOperation()
这个 $rootOperation() 钩子叫同一段 $allOperations() 钩子,但 params.args 对象
已更新 $allNestedOperations() 查询功能。 同样的模式适用于
返回结果,它是通过返回结果更新的查询的结果 $allNestedOperations() 打电话.
$allNestedOperations() 参数
参数对象传递到 $allNestedOperations() 函数与传递到 $allOperations()。 。 。 .
它已经 args, (中文(简体) ), model, (中文(简体) ), operation,以及 query 字段,但有一些关键差异:
-
页:1
operation字段添加以下选项:"连接 OrCreate","连接","断开","包含","选择"和"在哪里" -
页:1
query字段需要第二个参数,即operation执行中。 这在巢穴操作的类型应该被改变的地方是有用的. -
还有一个
scope字段,其中包含与嵌入关系相关的特定信息:- 页:1
parentParams字段包含父关系参数对象 - 页:1
modifier字段中包含任何修改符,例如包含参数some或者说every。 。 。 . - 页:1
logicalOperators字段包含当前关系与其父关系之间的任何逻辑运算符,例如AND或者说NOT。 。 。 . - 页:1
relations字段包含一个与关系相关的对象to当前模式和from模特儿回到父母身边.
- 页:1
详情请查阅 modifier 财务报告和审定财务报表 logicalOperators 字段见 何处 节.
详情请查阅 relations 见 关系 节.
参数对象的类型是:
type NestedParams<ExtArgs> = {
query: (args: any, operation?: NestedOperation) => Prisma.PrismaPromise<any>;
model: keyof Prisma.TypeMap<ExtArgs>["model"];
args: any;
operation: NestedOperation;
scope?: Scope<ExtArgs>;
};
export type Scope<ExtArgs> = {
parentParams: Omit<NestedParams<ExtArgs>, "query">;
relations: { to: Prisma.DMMF.Field; from: Prisma.DMMF.Field };
modifier?: Modifier;
logicalOperators?: LogicalOperator[];
};
type Modifier = "is" | "isNot" | "some" | "none" | "every";
type LogicalOperator = "AND" | "OR" | "NOT";
type Operation =
| "create"
| "createMany"
| "update"
| "updateMany"
| "upsert"
| "delete"
| "deleteMany"
| "where"
| "include"
| "select"
| "connect"
| "connectOrCreate"
| "disconnect";
嵌入式写作
这个 $allNestedOperations() 函数为每个 嵌入式写作
在查询中操作。 这个 operation 字段设定为正在执行的操作,例如“创建”或“更新”.
这个 model 字段设定为正在运行的模型,例如“用户”或“后”.
例如,请查询如下:
const result = await client.user.update({
data: {
posts: {
update: {
where: { id: 1 },
data: { title: "Hello World" },
},
},
},
});
这个 $allNestedOperations() 函数将调用:
{
operation: 'update',
model: 'Post',
args: {
where: { id: 1 },
data: { title: 'Hello World' }
},
relations: {
to: { kind: 'object', name: 'posts', isList: true, ... },
from: { kind: 'object', name: 'author', isList: false, ... },
},
scope: [root params],
}
一些被嵌入的写作可以作为一系列操作来传递. 在这种情况下 $allNestedOperations() 对每个函数都要求
在数组中操作。 例如,请查询如下:
const result = await client.user.update({
data: {
posts: {
update: [
{ where: { id: 1 }, data: { title: "Hello World" } },
{ where: { id: 2 }, data: { title: "Hello World 2" } },
],
},
},
});
这个 $allNestedOperations() 函数将调用:
{
operation: 'update',
model: 'Post',
args: {
where: { id: 1 },
data: { title: 'Hello World' }
},
relations: {
to: { kind: 'object', name: 'posts', isList: true, ... },
from: { kind: 'object', name: 'author', isList: false, ... },
},
scope: [root params],
}
财务报告和审定财务报表
{
operation: 'update',
model: 'Post',
args: {
where: { id: 2 },
data: { title: 'Hello World 2' }
},
relations: {
to: { kind: 'object', name: 'posts', isList: true, ... },
from: { kind: 'object', name: 'author', isList: false, ... },
},
scope: [root params],
}
更改嵌入式写操作
这个 $allNestedOperations() 函数可以改变模型上的操作。 例如,请查询如下:
const result = await client.user.update({
data: {
posts: {
update: {
where: { id: 1 }
data: { title: 'Hello World' }
},
},
},
});
这个 $allNestedOperations() 函数可用于将操作更改为 upsert数字 :
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
$rootOperation: (params) => {
return params.query(params.args);
},
$allNestedOperations: (params) => {
if (params.model === "Post" && params.operation === "update") {
return params.query(
{
where: params.args.where,
create: params.args.data,
update: params.args.data,
},
"upsert"
);
}
return params.query(params);
},
}),
},
},
});
以上将修改最后查询 $allNestedOperations() 改为:
const result = await client.user.update({
data: {
posts: {
upsert: {
where: { id: 1 },
create: { title: "Hello World" },
update: { title: "Hello World" },
},
},
},
});
当改变操作时,操作有可能已经存在. 在这种情况下,由此产生的业务将合并. 例如,请查询如下:
const result = await client.user.update({
data: {
posts: {
update: {
where: { id: 1 },
data: { title: "Hello World" },
},
upsert: {
where: { id: 2 },
create: { title: "Hello World 2" },
update: { title: "Hello World 2" },
},
},
},
});
使用同样的 $allNestedOperations() 在更新操作改为更新操作之前定义,但有
已经是一个上调操作,所以将两个操作合并为上调操作阵列,并添加到新的操作中
数组的结尾。 当现有的操作已经是操作列表时,新的操作会被添加到结尾
名单 在这种情况下,最后的询问是:
const result = await client.user.update({
data: {
posts: {
upsert: [
{
where: { id: 2 },
create: { title: "Hello World 2" },
update: { title: "Hello World 2" },
},
{
where: { id: 1 },
create: { title: "Hello World" },
update: { title: "Hello World" },
},
],
},
},
});
有时无法以这种方式合并操作. 这个 createMany 操作不支持
操作阵列 data 报告 createMany 操作被合并。 例如,请查询如下:
const result = await client.user.create({
data: {
posts: {
createMany: {
data: [{ title: "Hello World" }, { title: "Hello World 2" }],
},
create: {
title: "Hello World 3",
},
},
},
});
如果 create 操作改为 a createMany 操作 data 字段将添加到现有
createMany 操作。 最后的询问是:
const result = await client.user.create({
data: {
posts: {
createMany: {
data: [
{ title: "Hello World" },
{ title: "Hello World 2" },
{ title: "Hello World 3" },
],
},
},
},
});
也不可能通过为非列表关系创建一系列操作来将操作合并. 对于 示例如下:
const result = await client.user.update({
data: {
profile: {
create: {
bio: "My personal bio",
age: 30,
},
update: {
where: { id: 1 },
data: { bio: "Updated bio" },
},
},
},
});
如果 update 操作改为 a create 使用下列扩展操作:
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
$rootOperation: (params) => {
return params.query(params.args);
},
$allNestedOperations: (params) => {
if (params.model === "Profile" && params.operation === "update") {
return params.query(params.args.data, "create");
}
return params.query(params);
},
}),
},
},
});
这个 create 从操作 update 业务需要与现有的 create 业务,但自
profile 不是一个列表关系, 我们必须合并 最终生成的对象 :
const result = await client.user.create({
data: {
profile: {
create: {
bio: "Updated bio",
age: 30,
},
},
},
});
写入结果
这个 query 函数 $allNestedOperations() 要求嵌入式写入操作总是返回 undefined 因为他们的结果.
这是因为从根查询中返回的结果可能不包括特定嵌入式写入的数据.
例如,请查询如下:
const result = await client.user.update({
data: {
profile: {
create: {
bio: "My personal bio",
age: 30,
},
}
posts: {
updateMany: {
where: {
published: false,
},
data: {
published: true,
},
},
},
},
select: {
id: true,
posts: {
where: {
title: {
contains: "Hello",
},
},
select: {
id: true,
},
},
}
});
这个 profile 字段不包含在 select 对象所以结果 create 操作不包含在
根结果。 这个 posts 字段包含在 select 对象但 where 对象仅包含带有
标题中包含“你好”并仅返回“id”字段,在此情况下,无法匹配
updateMany 返回的员额.
见 修改结果 以了解如何更新查询结果的更多信息.
何处
这个 where 操作用于在参数内发现对象的任何关系.
注意 where 操作不用于对象所在的根, 这是因为您需要根操作来知道
何为对象接受的根属性 。 对于巢穴的物体,这不是一个问题,因为他们总是跟随
同样的模式.
看这里 where 操作使用下列查询:
const result = await client.user.findMany({
where: {
posts: {
some: {
published: true,
},
},
},
});
上面对象产生在对象所在处发现的"后"关系的调用. 这个 modifier 字段设置为
"某"从物体所在"某"字段内.
{
operation: 'where',
model: 'Post',
args: {
published: true,
},
scope: {
parentParams: {...}
modifier: 'some',
relations: {...}
},
}
在发现和调用And、OR和NOT逻辑运算符时发现的关系 $allNestedOperations() 函数,
不过 where 对逻辑运算符本身不要求操作。 例如,请查询如下:
const result = await client.user.findMany({
where: {
posts: {
some: {
published: true,
AND: [
{
title: "Hello World",
},
{
comments: {
every: {
text: "Great post!",
},
},
},
],
},
},
},
});
这个 $allNestedOperations() 函数将使用类似“ post” 的参数调用, 但是它也会被调用
附有下列段落:
{
operation: 'where',
model: 'Comment',
args: {
text: "Great post!",
},
scope: {
parentParams: {...}
modifier: 'every',
logicalOperators: ['AND'],
relations: {...}
},
}
由于“注释”关系在“AND”逻辑运算符内找到
要求开展全美行动 这个 modifier 字段设置为“每个”,因为对象位于“每个”字段,并且
页:1 logicalOperators 字段设置为 ['AND'] 因为物体在“AND”逻辑运算符内.
注意到 $allNestedOperations() 函数不为“ AND” 数组中的第一个项目调用, 这是因为第一个项目
不包含任何关系.
这个 logicalOperators 字段跟踪在 parentParams 和当前参数。 对于
示例如下:
const result = await client.user.findMany({
where: {
AND: [
{
NOT: {
OR: [
{
posts: {
some: {
published: true,
},
},
},
],
},
},
],
},
});
这个 $allNestedOperations() 函数将调用以下段落:
{
operation: 'where',
model: 'Post',
args: {
published: true,
},
scope: {
parentParams: {...}
modifier: 'some',
logicalOperators: ['AND', 'NOT', 'OR'],
relations: {...},
},
}
这个 where 操作也用于在 where 包含和选择区域。 例如:
const result = await client.user.findMany({
select: {
posts: {
where: {
published: true,
},
},
},
});
这个 $allNestedOperations() 函数将调用以下段落:
{
operation: 'where',
model: 'Post',
args: {
published: true,
},
scope: {...}
}
成果
这个 query a 函数 where 操作总是用 undefined。 。 。 .
包含
这个 include 操作需要包含任何关系。 这个 args 字段将包含对象或布尔
关系。 例如,请查询如下:
const result = await client.user.findMany({
include: {
profile: true,
posts: {
where: {
published: true,
},
},
},
});
对于"相片"关系 $allNestedOperations() 函数将调用:
{
operation: 'include',
model: 'Profile',
args: true,
scope: {...}
}
而对于"后"关系 $allNestedOperations() 函数将调用:
{
operation: 'include',
model: 'Post',
args: {
where: {
published: true,
},
},
scope: {...}
}
包含结果
这个 query 函数 include 操作结果 include 操作。 举个例子
查询如下:
const result = await client.user.findMany({
include: {
profile: true,
},
});
这个 $allNestedOperations() 用于“ profile” 关系的函数将调用:
{
operation: 'include',
model: 'Profile',
args: true,
scope: {...}
}
还有 query 函数将随 include 操作,在这种情况下,诸如:
{
id: 2,
bio: 'My personal bio',
age: 30,
userId: 1,
}
对于被列入父母结果清单的关系 query 函数将用平整的阵列解决
每一个母公司的所有模型的结果。 例如,请查询如下:
const result = await client.user.findMany({
include: {
posts: true,
},
});
如果根结果看起来像如下:
[
{
id: 1,
name: "Alice",
posts: [
{
id: 1,
title: "Hello World",
published: false,
userId: 1,
},
{
id: 2,
title: "My first published post",
published: true,
userId: 1,
},
],
},
{
id: 2,
name: "Bob",
posts: [
{
id: 3,
title: "Clean Code",
published: true,
userId: 2,
},
],
},
];
这个 query 函数用于“ posts” 关系,将解决以下问题:
[
{
id: 1,
title: "Hello World",
published: false,
userId: 1,
},
{
id: 2,
title: "My first published post",
published: true,
userId: 1,
},
{
id: 3,
title: "Clean Code",
published: true,
userId: 2,
},
];
欲了解更多关于如何修改一项公约的结果的信息 include 操作参见 修改结果
选择
与 include 操作 select 操作将被调用到与 args 字段
中包含对象或布尔随关系选择而通过。 例如,请查询如下:
const result = await client.user.findMany({
select: {
posts: true,
profile: {
select: {
bio: true,
},
},
},
});
而对于"后"关系 $allNestedOperations() 函数将调用:
{
operation: 'select',
model: 'Post',
args: true,
scope: {...}
}
对于"相片"关系 $allNestedOperations() 函数将调用:
{
operation: 'select',
model: 'Profile',
args: {
bio: true,
},
scope: {...}
}
选择结果
这个 query a 函数 select 操作结果 select 操作。 这跟那个一样
include 操作。 见 包含结果 用于提供更多信息.
关系
这个 relations 报告 scope 对象包含与当前模型相关的关系。 举个例子
查询如下:
const result = await client.user.create({
data: {
email: "[email protected]",
profile: {
create: {
bio: "Hello World",
},
},
posts: {
create: {
title: "Hello World",
},
},
},
});
这个 $allNestedOperations() 函数将调用“ profile” 关系的下列参数:
{
operation: 'create',
model: 'Profile',
args: {
bio: "Hello World",
},
scope: {
parentParams: {...}
relations: {
to: { name: 'profile', kind: 'object', isList: false, ... },
from: { name: 'user', kind: 'object', isList: false, ... },
},
},
}
和以下关于“邮政”关系的段落:
{
operation: 'create',
model: 'Post',
args: {
title: "Hello World",
},
scope: {
parentParams: {...}
relations: {
to: { name: 'posts', kind: 'object', isList: true, ... },
from: { name: 'author', kind: 'object', isList: false, ... },
},
},
}
修改嵌入式书写参数
当写入修改查询参数的扩展名时, 您应该首先写入 $rootOperation() 像钩子一样
a 一个 $allOperations() 钩子,然后添加 $allNestedOperations() 钩.
假设您在为特定模型创建模型时正在写入设置默认值的中间软件:
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
// we only want to add default values for the "Invite" model
if (params.model !== "Invite") {
return params.query(params.args);
}
if (params.operation === "create" && !params.args.data.code) {
params.args.data.code = createCode();
}
if (params.operation === "upsert" && !params.args.create.code) {
params.args.create.code = createCode();
}
if (params.operation === "createMany") {
params.args.data.forEach((data) => {
if (!data.code) {
data.code = createCode();
}
});
}
return params.query(params.args);
},
async $allNestedOperations(params) {
return params.query(params.args);
},
}),
},
},
});
然后加入在巢中可以找到的不同参数和操作的条件:
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
[...]
},
async $allNestedOperations(params) {
// we only want to add default values for the "Invite" model
if (params.model !== "Invite") {
return params.query(params.args);
}
// when the "create" operation is from a nested write the data is not in the "data" field
if (params.operation === "create" && !params.args.code) {
params.args.code = createCode();
}
// handle the "connectOrCreate" operation
if (params.operation === "connectOrCreate" && !params.args.create.code) {
params.args.create.code = createCode();
}
// pass args to query
return params.query(params.args);
},
}),
},
},
});
修改参数位置
当写入修改查询参数的扩展时, 您应当首先写入 $rootOperation() 钩为
如果它是一个 $allOperations() 钩子,这是因为 where 操作不用于对象所在的根, 因此您
需要手动处理.
假设你正在写一个扩展, 排除模型与特定的领域, 让我们称之为"隐形"而不是 "取出"使这更不熟悉:
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
// don't handle operations that only accept unique fields such as findUnique or upsert
if (
params.operation === "findFirst" ||
params.operation === "findFirstOrThrow" ||
params.operation === "findMany" ||
params.operation === "updateMany" ||
params.operation === "deleteMany" ||
params.operation === "count" ||
params.operation === "aggregate"
) {
return params.query({
...params.args,
where: {
...params.args.where,
invisible: false,
},
});
}
return params.query(params.args);
},
async $allNestedOperations(params) {
return params.query(params.args);
},
}),
},
},
});
然后添加条件 where 操作 :
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
[...]
},
async $allNestedOperations(params) {
// handle the "where" operation
if (params.operation === "where") {
return params.query({
...params.args,
invisible: false,
});
}
return params.query(params.args);
},
}),
},
},
});
修改结果
在写入修改查询结果的扩展名时,您应当遵循以下程序:
- 处理
$rootOperation()钩一样,你会与一个$allOperations()钩. - 使用
include财务报告和审定财务报表select业务活动$allNestedOperations()钩.
说你正在写中间软件 给查询结果添加了时间戳 你将首先处理根源案件:
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
const result = await params.query(params.args);
// ensure result is defined
if (!result) return result;
// handle root operations
if (
params.operation === "findFirst" ||
params.operation === "findFirstOrThrow" ||
params.operation === "findUnique" ||
params.operation === "findUniqueOrThrow" ||
params.operation === "create" ||
params.operation === "update" ||
params.operation === "upsert" ||
params.operation === "delete"
) {
result.timestamp = Date.now();
return result;
}
if (params.operation === "findMany") {
const result = await params.query(params.args);
result.forEach((model) => {
model.timestamp = Date.now();
});
return result;
}
return result;
},
async $allNestedOperations(params) {
return params.query(params.args);
},
}),
},
},
});
然后,你会处理 巢的结果使用 include 财务报告和审定财务报表 select 操作 :
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
[...]
},
async $allNestedOperations(params) {
const result = await next(params);
// ensure result is defined
if (!result) return result;
// handle nested operations
if (params.operation === "include" || params.operation === "select") {
if (Array.isArray(result)) {
result.forEach((model) => {
model.timestamp = Date.now();
});
} else {
result.timestamp = Date.now();
}
return result;
}
return result;
},
}),
},
},
});
您也可以通过为每个结果创建新对象来写入上面的中间软件,而不是改变现有的 对象 :
const client = _client.$extends({
query: {
$allModels: {
$allOperations: withNestedOperations({
dmmf: Prisma.dmmf,
inlineSchema: (client as any)._engineConfig?.inlineSchema,
async $rootOperation(params) {
[...]
},
async $allNestedOperations(params) {
const result = await next(params);
// ensure result is defined
if (!result) return result;
// handle nested operations
if (params.operation === "include" || params.operation === "select") {
if (Array.isArray(result)) {
return result.map((model) => ({
...model,
timestamp: Date.now(),
});
}
return {
...result,
timestamp: Date.now(),
};
}
return result;
},
}),
},
},
});
注:当修改结果来自 include 或者说 select 操作中必须变换现有对象或
将已有对象扩展为新对象。 这是因为 createNestedMiddleware 需要从
原始对象以修正更新根结果.
错误
如果任何中间软件在任何一点投出出出错,则根查询会随该出错一起投出. 任何中间软件 等待会让承诺在那时遭到拒绝.
自由主义
Apache 2.0 (英语)