简体   繁体   中英

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

Sequelize version: 4.38.0

In my node.js web application. I write model spec and run npm test. at the Create a model with associated data using set() unit test. 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:

 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 . 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). This will allow it to properly inspect that options object while initializing the model.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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