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

Commit 8d0b0484 by Sascha Depold

Merge branch 'master' into milestones/2.0.0

2 parents 60778406 0a1661c7
...@@ -83,6 +83,7 @@ ...@@ -83,6 +83,7 @@
- [FEATURE] Triggers for Postgres. [#915](https://github.com/sequelize/sequelize/pull/915). Thanks to jonathana. - [FEATURE] Triggers for Postgres. [#915](https://github.com/sequelize/sequelize/pull/915). Thanks to jonathana.
- [FEATURE] Support for join tables. [#877](https://github.com/sequelize/sequelize/pull/877). Thanks to janmeier. - [FEATURE] Support for join tables. [#877](https://github.com/sequelize/sequelize/pull/877). Thanks to janmeier.
- [FEATURE] Support for hooks. [#894](https://github.com/sequelize/sequelize/pull/894). Thanks to durango. - [FEATURE] Support for hooks. [#894](https://github.com/sequelize/sequelize/pull/894). Thanks to durango.
- [FEATURE] Support for literals and casts. [#950](https://github.com/sequelize/sequelize/pull/950). Thanks to durango.
- [REFACTORING] hasMany now uses a single SQL statement when creating and destroying associations, instead of removing each association seperately [690](https://github.com/sequelize/sequelize/pull/690). Inspired by [#104](https://github.com/sequelize/sequelize/issues/104). janmeier - [REFACTORING] hasMany now uses a single SQL statement when creating and destroying associations, instead of removing each association seperately [690](https://github.com/sequelize/sequelize/pull/690). Inspired by [#104](https://github.com/sequelize/sequelize/issues/104). janmeier
- [REFACTORING] Consistent handling of offset across dialects. Offset is now always applied, and limit is set to max table size of not limit is given [#725](https://github.com/sequelize/sequelize/pull/725). janmeier - [REFACTORING] Consistent handling of offset across dialects. Offset is now always applied, and limit is set to max table size of not limit is given [#725](https://github.com/sequelize/sequelize/pull/725). janmeier
- [REFACTORING] Moved Jasmine to Buster and then Buster to Mocha + Chai. sdepold and durango - [REFACTORING] Moved Jasmine to Buster and then Buster to Mocha + Chai. sdepold and durango
......
...@@ -279,7 +279,7 @@ module.exports = (function() { ...@@ -279,7 +279,7 @@ module.exports = (function() {
return this.quoteIdentifiers(obj, force) return this.quoteIdentifiers(obj, force)
} else if (Array.isArray(obj)) { } else if (Array.isArray(obj)) {
return this.quote(obj[0], force) + ' ' + obj[1] return this.quote(obj[0], force) + ' ' + obj[1]
} else if (obj instanceof Utils.fn || obj instanceof Utils.col) { } else if (obj instanceof Utils.fn || obj instanceof Utils.col || obj instanceof Utils.literal || obj instanceof Utils.cast) {
return obj.toString(this) return obj.toString(this)
} else if (Utils._.isObject(obj) && 'raw' in obj) { } else if (Utils._.isObject(obj) && 'raw' in obj) {
return obj.raw return obj.raw
...@@ -349,7 +349,7 @@ module.exports = (function() { ...@@ -349,7 +349,7 @@ module.exports = (function() {
Escape a value (e.g. a string, number or date) Escape a value (e.g. a string, number or date)
*/ */
escape: function(value, field) { escape: function(value, field) {
if (value instanceof Utils.fn || value instanceof Utils.col) { if (value instanceof Utils.fn || value instanceof Utils.col || value instanceof Utils.literal || value instanceof Utils.cast) {
return value.toString(this) return value.toString(this)
} else { } else {
return SqlString.escape(value, false, null, this.dialect, field) return SqlString.escape(value, false, null, this.dialect, field)
......
...@@ -364,5 +364,13 @@ module.exports = (function() { ...@@ -364,5 +364,13 @@ module.exports = (function() {
return new Utils.col(col) return new Utils.col(col)
} }
Sequelize.prototype.cast = function (val, type) {
return new Utils.cast(val, type)
}
Sequelize.prototype.literal = function (val) {
return new Utils.literal(val)
}
return Sequelize return Sequelize
})() })()
...@@ -492,7 +492,31 @@ var Utils = module.exports = { ...@@ -492,7 +492,31 @@ var Utils = module.exports = {
}, },
col: function (col) { col: function (col) {
this.col = col this.col = col
},
cast: function (val, type) {
this.val = val
this.type = (type || '').trim()
},
literal: function (val) {
this.val = val
}
}
// I know this may seem silly, but this gives us the ability to recognize whether
// or not we should be escaping or if we should trust the user. Basically, it
// keeps things in perspective and organized.
Utils.literal.prototype.toString = function() {
return this.val
}
Utils.cast.prototype.toString = function(queryGenerator) {
if (!this.val instanceof Utils.fn && !this.val instanceof Utils.col && !this.val instanceof Utils.literal) {
this.val = queryGenerator.escape(this.val)
} else {
this.val = this.val.toString(queryGenerator)
} }
return 'CAST(' + this.val + ' AS ' + this.type.toUpperCase() + ')'
} }
Utils.fn.prototype.toString = function(queryGenerator) { Utils.fn.prototype.toString = function(queryGenerator) {
...@@ -501,9 +525,10 @@ Utils.fn.prototype.toString = function(queryGenerator) { ...@@ -501,9 +525,10 @@ Utils.fn.prototype.toString = function(queryGenerator) {
return arg.toString(queryGenerator) return arg.toString(queryGenerator)
} else { } else {
return queryGenerator.escape(arg) return queryGenerator.escape(arg)
} }
}).join(', ') + ')' }).join(', ') + ')'
} }
Utils.col.prototype.toString = function (queryGenerator) { Utils.col.prototype.toString = function (queryGenerator) {
return queryGenerator.quote(this.col) return queryGenerator.quote(this.col)
} }
......
...@@ -383,6 +383,82 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -383,6 +383,82 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
describe('create', function() { describe('create', function() {
it('is possible to use casting when creating an instance', function (done) {
var self = this
, type = dialect === "mysql" ? 'signed' : 'integer'
, _done = _.after(2, function() {
done()
})
this.User.create({
intVal: this.sequelize.cast('1', type)
}).on('sql', function (sql) {
expect(sql).to.match(new RegExp('CAST\\(1 AS ' + type.toUpperCase() + '\\)'))
_done()
})
.success(function (user) {
self.User.find(user.id).success(function (user) {
expect(user.intVal).to.equal(1)
_done()
})
})
})
it('is possible to use casting multiple times mixed in with other utilities', function (done) {
var self = this
, type = this.sequelize.cast(this.sequelize.cast(this.sequelize.literal('1-2'), 'integer'), 'integer')
, _done = _.after(2, function() {
done()
})
if (dialect === "mysql") {
type = this.sequelize.cast(this.sequelize.cast(this.sequelize.literal('1-2'), 'unsigned'), 'signed')
}
this.User.create({
intVal: type
}).on('sql', function (sql) {
if (dialect === "mysql") {
expect(sql).to.contain('CAST(CAST(1-2 AS UNSIGNED) AS SIGNED)')
} else {
expect(sql).to.contain('CAST(CAST(1-2 AS INTEGER) AS INTEGER)')
}
_done()
}).success(function (user) {
self.User.find(user.id).success(function (user) {
expect(user.intVal).to.equal(-1)
_done()
})
})
})
it('is possible to just use .literal() to bypass escaping', function (done) {
var self = this
this.User.create({
intVal: this.sequelize.literal('CAST(1-2 AS ' + (dialect === "mysql" ? 'SIGNED' : 'INTEGER') + ')')
}).success(function (user) {
self.User.find(user.id).success(function (user) {
expect(user.intVal).to.equal(-1)
done()
})
})
})
it('is possible for .literal() to contain other utility functions', function (done) {
var self = this
this.User.create({
intVal: this.sequelize.literal(this.sequelize.cast('1-2', (dialect === "mysql" ? 'SIGNED' : 'INTEGER')))
}).success(function (user) {
self.User.find(user.id).success(function (user) {
expect(user.intVal).to.equal(-1)
done()
})
})
})
it('is possible to use funtions when creating an instance', function (done) { it('is possible to use funtions when creating an instance', function (done) {
var self = this var self = this
this.User.create({ this.User.create({
...@@ -394,6 +470,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -394,6 +470,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
}) })
}) })
it('is possible to use functions as default values', function (done) { it('is possible to use functions as default values', function (done) {
var self = this var self = this
, userWithDefaults , userWithDefaults
...@@ -446,6 +523,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -446,6 +523,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
done() done()
} }
}) })
it("casts empty arrays correctly for postgresql insert", function(done) { it("casts empty arrays correctly for postgresql insert", function(done) {
if (dialect !== "postgres" && dialect !== "postgresql-native") { if (dialect !== "postgres" && dialect !== "postgresql-native") {
expect('').to.equal('') expect('').to.equal('')
...@@ -1068,6 +1146,21 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -1068,6 +1146,21 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
}) })
}) })
it('updates with casting', function (done) {
var self = this
this.User.create({
username: 'John'
}).success(function(user) {
self.User.update({username: self.sequelize.cast('1', 'char')}, {username: 'John'}).success(function() {
self.User.all().success(function(users) {
expect(users[0].username).to.equal('1')
done()
})
})
})
})
it('updates with function and column value', function (done) { it('updates with function and column value', function (done) {
var self = this var self = this
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!