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

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 @@
- [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)
- [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:
- 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
- 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
- [FIXED] Pass ResourceLock instead of raw connection in MSSQL disconnect handling
......
......@@ -285,14 +285,12 @@ this.Comment = this.sequelize.define('comment', {
title: Sequelize.STRING,
commentable: Sequelize.STRING,
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, {
foreignKey: 'commentable_id',
constraints: false,
......
......@@ -106,7 +106,7 @@ Sequelize.DECIMAL // DECIMAL
Sequelize.DECIMAL(10, 2) // DECIMAL(10,2)
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.BOOLEAN // TINYINT(1)
......@@ -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:
```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
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]; // '[)'
// or as a single expression
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 },
];
// '("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
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)),
];
// '("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 });
```
......@@ -630,59 +630,33 @@ sequelize.sync({ force: true, match: /_test$/ });
## 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
var Foo = sequelize.define('foo', { /* attributes */}, {
classMethods: {
method1: function(){ return 'smth' }
},
instanceMethods: {
method2: function() { return 'foo' }
}
})
var User = sequelize.define('user', { firstname: Sequelize.STRING });
// Example:
Foo.method1()
Foo.build().method2()
// Adding a class level method
User.classLevelMethod = function() {
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:
```js
var User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING }, {
instanceMethods: {
getFullname: function() {
return [this.firstname, this.lastname].join(' ')
}
}
})
var User = sequelize.define('user', { firstname: Sequelize.STRING, lastname: Sequelize.STRING });
// Example:
User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'
```
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() {}
}
}
})
User.prototype.getFullname = function() {
return [this.firstname, this.lastname].join(' ');
};
// Example:
var Foo = sequelize.define('foo', { /* attributes */});
Foo.method1()
Foo.method2()
Foo.build().method3()
User.build({ firstname: 'foo', lastname: 'bar' }).getFullname() // 'foo bar'
```
### Indexes
......
......@@ -93,8 +93,6 @@ var sequelize = new Sequelize('database', 'username', 'password', {
dialectOptions: {
collate: 'utf8_general_ci'
},
classMethods: {method1: function() {}},
instanceMethods: {method2: function() {}},
timestamps: true
},
 
......
......@@ -82,10 +82,6 @@ class Model {
return options;
}
static _addOptionalClassMethods() {
Utils._.each(this.options.classMethods || {}, (fct, name) => { this[name] = fct; });
}
static _addDefaultAttributes() {
const tail = {};
let head = {};
......@@ -571,8 +567,6 @@ class Model {
this.options = Utils._.extend({
timestamps: true,
instanceMethods: {},
classMethods: {},
validate: {},
freezeTableName: false,
underscored: false,
......@@ -651,18 +645,10 @@ class Model {
}
// Add head and tail default attributes (id, timestamps)
this._addOptionalClassMethods();
this._readOnlyAttributes = Utils._.values(this._timestampAttributes);
this._hasReadOnlyAttributes = this._readOnlyAttributes && this._readOnlyAttributes.length;
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.refreshAttributes();
......
......@@ -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 {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.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.engine]
* @param {String} [options.charset]
......
......@@ -22,13 +22,11 @@ describe(Support.getTestDialectTeaser('associations'), function() {
type: Sequelize.BOOLEAN,
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', {
include: [this.Comment]
......
......@@ -57,21 +57,6 @@ describe(Support.getTestDialectTeaser('Model'), function() {
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() {
var User = this.sequelize.define('UserCol', {
id: {
......
......@@ -789,32 +789,16 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
describe('set', function() {
it("should be configurable with global functions", function() {
var defaultClassMethod = sinon.spy()
, overrideClassMethod = sinon.spy()
, defaultInstanceMethod = sinon.spy()
, overrideInstanceMethod = sinon.spy()
, defaultSetterMethod = sinon.spy()
var defaultSetterMethod = sinon.spy()
, overrideSetterMethod = sinon.spy()
, defaultGetterMethod = sinon.spy()
, overrideGetterMethod = sinon.spy()
, customClassMethod = sinon.spy()
, customOverrideClassMethod = sinon.spy()
, customInstanceMethod = sinon.spy()
, customOverrideInstanceMethod = sinon.spy()
, customSetterMethod = sinon.spy()
, customOverrideSetterMethod = sinon.spy()
, customGetterMethod = sinon.spy()
, customOverrideGetterMethod = sinon.spy();
this.sequelize.options.define = {
'classMethods': {
'defaultClassMethod': defaultClassMethod,
'overrideClassMethod': overrideClassMethod
},
'instanceMethods': {
'defaultInstanceMethod': defaultInstanceMethod,
'overrideInstanceMethod': overrideInstanceMethod
},
'setterMethods': {
'default': defaultSetterMethod,
'override': overrideSetterMethod
......@@ -825,14 +809,6 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
}
};
var testEntity = this.sequelize.define('TestEntity', {}, {
'classMethods': {
'customClassMethod': customClassMethod,
'overrideClassMethod': customOverrideClassMethod
},
'instanceMethods': {
'customInstanceMethod': customInstanceMethod,
'overrideInstanceMethod': customOverrideInstanceMethod
},
'setterMethods': {
'custom': customSetterMethod,
'override': customOverrideSetterMethod
......@@ -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
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
instance.default;
instance.custom;
......@@ -961,58 +909,6 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
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() {
var self = this
, 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!