Как удалить неизвестное с помощью HapiJS Joi и SequelizeJS?

Поэтому я сопоставляю поля базы данных с полями ответа, поэтому я не раскрываю уровень данных для потребителей, используя свойство field в моделях SequelizeJS, например:

module.exports = function (sequelize, DataTypes)
{
    return sequelize.define('Product',
    {
      id: 
      {
        type: DataTypes.INTEGER,
        primaryKey: true,
        field: 'sku_id'
      },
      name: 
      {
        type: DataTypes.STRING,
        field: 'sku_name'
      },
      code: 
      {
        type: DataTypes.STRING,
        field: 'sku_code'
      }
    },
    {
      timestamps: false,
      freezeTableName: true
    });
 };

Тогда контроллер маршрута выглядит так:

module.exports = server => 
{
  const Joi = require('joi');
  const db = require('rfr')('models/index');
  const _ = require('lodash');

  const schema = Joi.array()
    .items(Joi.object(
      {
        id: Joi.number().integer().positive().required().description('The id of the product'),
        name: Joi.string().required().description('The name of the product'),
        code: Joi.string().required().description('The code of the product')
      })
      .label('Product'))
    .label('ProductCollection');

  return server.route(
    {
      method: 'GET',
      path: '/products/group/{id}',
      config:
      {
        handler,
        validate:
        {
          params:
          {
            id: Joi.number().integer().positive().required().description('the product group id')
          }
        },
        response:
        {
          schema,
          modify: true,
          options: { stripUnknown: true }
        },
        tags: ['api', 'products'],
        description: 'Get a list of products by group'
      }
    });

  ////////////////////////

  function handler(request, reply)
  {
    var sql = db.sequelize;
    var options =
      {
        replacements:
        {
          id: request.params.id
        },
        model: db.Product,
        mapToModel: true,
        type: sql.QueryTypes.SELECT
      };

    sql.query('sp_GetProducts @RowId = :id', options)
      .then(results => 
      {
        let sorted = _.orderBy(results, 'code');
        return reply(sorted);
      })
      .catch(err => reply(require('boom').wrap(err)));
  }
};

Проблема в том, что:

  1. Отсутствие modify: true и stripUnknown: true в ответе вызывает ошибки проверки из-за всех частных свойств в модели SequelizeJS, например; _changed, _options, _previousDataValues ​​и т. д.
  2. Чтобы решить проблему №1 и по-прежнему оставить значения modify: true и stripUnknown: true, мы могли бы добавить unknown(true) к проверке Joi ... но тогда все общедоступные свойства (не частные, перечисленные выше в №1) включаются в ответ, поскольку проверка выполняется позволяя им, и мы не снимаем их
  3. Если мы удалим unknown(true) из проверки Joi и добавим свойства modify: true и stripUnknown: true (как показано в приведенном выше коде), то выдается ошибка, поскольку частные свойства (и общедоступные) удаляются из модели Sequelize ... поэтому модель выходит из строя, поскольку ожидает, что они существуют

Следовательно, вместо того, чтобы вручную сопоставлять объекты базы данных с объектами ответа, я вижу единственный способ избежать этого:

  1. Установите unknown(true) на валидацию
  2. Реализуйте какой-то глобальный обработчик (или обработчик для каждого маршрута), который будет выполнять разборку после того, как проверка будет выполнена и ответ будет отправлен

Я не уверен, какой будет правильная точка расширения в # 2 выше, и есть ли более аккуратный подход к достижению желаемого результата.

или используя что-то вроде map-obj и попросите обработчик опросить схему Joi, чтобы определить, исходный объект (модель) key => value должен быть скопирован в новый объект (ответ), я считаю, что это просто дополнительные накладные расходы (циклы ЦП и дорогостоящие для больших массивов объектов), в отличие от того, чтобы позволить Sequelize делать это при построении модели.

ИЗМЕНИТЬ

Это служебная функция, которую я создал, чтобы получить отображение, предложенное @Shivan. В котором используется пакет object-mapper.

function mapFromModel(data, model)
{
  if (!data) { return []; }
  if (_.isArray(data) === false) { data = [data]; }
  if (!model.attributes && !model.sequelize) { throw new Error('Expecting `model` argument to be a sequelize model.'); }

  let transform = {};

  Object
    .keys(model.attributes)
    .forEach(key => 
    {
      let obj = model.attributes[key];
      transform[obj.field] = `${obj.fieldName}?`;
    });

  return data.map(value => objectMapper(value, {}, transform));
}

Мой пример использования здесь заключается в том, что я использую модель для определения того, как я хочу, чтобы объект выглядел, а затем эта функция выполняет сопоставление, которое также изменяет имена свойств на основе поля в модели для каждого поля данных. Благодаря этому я также могу легко построить модель из объекта, который возвращает эта функция, если мне нужно повторно использовать этот объект для обновлений / удалений, что, по моему мнению, не понадобится в ближайшем будущем.


person click2install    schedule 30.08.2017    source источник
comment
Вы не можете использовать свойство raw в запросе. документы   -  person Shivam    schedule 31.08.2017
comment
Насколько я понял, эти документы (с некоторого времени назад) raw не будут создавать для меня модели Sequelize, а это значит, что мне нужно сделать сопоставление самому ... что я мог бы сделать, но я надеялся, что есть способ использовать мой текущий подход . Отображение не является проблемой, в конце концов, Sequelize делает это для создания моделей, если в моем текущем дизайне это невозможно сделать.   -  person click2install    schedule 31.08.2017
comment
@Shivam, если вы хотите оставить свой комментарий, я награжу его как ответ. Из-за отсутствия активности я согласился с вашим предложением, а затем передал необработанный результат в созданную мною функцию сопоставления, которая сопоставляет определение модели Sequelize с простым объектом, который затем проверяет Joi.   -  person click2install    schedule 05.09.2017


Ответы (1)


Кажется, вы используете свойство raw в запросе, который сглаживает результат

Можешь попробовать без него.

person Shivam    schedule 05.09.2017
comment
Для всех, кто заинтересован, в моем редактировании вопроса есть функция утилиты, которую я использовал - person click2install; 06.09.2017
comment
Я думаю, вы имели в виду использовать raw (в соответствии с вашим предыдущим комментарием) и самостоятельно выполнить сопоставление, что отлично работает. Спасибо. - person click2install; 06.09.2017