簡體   English   中英

續集錯誤 - “TypeError: hooks.concat is not a function”

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

續集版本:4.38.0

在我的 node.js Web 應用程序中。 我編寫模型規范並運行 npm test。 Create a model with associated data using set()單元測試Create a model with associated data using set() 但我收到以下錯誤:

 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)

以下是我的單元測試代碼:

 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); }); });

以下是我的用戶模型:

 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; };

以下是我的護照型號:

 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; };

以下是我的 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; };

謝謝!

環顧文檔中的示例並稍微查看源代碼,我認為 Sequelize 喜歡您在調用define傳遞完整的選項對象。 Passport模型創建一個選項對象,並在將其作為第二個參數傳遞給define調用(而不是在define后修改選項)之前為其分配鈎子。 這將允許它在初始化模型時正確檢查該選項對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM