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

Commit cdeaff8c by Sascha Depold

merge

2 parents 9ed51569 5d4227ce
...@@ -20,4 +20,3 @@ language: node_js ...@@ -20,4 +20,3 @@ language: node_js
node_js: node_js:
- 0.8 - 0.8
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
- [FEATURE] timestamps are now stored as UTC. #461 (thanks to innofluence/janmeier) - [FEATURE] timestamps are now stored as UTC. #461 (thanks to innofluence/janmeier)
- [FEATURE] results of raw queries are parsed with dottie. #468 (thanks to kozze89) - [FEATURE] results of raw queries are parsed with dottie. #468 (thanks to kozze89)
- [FEATURE] support for array serialization. pg only. #443 (thanks to clkao) - [FEATURE] support for array serialization. pg only. #443 (thanks to clkao)
- [FEATURE] add increment and decrement methods on dao (thanks to janmeier/innofluence)
# v1.5.0 # # v1.5.0 #
- [REFACTORING] use underscore functions for Utils.isHash (thanks to Mick-Hansen/innofluence) - [REFACTORING] use underscore functions for Utils.isHash (thanks to Mick-Hansen/innofluence)
......
...@@ -237,6 +237,35 @@ module.exports = (function() { ...@@ -237,6 +237,35 @@ module.exports = (function() {
} }
} }
DAO.prototype.increment = function(fields, count) {
var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : this.id,
values = {}
if (count === undefined) count = 1;
if (Utils._.isString(fields)) {
values[fields] = count;
} else if (Utils._.isArray(fields)) {
Utils._.each(fields, function (field) {
values[field] = count
})
} else { // Assume fields is key-value pairs
values = fields;
}
return this.QueryInterface.increment(this, this.__factory.tableName, values, identifier)
}
DAO.prototype.decrement = function (fields, count) {
if (!Utils._.isString(fields) && !Utils._.isArray(fields)) { // Assume fields is key-value pairs
Utils._.each(fields, function (value, field) {
fields[field] = -value;
});
}
return this.increment(fields, 0 - count);
}
DAO.prototype.equals = function(other) { DAO.prototype.equals = function(other) {
var result = true var result = true
, self = this , self = this
......
...@@ -233,6 +233,28 @@ module.exports = (function() { ...@@ -233,6 +233,28 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
incrementQuery: function (tableName, attrValueHash, where) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %> "
, values = []
for (var key in attrValueHash) {
var value = attrValueHash[key]
, _value = (value instanceof Date) ? Utils.toSqlDate(value) : value
values.push(Utils.addTicks(key) + "=" + Utils.addTicks(key) + " + " +Utils.escape(_value))
}
var replacements = {
table: Utils.addTicks(tableName),
values: values.join(","),
where: QueryGenerator.getWhereConditions(where)
}
return Utils._.template(query)(replacements)
},
addIndexQuery: function(tableName, attributes, options) { addIndexQuery: function(tableName, attributes, options) {
var transformedAttributes = attributes.map(function(attribute) { var transformedAttributes = attributes.map(function(attribute) {
if(typeof attribute === 'string') { if(typeof attribute === 'string') {
......
...@@ -363,6 +363,27 @@ module.exports = (function() { ...@@ -363,6 +363,27 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
incrementQuery: function(tableName, attrValueHash, where) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %> RETURNING *"
, values = []
for (var key in attrValueHash) {
var value = attrValueHash[key]
values.push(addQuotes(key) + "=" + addQuotes(key) + " + " + pgEscape(value))
}
var replacements = {
table: addQuotes(tableName),
values: values.join(","),
where: QueryGenerator.getWhereConditions(where)
}
return Utils._.template(query)(replacements)
},
addIndexQuery: function(tableName, attributes, options) { addIndexQuery: function(tableName, attributes, options) {
var transformedAttributes = attributes.map(function(attribute) { var transformedAttributes = attributes.map(function(attribute) {
if (typeof attribute === 'string') { if (typeof attribute === 'string') {
......
...@@ -144,6 +144,20 @@ module.exports = (function() { ...@@ -144,6 +144,20 @@ module.exports = (function() {
}, },
/* /*
Returns an update query.
Parameters:
- tableName -> Name of the table
- values -> A hash with attribute-value-pairs
- where -> A hash with conditions (e.g. {name: 'foo'})
OR an ID as integer
OR a string with conditions (e.g. 'name="foo"').
If you use a string, you have to escape it on your own.
*/
incrementQuery: function(tableName, values, where) {
throwMethodUndefined('incrementQuery')
},
/*
Returns an add index query. Returns an add index query.
Parameters: Parameters:
- tableName -> Name of an existing table. - tableName -> Name of an existing table.
......
...@@ -114,6 +114,26 @@ module.exports = (function() { ...@@ -114,6 +114,26 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
incrementQuery: function(tableName, attrValueHash, where) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
, values = []
for (var key in attrValueHash) {
var value = attrValueHash[key]
values.push(Utils.addTicks(key) + "=" + Utils.addTicks(key) + "+ " + escape((value instanceof Date) ? Utils.toSqlDate(value) : value))
}
var replacements = {
table: Utils.addTicks(tableName),
values: values.join(","),
where: MySqlQueryGenerator.getWhereConditions(where)
}
return Utils._.template(query)(replacements)
},
attributesToSQL: function(attributes) { attributesToSQL: function(attributes) {
var result = {} var result = {}
......
...@@ -205,6 +205,11 @@ module.exports = (function() { ...@@ -205,6 +205,11 @@ module.exports = (function() {
return queryAndEmit.call(this, [sql, factory, queryOptions], 'select') return queryAndEmit.call(this, [sql, factory, queryOptions], 'select')
} }
QueryInterface.prototype.increment = function(dao, tableName, values, identifier) {
var sql = this.QueryGenerator.incrementQuery(tableName, values, identifier);
return queryAndEmit.call(this, [sql, dao], 'increment');
}
QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector) { QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector) {
var self = this var self = this
......
...@@ -75,8 +75,8 @@ describe('Sequelize', function() { ...@@ -75,8 +75,8 @@ describe('Sequelize', function() {
Photo.sync({ force: true }).success(function() { Photo.sync({ force: true }).success(function() {
sequelize.getQueryInterface().showAllTables().success(function(tableNames) { sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
expect(tableNames.indexOf('photos') !== -1).toBeTruthy() expect(tableNames).toContain('photos')
done(); done()
}) })
}) })
}) })
......
No preview for this file type
...@@ -2,6 +2,7 @@ if (typeof require === 'function') { ...@@ -2,6 +2,7 @@ if (typeof require === 'function') {
const buster = require("buster") const buster = require("buster")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, _ = require('underscore')
} }
buster.spec.expose() buster.spec.expose()
...@@ -17,7 +18,8 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -17,7 +18,8 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
self.User = sequelize.define('User', { self.User = sequelize.define('User', {
username: { type: DataTypes.STRING }, username: { type: DataTypes.STRING },
touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
aNumber: { type: DataTypes.INTEGER } aNumber: { type: DataTypes.INTEGER },
bNumber: { type: DataTypes.INTEGER }
}) })
self.HistoryLog = sequelize.define('HistoryLog', { self.HistoryLog = sequelize.define('HistoryLog', {
...@@ -34,6 +36,186 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -34,6 +36,186 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
}) })
describe('increment', function () {
before(function (done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
});
it('with array', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
user1.increment(['aNumber'], 2).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(2);
done();
});
});
});
});
it('with single field', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
user1.increment('aNumber', 2).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(2);
done();
});
});
});
});
it('should still work right with other concurrent updates', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
// Select the user again (simulating a concurrent query)
self.User.find(1).done(function (err, user2) {
user2.updateAttributes({
aNumber: user2.aNumber + 1
}).done(function (err, user3) {
user1.increment(['aNumber'], 2).done(function (err, user4) {
self.User.find(1).done(function (err, user5) {
expect(user5.aNumber).toBe(3);
done();
});
});
});
});
});
});
it('should still work right with other concurrent increments', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
var _done = _.after(3, function () {
self.User.find(1).done(function (err, user2) {
expect(user2.aNumber).toEqual(6);
done();
})
});
user1.increment(['aNumber'], 2).done(_done);
user1.increment(['aNumber'], 2).done(_done);
user1.increment(['aNumber'], 2).done(_done);
});
});
it('with key value pair', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
user1.increment({ 'aNumber': 1, 'bNumber': 2}).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(1);
expect(user3.bNumber).toBe(2);
done();
});
});
});
});
});
describe('decrement', function () {
before(function (done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
});
it('with array', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
user1.decrement(['aNumber'], 2).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(-2);
done();
});
});
});
});
it('with single field', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
user1.decrement('aNumber', 2).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(-2);
done();
});
});
});
});
it('should still work right with other concurrent updates', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
// Select the user again (simulating a concurrent query)
self.User.find(1).done(function (err, user2) {
user2.updateAttributes({
aNumber: user2.aNumber + 1
}).done(function (err, user3) {
user1.decrement(['aNumber'], 2).done(function (err, user4) {
self.User.find(1).done(function (err, user5) {
expect(user5.aNumber).toBe(-1);
done();
});
});
});
});
});
});
it('should still work right with other concurrent increments', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
var _done = _.after(3, function () {
self.User.find(1).done(function (err, user2) {
expect(user2.aNumber).toEqual(-6);
done();
})
});
user1.decrement(['aNumber'], 2).done(_done);
user1.decrement(['aNumber'], 2).done(_done);
user1.decrement(['aNumber'], 2).done(_done);
});
});
it('with key value pair', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
user1.decrement({ 'aNumber': 1, 'bNumber': 2}).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(-1);
expect(user3.bNumber).toBe(-2);
done();
});
});
});
});
});
describe('default values', function() { describe('default values', function() {
describe('current date', function() { describe('current date', function() {
it('should store a date in touchedAt', function() { it('should store a date in touchedAt', function() {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!