Skip to content
This repository has been archived by the owner on Aug 13, 2021. It is now read-only.

Add support for ANSI_QUOTES #107

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 16 additions & 13 deletions sequel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ var Sequel = module.exports = function(schema, options) {
// should use lower or regex logic for querying.
this.caseSensitive = options && utils.object.hasOwnProperty(options, 'caseSensitive') ? options.caseSensitive : true;

// Set the escape character, default is "
this.escapeCharacter = options && utils.object.hasOwnProperty(options, 'escapeCharacter') ? options.escapeCharacter : '"';
// Set the identifier character, default is `
this.identifierCharacter = options && utils.object.hasOwnProperty(options, 'identifierCharacter') ? options.identifierCharacter : '`';

// Set the escape character, default is '
this.escapeCharacter = options && utils.object.hasOwnProperty(options, 'escapeCharacter') ? options.escapeCharacter : '\'';

// Set if the database can return values from things such as an insert
this.canReturnValues = options && utils.object.hasOwnProperty(options, 'canReturnValues') ? options.canReturnValues : false;
Expand All @@ -46,7 +49,7 @@ var Sequel = module.exports = function(schema, options) {
this.escapeInserts = options && utils.object.hasOwnProperty(options, 'escapeInserts') ? options.escapeInserts : false;

// Determine if aliased tablenames in DELETE queries need to be referenced before the FROM, e.g.
// DELETE `tableName` FROM `tableName` as `otherTableName` WHERE `otherTableName`.`foo` = "bar"
// DELETE `tableName` FROM `tableName` as `otherTableName` WHERE `otherTableName`.`foo` = 'bar'
// MySQL and Oracle require this, but it doesn't work in Postgresql.
this.declareDeleteAlias = options && utils.object.hasOwnProperty(options, 'declareDeleteAlias') ? options.declareDeleteAlias : true;

Expand Down Expand Up @@ -116,8 +119,8 @@ Sequel.prototype.find = function find(currentTable, queryObject) {
Sequel.prototype.count = function count(currentTable, queryObject) {

// Escape table name
var tableName = utils.escapeName(this.schema[currentTable].tableName, this.escapeCharacter, this.schemaName);
var alias = utils.escapeName(this.schema[currentTable].tableName, this.escapeCharacter);
var tableName = utils.escapeName(this.schema[currentTable].tableName, this.identifierCharacter, this.schemaName);
var alias = utils.escapeName(this.schema[currentTable].tableName, this.identifierCharacter);

// Step 1:
// Build out the Count statements
Expand Down Expand Up @@ -164,7 +167,7 @@ Sequel.prototype.create = function create(currentTable, data) {

var options = {
parameterized: this.parameterized,
escapeCharacter: this.escapeCharacter,
identifierCharacter: this.identifierCharacter,
escapeInserts: this.escapeInserts,
schemaName: this.schemaName
};
Expand All @@ -175,7 +178,7 @@ Sequel.prototype.create = function create(currentTable, data) {
var paramValues = attributes.params.join(', ');

// Build Query
var query = 'INSERT INTO ' + utils.escapeName(currentTable, this.escapeCharacter, this.schemaName) + ' (' + columnNames + ') values (' + paramValues + ')';
var query = 'INSERT INTO ' + utils.escapeName(currentTable, this.identifierCharacter, this.schemaName) + ' (' + columnNames + ') values (' + paramValues + ')';

if(this.canReturnValues) {
query += ' RETURNING *';
Expand All @@ -192,15 +195,15 @@ Sequel.prototype.update = function update(currentTable, queryObject, data) {

var options = {
parameterized: this.parameterized,
escapeCharacter: this.escapeCharacter,
identifierCharacter: this.identifierCharacter,
escapeInserts: this.escapeInserts,
schemaName: this.schemaName
};

// Get the attribute identity (as opposed to the table name)
var identity = currentTable;
// Create the query with the tablename aliased as the identity (in case they are different)
var query = 'UPDATE ' + utils.escapeName(currentTable, this.escapeCharacter, this.schemaName) + ' AS ' + utils.escapeName(identity, this.escapeCharacter) + ' ';
var query = 'UPDATE ' + utils.escapeName(currentTable, this.identifierCharacter, this.schemaName) + ' AS ' + utils.escapeName(identity, this.identifierCharacter) + ' ';

// Transform the Data object into arrays used in a parameterized query
var attributes = utils.mapAttributes(data, options);
Expand Down Expand Up @@ -248,7 +251,7 @@ Sequel.prototype.destroy = function destroy(currentTable, queryObject) {
// Get the attribute identity (as opposed to the table name)
var identity = currentTable;

var query = 'DELETE ' + (this.declareDeleteAlias ? utils.escapeName(identity, this.escapeCharacter) : '') + ' FROM ' + utils.escapeName(currentTable, this.escapeCharacter, this.schemaName) + ' AS ' + utils.escapeName(identity, this.escapeCharacter) + ' ';
var query = 'DELETE ' + (this.declareDeleteAlias ? utils.escapeName(identity, this.identifierCharacter) : '') + ' FROM ' + utils.escapeName(currentTable, this.identifierCharacter, this.schemaName) + ' AS ' + utils.escapeName(identity, this.identifierCharacter) + ' ';

// Build Criteria clause
var whereObject = this.simpleWhere(currentTable, queryObject);
Expand All @@ -273,7 +276,7 @@ Sequel.prototype.destroy = function destroy(currentTable, queryObject) {

Sequel.prototype.select = function select(currentTable, queryObject) {
var options = {
escapeCharacter: this.escapeCharacter,
identifierCharacter: this.identifierCharacter,
caseSensitive: this.caseSensitive,
cast: this.cast,
wlNext: this.wlNext,
Expand All @@ -291,7 +294,7 @@ Sequel.prototype.simpleWhere = function simpleWhere(currentTable, queryObject, o
var _options = {
parameterized: this.parameterized,
caseSensitive: this.caseSensitive,
escapeCharacter: this.escapeCharacter,
identifierCharacter: this.identifierCharacter,
wlNext: this.wlNext,
schemaName: this.schemaName
};
Expand All @@ -304,7 +307,7 @@ Sequel.prototype.complexWhere = function complexWhere(currentTable, queryObject,
var _options = {
parameterized: this.parameterized,
caseSensitive: this.caseSensitive,
escapeCharacter: this.escapeCharacter,
identifierCharacter: this.identifierCharacter,
schemaName: this.schemaName
};

Expand Down
6 changes: 3 additions & 3 deletions sequel/lib/cast.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Cast special values to proper types.
*
* Ex: Array is stored as "[0,1,2,3]" and should be cast to proper
* Ex: Array is stored as '[0,1,2,3]' and should be cast to proper
* array for return values.
*/

Expand All @@ -27,7 +27,7 @@ Query.prototype.cast = function(values) {

Query.prototype.castValue = function(key, value, attributes, schema, joinKey) {

// Check if key is a special "join" key, identified with a '__' split
// Check if key is a special 'join' key, identified with a '__' split
var attr = key.split('__');
if(attr.length === 2) {

Expand All @@ -38,7 +38,7 @@ Query.prototype.castValue = function(key, value, attributes, schema, joinKey) {
}
}

// Lookup Schema "Type"
// Lookup Schema 'Type'
if(!schema[key]) return;
var type = schema[key].type;
if(!type) return;
Expand Down
52 changes: 29 additions & 23 deletions sequel/lib/criteriaProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ var CriteriaProcessor = module.exports = function CriteriaProcessor(currentTable
this.paramCount = 1;
this.parameterized = true;
this.caseSensitive = true;
this.escapeCharacter = '"';
this.identifierCharacter = '`';
this.escapeCharacter = '\'';
this.wlNext = {};

if(options && utils.object.hasOwnProperty(options, 'parameterized')) {
Expand All @@ -54,8 +55,8 @@ var CriteriaProcessor = module.exports = function CriteriaProcessor(currentTable
this.caseSensitive = options.caseSensitive;
}

if(options && utils.object.hasOwnProperty(options, 'escapeCharacter')) {
this.escapeCharacter = options.escapeCharacter;
if(options && utils.object.hasOwnProperty(options, 'identifierCharacter')) {
this.identifierCharacter = options.identifierCharacter;
}

if(options && utils.object.hasOwnProperty(options, 'paramCount')) {
Expand Down Expand Up @@ -325,13 +326,13 @@ CriteriaProcessor.prototype._in = function _in(key, val) {
// Check case sensitivity to decide if LOWER logic is used
if(!caseSensitivity) {
if(lower) {
key = 'LOWER(' + utils.escapeName(self.getTableAlias(), self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter) + ')';
key = 'LOWER(' + utils.escapeName(self.getTableAlias(), self.identifierCharacter, self.schemaName) + '.' + utils.escapeName(key, self.identifierCharacter) + ')';
} else {
key = utils.escapeName(self.getTableAlias(), self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter);
key = utils.escapeName(self.getTableAlias(), self.identifierCharacter, self.schemaName) + '.' + utils.escapeName(key, self.identifierCharacter);
}
self.queryString += key + ' IN (';
} else {
self.queryString += utils.escapeName(self.getTableAlias(), self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter) + ' IN (';
self.queryString += utils.escapeName(self.getTableAlias(), self.identifierCharacter, self.schemaName) + '.' + utils.escapeName(key, self.identifierCharacter) + ' IN (';
}

// Append each value to query
Expand All @@ -349,7 +350,7 @@ CriteriaProcessor.prototype._in = function _in(key, val) {
}
else {
if(_.isString(value)) {
value = '"' + utils.escapeString(value) + '"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);
}

self.queryString += value + ',';
Expand Down Expand Up @@ -377,7 +378,7 @@ CriteriaProcessor.prototype.buildParam = function buildParam (tableName, propert
var escape = utils.escapeName,
param;

param = escape(tableName, this.escapeCharacter, this.schemaName) + '.' + escape(property, this.escapeCharacter);
param = escape(tableName, this.identifierCharacter, this.schemaName) + '.' + escape(property, this.identifierCharacter);

if (caseSensitive) {
param = 'LOWER(' + param + ')';
Expand Down Expand Up @@ -483,7 +484,7 @@ CriteriaProcessor.prototype.processSimple = function processSimple (tableName, p
}

if (_.isString(value)) {
value = '"' + utils.escapeString(value) +'"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);
}

this.queryString += parent + ' ' + combinator + ' ' + value;
Expand Down Expand Up @@ -511,7 +512,7 @@ CriteriaProcessor.prototype.processObject = function processObject (tableName, p
// Expand criteria object
function expandCriteria (obj) {
var child = self.findChild(parent),
sensitiveTypes = ['text', 'string'], // haha, "sensitive types". "I'll watch 'the notebook' with you, babe."
sensitiveTypes = ['text', 'string'], // haha, 'sensitive types'. 'I'll watch \'the notebook\' with you, babe.'
lower;

_.keys(obj).forEach(function(key) {
Expand Down Expand Up @@ -606,7 +607,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
('00' + value.getMinutes()).slice(-2) + ':' +
('00' + value.getSeconds()).slice(-2);

value = '"' + value + '"';
value = utils.wrapValue(value, self.escapeCharacter);
escapedDate = true;
}

Expand All @@ -621,7 +622,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
}
else {
if(_.isString(value) && !escapedDate) {
value = '"' + utils.escapeString(value) + '"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);
}
str = '< ' + value;
}
Expand All @@ -637,7 +638,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
}
else {
if(_.isString(value) && !escapedDate) {
value = '"' + utils.escapeString(value) + '"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);
}
str = '<= ' + value;
}
Expand All @@ -653,7 +654,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
}
else {
if(_.isString(value) && !escapedDate) {
value = '"' + utils.escapeString(value) + '"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);
}
str = '> ' + value;
}
Expand All @@ -669,7 +670,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
}
else {
if(_.isString(value) && !escapedDate) {
value = '"' + utils.escapeString(value) + '"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);;
}
str = '>= ' + value;
}
Expand Down Expand Up @@ -706,7 +707,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
value.forEach(function(val) {

if(_.isString(val)) {
val = '"' + utils.escapeString(val) + '"';
val = utils.wrapValue(utils.escapeString(val), self.escapeCharacter);
}

str += val + ',';
Expand All @@ -724,7 +725,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
}
else {
if(_.isString(value)) {
value = '"' + utils.escapeString(value) + '"';
value = utils.wrapValue(utils.escapeString(value), self.escapeCharacter);;
}

str = '<> ' + value;
Expand Down Expand Up @@ -754,7 +755,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
}
else {
// Note that wildcards are not escaped out of like criterion intentionally
str = comparator + ' "' + utils.escapeString(value) + '"';
str = comparator + ' ' + utils.wrapValue(utils.escapeString(value), self.escapeCharacter);
}

break;
Expand All @@ -778,7 +779,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
str = comparator + ' ' + '$' + this.paramCount;
}
else {
str = comparator + ' "%' + utils.escapeString(value, true) + '%"';
str = comparator + ' ' + utils.wrapValue('%' + utils.escapeString(value, true) + '%', self.escapeCharacter);
}

break;
Expand All @@ -802,7 +803,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
str = comparator + ' ' + '$' + this.paramCount;
}
else {
str = comparator + ' "' + utils.escapeString(value, true) + '%"';
str = comparator + ' ' + utils.wrapValue(utils.escapeString(value, true) + '%', self.escapeCharacter);
}

break;
Expand All @@ -826,10 +827,15 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va
str = comparator + ' ' + '$' + this.paramCount;
}
else {
str = comparator + ' "%' + utils.escapeString(value, true) + '"';
str = comparator + ' ' + utils.wrapValue('%' + utils.escapeString(value, true), self.escapeCharacter);
}

break;

default:
var err = new Error('Unknown filtering operator: \'' + key + '\'. Should be \'startsWith\', \'>\', \'contains\' or similar');
err.operator = key;
throw err;
}

// Bump paramCount
Expand Down Expand Up @@ -877,7 +883,7 @@ CriteriaProcessor.prototype.sort = function(options) {

keys.forEach(function(key) {
var direction = options[key] === 1 ? 'ASC' : 'DESC';
self.queryString += utils.escapeName(self.currentTable, self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter) + ' ' + direction + ', ';
self.queryString += utils.escapeName(self.currentTable, self.identifierCharacter, self.schemaName) + '.' + utils.escapeName(key, self.identifierCharacter) + ' ' + direction + ', ';
});

// Remove trailing comma
Expand All @@ -899,7 +905,7 @@ CriteriaProcessor.prototype.group = function(options) {
options.forEach(function(key) {
// Check whether we are grouping by a column or an expression.
if (_.includes(_.keys(self.currentSchema), key)) {
self.queryString += utils.escapeName(self.currentTable, self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter) + ', ';
self.queryString += utils.escapeName(self.currentTable, self.identifierCharacter, self.schemaName) + '.' + utils.escapeName(key, self.identifierCharacter) + ', ';
} else {
self.queryString += key + ', ';
}
Expand Down
Loading