简体   繁体   English

续集错误 - “TypeError: hooks.concat is not a function”

[英]Sequelize error - "TypeError: hooks.concat is not a function"

Sequelize version: 4.38.0续集版本:4.38.0

In my node.js web application.在我的 node.js Web 应用程序中。 I write model spec and run npm test.我编写模型规范并运行 npm test。 at the Create a model with associated data using set() unit test.Create a model with associated data using set()单元测试Create a model with associated data using set() but I get the following error:但我收到以下错误:

 TypeError: hooks.concat is not a function at Function.runHooks (node_modules/sequelize/lib/hooks.js:102:23) at Promise.try.then (node_modules/sequelize/lib/model.js:3624:33) at tryCatcher (node_modules/bluebird/js/release/util.js:16:23) at Promise._settlePromiseFromHandler (node_modules/bluebird/js/release/promise.js:512:31) at Promise._settlePromise (node_modules/bluebird/js/release/promise.js:569:18) at Promise._settlePromise0 (node_modules/bluebird/js/release/promise.js:614:10) at Promise._settlePromises (node_modules/bluebird/js/release/promise.js:693:18) at Async._drainQueue (node_modules/bluebird/js/release/async.js:133:16) at Async._drainQueues (node_modules/bluebird/js/release/async.js:143:10) at Immediate.Async.drainQueues (node_modules/bluebird/js/release/async.js:17:14)

the following is my unit test code :以下是我的单元测试代码:

 it('Create a model with associated data using set()', async () => { // TODO: // 1. create a User and use set() method to set 1 associated model data. // 2. use model.findOne() with include to get model data with associated data. // 3. use data as Passport data, use `fakeData.create3` as user data. const data = { token: '1', workspaceName: 'ws1', passwordHash: 'ws1ws1ws1', provider: 'local', }; let user = await models[SPEC_MODEL_NAME].create({ ...fakeData.create3, Passports: data }, { include: [models.Passport] }); const passport = await models.Passport.create(data); await user.setPassports(passport); const userWithPassport = await models[SPEC_MODEL_NAME].findOne( { where: { nickName: fakeData.create3.nickName }, include: [models.Passport], } ); expect(userWithPassport.nickName).to.be.equal(fakeData.create3.nickName); expect(userWithPassport.email).to.be.equal(fakeData.create3.email); expect(userWithPassport.Passports.length).to.equal(1); expect(userWithPassport.Passports[0].token).to.equal(data.token); expect(userWithPassport.Passports[0].workspaceName).to.equal(data.workspaceName); expect(userWithPassport.Passports[0].passwordHash).to.equal(data.passwordHash); }); });

the following is my user model:以下是我的用户模型:

 module.exports = (sequelize, DataTypes) => { const User = sequelize.define('User', { nickName: { type: DataTypes.STRING, allowNull: false, }, email: { type: DataTypes.STRING, allowNull: false, unique: true, }, }); User.associate = function (models) { User.hasMany(models.UserOrder); User.hasMany(models.Passport); }; return User; };

the following is my passport model:以下是我的护照型号:

 const bcrypt = require('bcrypt'); const crypto = require('crypto'); module.exports = (sequelize, DataTypes) => { const Passport = sequelize.define('Passport', { provider: { type: DataTypes.STRING, allowNull: false, }, token: { type: DataTypes.STRING, allowNull: true, }, password: { type: DataTypes.STRING, allowNull: true, }, workspaceName: { type: DataTypes.STRING, allowNull: true, }, }); Passport.associate = function (models) { Passport.belongsTo(models.User); }; Passport.options.classMethod = { hashPassword: async (passport) => { // eslint-disable-next-line await new Promise((defer, reject) => { if (passport.passwordHash) { bcrypt.hash(passport.passwordHash, 10, (err, hash) => { if (err) reject(err); // eslint-disable-next-line passport.passwordHash = hash; defer(); }); } defer(); }); }, async createDefaultLocalProviderIfNotExist (user) { try { const localPassport = await Passport.findOne({ where: { provider: 'local', userId: user.id, }, }); console.log('localPassport ==', localPassport); if (localPassport == null) { const newLocalPassport = { provider: 'local', password: 'password', userId: user.id, }; console.log('=== newLocalPassport ===', newLocalPassport); await Passport.create(newLocalPassport); } } catch (e) { throw e; } }, }; Passport.options.instanceMethod = { async validatePassword (password) { try { const that = this; // eslint-disable-next-line let result = await new Promise((defer, reject) => { if (password === that.password) { defer(true); } // eslint-disable-next-line bcrypt.compare(password, that.password, (err, result) => { if (err) defer(false); else defer(result); }); }); if (result) return result; console.log('=== this.salt ===', that.salt); console.log('=== this.salt ===', result); if (!this.salt) return result; console.log('=== check two ==='); const comparePassword = crypto.pbkdf2Sync(password, Buffer.from(this.salt, 'base64'), 10000, 64).toString('base64'); if (comparePassword === that.password) { result = true; } return result; } catch (e) { throw e; } }, }; Passport.options.hooks = { async beforeCreate (passport) { return new Promise(async (resolve, reject) => { try { await Passport.hashPassword(passport); return resolve(passport); } catch (e) { return reject(e); } }); }, async beforeUpdate (passport) { return new Promise(async (resolve, reject) => { try { await Passport.hashPassword(passport); return resolve(passport); } catch (e) { return reject(e); } }); }, }; return Passport; };

the following is my userOrder model:以下是我的 userOrder 模型:

 module.exports = (sequelize, DataTypes) => { const UserOrder = sequelize.define('UserOrder', { price: { type: DataTypes.INTEGER, allowNull: false, }, count: { type: DataTypes.INTEGER, allowNull: false, }, subTotal: { type: DataTypes.INTEGER, allowNull: false, }, remark: DataTypes.STRING, }); UserOrder.associate = function (models) { UserOrder.belongsTo(models.User); UserOrder.belongsTo(models.GroupOrder); UserOrder.belongsTo(models.Food); }; return UserOrder; };

thanks!谢谢!

Looking around at examples from the docs and looking into the source a little, I think Sequelize likes you to pass the full options object at the moment you call define .环顾文档中的示例并稍微查看源代码,我认为 Sequelize 喜欢您在调用define传递完整的选项对象。 Create an options object for the Passport model, and assign the hooks to it before passing it as a second parameter to the define call (instead of modifying the options post-define).Passport模型创建一个选项对象,并在将其作为第二个参数传递给define调用(而不是在define后修改选项)之前为其分配钩子。 This will allow it to properly inspect that options object while initializing the model.这将允许它在初始化模型时正确检查该选项对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM