You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
5.7 KiB
237 lines
5.7 KiB
var SqlString = exports; |
|
|
|
var ID_GLOBAL_REGEXP = /`/g; |
|
var QUAL_GLOBAL_REGEXP = /\./g; |
|
var CHARS_GLOBAL_REGEXP = /[\0\b\t\n\r\x1a\"\'\\]/g; // eslint-disable-line no-control-regex |
|
var CHARS_ESCAPE_MAP = { |
|
'\0' : '\\0', |
|
'\b' : '\\b', |
|
'\t' : '\\t', |
|
'\n' : '\\n', |
|
'\r' : '\\r', |
|
'\x1a' : '\\Z', |
|
'"' : '\\"', |
|
'\'' : '\\\'', |
|
'\\' : '\\\\' |
|
}; |
|
|
|
SqlString.escapeId = function escapeId(val, forbidQualified) { |
|
if (Array.isArray(val)) { |
|
var sql = ''; |
|
|
|
for (var i = 0; i < val.length; i++) { |
|
sql += (i === 0 ? '' : ', ') + SqlString.escapeId(val[i], forbidQualified); |
|
} |
|
|
|
return sql; |
|
} else if (forbidQualified) { |
|
return '`' + String(val).replace(ID_GLOBAL_REGEXP, '``') + '`'; |
|
} else { |
|
return '`' + String(val).replace(ID_GLOBAL_REGEXP, '``').replace(QUAL_GLOBAL_REGEXP, '`.`') + '`'; |
|
} |
|
}; |
|
|
|
SqlString.escape = function escape(val, stringifyObjects, timeZone) { |
|
if (val === undefined || val === null) { |
|
return 'NULL'; |
|
} |
|
|
|
switch (typeof val) { |
|
case 'boolean': return (val) ? 'true' : 'false'; |
|
case 'number': return val + ''; |
|
case 'object': |
|
if (val instanceof Date) { |
|
return SqlString.dateToString(val, timeZone || 'local'); |
|
} else if (Array.isArray(val)) { |
|
return SqlString.arrayToList(val, timeZone); |
|
} else if (Buffer.isBuffer(val)) { |
|
return SqlString.bufferToString(val); |
|
} else if (typeof val.toSqlString === 'function') { |
|
return String(val.toSqlString()); |
|
} else if (stringifyObjects) { |
|
return escapeString(val.toString()); |
|
} else { |
|
return SqlString.objectToValues(val, timeZone); |
|
} |
|
default: return escapeString(val); |
|
} |
|
}; |
|
|
|
SqlString.arrayToList = function arrayToList(array, timeZone) { |
|
var sql = ''; |
|
|
|
for (var i = 0; i < array.length; i++) { |
|
var val = array[i]; |
|
|
|
if (Array.isArray(val)) { |
|
sql += (i === 0 ? '' : ', ') + '(' + SqlString.arrayToList(val, timeZone) + ')'; |
|
} else { |
|
sql += (i === 0 ? '' : ', ') + SqlString.escape(val, true, timeZone); |
|
} |
|
} |
|
|
|
return sql; |
|
}; |
|
|
|
SqlString.format = function format(sql, values, stringifyObjects, timeZone) { |
|
if (values == null) { |
|
return sql; |
|
} |
|
|
|
if (!(values instanceof Array || Array.isArray(values))) { |
|
values = [values]; |
|
} |
|
|
|
var chunkIndex = 0; |
|
var placeholdersRegex = /\?+/g; |
|
var result = ''; |
|
var valuesIndex = 0; |
|
var match; |
|
|
|
while (valuesIndex < values.length && (match = placeholdersRegex.exec(sql))) { |
|
var len = match[0].length; |
|
|
|
if (len > 2) { |
|
continue; |
|
} |
|
|
|
var value = len === 2 |
|
? SqlString.escapeId(values[valuesIndex]) |
|
: SqlString.escape(values[valuesIndex], stringifyObjects, timeZone); |
|
|
|
result += sql.slice(chunkIndex, match.index) + value; |
|
chunkIndex = placeholdersRegex.lastIndex; |
|
valuesIndex++; |
|
} |
|
|
|
if (chunkIndex === 0) { |
|
// Nothing was replaced |
|
return sql; |
|
} |
|
|
|
if (chunkIndex < sql.length) { |
|
return result + sql.slice(chunkIndex); |
|
} |
|
|
|
return result; |
|
}; |
|
|
|
SqlString.dateToString = function dateToString(date, timeZone) { |
|
var dt = new Date(date); |
|
|
|
if (isNaN(dt.getTime())) { |
|
return 'NULL'; |
|
} |
|
|
|
var year; |
|
var month; |
|
var day; |
|
var hour; |
|
var minute; |
|
var second; |
|
var millisecond; |
|
|
|
if (timeZone === 'local') { |
|
year = dt.getFullYear(); |
|
month = dt.getMonth() + 1; |
|
day = dt.getDate(); |
|
hour = dt.getHours(); |
|
minute = dt.getMinutes(); |
|
second = dt.getSeconds(); |
|
millisecond = dt.getMilliseconds(); |
|
} else { |
|
var tz = convertTimezone(timeZone); |
|
|
|
if (tz !== false && tz !== 0) { |
|
dt.setTime(dt.getTime() + (tz * 60000)); |
|
} |
|
|
|
year = dt.getUTCFullYear(); |
|
month = dt.getUTCMonth() + 1; |
|
day = dt.getUTCDate(); |
|
hour = dt.getUTCHours(); |
|
minute = dt.getUTCMinutes(); |
|
second = dt.getUTCSeconds(); |
|
millisecond = dt.getUTCMilliseconds(); |
|
} |
|
|
|
// YYYY-MM-DD HH:mm:ss.mmm |
|
var str = zeroPad(year, 4) + '-' + zeroPad(month, 2) + '-' + zeroPad(day, 2) + ' ' + |
|
zeroPad(hour, 2) + ':' + zeroPad(minute, 2) + ':' + zeroPad(second, 2) + '.' + |
|
zeroPad(millisecond, 3); |
|
|
|
return escapeString(str); |
|
}; |
|
|
|
SqlString.bufferToString = function bufferToString(buffer) { |
|
return 'X' + escapeString(buffer.toString('hex')); |
|
}; |
|
|
|
SqlString.objectToValues = function objectToValues(object, timeZone) { |
|
var sql = ''; |
|
|
|
for (var key in object) { |
|
var val = object[key]; |
|
|
|
if (typeof val === 'function') { |
|
continue; |
|
} |
|
|
|
sql += (sql.length === 0 ? '' : ', ') + SqlString.escapeId(key) + ' = ' + SqlString.escape(val, true, timeZone); |
|
} |
|
|
|
return sql; |
|
}; |
|
|
|
SqlString.raw = function raw(sql) { |
|
if (typeof sql !== 'string') { |
|
throw new TypeError('argument sql must be a string'); |
|
} |
|
|
|
return { |
|
toSqlString: function toSqlString() { return sql; } |
|
}; |
|
}; |
|
|
|
function escapeString(val) { |
|
var chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex = 0; |
|
var escapedVal = ''; |
|
var match; |
|
|
|
while ((match = CHARS_GLOBAL_REGEXP.exec(val))) { |
|
escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]]; |
|
chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex; |
|
} |
|
|
|
if (chunkIndex === 0) { |
|
// Nothing was escaped |
|
return "'" + val + "'"; |
|
} |
|
|
|
if (chunkIndex < val.length) { |
|
return "'" + escapedVal + val.slice(chunkIndex) + "'"; |
|
} |
|
|
|
return "'" + escapedVal + "'"; |
|
} |
|
|
|
function zeroPad(number, length) { |
|
number = number.toString(); |
|
while (number.length < length) { |
|
number = '0' + number; |
|
} |
|
|
|
return number; |
|
} |
|
|
|
function convertTimezone(tz) { |
|
if (tz === 'Z') { |
|
return 0; |
|
} |
|
|
|
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 false; |
|
}
|
|
|