Поэтому я сопоставляю поля базы данных с полями ответа, поэтому я не раскрываю уровень данных для потребителей, используя свойство 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)));
}
};
Проблема в том, что:
- Отсутствие
modify: true
иstripUnknown: true
в ответе вызывает ошибки проверки из-за всех частных свойств в модели SequelizeJS, например; _changed, _options, _previousDataValues и т. д. - Чтобы решить проблему №1 и по-прежнему оставить значения
modify: true
иstripUnknown: true
, мы могли бы добавитьunknown(true)
к проверке Joi ... но тогда все общедоступные свойства (не частные, перечисленные выше в №1) включаются в ответ, поскольку проверка выполняется позволяя им, и мы не снимаем их - Если мы удалим
unknown(true)
из проверки Joi и добавим свойстваmodify: true
иstripUnknown: true
(как показано в приведенном выше коде), то выдается ошибка, поскольку частные свойства (и общедоступные) удаляются из модели Sequelize ... поэтому модель выходит из строя, поскольку ожидает, что они существуют
Следовательно, вместо того, чтобы вручную сопоставлять объекты базы данных с объектами ответа, я вижу единственный способ избежать этого:
- Установите
unknown(true)
на валидацию - Реализуйте какой-то глобальный обработчик (или обработчик для каждого маршрута), который будет выполнять разборку после того, как проверка будет выполнена и ответ будет отправлен
Я не уверен, какой будет правильная точка расширения в # 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));
}
Мой пример использования здесь заключается в том, что я использую модель для определения того, как я хочу, чтобы объект выглядел, а затем эта функция выполняет сопоставление, которое также изменяет имена свойств на основе поля в модели для каждого поля данных. Благодаря этому я также могу легко построить модель из объекта, который возвращает эта функция, если мне нужно повторно использовать этот объект для обновлений / удалений, что, по моему мнению, не понадобится в ближайшем будущем.
raw
не будут создавать для меня модели Sequelize, а это значит, что мне нужно сделать сопоставление самому ... что я мог бы сделать, но я надеялся, что есть способ использовать мой текущий подход . Отображение не является проблемой, в конце концов, Sequelize делает это для создания моделей, если в моем текущем дизайне это невозможно сделать. - person click2install   schedule 31.08.2017