定义环回观察者的顺序
Defining the order of loopback observers
我目前正在使用 IBM 的环回在 node.js 中编写 REST API。我正在 运行 解决观察者顺序相关的问题,并且它们的调用顺序错误。
我的 Ticket 模型有一个 内部状态 字段。此状态作为 UUID 存储在数据库中。在大型 "metadata" 文件的某处,还定义了每个状态的人名。 外部状态 字段也是如此。
以下是Ticket.json
的相关部分:
{
"name": "Ticket",
"properties": {
"internalStatusId": {
"type": "String"
},
"externalStatusId": {
"type": "String"
}
}
}
我写了一个通用的 mixin,可以将这样一个 UUID 字段的人名转换为正确的 UUID。此 mixin 用于允许客户端通过名称设置 UUID 字段(通过不同名称的字段)。
这里是 mixin 的简化版本:
// This observer is actually a simplification of the actual observer,
// which is more generic. It handles "name to id" mapping for any number
// of fields you can configure in the <model>.json file.
Model.observe('before save', function (ctx, next) {
let data = ctx.isNewInstance ? ctx.instance : ctx.data;
if (data.internalStatusName) {
data.internalStatusId = internalStatusNameToIdMap[data.internalStatusName];
delete data.internalStatusName;
}
next();
});
因此,如果您向 /Tickets/1
发送一个 PUT
请求,正文为 { "internalStatusName": "Closed" }
,此代码会将其转换为正确的 UUID,将其放入 internalStatusId
字段,并从参数中删除 internalStatusName
字段。
现在,系统中有一个业务规则:如果内部状态设置为Closed
,则外部状态也需要设置为Closed
。该代码位于 Ticket.js
中,因为它不是通用的,但仅与 Ticket 模型相关:
// This observer is located in Ticket.json.
// It makes sure that, when a ticket's internal status is set to Closed,
// the external status is also set to Closed.
Ticket.observe('before save', function (ctx, next) {
let data = ctx.isNewInstance ? ctx.instance : ctx.data;
if (data.internalStatusId === INTERNAL_STATUS_CLOSED_UUID) {
data.externalStatusId = EXTERNAL_STATUS_CLOSED_UUID;
}
next();
});
我 运行 遇到的问题是这两个观察者不能很好地协同工作,因为它们的调用顺序错误。
如果我发送 { "internalStatusName": "Closed" }
:
- 首先调用来自
Ticket.js
的观察者。这将检查是否设置了 internalStatusId
字段,以了解是否需要更新外部状态。 internalStatusId
不在参数中,因此未设置外部状态。
- 其次,mixin观察者被调用。内部状态名称转换为id。
这个顺序可能是loopback首先加载Ticket.js
中的观察者,然后是mixin观察者造成的。
当然,我可以修改第二个观察者来查找 internalStatusId
和 以及 internalStatusName
字段。然而,这会导致大量的代码重复,尤其是因为我有很多这样的业务逻辑观察器,还有很多像这样的 UUID 字段。
我一直在寻找一种方法来告诉环回 运行 这些观察者的顺序。即使是像 Model.observeFirst()
这样简单的函数(这实际上并不存在!)或链前端的更多观察者将解决这个问题。我一直无法找到这是否可行,如果可行,如何实现。
你会如何解决这个问题?
Loopback 首先加载模型的实现,然后才加载 mixins 的实现,因此顺序错误。
Loopback 使用标准的事件订阅系统。因此,您可以使用 prependListener 将侦听器添加到开头。
// Puts first
Model.prependListener('before save', function (ctx, next) {
let data = ctx.isNewInstance ? ctx.instance : ctx.data;
if (data.internalStatusName) {
data.internalStatusId = internalStatusNameToIdMap[data.internalStatusName];
delete data.internalStatusName;
}
next();
});
我目前正在使用 IBM 的环回在 node.js 中编写 REST API。我正在 运行 解决观察者顺序相关的问题,并且它们的调用顺序错误。
我的 Ticket 模型有一个 内部状态 字段。此状态作为 UUID 存储在数据库中。在大型 "metadata" 文件的某处,还定义了每个状态的人名。 外部状态 字段也是如此。
以下是Ticket.json
的相关部分:
{
"name": "Ticket",
"properties": {
"internalStatusId": {
"type": "String"
},
"externalStatusId": {
"type": "String"
}
}
}
我写了一个通用的 mixin,可以将这样一个 UUID 字段的人名转换为正确的 UUID。此 mixin 用于允许客户端通过名称设置 UUID 字段(通过不同名称的字段)。
这里是 mixin 的简化版本:
// This observer is actually a simplification of the actual observer,
// which is more generic. It handles "name to id" mapping for any number
// of fields you can configure in the <model>.json file.
Model.observe('before save', function (ctx, next) {
let data = ctx.isNewInstance ? ctx.instance : ctx.data;
if (data.internalStatusName) {
data.internalStatusId = internalStatusNameToIdMap[data.internalStatusName];
delete data.internalStatusName;
}
next();
});
因此,如果您向 /Tickets/1
发送一个 PUT
请求,正文为 { "internalStatusName": "Closed" }
,此代码会将其转换为正确的 UUID,将其放入 internalStatusId
字段,并从参数中删除 internalStatusName
字段。
现在,系统中有一个业务规则:如果内部状态设置为Closed
,则外部状态也需要设置为Closed
。该代码位于 Ticket.js
中,因为它不是通用的,但仅与 Ticket 模型相关:
// This observer is located in Ticket.json.
// It makes sure that, when a ticket's internal status is set to Closed,
// the external status is also set to Closed.
Ticket.observe('before save', function (ctx, next) {
let data = ctx.isNewInstance ? ctx.instance : ctx.data;
if (data.internalStatusId === INTERNAL_STATUS_CLOSED_UUID) {
data.externalStatusId = EXTERNAL_STATUS_CLOSED_UUID;
}
next();
});
我 运行 遇到的问题是这两个观察者不能很好地协同工作,因为它们的调用顺序错误。
如果我发送 { "internalStatusName": "Closed" }
:
- 首先调用来自
Ticket.js
的观察者。这将检查是否设置了internalStatusId
字段,以了解是否需要更新外部状态。internalStatusId
不在参数中,因此未设置外部状态。 - 其次,mixin观察者被调用。内部状态名称转换为id。
这个顺序可能是loopback首先加载Ticket.js
中的观察者,然后是mixin观察者造成的。
当然,我可以修改第二个观察者来查找 internalStatusId
和 以及 internalStatusName
字段。然而,这会导致大量的代码重复,尤其是因为我有很多这样的业务逻辑观察器,还有很多像这样的 UUID 字段。
我一直在寻找一种方法来告诉环回 运行 这些观察者的顺序。即使是像 Model.observeFirst()
这样简单的函数(这实际上并不存在!)或链前端的更多观察者将解决这个问题。我一直无法找到这是否可行,如果可行,如何实现。
你会如何解决这个问题?
Loopback 首先加载模型的实现,然后才加载 mixins 的实现,因此顺序错误。 Loopback 使用标准的事件订阅系统。因此,您可以使用 prependListener 将侦听器添加到开头。
// Puts first
Model.prependListener('before save', function (ctx, next) {
let data = ctx.isNewInstance ? ctx.instance : ctx.data;
if (data.internalStatusName) {
data.internalStatusId = internalStatusNameToIdMap[data.internalStatusName];
delete data.internalStatusName;
}
next();
});