我正在使用sequelize.js构建多种类型的多租户。从技术上讲,我需要按预定义列和当前上下文的动态值过滤所有查询。一般的想法是使用defaultScope
来过滤掉其他上下文,例如:
var context = () => { return "some current context id"; }
connection.define('kid', {
firstName: Sequelize.STRING,
photoUrl: Sequelize.STRING,
context: {
type: Sequelize.STRING,
defaultValue: context // this part works, it accepts function
}
}, {
defaultScope: {
where: {
context: context // this does not work, it does not accept function and values is defined only once
}
}
});
但是这不起作用,因为在应用程序启动时定义了defaultScope
。
这样做的正确方法是什么?
答案 0 :(得分:2)
我不确定它会有所帮助,但您可以随时覆盖模型默认范围。
let defaultScope = {
where: {
context: ""
}
};
defaultScope.where.context = context();
model.addScope('defaultScope',defaultScope,{override: true});
答案 1 :(得分:1)
问题是Sequelize范围是在模型上定义的,但您需要在查询之前应用范围,因为那时您有上下文,例如用户和角色。
以下是Sequelize中范围合并功能的略微修改副本,您可以在beforeFind()
// Feel free to write a more fp version; mutations stink.
const {assign, assignWith} = require('lodash')
const applyScope = ({scope, options}) => {
if (!scope) {
throw new Error('Invalid scope.')
}
if (!options) {
throw new Error('Invalid options.')
}
assignWith(options, scope, (objectValue, sourceValue, key) => {
if (key === 'where') {
if (Array.isArray(sourceValue)) {
return sourceValue
}
return assign(objectValue || {}, sourceValue)
}
else if (['attributes', 'include'].indexOf(key) >= 0
&& Array.isArray(objectValue)
&& Array.isArray(sourceValue)
) {
return objectValue.concat(sourceValue)
}
return objectValue ? objectValue : sourceValue
})
}
在你的模特中:
{
hooks: {
beforeFind(options) {
// Mutates options...
applyScope({
scope: this.options.scopes.user(options.user)
, options
})
return options
}
}
, scopes: {
user(user) {
// Set the scope based on user/role.
return {
where: {
id: user.id
}
}
}
}
}
最后在您的查询中,使用您需要的上下文设置一个选项。
const user = {id: 12, role: 'admin'}
YourModel.findOne({
attributes: [
'id'
]
, where: {
status: 'enabled'
}
, user
})
答案 2 :(得分:0)
这里可能为时已晚,但如果定义为函数,作用域可以接受参数。如果范围定义为
,则来自文档 Sequelize scope docsscopes: {
accessLevel (value) {
return {
where: {
accessLevel: {
[Op.gte]: value
}
}
}
}
sequelize,
modelName: 'project'
}
您可以像这样使用它:Project.scope({ method: ['accessLevel', 19]}).findAll();
其中 19
是范围将使用的动态值。
根据 defaultScope
我不确定它是否可以定义为函数