From f97dae0bb201644d661d554e42be7279fe1b46cd Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 2 May 2013 22:47:42 +0100 Subject: [PATCH 001/106] 0.0.22 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0b2d2d..218327a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.21", + "version": "0.0.22", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From be9c629301e560d4ebdea01acc2a506ff28c8ba4 Mon Sep 17 00:00:00 2001 From: DavidKosub Date: Fri, 17 May 2013 16:45:38 -0500 Subject: [PATCH 002/106] Fix case where falsy columns can equal zero --- lib/Where.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Where.js b/lib/Where.js index 85418c0..1bab111 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -37,7 +37,7 @@ function buildOrGroup(Dialect, where) { var query = [], op; for (var k in where.w) { - if (!where.w[k]) { + if (!where.w[k] && where.w[k] !== 0) { query.push( buildComparisonKey(Dialect, where.t, k) + " IS NULL" From 2e4b1e5bd4c480597af81e6c26a27bf1b533bc7f Mon Sep 17 00:00:00 2001 From: DavidKosub Date: Fri, 17 May 2013 16:55:24 -0500 Subject: [PATCH 003/106] Test for zero case --- test/integration/test-where.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/integration/test-where.js b/test/integration/test-where.js index a4befb4..3bbdb8e 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -16,6 +16,11 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` = 1" ); +assert.equal( + common.Select().from('table1').where({ col: 0 }).build(), + "SELECT * FROM `table1` WHERE `col` = 0" +); + assert.equal( common.Select().from('table1').where({ col: 'a' }).build(), "SELECT * FROM `table1` WHERE `col` = 'a'" From 0a9c94ad77bb0862f9117d18908c2c595f398352 Mon Sep 17 00:00:00 2001 From: DavidKosub Date: Tue, 21 May 2013 09:53:31 -0500 Subject: [PATCH 004/106] Handle more falsy cases, add more tests --- lib/Where.js | 2 +- test/integration/test-where.js | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/Where.js b/lib/Where.js index 1bab111..5ee076c 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -37,7 +37,7 @@ function buildOrGroup(Dialect, where) { var query = [], op; for (var k in where.w) { - if (!where.w[k] && where.w[k] !== 0) { + if (where.w[k] === null || where.w[k] === undefined) { query.push( buildComparisonKey(Dialect, where.t, k) + " IS NULL" diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 3bbdb8e..8501f42 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -21,6 +21,26 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` = 0" ); +assert.equal( + common.Select().from('table1').where({ col: null }).build(), + "SELECT * FROM `table1` WHERE `col` IS NULL" +); + +assert.equal( + common.Select().from('table1').where({ col: undefined }).build(), + "SELECT * FROM `table1` WHERE `col` IS NULL" +); + +assert.equal( + common.Select().from('table1').where({ col: false }).build(), + "SELECT * FROM `table1` WHERE `col` = false" +); + +assert.equal( + common.Select().from('table1').where({ col: true }).build(), + "SELECT * FROM `table1` WHERE `col` = true" +); + assert.equal( common.Select().from('table1').where({ col: 'a' }).build(), "SELECT * FROM `table1` WHERE `col` = 'a'" From 3e9adc2c843f82567016f70718bdd81957ea3fd1 Mon Sep 17 00:00:00 2001 From: DavidKosub Date: Tue, 21 May 2013 09:58:35 -0500 Subject: [PATCH 005/106] Empty string test case --- test/integration/test-where.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 8501f42..5638c01 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -36,6 +36,11 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` = false" ); +assert.equal( + common.Select().from('table1').where({ col: "" }).build(), + "SELECT * FROM `table1` WHERE `col` = ''" +); + assert.equal( common.Select().from('table1').where({ col: true }).build(), "SELECT * FROM `table1` WHERE `col` = true" From cea38481f14e87bedd354203f4df605a94d90fee Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 27 May 2013 23:05:13 +0100 Subject: [PATCH 006/106] Fixes postgres Date escaping (closes #5) --- lib/Dialects/postgresql.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 612f816..3e4b27c 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -1,3 +1,5 @@ +var util = require("util"); + exports.escapeId = function () { return Array.prototype.slice.apply(arguments).map(function (el) { if (typeof el == "object") { @@ -24,6 +26,9 @@ exports.escapeVal = function (val, timeZone) { } return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; } + if (util.isDate(val)) { + return "'" + JSON.stringify(val).substr(1, 24) + "'"; + } switch (typeof val) { case "number": return val; From 3bd85a6a893239582e40421ed008a7433964a5f6 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 27 May 2013 23:05:29 +0100 Subject: [PATCH 007/106] 0.0.23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 218327a..db38216 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.22", + "version": "0.0.23", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From d205942b654764b1c8dca0b6b041a7e31f03afb5 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 27 May 2013 23:49:57 +0100 Subject: [PATCH 008/106] Adds Select.calculateFoundRows() This is specific for MySQL and it adds SQL_CALC_FOUND_ROWS to queries. --- lib/Select.js | 23 +++++++++++++++++++---- test/integration/test-select.js | 10 ++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/Select.js b/lib/Select.js index b7a25de..bd9a59d 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -12,10 +12,11 @@ exports.SelectQuery = SelectQuery; function SelectQuery(Dialect) { var sql = { - from : [], - where : [], - order : [], - group_by : null + from : [], + where : [], + order : [], + group_by : null, + found_rows : false }; var get_table_alias = function (table) { for (var i = 0; i < sql.from.length; i++) { @@ -50,6 +51,11 @@ function SelectQuery(Dialect) { } return this; }, + calculateFoundRows: function () { + sql.found_rows = true; + + return this; + }, fun: function (fun, column, alias) { if (!Array.isArray(sql.from[sql.from.length - 1].select)) { sql.from[sql.from.length - 1].select = []; @@ -210,6 +216,15 @@ function SelectQuery(Dialect) { tmp.push(str); } } + + // MySQL specific! + if (sql.found_rows) { + tmp.unshift("SQL_CALC_FOUND_ROWS"); + if (tmp.length == 1) { + tmp.push("*"); + } + } + if (tmp.length) { query.push(tmp.join(", ")); } else { diff --git a/test/integration/test-select.js b/test/integration/test-select.js index 1e3010e..891bfff 100644 --- a/test/integration/test-select.js +++ b/test/integration/test-select.js @@ -21,6 +21,16 @@ assert.equal( "SELECT * FROM `table1`" ); +assert.equal( + common.Select().calculateFoundRows().from('table1').build(), + "SELECT SQL_CALC_FOUND_ROWS, * FROM `table1`" +); + +assert.equal( + common.Select().calculateFoundRows().from('table1').select('id').build(), + "SELECT SQL_CALC_FOUND_ROWS, `id` FROM `table1`" +); + assert.equal( common.Select().from('table1').select('id1', 'name') .from('table2', 'id2', 'id1').select('id2').build(), From d61e5ef37a39d16c36030437552d95152a49b36d Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 27 May 2013 23:50:06 +0100 Subject: [PATCH 009/106] 0.0.24 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index db38216..c0dad27 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.23", + "version": "0.0.24", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From b8fc6be4f3f518f2b4159809bd0e972ada3ae292 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 28 May 2013 00:33:00 +0100 Subject: [PATCH 010/106] Fixes previous commit on Select.calculateFoundRows() (#7) --- lib/Select.js | 5 +---- test/integration/test-select.js | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/Select.js b/lib/Select.js index bd9a59d..1c2e7c1 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -219,10 +219,7 @@ function SelectQuery(Dialect) { // MySQL specific! if (sql.found_rows) { - tmp.unshift("SQL_CALC_FOUND_ROWS"); - if (tmp.length == 1) { - tmp.push("*"); - } + query.push("SQL_CALC_FOUND_ROWS"); } if (tmp.length) { diff --git a/test/integration/test-select.js b/test/integration/test-select.js index 891bfff..5a9743c 100644 --- a/test/integration/test-select.js +++ b/test/integration/test-select.js @@ -23,12 +23,12 @@ assert.equal( assert.equal( common.Select().calculateFoundRows().from('table1').build(), - "SELECT SQL_CALC_FOUND_ROWS, * FROM `table1`" + "SELECT SQL_CALC_FOUND_ROWS * FROM `table1`" ); assert.equal( common.Select().calculateFoundRows().from('table1').select('id').build(), - "SELECT SQL_CALC_FOUND_ROWS, `id` FROM `table1`" + "SELECT SQL_CALC_FOUND_ROWS `id` FROM `table1`" ); assert.equal( From 5dfecf479d97f9a56ed6817b07f113cbe5fa65f9 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 28 May 2013 00:33:05 +0100 Subject: [PATCH 011/106] 0.0.25 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c0dad27..34856df 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.24", + "version": "0.0.25", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 265950fc000bfd256d273552e9ffabbc220e04a3 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 3 Jun 2013 12:11:18 +0100 Subject: [PATCH 012/106] Adds possibility for IS NOT NULL in where conditions (closes #8) --- lib/Where.js | 4 ++-- test/integration/test-where.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/Where.js b/lib/Where.js index 5ee076c..c534220 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -90,8 +90,8 @@ function buildOrGroup(Dialect, where) { case "lt": case "lte": switch (op) { - case "eq" : op = "="; break; - case "ne" : op = "<>"; break; + case "eq" : op = (where.w[k].val === null ? "IS" : "="); break; + case "ne" : op = (where.w[k].val === null ? "IS NOT" : "<>"); break; case "gt" : op = ">"; break; case "gte" : op = ">="; break; case "lt" : op = "<"; break; diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 5638c01..5c2ba3a 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -26,6 +26,16 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` IS NULL" ); +assert.equal( + common.Select().from('table1').where({ col: common.Query.eq(null) }).build(), + "SELECT * FROM `table1` WHERE `col` IS NULL" +); + +assert.equal( + common.Select().from('table1').where({ col: common.Query.ne(null) }).build(), + "SELECT * FROM `table1` WHERE `col` IS NOT NULL" +); + assert.equal( common.Select().from('table1').where({ col: undefined }).build(), "SELECT * FROM `table1` WHERE `col` IS NULL" From 23126369343a717dc8d0221c5f859067f9daf72b Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 3 Jun 2013 12:11:29 +0100 Subject: [PATCH 013/106] 0.0.26 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 34856df..7640c82 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.25", + "version": "0.0.26", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 761e04114000ec12d850bfd9a85b638f7b9e8393 Mon Sep 17 00:00:00 2001 From: Andrei K Date: Fri, 14 Jun 2013 23:33:34 +0400 Subject: [PATCH 014/106] Fixed sql query escapes enumeration --- lib/Where.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Where.js b/lib/Where.js index c534220..f125018 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -108,7 +108,7 @@ function buildOrGroup(Dialect, where) { var sql = where.w[k].where.str.replace("?:column", buildComparisonKey(Dialect, where.t, k)); sql = sql.replace(/\?:(id|value)/g, function (m) { - if (where.w[k].replace.length === 0) { + if (where.w[k].where.escapes.length === 0) { return ''; } From 8156f91814e9b5ed6668531646c05c70e47427d0 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sat, 15 Jun 2013 11:23:03 +0100 Subject: [PATCH 015/106] 0.0.27 --- .travis.yml | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2a9b9e6..d523c5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,4 @@ node_js: - 0.4 - 0.6 - 0.8 + - 0.10 diff --git a/package.json b/package.json index 7640c82..72ee001 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.26", + "version": "0.0.27", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 657a2a192ba68aab659157aa2fe38c1eb0c3037a Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 20 Jun 2013 16:39:22 +0100 Subject: [PATCH 016/106] Adds test.js file to .gitignore This allows to have a test file that changes to specific improvement we're testing without having to care about it.. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3f7cb55..01aa4f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.sublime-* .DS_Store node_modules +test.js From 9e3519579a18e6c227ba991900bd0db1a2459f14 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 20 Jun 2013 16:46:55 +0100 Subject: [PATCH 017/106] Adds Query.Text('text') to create an object that can be used in sql functions to indicate it's a text and not an identifier --- lib/Query.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/Query.js b/lib/Query.js index aedc753..46b28d5 100644 --- a/lib/Query.js +++ b/lib/Query.js @@ -6,6 +6,7 @@ var Comparators = require("./Comparators"); exports.Query = Query; exports.Comparators = Object.keys(Comparators); +exports.Text = buildQueryType("text"); for (var comparator in Comparators) { exports[comparator] = Comparators[comparator]; @@ -37,3 +38,18 @@ function Query(opts) { } }; } + +function buildQueryType(type) { + return function (data) { + var o = { data: data }; + + Object.defineProperty(o, "type", { + value: function () { + return type; + }, + enumerable: false + }); + + return o; + }; +} From 995ed1f6b89c610f67754cf5b83ef4fcc6f02929 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 20 Jun 2013 16:47:30 +0100 Subject: [PATCH 018/106] Adds support for Query.Text() to sql function calls (closes #10) --- lib/Select.js | 8 ++++++++ test/common.js | 1 + test/integration/test-select-type.js | 22 ++++++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 test/integration/test-select-type.js diff --git a/lib/Select.js b/lib/Select.js index 1c2e7c1..bacf6a5 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -192,6 +192,14 @@ function SelectQuery(Dialect) { if (Array.isArray(sql.from[i].select[j].c)) { str += sql.from[i].select[j].c.map(function (el) { + if (typeof el.type == "function") { + switch (el.type()) { + case "text": + return Dialect.escapeVal(el.data); + default: + return el; + } + } if (typeof el != "string") { return el; } diff --git a/test/common.js b/test/common.js index c958355..04a9ea6 100644 --- a/test/common.js +++ b/test/common.js @@ -2,6 +2,7 @@ var common = exports; var Query = require('../'); common.Query = Query; +common.Text = Query.Text; common.Select = function () { var q = new (Query.Query)(); diff --git a/test/integration/test-select-type.js b/test/integration/test-select-type.js new file mode 100644 index 0000000..60aa066 --- /dev/null +++ b/test/integration/test-select-type.js @@ -0,0 +1,22 @@ +var common = require('../common'); +var assert = require('assert'); + +assert.equal( + common.Select().from('table1').fun('myfun', 'col1').build(), + "SELECT MYFUN(`col1`) FROM `table1`" +); + +assert.equal( + common.Select().from('table1').fun('myfun', [ 'col1', 'col2']).build(), + "SELECT MYFUN(`col1`, `col2`) FROM `table1`" +); + +assert.equal( + common.Select().from('table1').fun('myfun', [ 'col1', 'col2'], 'alias').build(), + "SELECT MYFUN(`col1`, `col2`) AS `alias` FROM `table1`" +); + +assert.equal( + common.Select().from('table1').fun('myfun', [ 'col1', common.Text('col2') ], 'alias').build(), + "SELECT MYFUN(`col1`, 'col2') AS `alias` FROM `table1`" +); From bbf54a4cc2f7ed1ed1c7afe95a3834a955fb0b94 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 20 Jun 2013 16:47:40 +0100 Subject: [PATCH 019/106] 0.0.28 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 72ee001..9d2563b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.27", + "version": "0.0.28", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 39f2ca181c8bf14bb8449dff6dfea6ebeea82ca8 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 27 Jun 2013 19:11:15 +0100 Subject: [PATCH 020/106] Adds support for 'AS' column alias (#11) See updated test file for examples --- lib/Select.js | 39 +++++++++++++++++++++++++++++++-- test/integration/test-select.js | 15 +++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/Select.js b/lib/Select.js index bacf6a5..e461765 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -47,7 +47,14 @@ function SelectQuery(Dialect) { var proto = { select: function (fields) { if (fields) { - sql.from[sql.from.length - 1].select = (Array.isArray(fields) ? fields : Array.prototype.slice.apply(arguments)); + if (!sql.from[sql.from.length - 1].select) { + sql.from[sql.from.length - 1].select = []; + } + sql.from[sql.from.length - 1].select = sql.from[sql.from.length - 1].select.concat( + Array.isArray(fields) + ? fields + : Array.prototype.slice.apply(arguments) + ); } return this; }, @@ -56,6 +63,20 @@ function SelectQuery(Dialect) { return this; }, + as: function (alias) { + var idx = sql.from.length - 1; + + if (sql.from[idx].select.length) { + var idx2 = sql.from[idx].select.length - 1; + + if (typeof sql.from[idx].select[idx2] == "string") { + sql.from[idx].select[idx2] = { c: sql.from[idx].select[idx2] }; + } + sql.from[idx].select[sql.from[idx].select.length - 1].a = alias || null; + } + + return this; + }, fun: function (fun, column, alias) { if (!Array.isArray(sql.from[sql.from.length - 1].select)) { sql.from[sql.from.length - 1].select = []; @@ -164,9 +185,11 @@ function SelectQuery(Dialect) { for (i = 0; i < sql.from.length; i++) { if (!sql.from[i].select) continue; // if (typeof sql.from[i].select[0] != "object") continue; + // + console.log(sql.from[i].select); for (j = 0; j < sql.from[i].select.length; j++) { - if (typeof sql.from[i].select[j] == "string") { + if (typeof sql.from[i].select[j] == "string" ) { if (sql.from.length == 1) { tmp.push(Dialect.escapeId(sql.from[i].select[j])); } else { @@ -175,6 +198,16 @@ function SelectQuery(Dialect) { continue; } if (typeof sql.from[i].select[j] == "object") { + if (!sql.from[i].select[j].f && sql.from[i].select[j].c) { + if (sql.from.length == 1) { + tmp.push(Dialect.escapeId(sql.from[i].select[j].c)); + } else { + tmp.push(Dialect.escapeId(sql.from[i].a, sql.from[i].select[j].c)); + } + if (sql.from[i].select[j].a) { + tmp[tmp.length - 1] += " AS " + Dialect.escapeId(sql.from[i].select[j].a); + } + } if (sql.from[i].select[j].having) { having.push(Dialect.escapeId(sql.from[i].select[j].having)); } @@ -184,6 +217,8 @@ function SelectQuery(Dialect) { } } + if (!sql.from[i].select[j].f) continue; + str = sql.from[i].select[j].f + "("; if (sql.from[i].select[j].c && !Array.isArray(sql.from[i].select[j].c)) { diff --git a/test/integration/test-select.js b/test/integration/test-select.js index 5a9743c..ddfe32e 100644 --- a/test/integration/test-select.js +++ b/test/integration/test-select.js @@ -11,6 +11,21 @@ assert.equal( "SELECT `id`, `name` FROM `table1`" ); +assert.equal( + common.Select().from('table1').select('id', 'name').as('label').build(), + "SELECT `id`, `name` AS `label` FROM `table1`" +); + +assert.equal( + common.Select().from('table1').select('id', 'name').select('title').as('label').build(), + "SELECT `id`, `name`, `title` AS `label` FROM `table1`" +); + +assert.equal( + common.Select().from('table1').select('id', 'name').as('label').select('title').build(), + "SELECT `id`, `name` AS `label`, `title` FROM `table1`" +); + assert.equal( common.Select().from('table1').select([ 'id', 'name' ]).build(), "SELECT `id`, `name` FROM `table1`" From 70e87b922e83d08bb08616ffb0795a0851480975 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 27 Jun 2013 19:11:23 +0100 Subject: [PATCH 021/106] 0.0.29 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d2563b..c350644 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.28", + "version": "0.0.29", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From a70f3e0f9abdb5071f781b2f2341d1cdc143d14d Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 27 Jun 2013 19:20:59 +0100 Subject: [PATCH 022/106] Removes console.log from Select.js --- lib/Select.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Select.js b/lib/Select.js index e461765..56936cb 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -186,7 +186,6 @@ function SelectQuery(Dialect) { if (!sql.from[i].select) continue; // if (typeof sql.from[i].select[0] != "object") continue; // - console.log(sql.from[i].select); for (j = 0; j < sql.from[i].select.length; j++) { if (typeof sql.from[i].select[j] == "string" ) { From 2d9de115004d9394a09244ef1958591a3f428e11 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Wed, 3 Jul 2013 23:14:31 +0100 Subject: [PATCH 023/106] Fixes postgres dialect escaping binary data (buffers) --- lib/Dialects/postgresql.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 3e4b27c..8800f52 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -29,6 +29,9 @@ exports.escapeVal = function (val, timeZone) { if (util.isDate(val)) { return "'" + JSON.stringify(val).substr(1, 24) + "'"; } + if (Buffer.isBuffer(val)) { + return "'\\x" + val.toString("hex") + "'"; + } switch (typeof val) { case "number": return val; From 73f88c355f7a3125d0cee8073ba957b5a08be515 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Wed, 3 Jul 2013 23:14:41 +0100 Subject: [PATCH 024/106] 0.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c350644..d64bcab 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.0.29", + "version": "0.1.0", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From e2facb8a92eae3edef0010a5ce375686351e8835 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Wed, 3 Jul 2013 23:23:56 +0100 Subject: [PATCH 025/106] Fixes sqlite escaping binary data as hex --- lib/Dialects/sqlite.js | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 213083e..59484a0 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -1,2 +1,31 @@ +var util = require("util"); + exports.escapeId = require("./mysql").escapeId; -exports.escapeVal = require("./postgresql").escapeVal; + +exports.escapeVal = function (val, timeZone) { + if (val === undefined || val === null) { + return 'NULL'; + } + + if (Array.isArray(val)) { + if (val.length === 1 && Array.isArray(val[0])) { + return "(" + val[0].map(exports.escapeVal.bind(this)) + ")"; + } + return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; + } + if (util.isDate(val)) { + return "'" + JSON.stringify(val).substr(1, 24) + "'"; + } + if (Buffer.isBuffer(val)) { + return "X'" + val.toString("hex") + "'"; + } + switch (typeof val) { + case "number": + return val; + case "boolean": + return val ? "true" : "false"; + } + // No need to escape backslashes with default PostgreSQL 9.1+ config. + // Google 'postgresql standard_conforming_strings' for details. + return "'" + val.replace(/\'/g, "''") + "'"; +}; From d65216ac7f1a4d9fa7bd1e23027ca46c05890f9b Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Wed, 3 Jul 2013 23:24:11 +0100 Subject: [PATCH 026/106] 0.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d64bcab..eff17f8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From f52840def60b4e37b1fe00e233d657d7e814ce7c Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 4 Jul 2013 12:00:18 +0100 Subject: [PATCH 027/106] Saves when using whereExists() to force tables to have aliases --- lib/Select.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/Select.js b/lib/Select.js index 56936cb..14705bb 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -12,11 +12,12 @@ exports.SelectQuery = SelectQuery; function SelectQuery(Dialect) { var sql = { - from : [], - where : [], - order : [], - group_by : null, - found_rows : false + from : [], + where : [], + order : [], + group_by : null, + found_rows : false, + where_exists : false }; var get_table_alias = function (table) { for (var i = 0; i < sql.from.length; i++) { @@ -146,6 +147,7 @@ function SelectQuery(Dialect) { w: conditions, e: { t: table, tl: get_table_alias(table_link), l: link } }); + sql.where_exists = true; return this; }, groupBy: function () { @@ -281,7 +283,7 @@ function SelectQuery(Dialect) { if (i > 0) { query.push("JOIN"); } - if (sql.from.length == 1) { + if (sql.from.length == 1 && !sql.where_exists) { query.push(Dialect.escapeId(sql.from[i].t)); } else { query.push(Dialect.escapeId(sql.from[i].t) + " " + Dialect.escapeId(sql.from[i].a)); From c9ea81f5638d80cb4ac94083c2de8111364f725e Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 4 Jul 2013 12:00:25 +0100 Subject: [PATCH 028/106] 0.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eff17f8..f5cb322 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.1", + "version": "0.1.2", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 598eefea9d33a14b9150a886bf81230116b8ec32 Mon Sep 17 00:00:00 2001 From: Brian Romanko Date: Sat, 6 Jul 2013 11:26:28 -0700 Subject: [PATCH 029/106] Adding support for custom value types --- lib/Dialects/mysql.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index a702395..ea7d131 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -41,6 +41,10 @@ exports.escapeVal = function (val, timeZone) { return objectToValues(val, timeZone || "Z"); } + if (typeof val === 'function') { + return val(); + } + val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) { switch(s) { case "\0": return "\\0"; From cf6b11276ba539498a065c4ee69210c5710cde97 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sun, 7 Jul 2013 21:17:56 +0100 Subject: [PATCH 030/106] Lints mysql.escapeId --- lib/Dialects/mysql.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index ea7d131..c3970a0 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -1,3 +1,5 @@ +var util = require("util"); + exports.escapeId = function () { return Array.prototype.slice.apply(arguments).map(function (el) { if (typeof el == "object") { @@ -18,17 +20,6 @@ exports.escapeVal = function (val, timeZone) { return 'NULL'; } - switch (typeof val) { - case 'boolean': - return (val) ? 'true' : 'false'; - case 'number': - return val + ''; - } - - if (val instanceof Date) { - val = dateToString(val, timeZone || "Z"); - } - if (Buffer.isBuffer(val)) { return bufferToString(val); } @@ -37,14 +28,21 @@ exports.escapeVal = function (val, timeZone) { return arrayToList(val, timeZone || "Z"); } - if (typeof val === 'object') { - return objectToValues(val, timeZone || "Z"); + if (util.isDate(val)) { + val = dateToString(val, timeZone || "Z"); + } else { + switch (typeof val) { + case 'boolean': + return (val) ? 'true' : 'false'; + case 'number': + return val + ''; + case "object": + return objectToValues(val, timeZone || "Z"); + case "function": + return val(exports); + } } - if (typeof val === 'function') { - return val(); - } - val = val.replace(/[\0\n\r\b\t\\\'\"\x1a]/g, function(s) { switch(s) { case "\0": return "\\0"; From ba6606766430c0473a4bb9c82baa3bbc196199ed Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sun, 7 Jul 2013 21:18:09 +0100 Subject: [PATCH 031/106] Adds custom types to other missing dialects --- lib/Dialects/postgresql.js | 5 +++++ lib/Dialects/sqlite.js | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 8800f52..b5b3bc9 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -26,17 +26,22 @@ exports.escapeVal = function (val, timeZone) { } return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; } + if (util.isDate(val)) { return "'" + JSON.stringify(val).substr(1, 24) + "'"; } + if (Buffer.isBuffer(val)) { return "'\\x" + val.toString("hex") + "'"; } + switch (typeof val) { case "number": return val; case "boolean": return val ? "true" : "false"; + case "function": + return val(exports); } // No need to escape backslashes with default PostgreSQL 9.1+ config. // Google 'postgresql standard_conforming_strings' for details. diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 59484a0..f3eeb75 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -13,18 +13,24 @@ exports.escapeVal = function (val, timeZone) { } return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; } + if (util.isDate(val)) { return "'" + JSON.stringify(val).substr(1, 24) + "'"; } + if (Buffer.isBuffer(val)) { return "X'" + val.toString("hex") + "'"; } + switch (typeof val) { case "number": return val; case "boolean": return val ? "true" : "false"; + case "function": + return val(exports); } + // No need to escape backslashes with default PostgreSQL 9.1+ config. // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; From 61f568405e3ed578598cbc7857f06b47a109a0bf Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sun, 7 Jul 2013 21:18:28 +0100 Subject: [PATCH 032/106] Adds support for custom types in .select() --- lib/Select.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Select.js b/lib/Select.js index 14705bb..cb8208a 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -218,6 +218,11 @@ function SelectQuery(Dialect) { } } + if (typeof sql.from[i].select[j] == "function") { + tmp.push(sql.from[i].select[j](Dialect)); + continue; + } + if (!sql.from[i].select[j].f) continue; str = sql.from[i].select[j].f + "("; From d2ba0a9280b26743c2230b24bec2c92f00f77cd8 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sun, 7 Jul 2013 21:18:46 +0100 Subject: [PATCH 033/106] Adds tests for custom types (#13) --- test/integration/test-where-custom-types.js | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/integration/test-where-custom-types.js diff --git a/test/integration/test-where-custom-types.js b/test/integration/test-where-custom-types.js new file mode 100644 index 0000000..fdbab50 --- /dev/null +++ b/test/integration/test-where-custom-types.js @@ -0,0 +1,26 @@ +var common = require('../common'); +var assert = require('assert'); + +var Point = function () { + var point = "POINT(" + Array.prototype.slice.apply(arguments).join(" ") + ")"; + + return function () { + return point; + }; +}; + +var Year = function (col) { + return function (dialect) { + return "YEAR(" + dialect.escapeId(col) + ")"; + }; +}; + +assert.equal( + common.Select().from('table1').where({ col: Point(1, 2) }).build(), + "SELECT * FROM `table1` WHERE `col` = POINT(1 2)" +); + +assert.equal( + common.Select().from('table1').select(Year('dt')).build(), + "SELECT YEAR(`dt`) FROM `table1`" +); From cfee9bb0364f365d57aa9cee7a6eaff7717a6a7e Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sun, 7 Jul 2013 21:19:03 +0100 Subject: [PATCH 034/106] 0.1.3 Because of #13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f5cb322..1f3b1b7 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.2", + "version": "0.1.3", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 4da9182bdc116536268a5dd6b9487529e0335414 Mon Sep 17 00:00:00 2001 From: Benjamin Pannell Date: Sat, 13 Jul 2013 22:45:16 +0200 Subject: [PATCH 035/106] Support for multiple joins Allows you to execute joins on records which match a number of values between the tables. This functionality is implemented in a backwards compatible manner to prevent breaking node-orm2, pending changes on that branch which make use of this functionality. This allows queries like the following to be generated SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t1`.`id1` = `t2`.`id1` AND `t1`.`id2` = `t2`.`id2` --- .gitignore | 1 + lib/Select.js | 41 +++++++++++++++++++++++++-------- test/integration/test-select.js | 6 +++++ 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 01aa4f5..a58cf7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.sublime-* +*.njsproj .DS_Store node_modules test.js diff --git a/lib/Select.js b/lib/Select.js index cb8208a..3e9a8dc 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -102,11 +102,28 @@ function SelectQuery(Dialect) { return this; } + var a, f = from_id, t; if (arguments.length == 3) { - from.j = [ from_id, sql.from[sql.from.length - 1].a, to_table ]; + a = sql.from[sql.from.length - 1].a; + t = to_table; } else { - from.j = [ from_id, get_table_alias(to_table), to_id ]; + a = get_table_alias(to_table); + t = to_id; } + + from.j = []; + if (f.length && t.length) { + if (Array.isArray(f) && Array.isArray(t) && f.length == t.length) { + for (i = 0; i < f.length; i++) { + from.j.push([f[i], a, t[i]]); + } + } else { + from.j.push([f, a, t]); + } + } else { + throw new Error(); + } + sql.from.push(from); return this; }, @@ -294,15 +311,21 @@ function SelectQuery(Dialect) { query.push(Dialect.escapeId(sql.from[i].t) + " " + Dialect.escapeId(sql.from[i].a)); } if (i > 0) { - query.push( - "ON " + - Dialect.escapeId(sql.from[i].a, sql.from[i].j[0]) + - " = " + - Dialect.escapeId(sql.from[i].j[1], sql.from[i].j[2]) - ); + query.push("ON"); + + for (ii = 0; ii < sql.from[i].j.length; ii++) { + if (ii > 0) { + query.push("AND"); + } + query.push( + Dialect.escapeId(sql.from[i].a, sql.from[i].j[ii][0]) + + " = " + + Dialect.escapeId(sql.from[i].j[ii][1], sql.from[i].j[ii][2]) + ); + } if (i < sql.from.length - 1) { - query.push(")"); + query.push(")"); } } } diff --git a/test/integration/test-select.js b/test/integration/test-select.js index ddfe32e..76d8b98 100644 --- a/test/integration/test-select.js +++ b/test/integration/test-select.js @@ -93,3 +93,9 @@ assert.equal( .from('table2', 'id2', 'table1', 'id1').fun('AVG', 'col').build(), "SELECT AVG(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" ); + +assert.equal( + common.Select().from('table1') + .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']).count('id').build(), + "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2a` = `t1`.`id1a` AND `t2`.`id2b` = `t1`.`id1b`" +); From c1e3c995513f82c85796fde5721483a63891f608 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sun, 14 Jul 2013 15:09:12 +0100 Subject: [PATCH 036/106] 0.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1f3b1b7..e030ed9 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.3", + "version": "0.1.4", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 53cf403afbb6f1b285f51f2cbb2cccbacd7227f3 Mon Sep 17 00:00:00 2001 From: Benjamin Pannell Date: Sun, 14 Jul 2013 20:16:43 +0200 Subject: [PATCH 037/106] Add support for multi-conditional exists Required to support the most recent changes to node-orm2 which provide support for multiple primary keys on models. --- lib/Where.js | 16 +++++++++++++--- package.json | 5 ++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/Where.js b/lib/Where.js index f125018..03434a9 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -24,13 +24,23 @@ exports.build = function (Dialect, where) { function buildOrGroup(Dialect, where) { if (where.e) { - // EXISTS + // EXISTS + + wheres = []; + if(Array.isArray(where.e.l[0]) && Array.isArray(where.e.l[1])) { + for (i = 0; i < where.e.l[0].length; i++) { + wheres.push(Dialect.escapeId(where.e.l[0][i]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1][i])); + } + } else { + wheres.push(Dialect.escapeId(where.e.l[0]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1])); + } + return [ "EXISTS (" + "SELECT * FROM " + Dialect.escapeId(where.e.t) + " " + - "WHERE " + Dialect.escapeId(where.e.l[0]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1]) + " " + + "WHERE " + wheres.join(" AND ") + "AND " + buildOrGroup(Dialect, { t: null, w: where.w }) + - ")" + ")" ]; } diff --git a/package.json b/package.json index e030ed9..2cf5a67 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,14 @@ "sql", "query" ], - "version": "0.1.4", + "version": "0.1.5", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" }, + "contributors": [ + { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" } + ], "scripts": { "test": "make" }, From b898f9c3cfe44d5d5991311cc0953e198e81252a Mon Sep 17 00:00:00 2001 From: Benjamin Pannell Date: Mon, 15 Jul 2013 11:40:39 +0200 Subject: [PATCH 038/106] Added tests for where exists --- lib/Where.js | 2 +- test/integration/test-where-exists.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test/integration/test-where-exists.js diff --git a/lib/Where.js b/lib/Where.js index 03434a9..6740aaf 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -38,7 +38,7 @@ function buildOrGroup(Dialect, where) { return [ "EXISTS (" + "SELECT * FROM " + Dialect.escapeId(where.e.t) + " " + - "WHERE " + wheres.join(" AND ") + + "WHERE " + wheres.join(" AND ") + " " + "AND " + buildOrGroup(Dialect, { t: null, w: where.w }) + ")" ]; diff --git a/test/integration/test-where-exists.js b/test/integration/test-where-exists.js new file mode 100644 index 0000000..3d0c14a --- /dev/null +++ b/test/integration/test-where-exists.js @@ -0,0 +1,12 @@ +var common = require('../common'); +var assert = require('assert'); + +assert.equal( + common.Select().from('table1').whereExists('table2', 'table1', ['fid', 'id'], { col1: 1, col2: 2 }).build(), + "SELECT * FROM `table1` `t1` WHERE EXISTS (SELECT * FROM `table2` WHERE `fid` = `t1`.`id` AND `col1` = 1 AND `col2` = 2)" + ); + +assert.equal( + common.Select().from('table1').whereExists('table2', 'table1', [['fid1', 'fid2'],['id1', 'id2']], { col1: 1, col2: 2 }).build(), + "SELECT * FROM `table1` `t1` WHERE EXISTS (SELECT * FROM `table2` WHERE `fid1` = `t1`.`id1` AND `fid2` = `t1`.`id2` AND `col1` = 1 AND `col2` = 2)" + ); \ No newline at end of file From 8aaa5ef750d6b570376ec58774139121a53d690c Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 17 Jul 2013 21:49:00 +1000 Subject: [PATCH 039/106] Allow sql where conditions --- lib/Where.js | 44 ++++++++++++++++++++++++++++------ package.json | 2 +- test/integration/test-where.js | 20 ++++++++++++++++ 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/lib/Where.js b/lib/Where.js index 6740aaf..b85c057 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -25,7 +25,7 @@ exports.build = function (Dialect, where) { function buildOrGroup(Dialect, where) { if (where.e) { // EXISTS - + wheres = []; if(Array.isArray(where.e.l[0]) && Array.isArray(where.e.l[1])) { for (i = 0; i < where.e.l[0].length; i++) { @@ -34,7 +34,7 @@ function buildOrGroup(Dialect, where) { } else { wheres.push(Dialect.escapeId(where.e.l[0]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1])); } - + return [ "EXISTS (" + "SELECT * FROM " + Dialect.escapeId(where.e.t) + " " + @@ -73,6 +73,7 @@ function buildOrGroup(Dialect, where) { } continue; } + if (typeof where.w[k].sql_comparator == "function") { op = where.w[k].sql_comparator(); @@ -136,11 +137,17 @@ function buildOrGroup(Dialect, where) { continue; } - query.push( - buildComparisonKey(Dialect, where.t, k) + - (Array.isArray(where.w[k]) ? " IN " : " = ") + - Dialect.escapeVal(where.w[k]) - ); + if (k == '__sql') { + for (var a = 0; a < where.w[k].length; a++) { + query.push(normalizeSqlConditions(Dialect, where.w[k][a])); + } + } else { + query.push( + buildComparisonKey(Dialect, where.t, k) + + (Array.isArray(where.w[k]) ? " IN " : " = ") + + Dialect.escapeVal(where.w[k]) + ); + } } if (query.length === 0) { @@ -153,3 +160,26 @@ function buildOrGroup(Dialect, where) { function buildComparisonKey(Dialect, table, column) { return (table ? Dialect.escapeId(table, column) : Dialect.escapeId(column)); } + +// Transforms: +// ["name LIKE ? AND age > ?", ["John", 23]] +// into: +// "name LIKE 'John' AND age > 23" +function normalizeSqlConditions(Dialect, queryArray) { + var a, args, last = -1, query = ''; + + if (queryArray.length == 1) { + return queryArray[0]; + } + args = queryArray[1]; + + for (a = 0; a < queryArray[0].length; a++) { + if (queryArray[0][a] === '?') { + query = query + queryArray[0].substring(last + 1, a) + Dialect.escapeVal(args.shift()); + last = a; + } + } + query = query + queryArray[0].substring(last + 1) + + return query; +} diff --git a/package.json b/package.json index 2cf5a67..3311e7c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.5", + "version": "0.1.6", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 5c2ba3a..0f12ca2 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -144,3 +144,23 @@ assert.equal( common.Select().from('table1').where({ col: common.Query.like('abc') }).build(), "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" ); + +assert.equal( + common.Select().from('table1').where({ __sql: [["LOWER(`stuff`) LIKE 'peaches'"]] }).build(), + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" +); + +assert.equal( + common.Select().from('table1').where({ __sql: [["LOWER(`stuff`) LIKE ?", ['peaches']]] }).build(), + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" +); + +assert.equal( + common.Select().from('table1').where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]]] }).build(), + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" +); + +assert.equal( + common.Select().from('table1').where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']]] }).build(), + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" +); From 32b9a3e95f865a11c3ca23735a9fee63431f967a Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 17 Jul 2013 22:50:54 +1000 Subject: [PATCH 040/106] Simplify sql condition normalization --- lib/Where.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/lib/Where.js b/lib/Where.js index b85c057..7129e25 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -166,20 +166,11 @@ function buildComparisonKey(Dialect, table, column) { // into: // "name LIKE 'John' AND age > 23" function normalizeSqlConditions(Dialect, queryArray) { - var a, args, last = -1, query = ''; - if (queryArray.length == 1) { return queryArray[0]; } - args = queryArray[1]; - - for (a = 0; a < queryArray[0].length; a++) { - if (queryArray[0][a] === '?') { - query = query + queryArray[0].substring(last + 1, a) + Dialect.escapeVal(args.shift()); - last = a; - } - } - query = query + queryArray[0].substring(last + 1) - return query; + return queryArray[0].replace(/\?/g, function () { + return Dialect.escapeVal(queryArray[1].shift()); + }); } From 83583c3070a20b89d2a89c7d2986501342fc2c8d Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 23 Jul 2013 11:22:18 +0100 Subject: [PATCH 041/106] Adds .not_between(a, b) comparator --- lib/Comparators.js | 3 +++ lib/Where.js | 9 +++++++++ test/integration/test-where.js | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/lib/Comparators.js b/lib/Comparators.js index 947017b..a216c63 100644 --- a/lib/Comparators.js +++ b/lib/Comparators.js @@ -1,6 +1,9 @@ exports.between = function (a, b) { return createSpecialObject({ from: a, to: b }, 'between'); }; +exports.not_between = function (a, b) { + return createSpecialObject({ from: a, to: b }, 'not_between'); +}; exports.like = function (expr) { return createSpecialObject({ expr: expr }, 'like'); }; diff --git a/lib/Where.js b/lib/Where.js index 7129e25..df486c5 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -87,6 +87,15 @@ function buildOrGroup(Dialect, where) { Dialect.escapeVal(where.w[k].to) ); break; + case "not_between": + query.push( + buildComparisonKey(Dialect, where.t, k) + + " NOT BETWEEN " + + Dialect.escapeVal(where.w[k].from) + + " AND " + + Dialect.escapeVal(where.w[k].to) + ); + break; case "like": query.push( buildComparisonKey(Dialect, where.t, k) + diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 0f12ca2..72a2a52 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -140,6 +140,11 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` BETWEEN 'a' AND 'b'" ); +assert.equal( + common.Select().from('table1').where({ col: common.Query.not_between('a', 'b') }).build(), + "SELECT * FROM `table1` WHERE `col` NOT BETWEEN 'a' AND 'b'" +); + assert.equal( common.Select().from('table1').where({ col: common.Query.like('abc') }).build(), "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" From ae52aa26238d808cfc9cbeb676ce8aca13117804 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 23 Jul 2013 11:22:23 +0100 Subject: [PATCH 042/106] 0.1.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3311e7c..d452cb3 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.6", + "version": "0.1.7", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 414162d1a6ce9074826b9c62e289841209676cc9 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 23 Jul 2013 18:07:33 +0100 Subject: [PATCH 043/106] Adds .order(), .limit() and .offset() to DELETE statements (#17) Same as SELECT statements --- lib/Remove.js | 47 +++++++++++++++++++++++++++++++-- test/integration/test-remove.js | 20 ++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/lib/Remove.js b/lib/Remove.js index 64971bb..a063a14 100644 --- a/lib/Remove.js +++ b/lib/Remove.js @@ -4,7 +4,8 @@ exports.RemoveQuery = RemoveQuery; function RemoveQuery(Dialect) { var sql = { - where : [] + where : [], + order : [] }; return { @@ -22,14 +23,56 @@ function RemoveQuery(Dialect) { return this; }, build: function () { - var query = []; + var query = [], tmp; query.push("DELETE FROM"); query.push(Dialect.escapeId(sql.table)); query = query.concat(Where.build(Dialect, sql.where)); + // 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); + } + } + + if (tmp.length > 0) { + 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); + } + } else if (sql.hasOwnProperty("offset")) { + query.push("OFFSET " + sql.offset); + } + return query.join(" "); + }, + offset: function (offset) { + sql.offset = offset; + return this; + }, + limit: function (limit) { + sql.limit = limit; + return this; + }, + order: function (column, dir) { + sql.order.push({ + c : Array.isArray(column) ? [ get_table_alias(column[0]), column[1] ] : column, + d : (dir == "Z" ? "DESC" : "ASC") + }); + return this; } }; } diff --git a/test/integration/test-remove.js b/test/integration/test-remove.js index 9b0877c..af43856 100644 --- a/test/integration/test-remove.js +++ b/test/integration/test-remove.js @@ -20,3 +20,23 @@ assert.equal( common.Remove().from('table1').where({ or: [{ col: 1 }, { col: 2 }] }).build(), "DELETE FROM `table1` WHERE ((`col` = 1) OR (`col` = 2))" ); + +assert.equal( + common.Remove().from('table1').limit(10).build(), + "DELETE FROM `table1` LIMIT 10" +); + +assert.equal( + common.Remove().from('table1').limit(10).offset(3).build(), + "DELETE FROM `table1` LIMIT 10 OFFSET 3" +); + +assert.equal( + common.Remove().from('table1').order('col').limit(5).build(), + "DELETE FROM `table1` ORDER BY `col` ASC LIMIT 5" +); + +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" +); From 79343c979abb0605e63328cd81a983db818ccd9d Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 23 Jul 2013 18:07:49 +0100 Subject: [PATCH 044/106] 0.1.8 Because of #17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d452cb3..79f3a2b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.7", + "version": "0.1.8", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 6c9faba03cbc49abb893f5809b20be1cea488efe Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sat, 3 Aug 2013 08:57:14 +0100 Subject: [PATCH 045/106] Fixes converting an empty array to "IN ()" and instead pass a falsy sentence (dresende/node-orm2#274) --- lib/Where.js | 15 ++++++++++----- test/integration/test-where.js | 5 +++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/Where.js b/lib/Where.js index df486c5..1e2c7bb 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -151,11 +151,16 @@ function buildOrGroup(Dialect, where) { query.push(normalizeSqlConditions(Dialect, where.w[k][a])); } } else { - query.push( - buildComparisonKey(Dialect, where.t, k) + - (Array.isArray(where.w[k]) ? " IN " : " = ") + - Dialect.escapeVal(where.w[k]) - ); + 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"); + } else { + query.push(buildComparisonKey(Dialect, where.t, k) + " IN " + Dialect.escapeVal(where.w[k])); + } + } else { + query.push(buildComparisonKey(Dialect, where.t, k) + " = " + Dialect.escapeVal(where.w[k])); + } } } diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 72a2a52..c199ffd 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -71,6 +71,11 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` IN (1, 2, 3)" ); +assert.equal( + common.Select().from('table1').where({ col: [] }).build(), + "SELECT * FROM `table1` WHERE FALSE" +); + assert.equal( common.Select().from('table1').where({ col1: 1, col2: 2 }).build(), "SELECT * FROM `table1` WHERE `col1` = 1 AND `col2` = 2" From d9e61a3d4d709dade06c97eea32ae452e921c997 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sat, 3 Aug 2013 08:57:46 +0100 Subject: [PATCH 046/106] 0.1.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 79f3a2b..4b4d246 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.8", + "version": "0.1.9", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 0102fadd361f01e77a82d7a3fabc7c2c57a0fa4c Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 20 Aug 2013 11:55:32 +0100 Subject: [PATCH 047/106] Fixes sqlite boolean values to be converted to 1/0 instead of true/false --- lib/Dialects/sqlite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index f3eeb75..bca0639 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -26,7 +26,7 @@ exports.escapeVal = function (val, timeZone) { case "number": return val; case "boolean": - return val ? "true" : "false"; + return val ? 1 : 0; case "function": return val(exports); } From 7f7bf71e981f5959e5fcaca564509b541848244d Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 20 Aug 2013 11:56:20 +0100 Subject: [PATCH 048/106] Fixes test for sqlite boolean values --- test/integration/test-dialect-sqlite.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index 298ec07..54598c9 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -49,10 +49,10 @@ assert.equal( assert.equal( dialect.escapeVal(true), - "true" + "1" ); assert.equal( dialect.escapeVal(false), - "false" + "0" ); From 6894218ead1a982377f8fcb40ee6dc7b772d664b Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 20 Aug 2013 11:56:50 +0100 Subject: [PATCH 049/106] 0.1.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4b4d246..17d8e67 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.9", + "version": "0.1.10", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From f2d1dcea65c225054dcb4cca41b11083550fcac5 Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 21 Aug 2013 20:28:15 +1000 Subject: [PATCH 050/106] Expose Query.escape --- lib/Helpers.js | 10 ++++++++++ lib/Query.js | 6 ++++-- lib/Where.js | 11 +++-------- test/lib/test-helpers.js | 25 +++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 lib/Helpers.js create mode 100644 test/lib/test-helpers.js diff --git a/lib/Helpers.js b/lib/Helpers.js new file mode 100644 index 0000000..3d66c63 --- /dev/null +++ b/lib/Helpers.js @@ -0,0 +1,10 @@ + +// Transforms: +// "name LIKE ? AND age > ?", ["John", 23] +// into: +// "name LIKE 'John' AND age > 23" +module.exports.escapeQuery = function (Dialect, query, args) { + return query.replace(/\?/g, function () { + return Dialect.escapeVal(args.shift()); + }); +} diff --git a/lib/Query.js b/lib/Query.js index 46b28d5..fb4584c 100644 --- a/lib/Query.js +++ b/lib/Query.js @@ -3,6 +3,7 @@ var InsertQuery = require("./Insert").InsertQuery; var UpdateQuery = require("./Update").UpdateQuery; var RemoveQuery = require("./Remove").RemoveQuery; var Comparators = require("./Comparators"); +var Helpers = require('./Helpers'); exports.Query = Query; exports.Comparators = Object.keys(Comparators); @@ -22,8 +23,9 @@ function Query(opts) { var Dialect = require("./Dialects/" + (opts.dialect || "mysql")); return { - escapeId: Dialect.escapeId.bind(Dialect), - escapeVal: Dialect.escapeVal.bind(Dialect), + escape : Helpers.escapeQuery.bind(Dialect), + escapeId : Dialect.escapeId.bind(Dialect), + escapeVal : Dialect.escapeVal.bind(Dialect), select: function () { return new SelectQuery(Dialect); }, diff --git a/lib/Where.js b/lib/Where.js index 1e2c7bb..04941fe 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -1,3 +1,5 @@ +var Helpers = require('./Helpers'); + exports.build = function (Dialect, where) { if (where.length === 0) { return []; @@ -175,16 +177,9 @@ function buildComparisonKey(Dialect, table, column) { return (table ? Dialect.escapeId(table, column) : Dialect.escapeId(column)); } -// Transforms: -// ["name LIKE ? AND age > ?", ["John", 23]] -// into: -// "name LIKE 'John' AND age > 23" function normalizeSqlConditions(Dialect, queryArray) { if (queryArray.length == 1) { return queryArray[0]; } - - return queryArray[0].replace(/\?/g, function () { - return Dialect.escapeVal(queryArray[1].shift()); - }); + return Helpers.escapeQuery(Dialect, queryArray[0], queryArray[1]); } diff --git a/test/lib/test-helpers.js b/test/lib/test-helpers.js new file mode 100644 index 0000000..927ad70 --- /dev/null +++ b/test/lib/test-helpers.js @@ -0,0 +1,25 @@ +var assert = require('assert'); +var Helpers = require('../../lib/Helpers'); +var common = require('../common'); + +var Dialect = common.getDialect('mysql'); + +assert.equal( + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'"), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" +); + +assert.equal( + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ?", ['peaches']), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" +); + +assert.equal( + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" +); + +assert.equal( + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" +); From 1f501e27688cd660bf757f0bffcd9b7434c4007a Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 21 Aug 2013 20:29:20 +1000 Subject: [PATCH 051/106] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17d8e67..a6d1da3 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.10", + "version": "0.1.11", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From c8014c7978dae73d1c3e2a94c5c954e28c800bd8 Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 21 Aug 2013 20:48:30 +1000 Subject: [PATCH 052/106] Spaces -> tabs --- test/lib/test-helpers.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/lib/test-helpers.js b/test/lib/test-helpers.js index 927ad70..1a36642 100644 --- a/test/lib/test-helpers.js +++ b/test/lib/test-helpers.js @@ -5,21 +5,21 @@ var common = require('../common'); var Dialect = common.getDialect('mysql'); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'"), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'"), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" ); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ?", ['peaches']), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ?", ['peaches']), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" ); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" ); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']), + "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" ); From 42bcee8be9de88bdc524f292359d54b39fcbbf6c Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 21 Aug 2013 21:13:25 +1000 Subject: [PATCH 053/106] Allow escaping identifiers & values --- lib/Helpers.js | 8 ++++++-- test/lib/test-helpers.js | 26 ++++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/Helpers.js b/lib/Helpers.js index 3d66c63..a362bed 100644 --- a/lib/Helpers.js +++ b/lib/Helpers.js @@ -4,7 +4,11 @@ // into: // "name LIKE 'John' AND age > 23" module.exports.escapeQuery = function (Dialect, query, args) { - return query.replace(/\?/g, function () { - return Dialect.escapeVal(args.shift()); + return query.replace(/[?]+/g, function (match) { + if (match == '?') { + return Dialect.escapeVal(args.shift()); + } else if (match == '??') { + return Dialect.escapeId(args.shift()); + } }); } diff --git a/test/lib/test-helpers.js b/test/lib/test-helpers.js index 1a36642..c230e0c 100644 --- a/test/lib/test-helpers.js +++ b/test/lib/test-helpers.js @@ -5,21 +5,31 @@ var common = require('../common'); var Dialect = common.getDialect('mysql'); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'"), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches'"), + "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches'" ); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ?", ['peaches']), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches'" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE ?", ['peaches']), + "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches'" ); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]), + "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches' AND `number` > 12" ); assert.equal( - Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']), - "SELECT * FROM abc WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE ? AND `number` == ?", ['peaches']), + "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches' AND `number` == NULL" +); + +assert.equal( + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.??) LIKE ? AND abc.?? > ?", ['stuff', 'peaches', 'number', 12]), + "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches' AND abc.`number` > 12" +); + +assert.equal( + Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.??) LIKE ? AND ?? == ?", ['stuff', 'peaches', 'number']), + "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches' AND `number` == NULL" ); From 45aa7a9d5c5a11db2aadd44830bf2ac3e8b43636 Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 21 Aug 2013 22:38:25 +1000 Subject: [PATCH 054/106] Fix binding --- lib/Query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Query.js b/lib/Query.js index fb4584c..7b06f5f 100644 --- a/lib/Query.js +++ b/lib/Query.js @@ -23,7 +23,7 @@ function Query(opts) { var Dialect = require("./Dialects/" + (opts.dialect || "mysql")); return { - escape : Helpers.escapeQuery.bind(Dialect), + escape : Helpers.escapeQuery.bind(Helpers, Dialect), escapeId : Dialect.escapeId.bind(Dialect), escapeVal : Dialect.escapeVal.bind(Dialect), select: function () { From 7faa13398a433cfba1c4efb5989ffe22f76ae2ef Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 22 Aug 2013 09:30:43 +0100 Subject: [PATCH 055/106] 0.1.11 --- package.json | 58 +++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index a6d1da3..60d8b6e 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,30 @@ { - "author": "Diogo Resende ", - "name": "sql-query", - "description": "NodeJS SQL query builder", - "keywords": [ - "sql", - "query" - ], - "version": "0.1.11", - "license": "MIT", - "repository": { - "url": "http://github.com/dresende/node-sql-query" - }, - "contributors": [ - { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" } - ], - "scripts": { - "test": "make" - }, - "main": "./lib/Query", - "scripts": { - "test": "make test" - }, - "engines": { - "node": "*" - }, - "analyse": false, - "devDependencies": { - "utest": "0.0.6", - "urun": "0.0.6" - } + "author": "Diogo Resende ", + "name": "sql-query", + "description": "NodeJS SQL query builder", + "keywords": [ + "sql", + "query" + ], + "version": "0.1.11", + "license": "MIT", + "repository": { + "url": "http://github.com/dresende/node-sql-query" + }, + "contributors": [ + { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" }, + { "name" : "Arek W" }, + ], + "scripts": { + "test": "make" + }, + "main": "./lib/Query", + "engines": { + "node": "*" + }, + "analyse": false, + "devDependencies": { + "utest": "0.0.6", + "urun": "0.0.6" + } } From e86658a6d9b23bd33871263af48638dacc5cc241 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 22 Aug 2013 09:32:00 +0100 Subject: [PATCH 056/106] 0.1.11 Fixes missing comma --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 60d8b6e..9b91d9c 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "contributors": [ { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" }, - { "name" : "Arek W" }, + { "name" : "Arek W" } ], "scripts": { "test": "make" From 668ab1db1795e1cfb5b52957672e811b54141163 Mon Sep 17 00:00:00 2001 From: Arek W Date: Fri, 23 Aug 2013 09:20:06 +1000 Subject: [PATCH 057/106] Deal with NaN [https://github.com/dresende/node-orm2/issues/310](https://github.com/dresende/node-orm2/issues/310) --- lib/Dialects/mysql.js | 4 ++++ lib/Dialects/postgresql.js | 4 ++++ lib/Dialects/sqlite.js | 4 ++++ test/integration/test-dialect-mysql.js | 5 +++++ test/integration/test-dialect-postgresql.js | 5 +++++ test/integration/test-dialect-sqlite.js | 5 +++++ 6 files changed, 27 insertions(+) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index c3970a0..c3a5b89 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -35,6 +35,10 @@ exports.escapeVal = function (val, timeZone) { case 'boolean': return (val) ? 'true' : 'false'; case 'number': + if (val != val) { + val = val.toString(); + break; + } return val + ''; case "object": return objectToValues(val, timeZone || "Z"); diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index b5b3bc9..d21dd2a 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -37,6 +37,10 @@ exports.escapeVal = function (val, timeZone) { switch (typeof val) { case "number": + if (val != val) { + val = val.toString(); + break; + } return val; case "boolean": return val ? "true" : "false"; diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index bca0639..d98a5bf 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -24,6 +24,10 @@ exports.escapeVal = function (val, timeZone) { switch (typeof val) { case "number": + if (val != val) { + val = val.toString(); + break; + } return val; case "boolean": return val ? 1 : 0; diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index e340b76..8e01bc4 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -32,6 +32,11 @@ assert.equal( "123" ); +assert.equal( + dialect.escapeVal(NaN), + "'NaN'" +); + assert.equal( dialect.escapeVal('abc'), "'abc'" diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index 3683341..eddc552 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -37,6 +37,11 @@ assert.equal( "123" ); +assert.equal( + dialect.escapeVal(NaN), + "'NaN'" +); + assert.equal( dialect.escapeVal('abc'), "'abc'" diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index 54598c9..c78f977 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -32,6 +32,11 @@ assert.equal( "123" ); +assert.equal( + dialect.escapeVal(NaN), + "'NaN'" +); + assert.equal( dialect.escapeVal('abc'), "'abc'" From 378db5c0c2e98cee04f0672a20647c15866dff31 Mon Sep 17 00:00:00 2001 From: Arek W Date: Fri, 23 Aug 2013 09:28:55 +1000 Subject: [PATCH 058/106] Also deal with Infinity. dresende/node-orm2/#310 --- lib/Dialects/mysql.js | 2 +- lib/Dialects/postgresql.js | 2 +- lib/Dialects/sqlite.js | 2 +- test/integration/test-dialect-mysql.js | 5 +++++ test/integration/test-dialect-postgresql.js | 5 +++++ test/integration/test-dialect-sqlite.js | 5 +++++ 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index c3a5b89..fd3bf0a 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -35,7 +35,7 @@ exports.escapeVal = function (val, timeZone) { case 'boolean': return (val) ? 'true' : 'false'; case 'number': - if (val != val) { + if (!isFinite(val)) { val = val.toString(); break; } diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index d21dd2a..7b36000 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -37,7 +37,7 @@ exports.escapeVal = function (val, timeZone) { switch (typeof val) { case "number": - if (val != val) { + if (!isFinite(val)) { val = val.toString(); break; } diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index d98a5bf..935bef8 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -24,7 +24,7 @@ exports.escapeVal = function (val, timeZone) { switch (typeof val) { case "number": - if (val != val) { + if (!isFinite(val)) { val = val.toString(); break; } diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index 8e01bc4..34c7fc5 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -37,6 +37,11 @@ assert.equal( "'NaN'" ); +assert.equal( + dialect.escapeVal(Infinity), + "'Infinity'" +); + assert.equal( dialect.escapeVal('abc'), "'abc'" diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index eddc552..82f1f84 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -42,6 +42,11 @@ assert.equal( "'NaN'" ); +assert.equal( + dialect.escapeVal(Infinity), + "'Infinity'" +); + assert.equal( dialect.escapeVal('abc'), "'abc'" diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index c78f977..f3fc121 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -37,6 +37,11 @@ assert.equal( "'NaN'" ); +assert.equal( + dialect.escapeVal(Infinity), + "'Infinity'" +); + assert.equal( dialect.escapeVal('abc'), "'abc'" From ab2b7d2c3f743cd9907778a97caa94331e13360a Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Wed, 28 Aug 2013 22:46:02 +0100 Subject: [PATCH 059/106] 0.1.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9b91d9c..7b2d4db 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.11", + "version": "0.1.12", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From b65e9ffbf2d3d1b9d574bfd92b697443582bec03 Mon Sep 17 00:00:00 2001 From: Dirk Mccormick Date: Tue, 3 Sep 2013 18:14:12 -0400 Subject: [PATCH 060/106] Use local as default timezone, pass timezone to escapeVal() --- lib/Dialects/mysql.js | 4 ++-- lib/Insert.js | 4 ++-- lib/Query.js | 8 ++++---- lib/Remove.js | 4 ++-- lib/Select.js | 6 +++--- lib/Set.js | 6 ++++-- lib/Update.js | 6 +++--- lib/Where.js | 30 ++++++++++++++++-------------- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index fd3bf0a..d6f1c48 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -25,11 +25,11 @@ exports.escapeVal = function (val, timeZone) { } if (Array.isArray(val)) { - return arrayToList(val, timeZone || "Z"); + return arrayToList(val, timeZone || "local"); } if (util.isDate(val)) { - val = dateToString(val, timeZone || "Z"); + val = dateToString(val, timeZone || "local"); } else { switch (typeof val) { case 'boolean': diff --git a/lib/Insert.js b/lib/Insert.js index 452aa16..6d24e99 100644 --- a/lib/Insert.js +++ b/lib/Insert.js @@ -2,7 +2,7 @@ var Set = require("./Set"); exports.InsertQuery = InsertQuery; -function InsertQuery(Dialect) { +function InsertQuery(Dialect, opts) { var sql = {}; return { @@ -23,7 +23,7 @@ function InsertQuery(Dialect) { if (sql.hasOwnProperty("set")) { for (var k in sql.set) { cols.push(Dialect.escapeId(k)); - vals.push(Dialect.escapeVal(sql.set[k])); + vals.push(Dialect.escapeVal(sql.set[k], opts.timezone)); } query.push("(" + cols.join(", ") + ")"); query.push("VALUES (" + vals.join(", ") + ")"); diff --git a/lib/Query.js b/lib/Query.js index 7b06f5f..4203812 100644 --- a/lib/Query.js +++ b/lib/Query.js @@ -27,16 +27,16 @@ function Query(opts) { escapeId : Dialect.escapeId.bind(Dialect), escapeVal : Dialect.escapeVal.bind(Dialect), select: function () { - return new SelectQuery(Dialect); + return new SelectQuery(Dialect, opts); }, insert: function () { - return new InsertQuery(Dialect); + return new InsertQuery(Dialect, opts); }, update: function () { - return new UpdateQuery(Dialect); + return new UpdateQuery(Dialect, opts); }, remove: function () { - return new RemoveQuery(Dialect); + return new RemoveQuery(Dialect, opts); } }; } diff --git a/lib/Remove.js b/lib/Remove.js index a063a14..6fe367b 100644 --- a/lib/Remove.js +++ b/lib/Remove.js @@ -2,7 +2,7 @@ var Where = require("./Where"); exports.RemoveQuery = RemoveQuery; -function RemoveQuery(Dialect) { +function RemoveQuery(Dialect, opts) { var sql = { where : [], order : [] @@ -28,7 +28,7 @@ function RemoveQuery(Dialect) { query.push("DELETE FROM"); query.push(Dialect.escapeId(sql.table)); - query = query.concat(Where.build(Dialect, sql.where)); + query = query.concat(Where.build(Dialect, sql.where, opts)); // order if (sql.order.length > 0) { diff --git a/lib/Select.js b/lib/Select.js index 3e9a8dc..6dde1af 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -10,7 +10,7 @@ var aggregate_functions = [ exports.SelectQuery = SelectQuery; -function SelectQuery(Dialect) { +function SelectQuery(Dialect, opts) { var sql = { from : [], where : [], @@ -253,7 +253,7 @@ function SelectQuery(Dialect) { if (typeof el.type == "function") { switch (el.type()) { case "text": - return Dialect.escapeVal(el.data); + return Dialect.escapeVal(el.data, opts.timezone); default: return el; } @@ -337,7 +337,7 @@ function SelectQuery(Dialect) { } } - query = query.concat(Where.build(Dialect, sql.where)); + query = query.concat(Where.build(Dialect, sql.where, opts)); if (sql.group_by !== null) { query.push("GROUP BY " + sql.group_by.map(function (column) { diff --git a/lib/Set.js b/lib/Set.js index 69e7ad1..f9beb05 100644 --- a/lib/Set.js +++ b/lib/Set.js @@ -1,4 +1,6 @@ -exports.build = function (Dialect, set) { +exports.build = function (Dialect, set, opts) { + opts = opts || {}; + if (!set || set.length === 0) { return []; } @@ -9,7 +11,7 @@ exports.build = function (Dialect, set) { query.push( Dialect.escapeId(k) + " = " + - Dialect.escapeVal(set[k]) + Dialect.escapeVal(set[k], opts.timezone) ); } diff --git a/lib/Update.js b/lib/Update.js index d0209a2..1692051 100644 --- a/lib/Update.js +++ b/lib/Update.js @@ -3,7 +3,7 @@ var Where = require("./Where"); exports.UpdateQuery = UpdateQuery; -function UpdateQuery(Dialect) { +function UpdateQuery(Dialect, opts) { var sql = { where : [] }; @@ -32,8 +32,8 @@ function UpdateQuery(Dialect) { query.push("UPDATE"); query.push(Dialect.escapeId(sql.table)); - query = query.concat(Set.build(Dialect, sql.set)); - query = query.concat(Where.build(Dialect, sql.where)); + query = query.concat(Set.build(Dialect, sql.set, opts)); + query = query.concat(Where.build(Dialect, sql.where, opts)); return query.join(" "); } diff --git a/lib/Where.js b/lib/Where.js index 04941fe..7ee567b 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -1,6 +1,6 @@ var Helpers = require('./Helpers'); -exports.build = function (Dialect, where) { +exports.build = function (Dialect, where, opts) { if (where.length === 0) { return []; } @@ -8,7 +8,7 @@ exports.build = function (Dialect, where) { var query = [], subquery; for (var i = 0; i < where.length; i++) { - subquery = buildOrGroup(Dialect, where[i]); + subquery = buildOrGroup(Dialect, where[i], opts); if (subquery !== false) { query.push(subquery); @@ -24,7 +24,9 @@ exports.build = function (Dialect, where) { return "WHERE (" + query.join(") AND (") + ")"; }; -function buildOrGroup(Dialect, where) { +function buildOrGroup(Dialect, where, opts) { + opts = opts || {}; + if (where.e) { // EXISTS @@ -41,7 +43,7 @@ function buildOrGroup(Dialect, where) { "EXISTS (" + "SELECT * FROM " + Dialect.escapeId(where.e.t) + " " + "WHERE " + wheres.join(" AND ") + " " + - "AND " + buildOrGroup(Dialect, { t: null, w: where.w }) + + "AND " + buildOrGroup(Dialect, { t: null, w: where.w }, opts) + ")" ]; } @@ -64,7 +66,7 @@ function buildOrGroup(Dialect, where) { op = (k == "not" ? "and" : (k.indexOf("_") >= 0 ? k.substr(4) : k)).toUpperCase(); for (var j = 0; j < where.w[k].length; j++) { - q = buildOrGroup(Dialect, { t: where.t, w: where.w[k][j] }); + q = buildOrGroup(Dialect, { t: where.t, w: where.w[k][j] }, opts); if (q !== false) { subquery.push(q); } @@ -84,25 +86,25 @@ function buildOrGroup(Dialect, where) { query.push( buildComparisonKey(Dialect, where.t, k) + " BETWEEN " + - Dialect.escapeVal(where.w[k].from) + + Dialect.escapeVal(where.w[k].from, opts.timezone) + " AND " + - Dialect.escapeVal(where.w[k].to) + Dialect.escapeVal(where.w[k].to, opts.timezone) ); break; case "not_between": query.push( buildComparisonKey(Dialect, where.t, k) + " NOT BETWEEN " + - Dialect.escapeVal(where.w[k].from) + + Dialect.escapeVal(where.w[k].from, opts.timezone) + " AND " + - Dialect.escapeVal(where.w[k].to) + Dialect.escapeVal(where.w[k].to, opts.timezone) ); break; case "like": query.push( buildComparisonKey(Dialect, where.t, k) + " LIKE " + - Dialect.escapeVal(where.w[k].expr) + Dialect.escapeVal(where.w[k].expr, opts.timezone) ); break; case "eq": @@ -122,7 +124,7 @@ function buildOrGroup(Dialect, where) { query.push( buildComparisonKey(Dialect, where.t, k) + " " + op + " " + - Dialect.escapeVal(where.w[k].val) + Dialect.escapeVal(where.w[k].val, opts.timezone) ); break; case "sql": @@ -138,7 +140,7 @@ function buildOrGroup(Dialect, where) { return Dialect.escapeId(where.w[k].where.escapes.shift()); } // ?:value - return Dialect.escapeVal(where.w[k].where.escapes.shift()); + return Dialect.escapeVal(where.w[k].where.escapes.shift(), opts.timezone); }); query.push(sql); @@ -158,10 +160,10 @@ function buildOrGroup(Dialect, where) { // #274: IN with empty arrays should be a false sentence query.push("FALSE"); } else { - query.push(buildComparisonKey(Dialect, where.t, k) + " IN " + Dialect.escapeVal(where.w[k])); + query.push(buildComparisonKey(Dialect, where.t, k) + " IN " + Dialect.escapeVal(where.w[k], opts.timezone)); } } else { - query.push(buildComparisonKey(Dialect, where.t, k) + " = " + Dialect.escapeVal(where.w[k])); + query.push(buildComparisonKey(Dialect, where.t, k) + " = " + Dialect.escapeVal(where.w[k], opts.timezone)); } } } From d03cf05895c828ce33235c47f8a31fbb5f064c1f Mon Sep 17 00:00:00 2001 From: Dirk Mccormick Date: Wed, 4 Sep 2013 15:34:24 -0400 Subject: [PATCH 061/106] Added mysql date and timezone tests --- test/integration/test-dialect-mysql.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index 34c7fc5..4680399 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -66,3 +66,29 @@ assert.equal( dialect.escapeVal(false), "false" ); + + +// Dates and Timezones +var d = new Date(1378322111133); +var tzOffsetMillis = (d.getTimezoneOffset() * 60 * 1000); + +assert.equal( + dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), + "'2013-09-04 19:15:11'" +); +assert.equal( + dialect.escapeVal(new Date(d.getTime()), 'Z'), + "'2013-09-04 19:15:11'" +); +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0000'), + "'2013-09-04 19:15:11'" +); +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0400'), + "'2013-09-04 15:15:11'" +); +assert.equal( + dialect.escapeVal(new Date(d.getTime())), + dialect.escapeVal(new Date(d.getTime()), 'local') +); From 8e8a50a11ef2dfd9aaa4664e3a183863680ffc83 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Fri, 6 Sep 2013 16:35:07 +0100 Subject: [PATCH 062/106] 0.1.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b2d4db..fb59cb4 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.12", + "version": "0.1.13", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 2ab72632bdb381e82409889d3087473d21dca60e Mon Sep 17 00:00:00 2001 From: Arek W Date: Tue, 10 Sep 2013 21:00:32 +1000 Subject: [PATCH 063/106] Allow ordering by raw sql --- lib/Select.js | 35 +++++++++++++++++++++++----------- test/integration/test-order.js | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/lib/Select.js b/lib/Select.js index 6dde1af..7f70853 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -1,4 +1,5 @@ -var Where = require("./Where"); +var Helpers = require('./Helpers'); +var Where = require("./Where"); var aggregate_functions = [ "ABS", "CEIL", "FLOOR", "ROUND", "AVG", "MIN", "MAX", @@ -180,14 +181,20 @@ function SelectQuery(Dialect, opts) { return this; }, order: function (column, dir) { - sql.order.push({ - c : Array.isArray(column) ? [ get_table_alias(column[0]), column[1] ] : column, - d : (dir == "Z" ? "DESC" : "ASC") - }); + if (Array.isArray(dir)) { + sql.order.push( + Helpers.escapeQuery(Dialect, column, dir) + ); + } else { + sql.order.push({ + c : Array.isArray(column) ? [ get_table_alias(column[0]), column[1] ] : column, + d : (dir == "Z" ? "DESC" : "ASC") + }); + } return this; }, build: function () { - var query = [], tmp, i, j, str, select_all = true; + var query = [], tmp, i, j, ord, str, select_all = true; var having = []; if (fun_stack.length) { @@ -312,7 +319,7 @@ function SelectQuery(Dialect, opts) { } if (i > 0) { query.push("ON"); - + for (ii = 0; ii < sql.from[i].j.length; ii++) { if (ii > 0) { query.push("AND"); @@ -353,10 +360,16 @@ function SelectQuery(Dialect, opts) { 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); + ord = sql.order[i]; + + if (typeof ord == 'object') { + if (Array.isArray(ord.c)) { + tmp.push(Dialect.escapeId.apply(Dialect, ord.c) + " " + ord.d); + } else { + tmp.push(Dialect.escapeId(ord.c) + " " + ord.d); + } + } else if (typeof ord == 'string') { + tmp.push(ord); } } diff --git a/test/integration/test-order.js b/test/integration/test-order.js index 8ae0809..cb966e2 100644 --- a/test/integration/test-order.js +++ b/test/integration/test-order.js @@ -20,3 +20,18 @@ assert.equal( common.Select().from('table1').order('col').order('col2', 'Z').build(), "SELECT * FROM `table1` ORDER BY `col` ASC, `col2` DESC" ); + +assert.equal( + common.Select().from('table1').order('col', []).build(), + "SELECT * FROM `table1` ORDER BY col" +); + +assert.equal( + common.Select().from('table1').order('?? DESC', ['col']).build(), + "SELECT * FROM `table1` ORDER BY `col` DESC" +); + +assert.equal( + common.Select().from('table1').order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-72.1235 42.3521)']).build(), + "SELECT * FROM `table1` ORDER BY ST_Distance(`geopoint`, ST_GeomFromText('POINT(-68.3394 27.5578)',4326))" +); From 41d16077bdb56a5d31d317d794622837fecb06b4 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 10 Sep 2013 19:55:56 +0100 Subject: [PATCH 064/106] Fixes test-order.js test --- test/integration/test-order.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/test-order.js b/test/integration/test-order.js index cb966e2..2318e8e 100644 --- a/test/integration/test-order.js +++ b/test/integration/test-order.js @@ -32,6 +32,6 @@ assert.equal( ); assert.equal( - common.Select().from('table1').order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-72.1235 42.3521)']).build(), + common.Select().from('table1').order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-68.3394 27.5578)']).build(), "SELECT * FROM `table1` ORDER BY ST_Distance(`geopoint`, ST_GeomFromText('POINT(-68.3394 27.5578)',4326))" ); From 4a3ba599db66aff329eeba330abc73d14851ba78 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 10 Sep 2013 19:56:52 +0100 Subject: [PATCH 065/106] 0.1.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb59cb4..6f27cba 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.13", + "version": "0.1.14", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From b3dae2a053c6e9c28481b24a8ab6aee25a4d6365 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 10 Sep 2013 20:08:36 +0100 Subject: [PATCH 066/106] Fixes escapeVal() in sqlite and postgres for dates and timezones (#23) --- lib/Dialects/postgresql.js | 46 ++++++++++++++++++++- lib/Dialects/sqlite.js | 46 ++++++++++++++++++++- test/integration/test-dialect-mysql.js | 17 ++++---- test/integration/test-dialect-postgresql.js | 33 +++++++++++++-- test/integration/test-dialect-sqlite.js | 33 +++++++++++++-- 5 files changed, 159 insertions(+), 16 deletions(-) diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 7b36000..4c34861 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -28,7 +28,7 @@ exports.escapeVal = function (val, timeZone) { } if (util.isDate(val)) { - return "'" + JSON.stringify(val).substr(1, 24) + "'"; + return "'" + dateToString(val, timeZone || "local") + "'"; } if (Buffer.isBuffer(val)) { @@ -51,3 +51,47 @@ exports.escapeVal = function (val, timeZone) { // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; }; + +function dateToString(date, timeZone) { + var dt = new Date(date); + + if (timeZone != 'local') { + var tz = convertTimezone(timeZone); + + dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); + if (tz !== false) { + dt.setTime(dt.getTime() + (tz * 60000)); + } + } + + var year = dt.getFullYear(); + 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()); + var milli = zeroPad(dt.getMilliseconds(), 3); + + return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; +} + +function zeroPad(number, n) { + if (arguments.length == 1) n = 2; + + number = "" + number; + + while (number.length < n) { + 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; +} diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 935bef8..f5fba7d 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -15,7 +15,7 @@ exports.escapeVal = function (val, timeZone) { } if (util.isDate(val)) { - return "'" + JSON.stringify(val).substr(1, 24) + "'"; + return "'" + dateToString(val, timeZone || "local") + "'"; } if (Buffer.isBuffer(val)) { @@ -39,3 +39,47 @@ exports.escapeVal = function (val, timeZone) { // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; }; + +function dateToString(date, timeZone) { + var dt = new Date(date); + + if (timeZone != 'local') { + var tz = convertTimezone(timeZone); + + dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); + if (tz !== false) { + dt.setTime(dt.getTime() + (tz * 60000)); + } + } + + var year = dt.getFullYear(); + 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()); + var milli = zeroPad(dt.getMilliseconds(), 3); + + return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; +} + +function zeroPad(number, n) { + if (arguments.length == 1) n = 2; + + number = "" + number; + + while (number.length < n) { + 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; +} diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index 4680399..46c5294 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -1,6 +1,8 @@ -var common = require('../common'); -var assert = require('assert'); -var dialect = common.getDialect('mysql'); +var common = require('../common'); +var assert = require('assert'); +var dialect = common.getDialect('mysql'); +var d = new Date(1378322111133); +var tzOffsetMillis = (d.getTimezoneOffset() * 60 * 1000); assert.equal( dialect.escapeId('col'), @@ -67,27 +69,26 @@ assert.equal( "false" ); - -// Dates and Timezones -var d = new Date(1378322111133); -var tzOffsetMillis = (d.getTimezoneOffset() * 60 * 1000); - assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), "'2013-09-04 19:15:11'" ); + assert.equal( dialect.escapeVal(new Date(d.getTime()), 'Z'), "'2013-09-04 19:15:11'" ); + assert.equal( dialect.escapeVal(new Date(d.getTime()), '-0000'), "'2013-09-04 19:15:11'" ); + assert.equal( dialect.escapeVal(new Date(d.getTime()), '-0400'), "'2013-09-04 15:15:11'" ); + assert.equal( dialect.escapeVal(new Date(d.getTime())), dialect.escapeVal(new Date(d.getTime()), 'local') diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index 82f1f84..c8a2e77 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -1,6 +1,8 @@ -var common = require('../common'); -var assert = require('assert'); -var dialect = common.getDialect('postgresql'); +var common = require('../common'); +var assert = require('assert'); +var dialect = common.getDialect('postgresql'); +var d = new Date(1378322111133); +var tzOffsetMillis = (d.getTimezoneOffset() * 60 * 1000); assert.equal( dialect.escapeId('col'), @@ -71,3 +73,28 @@ assert.equal( dialect.escapeVal(false), "false" ); + +assert.equal( + dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), 'Z'), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0000'), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0400'), + "'2013-09-04T15:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime())), + dialect.escapeVal(new Date(d.getTime()), 'local') +); diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index f3fc121..3f45662 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -1,6 +1,8 @@ -var common = require('../common'); -var assert = require('assert'); -var dialect = common.getDialect('sqlite'); +var common = require('../common'); +var assert = require('assert'); +var dialect = common.getDialect('sqlite'); +var d = new Date(1378322111133); +var tzOffsetMillis = (d.getTimezoneOffset() * 60 * 1000); assert.equal( dialect.escapeId('col'), @@ -66,3 +68,28 @@ assert.equal( dialect.escapeVal(false), "0" ); + +assert.equal( + dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), 'Z'), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0000'), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0400'), + "'2013-09-04T15:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime())), + dialect.escapeVal(new Date(d.getTime()), 'local') +); From af7961baa18bd2a4f6cd7cae4b51572eb0d59752 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 10 Sep 2013 20:09:01 +0100 Subject: [PATCH 067/106] 0.1.15 #23 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f27cba..fc17b35 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.14", + "version": "0.1.15", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 6849b907bb0f15aa73c82a741932e7bb8d3e55c4 Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 11 Sep 2013 09:26:44 +1000 Subject: [PATCH 068/106] DRY and all that jazz --- lib/Dialects/mysql.js | 41 +++---------------------------- lib/Dialects/postgresql.js | 49 +++----------------------------------- lib/Dialects/sqlite.js | 49 +++----------------------------------- lib/Helpers.js | 48 +++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 130 deletions(-) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index d6f1c48..b8ac37c 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -1,4 +1,5 @@ -var util = require("util"); +var util = require("util"); +var helpers = require("../Helpers"); exports.escapeId = function () { return Array.prototype.slice.apply(arguments).map(function (el) { @@ -29,7 +30,7 @@ exports.escapeVal = function (val, timeZone) { } if (util.isDate(val)) { - val = dateToString(val, timeZone || "local"); + val = helpers.dateToString(val, timeZone || "local", { dialect: 'mysql' }); } else { switch (typeof val) { case 'boolean': @@ -99,39 +100,3 @@ function bufferToString(buffer) { return "X'" + hex+ "'"; } - -function dateToString(date, timeZone) { - var dt = new Date(date); - - if (timeZone != 'local') { - var tz = convertTimezone(timeZone); - - dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); - if (tz !== false) { - dt.setTime(dt.getTime() + (tz * 60000)); - } - } - - var year = dt.getFullYear(); - 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; -} - -function zeroPad(number) { - return (number < 10) ? '0' + number : 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; -} diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 4c34861..9319c6c 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -1,4 +1,5 @@ -var util = require("util"); +var util = require("util"); +var helpers = require("../Helpers"); exports.escapeId = function () { return Array.prototype.slice.apply(arguments).map(function (el) { @@ -28,7 +29,7 @@ exports.escapeVal = function (val, timeZone) { } if (util.isDate(val)) { - return "'" + dateToString(val, timeZone || "local") + "'"; + return "'" + helpers.dateToString(val, timeZone || "local", { dialect: 'postgresql' }) + "'"; } if (Buffer.isBuffer(val)) { @@ -51,47 +52,3 @@ exports.escapeVal = function (val, timeZone) { // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; }; - -function dateToString(date, timeZone) { - var dt = new Date(date); - - if (timeZone != 'local') { - var tz = convertTimezone(timeZone); - - dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); - if (tz !== false) { - dt.setTime(dt.getTime() + (tz * 60000)); - } - } - - var year = dt.getFullYear(); - 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()); - var milli = zeroPad(dt.getMilliseconds(), 3); - - return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; -} - -function zeroPad(number, n) { - if (arguments.length == 1) n = 2; - - number = "" + number; - - while (number.length < n) { - 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; -} diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index f5fba7d..2dc372c 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -1,4 +1,5 @@ -var util = require("util"); +var util = require("util"); +var helpers = require("../Helpers"); exports.escapeId = require("./mysql").escapeId; @@ -15,7 +16,7 @@ exports.escapeVal = function (val, timeZone) { } if (util.isDate(val)) { - return "'" + dateToString(val, timeZone || "local") + "'"; + return "'" + helpers.dateToString(val, timeZone || "local", { dialect: 'sqlite' }) + "'"; } if (Buffer.isBuffer(val)) { @@ -39,47 +40,3 @@ exports.escapeVal = function (val, timeZone) { // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; }; - -function dateToString(date, timeZone) { - var dt = new Date(date); - - if (timeZone != 'local') { - var tz = convertTimezone(timeZone); - - dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); - if (tz !== false) { - dt.setTime(dt.getTime() + (tz * 60000)); - } - } - - var year = dt.getFullYear(); - 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()); - var milli = zeroPad(dt.getMilliseconds(), 3); - - return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; -} - -function zeroPad(number, n) { - if (arguments.length == 1) n = 2; - - number = "" + number; - - while (number.length < n) { - 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; -} diff --git a/lib/Helpers.js b/lib/Helpers.js index a362bed..e8a5c26 100644 --- a/lib/Helpers.js +++ b/lib/Helpers.js @@ -12,3 +12,51 @@ module.exports.escapeQuery = function (Dialect, query, args) { } }); } + +module.exports.dateToString = function (date, timeZone, opts) { + var dt = new Date(date); + + if (timeZone != 'local') { + var tz = convertTimezone(timeZone); + + dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); + if (tz !== false) { + dt.setTime(dt.getTime() + (tz * 60000)); + } + } + + var year = dt.getFullYear(); + 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()); + var milli = zeroPad(dt.getMilliseconds(), 3); + + if (opts.dialect == 'mysql') { + return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second; + } else { + return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; + } +} + +function zeroPad(number, n) { + if (arguments.length == 1) n = 2; + + number = "" + number; + + while (number.length < n) { + 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; +} From 57449ca5beff9ca1de4a9b72b33be4f0d90a0f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Wolski?= Date: Mon, 7 Oct 2013 15:57:22 +0200 Subject: [PATCH 069/106] Adds .not_in() comparator --- lib/Comparators.js | 3 +++ lib/Where.js | 2 ++ test/integration/test-where.js | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/lib/Comparators.js b/lib/Comparators.js index a216c63..5f0e450 100644 --- a/lib/Comparators.js +++ b/lib/Comparators.js @@ -26,6 +26,9 @@ exports.lt = function (v) { exports.lte = function (v) { return createSpecialObject({ val: v }, 'lte'); }; +exports.not_in = function (v) { + return createSpecialObject({ val: v }, 'not_in'); +}; function createSpecialObject(obj, tag) { Object.defineProperty(obj, "sql_comparator", { diff --git a/lib/Where.js b/lib/Where.js index 7ee567b..37cab9a 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -113,6 +113,7 @@ function buildOrGroup(Dialect, where, opts) { case "gte": case "lt": case "lte": + case "not_in": switch (op) { case "eq" : op = (where.w[k].val === null ? "IS" : "="); break; case "ne" : op = (where.w[k].val === null ? "IS NOT" : "<>"); break; @@ -120,6 +121,7 @@ function buildOrGroup(Dialect, where, opts) { case "gte" : op = ">="; break; case "lt" : op = "<"; break; case "lte" : op = "<="; break; + case "not_in" : op = "NOT IN"; break; } query.push( buildComparisonKey(Dialect, where.t, k) + diff --git a/test/integration/test-where.js b/test/integration/test-where.js index c199ffd..48a8694 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -155,6 +155,11 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" ); +assert.equal( + common.Select().from('table1').where({ col: common.Query.not_in([ 1, 2, 3 ]) }).build(), + "SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" +); + assert.equal( common.Select().from('table1').where({ __sql: [["LOWER(`stuff`) LIKE 'peaches'"]] }).build(), "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" From c2f44edb5979d5625416b09395bd4e711e262180 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Sat, 2 Nov 2013 18:14:08 -0400 Subject: [PATCH 070/106] Milli-second accuracy for mysql --- lib/Helpers.js | 2 +- test/integration/test-dialect-mysql.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Helpers.js b/lib/Helpers.js index e8a5c26..3cbe24f 100644 --- a/lib/Helpers.js +++ b/lib/Helpers.js @@ -34,7 +34,7 @@ module.exports.dateToString = function (date, timeZone, opts) { var milli = zeroPad(dt.getMilliseconds(), 3); if (opts.dialect == 'mysql') { - return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second; + return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + milli; } else { return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; } diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index 46c5294..62653b7 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -71,22 +71,22 @@ assert.equal( assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), - "'2013-09-04 19:15:11'" + "'2013-09-04 19:15:11.133'" ); assert.equal( dialect.escapeVal(new Date(d.getTime()), 'Z'), - "'2013-09-04 19:15:11'" + "'2013-09-04 19:15:11.133'" ); assert.equal( dialect.escapeVal(new Date(d.getTime()), '-0000'), - "'2013-09-04 19:15:11'" + "'2013-09-04 19:15:11.133'" ); assert.equal( dialect.escapeVal(new Date(d.getTime()), '-0400'), - "'2013-09-04 15:15:11'" + "'2013-09-04 15:15:11.133'" ); assert.equal( From c9e516e9b3af2f7dbe5c7f0d4e6035d5e6f9f1ae Mon Sep 17 00:00:00 2001 From: Jeremy Worboys Date: Wed, 20 Nov 2013 21:07:26 +1100 Subject: [PATCH 071/106] Fix global leak of variable `ii` --- lib/Select.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Select.js b/lib/Select.js index 7f70853..f594682 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -194,7 +194,7 @@ function SelectQuery(Dialect, opts) { return this; }, build: function () { - var query = [], tmp, i, j, ord, str, select_all = true; + var query = [], tmp, i, ii, j, ord, str, select_all = true; var having = []; if (fun_stack.length) { From b5b4a5d3af073ac2ea80ec2f564dacd1a3d95970 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 5 Dec 2013 18:24:15 +0000 Subject: [PATCH 072/106] Adds .npmignore --- .npmignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..a58cf7a --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +*.sublime-* +*.njsproj +.DS_Store +node_modules +test.js From 3f145ee0bcb2fa001a01d76caca95bda7125afa1 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Thu, 5 Dec 2013 18:24:32 +0000 Subject: [PATCH 073/106] 0.1.16 --- Readme.md | 4 +--- package.json | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 2d2bd4d..f78809f 100644 --- a/Readme.md +++ b/Readme.md @@ -16,6 +16,4 @@ npm install sql-query ## About -This module is used by [ORM](http://dresende.github.com/node-orm2) to build SQL queries in the different supported -dialects. Sorry there is no API documentation but there are a couple of tests you can read and find out how to use -it if you want. +This module is used by [ORM](http://dresende.github.com/node-orm2) to build SQL queries in the different supported dialects. Sorry there is no API documentation but there are a couple of tests you can read and find out how to use it if you want. diff --git a/package.json b/package.json index fc17b35..4e7f4b5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.15", + "version": "0.1.16", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 8ecf962eeeb4aa244ec1159ca75d603ce99212ba Mon Sep 17 00:00:00 2001 From: Lawrence Selvy Date: Wed, 19 Feb 2014 23:12:29 -0500 Subject: [PATCH 074/106] #29 - Allows null and undefined to be treated differently. --- lib/Dialects/postgresql.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 9319c6c..6db8f18 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -17,9 +17,11 @@ exports.escapeId = function () { }; exports.escapeVal = function (val, timeZone) { - if (val === undefined || val === null) { - return 'NULL'; - } + if (val === undefined){ + return 'DEFAULT'; + }else if(val === null){ + return 'NULL'; + } if (Array.isArray(val)) { if (val.length === 1 && Array.isArray(val[0])) { From 08efc2e9424ed3283fa3db49cb3b7d7e2d4989e8 Mon Sep 17 00:00:00 2001 From: Lawrence Selvy Date: Thu, 20 Feb 2014 07:49:02 -0500 Subject: [PATCH 075/106] #30 - Neglected to fix the test case for undefined. Should pass now --- test/integration/test-dialect-postgresql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index c8a2e77..e131dab 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -26,7 +26,7 @@ assert.equal( assert.equal( dialect.escapeVal(undefined), - 'NULL' + 'DEFAULT' ); assert.equal( From cc4223bd54fa8dce7982c837554b77582dd2977a Mon Sep 17 00:00:00 2001 From: Arek W Date: Mon, 7 Apr 2014 21:02:46 +1000 Subject: [PATCH 076/106] Allow custom named properties and custom selects --- lib/Dialects/mysql.js | 4 +++ lib/Dialects/postgresql.js | 4 +++ lib/Dialects/sqlite.js | 4 +++ lib/Select.js | 56 +++++++++++++++++++++----------------- package.json | 2 +- 5 files changed, 44 insertions(+), 26 deletions(-) diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index b8ac37c..b1a65c3 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -1,6 +1,10 @@ var util = require("util"); var helpers = require("../Helpers"); +exports.escape = function (query, args) { + return helpers.escapeQuery(exports, query, args); +} + exports.escapeId = function () { return Array.prototype.slice.apply(arguments).map(function (el) { if (typeof el == "object") { diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 6db8f18..9f26c1c 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -1,6 +1,10 @@ var util = require("util"); var helpers = require("../Helpers"); +exports.escape = function (query, args) { + return helpers.escapeQuery(exports, query, args); +} + exports.escapeId = function () { return Array.prototype.slice.apply(arguments).map(function (el) { if (typeof el == "object") { diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 2dc372c..234e162 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -1,6 +1,10 @@ var util = require("util"); var helpers = require("../Helpers"); +exports.escape = function (query, args) { + return helpers.escapeQuery(exports, query, args); +} + exports.escapeId = require("./mysql").escapeId; exports.escapeVal = function (val, timeZone) { diff --git a/lib/Select.js b/lib/Select.js index f594682..1bff327 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -247,38 +247,44 @@ function SelectQuery(Dialect, opts) { continue; } - if (!sql.from[i].select[j].f) continue; - str = sql.from[i].select[j].f + "("; - if (sql.from[i].select[j].c && !Array.isArray(sql.from[i].select[j].c)) { - sql.from[i].select[j].c = [ sql.from[i].select[j].c ]; - } + if (sql.from[i].select[j].f) { + str = sql.from[i].select[j].f + "("; + + if (sql.from[i].select[j].c && !Array.isArray(sql.from[i].select[j].c)) { + sql.from[i].select[j].c = [ sql.from[i].select[j].c ]; + } - if (Array.isArray(sql.from[i].select[j].c)) { - str += sql.from[i].select[j].c.map(function (el) { - if (typeof el.type == "function") { - switch (el.type()) { - case "text": - return Dialect.escapeVal(el.data, opts.timezone); - default: - return el; + if (Array.isArray(sql.from[i].select[j].c)) { + str += sql.from[i].select[j].c.map(function (el) { + if (typeof el.type == "function") { + switch (el.type()) { + case "text": + return Dialect.escapeVal(el.data, opts.timezone); + default: + return el; + } } - } - if (typeof el != "string") { - return el; - } - if (sql.from.length == 1) { - return Dialect.escapeId(el); - } else { - return Dialect.escapeId(sql.from[i].a, el); - } - }).join(", "); + if (typeof el != "string") { + return el; + } + if (sql.from.length == 1) { + return Dialect.escapeId(el); + } else { + return Dialect.escapeId(sql.from[i].a, el); + } + }).join(", "); + } else { + str += "*"; + } + str += ")"; + } else if (sql.from[i].select[j].sql) { + str = '(' + sql.from[i].select[j].sql + ')'; } else { - str += "*"; + continue; } - str += ")"; str += (sql.from[i].select[j].a ? " AS " + Dialect.escapeId(sql.from[i].select[j].a) : ""); if (sql.from[i].select[j].s && sql.from[i].select[j].s.length > 0) { diff --git a/package.json b/package.json index 4e7f4b5..d33cc49 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.16", + "version": "0.1.17", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From da0033835040ec05196f8070906e641322e0d108 Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 7 May 2014 20:43:47 +1000 Subject: [PATCH 077/106] Add custom select test --- test/integration/test-select.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/integration/test-select.js b/test/integration/test-select.js index 76d8b98..7b8b81e 100644 --- a/test/integration/test-select.js +++ b/test/integration/test-select.js @@ -36,6 +36,13 @@ assert.equal( "SELECT * FROM `table1`" ); +assert.equal( + common.Select().from('table1').select( + ['abc','def', { a: 'ghi', sql: 'SOMEFUNC(ghi)' }] + ).build(), + "SELECT `abc`, `def`, (SOMEFUNC(ghi)) AS `ghi` FROM `table1`" +); + assert.equal( common.Select().calculateFoundRows().from('table1').build(), "SELECT SQL_CALC_FOUND_ROWS * FROM `table1`" From 5aefbf7af62f853e611b7ca5100be140a2736f83 Mon Sep 17 00:00:00 2001 From: cfv1984 Date: Sat, 10 May 2014 03:42:34 +0200 Subject: [PATCH 078/106] Added a CREATE TABLE builder --- lib/Create.js | 112 ++++++++++++++++++++++++++++++++ lib/Dialects/mysql.js | 9 +++ lib/Dialects/postgresql.js | 9 +++ lib/Dialects/sqlite.js | 10 +++ lib/Query.js | 4 ++ test/common.js | 4 ++ test/integration/test-create.js | 30 +++++++++ 7 files changed, 178 insertions(+) create mode 100644 lib/Create.js create mode 100644 test/integration/test-create.js diff --git a/lib/Create.js b/lib/Create.js new file mode 100644 index 0000000..df2f4d8 --- /dev/null +++ b/lib/Create.js @@ -0,0 +1,112 @@ +exports.CreateQuery = CreateQuery; + +/** + * Really lightweight templating + * @param template + * @param args + * @returns {string} + */ +var tmpl = function (template, args) { + var has = {}.hasOwnProperty; + for (var key in args) { + if (!has.call(args, key)) { + continue; + } + var token = '{{' + key + '}}'; + template = template.split(token).join(args[key]); + } + + return template; +}; +/** + * Builds a list of fields according to the used dialect + * @param dialect + * @param structure + * @returns {string} + */ +var buildFieldsList = function (dialect, structure) { + if (!structure) { + return ""; + } + var tpl = "'{{NAME}}' {{TYPE}}", fields = [], has = {}.hasOwnProperty; + for (var field in structure) { + if (has.call(structure, field)) { + fields.push(tmpl(tpl, { + NAME: field, + TYPE: dialect.DataTypes[structure[field]] + })); + } + } + + return fields.join(','); +}; + +/** + * Instantiate a new CREATE-type query builder + * @param Dialect + * @param opts + * @returns {{table: table, field: field, fields: fields, build: build}} + * @constructor + */ +function CreateQuery(Dialect, opts) { + var sql = {}; + var tableName = null; + var structure = {}; + + return { + /** + * Set the table name + * @param table_name + * @returns {*} + */ + table: function (table_name) { + tableName = table_name; + + return this; + }, + /** + * Add a field + * @param name + * @param type + * @returns {Object} + */ + field: function (name, type) { + structure[name] = type; + + return this; + }, + /** + * Set all the fields + * @param fields + * @returns {Object} + */ + fields: function (fields) { + if (!fields) { + return structure; + } + structure = fields; + + return this; + }, + + /** + * Build a query from the passed params + * @returns {string} + */ + build: function () { + var query, fieldsList, template = "CREATE TABLE '{{TABLE_NAME}}'({{FIELDS_LIST}})"; + + if(!tableName){ + return ''; + } + + fieldsList = buildFieldsList(Dialect, structure); + + return tmpl(template, { + TABLE_NAME: tableName, + FIELDS_LIST: fieldsList + }); + + } + }; +} diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index b1a65c3..1d9afa9 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -1,6 +1,15 @@ var util = require("util"); var helpers = require("../Helpers"); +exports.DataTypes = { + id: 'INTEGER PRIMARY KEY AUTO_INCREMENT', + int: 'INTEGER', + float: 'FLOAT(12,2)', + bool: 'TINYINT(1)', + text: 'TEXT' +}; + + exports.escape = function (query, args) { return helpers.escapeQuery(exports, query, args); } diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 9f26c1c..4422cbf 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -1,6 +1,15 @@ var util = require("util"); var helpers = require("../Helpers"); +exports.DataTypes = { + id: 'SERIAL PRIMARY KEY', + int: 'INTEGER', + float: 'REAL', + bool: 'SMALLINT', + text: 'TEXT' +}; + + exports.escape = function (query, args) { return helpers.escapeQuery(exports, query, args); } diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 234e162..f05af53 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -1,6 +1,16 @@ var util = require("util"); var helpers = require("../Helpers"); + +exports.DataTypes = { + isSQLITE: true, + id: 'INTEGER PRIMARY KEY AUTOINCREMENT', + int: 'INTEGER', + float: 'FLOAT(12,2)', + bool: 'TINYINT(1)', + text: 'TEXT' +}; + exports.escape = function (query, args) { return helpers.escapeQuery(exports, query, args); } diff --git a/lib/Query.js b/lib/Query.js index 4203812..bb66cda 100644 --- a/lib/Query.js +++ b/lib/Query.js @@ -1,3 +1,4 @@ +var CreateQuery = require("./Create").CreateQuery; var SelectQuery = require("./Select").SelectQuery; var InsertQuery = require("./Insert").InsertQuery; var UpdateQuery = require("./Update").UpdateQuery; @@ -26,6 +27,9 @@ function Query(opts) { escape : Helpers.escapeQuery.bind(Helpers, Dialect), escapeId : Dialect.escapeId.bind(Dialect), escapeVal : Dialect.escapeVal.bind(Dialect), + create: function(){ + return new CreateQuery(Dialect, opts); + }, select: function () { return new SelectQuery(Dialect, opts); }, diff --git a/test/common.js b/test/common.js index 04a9ea6..881a714 100644 --- a/test/common.js +++ b/test/common.js @@ -9,7 +9,11 @@ common.Select = function () { return q.select(); }; +common.Create = function(){ + var q = new (Query.Query)(); + return q.create(); +}; common.Insert = function () { var q = new (Query.Query)(); diff --git a/test/integration/test-create.js b/test/integration/test-create.js new file mode 100644 index 0000000..02ccbb1 --- /dev/null +++ b/test/integration/test-create.js @@ -0,0 +1,30 @@ +var common = require('../common'); +var assert = require('assert'); + +assert.equal( + common.Create().table('table1').build(), + "CREATE TABLE 'table1'()" +); + +assert.equal( + common.Create().table('table1').field('id','id').build(), + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT)" +); + +assert.equal( + common.Create().table('table1').fields({id: 'id', a_text: 'text'}).build(), + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_text' TEXT)" +); +assert.equal( + common.Create().table('table1').fields({id: 'id', a_num: 'int'}).build(), + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' INTEGER)" +); + +assert.equal( + common.Create().table('table1').fields({id: 'id', a_num: 'float'}).build(), + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' FLOAT(12,2))" +); +assert.equal( + common.Create().table('table1').fields({id: 'id', a_bool: 'bool'}).build(), + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_bool' TINYINT(1))" +); \ No newline at end of file From a98cae1b990c9a8d81de1d869c33a39beafcbf25 Mon Sep 17 00:00:00 2001 From: Arek W Date: Mon, 12 May 2014 22:00:32 +1000 Subject: [PATCH 079/106] Remove ancient node versions from travis & bump version --- .travis.yml | 2 -- package.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d523c5f..09d3ef3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,4 @@ language: node_js node_js: - - 0.4 - - 0.6 - 0.8 - 0.10 diff --git a/package.json b/package.json index d33cc49..27cc51e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.17", + "version": "0.1.18", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 9eaf44c19cf012867bde1a4512d75af4b98f80a8 Mon Sep 17 00:00:00 2001 From: Arek W Date: Mon, 12 May 2014 22:03:12 +1000 Subject: [PATCH 080/106] Strings for travis version nums --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 09d3ef3..b9207e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js node_js: - - 0.8 - - 0.10 + - '0.8' + - '0.10' From 48815f33cbd63f70fea85a13eef5b6cb9551a52f Mon Sep 17 00:00:00 2001 From: Arek W Date: Mon, 12 May 2014 22:13:47 +1000 Subject: [PATCH 081/106] Allow passing nulls to select functions. Closes #32 --- lib/Select.js | 3 +++ package.json | 2 +- test/integration/test-select-type.js | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/Select.js b/lib/Select.js index 1bff327..a414ecb 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -258,6 +258,9 @@ function SelectQuery(Dialect, opts) { if (Array.isArray(sql.from[i].select[j].c)) { str += sql.from[i].select[j].c.map(function (el) { + if (!el) { + return Dialect.escapeVal(el); + } if (typeof el.type == "function") { switch (el.type()) { case "text": diff --git a/package.json b/package.json index 27cc51e..c194b6c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.18", + "version": "0.1.19", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" diff --git a/test/integration/test-select-type.js b/test/integration/test-select-type.js index 60aa066..17cfb78 100644 --- a/test/integration/test-select-type.js +++ b/test/integration/test-select-type.js @@ -11,6 +11,11 @@ assert.equal( "SELECT MYFUN(`col1`, `col2`) FROM `table1`" ); +assert.equal( + common.Select().from('table1').fun('dbo.fnBalance', [ 80, null, null], 'balance').build(), + "SELECT DBO.FNBALANCE(80, NULL, NULL) AS `balance` FROM `table1`" +); + assert.equal( common.Select().from('table1').fun('myfun', [ 'col1', 'col2'], 'alias').build(), "SELECT MYFUN(`col1`, `col2`) AS `alias` FROM `table1`" From e9532328889d690eb547df361194d0b86480b385 Mon Sep 17 00:00:00 2001 From: Arek W Date: Tue, 13 May 2014 16:34:59 +1000 Subject: [PATCH 082/106] escapeQuery shouldn't modify provided array --- lib/Helpers.js | 8 +++++--- package.json | 2 +- test/lib/test-helpers.js | 13 +++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/Helpers.js b/lib/Helpers.js index 3cbe24f..6cd10ad 100644 --- a/lib/Helpers.js +++ b/lib/Helpers.js @@ -4,11 +4,13 @@ // into: // "name LIKE 'John' AND age > 23" module.exports.escapeQuery = function (Dialect, query, args) { - return query.replace(/[?]+/g, function (match) { + var pos = 0; + + return query.replace(/\?{1,2}/g, function (match) { if (match == '?') { - return Dialect.escapeVal(args.shift()); + return Dialect.escapeVal(args[pos++]); } else if (match == '??') { - return Dialect.escapeId(args.shift()); + return Dialect.escapeId(args[pos++]); } }); } diff --git a/package.json b/package.json index c194b6c..bd588fa 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.19", + "version": "0.1.20", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" diff --git a/test/lib/test-helpers.js b/test/lib/test-helpers.js index c230e0c..8c376bc 100644 --- a/test/lib/test-helpers.js +++ b/test/lib/test-helpers.js @@ -33,3 +33,16 @@ assert.equal( Helpers.escapeQuery(Dialect, "SELECT * FROM abc WHERE LOWER(abc.??) LIKE ? AND ?? == ?", ['stuff', 'peaches', 'number']), "SELECT * FROM abc WHERE LOWER(abc.`stuff`) LIKE 'peaches' AND `number` == NULL" ); + +// Should match at most 2 '?' at a time +assert.equal( + Helpers.escapeQuery(Dialect, "?????", ['a', 'b', 'c']), + "`a``b`'c'" +); + +// Should not modify provided array +var arr = ['a', 'b', 'c']; +assert.equal( + arr.join(','), + 'a,b,c' +) From 3a1a8a9ba0242b67ed2063c24c36aabf3c811f3a Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 21 May 2014 16:41:14 +1000 Subject: [PATCH 083/106] Revert different treatment of and . It generates invalid SQL queries when users accidentally set something to undefined rather than null. --- lib/Dialects/postgresql.js | 8 +++----- package.json | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 4422cbf..5b40275 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -30,11 +30,9 @@ exports.escapeId = function () { }; exports.escapeVal = function (val, timeZone) { - if (val === undefined){ - return 'DEFAULT'; - }else if(val === null){ - return 'NULL'; - } + if (val === undefined || val === null) { + return 'NULL'; + } if (Array.isArray(val)) { if (val.length === 1 && Array.isArray(val[0])) { diff --git a/package.json b/package.json index bd588fa..4f46514 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.20", + "version": "0.1.21", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From f9585059d2dadee3cb0e785f0cdffbfa021a9170 Mon Sep 17 00:00:00 2001 From: Arek W Date: Fri, 23 May 2014 09:31:01 +1000 Subject: [PATCH 084/106] Fix tests --- test/integration/test-dialect-postgresql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index e131dab..c8a2e77 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -26,7 +26,7 @@ assert.equal( assert.equal( dialect.escapeVal(undefined), - 'DEFAULT' + 'NULL' ); assert.equal( From d8d3c56bae6de71a8b55356056cf6edc1fc50bd4 Mon Sep 17 00:00:00 2001 From: iammapping Date: Thu, 19 Jun 2014 13:40:12 +0800 Subject: [PATCH 085/106] add a "NOT LIKE" comparator --- lib/Comparators.js | 3 +++ lib/Where.js | 7 +++++++ test/integration/test-where.js | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/lib/Comparators.js b/lib/Comparators.js index 5f0e450..5ace73c 100644 --- a/lib/Comparators.js +++ b/lib/Comparators.js @@ -7,6 +7,9 @@ exports.not_between = function (a, b) { exports.like = function (expr) { return createSpecialObject({ expr: expr }, 'like'); }; +exports.not_like = function (expr) { + return createSpecialObject({ expr: expr }, 'not_like'); +}; exports.eq = function (v) { return createSpecialObject({ val: v }, 'eq'); diff --git a/lib/Where.js b/lib/Where.js index 37cab9a..513591a 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -107,6 +107,13 @@ function buildOrGroup(Dialect, where, opts) { Dialect.escapeVal(where.w[k].expr, opts.timezone) ); break; + case "not_like": + query.push( + buildComparisonKey(Dialect, where.t, k) + + " NOT LIKE " + + Dialect.escapeVal(where.w[k].expr, opts.timezone) + ); + break; case "eq": case "ne": case "gt": diff --git a/test/integration/test-where.js b/test/integration/test-where.js index 48a8694..d5c9259 100644 --- a/test/integration/test-where.js +++ b/test/integration/test-where.js @@ -155,6 +155,11 @@ assert.equal( "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" ); +assert.equal( + common.Select().from('table1').where({ col: common.Query.not_like('abc') }).build(), + "SELECT * FROM `table1` WHERE `col` NOT LIKE 'abc'" +); + assert.equal( common.Select().from('table1').where({ col: common.Query.not_in([ 1, 2, 3 ]) }).build(), "SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" From e8b6cc538b1a7a38c0ec3f4c7c7a76eeff5d5579 Mon Sep 17 00:00:00 2001 From: Christiaan Westerbeek Date: Wed, 9 Jul 2014 09:24:10 +0200 Subject: [PATCH 086/106] Add support for mssql --- Readme.md | 1 + lib/Dialects/mssql.js | 66 ++++++++++++++++++ test/integration/test-dialect-mssql.js | 95 ++++++++++++++++++++++++++ 3 files changed, 162 insertions(+) create mode 100644 lib/Dialects/mssql.js create mode 100644 test/integration/test-dialect-mssql.js diff --git a/Readme.md b/Readme.md index f78809f..7bb37a2 100644 --- a/Readme.md +++ b/Readme.md @@ -13,6 +13,7 @@ npm install sql-query - MySQL - PostgreSQL - SQLite +- MSSQL ## About diff --git a/lib/Dialects/mssql.js b/lib/Dialects/mssql.js new file mode 100644 index 0000000..9937d34 --- /dev/null +++ b/lib/Dialects/mssql.js @@ -0,0 +1,66 @@ +var util = require("util"); +var helpers = require("../Helpers"); + +exports.DataTypes = { + id: 'INT IDENTITY(1,1) NOT NULL PRIMARY KEY', + int: 'INT', + float: 'FLOAT', + bool: 'BIT', + text: 'TEXT' +}; + + +exports.escape = function (query, args) { + return helpers.escapeQuery(exports, query, args); +} + +exports.escapeId = function () { + return Array.prototype.slice.apply(arguments).map(function (el) { + if (typeof el == "object") { + return el.str.replace(/\?:(id|value)/g, function (m) { + if (m == "?:id") { + return exports.escapeId(el.escapes.shift()); + } + // ?:value + return exports.escapeVal(el.escapes.shift()); + }); + } + return "[" + el + "]"; + }).join("."); +}; + +exports.escapeVal = function (val, timeZone) { + if (val === undefined || val === null) { + return 'NULL'; + } + + if (Array.isArray(val)) { + if (val.length === 1 && Array.isArray(val[0])) { + return "(" + val[0].map(exports.escapeVal.bind(this)) + ")"; + } + return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; + } + + if (util.isDate(val)) { + return "'" + helpers.dateToString(val, timeZone || "local", { dialect: 'mssql' }) + "'"; + } + + if (Buffer.isBuffer(val)) { + return "X'" + val.toString("hex") + "'"; + } + + switch (typeof val) { + case "number": + if (!isFinite(val)) { + val = val.toString(); + break; + } + return val; + case "boolean": + return val ? 1 : 0; + case "function": + return val(exports); + } + + return "'" + val.replace(/\'/g, "''") + "'"; +}; diff --git a/test/integration/test-dialect-mssql.js b/test/integration/test-dialect-mssql.js new file mode 100644 index 0000000..db0d0f5 --- /dev/null +++ b/test/integration/test-dialect-mssql.js @@ -0,0 +1,95 @@ +var common = require('../common'); +var assert = require('assert'); +var dialect = common.getDialect('mssql'); +var d = new Date(1378322111133); +var tzOffsetMillis = (d.getTimezoneOffset() * 60 * 1000); + +assert.equal( + dialect.escapeId('col'), + "[col]" +); + +assert.equal( + dialect.escapeId('table', 'col'), + "[table].[col]" +); + +assert.equal( + dialect.escapeId('table', 'co\'l'), + "[table].[co\'l]" +); + +assert.equal( + dialect.escapeVal(undefined), + 'NULL' +); + +assert.equal( + dialect.escapeVal(null), + 'NULL' +); + +assert.equal( + dialect.escapeVal(123), + "123" +); + +assert.equal( + dialect.escapeVal(NaN), + "'NaN'" +); + +assert.equal( + dialect.escapeVal(Infinity), + "'Infinity'" +); + +assert.equal( + dialect.escapeVal('abc'), + "'abc'" +); + +assert.equal( + dialect.escapeVal('ab\'c'), + "'ab''c'" +); + +assert.equal( + dialect.escapeVal([ 1, 'abc', 'a\'' ]), + "(1, 'abc', 'a''')" +); + +assert.equal( + dialect.escapeVal(true), + "1" +); + +assert.equal( + dialect.escapeVal(false), + "0" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), 'Z'), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0000'), + "'2013-09-04T19:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime()), '-0400'), + "'2013-09-04T15:15:11.133Z'" +); + +assert.equal( + dialect.escapeVal(new Date(d.getTime())), + dialect.escapeVal(new Date(d.getTime()), 'local') +); From cee723d244bed906de1098d0dbd25349f4cd2cf8 Mon Sep 17 00:00:00 2001 From: Arek W Date: Thu, 21 Aug 2014 20:24:59 +1000 Subject: [PATCH 087/106] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4f46514..fcbf8bf 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.21", + "version": "0.1.22", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 117ced2ea09d8829d896c2640d8be68e500fbe16 Mon Sep 17 00:00:00 2001 From: Arek W Date: Thu, 21 Aug 2014 20:29:52 +1000 Subject: [PATCH 088/106] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fcbf8bf..28b1093 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.22", + "version": "0.1.23", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 926e497b6af6e7ffd5c9e87dd9c5faebc014ee85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Thu, 11 Dec 2014 02:50:50 +0100 Subject: [PATCH 089/106] Allow insertion of empty row using default values --- lib/Dialects/mssql.js | 2 ++ lib/Dialects/mysql.js | 2 ++ lib/Dialects/postgresql.js | 2 ++ lib/Dialects/sqlite.js | 2 ++ lib/Insert.js | 8 ++++++-- 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/Dialects/mssql.js b/lib/Dialects/mssql.js index 9937d34..b99ebe8 100644 --- a/lib/Dialects/mssql.js +++ b/lib/Dialects/mssql.js @@ -64,3 +64,5 @@ exports.escapeVal = function (val, timeZone) { return "'" + val.replace(/\'/g, "''") + "'"; }; + +exports.defaultValuesStmt = "DEFAULT VALUES"; diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index 1d9afa9..1e9c180 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -113,3 +113,5 @@ function bufferToString(buffer) { return "X'" + hex+ "'"; } + +exports.defaultValuesStmt = "VALUES()"; diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 5b40275..c3bfc3c 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -65,3 +65,5 @@ exports.escapeVal = function (val, timeZone) { // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; }; + +exports.defaultValuesStmt = "DEFAULT VALUES"; diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index f05af53..33ecfe3 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -54,3 +54,5 @@ exports.escapeVal = function (val, timeZone) { // Google 'postgresql standard_conforming_strings' for details. return "'" + val.replace(/\'/g, "''") + "'"; }; + +exports.defaultValuesStmt = "DEFAULT VALUES"; diff --git a/lib/Insert.js b/lib/Insert.js index 6d24e99..cdda986 100644 --- a/lib/Insert.js +++ b/lib/Insert.js @@ -25,8 +25,12 @@ function InsertQuery(Dialect, opts) { cols.push(Dialect.escapeId(k)); vals.push(Dialect.escapeVal(sql.set[k], opts.timezone)); } - query.push("(" + cols.join(", ") + ")"); - query.push("VALUES (" + vals.join(", ") + ")"); + if (cols.length == 0) { + query.push(Dialect.defaultValuesStmt); + } else { + query.push("(" + cols.join(", ") + ")"); + query.push("VALUES (" + vals.join(", ") + ")"); + } } return query.join(" "); From 30e569ecda7cb99c21552a0140074b4b7597bce7 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Mon, 22 Dec 2014 18:31:04 +0000 Subject: [PATCH 090/106] 0.1.24 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 28b1093..a447f1b 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.23", + "version": "0.1.24", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From 5f12c91443cc5f7de967c487d2de4113a7db01cd Mon Sep 17 00:00:00 2001 From: Arek W Date: Sat, 21 Mar 2015 22:59:02 +0000 Subject: [PATCH 091/106] Add tests for #37 --- test/integration/test-dialect-mssql.js | 5 +++++ test/integration/test-dialect-mysql.js | 5 +++++ test/integration/test-dialect-postgresql.js | 5 +++++ test/integration/test-dialect-sqlite.js | 5 +++++ test/integration/test-insert.js | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/test/integration/test-dialect-mssql.js b/test/integration/test-dialect-mssql.js index db0d0f5..1542b7e 100644 --- a/test/integration/test-dialect-mssql.js +++ b/test/integration/test-dialect-mssql.js @@ -93,3 +93,8 @@ assert.equal( dialect.escapeVal(new Date(d.getTime())), dialect.escapeVal(new Date(d.getTime()), 'local') ); + +assert.equal( + dialect.defaultValuesStmt, + "DEFAULT VALUES" +); diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index 62653b7..f174c70 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -93,3 +93,8 @@ assert.equal( dialect.escapeVal(new Date(d.getTime())), dialect.escapeVal(new Date(d.getTime()), 'local') ); + +assert.equal( + dialect.defaultValuesStmt, + "VALUES()" +); diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index c8a2e77..685b7f0 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -98,3 +98,8 @@ assert.equal( dialect.escapeVal(new Date(d.getTime())), dialect.escapeVal(new Date(d.getTime()), 'local') ); + +assert.equal( + dialect.defaultValuesStmt, + "DEFAULT VALUES" +); diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index 3f45662..d25e72e 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -93,3 +93,8 @@ assert.equal( dialect.escapeVal(new Date(d.getTime())), dialect.escapeVal(new Date(d.getTime()), 'local') ); + +assert.equal( + dialect.defaultValuesStmt, + "DEFAULT VALUES" +); diff --git a/test/integration/test-insert.js b/test/integration/test-insert.js index 7b2171c..3c272bf 100644 --- a/test/integration/test-insert.js +++ b/test/integration/test-insert.js @@ -6,6 +6,11 @@ assert.equal( "INSERT INTO `table1`" ); +assert.equal( + common.Insert().into('table1').set({}).build(), + "INSERT INTO `table1` VALUES()" +); + assert.equal( common.Insert().into('table1').set({ col: 1 }).build(), "INSERT INTO `table1` (`col`) VALUES (1)" From af8d603c021cd15dd8e23816ec0f18cd932a68ea Mon Sep 17 00:00:00 2001 From: Arek W Date: Sat, 21 Mar 2015 23:19:05 +0000 Subject: [PATCH 092/106] Lint --- lib/Create.js | 146 ++++++++++++++++++------------------- lib/Dialects/mssql.js | 12 +-- lib/Dialects/mysql.js | 10 +-- lib/Dialects/postgresql.js | 10 +-- lib/Dialects/sqlite.js | 12 +-- lib/Helpers.js | 64 ++++++++-------- lib/Query.js | 6 +- lib/Select.js | 24 +++--- lib/Where.js | 22 +++--- 9 files changed, 153 insertions(+), 153 deletions(-) diff --git a/lib/Create.js b/lib/Create.js index df2f4d8..1ffb028 100644 --- a/lib/Create.js +++ b/lib/Create.js @@ -7,16 +7,16 @@ exports.CreateQuery = CreateQuery; * @returns {string} */ var tmpl = function (template, args) { - var has = {}.hasOwnProperty; - for (var key in args) { - if (!has.call(args, key)) { - continue; - } - var token = '{{' + key + '}}'; - template = template.split(token).join(args[key]); - } + var has = {}.hasOwnProperty; + for (var key in args) { + if (!has.call(args, key)) { + continue; + } + var token = '{{' + key + '}}'; + template = template.split(token).join(args[key]); + } - return template; + return template; }; /** * Builds a list of fields according to the used dialect @@ -25,20 +25,20 @@ var tmpl = function (template, args) { * @returns {string} */ var buildFieldsList = function (dialect, structure) { - if (!structure) { - return ""; - } - var tpl = "'{{NAME}}' {{TYPE}}", fields = [], has = {}.hasOwnProperty; - for (var field in structure) { - if (has.call(structure, field)) { - fields.push(tmpl(tpl, { - NAME: field, - TYPE: dialect.DataTypes[structure[field]] - })); - } - } + if (!structure) { + return ""; + } + var tpl = "'{{NAME}}' {{TYPE}}", fields = [], has = {}.hasOwnProperty; + for (var field in structure) { + if (has.call(structure, field)) { + fields.push(tmpl(tpl, { + NAME: field, + TYPE: dialect.DataTypes[structure[field]] + })); + } + } - return fields.join(','); + return fields.join(','); }; /** @@ -49,64 +49,64 @@ var buildFieldsList = function (dialect, structure) { * @constructor */ function CreateQuery(Dialect, opts) { - var sql = {}; - var tableName = null; - var structure = {}; + var sql = {}; + var tableName = null; + var structure = {}; - return { - /** - * Set the table name - * @param table_name - * @returns {*} - */ - table: function (table_name) { - tableName = table_name; + return { + /** + * Set the table name + * @param table_name + * @returns {*} + */ + table: function (table_name) { + tableName = table_name; - return this; - }, - /** - * Add a field - * @param name - * @param type - * @returns {Object} - */ - field: function (name, type) { - structure[name] = type; + return this; + }, + /** + * Add a field + * @param name + * @param type + * @returns {Object} + */ + field: function (name, type) { + structure[name] = type; - return this; - }, - /** - * Set all the fields - * @param fields - * @returns {Object} - */ - fields: function (fields) { - if (!fields) { - return structure; - } - structure = fields; + return this; + }, + /** + * Set all the fields + * @param fields + * @returns {Object} + */ + fields: function (fields) { + if (!fields) { + return structure; + } + structure = fields; - return this; - }, + return this; + }, - /** - * Build a query from the passed params - * @returns {string} - */ - build: function () { - var query, fieldsList, template = "CREATE TABLE '{{TABLE_NAME}}'({{FIELDS_LIST}})"; + /** + * Build a query from the passed params + * @returns {string} + */ + build: function () { + var query, fieldsList, template = "CREATE TABLE '{{TABLE_NAME}}'({{FIELDS_LIST}})"; - if(!tableName){ - return ''; - } + if(!tableName){ + return ''; + } - fieldsList = buildFieldsList(Dialect, structure); + fieldsList = buildFieldsList(Dialect, structure); - return tmpl(template, { - TABLE_NAME: tableName, - FIELDS_LIST: fieldsList - }); + return tmpl(template, { + TABLE_NAME: tableName, + FIELDS_LIST: fieldsList + }); - } - }; + } + }; } diff --git a/lib/Dialects/mssql.js b/lib/Dialects/mssql.js index b99ebe8..69a3ada 100644 --- a/lib/Dialects/mssql.js +++ b/lib/Dialects/mssql.js @@ -2,11 +2,11 @@ var util = require("util"); var helpers = require("../Helpers"); exports.DataTypes = { - id: 'INT IDENTITY(1,1) NOT NULL PRIMARY KEY', - int: 'INT', - float: 'FLOAT', - bool: 'BIT', - text: 'TEXT' + id: 'INT IDENTITY(1,1) NOT NULL PRIMARY KEY', + int: 'INT', + float: 'FLOAT', + bool: 'BIT', + text: 'TEXT' }; @@ -25,7 +25,7 @@ exports.escapeId = function () { return exports.escapeVal(el.escapes.shift()); }); } - return "[" + el + "]"; + return "[" + el + "]"; }).join("."); }; diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index 1e9c180..e058814 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -2,11 +2,11 @@ var util = require("util"); var helpers = require("../Helpers"); exports.DataTypes = { - id: 'INTEGER PRIMARY KEY AUTO_INCREMENT', - int: 'INTEGER', - float: 'FLOAT(12,2)', - bool: 'TINYINT(1)', - text: 'TEXT' + id: 'INTEGER PRIMARY KEY AUTO_INCREMENT', + int: 'INTEGER', + float: 'FLOAT(12,2)', + bool: 'TINYINT(1)', + text: 'TEXT' }; diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index c3bfc3c..8a85bfc 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -2,11 +2,11 @@ var util = require("util"); var helpers = require("../Helpers"); exports.DataTypes = { - id: 'SERIAL PRIMARY KEY', - int: 'INTEGER', - float: 'REAL', - bool: 'SMALLINT', - text: 'TEXT' + id: 'SERIAL PRIMARY KEY', + int: 'INTEGER', + float: 'REAL', + bool: 'SMALLINT', + text: 'TEXT' }; diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 33ecfe3..91fc205 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -3,12 +3,12 @@ var helpers = require("../Helpers"); exports.DataTypes = { - isSQLITE: true, - id: 'INTEGER PRIMARY KEY AUTOINCREMENT', - int: 'INTEGER', - float: 'FLOAT(12,2)', - bool: 'TINYINT(1)', - text: 'TEXT' + isSQLITE: true, + id: 'INTEGER PRIMARY KEY AUTOINCREMENT', + int: 'INTEGER', + float: 'FLOAT(12,2)', + bool: 'TINYINT(1)', + text: 'TEXT' }; exports.escape = function (query, args) { diff --git a/lib/Helpers.js b/lib/Helpers.js index 6cd10ad..0c56aca 100644 --- a/lib/Helpers.js +++ b/lib/Helpers.js @@ -16,49 +16,49 @@ module.exports.escapeQuery = function (Dialect, query, args) { } module.exports.dateToString = function (date, timeZone, opts) { - var dt = new Date(date); + var dt = new Date(date); - if (timeZone != 'local') { - var tz = convertTimezone(timeZone); + if (timeZone != 'local') { + var tz = convertTimezone(timeZone); - dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); - if (tz !== false) { - dt.setTime(dt.getTime() + (tz * 60000)); - } - } + dt.setTime(dt.getTime() + (dt.getTimezoneOffset() * 60000)); + if (tz !== false) { + dt.setTime(dt.getTime() + (tz * 60000)); + } + } - var year = dt.getFullYear(); - 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()); - var milli = zeroPad(dt.getMilliseconds(), 3); + var year = dt.getFullYear(); + 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()); + var milli = zeroPad(dt.getMilliseconds(), 3); - if (opts.dialect == 'mysql') { - return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + milli; - } else { - return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; - } + if (opts.dialect == 'mysql') { + return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + milli; + } else { + return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; + } } function zeroPad(number, n) { - if (arguments.length == 1) n = 2; + if (arguments.length == 1) n = 2; - number = "" + number; + number = "" + number; - while (number.length < n) { - number = "0" + number; - } - return number; + while (number.length < n) { + number = "0" + number; + } + return number; } function convertTimezone(tz) { - if (tz == "Z") return 0; + 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; + 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; } diff --git a/lib/Query.js b/lib/Query.js index bb66cda..f8e9b6d 100644 --- a/lib/Query.js +++ b/lib/Query.js @@ -27,9 +27,9 @@ function Query(opts) { escape : Helpers.escapeQuery.bind(Helpers, Dialect), escapeId : Dialect.escapeId.bind(Dialect), escapeVal : Dialect.escapeVal.bind(Dialect), - create: function(){ - return new CreateQuery(Dialect, opts); - }, + create: function(){ + return new CreateQuery(Dialect, opts); + }, select: function () { return new SelectQuery(Dialect, opts); }, diff --git a/lib/Select.js b/lib/Select.js index a414ecb..e37b249 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -105,24 +105,24 @@ function SelectQuery(Dialect, opts) { var a, f = from_id, t; if (arguments.length == 3) { - a = sql.from[sql.from.length - 1].a; - t = to_table; + a = sql.from[sql.from.length - 1].a; + t = to_table; } else { - a = get_table_alias(to_table); - t = to_id; + a = get_table_alias(to_table); + t = to_id; } from.j = []; if (f.length && t.length) { - if (Array.isArray(f) && Array.isArray(t) && f.length == t.length) { - for (i = 0; i < f.length; i++) { - from.j.push([f[i], a, t[i]]); - } - } else { - from.j.push([f, a, t]); - } + if (Array.isArray(f) && Array.isArray(t) && f.length == t.length) { + for (i = 0; i < f.length; i++) { + from.j.push([f[i], a, t[i]]); + } + } else { + from.j.push([f, a, t]); + } } else { - throw new Error(); + throw new Error(); } sql.from.push(from); diff --git a/lib/Where.js b/lib/Where.js index 513591a..88b45af 100644 --- a/lib/Where.js +++ b/lib/Where.js @@ -26,25 +26,25 @@ exports.build = function (Dialect, where, opts) { function buildOrGroup(Dialect, where, opts) { opts = opts || {}; - + if (where.e) { - // EXISTS + // EXISTS - wheres = []; - if(Array.isArray(where.e.l[0]) && Array.isArray(where.e.l[1])) { - for (i = 0; i < where.e.l[0].length; i++) { - wheres.push(Dialect.escapeId(where.e.l[0][i]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1][i])); - } - } else { - wheres.push(Dialect.escapeId(where.e.l[0]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1])); - } + wheres = []; + if(Array.isArray(where.e.l[0]) && Array.isArray(where.e.l[1])) { + for (i = 0; i < where.e.l[0].length; i++) { + wheres.push(Dialect.escapeId(where.e.l[0][i]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1][i])); + } + } else { + wheres.push(Dialect.escapeId(where.e.l[0]) + " = " + Dialect.escapeId(where.e.tl, where.e.l[1])); + } return [ "EXISTS (" + "SELECT * FROM " + Dialect.escapeId(where.e.t) + " " + "WHERE " + wheres.join(" AND ") + " " + "AND " + buildOrGroup(Dialect, { t: null, w: where.w }, opts) + - ")" + ")" ]; } From 67fd40e58ff390b857a8f517449ef907697e54e5 Mon Sep 17 00:00:00 2001 From: Arek W Date: Sun, 22 Mar 2015 00:19:14 +0000 Subject: [PATCH 093/106] Lint + less [] --- lib/Select.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/lib/Select.js b/lib/Select.js index e37b249..09f7b1c 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -194,7 +194,7 @@ function SelectQuery(Dialect, opts) { return this; }, build: function () { - var query = [], tmp, i, ii, j, ord, str, select_all = true; + var query = [], tmp, from, i, ii, j, ord, str, select_all = true; var having = []; if (fun_stack.length) { @@ -318,30 +318,32 @@ function SelectQuery(Dialect, opts) { } for (i = 0; i < sql.from.length; i++) { + from = sql.from[i]; + if (i > 0) { query.push("JOIN"); } if (sql.from.length == 1 && !sql.where_exists) { - query.push(Dialect.escapeId(sql.from[i].t)); + query.push(Dialect.escapeId(from.t)); } else { - query.push(Dialect.escapeId(sql.from[i].t) + " " + Dialect.escapeId(sql.from[i].a)); + query.push(Dialect.escapeId(from.t) + " " + Dialect.escapeId(from.a)); } if (i > 0) { - query.push("ON"); - - for (ii = 0; ii < sql.from[i].j.length; ii++) { - if (ii > 0) { - query.push("AND"); - } - query.push( - Dialect.escapeId(sql.from[i].a, sql.from[i].j[ii][0]) + - " = " + - Dialect.escapeId(sql.from[i].j[ii][1], sql.from[i].j[ii][2]) - ); - } + query.push("ON"); + + for (ii = 0; ii < from.j.length; ii++) { + if (ii > 0) { + query.push("AND"); + } + query.push( + Dialect.escapeId(from.a, from.j[ii][0]) + + " = " + + Dialect.escapeId(from.j[ii][1], from.j[ii][2]) + ); + } if (i < sql.from.length - 1) { - query.push(")"); + query.push(")"); } } } From c0108e1a6921ac34d12daeeeb661e2ea7f525c5f Mon Sep 17 00:00:00 2001 From: Arek W Date: Sun, 22 Mar 2015 00:54:36 +0000 Subject: [PATCH 094/106] Allow specifying join type #22 --- Changelog.md | 7 +++++++ lib/Select.js | 14 ++++++++++++-- package.json | 2 +- test/integration/test-select.js | 13 ++++++++++--- 4 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 Changelog.md diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..6150c0b --- /dev/null +++ b/Changelog.md @@ -0,0 +1,7 @@ +### v0.1.25 - 22 Mar 2015 + +- Added support for left/right joins (#22) + +### v0.1.24 - 23 Dec 2014 + +- Allow insertion of empty row using default values (#37) diff --git a/lib/Select.js b/lib/Select.js index 09f7b1c..205b9b7 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -92,7 +92,7 @@ function SelectQuery(Dialect, opts) { fun_stack = []; return this; }, - from: function (table, from_id, to_table, to_id) { + from: function (table, from_id, to_table, to_id, fromOpts) { var from = { t: table, // table a: "t" + (sql.from.length + 1) // alias @@ -104,7 +104,14 @@ function SelectQuery(Dialect, opts) { } var a, f = from_id, t; - if (arguments.length == 3) { + var args = Array.prototype.slice.call(arguments); + var last = args[args.length - 1]; + + if (typeof last == 'object' && !Array.isArray(last)) { + from.opts = args.pop(); + } + + if (args.length == 3) { a = sql.from[sql.from.length - 1].a; t = to_table; } else { @@ -321,6 +328,9 @@ function SelectQuery(Dialect, opts) { from = sql.from[i]; if (i > 0) { + if (from.opts && from.opts.joinType) { + query.push(from.opts.joinType.toUpperCase()); + } query.push("JOIN"); } if (sql.from.length == 1 && !sql.where_exists) { diff --git a/package.json b/package.json index a447f1b..4b338a7 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.24", + "version": "0.1.25", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" diff --git a/test/integration/test-select.js b/test/integration/test-select.js index 7b8b81e..5b9b3dd 100644 --- a/test/integration/test-select.js +++ b/test/integration/test-select.js @@ -59,6 +59,13 @@ assert.equal( "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" ); +assert.equal( + common.Select().from('table1').select('id1') + .from('table2', 'id2', 'id1', { joinType: 'left inner' }).select('id2').build(), + "SELECT `t1`.`id1`, `t2`.`id2` FROM `table1` `t1` LEFT INNER JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" +) + + assert.equal( common.Select().from('table1').select('id1', 'name') .from('table2', 'id2', 'table1', 'id1').select('id2').build(), @@ -102,7 +109,7 @@ assert.equal( ); assert.equal( - common.Select().from('table1') - .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']).count('id').build(), - "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2a` = `t1`.`id1a` AND `t2`.`id2b` = `t1`.`id1b`" + common.Select().from('table1') + .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']).count('id').build(), + "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2a` = `t1`.`id1a` AND `t2`.`id2b` = `t1`.`id1b`" ); From f4450a4f0c65a275245635fd4613f3f0abd8c31e Mon Sep 17 00:00:00 2001 From: Arek W Date: Sun, 22 Mar 2015 00:58:28 +0000 Subject: [PATCH 095/106] Add node 0.12 and iojs --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index b9207e5..a152b92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,5 @@ language: node_js node_js: - '0.8' - '0.10' + - '0.12' + - 'iojs' From 7f723e1e107c747cef98a90986021f4bcf69f904 Mon Sep 17 00:00:00 2001 From: Christiaan Westerbeek Date: Mon, 11 May 2015 10:40:39 +0200 Subject: [PATCH 096/106] Add support for SELECT TOP construct for mssql dialect for limit --- lib/Dialects/mssql.js | 2 ++ lib/Remove.js | 25 +++++++++++++-------- lib/Select.js | 23 ++++++++++++------- test/integration/test-dialect-mssql.js | 6 +++++ test/integration/test-dialect-mysql.js | 6 +++++ test/integration/test-dialect-postgresql.js | 6 +++++ test/integration/test-dialect-sqlite.js | 6 +++++ 7 files changed, 57 insertions(+), 17 deletions(-) diff --git a/lib/Dialects/mssql.js b/lib/Dialects/mssql.js index 69a3ada..e49f592 100644 --- a/lib/Dialects/mssql.js +++ b/lib/Dialects/mssql.js @@ -66,3 +66,5 @@ exports.escapeVal = function (val, timeZone) { }; exports.defaultValuesStmt = "DEFAULT VALUES"; + +exports.limitAsTop = true; diff --git a/lib/Remove.js b/lib/Remove.js index 6fe367b..cc4aa55 100644 --- a/lib/Remove.js +++ b/lib/Remove.js @@ -25,7 +25,12 @@ function RemoveQuery(Dialect, opts) { build: function () { var query = [], tmp; - query.push("DELETE FROM"); + // limit as: SELECT TOP n (MSSQL only) + if (Dialect.limitAsTop && sql.hasOwnProperty("limit")) { + query.push("DELETE TOP " + sql.limit + " FROM"); + } else { + query.push("DELETE FROM"); + } query.push(Dialect.escapeId(sql.table)); query = query.concat(Where.build(Dialect, sql.where, opts)); @@ -46,15 +51,17 @@ function RemoveQuery(Dialect, opts) { } } - // limit - if (sql.hasOwnProperty("limit")) { - if (sql.hasOwnProperty("offset")) { - query.push("LIMIT " + sql.limit + " OFFSET " + sql.offset); - } else { - query.push("LIMIT " + sql.limit); + // limit for all Dialects but MSSQL + if (!Dialect.limitAsTop) { + 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(" "); diff --git a/lib/Select.js b/lib/Select.js index 205b9b7..a06ef03 100644 --- a/lib/Select.js +++ b/lib/Select.js @@ -210,6 +210,11 @@ function SelectQuery(Dialect, opts) { query.push("SELECT"); + // limit as: SELECT TOP n (MSSQL only) + if (Dialect.limitAsTop && sql.hasOwnProperty("limit")) { + query.push("TOP " + sql.limit); + } + for (i = 0; i < sql.from.length; i++) { sql.from[i].a = "t" + (i + 1); } @@ -399,15 +404,17 @@ function SelectQuery(Dialect, opts) { } } - // limit - if (sql.hasOwnProperty("limit")) { - if (sql.hasOwnProperty("offset")) { - query.push("LIMIT " + sql.limit + " OFFSET " + sql.offset); - } else { - query.push("LIMIT " + sql.limit); + // limit for all Dialects but MSSQL + if (!Dialect.limitAsTop) { + 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(" "); diff --git a/test/integration/test-dialect-mssql.js b/test/integration/test-dialect-mssql.js index 1542b7e..b737bbb 100644 --- a/test/integration/test-dialect-mssql.js +++ b/test/integration/test-dialect-mssql.js @@ -98,3 +98,9 @@ assert.equal( dialect.defaultValuesStmt, "DEFAULT VALUES" ); + +//Assert that mssql is configured to use the SELECT TOP as a contruct for limit +assert.equal( + dialect.limitAsTop, + true +); \ No newline at end of file diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index f174c70..fa7b836 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -98,3 +98,9 @@ assert.equal( dialect.defaultValuesStmt, "VALUES()" ); + +//For all dialects but mssql limitAsTop should be undefined or false +assert.equal( + dialect.limitAsTop || false, + false +); \ No newline at end of file diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index 685b7f0..8fd1e30 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -103,3 +103,9 @@ assert.equal( dialect.defaultValuesStmt, "DEFAULT VALUES" ); + +//For all dialects but mssql limitAsTop should be undefined or false +assert.equal( + dialect.limitAsTop || false, + false +); \ No newline at end of file diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index d25e72e..5327706 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -98,3 +98,9 @@ assert.equal( dialect.defaultValuesStmt, "DEFAULT VALUES" ); + +//For all dialects but mssql limitAsTop should be undefined or false +assert.equal( + dialect.limitAsTop || false, + false +); \ No newline at end of file From 11acccb46a72180b47940ec4d62f979b25ff13e1 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Sat, 16 May 2015 14:10:25 +0100 Subject: [PATCH 097/106] 0.1.26 --- Changelog.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 6150c0b..7a5ed33 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +### v0.1.26 - 16 May 2015 + +- Add support for SELECT TOP construct for mssql dialect for limit (#41) + ### v0.1.25 - 22 Mar 2015 - Added support for left/right joins (#22) diff --git a/package.json b/package.json index 4b338a7..e6f7899 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.25", + "version": "0.1.26", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" From ab7d878af9db13a791b49737a4c59621d93839dd Mon Sep 17 00:00:00 2001 From: Brian Noah Date: Wed, 16 Sep 2015 15:29:10 -0700 Subject: [PATCH 098/106] update documention --- Readme.md | 635 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 632 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 7bb37a2..f6f4303 100644 --- a/Readme.md +++ b/Readme.md @@ -1,11 +1,11 @@ -## NodeJS SQL query builder +# NodeJS SQL query builder [![Build Status](https://secure.travis-ci.org/dresende/node-sql-query.png?branch=master)](http://travis-ci.org/dresende/node-sql-query) ## Install ```sh -npm install sql-query +npm install sql-query --save ``` ## Dialects @@ -17,4 +17,633 @@ npm install sql-query ## About -This module is used by [ORM](http://dresende.github.com/node-orm2) to build SQL queries in the different supported dialects. Sorry there is no API documentation but there are a couple of tests you can read and find out how to use it if you want. +This module is used by [ORM](http://dresende.github.com/node-orm2) to build SQL queries in the different supported dialects. +Sorry the API documentation is not complete. There are tests in ./test/integration that you can read. + + +#Usage + + var sqlQuery = require('sql-query'); + +##Create + + sqlQuery + .Create() + .table('table1') + .build() + "CREATE TABLE 'table1'()" + + sqlQuery + .Create() + .table('table1') + .field('id','id') + .build() + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT)" + + sqlQuery + .Create() + .table('table1') + .fields({id: 'id', a_text: 'text'}) + .build() + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_text' TEXT)" + + sqlQuery + .Create() + .table('table1') + .fields({id: 'id', a_num: 'int'}) + .build() + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' INTEGER)" + + sqlQuery + .Create() + .table('table1') + .fields({id: 'id', a_num: 'float'}) + .build() + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' FLOAT(12,2))" + + sqlQuery + .Create() + .table('table1') + .fields({id: 'id', a_bool: 'bool'}) + .build() + "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_bool' TINYINT(1))" + +##Select + + sqlQuery + .Select() + .from('table1') + .build(); + "SELECT * FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select('id', 'name') + .build(); + "SELECT `id`, `name` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select('id', 'name') + .as('label') + .build(); + "SELECT `id`, `name` AS `label` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select('id', 'name') + .select('title') + .as('label') + .build(); + "SELECT `id`, `name`, `title` AS `label` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select('id', 'name') + .as('label') + .select('title') + .build(); + "SELECT `id`, `name` AS `label`, `title` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select([ 'id', 'name' ]) + .build(); + "SELECT `id`, `name` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select() + .build(); + "SELECT * FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select(['abc','def', { a: 'ghi', sql: 'SOMEFUNC(ghi)' }]) + .build(); + "SELECT `abc`, `def`, (SOMEFUNC(ghi)) AS `ghi` FROM `table1`" + + sqlQuery + .Select() + .calculateFoundRows() + .from('table1') + .build(); + "SELECT SQL_CALC_FOUND_ROWS * FROM `table1`" + + sqlQuery + .Select() + .calculateFoundRows() + .from('table1') + .select('id') + .build(); + "SELECT SQL_CALC_FOUND_ROWS `id` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .select('id1', 'name') + .from('table2', 'id2', 'id1') + .select('id2') + .build(); + "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .select('id1') + .from('table2', 'id2', 'id1', { joinType: 'left inner' }) + .select('id2') + .build(); + "SELECT `t1`.`id1`, `t2`.`id2` FROM `table1` `t1` LEFT INNER JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .select('id1', 'name') + .from('table2', 'id2', 'table1', 'id1') + .select('id2') + .build(); + "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count() + .build(); + "SELECT COUNT(*) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count(null, 'c') + .build(); + "SELECT COUNT(*) AS `c` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count('id') + .build(); + "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .count('id') + .from('table2', 'id2', 'table1', 'id1') + .count('id') + .build(); + "SELECT COUNT(`t1`.`id`), COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count('id') + .count('col') + .build(); + "SELECT COUNT(`t2`.`id`), COUNT(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .fun('AVG', 'col') + .build(); + "SELECT AVG(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + sqlQuery + .Select() + .from('table1') + .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']) + .count('id') + .build(); + "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2a` = `t1`.`id1a` AND `t2`.`id2b` = `t1`.`id1b`" + +##Where + + sqlQuery + .Select() + .from('table1') + .where() + .build(); + "SELECT * FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .where(null) + .build(); + "SELECT * FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .where({ col: 1 }) + .build(); + "SELECT * FROM `table1` WHERE `col` = 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: 0 }) + .build(); + "SELECT * FROM `table1` WHERE `col` = 0" + + sqlQuery + .Select() + .from('table1') + .where({ col: null }) + .build(); + "SELECT * FROM `table1` WHERE `col` IS NULL" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.eq(null) }) + .build(); + "SELECT * FROM `table1` WHERE `col` IS NULL" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.ne(null) }) + .build(); + "SELECT * FROM `table1` WHERE `col` IS NOT NULL" + + sqlQuery + .Select() + .from('table1') + .where({ col: undefined }) + .build(); + "SELECT * FROM `table1` WHERE `col` IS NULL" + + sqlQuery + .Select() + .from('table1') + .where({ col: false }) + .build(); + "SELECT * FROM `table1` WHERE `col` = false" + + sqlQuery + .Select() + .from('table1') + .where({ col: "" }) + .build(); + "SELECT * FROM `table1` WHERE `col` = ''" + + sqlQuery + .Select() + .from('table1') + .where({ col: true }) + .build(); + "SELECT * FROM `table1` WHERE `col` = true" + + sqlQuery + .Select() + .from('table1') + .where({ col: 'a' }) + .build(); + "SELECT * FROM `table1` WHERE `col` = 'a'" + + sqlQuery + .Select() + .from('table1') + .where({ col: 'a\'' }) + .build(); + "SELECT * FROM `table1` WHERE `col` = 'a\\''" + + sqlQuery + .Select() + .from('table1') + .where({ col: [ 1, 2, 3 ] }) + .build(); + "SELECT * FROM `table1` WHERE `col` IN (1, 2, 3)" + + sqlQuery + .Select() + .from('table1') + .where({ col: [] }) + .build(); + "SELECT * FROM `table1` WHERE FALSE" + + sqlQuery + .Select() + .from('table1') + .where({ col1: 1, col2: 2 }) + .build(); + "SELECT * FROM `table1` WHERE `col1` = 1 AND `col2` = 2" + + sqlQuery + .Select() + .from('table1') + .where({ col1: 1 }, { col2: 2 }) + .build(); + "SELECT * FROM `table1` WHERE (`col1` = 1) AND (`col2` = 2)" + + sqlQuery + .Select() + .from('table1') + .where({ col: 1 }).where({ col: 2 }) + .build(); + "SELECT * FROM `table1` WHERE (`col` = 1) AND (`col` = 2)" + + sqlQuery + .Select() + .from('table1') + .where({ col1: 1, col2: 2 }).where({ col3: 3 }) + .build(); + "SELECT * FROM `table1` WHERE (`col1` = 1 AND `col2` = 2) AND (`col3` = 3)" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id', 'id') + .where('table1', { col: 1 }, 'table2', { col: 2 }) + .build(); + "SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`t2`.`col` = 2)" + + sqlQuery + .Select() + .from('table1') + .from('table2', 'id', 'id') + .where('table1', { col: 1 }, { col: 2 }) + .build(); + "SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`col` = 2)" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.gt(1) }) + .build(); + "SELECT * FROM `table1` WHERE `col` > 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.gte(1) }) + .build(); + "SELECT * FROM `table1` WHERE `col` >= 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.lt(1) }) + .build(); + "SELECT * FROM `table1` WHERE `col` < 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.lte(1) }) + .build(); + "SELECT * FROM `table1` WHERE `col` <= 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.eq(1) }) + .build(); + "SELECT * FROM `table1` WHERE `col` = 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.ne(1) }) + .build(); + "SELECT * FROM `table1` WHERE `col` <> 1" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.between('a', 'b') }) + .build(); + "SELECT * FROM `table1` WHERE `col` BETWEEN 'a' AND 'b'" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.not_between('a', 'b') }) + .build(); + "SELECT * FROM `table1` WHERE `col` NOT BETWEEN 'a' AND 'b'" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.like('abc') }) + .build(); + "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.not_like('abc') }) + .build(); + "SELECT * FROM `table1` WHERE `col` NOT LIKE 'abc'" + + sqlQuery + .Select() + .from('table1') + .where({ col: sqlQuery.Query.not_in([ 1, 2, 3 ]) }) + .build(); + "SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" + + sqlQuery + .Select() + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE 'peaches'"]] }) + .build(); + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" + + sqlQuery + .Select() + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE ?", ['peaches']]] }) + .build(); + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" + + sqlQuery + .Select() + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]]] }) + .build(); + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" + + sqlQuery + .Select() + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']]] }) + .build(); + "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" + +##Order + + sqlQuery + .Select() + .from('table1') + .order('col') + .build(); + "SELECT * FROM `table1` ORDER BY `col` ASC" + + sqlQuery + .Select() + .from('table1') + .order('col', 'A') + .build(); + "SELECT * FROM `table1` ORDER BY `col` ASC" + + sqlQuery + .Select() + .from('table1') + .order('col', 'Z') + .build(); + "SELECT * FROM `table1` ORDER BY `col` DESC" + + sqlQuery + .Select() + .from('table1') + .order('col').order('col2', 'Z') + .build(); + "SELECT * FROM `table1` ORDER BY `col` ASC, `col2` DESC" + + sqlQuery + .Select() + .from('table1') + .order('col', []) + .build(); + "SELECT * FROM `table1` ORDER BY col" + + sqlQuery + .Select() + .from('table1') + .order('?? DESC', ['col']) + .build(); + "SELECT * FROM `table1` ORDER BY `col` DESC" + + sqlQuery + .Select() + .from('table1') + .order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-68.3394 27.5578)']) + .build(); + "SELECT * FROM `table1` ORDER BY ST_Distance(`geopoint`, ST_GeomFromText('POINT(-68.3394 27.5578)',4326))" + +##Limit + + sqlQuery + .Select() + .from('table1') + .limit(123) + .build(); + "SELECT * FROM `table1` LIMIT 123" + + sqlQuery + .Select() + .from('table1') + .limit('123456789') + .build(); + "SELECT * FROM `table1` LIMIT 123456789" + +##Select Function + + sqlQuery + .Select() + .from('table1') + .fun('myfun', 'col1') + .build(); + "SELECT MYFUN(`col1`) FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .fun('myfun', [ 'col1', 'col2']) + .build(); + "SELECT MYFUN(`col1`, `col2`) FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .fun('dbo.fnBalance', [ 80, null, null], 'balance') + .build(); + "SELECT DBO.FNBALANCE(80, NULL, NULL) AS `balance` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .fun('myfun', [ 'col1', 'col2'], 'alias') + .build(); + "SELECT MYFUN(`col1`, `col2`) AS `alias` FROM `table1`" + + sqlQuery + .Select() + .from('table1') + .fun('myfun', [ 'col1', sqlQuery.Text('col2') ], 'alias') + .build(); + "SELECT MYFUN(`col1`, 'col2') AS `alias` FROM `table1`" + +##Insert + + sqlQuery + .Insert() + .into('table1') + .build(); + "INSERT INTO `table1`" + + sqlQuery + .Insert() + .into('table1') + .set({}) + .build(); + "INSERT INTO `table1` VALUES()" + + sqlQuery + .Insert() + .into('table1') + .set({ col: 1 }) + .build(); + "INSERT INTO `table1` (`col`) VALUES (1)" + + sqlQuery + .Insert() + .into('table1') + .set({ col1: 1, col2: 'a' }) + .build(); + "INSERT INTO `table1` (`col1`, `col2`) VALUES (1, 'a')" + +##Update + + sqlQuery + .Update() + .into('table1') + .build(); + "UPDATE `table1`" + + sqlQuery + .Update() + .into('table1') + .set({ col: 1 }) + .build(); + "UPDATE `table1` SET `col` = 1" + + sqlQuery + .Update() + .into('table1') + .set({ col1: 1, col2: 2 }) + .build(); + "UPDATE `table1` SET `col1` = 1, `col2` = 2" + + sqlQuery + .Update() + .into('table1') + .set({ col1: 1, col2: 2 }).where({ id: 3 }) + .build(); + "UPDATE `table1` SET `col1` = 1, `col2` = 2 WHERE `id` = 3" From 3f85a8de732aaeb996da002ab163da6ed90fcc26 Mon Sep 17 00:00:00 2001 From: Brian Noah Date: Thu, 17 Sep 2015 13:54:11 -0700 Subject: [PATCH 099/106] update docs to match actual use vs test usage --- Readme.md | 270 ++++++++++++++++++++---------------------------------- 1 file changed, 101 insertions(+), 169 deletions(-) diff --git a/Readme.md b/Readme.md index f6f4303..a0e7b07 100644 --- a/Readme.md +++ b/Readme.md @@ -23,46 +23,42 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati #Usage - var sqlQuery = require('sql-query'); + var sqlQuery = require('sql-query').Query(); ##Create - sqlQuery - .Create() + var sqlCreate = sqlQuery.create(); + + sqlCreate .table('table1') .build() "CREATE TABLE 'table1'()" - sqlQuery - .Create() + sqlCreate .table('table1') .field('id','id') .build() "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT)" - sqlQuery - .Create() + sqlCreate .table('table1') .fields({id: 'id', a_text: 'text'}) .build() "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_text' TEXT)" - sqlQuery - .Create() + sqlCreate .table('table1') .fields({id: 'id', a_num: 'int'}) .build() "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' INTEGER)" - sqlQuery - .Create() + sqlCreate .table('table1') .fields({id: 'id', a_num: 'float'}) .build() "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' FLOAT(12,2))" - sqlQuery - .Create() + sqlCreate .table('table1') .fields({id: 'id', a_bool: 'bool'}) .build() @@ -70,29 +66,27 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Select - sqlQuery - .Select() + var sqlSelect = sqlQuery.select(); + + sqlSelect .from('table1') .build(); "SELECT * FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id', 'name') .build(); "SELECT `id`, `name` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id', 'name') .as('label') .build(); "SELECT `id`, `name` AS `label` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id', 'name') .select('title') @@ -100,8 +94,7 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT `id`, `name`, `title` AS `label` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id', 'name') .as('label') @@ -109,44 +102,38 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT `id`, `name` AS `label`, `title` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select([ 'id', 'name' ]) .build(); "SELECT `id`, `name` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select() .build(); "SELECT * FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select(['abc','def', { a: 'ghi', sql: 'SOMEFUNC(ghi)' }]) .build(); "SELECT `abc`, `def`, (SOMEFUNC(ghi)) AS `ghi` FROM `table1`" - sqlQuery - .Select() + sqlSelect .calculateFoundRows() .from('table1') .build(); "SELECT SQL_CALC_FOUND_ROWS * FROM `table1`" - sqlQuery - .Select() + sqlSelect .calculateFoundRows() .from('table1') .select('id') .build(); "SELECT SQL_CALC_FOUND_ROWS `id` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id1', 'name') .from('table2', 'id2', 'id1') @@ -154,8 +141,7 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id1') .from('table2', 'id2', 'id1', { joinType: 'left inner' }) @@ -163,8 +149,7 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT `t1`.`id1`, `t2`.`id2` FROM `table1` `t1` LEFT INNER JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .select('id1', 'name') .from('table2', 'id2', 'table1', 'id1') @@ -172,32 +157,28 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id2', 'table1', 'id1') .count() .build(); "SELECT COUNT(*) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id2', 'table1', 'id1') .count(null, 'c') .build(); "SELECT COUNT(*) AS `c` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id2', 'table1', 'id1') .count('id') .build(); "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .count('id') .from('table2', 'id2', 'table1', 'id1') @@ -205,8 +186,7 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT COUNT(`t1`.`id`), COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id2', 'table1', 'id1') .count('id') @@ -214,16 +194,14 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati .build(); "SELECT COUNT(`t2`.`id`), COUNT(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id2', 'table1', 'id1') .fun('AVG', 'col') .build(); "SELECT AVG(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']) .count('id') @@ -232,255 +210,221 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Where - sqlQuery - .Select() + var sqlSelect = sqlQuery.select(); + + sqlSelect .from('table1') .where() .build(); "SELECT * FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .where(null) .build(); "SELECT * FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: 1 }) .build(); "SELECT * FROM `table1` WHERE `col` = 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: 0 }) .build(); "SELECT * FROM `table1` WHERE `col` = 0" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: null }) .build(); "SELECT * FROM `table1` WHERE `col` IS NULL" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.eq(null) }) .build(); "SELECT * FROM `table1` WHERE `col` IS NULL" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.ne(null) }) .build(); "SELECT * FROM `table1` WHERE `col` IS NOT NULL" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: undefined }) .build(); "SELECT * FROM `table1` WHERE `col` IS NULL" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: false }) .build(); "SELECT * FROM `table1` WHERE `col` = false" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: "" }) .build(); "SELECT * FROM `table1` WHERE `col` = ''" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: true }) .build(); "SELECT * FROM `table1` WHERE `col` = true" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: 'a' }) .build(); "SELECT * FROM `table1` WHERE `col` = 'a'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: 'a\'' }) .build(); "SELECT * FROM `table1` WHERE `col` = 'a\\''" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: [ 1, 2, 3 ] }) .build(); "SELECT * FROM `table1` WHERE `col` IN (1, 2, 3)" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: [] }) .build(); "SELECT * FROM `table1` WHERE FALSE" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col1: 1, col2: 2 }) .build(); "SELECT * FROM `table1` WHERE `col1` = 1 AND `col2` = 2" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col1: 1 }, { col2: 2 }) .build(); "SELECT * FROM `table1` WHERE (`col1` = 1) AND (`col2` = 2)" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: 1 }).where({ col: 2 }) .build(); "SELECT * FROM `table1` WHERE (`col` = 1) AND (`col` = 2)" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col1: 1, col2: 2 }).where({ col3: 3 }) .build(); "SELECT * FROM `table1` WHERE (`col1` = 1 AND `col2` = 2) AND (`col3` = 3)" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id', 'id') .where('table1', { col: 1 }, 'table2', { col: 2 }) .build(); "SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`t2`.`col` = 2)" - sqlQuery - .Select() + sqlSelect .from('table1') .from('table2', 'id', 'id') .where('table1', { col: 1 }, { col: 2 }) .build(); "SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`col` = 2)" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.gt(1) }) .build(); "SELECT * FROM `table1` WHERE `col` > 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.gte(1) }) .build(); "SELECT * FROM `table1` WHERE `col` >= 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.lt(1) }) .build(); "SELECT * FROM `table1` WHERE `col` < 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.lte(1) }) .build(); "SELECT * FROM `table1` WHERE `col` <= 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.eq(1) }) .build(); "SELECT * FROM `table1` WHERE `col` = 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.ne(1) }) .build(); "SELECT * FROM `table1` WHERE `col` <> 1" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.between('a', 'b') }) .build(); "SELECT * FROM `table1` WHERE `col` BETWEEN 'a' AND 'b'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.not_between('a', 'b') }) .build(); "SELECT * FROM `table1` WHERE `col` NOT BETWEEN 'a' AND 'b'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.like('abc') }) .build(); "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.not_like('abc') }) .build(); "SELECT * FROM `table1` WHERE `col` NOT LIKE 'abc'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ col: sqlQuery.Query.not_in([ 1, 2, 3 ]) }) .build(); "SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ __sql: [["LOWER(`stuff`) LIKE 'peaches'"]] }) .build(); "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ __sql: [["LOWER(`stuff`) LIKE ?", ['peaches']]] }) .build(); "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]]] }) .build(); "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" - sqlQuery - .Select() + sqlSelect .from('table1') .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']]] }) .build(); @@ -488,50 +432,45 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Order - sqlQuery - .Select() + var sqlSelect = sqlQuery.select(); + + sqlSelect .from('table1') .order('col') .build(); "SELECT * FROM `table1` ORDER BY `col` ASC" - sqlQuery - .Select() + sqlSelect .from('table1') .order('col', 'A') .build(); "SELECT * FROM `table1` ORDER BY `col` ASC" - sqlQuery - .Select() + sqlSelect .from('table1') .order('col', 'Z') .build(); "SELECT * FROM `table1` ORDER BY `col` DESC" - sqlQuery - .Select() + sqlSelect .from('table1') .order('col').order('col2', 'Z') .build(); "SELECT * FROM `table1` ORDER BY `col` ASC, `col2` DESC" - sqlQuery - .Select() + sqlSelect .from('table1') .order('col', []) .build(); "SELECT * FROM `table1` ORDER BY col" - sqlQuery - .Select() + sqlSelect .from('table1') .order('?? DESC', ['col']) .build(); "SELECT * FROM `table1` ORDER BY `col` DESC" - sqlQuery - .Select() + sqlSelect .from('table1') .order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-68.3394 27.5578)']) .build(); @@ -539,15 +478,15 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Limit - sqlQuery - .Select() + var sqlSelect = sqlQuery.select(); + + sqlSelect .from('table1') .limit(123) .build(); "SELECT * FROM `table1` LIMIT 123" - sqlQuery - .Select() + sqlSelect .from('table1') .limit('123456789') .build(); @@ -555,36 +494,33 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Select Function - sqlQuery - .Select() + var sqlSelect = sqlQuery.select(); + + sqlSelect .from('table1') .fun('myfun', 'col1') .build(); "SELECT MYFUN(`col1`) FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .fun('myfun', [ 'col1', 'col2']) .build(); "SELECT MYFUN(`col1`, `col2`) FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .fun('dbo.fnBalance', [ 80, null, null], 'balance') .build(); "SELECT DBO.FNBALANCE(80, NULL, NULL) AS `balance` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .fun('myfun', [ 'col1', 'col2'], 'alias') .build(); "SELECT MYFUN(`col1`, `col2`) AS `alias` FROM `table1`" - sqlQuery - .Select() + sqlSelect .from('table1') .fun('myfun', [ 'col1', sqlQuery.Text('col2') ], 'alias') .build(); @@ -592,28 +528,26 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Insert - sqlQuery - .Insert() + var sqlInsert = sqlQuery.insert(); + + sqlInsert .into('table1') .build(); "INSERT INTO `table1`" - sqlQuery - .Insert() + sqlInsert .into('table1') .set({}) .build(); "INSERT INTO `table1` VALUES()" - sqlQuery - .Insert() + sqlInsert .into('table1') .set({ col: 1 }) .build(); "INSERT INTO `table1` (`col`) VALUES (1)" - sqlQuery - .Insert() + sqlInsert .into('table1') .set({ col1: 1, col2: 'a' }) .build(); @@ -621,28 +555,26 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati ##Update - sqlQuery - .Update() + var sqlUpdate = sqlQuery.update() + + sqlUpdate .into('table1') .build(); "UPDATE `table1`" - sqlQuery - .Update() + sqlUpdate .into('table1') .set({ col: 1 }) .build(); "UPDATE `table1` SET `col` = 1" - sqlQuery - .Update() + sqlUpdate .into('table1') .set({ col1: 1, col2: 2 }) .build(); "UPDATE `table1` SET `col1` = 1, `col2` = 2" - sqlQuery - .Update() + sqlUpdate .into('table1') .set({ col1: 1, col2: 2 }).where({ id: 3 }) .build(); From 8322fc137092d71e26f945657f3c03f34c472061 Mon Sep 17 00:00:00 2001 From: Brian Noah Date: Mon, 21 Sep 2015 10:47:34 -0700 Subject: [PATCH 100/106] update comparators --- Readme.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Readme.md b/Readme.md index a0e7b07..c6b590c 100644 --- a/Readme.md +++ b/Readme.md @@ -22,8 +22,8 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati #Usage - - var sqlQuery = require('sql-query').Query(); + var sql = require('sql-query'), + sqlQuery = sql.Query(); ##Create @@ -244,13 +244,13 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati sqlSelect .from('table1') - .where({ col: sqlQuery.Query.eq(null) }) + .where({ col: sql.eq(null) }) .build(); "SELECT * FROM `table1` WHERE `col` IS NULL" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.ne(null) }) + .where({ col: sql.ne(null) }) .build(); "SELECT * FROM `table1` WHERE `col` IS NOT NULL" @@ -342,67 +342,67 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati sqlSelect .from('table1') - .where({ col: sqlQuery.Query.gt(1) }) + .where({ col: sql.gt(1) }) .build(); "SELECT * FROM `table1` WHERE `col` > 1" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.gte(1) }) + .where({ col: sql.gte(1) }) .build(); "SELECT * FROM `table1` WHERE `col` >= 1" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.lt(1) }) + .where({ col: sql.lt(1) }) .build(); "SELECT * FROM `table1` WHERE `col` < 1" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.lte(1) }) + .where({ col: sql.lte(1) }) .build(); "SELECT * FROM `table1` WHERE `col` <= 1" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.eq(1) }) + .where({ col: sql.eq(1) }) .build(); "SELECT * FROM `table1` WHERE `col` = 1" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.ne(1) }) + .where({ col: sql.ne(1) }) .build(); "SELECT * FROM `table1` WHERE `col` <> 1" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.between('a', 'b') }) + .where({ col: sql.between('a', 'b') }) .build(); "SELECT * FROM `table1` WHERE `col` BETWEEN 'a' AND 'b'" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.not_between('a', 'b') }) + .where({ col: sql.not_between('a', 'b') }) .build(); "SELECT * FROM `table1` WHERE `col` NOT BETWEEN 'a' AND 'b'" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.like('abc') }) + .where({ col: sql.like('abc') }) .build(); "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.not_like('abc') }) + .where({ col: sql.not_like('abc') }) .build(); "SELECT * FROM `table1` WHERE `col` NOT LIKE 'abc'" sqlSelect .from('table1') - .where({ col: sqlQuery.Query.not_in([ 1, 2, 3 ]) }) + .where({ col: sql.not_in([ 1, 2, 3 ]) }) .build(); "SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" From 26239cb3397cec1bb18b42c823e160c490517e9d Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 14 Nov 2017 14:00:28 +0000 Subject: [PATCH 101/106] utest@0.0.8, urun@0.0.8 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e6f7899..a952de9 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ }, "analyse": false, "devDependencies": { - "utest": "0.0.6", - "urun": "0.0.6" + "utest": "0.0.8", + "urun": "0.0.8" } } From b7dc7f02c193f7d9cb3ba21fc832ebcb05157a55 Mon Sep 17 00:00:00 2001 From: Diogo Resende Date: Tue, 14 Nov 2017 14:04:11 +0000 Subject: [PATCH 102/106] helpers: when escaping a date, avoid adding 'Z' if timezone is local (should fix #50) --- lib/Helpers.js | 2 +- test/integration/test-dialect-mssql.js | 4 ++-- test/integration/test-dialect-postgresql.js | 4 ++-- test/integration/test-dialect-sqlite.js | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Helpers.js b/lib/Helpers.js index 0c56aca..561c6fd 100644 --- a/lib/Helpers.js +++ b/lib/Helpers.js @@ -35,7 +35,7 @@ module.exports.dateToString = function (date, timeZone, opts) { var second = zeroPad(dt.getSeconds()); var milli = zeroPad(dt.getMilliseconds(), 3); - if (opts.dialect == 'mysql') { + if (opts.dialect == 'mysql' || timeZone == 'local') { return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + milli; } else { return year + '-' + month + '-' + day + 'T' + hour + ':' + minute + ':' + second + '.' + milli + 'Z'; diff --git a/test/integration/test-dialect-mssql.js b/test/integration/test-dialect-mssql.js index b737bbb..2d419ad 100644 --- a/test/integration/test-dialect-mssql.js +++ b/test/integration/test-dialect-mssql.js @@ -71,7 +71,7 @@ assert.equal( assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), - "'2013-09-04T19:15:11.133Z'" + "'2013-09-04 19:15:11.133'" ); assert.equal( @@ -103,4 +103,4 @@ assert.equal( assert.equal( dialect.limitAsTop, true -); \ No newline at end of file +); diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index 8fd1e30..5590bff 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -76,7 +76,7 @@ assert.equal( assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), - "'2013-09-04T19:15:11.133Z'" + "'2013-09-04 19:15:11.133'" ); assert.equal( @@ -108,4 +108,4 @@ assert.equal( assert.equal( dialect.limitAsTop || false, false -); \ No newline at end of file +); diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index 5327706..a002b02 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -71,7 +71,7 @@ assert.equal( assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), - "'2013-09-04T19:15:11.133Z'" + "'2013-09-04 19:15:11.133'" ); assert.equal( @@ -103,4 +103,4 @@ assert.equal( assert.equal( dialect.limitAsTop || false, false -); \ No newline at end of file +); From e75a72d06289c7dee88e00751b257d1974391ae2 Mon Sep 17 00:00:00 2001 From: Arek W Date: Tue, 6 Feb 2018 16:05:18 +1100 Subject: [PATCH 103/106] Add some syntax highlighting --- Readme.md | 1291 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 733 insertions(+), 558 deletions(-) diff --git a/Readme.md b/Readme.md index c6b590c..aafb788 100644 --- a/Readme.md +++ b/Readme.md @@ -21,561 +21,736 @@ This module is used by [ORM](http://dresende.github.com/node-orm2) to build SQL Sorry the API documentation is not complete. There are tests in ./test/integration that you can read. -#Usage - var sql = require('sql-query'), - sqlQuery = sql.Query(); - -##Create - - var sqlCreate = sqlQuery.create(); - - sqlCreate - .table('table1') - .build() - "CREATE TABLE 'table1'()" - - sqlCreate - .table('table1') - .field('id','id') - .build() - "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT)" - - sqlCreate - .table('table1') - .fields({id: 'id', a_text: 'text'}) - .build() - "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_text' TEXT)" - - sqlCreate - .table('table1') - .fields({id: 'id', a_num: 'int'}) - .build() - "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' INTEGER)" - - sqlCreate - .table('table1') - .fields({id: 'id', a_num: 'float'}) - .build() - "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' FLOAT(12,2))" - - sqlCreate - .table('table1') - .fields({id: 'id', a_bool: 'bool'}) - .build() - "CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_bool' TINYINT(1))" - -##Select - - var sqlSelect = sqlQuery.select(); - - sqlSelect - .from('table1') - .build(); - "SELECT * FROM `table1`" - - sqlSelect - .from('table1') - .select('id', 'name') - .build(); - "SELECT `id`, `name` FROM `table1`" - - sqlSelect - .from('table1') - .select('id', 'name') - .as('label') - .build(); - "SELECT `id`, `name` AS `label` FROM `table1`" - - sqlSelect - .from('table1') - .select('id', 'name') - .select('title') - .as('label') - .build(); - "SELECT `id`, `name`, `title` AS `label` FROM `table1`" - - sqlSelect - .from('table1') - .select('id', 'name') - .as('label') - .select('title') - .build(); - "SELECT `id`, `name` AS `label`, `title` FROM `table1`" - - sqlSelect - .from('table1') - .select([ 'id', 'name' ]) - .build(); - "SELECT `id`, `name` FROM `table1`" - - sqlSelect - .from('table1') - .select() - .build(); - "SELECT * FROM `table1`" - - sqlSelect - .from('table1') - .select(['abc','def', { a: 'ghi', sql: 'SOMEFUNC(ghi)' }]) - .build(); - "SELECT `abc`, `def`, (SOMEFUNC(ghi)) AS `ghi` FROM `table1`" - - sqlSelect - .calculateFoundRows() - .from('table1') - .build(); - "SELECT SQL_CALC_FOUND_ROWS * FROM `table1`" - - sqlSelect - .calculateFoundRows() - .from('table1') - .select('id') - .build(); - "SELECT SQL_CALC_FOUND_ROWS `id` FROM `table1`" - - sqlSelect - .from('table1') - .select('id1', 'name') - .from('table2', 'id2', 'id1') - .select('id2') - .build(); - "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .select('id1') - .from('table2', 'id2', 'id1', { joinType: 'left inner' }) - .select('id2') - .build(); - "SELECT `t1`.`id1`, `t2`.`id2` FROM `table1` `t1` LEFT INNER JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .select('id1', 'name') - .from('table2', 'id2', 'table1', 'id1') - .select('id2') - .build(); - "SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .from('table2', 'id2', 'table1', 'id1') - .count() - .build(); - "SELECT COUNT(*) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .from('table2', 'id2', 'table1', 'id1') - .count(null, 'c') - .build(); - "SELECT COUNT(*) AS `c` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .from('table2', 'id2', 'table1', 'id1') - .count('id') - .build(); - "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .count('id') - .from('table2', 'id2', 'table1', 'id1') - .count('id') - .build(); - "SELECT COUNT(`t1`.`id`), COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .from('table2', 'id2', 'table1', 'id1') - .count('id') - .count('col') - .build(); - "SELECT COUNT(`t2`.`id`), COUNT(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .from('table2', 'id2', 'table1', 'id1') - .fun('AVG', 'col') - .build(); - "SELECT AVG(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" - - sqlSelect - .from('table1') - .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']) - .count('id') - .build(); - "SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2a` = `t1`.`id1a` AND `t2`.`id2b` = `t1`.`id1b`" - -##Where - - var sqlSelect = sqlQuery.select(); - - sqlSelect - .from('table1') - .where() - .build(); - "SELECT * FROM `table1`" - - sqlSelect - .from('table1') - .where(null) - .build(); - "SELECT * FROM `table1`" - - sqlSelect - .from('table1') - .where({ col: 1 }) - .build(); - "SELECT * FROM `table1` WHERE `col` = 1" - - sqlSelect - .from('table1') - .where({ col: 0 }) - .build(); - "SELECT * FROM `table1` WHERE `col` = 0" - - sqlSelect - .from('table1') - .where({ col: null }) - .build(); - "SELECT * FROM `table1` WHERE `col` IS NULL" - - sqlSelect - .from('table1') - .where({ col: sql.eq(null) }) - .build(); - "SELECT * FROM `table1` WHERE `col` IS NULL" - - sqlSelect - .from('table1') - .where({ col: sql.ne(null) }) - .build(); - "SELECT * FROM `table1` WHERE `col` IS NOT NULL" - - sqlSelect - .from('table1') - .where({ col: undefined }) - .build(); - "SELECT * FROM `table1` WHERE `col` IS NULL" - - sqlSelect - .from('table1') - .where({ col: false }) - .build(); - "SELECT * FROM `table1` WHERE `col` = false" - - sqlSelect - .from('table1') - .where({ col: "" }) - .build(); - "SELECT * FROM `table1` WHERE `col` = ''" - - sqlSelect - .from('table1') - .where({ col: true }) - .build(); - "SELECT * FROM `table1` WHERE `col` = true" - - sqlSelect - .from('table1') - .where({ col: 'a' }) - .build(); - "SELECT * FROM `table1` WHERE `col` = 'a'" - - sqlSelect - .from('table1') - .where({ col: 'a\'' }) - .build(); - "SELECT * FROM `table1` WHERE `col` = 'a\\''" - - sqlSelect - .from('table1') - .where({ col: [ 1, 2, 3 ] }) - .build(); - "SELECT * FROM `table1` WHERE `col` IN (1, 2, 3)" - - sqlSelect - .from('table1') - .where({ col: [] }) - .build(); - "SELECT * FROM `table1` WHERE FALSE" - - sqlSelect - .from('table1') - .where({ col1: 1, col2: 2 }) - .build(); - "SELECT * FROM `table1` WHERE `col1` = 1 AND `col2` = 2" - - sqlSelect - .from('table1') - .where({ col1: 1 }, { col2: 2 }) - .build(); - "SELECT * FROM `table1` WHERE (`col1` = 1) AND (`col2` = 2)" - - sqlSelect - .from('table1') - .where({ col: 1 }).where({ col: 2 }) - .build(); - "SELECT * FROM `table1` WHERE (`col` = 1) AND (`col` = 2)" - - sqlSelect - .from('table1') - .where({ col1: 1, col2: 2 }).where({ col3: 3 }) - .build(); - "SELECT * FROM `table1` WHERE (`col1` = 1 AND `col2` = 2) AND (`col3` = 3)" - - sqlSelect - .from('table1') - .from('table2', 'id', 'id') - .where('table1', { col: 1 }, 'table2', { col: 2 }) - .build(); - "SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`t2`.`col` = 2)" - - sqlSelect - .from('table1') - .from('table2', 'id', 'id') - .where('table1', { col: 1 }, { col: 2 }) - .build(); - "SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`col` = 2)" - - sqlSelect - .from('table1') - .where({ col: sql.gt(1) }) - .build(); - "SELECT * FROM `table1` WHERE `col` > 1" - - sqlSelect - .from('table1') - .where({ col: sql.gte(1) }) - .build(); - "SELECT * FROM `table1` WHERE `col` >= 1" - - sqlSelect - .from('table1') - .where({ col: sql.lt(1) }) - .build(); - "SELECT * FROM `table1` WHERE `col` < 1" - - sqlSelect - .from('table1') - .where({ col: sql.lte(1) }) - .build(); - "SELECT * FROM `table1` WHERE `col` <= 1" - - sqlSelect - .from('table1') - .where({ col: sql.eq(1) }) - .build(); - "SELECT * FROM `table1` WHERE `col` = 1" - - sqlSelect - .from('table1') - .where({ col: sql.ne(1) }) - .build(); - "SELECT * FROM `table1` WHERE `col` <> 1" - - sqlSelect - .from('table1') - .where({ col: sql.between('a', 'b') }) - .build(); - "SELECT * FROM `table1` WHERE `col` BETWEEN 'a' AND 'b'" - - sqlSelect - .from('table1') - .where({ col: sql.not_between('a', 'b') }) - .build(); - "SELECT * FROM `table1` WHERE `col` NOT BETWEEN 'a' AND 'b'" - - sqlSelect - .from('table1') - .where({ col: sql.like('abc') }) - .build(); - "SELECT * FROM `table1` WHERE `col` LIKE 'abc'" - - sqlSelect - .from('table1') - .where({ col: sql.not_like('abc') }) - .build(); - "SELECT * FROM `table1` WHERE `col` NOT LIKE 'abc'" - - sqlSelect - .from('table1') - .where({ col: sql.not_in([ 1, 2, 3 ]) }) - .build(); - "SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" - - sqlSelect - .from('table1') - .where({ __sql: [["LOWER(`stuff`) LIKE 'peaches'"]] }) - .build(); - "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" - - sqlSelect - .from('table1') - .where({ __sql: [["LOWER(`stuff`) LIKE ?", ['peaches']]] }) - .build(); - "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" - - sqlSelect - .from('table1') - .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]]] }) - .build(); - "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" - - sqlSelect - .from('table1') - .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']]] }) - .build(); - "SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" - -##Order - - var sqlSelect = sqlQuery.select(); - - sqlSelect - .from('table1') - .order('col') - .build(); - "SELECT * FROM `table1` ORDER BY `col` ASC" - - sqlSelect - .from('table1') - .order('col', 'A') - .build(); - "SELECT * FROM `table1` ORDER BY `col` ASC" - - sqlSelect - .from('table1') - .order('col', 'Z') - .build(); - "SELECT * FROM `table1` ORDER BY `col` DESC" - - sqlSelect - .from('table1') - .order('col').order('col2', 'Z') - .build(); - "SELECT * FROM `table1` ORDER BY `col` ASC, `col2` DESC" - - sqlSelect - .from('table1') - .order('col', []) - .build(); - "SELECT * FROM `table1` ORDER BY col" - - sqlSelect - .from('table1') - .order('?? DESC', ['col']) - .build(); - "SELECT * FROM `table1` ORDER BY `col` DESC" - - sqlSelect - .from('table1') - .order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-68.3394 27.5578)']) - .build(); - "SELECT * FROM `table1` ORDER BY ST_Distance(`geopoint`, ST_GeomFromText('POINT(-68.3394 27.5578)',4326))" - -##Limit - - var sqlSelect = sqlQuery.select(); - - sqlSelect - .from('table1') - .limit(123) - .build(); - "SELECT * FROM `table1` LIMIT 123" - - sqlSelect - .from('table1') - .limit('123456789') - .build(); - "SELECT * FROM `table1` LIMIT 123456789" - -##Select Function - - var sqlSelect = sqlQuery.select(); - - sqlSelect - .from('table1') - .fun('myfun', 'col1') - .build(); - "SELECT MYFUN(`col1`) FROM `table1`" - - sqlSelect - .from('table1') - .fun('myfun', [ 'col1', 'col2']) - .build(); - "SELECT MYFUN(`col1`, `col2`) FROM `table1`" - - sqlSelect - .from('table1') - .fun('dbo.fnBalance', [ 80, null, null], 'balance') - .build(); - "SELECT DBO.FNBALANCE(80, NULL, NULL) AS `balance` FROM `table1`" - - sqlSelect - .from('table1') - .fun('myfun', [ 'col1', 'col2'], 'alias') - .build(); - "SELECT MYFUN(`col1`, `col2`) AS `alias` FROM `table1`" - - sqlSelect - .from('table1') - .fun('myfun', [ 'col1', sqlQuery.Text('col2') ], 'alias') - .build(); - "SELECT MYFUN(`col1`, 'col2') AS `alias` FROM `table1`" - -##Insert - - var sqlInsert = sqlQuery.insert(); - - sqlInsert - .into('table1') - .build(); - "INSERT INTO `table1`" - - sqlInsert - .into('table1') - .set({}) - .build(); - "INSERT INTO `table1` VALUES()" - - sqlInsert - .into('table1') - .set({ col: 1 }) - .build(); - "INSERT INTO `table1` (`col`) VALUES (1)" - - sqlInsert - .into('table1') - .set({ col1: 1, col2: 'a' }) - .build(); - "INSERT INTO `table1` (`col1`, `col2`) VALUES (1, 'a')" - -##Update - - var sqlUpdate = sqlQuery.update() - - sqlUpdate - .into('table1') - .build(); - "UPDATE `table1`" - - sqlUpdate - .into('table1') - .set({ col: 1 }) - .build(); - "UPDATE `table1` SET `col` = 1" - - sqlUpdate - .into('table1') - .set({ col1: 1, col2: 2 }) - .build(); - "UPDATE `table1` SET `col1` = 1, `col2` = 2" - - sqlUpdate - .into('table1') - .set({ col1: 1, col2: 2 }).where({ id: 3 }) - .build(); - "UPDATE `table1` SET `col1` = 1, `col2` = 2 WHERE `id` = 3" +# Usage +```js +var sql = require('sql-query'), + sqlQuery = sql.Query(); +``` + +## Create +```js +var sqlCreate = sqlQuery.create(); + +sqlCreate + .table('table1') + .build() + +"CREATE TABLE 'table1'()" + + +sqlCreate + .table('table1') + .field('id','id') + .build() + +"CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT)" + + +sqlCreate + .table('table1') + .fields({id: 'id', a_text: 'text'}) + .build() + +"CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_text' TEXT)" + + +sqlCreate + .table('table1') + .fields({id: 'id', a_num: 'int'}) + .build() + +"CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' INTEGER)" + + +sqlCreate + .table('table1') + .fields({id: 'id', a_num: 'float'}) + .build() + +"CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_num' FLOAT(12,2))" + + +sqlCreate + .table('table1') + .fields({id: 'id', a_bool: 'bool'}) + .build() + +"CREATE TABLE 'table1'('id' INTEGER PRIMARY KEY AUTO_INCREMENT,'a_bool' TINYINT(1))" +``` + +## Select +```js +var sqlSelect = sqlQuery.select(); + +sqlSelect + .from('table1') + .build(); + +"SELECT * FROM `table1`" + + +sqlSelect + .from('table1') + .select('id', 'name') + .build(); + +"SELECT `id`, `name` FROM `table1`" + + +sqlSelect + .from('table1') + .select('id', 'name') + .as('label') + .build(); + +"SELECT `id`, `name` AS `label` FROM `table1`" + + +sqlSelect + .from('table1') + .select('id', 'name') + .select('title') + .as('label') + .build(); + +"SELECT `id`, `name`, `title` AS `label` FROM `table1`" + + +sqlSelect + .from('table1') + .select('id', 'name') + .as('label') + .select('title') + .build(); + +"SELECT `id`, `name` AS `label`, `title` FROM `table1`" + + +sqlSelect + .from('table1') + .select([ 'id', 'name' ]) + .build(); + +"SELECT `id`, `name` FROM `table1`" + + +sqlSelect + .from('table1') + .select() + .build(); + +"SELECT * FROM `table1`" + + +sqlSelect + .from('table1') + .select(['abc','def', { a: 'ghi', sql: 'SOMEFUNC(ghi)' }]) + .build(); + +"SELECT `abc`, `def`, (SOMEFUNC(ghi)) AS `ghi` FROM `table1`" + + +sqlSelect + .calculateFoundRows() + .from('table1') + .build(); + +"SELECT SQL_CALC_FOUND_ROWS * FROM `table1`" + + +sqlSelect + .calculateFoundRows() + .from('table1') + .select('id') + .build(); + +"SELECT SQL_CALC_FOUND_ROWS `id` FROM `table1`" + + +sqlSelect + .from('table1') + .select('id1', 'name') + .from('table2', 'id2', 'id1') + .select('id2') + .build(); + +"SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .select('id1') + .from('table2', 'id2', 'id1', { joinType: 'left inner' }) + .select('id2') + .build(); + +"SELECT `t1`.`id1`, `t2`.`id2` FROM `table1` `t1` LEFT INNER JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .select('id1', 'name') + .from('table2', 'id2', 'table1', 'id1') + .select('id2') + .build(); + +"SELECT `t1`.`id1`, `t1`.`name`, `t2`.`id2` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count() + .build(); + +"SELECT COUNT(*) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count(null, 'c') + .build(); + +"SELECT COUNT(*) AS `c` FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count('id') + .build(); + +"SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .count('id') + .from('table2', 'id2', 'table1', 'id1') + .count('id') + .build(); + +"SELECT COUNT(`t1`.`id`), COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .count('id') + .count('col') + .build(); + +"SELECT COUNT(`t2`.`id`), COUNT(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .from('table2', 'id2', 'table1', 'id1') + .fun('AVG', 'col') + .build(); + +"SELECT AVG(`t2`.`col`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2` = `t1`.`id1`" + + +sqlSelect + .from('table1') + .from('table2',['id2a', 'id2b'], 'table1', ['id1a', 'id1b']) + .count('id') + .build(); + +"SELECT COUNT(`t2`.`id`) FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id2a` = `t1`.`id1a` AND `t2`.`id2b` = `t1`.`id1b`" +``` + +## Where +```js +var sqlSelect = sqlQuery.select(); + +sqlSelect + .from('table1') + .where() + .build(); + +"SELECT * FROM `table1`" + + +sqlSelect + .from('table1') + .where(null) + .build(); + +"SELECT * FROM `table1`" + + +sqlSelect + .from('table1') + .where({ col: 1 }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = 1" + + +sqlSelect + .from('table1') + .where({ col: 0 }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = 0" + + +sqlSelect + .from('table1') + .where({ col: null }) + .build(); + +"SELECT * FROM `table1` WHERE `col` IS NULL" + + +sqlSelect + .from('table1') + .where({ col: sql.eq(null) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` IS NULL" + + +sqlSelect + .from('table1') + .where({ col: sql.ne(null) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` IS NOT NULL" + + +sqlSelect + .from('table1') + .where({ col: undefined }) + .build(); + +"SELECT * FROM `table1` WHERE `col` IS NULL" + + +sqlSelect + .from('table1') + .where({ col: false }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = false" + + +sqlSelect + .from('table1') + .where({ col: "" }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = ''" + + +sqlSelect + .from('table1') + .where({ col: true }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = true" + + +sqlSelect + .from('table1') + .where({ col: 'a' }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = 'a'" + + +sqlSelect + .from('table1') + .where({ col: 'a\'' }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = 'a\\''" + + +sqlSelect + .from('table1') + .where({ col: [ 1, 2, 3 ] }) + .build(); + +"SELECT * FROM `table1` WHERE `col` IN (1, 2, 3)" + + +sqlSelect + .from('table1') + .where({ col: [] }) + .build(); + +"SELECT * FROM `table1` WHERE FALSE" + + +sqlSelect + .from('table1') + .where({ col1: 1, col2: 2 }) + .build(); + +"SELECT * FROM `table1` WHERE `col1` = 1 AND `col2` = 2" + + +sqlSelect + .from('table1') + .where({ col1: 1 }, { col2: 2 }) + .build(); + +"SELECT * FROM `table1` WHERE (`col1` = 1) AND (`col2` = 2)" + + +sqlSelect + .from('table1') + .where({ col: 1 }).where({ col: 2 }) + .build(); + +"SELECT * FROM `table1` WHERE (`col` = 1) AND (`col` = 2)" + + +sqlSelect + .from('table1') + .where({ col1: 1, col2: 2 }).where({ col3: 3 }) + .build(); + +"SELECT * FROM `table1` WHERE (`col1` = 1 AND `col2` = 2) AND (`col3` = 3)" + + +sqlSelect + .from('table1') + .from('table2', 'id', 'id') + .where('table1', { col: 1 }, 'table2', { col: 2 }) + .build(); + +"SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`t2`.`col` = 2)" + + +sqlSelect + .from('table1') + .from('table2', 'id', 'id') + .where('table1', { col: 1 }, { col: 2 }) + .build(); + +"SELECT * FROM `table1` `t1` JOIN `table2` `t2` ON `t2`.`id` = `t1`.`id` WHERE (`t1`.`col` = 1) AND (`col` = 2)" + + +sqlSelect + .from('table1') + .where({ col: sql.gt(1) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` > 1" + + +sqlSelect + .from('table1') + .where({ col: sql.gte(1) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` >= 1" + + +sqlSelect + .from('table1') + .where({ col: sql.lt(1) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` < 1" + + +sqlSelect + .from('table1') + .where({ col: sql.lte(1) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` <= 1" + + +sqlSelect + .from('table1') + .where({ col: sql.eq(1) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` = 1" + + +sqlSelect + .from('table1') + .where({ col: sql.ne(1) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` <> 1" + + +sqlSelect + .from('table1') + .where({ col: sql.between('a', 'b') }) + .build(); + +"SELECT * FROM `table1` WHERE `col` BETWEEN 'a' AND 'b'" + + +sqlSelect + .from('table1') + .where({ col: sql.not_between('a', 'b') }) + .build(); + +"SELECT * FROM `table1` WHERE `col` NOT BETWEEN 'a' AND 'b'" + + +sqlSelect + .from('table1') + .where({ col: sql.like('abc') }) + .build(); + +"SELECT * FROM `table1` WHERE `col` LIKE 'abc'" + + +sqlSelect + .from('table1') + .where({ col: + sql.not_like('abc') }) + .build(); + +"SELECT * FROM `table1` WHERE `col` NOT LIKE 'abc'" + + +sqlSelect + .from('table1') + .where({ col: sql.not_in([ 1, 2, 3 ]) }) + .build(); + +"SELECT * FROM `table1` WHERE `col` NOT IN (1, 2, 3)" + + +sqlSelect + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE 'peaches'"]] }) + .build(); + +"SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" + + +sqlSelect + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE ?", ['peaches']]] }) + .build(); + +"SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches'" + + +sqlSelect + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` > ?", ['peaches', 12]]] }) + .build(); + +"SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` > 12" + + +sqlSelect + .from('table1') + .where({ __sql: [["LOWER(`stuff`) LIKE ? AND `number` == ?", ['peaches']]] }) + .build(); + +"SELECT * FROM `table1` WHERE LOWER(`stuff`) LIKE 'peaches' AND `number` == NULL" +``` + +## Order +```js +var sqlSelect = sqlQuery.select(); + +sqlSelect + .from('table1') + .order('col') + .build(); + +"SELECT * FROM `table1` ORDER BY `col` ASC" + + +sqlSelect + .from('table1') + .order('col', 'A') + .build(); + +"SELECT * FROM `table1` ORDER BY `col` ASC" + + +sqlSelect + .from('table1') + .order('col', 'Z') + .build(); + +"SELECT * FROM `table1` ORDER BY `col` DESC" + + +sqlSelect + .from('table1') + .order('col').order('col2', 'Z') + .build(); + +"SELECT * FROM `table1` ORDER BY `col` ASC, `col2` DESC" + + +sqlSelect + .from('table1') + .order('col', []) + .build(); + +"SELECT * FROM `table1` ORDER BY col" + + +sqlSelect + .from('table1') + .order('?? DESC', ['col']) + .build(); + +"SELECT * FROM `table1` ORDER BY `col` DESC" + + +sqlSelect + .from('table1') + .order('ST_Distance(??, ST_GeomFromText(?,4326))', ['geopoint', 'POINT(-68.3394 27.5578)']) + .build(); + +"SELECT * FROM `table1` ORDER BY ST_Distance(`geopoint`, ST_GeomFromText('POINT(-68.3394 27.5578)',4326))" +``` + +## Limit + +```js +var sqlSelect = sqlQuery.select(); + +sqlSelect + .from('table1') + .limit(123) + .build(); + +"SELECT * FROM `table1` LIMIT 123" + + +sqlSelect + .from('table1') + .limit('123456789') + .build(); + +"SELECT * FROM `table1` LIMIT 123456789" +``` + +## Select function + +```js +var sqlSelect = sqlQuery.select(); + +sqlSelect + .from('table1') + .fun('myfun', 'col1') + .build(); + +"SELECT MYFUN(`col1`) FROM `table1`" + + +sqlSelect + .from('table1') + .fun('myfun', [ 'col1', 'col2']) + .build(); + +"SELECT MYFUN(`col1`, `col2`) FROM `table1`" + + +sqlSelect + .from('table1') + .fun('dbo.fnBalance', [ 80, null, null], 'balance') + .build(); + +"SELECT DBO.FNBALANCE(80, NULL, NULL) AS `balance` FROM `table1`" + + +sqlSelect + .from('table1') + .fun('myfun', [ 'col1', 'col2'], 'alias') + .build(); + +"SELECT MYFUN(`col1`, `col2`) AS `alias` FROM `table1`" + + +sqlSelect + .from('table1') + .fun('myfun', [ 'col1', sqlQuery.Text('col2') ], 'alias') + .build(); + +"SELECT MYFUN(`col1`, 'col2') AS `alias` FROM `table1`" +``` + +## Insert + +```js +var sqlInsert = sqlQuery.insert(); + +sqlInsert + .into('table1') + .build(); + +"INSERT INTO `table1`" + + +sqlInsert + .into('table1') + .set({}) + .build(); + +"INSERT INTO `table1` VALUES()" + + +sqlInsert + .into('table1') + .set({ col: 1 }) + .build(); + +"INSERT INTO `table1` (`col`) VALUES (1)" + + +sqlInsert + .into('table1') + .set({ col1: 1, col2: 'a' }) + .build(); + +"INSERT INTO `table1` (`col1`, `col2`) VALUES (1, 'a')" +``` + +## Update + +```js +var sqlUpdate = sqlQuery.update() + +sqlUpdate + .into('table1') + .build(); + +"UPDATE `table1`" + + +sqlUpdate + .into('table1') + .set({ col: 1 }) + .build(); + +"UPDATE `table1` SET `col` = 1" + + +sqlUpdate + .into('table1') + .set({ col1: 1, col2: 2 }) + .build(); + +"UPDATE `table1` SET `col1` = 1, `col2` = 2" + + +sqlUpdate + .into('table1') + .set({ col1: 1, col2: 2 }).where({ id: 3 }) + .build(); + +"UPDATE `table1` SET `col1` = 1, `col2` = 2 WHERE `id` = 3" +``` From 45c7c7330e0bc84ba4bc7838085cc0a77e0eee9e Mon Sep 17 00:00:00 2001 From: Joseph Lee Hunsaker Date: Tue, 3 Apr 2018 16:07:23 -0600 Subject: [PATCH 104/106] show how to configure dialect --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index aafb788..f6b87e3 100644 --- a/Readme.md +++ b/Readme.md @@ -24,7 +24,7 @@ Sorry the API documentation is not complete. There are tests in ./test/integrati # Usage ```js var sql = require('sql-query'), - sqlQuery = sql.Query(); + sqlQuery = sql.Query(); //for dialect: sql.Query('postgresql') ``` ## Create From 244151f8c9180bfb32a81224356a832b560d5b5c Mon Sep 17 00:00:00 2001 From: Arek W Date: Wed, 27 Jun 2018 12:10:34 +0000 Subject: [PATCH 105/106] Fix crash with objects and symbols --- .travis.yml | 8 ++++---- Changelog.md | 4 ++++ lib/Dialects/mssql.js | 6 +++++- lib/Dialects/mysql.js | 2 +- lib/Dialects/postgresql.js | 6 +++++- lib/Dialects/sqlite.js | 6 +++++- package-lock.json | 20 ++++++++++++++++++++ package.json | 13 +++++++++---- test/integration/test-dialect-mssql.js | 10 ++++++++++ test/integration/test-dialect-mysql.js | 10 ++++++++++ test/integration/test-dialect-postgresql.js | 10 ++++++++++ test/integration/test-dialect-sqlite.js | 10 ++++++++++ 12 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 package-lock.json diff --git a/.travis.yml b/.travis.yml index a152b92..4689cb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - '0.8' - - '0.10' - - '0.12' - - 'iojs' + - '4' + - '6' + - '8' + - '10' diff --git a/Changelog.md b/Changelog.md index 7a5ed33..442b57b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +### v0.1.27 - 27 Jun 2018 + +- Handle objects & symbols causing crash in driver 'escapeVal' (#54) + ### v0.1.26 - 16 May 2015 - Add support for SELECT TOP construct for mssql dialect for limit (#41) diff --git a/lib/Dialects/mssql.js b/lib/Dialects/mssql.js index e49f592..3a2702f 100644 --- a/lib/Dialects/mssql.js +++ b/lib/Dialects/mssql.js @@ -30,7 +30,7 @@ exports.escapeId = function () { }; exports.escapeVal = function (val, timeZone) { - if (val === undefined || val === null) { + if (val === undefined || val === null || typeof val === "symbol") { return 'NULL'; } @@ -60,6 +60,10 @@ exports.escapeVal = function (val, timeZone) { return val ? 1 : 0; case "function": return val(exports); + case "string": + break; + default: + val = JSON.stringify(val); } return "'" + val.replace(/\'/g, "''") + "'"; diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index e058814..239727a 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -30,7 +30,7 @@ exports.escapeId = function () { }; exports.escapeVal = function (val, timeZone) { - if (val === undefined || val === null) { + if (val === undefined || val === null || typeof val === "symbol") { return 'NULL'; } diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index 8a85bfc..b2a269c 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -30,7 +30,7 @@ exports.escapeId = function () { }; exports.escapeVal = function (val, timeZone) { - if (val === undefined || val === null) { + if (val === undefined || val === null || typeof val === "symbol") { return 'NULL'; } @@ -60,6 +60,10 @@ exports.escapeVal = function (val, timeZone) { return val ? "true" : "false"; case "function": return val(exports); + case "string": + break; + default: + val = JSON.stringify(val); } // No need to escape backslashes with default PostgreSQL 9.1+ config. // Google 'postgresql standard_conforming_strings' for details. diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 91fc205..547d9f5 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -18,7 +18,7 @@ exports.escape = function (query, args) { exports.escapeId = require("./mysql").escapeId; exports.escapeVal = function (val, timeZone) { - if (val === undefined || val === null) { + if (val === undefined || val === null || typeof val === "symbol") { return 'NULL'; } @@ -48,6 +48,10 @@ exports.escapeVal = function (val, timeZone) { return val ? 1 : 0; case "function": return val(exports); + case "string": + break; + default: + val = JSON.stringify(val); } // No need to escape backslashes with default PostgreSQL 9.1+ config. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..fc9ede4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,20 @@ +{ + "name": "sql-query", + "version": "0.1.27", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "urun": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/urun/-/urun-0.0.8.tgz", + "integrity": "sha1-N5mgKTcUwRFdMmpOaeKl+W7nhuI=", + "dev": true + }, + "utest": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/utest/-/utest-0.0.8.tgz", + "integrity": "sha1-/AlFH+aXuQCNDEMv4NtDnWzzeRQ=", + "dev": true + } + } +} diff --git a/package.json b/package.json index a952de9..a765828 100644 --- a/package.json +++ b/package.json @@ -5,15 +5,20 @@ "keywords": [ "sql", "query" - ], - "version": "0.1.26", + ], + "version": "0.1.27", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query" }, "contributors": [ - { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" }, - { "name" : "Arek W" } + { + "name": "Benjamin Pannell", + "email": "admin@sierrasoftworks.com" + }, + { + "name": "Arek W" + } ], "scripts": { "test": "make" diff --git a/test/integration/test-dialect-mssql.js b/test/integration/test-dialect-mssql.js index 2d419ad..71e792b 100644 --- a/test/integration/test-dialect-mssql.js +++ b/test/integration/test-dialect-mssql.js @@ -69,6 +69,16 @@ assert.equal( "0" ); +assert.equal( + dialect.escapeVal({ key: 'value' }), + "'{\"key\":\"value\"}'" +); + +assert.equal( + dialect.escapeVal(Symbol("why does this exist")), + "NULL" +) + assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), "'2013-09-04 19:15:11.133'" diff --git a/test/integration/test-dialect-mysql.js b/test/integration/test-dialect-mysql.js index fa7b836..e689c58 100644 --- a/test/integration/test-dialect-mysql.js +++ b/test/integration/test-dialect-mysql.js @@ -69,6 +69,16 @@ assert.equal( "false" ); +assert.equal( + dialect.escapeVal({ key: 'value' }), + "`key` = 'value'" +); + +assert.equal( + dialect.escapeVal(Symbol("why does this exist")), + "NULL" +) + assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), "'2013-09-04 19:15:11.133'" diff --git a/test/integration/test-dialect-postgresql.js b/test/integration/test-dialect-postgresql.js index 5590bff..55c9fac 100644 --- a/test/integration/test-dialect-postgresql.js +++ b/test/integration/test-dialect-postgresql.js @@ -74,6 +74,16 @@ assert.equal( "false" ); +assert.equal( + dialect.escapeVal({ key: 'value' }), + "'{\"key\":\"value\"}'" +); + +assert.equal( + dialect.escapeVal(Symbol("why does this exist")), + "NULL" +) + assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), "'2013-09-04 19:15:11.133'" diff --git a/test/integration/test-dialect-sqlite.js b/test/integration/test-dialect-sqlite.js index a002b02..c4a3d6a 100644 --- a/test/integration/test-dialect-sqlite.js +++ b/test/integration/test-dialect-sqlite.js @@ -69,6 +69,16 @@ assert.equal( "0" ); +assert.equal( + dialect.escapeVal({ key: 'value' }), + "'{\"key\":\"value\"}'" +); + +assert.equal( + dialect.escapeVal(Symbol("why does this exist")), + "NULL" +) + assert.equal( dialect.escapeVal(new Date(d.getTime() + tzOffsetMillis)), "'2013-09-04 19:15:11.133'" From fcbbb60a7f2c8d99edbb09aeebdf1494f9d8394a Mon Sep 17 00:00:00 2001 From: Arek W Date: Thu, 13 Mar 2025 14:06:57 +0100 Subject: [PATCH 106/106] Replace deprecated util.isDate usage Deprecated in Node.js 21/22 --- Changelog.md | 4 ++++ lib/Dialects/mssql.js | 3 +-- lib/Dialects/mysql.js | 3 +-- lib/Dialects/postgresql.js | 3 +-- lib/Dialects/sqlite.js | 4 +--- package-lock.json | 2 +- package.json | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Changelog.md b/Changelog.md index 442b57b..b0f649a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +### v0.1.28 - 13 March 2025 + +- Replace deprecated (in Node.js 22) `util.isDate(val)` with `val instanceof Date` + ### v0.1.27 - 27 Jun 2018 - Handle objects & symbols causing crash in driver 'escapeVal' (#54) diff --git a/lib/Dialects/mssql.js b/lib/Dialects/mssql.js index 3a2702f..d5c4246 100644 --- a/lib/Dialects/mssql.js +++ b/lib/Dialects/mssql.js @@ -1,4 +1,3 @@ -var util = require("util"); var helpers = require("../Helpers"); exports.DataTypes = { @@ -41,7 +40,7 @@ exports.escapeVal = function (val, timeZone) { return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; } - if (util.isDate(val)) { + if (val instanceof Date) { return "'" + helpers.dateToString(val, timeZone || "local", { dialect: 'mssql' }) + "'"; } diff --git a/lib/Dialects/mysql.js b/lib/Dialects/mysql.js index 239727a..7d8ec98 100644 --- a/lib/Dialects/mysql.js +++ b/lib/Dialects/mysql.js @@ -1,4 +1,3 @@ -var util = require("util"); var helpers = require("../Helpers"); exports.DataTypes = { @@ -42,7 +41,7 @@ exports.escapeVal = function (val, timeZone) { return arrayToList(val, timeZone || "local"); } - if (util.isDate(val)) { + if (val instanceof Date) { val = helpers.dateToString(val, timeZone || "local", { dialect: 'mysql' }); } else { switch (typeof val) { diff --git a/lib/Dialects/postgresql.js b/lib/Dialects/postgresql.js index b2a269c..0a42d72 100644 --- a/lib/Dialects/postgresql.js +++ b/lib/Dialects/postgresql.js @@ -1,4 +1,3 @@ -var util = require("util"); var helpers = require("../Helpers"); exports.DataTypes = { @@ -41,7 +40,7 @@ exports.escapeVal = function (val, timeZone) { return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; } - if (util.isDate(val)) { + if (val instanceof Date) { return "'" + helpers.dateToString(val, timeZone || "local", { dialect: 'postgresql' }) + "'"; } diff --git a/lib/Dialects/sqlite.js b/lib/Dialects/sqlite.js index 547d9f5..4ec0a34 100644 --- a/lib/Dialects/sqlite.js +++ b/lib/Dialects/sqlite.js @@ -1,7 +1,5 @@ -var util = require("util"); var helpers = require("../Helpers"); - exports.DataTypes = { isSQLITE: true, id: 'INTEGER PRIMARY KEY AUTOINCREMENT', @@ -29,7 +27,7 @@ exports.escapeVal = function (val, timeZone) { return "(" + val.map(exports.escapeVal.bind(this)).join(", ") + ")"; } - if (util.isDate(val)) { + if (val instanceof Date) { return "'" + helpers.dateToString(val, timeZone || "local", { dialect: 'sqlite' }) + "'"; } diff --git a/package-lock.json b/package-lock.json index fc9ede4..27767b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "sql-query", - "version": "0.1.27", + "version": "0.1.28", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a765828..0d398d5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sql", "query" ], - "version": "0.1.27", + "version": "0.1.28", "license": "MIT", "repository": { "url": "http://github.com/dresende/node-sql-query"