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

Commit de91a8f1 by Daniel Durante

Merge pull request #891 from LJ1102/master

Add support for typed arrays in SqlString.escape and SqlString.arrayToList
2 parents 10376a7d cb468426
var moment = require("moment")
, isArrayBufferView
, SqlString = exports;
if (typeof ArrayBufferView === 'function') {
isArrayBufferView = function(object) { return object && (object instanceof ArrayBufferView) }
} else {
var arrayBufferViews = [
Int8Array, Uint8Array, Int16Array, Uint16Array,
Int32Array, Uint32Array, Float32Array, Float64Array
]
isArrayBufferView = function(object) {
for (var i=0; i<8; i++) {
if (object instanceof arrayBufferViews[i]) {
return true
}
}
return false
};
}
SqlString.escapeId = function (val, forbidQualified) {
if (forbidQualified) {
return '`' + val.replace(/`/g, '``') + '`';
return '`' + val.replace(/`/g, '``') + '`'
}
return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`';
};
return '`' + val.replace(/`/g, '``').replace(/\./g, '`.`') + '`'
}
SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
if (arguments.length === 1 && typeof arguments[0] === "object") {
......@@ -37,29 +56,28 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
}
if (val instanceof Date) {
val = SqlString.dateToString(val, timeZone || "Z", dialect);
val = SqlString.dateToString(val, timeZone || "Z", dialect)
}
if (Buffer.isBuffer(val)) {
return SqlString.bufferToString(val, dialect);
return SqlString.bufferToString(val, dialect)
}
if (Array.isArray(val)) {
return SqlString.arrayToList(val, timeZone, dialect, field);
if (Array.isArray(val) || isArrayBufferView(val)) {
return SqlString.arrayToList(val, timeZone, dialect, field)
}
if (typeof val === 'object') {
if (stringifyObjects) {
val = val.toString();
val = val.toString()
} else {
return SqlString.objectToValues(val, timeZone);
return SqlString.objectToValues(val, timeZone)
}
}
if (dialect === 'postgres' || dialect === 'sqlite') {
// 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 {
val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) {
switch(s) {
......@@ -71,115 +89,134 @@ SqlString.escape = function(val, stringifyObjects, timeZone, dialect, field) {
case "\x1a": return "\\Z";
default: return "\\"+s;
}
});
})
}
return "'"+val+"'";
};
return "'"+val+"'"
}
SqlString.arrayToList = function(array, timeZone, dialect, field) {
if (dialect === 'postgres') {
var ret = 'ARRAY[' + array.map(function(v) {
return SqlString.escape(v, true, timeZone, dialect, field);
}).join(',') + ']';
if (array.map) {
var valstr = array.map(function(v) {
return SqlString.escape(v, true, timeZone, dialect, field)
}).join(',')
} else {
var valstr = ""
for (var i = 0; i < array.length; i++) {
valstr += SqlString.escape(array[i], true, timeZone, dialect, field) + ','
}
valstr = valstr.slice(0,-1)
}
var ret = 'ARRAY[' + valstr + ']'
if (!!field && !!field.type) {
ret += '::' + field.type.replace(/\(\d+\)/g, '');
ret += '::' + field.type.replace(/\(\d+\)/g, '')
}
return ret;
return ret
} else {
if (array.map) {
return array.map(function(v) {
if (Array.isArray(v))
return '(' + SqlString.arrayToList(v, timeZone, dialect) + ')';
return SqlString.escape(v, true, timeZone, dialect);
}).join(', ');
if (Array.isArray(v)) {
return '(' + SqlString.arrayToList(v, timeZone, dialect) + ')'
}
return SqlString.escape(v, true, timeZone, dialect)
}).join(', ')
} else {
var valstr = ""
for (var i = 0; i < array.length; i++) {
valstr += SqlString.escape(array[i], true, timeZone, dialect) + ', '
}
};
return valstr.slice(0, -2)
}
}
}
SqlString.format = function(sql, values, timeZone, dialect) {
values = [].concat(values);
return sql.replace(/\?/g, function(match) {
if (!values.length) {
return match;
return match
}
return SqlString.escape(values.shift(), false, timeZone, dialect);
});
};
return SqlString.escape(values.shift(), false, timeZone, dialect)
})
}
SqlString.formatNamedParameters = function(sql, values, timeZone, dialect) {
return sql.replace(/\:(\w+)/g, function (value, key) {
if (values.hasOwnProperty(key)) {
return SqlString.escape(values[key], false, timeZone, dialect);
}
else {
throw new Error('Named parameter "' + value + '" has no value in the given object.');
return SqlString.escape(values[key], false, timeZone, dialect)
} else {
throw new Error('Named parameter "' + value + '" has no value in the given object.')
}
});
};
})
}
SqlString.dateToString = function(date, timeZone, dialect) {
var dt = new Date(date);
var dt = new Date(date)
// TODO: Ideally all dialects would work a bit more like this
if (dialect === "postgres") {
return moment(dt).zone('+00:00').format("YYYY-MM-DD HH:mm:ss.SSS Z");
return moment(dt).zone('+00:00').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))
if (tz !== false) {
dt.setTime(dt.getTime() + (tz * 60000));
dt.setTime(dt.getTime() + (tz * 60000))
}
}
return moment(dt).format("YYYY-MM-DD HH:mm:ss");
};
return moment(dt).format("YYYY-MM-DD HH:mm:ss")
}
SqlString.bufferToString = function(buffer, dialect) {
var hex = '';
var hex = ''
try {
hex = buffer.toString('hex');
hex = buffer.toString('hex')
} catch (err) {
// node v0.4.x does not support hex / throws unknown encoding error
for (var i = 0; i < buffer.length; i++) {
var byte = buffer[i];
hex += zeroPad(byte.toString(16));
var byte = buffer[i]
hex += zeroPad(byte.toString(16))
}
}
if (dialect === 'postgres') {
// bytea hex format http://www.postgresql.org/docs/current/static/datatype-binary.html
return "E'\\\\x" + hex+ "'";
return "E'\\\\x" + hex+ "'"
}
return "X'" + hex+ "'";
};
return "X'" + hex+ "'"
}
SqlString.objectToValues = function(object, timeZone) {
var values = [];
var values = []
for (var key in object) {
var value = object[key];
var value = object[key]
if(typeof value === 'function') {
continue;
}
values.push(this.escapeId(key) + ' = ' + SqlString.escape(value, true, timeZone));
values.push(this.escapeId(key) + ' = ' + SqlString.escape(value, true, timeZone))
}
return values.join(', ');
};
return values.join(', ')
}
function zeroPad(number) {
return (number < 10) ? '0' + number : number;
return (number < 10) ? '0' + number : number
}
function convertTimezone(tz) {
if (tz == "Z") return 0;
if (tz == "Z") {
return 0
}
var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/)
if (m) {
return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60
}
return false;
return false
}
......@@ -17,6 +17,7 @@ if (dialect.match(/^postgres/)) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
numbers: {type: DataTypes.ARRAY(DataTypes.FLOAT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
})
this.User.sync({ force: true }).success(function() {
......@@ -361,6 +362,9 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', {data: new Buffer('Sequelize') }],
expectation: "INSERT INTO \"myTable\" (\"data\") VALUES (E'\\\\x53657175656c697a65') RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', numbers: new Uint8Array([1,2,3])}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"numbers\") VALUES ('foo',ARRAY[1,2,3]) RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', foo: 1}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1) RETURNING *;"
}, {
......@@ -403,6 +407,10 @@ if (dialect.match(/^postgres/)) {
expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', numbers: new Uint8Array([1,2,3])}],
expectation: "INSERT INTO myTable (name,numbers) VALUES ('foo',ARRAY[1,2,3]) RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', foo: 1}],
expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1) RETURNING *;",
context: {options: {quoteIdentifiers: false}}
......@@ -536,6 +544,9 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', {bar: 2}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *"
}, {
arguments: ['myTable', {numbers: new Uint8Array([1,2,3])}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"numbers\"=ARRAY[1,2,3] WHERE \"name\"='foo' RETURNING *"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"name\"='foo'';DROP TABLE myTable;' WHERE \"name\"='foo' RETURNING *"
}, {
......@@ -575,6 +586,10 @@ if (dialect.match(/^postgres/)) {
expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {numbers: new Uint8Array([1,2,3])}, {name: 'foo'}],
expectation: "UPDATE myTable SET numbers=ARRAY[1,2,3] WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}],
expectation: "UPDATE myTable SET name='foo'';DROP TABLE myTable;' WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!