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

Commit 0e5bbe88 by Mick Hansen

Merge branch 'master' of github.com:sequelize/sequelize

2 parents 713b42f2 ddf86f46
# Next # Next
- [FEATURE] Throw an error if no where clause is given to `Model.destroy()`.
- [BUG] Fixed issue with `order: sequelize.literal('string')` - [BUG] Fixed issue with `order: sequelize.literal('string')`
- [FEATURE] add `clone: true` support to `.get()`. Is needed when using `delete` on values from a `.get()` (`toJSON()`, `this.values`). (.get() is just a reference to the values for performance reasons when there's no custom getters or includes) - [FEATURE] add `clone: true` support to `.get()`. Is needed when using `delete` on values from a `.get()` (`toJSON()`, `this.values`). (.get() is just a reference to the values for performance reasons when there's no custom getters or includes)
- [FEATURE] add `sequelize.escape(value)` convenience method - [FEATURE] add `sequelize.escape(value)` convenience method
...@@ -11,7 +12,7 @@ ...@@ -11,7 +12,7 @@
#### Backwards compatability changes #### Backwards compatability changes
- `instance.update()` using default fields will now automatically also save and validate values provided via `beforeUpdate` hooks - `instance.update()` using default fields will now automatically also save and validate values provided via `beforeUpdate` hooks
- Sequelize no longer supports case insensitive mysql enums
# 2.0.0-rc6 # 2.0.0-rc6
- [BUG] Fixed issue with including by association reference and where - [BUG] Fixed issue with including by association reference and where
......
...@@ -8,6 +8,8 @@ In order to use the CLI you need to install the respective package: ...@@ -8,6 +8,8 @@ In order to use the CLI you need to install the respective package:
$ npm install --save sequelize-cli $ npm install --save sequelize-cli
``` ```
As with any npm package, you can use the global flag (`-g`) to install the CLI globally. If you have installed the CLI without the global flag, use `node_modules/.bin/sequelize [command]` instead of `sequelize [command]`.
The CLI currently supports the following commands: The CLI currently supports the following commands:
```bash ```bash
...@@ -18,7 +20,7 @@ $ sequelize init # Initializes the project. ...@@ -18,7 +20,7 @@ $ sequelize init # Initializes the project.
$ sequelize migration:create # Generates a new migration file. $ sequelize migration:create # Generates a new migration file.
$ sequelize version # Prints the version number. $ sequelize version # Prints the version number.
``` ```
Further and more detailled information about the available commands Further and more detailled information about the available commands
can be obtained via the help command: can be obtained via the help command:
...@@ -303,4 +305,4 @@ migrator ...@@ -303,4 +305,4 @@ migrator
[0]: http://gulpjs.com/ [0]: http://gulpjs.com/
[1]: https://github.com/sequelize/cli [1]: https://github.com/sequelize/cli
[2]: https://github.com/sequelize/gulp-sequelize [2]: https://github.com/sequelize/gulp-sequelize
\ No newline at end of file
...@@ -589,8 +589,8 @@ Let's assume we have an empty database with a `User` model which has a `username ...@@ -589,8 +589,8 @@ Let's assume we have an empty database with a `User` model which has a `username
```js ```js
User User
.findOrCreate({ username: 'sdepold' }, { job: 'Technical Lead JavaScript' }) .findOrCreate({where: {username: 'sdepold'}, defaults: {job: 'Technical Lead JavaScript'}})
.then(function(user, created) { .spread(function(user, created) {
console.log(user.values) console.log(user.values)
console.log(created) console.log(created)
   
...@@ -613,8 +613,8 @@ User ...@@ -613,8 +613,8 @@ User
.create({ username: 'fnord', job: 'omnomnom' }) .create({ username: 'fnord', job: 'omnomnom' })
.then(function() { .then(function() {
User User
.findOrCreate({ username: 'fnord' }, { job: 'something else' }) .findOrCreate({where: {username: 'fnord'}, defaults: {job: 'something else'}})
.then(function(user, created) { .spread(function(user, created) {
console.log(user.values) console.log(user.values)
console.log(created) console.log(created)
   
...@@ -634,8 +634,6 @@ User ...@@ -634,8 +634,6 @@ User
... the existing entry will not be changed. See the `job` of the second user, and the fact that created was false. ... the existing entry will not be changed. See the `job` of the second user, and the fact that created was false.
Notice that the success callback has two arguments. When using [promises][5] you should call `spread` [(API ref)][6] instead of `then`, since `then` will only recieve the first argument (the DAO), while `spread` will recieve both the DAO, and the `created` boolean.
### findAndCountAll - Search for multiple elements in the database, returns both data and total count ### findAndCountAll - Search for multiple elements in the database, returns both data and total count
This is a convienience method that combines`findAll()`and`count()`(see below), this is useful when dealing with queries related to pagination where you want to retrieve data with a`limit`and`offset`but also need to know the total number of records that match the query. This is a convienience method that combines`findAll()`and`count()`(see below), this is useful when dealing with queries related to pagination where you want to retrieve data with a`limit`and`offset`but also need to know the total number of records that match the query.
...@@ -835,7 +833,7 @@ Project.count({ where: ["id > ?", 25] }).then(function(c) { ...@@ -835,7 +833,7 @@ Project.count({ where: ["id > ?", 25] }).then(function(c) {
### max - Get the greatest value of a specific attribute within a specific table ### max - Get the greatest value of a specific attribute within a specific table
And here is a method for getting the max value of an attribute: And here is a method for getting the max value of an attribute:f
```js ```js
/* /*
......
...@@ -264,7 +264,7 @@ module.exports = (function() { ...@@ -264,7 +264,7 @@ module.exports = (function() {
var table = this.quoteTable(tableName); var table = this.quoteTable(tableName);
if (options.truncate === true) { if (options.truncate === true) {
// Truncate does not allow LIMIT and WHERE // Truncate does not allow LIMIT and WHERE
return 'TRUNCATE ' + table; return 'TRUNCATE TABLE ' + table;
} }
where = this.getWhereConditions(where); where = this.getWhereConditions(where);
......
...@@ -149,7 +149,7 @@ module.exports = (function() { ...@@ -149,7 +149,7 @@ module.exports = (function() {
} else if (this.isBulkUpdateQuery()) { } else if (this.isBulkUpdateQuery()) {
result = data.length; result = data.length;
} else if (this.isBulkDeleteQuery()){ } else if (this.isBulkDeleteQuery()){
result = data[0].AFFECTEDROWS; result = data[0] && data[0].AFFECTEDROWS;
} else if (this.isVersionQuery()) { } else if (this.isVersionQuery()) {
result = data[0].version; result = data[0].version;
} }
......
...@@ -518,27 +518,6 @@ module.exports = (function() { ...@@ -518,27 +518,6 @@ module.exports = (function() {
} }
}); });
for (var attrName in this.Model.rawAttributes) {
if (self.Model.rawAttributes.hasOwnProperty(attrName)) {
var definition = this.Model.rawAttributes[attrName]
, isEnum = definition.type.toString() === DataTypes.ENUM.toString()
, isMySQL = ['mysql', 'mariadb'].indexOf(this.Model.modelManager.sequelize.options.dialect) !== -1
, ciCollation = !!this.Model.options.collate && this.Model.options.collate.match(/_ci$/i)
, valueOutOfScope;
// Unfortunately for MySQL CI collation we need to map/lowercase values again
if (isEnum && isMySQL && ciCollation && (attrName in values) && values[attrName]) {
var scopeIndex = (definition.values || []).map(function(d) { return d.toLowerCase(); }).indexOf(values[attrName].toLowerCase());
valueOutOfScope = scopeIndex === -1;
// We'll return what the actual case will be, since a simple SELECT query would do the same...
if (!valueOutOfScope) {
values[attrName] = definition.values[scopeIndex];
}
}
}
}
if (updatedAtAttr && !options.silent) { if (updatedAtAttr && !options.silent) {
values[updatedAtAttr] = self.Model.__getTimestamp(updatedAtAttr); values[updatedAtAttr] = self.Model.__getTimestamp(updatedAtAttr);
} }
...@@ -559,7 +538,7 @@ module.exports = (function() { ...@@ -559,7 +538,7 @@ module.exports = (function() {
var identifier = self.primaryKeyValues; var identifier = self.primaryKeyValues;
if (identifier) { if (identifier) {
for (attrName in identifier) { for (var attrName in identifier) {
// Field name mapping // Field name mapping
var rawAttribute = self.Model.rawAttributes[attrName]; var rawAttribute = self.Model.rawAttributes[attrName];
if (rawAttribute.field && rawAttribute.field !== rawAttribute.fieldName) { if (rawAttribute.field && rawAttribute.field !== rawAttribute.fieldName) {
......
...@@ -1412,6 +1412,13 @@ module.exports = (function() { ...@@ -1412,6 +1412,13 @@ module.exports = (function() {
* @return {Promise<undefined>} * @return {Promise<undefined>}
*/ */
Model.prototype.destroy = function(options) { Model.prototype.destroy = function(options) {
var self = this
, instances;
if (!options || !(options.where || options.truncate)) {
throw new Error('Missing where or truncate attribute in the options parameter passed to destroy.');
}
options = Utils._.extend({ options = Utils._.extend({
hooks: true, hooks: true,
individualHooks: false, individualHooks: false,
...@@ -1421,8 +1428,6 @@ module.exports = (function() { ...@@ -1421,8 +1428,6 @@ module.exports = (function() {
options.type = QueryTypes.BULKDELETE; options.type = QueryTypes.BULKDELETE;
var self = this
, instances;
mapFieldNames.call(this, options, this); mapFieldNames.call(this, options, this);
......
...@@ -78,58 +78,6 @@ if (Support.dialectIsMySQL()) { ...@@ -78,58 +78,6 @@ if (Support.dialectIsMySQL()) {
}); });
}); });
describe('validations', function() {
describe('enums', function() {
it('enum data type should be case insensitive if my collation allows it', function(done) {
var User = this.sequelize.define('User' + config.rand(), {
mood: {
type: DataTypes.ENUM,
values: ['HAPPY', 'sad', 'WhatEver']
}
}, {
collate: 'utf8_general_ci'
});
User.sync({ force: true }).success(function() {
User.create({mood: 'happy'}).success(function(user) {
expect(user).to.exist;
expect(user.mood).to.equal('HAPPY');
var u = User.build({mood: 'SAD'});
u.save().success(function(_user) {
expect(_user).to.exist;
expect(_user.mood).to.equal('sad');
done();
});
});
});
});
it('enum data type should be case sensitive if my collation enforces it', function(done) {
var User = this.sequelize.define('User' + config.rand(), {
mood: {
type: DataTypes.ENUM,
values: ['HAPPY', 'sad', 'WhatEver']
}
}, {
collate: 'latin1_bin'
});
User.sync({ force: true }).success(function() {
User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error);
expect(err.get('mood')[0].message).to.equal('Value "happy" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver');
var u = User.build({mood: 'SAD'});
u.save().error(function(err) {
expect(err).to.be.instanceOf(Error);
expect(err.get('mood')[0].message).to.equal('Value "SAD" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver');
done();
});
});
});
});
});
});
describe('primaryKeys', function() { describe('primaryKeys', function() {
it('determines the correct primaryKeys', function(done) { it('determines the correct primaryKeys', function(done) {
var User = this.sequelize.define('User' + config.rand(), { var User = this.sequelize.define('User' + config.rand(), {
......
...@@ -857,6 +857,19 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -857,6 +857,19 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
describe('update', function() { describe('update', function() {
it('throws an error if no where clause is given', function() {
var User = this.sequelize.define('User', { username: DataTypes.STRING });
return this.sequelize.sync({ force: true }).then(function() {
return User.update();
}).then(function() {
throw new Error('Update should throw an error if no where clause is given.');
}, function(err) {
expect(err).to.be.an.instanceof(Error);
expect(err.message).to.equal('Missing where attribute in the options parameter passed to update.');
});
});
if (current.dialect.supports.transactions) { if (current.dialect.supports.transactions) {
it('supports transactions', function(done) { it('supports transactions', function(done) {
Support.prepareTransactionTest(this.sequelize, function(sequelize) { Support.prepareTransactionTest(this.sequelize, function(sequelize) {
...@@ -1081,6 +1094,54 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1081,6 +1094,54 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
describe('destroy', function() { describe('destroy', function() {
it('truncate should clear the table', function() {
var User = this.sequelize.define('User', { username: DataTypes.STRING }),
data = [
{ username: 'user1' },
{ username: 'user2' }
];
return this.sequelize.sync({ force: true }).then(function() {
return User.bulkCreate(data);
}).then(function() {
return User.destroy({ truncate: true });
}).then(function() {
return expect(User.findAll()).to.eventually.have.length(0);
});
});
it('throws an error if no where clause is given', function() {
var User = this.sequelize.define('User', { username: DataTypes.STRING });
return this.sequelize.sync({ force: true }).then(function() {
return User.destroy();
}).then(function() {
throw new Error('Destroy should throw an error if no where clause is given.');
}, function(err) {
expect(err).to.be.an.instanceof(Error);
expect(err.message).to.equal('Missing where or truncate attribute in the options parameter passed to destroy.');
});
});
it('deletes all instances when given an empty where object', function() {
var User = this.sequelize.define('User', { username: DataTypes.STRING }),
data = [
{ username: 'user1' },
{ username: 'user2' }
];
return this.sequelize.sync({ force: true }).then(function() {
return User.bulkCreate(data);
}).then(function() {
return User.destroy({ where: {} });
}).then(function(affectedRows) {
expect(affectedRows).to.equal(2);
return User.findAll();
}).then(function(users) {
expect(users).to.have.length(0);
});
});
if (current.dialect.supports.transactions) { if (current.dialect.supports.transactions) {
it('supports transactions', function(done) { it('supports transactions', function(done) {
Support.prepareTransactionTest(this.sequelize, function(sequelize) { Support.prepareTransactionTest(this.sequelize, function(sequelize) {
...@@ -1089,7 +1150,10 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -1089,7 +1150,10 @@ describe(Support.getTestDialectTeaser('Model'), function() {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function() { User.create({ username: 'foo' }).success(function() {
sequelize.transaction().then(function(t) { sequelize.transaction().then(function(t) {
User.destroy({transaction: t }).success(function() { User.destroy({
where: {},
transaction: t
}).success(function() {
User.count().success(function(count1) { User.count().success(function(count1) {
User.count({ transaction: t }).success(function(count2) { User.count({ transaction: t }).success(function(count2) {
expect(count1).to.equal(1); expect(count1).to.equal(1);
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!