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

Commit 08324ff9 by Daniel Durante

Merge pull request #700 from PiPeep/master

Consolidate escaping into SqlString
2 parents b14aeda9 70d38f78
var Utils = require("../../utils") var Utils = require("../../utils")
, DataTypes = require("../../data-types") , DataTypes = require("../../data-types")
, SqlString = require("../../sql-string")
, util = require("util") , util = require("util")
module.exports = (function() { module.exports = (function() {
...@@ -553,7 +554,7 @@ module.exports = (function() { ...@@ -553,7 +554,7 @@ module.exports = (function() {
} }
if (dataType.comment && Utils._.isString(dataType.comment) && dataType.comment.length) { if (dataType.comment && Utils._.isString(dataType.comment) && dataType.comment.length) {
template += " COMMENT " + Utils.escape(dataType.comment) template += " COMMENT " + this.escape(dataType.comment)
} }
result[name] = template result[name] = template
...@@ -600,12 +601,7 @@ module.exports = (function() { ...@@ -600,12 +601,7 @@ module.exports = (function() {
}, },
escape: function(value) { escape: function(value) {
if (value instanceof Date) { return SqlString.escape(value, false, null, "mysql")
value = Utils.toSqlDate(value)
} else if (typeof value === 'boolean') {
value = value ? 1 : 0
}
return Utils.escape(value)
} }
} }
......
var Utils = require("../../utils") var Utils = require("../../utils")
, util = require("util") , util = require("util")
, DataTypes = require("../../data-types") , DataTypes = require("../../data-types")
, SqlString = require("../../sql-string")
, tables = {} , tables = {}
, primaryKeys = {} , primaryKeys = {}
, moment = require("moment")
module.exports = (function() { module.exports = (function() {
var QueryGenerator = { var QueryGenerator = {
...@@ -724,10 +724,6 @@ module.exports = (function() { ...@@ -724,10 +724,6 @@ module.exports = (function() {
return (i < 10) ? '0' + i.toString() : i.toString() return (i < 10) ? '0' + i.toString() : i.toString()
}, },
pgSqlDate: function (dt) {
return moment(dt).format("YYYY-MM-DD HH:mm:ss.SSS Z")
},
pgDataTypeMapping: function (tableName, attr, dataType) { pgDataTypeMapping: function (tableName, attr, dataType) {
if (Utils._.includes(dataType, 'PRIMARY KEY')) { if (Utils._.includes(dataType, 'PRIMARY KEY')) {
primaryKeys[tableName].push(attr) primaryKeys[tableName].push(attr)
...@@ -778,33 +774,8 @@ module.exports = (function() { ...@@ -778,33 +774,8 @@ module.exports = (function() {
return identifiers.split('.').map(function(t) { return this.quoteIdentifier(t, force) }.bind(this)).join('.') return identifiers.split('.').map(function(t) { return this.quoteIdentifier(t, force) }.bind(this)).join('.')
}, },
escape: function (val, field) { escape: function(value, field) {
if (val === undefined || val === null) { return SqlString.escape(value, false, null, "postgres", field)
return 'NULL';
}
switch (typeof val) {
case 'boolean':
return (val) ? 'true' : 'false';
case 'number':
return val + '';
case 'object':
if (Array.isArray(val)) {
var ret = 'ARRAY['+ val.map(function(it) { return this.escape(it) }.bind(this)).join(',') + ']'
if (!!field && !!field.type) {
ret += '::' + field.type.replace(/\(\d+\)/g, '')
}
return ret
}
}
if (val instanceof Date) {
val = this.pgSqlDate(val);
}
// http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
val = val.replace(/'/g, "''");
return "'" + val + "'";
} }
} }
......
var Utils = require("../../utils") var Utils = require("../../utils")
, DataTypes = require("../../data-types") , DataTypes = require("../../data-types")
, SqlString = require("../../sql-string")
var MySqlQueryGenerator = Utils._.extend( var MySqlQueryGenerator = Utils._.extend(
Utils._.clone(require("../query-generator")), Utils._.clone(require("../query-generator")),
...@@ -453,19 +454,7 @@ module.exports = (function() { ...@@ -453,19 +454,7 @@ module.exports = (function() {
}, },
escape: function(value) { escape: function(value) {
if (value instanceof Date) { return SqlString.escape(value, false, null, "sqlite")
value = Utils.toSqlDate(value)
}
if (typeof value === 'string') {
return "'" + value.replace(/'/g, "''") + "'";
} else if (typeof value === 'boolean') {
return value ? 1 : 0; // SQLite has no type boolean
} else if (value === null || value === undefined) {
return 'NULL';
} else {
return value;
}
} }
} }
......
var SqlString = exports; var moment = require("moment")
, SqlString = exports;
SqlString.escapeId = function (val, forbidQualified) { SqlString.escapeId = function (val, forbidQualified) {
if (forbidQualified) { if (forbidQualified) {
...@@ -7,18 +8,22 @@ SqlString.escapeId = function (val, forbidQualified) { ...@@ -7,18 +8,22 @@ SqlString.escapeId = function (val, forbidQualified) {
return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`'; return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`';
}; };
SqlString.escape = function(val, stringifyObjects, timeZone, dialect) { SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
if (val === undefined || val === null) { if (val === undefined || val === null) {
return 'NULL'; return 'NULL';
} }
switch (typeof val) { switch (typeof val) {
case 'boolean': return (val) ? 'true' : 'false'; case 'boolean':
// SQLite doesn't have true/false support. MySQL aliases true/false to 1/0
// for us. Postgres actually has a boolean type with true/false literals,
// but sequelize doesn't use it yet.
return dialect === 'sqlite' ? +!!val : ('' + !!val);
case 'number': return val+''; case 'number': return val+'';
} }
if (val instanceof Date) { if (val instanceof Date) {
val = SqlString.dateToString(val, timeZone || "Z"); val = SqlString.dateToString(val, timeZone || "Z", dialect);
} }
if (Buffer.isBuffer(val)) { if (Buffer.isBuffer(val)) {
...@@ -26,7 +31,7 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect) { ...@@ -26,7 +31,7 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect) {
} }
if (Array.isArray(val)) { if (Array.isArray(val)) {
return SqlString.arrayToList(val, timeZone); return SqlString.arrayToList(val, timeZone, dialect, field);
} }
if (typeof val === 'object') { if (typeof val === 'object') {
...@@ -37,8 +42,9 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect) { ...@@ -37,8 +42,9 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect) {
} }
} }
if (dialect == "postgres") { if (dialect === 'postgres' || dialect === 'sqlite') {
// http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS // http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS
// http://stackoverflow.com/q/603572/130598
val = val.replace(/'/g, "''"); val = val.replace(/'/g, "''");
} else { } else {
val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) { val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
...@@ -56,11 +62,22 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect) { ...@@ -56,11 +62,22 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect) {
return "'"+val+"'"; return "'"+val+"'";
}; };
SqlString.arrayToList = function(array, timeZone) { SqlString.arrayToList = function(array, timeZone, dialect, field) {
return array.map(function(v) { if (dialect === 'postgres') {
if (Array.isArray(v)) return '(' + SqlString.arrayToList(v) + ')'; var ret = 'ARRAY[' + array.map(function(v) {
return SqlString.escape(v, true, timeZone); return SqlString.escape(v, true, timeZone, dialect, field);
}).join(', '); }).join(',') + ']';
if (!!field && !!field.type) {
ret += '::' + field.type.replace(/\(\d+\)/g, '');
}
return ret;
} else {
return array.map(function(v) {
if (Array.isArray(v))
return '(' + SqlString.arrayToList(v, timeZone, dialect) + ')';
return SqlString.escape(v, true, timeZone, dialect);
}).join(', ');
}
}; };
SqlString.format = function(sql, values, timeZone, dialect) { SqlString.format = function(sql, values, timeZone, dialect) {
...@@ -75,10 +92,15 @@ SqlString.format = function(sql, values, timeZone, dialect) { ...@@ -75,10 +92,15 @@ SqlString.format = function(sql, values, timeZone, dialect) {
}); });
}; };
SqlString.dateToString = function(date, timeZone) { SqlString.dateToString = function(date, timeZone, dialect) {
var dt = new Date(date); var dt = new Date(date);
if (timeZone != 'local') { // TODO: Ideally all dialects would work a bit more like this
if (dialect === "postgres") {
return moment(dt).format("YYYY-MM-DD HH:mm:ss.SSS Z");
}
if (timeZone !== 'local') {
var tz = convertTimezone(timeZone); var tz = convertTimezone(timeZone);
dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000));
...@@ -87,14 +109,7 @@ SqlString.dateToString = function(date, timeZone) { ...@@ -87,14 +109,7 @@ SqlString.dateToString = function(date, timeZone) {
} }
} }
var year = dt.getFullYear(); return moment(dt).format("YYYY-MM-DD HH:mm:ss");
var month = zeroPad(dt.getMonth() + 1);
var day = zeroPad(dt.getDate());
var hour = zeroPad(dt.getHours());
var minute = zeroPad(dt.getMinutes());
var second = zeroPad(dt.getSeconds());
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second;
}; };
SqlString.bufferToString = function(buffer) { SqlString.bufferToString = function(buffer) {
......
...@@ -42,17 +42,6 @@ var Utils = module.exports = { ...@@ -42,17 +42,6 @@ var Utils = module.exports = {
isHash: function(obj) { isHash: function(obj) {
return Utils._.isObject(obj) && !Array.isArray(obj); return Utils._.isObject(obj) && !Array.isArray(obj);
}, },
pad: function (s) {
return s < 10 ? '0' + s : s
},
toSqlDate: function(date) {
return date.getUTCFullYear() + '-' +
this.pad(date.getUTCMonth()+1) + '-' +
this.pad(date.getUTCDate()) + ' ' +
this.pad(date.getUTCHours()) + ':' +
this.pad(date.getUTCMinutes()) + ':' +
this.pad(date.getUTCSeconds())
},
argsArePrimaryKeys: function(args, primaryKeys) { argsArePrimaryKeys: function(args, primaryKeys) {
var result = (args.length == Object.keys(primaryKeys).length) var result = (args.length == Object.keys(primaryKeys).length)
if (result) { if (result) {
...@@ -181,12 +170,9 @@ var Utils = module.exports = { ...@@ -181,12 +170,9 @@ var Utils = module.exports = {
removeTicks: function(s, tickChar) { removeTicks: function(s, tickChar) {
tickChar = tickChar || Utils.TICK_CHAR tickChar = tickChar || Utils.TICK_CHAR
return s.replace(new RegExp(tickChar, 'g'), "") return s.replace(new RegExp(tickChar, 'g'), "")
},
escape: function(s) {
return SqlString.escape(s, true, "local").replace(/\\"/g, '"')
} }
} }
Utils.CustomEventEmitter = require("./emitters/custom-event-emitter") Utils.CustomEventEmitter = require("./emitters/custom-event-emitter")
Utils.QueryChainer = require("./query-chainer") Utils.QueryChainer = require("./query-chainer")
Utils.Lingo = require("lingo") Utils.Lingo = require("lingo")
\ No newline at end of file
...@@ -235,10 +235,10 @@ describe('QueryGenerator', function() { ...@@ -235,10 +235,10 @@ describe('QueryGenerator', function() {
context: {options: {omitNull: true}} context: {options: {omitNull: true}}
}, { }, {
arguments: ['myTable', {foo: false}], arguments: ['myTable', {foo: false}],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (0);" expectation: "INSERT INTO `myTable` (`foo`) VALUES (false);"
}, { }, {
arguments: ['myTable', {foo: true}], arguments: ['myTable', {foo: true}],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (1);" expectation: "INSERT INTO `myTable` (`foo`) VALUES (true);"
} }
], ],
...@@ -272,7 +272,7 @@ describe('QueryGenerator', function() { ...@@ -272,7 +272,7 @@ describe('QueryGenerator', function() {
context: {options: {omitNull: true}} // Note: As above context: {options: {omitNull: true}} // Note: As above
}, { }, {
arguments: ['myTable', [{name: "foo", value: true}, {name: 'bar', value: false}]], arguments: ['myTable', [{name: "foo", value: true}, {name: 'bar', value: false}]],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',1),('bar',0);" expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',true),('bar',false);"
} }
], ],
...@@ -302,10 +302,10 @@ describe('QueryGenerator', function() { ...@@ -302,10 +302,10 @@ describe('QueryGenerator', function() {
context: {options: {omitNull: true}} context: {options: {omitNull: true}}
}, { }, {
arguments: ['myTable', {bar: false}, {name: 'foo'}], arguments: ['myTable', {bar: false}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=0 WHERE `name`='foo'" expectation: "UPDATE `myTable` SET `bar`=false WHERE `name`='foo'"
}, { }, {
arguments: ['myTable', {bar: true}, {name: 'foo'}], arguments: ['myTable', {bar: true}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=1 WHERE `name`='foo'" expectation: "UPDATE `myTable` SET `bar`=true WHERE `name`='foo'"
} }
], ],
...@@ -385,11 +385,11 @@ describe('QueryGenerator', function() { ...@@ -385,11 +385,11 @@ describe('QueryGenerator', function() {
}, },
{ {
arguments: [{ maple: false, bacon: true }], arguments: [{ maple: false, bacon: true }],
expectation: "`maple`=0 AND `bacon`=1" expectation: "`maple`=false AND `bacon`=true"
}, },
{ {
arguments: [{ beaver: [false, true] }], arguments: [{ beaver: [false, true] }],
expectation: "`beaver` IN (0,1)" expectation: "`beaver` IN (false,true)"
}, },
{ {
arguments: [{birthday: new Date(Date.UTC(2011, 6, 1, 10, 1, 55))}], arguments: [{birthday: new Date(Date.UTC(2011, 6, 1, 10, 1, 55))}],
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!