Определение порядка петлевых наблюдателей

В настоящее время я пишу REST API в node.js, используя петлю IBM. Я столкнулся с проблемой, когда порядок наблюдателей имеет значение, и они вызываются в неправильном порядке.

В моей модели Ticket есть поле внутренний статус. Этот статус хранится в базе данных как UUID. Где-то в большом файле «метаданных» также определяется человеческое имя для каждого статуса. То же самое касается поля внешний статус.

Вот соответствующие части Ticket.json:

{
  "name": "Ticket",
  "properties": {
    "internalStatusId": {
      "type": "String"
    },
    "externalStatusId": {
      "type": "String"
    }
  }
}

Я написал общий миксин, который может преобразовать человеческое имя такого поля UUID в правильный UUID. Этот миксин позволяет клиентам устанавливать поле UUID по его имени (через поле с другим именем).

Вот упрощенная версия миксина:

// 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();
});

Таким образом, если вы отправите запрос PUT к /Tickets/1 с { "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 не присутствует в аргументах, поэтому внешний статус не установлен.
  • Во-вторых, вызывается миксин-наблюдатель. Внутреннее имя статуса преобразуется в идентификатор.

Этот порядок, вероятно, вызван тем, что петля сначала загружает наблюдателей в Ticket.js, а затем наблюдателей миксина.

Я мог бы, конечно, изменить второго наблюдателя, чтобы он искал поля internalStatusId и internalStatusName. Однако это приводит к значительному дублированию кода, особенно потому, что у меня много таких наблюдателей бизнес-логики, а также много таких полей UUID.

Я искал способ сообщить loopback, в каком порядке запускать этих наблюдателей. Даже такая простая функция, как Model.observeFirst() (на самом деле ее не существует!), чтобы поместить одного или нескольких наблюдателей в начало цепочки, решит эту проблему. . Я не смог найти, возможно ли это, и если да, то как.

Как бы вы решили эту проблему?


person Joost Vunderink    schedule 15.05.2017    source источник


Ответы (1)


Loopback загружает сначала реализацию модели и только после этой реализации миксины, поэтому неправильный порядок. 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();
});
person Denis Kulygin    schedule 24.05.2017