Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Added alternate query handler hooks for TDS---mostly pertaining to LI…
…MIT and OFFSET.
  • Loading branch information
rdhammond committed Aug 9, 2013
commit 19b86bd564f100506774d7d8dc817dde64e5ae2f
2 changes: 2 additions & 0 deletions lib/Dialects/mysql.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var util = require("util");

exports.name = 'mysql';

exports.escapeId = function () {
return Array.prototype.slice.apply(arguments).map(function (el) {
if (typeof el == "object") {
Expand Down
2 changes: 2 additions & 0 deletions lib/Dialects/postgresql.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var util = require("util");

exports.name = 'postgresql';

exports.escapeId = function () {
return Array.prototype.slice.apply(arguments).map(function (el) {
if (typeof el == "object") {
Expand Down
1 change: 1 addition & 0 deletions lib/Dialects/sqlite.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var util = require("util");

exports.name = 'sqlite';
exports.escapeId = require("./mysql").escapeId;

exports.escapeVal = function (val, timeZone) {
Expand Down
2 changes: 2 additions & 0 deletions lib/Dialects/tds.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
var util = require("util");

exports.name = 'tds';

exports.escapeId = function () {
return Array.prototype.slice.apply(arguments).map(function (el) {
if (typeof el == "object") {
Expand Down
31 changes: 21 additions & 10 deletions lib/Remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ exports.RemoveQuery = RemoveQuery;
function RemoveQuery(Dialect) {
var sql = {
where : [],
order : []
order : [],
use_top: (Dialect.name === 'tds'),
can_use_order_by: (Dialect.name !== 'tds')
};

return {
Expand All @@ -25,7 +27,14 @@ function RemoveQuery(Dialect) {
build: function () {
var query = [], tmp;

query.push("DELETE FROM");
query.push("DELETE");

// TDS only!
if (sql.use_top && sql.hasOwnProperty("limit")) {
query.push("TOP (" + sql.limit + ")");
}

query.push("FROM");
query.push(Dialect.escapeId(sql.table));

query = query.concat(Where.build(Dialect, sql.where));
Expand All @@ -41,20 +50,22 @@ function RemoveQuery(Dialect) {
}
}

if (tmp.length > 0) {
if (tmp.length > 0 && sql.can_use_order_by) {
query.push("ORDER BY " + tmp.join(", "));
}
}

// limit
if (sql.hasOwnProperty("limit")) {
if (sql.hasOwnProperty("offset")) {
query.push("LIMIT " + sql.limit + " OFFSET " + sql.offset);
} else {
query.push("LIMIT " + sql.limit);
if (!sql.use_top) {
if (sql.hasOwnProperty("limit")) {
if (sql.hasOwnProperty("offset")) {
query.push("LIMIT " + sql.limit + " OFFSET " + sql.offset);
} else {
query.push("LIMIT " + sql.limit);
}
} else if (sql.hasOwnProperty("offset")) {
query.push("OFFSET " + sql.offset);
}
} else if (sql.hasOwnProperty("offset")) {
query.push("OFFSET " + sql.offset);
}

return query.join(" ");
Expand Down
93 changes: 71 additions & 22 deletions lib/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ function SelectQuery(Dialect) {
order : [],
group_by : null,
found_rows : false,
where_exists : false
where_exists : false,
use_top : (Dialect.name === 'tds'),
manual_offset : (Dialect.name === 'tds')
};
var get_table_alias = function (table) {
for (var i = 0; i < sql.from.length; i++) {
Expand Down Expand Up @@ -194,8 +196,44 @@ function SelectQuery(Dialect) {
this.fun(fun_stack.pop());
}

// Calculate ORDER BY early, in case we need it for
// manual offset.
//
if (sql.group_by) {
sql.group_by.forEach(function (column) {
if (column[0] == "-") {
sql.order.unshift({ c: column.substr(1), d: "DESC" });
}
});
}

order_by = [];

if (sql.order.length > 0) {
for (i = 0; i < sql.order.length; i++) {
if (Array.isArray(sql.order[i].c)) {
order_by.push(Dialect.escapeId.apply(Dialect, sql.order[i].c) + " " + sql.order[i].d);
} else {
order_by.push(Dialect.escapeId(sql.order[i].c) + " " + sql.order[i].d);
}
}
}

// TDS only - Manual Offset Workaround
if (sql.manual_offset && sql.hasOwnProperty("offset")) {
if (sql.use_top && sql.hasOwnProperty("limit"))
query.push("SELECT TOP " + sql.limit + " * FROM (");
else
query.push("SELECT * FROM (");
}

query.push("SELECT");

// TDS only - TOP instead of LIMIT
if (sql.use_top && sql.hasOwnProperty("limit") && !sql.hasOwnProperty("offset")) {
query.push("TOP " + sql.limit);
}

for (i = 0; i < sql.from.length; i++) {
sql.from[i].a = "t" + (i + 1);
}
Expand Down Expand Up @@ -288,8 +326,23 @@ function SelectQuery(Dialect) {
query.push("SQL_CALC_FOUND_ROWS");
}

// Need to allow for TDS' manual offset, if necessary. Otherwise,
// we can just proceed with an unaltered SELECT stanza.
//
var row_number_clause;

if (sql.manual_offset && sql.hasOwnProperty('offset')) {
row_number_clause = order_by.length > 0 ? order_by.join(", ") : "id ASC";
}

if (tmp.length) {
if (sql.manual_offset && sql.hasOwnProperty('offset')) {
tmp.unshift("ROW_NUMBER() OVER (ORDER BY " + row_number_clause + ") AS p_RN")
}

query.push(tmp.join(", "));
} else if (sql.manual_offset && sql.hasOwnProperty('offset')) {
query.push("ROW_NUMBER() OVER (ORDER BY " + row_number_clause + ") AS p_RN, *");
} else {
query.push("*");
}
Expand Down Expand Up @@ -349,31 +402,27 @@ function SelectQuery(Dialect) {
}).join(", "));
}

// order
if (sql.order.length > 0) {
tmp = [];
for (i = 0; i < sql.order.length; i++) {
if (Array.isArray(sql.order[i].c)) {
tmp.push(Dialect.escapeId.apply(Dialect, sql.order[i].c) + " " + sql.order[i].d);
} else {
tmp.push(Dialect.escapeId(sql.order[i].c) + " " + sql.order[i].d);
}
}
// TDS only - Manual Offset Workaround
if (sql.manual_offset && sql.hasOwnProperty("offset")) {
query.push(") SQ WHERE p_RN > " + sql.offset);
}

if (tmp.length > 0) {
query.push("ORDER BY " + tmp.join(", "));
}
// order
if (order_by.length > 0) {
query.push("ORDER BY " + order_by.join(", "));
}

// limit
if (sql.hasOwnProperty("limit")) {
if (sql.hasOwnProperty("offset")) {
query.push("LIMIT " + sql.limit + " OFFSET " + sql.offset);
} else {
query.push("LIMIT " + sql.limit);
// limit (non-TDS only!)
if (!sql.use_top) {
if (sql.hasOwnProperty("limit")) {
if (!sql.manual_offset && sql.hasOwnProperty("offset")) {
query.push("LIMIT " + sql.limit + " OFFSET " + sql.offset);
} else {
query.push("LIMIT " + sql.limit);
}
} else if (!sql.manual_offset && sql.hasOwnProperty("offset")) {
query.push("OFFSET " + sql.offset);
}
} else if (sql.hasOwnProperty("offset")) {
query.push("OFFSET " + sql.offset);
}

return query.join(" ");
Expand Down
6 changes: 5 additions & 1 deletion lib/Where.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,11 @@ function buildOrGroup(Dialect, where) {
if (Array.isArray(where.w[k])) {
if (where.w[k].length === 0) {
// #274: IN with empty arrays should be a false sentence
query.push("FALSE");
//
// "1=0" will still evaluate to false and plays nice with
// TDS.
//
query.push("1=0");
} else {
query.push(buildComparisonKey(Dialect, where.t, k) + " IN " + Dialect.escapeVal(where.w[k]));
}
Expand Down
16 changes: 8 additions & 8 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ var Query = require('../');
common.Query = Query;
common.Text = Query.Text;

common.Select = function () {
var q = new (Query.Query)();
common.Select = function (dialect) {
var q = new (Query.Query)(dialect);

return q.select();
};

common.Insert = function () {
var q = new (Query.Query)();
common.Insert = function (dialect) {
var q = new (Query.Query)(dialect);

return q.insert();
};

common.Update = function () {
var q = new (Query.Query)();
common.Update = function (dialect) {
var q = new (Query.Query)(dialect);

return q.update();
};

common.Remove = function () {
var q = new (Query.Query)();
common.Remove = function (dialect) {
var q = new (Query.Query)(dialect);

return q.remove();
};
Expand Down
7 changes: 7 additions & 0 deletions test/integration/test-limit-offset-tds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var common = require('../common');
var assert = require('assert');

assert.equal(
common.Select('tds').from('table1').offset('123').limit('456').build(),
"SELECT TOP 456 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id ASC) AS p_RN, * FROM [table1] ) SQ WHERE p_RN > 123"
);
10 changes: 10 additions & 0 deletions test/integration/test-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ assert.equal(
"SELECT * FROM `table1` LIMIT 123"
);

assert.equal(
common.Select('tds').from('table1').limit(123).build(),
"SELECT TOP 123 * FROM [table1]"
);

assert.equal(
common.Select().from('table1').limit('123456789').build(),
"SELECT * FROM `table1` LIMIT 123456789"
);

assert.equal(
common.Select('tds').from('table1').limit('123456789').build(),
"SELECT TOP 123456789 * FROM [table1]"
);
10 changes: 10 additions & 0 deletions test/integration/test-offset.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ assert.equal(
"SELECT * FROM `table1` OFFSET 3"
);

assert.equal(
common.Select('tds').from('table1').offset(3).build(),
"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id ASC) AS p_RN, * FROM [table1] ) SQ WHERE p_RN > 3"
);

assert.equal(
common.Select().from('table1').offset('123456789').build(),
"SELECT * FROM `table1` OFFSET 123456789"
);

assert.equal(
common.Select('tds').from('table1').offset('123456789').build(),
"SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id ASC) AS p_RN, * FROM [table1] ) SQ WHERE p_RN > 123456789"
);
20 changes: 20 additions & 0 deletions test/integration/test-remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,37 @@ assert.equal(
"DELETE FROM `table1` LIMIT 10"
);

assert.equal(
common.Remove('tds').from('table1').limit(10).build(),
"DELETE TOP (10) FROM [table1]"
);

assert.equal(
common.Remove().from('table1').limit(10).offset(3).build(),
"DELETE FROM `table1` LIMIT 10 OFFSET 3"
);

assert.equal(
common.Remove('tds').from('table1').limit(10).offset(3).build(),
"DELETE TOP (10) FROM [table1]"
);

assert.equal(
common.Remove().from('table1').order('col').limit(5).build(),
"DELETE FROM `table1` ORDER BY `col` ASC LIMIT 5"
);

assert.equal(
common.Remove('tds').from('table1').order('col').limit(5).build(),
"DELETE TOP (5) FROM [table1]"
);

assert.equal(
common.Remove().from('table1').order('col1', 'A').order('col2', 'Z').limit(5).build(),
"DELETE FROM `table1` ORDER BY `col1` ASC, `col2` DESC LIMIT 5"
);

assert.equal(
common.Remove('tds').from('table1').order('col1', 'A').order('col2', 'Z').limit(5).build(),
"DELETE TOP (5) FROM [table1]"
);
2 changes: 1 addition & 1 deletion test/integration/test-where.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ assert.equal(

assert.equal(
common.Select().from('table1').where({ col: [] }).build(),
"SELECT * FROM `table1` WHERE FALSE"
"SELECT * FROM `table1` WHERE 1=0"
);

assert.equal(
Expand Down