不要怂,就是干,撸起袖子干!

Commit 94730618 by Mirko Jotic Committed by Sushant

feat: association hooks (#9590)

1 parent 702e3659
......@@ -26,6 +26,10 @@ const Mixin = {
options = _.extend(options, _.omit(source.options, ['hooks']));
if (options.useHooks) {
this.runHooks('beforeAssociate', {source, target, type: HasMany}, options);
}
// the id is in the foreign table or in a connecting table
const association = new HasMany(source, target, options);
source.associations[association.associationAccessor] = association;
......@@ -33,6 +37,10 @@ const Mixin = {
association._injectAttributes();
association.mixin(source.prototype);
if (options.useHooks) {
this.runHooks('afterAssociate', {source, target, type: HasMany, association}, options);
}
return association;
},
......@@ -49,6 +57,9 @@ const Mixin = {
options.timestamps = options.timestamps === undefined ? this.sequelize.options.timestamps : options.timestamps;
options = _.extend(options, _.omit(source.options, ['hooks', 'timestamps', 'scopes', 'defaultScope']));
if (options.useHooks) {
this.runHooks('beforeAssociate', {source, target, type: BelongsToMany}, options);
}
// the id is in the foreign table or in a connecting table
const association = new BelongsToMany(source, target, options);
source.associations[association.associationAccessor] = association;
......@@ -56,6 +67,10 @@ const Mixin = {
association._injectAttributes();
association.mixin(source.prototype);
if (options.useHooks) {
this.runHooks('afterAssociate', {source, target, type: BelongsToMany, association}, options);
}
return association;
},
......@@ -90,6 +105,9 @@ function singleLinked(Type) {
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks);
options.useHooks = options.hooks;
if (options.useHooks) {
this.runHooks('beforeAssociate', {source, target, type: Type}, options);
}
// the id is in the foreign table
const association = new Type(source, target, _.extend(options, source.options));
source.associations[association.associationAccessor] = association;
......@@ -97,6 +115,10 @@ function singleLinked(Type) {
association._injectAttributes();
association.mixin(source.prototype);
if (options.useHooks) {
this.runHooks('afterAssociate', {source, target, type: Type, association}, options);
}
return association;
};
}
......
......@@ -39,6 +39,8 @@ const hookTypes = {
afterDefine: {params: 1, sync: true},
beforeInit: {params: 2, sync: true},
afterInit: {params: 1, sync: true},
beforeAssociate: {params: 2, sync: true},
afterAssociate: {params: 2, sync: true},
beforeConnect: {params: 1},
afterConnect: {params: 2},
beforeSync: {params: 1},
......
......@@ -594,4 +594,63 @@ describe(Support.getTestDialectTeaser('belongsToMany'), () => {
expect(Group.associations.MyUsers.through.model.rawAttributes.GroupId.onDelete).to.equal('RESTRICT');
});
});
describe('association hooks', () => {
beforeEach(function() {
this.Projects = this.sequelize.define('Project', { title: DataTypes.STRING });
this.Tasks = this.sequelize.define('Task', { title: DataTypes.STRING });
});
describe('beforeBelongsToManyAssociate', () => {
it('should trigger', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.belongsToMany(this.Tasks, {through: 'projects_and_tasks', hooks: true});
const beforeAssociateArgs = beforeAssociate.getCall(0).args;
expect(beforeAssociate).to.have.been.called;
expect(beforeAssociateArgs.length).to.equal(2);
const firstArg = beforeAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('BelongsToMany');
expect(beforeAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.belongsToMany(this.Tasks, {through: 'projects_and_tasks', hooks: false});
expect(beforeAssociate).to.not.have.been.called;
});
});
describe('afterBelongsToManyAssociate', () => {
it('should trigger', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.belongsToMany(this.Tasks, {through: 'projects_and_tasks', hooks: true});
const afterAssociateArgs = afterAssociate.getCall(0).args;
expect(afterAssociate).to.have.been.called;
expect(afterAssociateArgs.length).to.equal(2);
const firstArg = afterAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type,association');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('BelongsToMany');
expect(firstArg.association.constructor.name).to.equal('BelongsToMany');
expect(afterAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.belongsToMany(this.Tasks, {through: 'projects_and_tasks', hooks: false});
expect(afterAssociate).to.not.have.been.called;
});
});
});
});
......@@ -2,7 +2,9 @@
const chai = require('chai'),
expect = chai.expect,
sinon = require('sinon'),
_ = require('lodash'),
DataTypes = require(__dirname + '/../../../lib/data-types'),
Support = require(__dirname + '/../support'),
current = Support.sequelize;
......@@ -49,4 +51,64 @@ describe(Support.getTestDialectTeaser('belongsTo'), () => {
expect(user[method]()).to.be.a('function');
});
});
describe('association hooks', () => {
beforeEach(function() {
this.Projects = this.sequelize.define('Project', { title: DataTypes.STRING });
this.Tasks = this.sequelize.define('Task', { title: DataTypes.STRING });
});
describe('beforeBelongsToAssociate', () => {
it('should trigger', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.belongsTo(this.Tasks, {hooks: true});
const beforeAssociateArgs = beforeAssociate.getCall(0).args;
expect(beforeAssociate).to.have.been.called;
expect(beforeAssociateArgs.length).to.equal(2);
const firstArg = beforeAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('BelongsTo');
expect(beforeAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.belongsTo(this.Tasks, {hooks: false});
expect(beforeAssociate).to.not.have.been.called;
});
});
describe('afterBelongsToAssociate', () => {
it('should trigger', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.belongsTo(this.Tasks, {hooks: true});
const afterAssociateArgs = afterAssociate.getCall(0).args;
expect(afterAssociate).to.have.been.called;
expect(afterAssociateArgs.length).to.equal(2);
const firstArg = afterAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type,association');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('BelongsTo');
expect(firstArg.association.constructor.name).to.equal('BelongsTo');
expect(afterAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.belongsTo(this.Tasks, {hooks: false});
expect(afterAssociate).to.not.have.been.called;
});
});
});
});
......@@ -198,4 +198,62 @@ describe(Support.getTestDialectTeaser('hasMany'), () => {
});
});
});
describe('association hooks', () => {
beforeEach(function() {
this.Projects = this.sequelize.define('Project', { title: DataTypes.STRING });
this.Tasks = this.sequelize.define('Task', { title: DataTypes.STRING });
});
describe('beforeHasManyAssociate', () => {
it('should trigger', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.hasMany(this.Tasks, {hooks: true});
const beforeAssociateArgs = beforeAssociate.getCall(0).args;
expect(beforeAssociate).to.have.been.called;
expect(beforeAssociateArgs.length).to.equal(2);
const firstArg = beforeAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('HasMany');
expect(beforeAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.hasMany(this.Tasks, {hooks: false});
expect(beforeAssociate).to.not.have.been.called;
});
});
describe('afterHasManyAssociate', () => {
it('should trigger', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.hasMany(this.Tasks, {hooks: true});
const afterAssociateArgs = afterAssociate.getCall(0).args;
expect(afterAssociate).to.have.been.called;
const firstArg = afterAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type,association');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('HasMany');
expect(firstArg.association.constructor.name).to.equal('HasMany');
expect(afterAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.hasMany(this.Tasks, {hooks: false});
expect(afterAssociate).to.not.have.been.called;
});
});
});
});
......@@ -2,6 +2,7 @@
const chai = require('chai'),
expect = chai.expect,
sinon = require('sinon'),
_ = require('lodash'),
Support = require(__dirname + '/../support'),
DataTypes = require(__dirname + '/../../../lib/data-types'),
......@@ -61,4 +62,64 @@ describe(Support.getTestDialectTeaser('hasOne'), () => {
expect(user[method]()).to.be.a('function');
});
});
describe('association hooks', () => {
beforeEach(function() {
this.Projects = this.sequelize.define('Project', { title: DataTypes.STRING });
this.Tasks = this.sequelize.define('Task', { title: DataTypes.STRING });
});
describe('beforeHasOneAssociate', () => {
it('should trigger', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.hasOne(this.Tasks, {hooks: true});
const beforeAssociateArgs = beforeAssociate.getCall(0).args;
expect(beforeAssociate).to.have.been.called;
expect(beforeAssociateArgs.length).to.equal(2);
const firstArg = beforeAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('HasOne');
expect(beforeAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const beforeAssociate = sinon.spy();
this.Projects.beforeAssociate(beforeAssociate);
this.Projects.hasOne(this.Tasks, {hooks: false});
expect(beforeAssociate).to.not.have.been.called;
});
});
describe('afterHasOneAssociate', () => {
it('should trigger', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.hasOne(this.Tasks, {hooks: true});
const afterAssociateArgs = afterAssociate.getCall(0).args;
expect(afterAssociate).to.have.been.called;
expect(afterAssociateArgs.length).to.equal(2);
const firstArg = afterAssociateArgs[0];
expect(Object.keys(firstArg).join()).to.equal('source,target,type,association');
expect(firstArg.source).to.equal(this.Projects);
expect(firstArg.target).to.equal(this.Tasks);
expect(firstArg.type.name).to.equal('HasOne');
expect(firstArg.association.constructor.name).to.equal('HasOne');
expect(afterAssociateArgs[1].sequelize.constructor.name).to.equal('Sequelize');
});
it('should not trigger association hooks', function() {
const afterAssociate = sinon.spy();
this.Projects.afterAssociate(afterAssociate);
this.Projects.hasOne(this.Tasks, {hooks: false});
expect(afterAssociate).to.not.have.been.called;
});
});
});
});
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!