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

Commit 48c8d2ae by Sushant Committed by Jan Aagaard Meier

(cleanup) removing classMethods / instanceMethods support (#6180)

* (cleanup) removing classMethods / instanceMethods support

* Language

* ; . 🐱
1 parent 527ec4df
...@@ -16,11 +16,13 @@ ...@@ -16,11 +16,13 @@
- [ADDED] Remove hooks by reference [#6155](https://github.com/sequelize/sequelize/issues/6155) - [ADDED] Remove hooks by reference [#6155](https://github.com/sequelize/sequelize/issues/6155)
- [ADDED] before/after Upsert hook [#3965](https://github.com/sequelize/sequelize/issues/3965) - [ADDED] before/after Upsert hook [#3965](https://github.com/sequelize/sequelize/issues/3965)
- [FIXED] Modifying `options` in `beforeFind` throws error [#5675](https://github.com/sequelize/sequelize/issues/5675) - [FIXED] Modifying `options` in `beforeFind` throws error [#5675](https://github.com/sequelize/sequelize/issues/5675)
- [REMOVED] `classMethods` and `instanceMethods` [#5869](https://github.com/sequelize/sequelize/issues/5869#issuecomment-221773485)
## BC breaks: ## BC breaks:
- Range type bounds now default to [postgres default](https://www.postgresql.org/docs/9.5/static/rangetypes.html#RANGETYPES-CONSTRUCT) `[)` (inclusive, exclusive), previously was `()` (exclusive, exclusive) - Range type bounds now default to [postgres default](https://www.postgresql.org/docs/9.5/static/rangetypes.html#RANGETYPES-CONSTRUCT) `[)` (inclusive, exclusive), previously was `()` (exclusive, exclusive)
- Only `belongsTo` uses `as` to construct foreign key - revert of [#5957](https://github.com/sequelize/sequelize/pull/5957) introduced in 4.0.0-0 - Only `belongsTo` uses `as` to construct foreign key - revert of [#5957](https://github.com/sequelize/sequelize/pull/5957) introduced in 4.0.0-0
- Sequelize uses an independent copy of `bluebird` library. This means (1) promises returned from Sequelize methods are instances of `Sequelize.Promise` but not global `Bluebird` and (2) the CLS patch does not affect global `Bluebird`. - Sequelize uses an independent copy of `bluebird` library. This means (1) promises returned from Sequelize methods are instances of `Sequelize.Promise` but not global `Bluebird` and (2) the CLS patch does not affect global `Bluebird`.
- Dropped support for `classMethods` and `instanceMethods`. As Models are now ES6 classes `classMethods` can be directly assigned and `instanceMethods` should be added to `Model.prototype`
# 4.0.0-0 # 4.0.0-0
- [FIXED] Pass ResourceLock instead of raw connection in MSSQL disconnect handling - [FIXED] Pass ResourceLock instead of raw connection in MSSQL disconnect handling
......
...@@ -285,14 +285,12 @@ this.Comment = this.sequelize.define('comment', { ...@@ -285,14 +285,12 @@ this.Comment = this.sequelize.define('comment', {
title: Sequelize.STRING, title: Sequelize.STRING,
commentable: Sequelize.STRING, commentable: Sequelize.STRING,
commentable_id: Sequelize.INTEGER commentable_id: Sequelize.INTEGER
}, {
instanceMethods: {
getItem: function() {
return this['get' + this.get('commentable').substr(0, 1).toUpperCase() + this.get('commentable').substr(1)]();
}
}
}); });
this.Comment.prototype.getItem = function() {
return this['get' + this.get('commentable').substr(0, 1).toUpperCase() + this.get('commentable').substr(1)]();
};
this.Post.hasMany(this.Comment, { this.Post.hasMany(this.Comment, {
foreignKey: 'commentable_id', foreignKey: 'commentable_id',
constraints: false, constraints: false,
......
...@@ -106,7 +106,7 @@ Sequelize.DECIMAL // DECIMAL ...@@ -106,7 +106,7 @@ Sequelize.DECIMAL // DECIMAL
Sequelize.DECIMAL(10, 2) // DECIMAL(10,2) Sequelize.DECIMAL(10, 2) // DECIMAL(10,2)
Sequelize.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres Sequelize.DATE // DATETIME for mysql / sqlite, TIMESTAMP WITH TIME ZONE for postgres
Sequelize.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision Sequelize.DATE(6) // DATETIME(6) for mysql 5.6.4+. Fractional seconds support with up to 6 digits of precision
Sequelize.DATEONLY // DATE without time. Sequelize.DATEONLY // DATE without time.
Sequelize.BOOLEAN // TINYINT(1) Sequelize.BOOLEAN // TINYINT(1)
...@@ -178,7 +178,7 @@ very straightforward to just use a touple to represent them in javascript. ...@@ -178,7 +178,7 @@ very straightforward to just use a touple to represent them in javascript.
When supplying ranges as values you can choose from the following APIs: When supplying ranges as values you can choose from the following APIs:
```js ```js
// defaults to '["2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")' // defaults to '["2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")'
// inclusive lower bound, exclusive upper bound // inclusive lower bound, exclusive upper bound
Timeline.create({ range: [new Date(Date.UTC(2016, 0, 1)), new Date(Date.UTC(2016, 1, 1))] }); Timeline.create({ range: [new Date(Date.UTC(2016, 0, 1)), new Date(Date.UTC(2016, 1, 1))] });
...@@ -191,17 +191,17 @@ range.inclusive = [true, false]; // '[)' ...@@ -191,17 +191,17 @@ range.inclusive = [true, false]; // '[)'
// or as a single expression // or as a single expression
const range = [ const range = [
{ value: new Date(Date.UTC(2016, 0, 1)), inclusive: false }, { value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
{ value: new Date(Date.UTC(2016, 1, 1)), inclusive: true }, { value: new Date(Date.UTC(2016, 1, 1)), inclusive: true },
]; ];
// '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]' // '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00"]'
// composite form // composite form
const range = [ const range = [
{ value: new Date(Date.UTC(2016, 0, 1)), inclusive: false }, { value: new Date(Date.UTC(2016, 0, 1)), inclusive: false },
new Date(Date.UTC(2016, 1, 1)), new Date(Date.UTC(2016, 1, 1)),
]; ];
// '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")' // '("2016-01-01 00:00:00+00:00", "2016-02-01 00:00:00+00:00")'
Timeline.create({ range }); Timeline.create({ range });
``` ```
...@@ -630,59 +630,33 @@ sequelize.sync({ force: true, match: /_test$/ }); ...@@ -630,59 +630,33 @@ sequelize.sync({ force: true, match: /_test$/ });
## Expansion of models ## Expansion of models
Sequelize allows you to pass custom methods to a model and its instances. Just do the following: Sequelize Models are ES6 classes. You can very easily add custom instance or class level methods.
```js ```js
var Foo = sequelize.define('foo', { /* attributes */}, { var User = sequelize.define('user', { firstname: Sequelize.STRING });
classMethods: {
method1: function(){ return 'smth' }
},
instanceMethods: {
method2: function() { return 'foo' }
}
})
// Example: // Adding a class level method
Foo.method1() User.classLevelMethod = function() {
Foo.build().method2() return 'foo';
};
// Adding an instance level method
User.prototype.instanceLevelMethod = function() {
return 'bar';
};
``` ```
Of course you can also access the instance's data and generate virtual getters: Of course you can also access the instance's data and generate virtual getters:
```js ```js
var User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING }, { var User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING });
instanceMethods: {
getFullname: function() {
return [this.firstname, this.lastname].join(' ')
}
}
})
// Example: User.prototype.getFullname = function() {
User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar' return [this.firstname, this.lastname].join(' ');
``` };
You can also set custom methods to all of your models during the instantiation:
```js
var sequelize = new Sequelize('database', 'username', 'password', {
// Other options during the initialization could be here
define: {
classMethods: {
method1: function() {},
method2: function() {}
},
instanceMethods: {
method3: function() {}
}
}
})
// Example: // Example:
var Foo = sequelize.define('foo', { /* attributes */}); User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'
Foo.method1()
Foo.method2()
Foo.build().method3()
``` ```
### Indexes ### Indexes
......
...@@ -93,8 +93,6 @@ var sequelize = new Sequelize('database', 'username', 'password', { ...@@ -93,8 +93,6 @@ var sequelize = new Sequelize('database', 'username', 'password', {
dialectOptions: { dialectOptions: {
collate: 'utf8_general_ci' collate: 'utf8_general_ci'
}, },
classMethods: {method1: function() {}},
instanceMethods: {method2: function() {}},
timestamps: true timestamps: true
}, },
   
......
...@@ -82,10 +82,6 @@ class Model { ...@@ -82,10 +82,6 @@ class Model {
return options; return options;
} }
static _addOptionalClassMethods() {
Utils._.each(this.options.classMethods || {}, (fct, name) => { this[name] = fct; });
}
static _addDefaultAttributes() { static _addDefaultAttributes() {
const tail = {}; const tail = {};
let head = {}; let head = {};
...@@ -571,8 +567,6 @@ class Model { ...@@ -571,8 +567,6 @@ class Model {
this.options = Utils._.extend({ this.options = Utils._.extend({
timestamps: true, timestamps: true,
instanceMethods: {},
classMethods: {},
validate: {}, validate: {},
freezeTableName: false, freezeTableName: false,
underscored: false, underscored: false,
...@@ -651,18 +645,10 @@ class Model { ...@@ -651,18 +645,10 @@ class Model {
} }
// Add head and tail default attributes (id, timestamps) // Add head and tail default attributes (id, timestamps)
this._addOptionalClassMethods();
this._readOnlyAttributes = Utils._.values(this._timestampAttributes); this._readOnlyAttributes = Utils._.values(this._timestampAttributes);
this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length; this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length;
this._isReadOnlyAttribute = Utils._.memoize(key => this._hasReadOnlyAttributes && this._readOnlyAttributes.indexOf(key) !== -1); this._isReadOnlyAttribute = Utils._.memoize(key => this._hasReadOnlyAttributes && this._readOnlyAttributes.indexOf(key) !== -1);
if (this.options.instanceMethods) {
Utils._.each(this.options.instanceMethods, (fct, name) => {
this.prototype[name] = fct;
});
}
this._addDefaultAttributes(); this._addDefaultAttributes();
this.refreshAttributes(); this.refreshAttributes();
......
...@@ -375,8 +375,6 @@ class Sequelize { ...@@ -375,8 +375,6 @@ class Sequelize {
* @param {String} [options.tableName] Defaults to pluralized model name, unless freezeTableName is true, in which case it uses model name verbatim * @param {String} [options.tableName] Defaults to pluralized model name, unless freezeTableName is true, in which case it uses model name verbatim
* @param {Object} [options.getterMethods] Provide getter functions that work like those defined per column. If you provide a getter method with the same name as a column, it will be used to access the value of that column. If you provide a name that does not match a column, this function will act as a virtual getter, that can fetch multiple other values * @param {Object} [options.getterMethods] Provide getter functions that work like those defined per column. If you provide a getter method with the same name as a column, it will be used to access the value of that column. If you provide a name that does not match a column, this function will act as a virtual getter, that can fetch multiple other values
* @param {Object} [options.setterMethods] Provide setter functions that work like those defined per column. If you provide a setter method with the same name as a column, it will be used to update the value of that column. If you provide a name that does not match a column, this function will act as a virtual setter, that can act on and set other values, but will not be persisted * @param {Object} [options.setterMethods] Provide setter functions that work like those defined per column. If you provide a setter method with the same name as a column, it will be used to update the value of that column. If you provide a name that does not match a column, this function will act as a virtual setter, that can act on and set other values, but will not be persisted
* @param {Object} [options.instanceMethods] Provide functions that are added to each instance (DAO). If you override methods provided by sequelize, you can access the original method using `this.constructor.super_.prototype`, e.g. `this.constructor.super_.prototype.toJSON.apply(this, arguments)`
* @param {Object} [options.classMethods] Provide functions that are added to the model (Model). If you override methods provided by sequelize, you can access the original method using `this.constructor.prototype`, e.g. `this.constructor.prototype.find.apply(this, arguments)`
* @param {String} [options.schema='public'] * @param {String} [options.schema='public']
* @param {String} [options.engine] * @param {String} [options.engine]
* @param {String} [options.charset] * @param {String} [options.charset]
......
...@@ -22,13 +22,11 @@ describe(Support.getTestDialectTeaser('associations'), function() { ...@@ -22,13 +22,11 @@ describe(Support.getTestDialectTeaser('associations'), function() {
type: Sequelize.BOOLEAN, type: Sequelize.BOOLEAN,
defaultValue: false defaultValue: false
} }
}, {
instanceMethods: {
getItem: function() {
return this['get' + this.get('commentable').substr(0, 1).toUpperCase() + this.get('commentable').substr(1)]();
}
}
}); });
this.Comment.prototype.getItem = function() {
return this['get' + this.get('commentable').substr(0, 1).toUpperCase() + this.get('commentable').substr(1)]();
};
this.Post.addScope('withComments', { this.Post.addScope('withComments', {
include: [this.Comment] include: [this.Comment]
......
...@@ -57,21 +57,6 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -57,21 +57,6 @@ describe(Support.getTestDialectTeaser('Model'), function() {
expect(factorySize).to.equal(factorySize2); expect(factorySize).to.equal(factorySize2);
}); });
it('attaches class and instance methods', function() {
var User = this.sequelize.define('UserWithClassAndInstanceMethods', {}, {
classMethods: { doSmth: function() { return 1; } },
instanceMethods: { makeItSo: function() { return 2; } }
});
expect(User.doSmth).to.exist;
expect(User.doSmth()).to.equal(1);
expect(User.makeItSo).not.to.exist;
expect(User.build().doSmth).not.to.exist;
expect(User.build().makeItSo).to.exist;
expect(User.build().makeItSo()).to.equal(2);
});
it('allows us us to predefine the ID column with our own specs', function() { it('allows us us to predefine the ID column with our own specs', function() {
var User = this.sequelize.define('UserCol', { var User = this.sequelize.define('UserCol', {
id: { id: {
......
...@@ -789,32 +789,16 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -789,32 +789,16 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
describe('set', function() { describe('set', function() {
it("should be configurable with global functions", function() { it("should be configurable with global functions", function() {
var defaultClassMethod = sinon.spy() var defaultSetterMethod = sinon.spy()
, overrideClassMethod = sinon.spy()
, defaultInstanceMethod = sinon.spy()
, overrideInstanceMethod = sinon.spy()
, defaultSetterMethod = sinon.spy()
, overrideSetterMethod = sinon.spy() , overrideSetterMethod = sinon.spy()
, defaultGetterMethod = sinon.spy() , defaultGetterMethod = sinon.spy()
, overrideGetterMethod = sinon.spy() , overrideGetterMethod = sinon.spy()
, customClassMethod = sinon.spy()
, customOverrideClassMethod = sinon.spy()
, customInstanceMethod = sinon.spy()
, customOverrideInstanceMethod = sinon.spy()
, customSetterMethod = sinon.spy() , customSetterMethod = sinon.spy()
, customOverrideSetterMethod = sinon.spy() , customOverrideSetterMethod = sinon.spy()
, customGetterMethod = sinon.spy() , customGetterMethod = sinon.spy()
, customOverrideGetterMethod = sinon.spy(); , customOverrideGetterMethod = sinon.spy();
this.sequelize.options.define = { this.sequelize.options.define = {
'classMethods': {
'defaultClassMethod': defaultClassMethod,
'overrideClassMethod': overrideClassMethod
},
'instanceMethods': {
'defaultInstanceMethod': defaultInstanceMethod,
'overrideInstanceMethod': overrideInstanceMethod
},
'setterMethods': { 'setterMethods': {
'default': defaultSetterMethod, 'default': defaultSetterMethod,
'override': overrideSetterMethod 'override': overrideSetterMethod
...@@ -825,14 +809,6 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -825,14 +809,6 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
} }
}; };
var testEntity = this.sequelize.define('TestEntity', {}, { var testEntity = this.sequelize.define('TestEntity', {}, {
'classMethods': {
'customClassMethod': customClassMethod,
'overrideClassMethod': customOverrideClassMethod
},
'instanceMethods': {
'customInstanceMethod': customInstanceMethod,
'overrideInstanceMethod': customOverrideInstanceMethod
},
'setterMethods': { 'setterMethods': {
'custom': customSetterMethod, 'custom': customSetterMethod,
'override': customOverrideSetterMethod 'override': customOverrideSetterMethod
...@@ -843,37 +819,9 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -843,37 +819,9 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
} }
}); });
// Call all Class Methods
testEntity.defaultClassMethod();
testEntity.customClassMethod();
testEntity.overrideClassMethod();
expect(typeof testEntity.defaultClassMethod).to.equal('function');
expect(typeof testEntity.customClassMethod).to.equal('function');
expect(typeof testEntity.overrideClassMethod).to.equal('function');
expect(defaultClassMethod).to.have.been.calledOnce;
expect(customClassMethod).to.have.been.calledOnce;
expect(overrideClassMethod.callCount).to.be.eql(0);
expect(customOverrideClassMethod).to.have.been.calledOnce;
// Create Instance to test // Create Instance to test
var instance = testEntity.build(); var instance = testEntity.build();
// Call all Instance Methods
instance.defaultInstanceMethod();
instance.customInstanceMethod();
instance.overrideInstanceMethod();
expect(typeof instance.defaultInstanceMethod).to.equal('function');
expect(typeof instance.customInstanceMethod).to.equal('function');
expect(typeof instance.overrideInstanceMethod).to.equal('function');
expect(defaultInstanceMethod).to.have.been.calledOnce;
expect(customInstanceMethod).to.have.been.calledOnce;
expect(overrideInstanceMethod.callCount).to.be.eql(0);
expect(customOverrideInstanceMethod).to.have.been.calledOnce;
// Call Getters // Call Getters
instance.default; instance.default;
instance.custom; instance.custom;
...@@ -961,58 +909,6 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -961,58 +909,6 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
expect(DAO.options.collate).to.equal('utf8_general_ci'); expect(DAO.options.collate).to.equal('utf8_general_ci');
}); });
it('inherits global classMethods and instanceMethods, and can override global methods with local ones', function() {
var globalClassMethod = sinon.spy()
, globalInstanceMethod = sinon.spy()
, localClassMethod = sinon.spy()
, localInstanceMethod = sinon.spy()
, sequelize = Support.createSequelizeInstance({
define: {
classMethods: {
globalClassMethod: function() {},
overrideMe: globalClassMethod
},
instanceMethods: {
globalInstanceMethod: function() {},
overrideMe: globalInstanceMethod
}
}
})
, DAO;
DAO = sequelize.define('foo', {bar: DataTypes.STRING}, {
classMethods: { localClassMethod: function() {} }
});
expect(typeof DAO.options.classMethods.globalClassMethod).to.equal('function');
expect(typeof DAO.options.classMethods.localClassMethod).to.equal('function');
expect(typeof DAO.options.instanceMethods.globalInstanceMethod).to.equal('function');
// This DAO inherits the global methods
DAO.overrideMe();
DAO.build().overrideMe();
DAO = sequelize.define('foo', {bar: DataTypes.STRING}, {
classMethods: {
overrideMe: localClassMethod
},
instanceMethods: {
overrideMe: localInstanceMethod
}
});
// This DAO has its own implementation
DAO.overrideMe();
DAO.build().overrideMe();
expect(globalClassMethod).to.have.been.calledOnce;
expect(globalInstanceMethod).to.have.been.calledOnce;
expect(localClassMethod).to.have.been.calledOnce;
expect(localInstanceMethod).to.have.been.calledOnce;
});
it('uses the passed tableName', function() { it('uses the passed tableName', function() {
var self = this var self = this
, Photo = this.sequelize.define('Foto', { name: DataTypes.STRING }, { tableName: 'photos' }); , Photo = this.sequelize.define('Foto', { name: DataTypes.STRING }, { tableName: 'photos' });
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!