From a9bdc3db8837a8c95a75e760246badaaf5f8fea6 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 31 Aug 2013 12:31:53 -0400 Subject: [PATCH 001/248] Initial commit for adding SQL Sever dialect. Trying to get a feel for things and get the tests and everything working. --- lib/dialect/index.js | 2 ++ lib/dialect/sqlserver.js | 63 +++++++++++++++++++++++++++++++++++ test/dialects/select-tests.js | 4 +++ test/index-tests.js | 14 ++++++++ 4 files changed, 83 insertions(+) create mode 100644 lib/dialect/sqlserver.js diff --git a/lib/dialect/index.js b/lib/dialect/index.js index 06dbd8c6..68ae5857 100644 --- a/lib/dialect/index.js +++ b/lib/dialect/index.js @@ -9,6 +9,8 @@ var getDialect = function(dialect) { return require('./mysql'); case 'sqlite': return require('./sqlite'); + case 'sqlserver': + return require('./sqlserver'); default: throw new Error(dialect + ' is unsupported'); } diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js new file mode 100644 index 00000000..b93e5ba9 --- /dev/null +++ b/lib/dialect/sqlserver.js @@ -0,0 +1,63 @@ +'use strict'; + +var util = require('util'); +var assert = require('assert'); + +var SqlServer = function() { + this.output = []; + this.params = []; +}; + +var Postgres = require(__dirname + '/postgres'); + +util.inherits(SqlServer, Postgres); + +SqlServer.prototype._myClass = SqlServer; + +SqlServer.prototype._quoteCharacter = '['; + +SqlServer.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; + +/* jshint unused: false */ +SqlServer.prototype._getParameterPlaceholder = function(index, value) { + return '?'; +}; + +//Mysql.prototype.visitCreate = function(create) { +// var result = Mysql.super_.prototype.visitCreate.call(this, create); +// var engine = this._queryNode.table._initialConfig.engine; +// var charset = this._queryNode.table._initialConfig.charset; +// +// if ( !! engine) { +// result.push('ENGINE=' + engine); +// } +// +// if ( !! charset) { +// result.push('DEFAULT CHARSET=' + charset); +// } +// +// return result; +//}; +// +//Mysql.prototype.visitRenameColumn = function(renameColumn) { +// var dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; +// assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + +// ' (CHANGE COLUMN statements require a dataType)'); +// return ['CHANGE COLUMN ' + this.visit(renameColumn.nodes[0]) + ' ' + this.visit(renameColumn.nodes[1]) + ' ' + dataType]; +//}; +// +//Mysql.prototype.visitInsert = function(insert) { +// var result = Postgres.prototype.visitInsert.call(this, insert); +// if (result[2] === 'DEFAULT VALUES') { +// result[2] = '() VALUES ()'; +// } +// return result; +//}; +// +//Mysql.prototype.visitIndexes = function(node) { +// var tableName = this.visit(this._queryNode.table.toNode()); +// +// return "SHOW INDEX FROM " + tableName; +//}; + +module.exports = SqlServer; diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 0809574c..34d2283a 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -17,5 +17,9 @@ Harness.test({ text : 'SELECT `post`.`id`, `post`.`content` FROM `post`', string: 'SELECT `post`.`id`, `post`.`content` FROM `post`' }, + sqlserver: { + text : 'SELECT [post].[id]. [post].[content] FROM [post]', + string: 'SELECT [post].[id]. [post].[content] FROM [post]' + }, params: [] }); diff --git a/test/index-tests.js b/test/index-tests.js index a959d357..7336ddcc 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -27,6 +27,10 @@ suite('index', function() { assert.equal(sql.create('mysql').dialectName, 'mysql'); }); + test('stores the sqlserver dialect', function() { + assert.equal(sql.create('sqlserver').dialectName, 'sqlserver'); + }); + test('can create a query using the default dialect', function() { var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); assert.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); @@ -52,14 +56,17 @@ suite('index', function() { var mysql = sql.create('mysql'); var postgres = sql.create('postgres'); var sqlite = sql.create('sqlite'); + var sqlserver = sql.create('sqlserver'); var mysqlTable = mysql.define({name: 'table', columns: ['column']}); var postgresTable = postgres.define({name: 'table', columns: ['column']}); var sqliteTable = sqlite.define({name: 'table', columns: ['column']}); + var sqlserverTable = sqlserver.define({name: 'table', columns: ['column']}); assert.equal(mysqlTable.sql, mysql); assert.equal(postgresTable.sql, postgres); assert.equal(sqliteTable.sql, sqlite); + assert.equal(sqlserverTable.sql, sqlserver); }); test('using Sql as a class', function() { @@ -67,10 +74,12 @@ suite('index', function() { var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); + var sqlserver = new Sql('sqlserver'); assert.equal(mysql.dialect, require(__dirname + '/../lib/dialect/mysql')); assert.equal(postgres.dialect, require(__dirname + '/../lib/dialect/postgres')); assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); + assert.equal(sqlserver.dialect, require(__dirname + '/../lib/dialect/sqlserver')); }); test('override dialect for toQuery using dialect name', function() { @@ -78,10 +87,12 @@ suite('index', function() { var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); + var sqlserver = new Sql('sqlserver'); var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlite'); var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('postgres'); var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mysql'); +// var sqlserverQuery = mysqlQuery.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlserver'); var values = ['brian.m.carlson@gmail.com']; assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); @@ -92,6 +103,9 @@ suite('index', function() { assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); assert.deepEqual(mysqlQuery.values, values); + +// assert.equal(sqlserverQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = ?)'); +// assert.deepEqual(sqlserverQuery.values, values); }); test('override dialect for toQuery using invalid dialect name', function() { From 2a68333c4a33a40a636466a9404d8c49611428ba Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 31 Aug 2013 13:16:49 -0400 Subject: [PATCH 002/248] - Handle "quoting" with square-brackets for sql server. - Updated the test runner to run tests for "sqlserver" - Updated select-tests and table-tests --- lib/dialect/postgres.js | 8 ++- test/dialects/select-tests.js | 4 +- test/dialects/support.js | 3 +- test/dialects/table-tests.js | 92 +++++++++++++++++++++++++++++++++++ test/index-tests.js | 2 +- 5 files changed, 103 insertions(+), 6 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a01d6311..f57ac34e 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -154,8 +154,12 @@ Postgres.prototype.quote = function(word, quoteCharacter) { } else { q = this._quoteCharacter; } - - return q + word.replace(new RegExp(q,'g'),q+q) + q; + // handle square brackets specially + if (q=='['){ + return '['+word+']' + } else { + return q + word.replace(new RegExp(q,'g'),q+q) + q; + } }; Postgres.prototype.visitSelect = function(select) { diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 34d2283a..9e0c0979 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -18,8 +18,8 @@ Harness.test({ string: 'SELECT `post`.`id`, `post`.`content` FROM `post`' }, sqlserver: { - text : 'SELECT [post].[id]. [post].[content] FROM [post]', - string: 'SELECT [post].[id]. [post].[content] FROM [post]' + text : 'SELECT [post].[id], [post].[content] FROM [post]', + string: 'SELECT [post].[id], [post].[content] FROM [post]' }, params: [] }); diff --git a/test/dialects/support.js b/test/dialects/support.js index 6eabee5c..2596f328 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -7,7 +7,8 @@ var Table = require('../../lib/table'); var dialects = { pg : require('../../lib/dialect/postgres'), sqlite : require('../../lib/dialect/sqlite'), - mysql : require('../../lib/dialect/mysql') + mysql : require('../../lib/dialect/mysql'), + sqlserver : require('../../lib/dialect/sqlserver') }; module.exports = { diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 01c2c1aa..e10ba782 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user`', string: 'SELECT `user`.`id` FROM `user`' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user]', + string: 'SELECT [user].[id] FROM [user]' + }, params: [] }); @@ -34,6 +38,10 @@ Harness.test({ text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, + sqlserver: { + text : 'SELECT [user].[id], [user].[name] FROM [user]', + string: 'SELECT [user].[id], [user].[name] FROM [user]' + }, params: [] }); @@ -51,6 +59,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user`', string: 'SELECT `user`.* FROM `user`' }, + sqlserver: { + text : 'SELECT [user].* FROM [user]', + string: 'SELECT [user].* FROM [user]' + }, params: [] }); @@ -68,6 +80,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'foo\')' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = ?)', + string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'foo\')' + }, params: ['foo'] }); @@ -85,6 +101,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = ?) OR ([user].[name] = ?))', + string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -102,6 +122,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') AND (`user`.`name` = \'bar\'))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = ?) AND ([user].[name] = ?))', + string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') AND ([user].[name] = \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -119,6 +143,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = ?) OR ([user].[name] = ?))', + string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -136,6 +164,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'foo\') OR (`user`.`name` = \'baz\')) AND (`user`.`name` = \'bar\'))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = ?) OR ([user].[name] = ?)) AND ([user].[name] = ?))', + string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'foo\') OR ([user].[name] = \'baz\')) AND ([user].[name] = \'bar\'))' + }, params: ['foo', 'baz', 'bar'] }); @@ -153,6 +185,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (\'foo\', \'bar\'))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (?, ?))', + string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (\'foo\', \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -170,6 +206,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (\'foo\', \'bar\')) AND (`user`.`id` = 1))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (?, ?)) AND ([user].[id] = ?))', + string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (\'foo\', \'bar\')) AND ([user].[id] = 1))' + }, params: ['foo', 'bar', 1] }); @@ -187,6 +227,10 @@ Harness.test({ text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, + sqlserver: { + text : 'SELECT [user].[id], [user].[name] FROM [user]', + string: 'SELECT [user].[id], [user].[name] FROM [user]' + }, params: [] }); @@ -211,6 +255,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'boom\') AND (`user`.`id` = 1)) OR ((`user`.`name` = \'bang\') AND (`user`.`id` = 2)))' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = ?) AND ([user].[id] = ?)) OR (([user].[name] = ?) AND ([user].[id] = ?)))', + string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'boom\') AND ([user].[id] = 1)) OR (([user].[name] = \'bang\') AND ([user].[id] = 2)))' + }, params: ['boom', 1, 'bang', 2] }); @@ -228,6 +276,10 @@ Harness.test({ text : 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`', string: 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' }, + sqlserver: { + text : 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]', + string: 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]' + }, params: [] }); @@ -245,6 +297,10 @@ Harness.test({ text : 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, + sqlsever: { + text : 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = ?)', + string: 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = \'brian\')' + }, params: ['brian'] }); @@ -262,6 +318,10 @@ Harness.test({ text : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, + sqlserver: { + text : 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = ?)', + string: 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = \'brian\')' + }, params: ['brian'] }); @@ -279,6 +339,10 @@ Harness.test({ text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, + sqlserver: { + text : 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, params: [] }); @@ -296,6 +360,10 @@ Harness.test({ text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, + sqlserver: { + text : 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, params: [] }); @@ -313,6 +381,10 @@ Harness.test({ text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, + sqlserver: { + text : 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, params: [] }); @@ -330,6 +402,10 @@ Harness.test({ text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' }, + sqlserver: { + text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, params: [] }); @@ -349,6 +425,10 @@ Harness.test({ text : 'SELECT name FROM user WHERE (`user`.`name` = ?)', string: 'SELECT name FROM user WHERE (`user`.`name` = \'brian\')' }, + sqlserver: { + text : 'SELECT name FROM user WHERE ([user].[name] = ?)', + string: 'SELECT name FROM user WHERE ([user].[name] = \'brian\')' + }, params: ['brian'] }); @@ -369,6 +449,10 @@ Harness.test({ text : 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', string: 'SELECT name FROM user WHERE ((`user`.`name` = \'brian\') AND (`user`.`id` = 1))' }, + sqlserver: { + text : 'SELECT name FROM user WHERE (([user].[name] = ?) AND ([user].[id] = ?))', + string: 'SELECT name FROM user WHERE (([user].[name] = \'brian\') AND ([user].[id] = 1))' + }, params: ['brian', 1] }); @@ -386,6 +470,10 @@ Harness.test({ text : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', string: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`' }, + sqlserver: { + text : 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]', + string: 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]' + }, params: [] }); @@ -403,5 +491,9 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))' }, + sqlserver: { + text : 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))', + string: 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))' + }, params: [] }); diff --git a/test/index-tests.js b/test/index-tests.js index 7336ddcc..2c30a537 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -92,7 +92,7 @@ suite('index', function() { var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlite'); var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('postgres'); var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mysql'); -// var sqlserverQuery = mysqlQuery.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlserver'); + var sqlserverQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlserver'); var values = ['brian.m.carlson@gmail.com']; assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); From 5f972bec0575191c7104fad6d1d86d9a6ab2767d Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 31 Aug 2013 21:20:46 -0400 Subject: [PATCH 003/248] start of fixing count(*) statement for sqlserver --- lib/dialect/sqlserver.js | 6 ++++++ test/dialects/aggregate-tests.js | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index b93e5ba9..2f25d033 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -23,6 +23,12 @@ SqlServer.prototype._getParameterPlaceholder = function(index, value) { return '?'; }; +/*jshint unused: false */ +SqlServer.prototype.visitColumn = function(columnNode) { + var result = Postgres.prototype.visitColumn.call(this, columnNode); + return result; +}; + //Mysql.prototype.visitCreate = function(create) { // var result = Mysql.super_.prototype.visitCreate.call(this, create); // var engine = this._queryNode.table._initialConfig.engine; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 4eff37b3..d06e1652 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' }, + sqlserver: { + text : 'SELECT COUNT(*) AS [post_count] FROM [post]', + string: 'SELECT COUNT(*) AS [post_count] FROM [post]' + }, params: [] }); From 30c233c456447c94420fad23d9efc4b2ae4b6908 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 31 Aug 2013 21:40:05 -0400 Subject: [PATCH 004/248] - Added aggregate tests for SqlServer. Had to do a bit of work to support COUNT(*) since SqlServer doesn't allow COUNT(tableName.*). --- lib/dialect/sqlserver.js | 19 ++++++++- test/dialects/aggregate-tests.js | 73 ++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 2f25d033..6a02e75c 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -25,8 +25,16 @@ SqlServer.prototype._getParameterPlaceholder = function(index, value) { /*jshint unused: false */ SqlServer.prototype.visitColumn = function(columnNode) { - var result = Postgres.prototype.visitColumn.call(this, columnNode); - return result; + if (!isCountStartExpression(columnNode)){ + return Postgres.prototype.visitColumn.call(this, columnNode); + } + // emit our own since count(table.*) is invalid in SqlServer + var inSelectClause = !this._selectOrDeleteEndIndex; + var txt='COUNT(*)' + if(inSelectClause && columnNode.alias) { + txt += ' AS ' + this.quote(columnNode.alias); + } + return txt; }; //Mysql.prototype.visitCreate = function(create) { @@ -66,4 +74,11 @@ SqlServer.prototype.visitColumn = function(columnNode) { // return "SHOW INDEX FROM " + tableName; //}; +function isCountStartExpression(columnNode){ + if (!columnNode.aggregator) return false; + if (columnNode.aggregator.toLowerCase()!='count') return false; + if (!columnNode.star) return false; + return true; +} + module.exports = SqlServer; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index d06e1652..931a0915 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -38,6 +38,10 @@ Harness.test({ text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' }, + sqlserver: { + text : 'SELECT COUNT(*) AS [post_count] FROM [post]', + string: 'SELECT COUNT(*) AS [post_count] FROM [post]' + }, params: [] }); @@ -55,6 +59,10 @@ Harness.test({ text : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`' }, + sqlserver: { + text : 'SELECT COUNT(*) AS [post_amount] FROM [post]', + string: 'SELECT COUNT(*) AS [post_amount] FROM [post]' + }, params: [] }); @@ -72,6 +80,10 @@ Harness.test({ text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, + sqlserver: { + text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', + string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' + }, params: [] }); @@ -89,6 +101,10 @@ Harness.test({ text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, + sqlserver: { + text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', + string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' + }, params: [] }); @@ -106,6 +122,10 @@ Harness.test({ text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, + sqlserver: { + text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', + string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' + }, params: [] }); @@ -123,6 +143,10 @@ Harness.test({ text : 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`' }, + sqlserver: { + text : 'SELECT MIN([post].[id]) AS [id_min] FROM [post]', + string: 'SELECT MIN([post].[id]) AS [id_min] FROM [post]' + }, params: [] }); @@ -140,6 +164,10 @@ Harness.test({ text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' }, + sqlserver: { + text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', + string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' + }, params: [] }); @@ -157,6 +185,10 @@ Harness.test({ text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' }, + sqlserver: { + text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', + string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' + }, params: [] }); @@ -174,6 +206,10 @@ Harness.test({ text : 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`' }, + sqlserver: { + text : 'SELECT MAX([post].[id]) AS [id_max] FROM [post]', + string: 'SELECT MAX([post].[id]) AS [id_max] FROM [post]' + }, params: [] }); @@ -191,6 +227,10 @@ Harness.test({ text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' }, + sqlserver: { + text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', + string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' + }, params: [] }); @@ -208,6 +248,10 @@ Harness.test({ text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' }, + sqlserver: { + text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', + string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' + }, params: [] }); @@ -225,6 +269,10 @@ Harness.test({ text : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`' }, + sqlserver: { + text : 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]', + string: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]' + }, }); Harness.test({ @@ -241,6 +289,11 @@ Harness.test({ text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' }, + sqlserver: { + text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', + string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' + }, + params: [] }); Harness.test({ @@ -257,6 +310,11 @@ Harness.test({ text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' }, + sqlserver: { + text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', + string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' + }, + params: [] }); Harness.test({ @@ -273,6 +331,11 @@ Harness.test({ text : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`' }, + sqlserver: { + text : 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]', + string: 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]' + }, + params: [] }); Harness.test({ @@ -289,6 +352,11 @@ Harness.test({ text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' }, + sqlserver: { + text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', + string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' + }, + params: [] }); Harness.test({ @@ -305,4 +373,9 @@ Harness.test({ text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' }, + sqlserver: { + text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', + string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' + }, + params: [] }); From 3cddc3514ab9ec414001cc7737df989a6c74d45e Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 31 Aug 2013 21:40:59 -0400 Subject: [PATCH 005/248] - Added a missing "params:[]" field in test. --- test/dialects/aggregate-tests.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 931a0915..b0f0d6ff 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -273,6 +273,7 @@ Harness.test({ text : 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]', string: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]' }, + params: [] }); Harness.test({ From 9d50ea8d3f8d08ac079eab46f9c1bfd161b54257 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sun, 1 Sep 2013 01:51:08 -0400 Subject: [PATCH 006/248] - Added alias-tests for SqlServer. --- test/dialects/alias-tests.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index 6981aaa6..87f56f36 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', string: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`' }, + sqlserver: { + text : 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]', + string: 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]' + }, params: [] }); @@ -34,6 +38,10 @@ Harness.test({ text : 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > ?) AND (`customer`.`age` < ?))', string: 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > 10) AND (`customer`.`age` < 20))' }, + sqlserver: { + text : 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > ?) AND ([customer].[age] < ?))', + string: 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > 10) AND ([customer].[age] < 20))' + }, params: [10, 20] }); @@ -51,5 +59,9 @@ Harness.test({ text : 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', string: 'SELECT (`customer`.`age` BETWEEN 10 AND 20) AS `ageBetween` FROM `customer`' }, + sqlserver: { + text : 'SELECT ([customer].[age] BETWEEN ? AND ?) AS [ageBetween] FROM [customer]', + string: 'SELECT ([customer].[age] BETWEEN 10 AND 20) AS [ageBetween] FROM [customer]' + }, params: [10, 20] }); From 27ae56728e3e19cb4974f1047876c82e7e573f79 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 01:36:19 -0400 Subject: [PATCH 007/248] - Implemented the alter-table-tests for SqlServer. Renaming of columns does not yet work because the syntax for SqlServer and the way visitXxx doesn't mesh well. Need to work on this. Also had to implement special code for renaming tables, adding columns, and dropping columns. --- lib/dialect/sqlserver.js | 118 +++++++++++++++++++++++++++-- test/dialects/alter-table-tests.js | 52 +++++++++++++ 2 files changed, 162 insertions(+), 8 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 6a02e75c..59e32119 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -25,16 +25,94 @@ SqlServer.prototype._getParameterPlaceholder = function(index, value) { /*jshint unused: false */ SqlServer.prototype.visitColumn = function(columnNode) { - if (!isCountStartExpression(columnNode)){ - return Postgres.prototype.visitColumn.call(this, columnNode); + if (!isCountStarExpression(columnNode)){ + return SqlServer.super_.prototype.visitColumn.call(this, columnNode); } // emit our own since count(table.*) is invalid in SqlServer var inSelectClause = !this._selectOrDeleteEndIndex; - var txt='COUNT(*)' + var result='COUNT(*)' if(inSelectClause && columnNode.alias) { - txt += ' AS ' + this.quote(columnNode.alias); + result += ' AS ' + this.quote(columnNode.alias); } - return txt; + return result; +}; + +SqlServer.prototype.visitAlter = function(alter) { + var _this=this; + var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; + + // Implement our own add column: + // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" + // SqlServer: ALTER TABLE [name] ADD [col1], [col2] + function addColumn(){ + _this._visitingAlter = true; + var table = _this._queryNode.table; + _this._visitingAddColumn = true; + var result='ALTER TABLE '+_this.visit(table.toNode())+' ADD '+_this.visit(alter.nodes[0].nodes[0]); + for (var i= 1,len=alter.nodes.length; i Date: Mon, 2 Sep 2013 01:40:48 -0400 Subject: [PATCH 008/248] - Added binary-clause-tests for SqlServer. --- test/dialects/binary-clause-tests.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 23c299c5..e78bb657 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -18,6 +18,10 @@ Harness.test({ text : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' }, + sqlserver: { + text : 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', + string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' + }, params: [] }); @@ -35,6 +39,10 @@ Harness.test({ text : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', string: 'SELECT (`post`.`content` + \'!\') FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))' }, + sqlserver: { + text : 'SELECT ([post].[content] + ?) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', + string: 'SELECT ([post].[content] + \'!\') FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))' + }, params: ['!'] }); @@ -52,5 +60,9 @@ Harness.test({ text : 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', string: 'SELECT ((`post`.`id` + \': \') + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))' }, + sqlserver: { + text : 'SELECT (([post].[id] + ?) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', + string: 'SELECT (([post].[id] + \': \') + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))' + }, params: [': '] }); From a8dc4ff31322b72c018b037792ad11047e929044 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 22:35:19 -0400 Subject: [PATCH 009/248] Added cast-tests for SqlServer. --- test/dialects/cast-tests.js | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js index 90e913e4..8bae1383 100644 --- a/test/dialects/cast-tests.js +++ b/test/dialects/cast-tests.js @@ -18,6 +18,10 @@ Harness.test({ text : 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' }, + sqlserver: { + text : 'SELECT CAST([customer].[age] AS int) FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' + }, params: [] }); @@ -35,6 +39,10 @@ Harness.test({ text : 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' }, + sqlserver: { + text : 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', + string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' + }, params: [] }); @@ -43,15 +51,19 @@ Harness.test({ query: customer.select(customer.name.plus(customer.age).cast('varchar(15)')), pg: { text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' }, sqlite: { text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', - string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' }, mysql: { text : 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', - string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', + string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' + }, + sqlserver: { + text : 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', + string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' }, params: [] }); @@ -71,6 +83,10 @@ Harness.test({ text : 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' }, + sqlserver: { + text : 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', + string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' + }, params: [] }); @@ -89,6 +105,10 @@ Harness.test({ text : 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', string: 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' }, + sqlserver: { + text : 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + ?) = ?)', + string: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' + }, params: [100, 150] }); @@ -107,5 +127,9 @@ Harness.test({ text : 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' }, + sqlserver: { + text : 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' + }, params: [] }); From 45d04810d989b2edd7b3081a73ecbc71d5cf01aa Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 22:38:41 -0400 Subject: [PATCH 010/248] Added clause-ordering-tests for SqlServer. --- test/dialects/clause-ordering-tests.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index 8d957471..e4cc5c63 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -9,7 +9,7 @@ Harness.test({ query: user.from(user.join(post).on(user.id.equals(post.userId))).select(user.name, post.content), pg: { text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' }, sqlite: { text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', @@ -19,6 +19,11 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, + sqlserver: { + text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' + }, + params: [] }); // WHERE - FROM - SELECT @@ -38,6 +43,10 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = ?)', + string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' + }, params: [''] }); @@ -61,6 +70,10 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = \'\')' }, + sqlserver: { + text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = ?)', + string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = \'\')' + }, params: [''] }); @@ -81,5 +94,9 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, + sqlserver: { + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = ?)', + string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' + }, params: [''] }); From c3c83ffd60de41ef6fabe900f938a72c44fbd9e0 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 23:11:21 -0400 Subject: [PATCH 011/248] Added where-clause-tests for SqlServer. --- test/dialects/where-clause-tests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index 7fef43f2..c63362a3 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' }, + sqlserver: { + text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', + string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' + }, params: [] }); @@ -34,5 +38,9 @@ Harness.test({ text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' }, + sqlserver: { + text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', + string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' + }, params: [] }); From e0d20eadd62bd6703694710c2f17380baef4d019 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 23:13:27 -0400 Subject: [PATCH 012/248] Added value-expression-tests for SqlServer. --- test/dialects/value-expression-tests.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index b9e335f6..7acfe96e 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -19,6 +19,10 @@ Harness.test({ text : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', string: 'SELECT `customer`.`name`, (`customer`.`income` % 100) FROM `customer` WHERE (((`customer`.`age` + 5) * (`customer`.`age` - 2)) = 10)' }, + sqlserver: { + text : 'SELECT [customer].[name], ([customer].[income] % ?) FROM [customer] WHERE ((([customer].[age] + ?) * ([customer].[age] - ?)) = ?)', + string: 'SELECT [customer].[name], ([customer].[income] % 100) FROM [customer] WHERE ((([customer].[age] + 5) * ([customer].[age] - 2)) = 10)' + }, params: [100, 5, 2, 10] }); @@ -37,6 +41,10 @@ Harness.test({ text : 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', string: 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + \'hello\'))' }, + sqlserver: { + text : 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + ?))', + string: 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + \'hello\'))' + }, params: ['hello'] }); @@ -56,6 +64,10 @@ Harness.test({ text : 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', string: 'SELECT ((((`variable`.`a` * `variable`.`a`) / 2) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`' }, + sqlserver: { + text : 'SELECT (((([variable].[a] * [variable].[a]) / ?) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', + string: 'SELECT (((([variable].[a] * [variable].[a]) / 2) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]' + }, params: [2] }); @@ -74,5 +86,9 @@ Harness.test({ text : 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', string: 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`' }, + sqlserver: { + text : 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]', + string: 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]' + }, params: [] }); From a2183091760c7d15813cebf014571d8f0411e07a Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 23:14:55 -0400 Subject: [PATCH 013/248] Added unary-clause-tests for SqlServer. --- test/dialects/unary-clause-tests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js index e7f6e3bd..c16c4dc7 100644 --- a/test/dialects/unary-clause-tests.js +++ b/test/dialects/unary-clause-tests.js @@ -18,6 +18,10 @@ Harness.test({ text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)' }, + sqlserver: { + text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)', + string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)' + }, params: [] }); @@ -35,5 +39,9 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))' }, + sqlserver: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))' + }, params: [] }); From 637038d6bb16568a75d933828289f9f84a703587 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 23:23:37 -0400 Subject: [PATCH 014/248] Added ternary-clause-tests for SqlServer. --- test/dialects/ternary-clause-tests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js index 20ba7c38..fe2f52cf 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -18,6 +18,10 @@ Harness.test({ text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN 18 AND 25)' }, + sqlserver: { + text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN ? AND ?)', + string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN 18 AND 25)' + }, params: [18, 25] }); @@ -35,5 +39,9 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))' }, + sqlserver: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))' + }, params: [] }); From c22f8a188b0ff14ac6e474dea3ff4148814203e9 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 5 Sep 2013 00:54:23 -0400 Subject: [PATCH 015/248] Added create-table-tests for SqlServer. --- lib/dialect/sqlserver.js | 53 ++++++++++++++++++----------- test/dialects/create-table-tests.js | 24 +++++++++++++ 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 59e32119..79838b65 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -1,3 +1,5 @@ +// TODO: visitCreate needs to support schemas + 'use strict'; var util = require('util'); @@ -18,17 +20,15 @@ SqlServer.prototype._quoteCharacter = '['; SqlServer.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; -/* jshint unused: false */ SqlServer.prototype._getParameterPlaceholder = function(index, value) { return '?'; }; -/*jshint unused: false */ SqlServer.prototype.visitColumn = function(columnNode) { if (!isCountStarExpression(columnNode)){ return SqlServer.super_.prototype.visitColumn.call(this, columnNode); } - // emit our own since count(table.*) is invalid in SqlServer + // Implement our own since count(table.*) is invalid in SqlServer var inSelectClause = !this._selectOrDeleteEndIndex; var result='COUNT(*)' if(inSelectClause && columnNode.alias) { @@ -37,6 +37,31 @@ SqlServer.prototype.visitColumn = function(columnNode) { return result; }; +SqlServer.prototype.visitCreate = function(create) { + if (!isCreateIfNotExists(create)) { + return SqlServer.super_.prototype.visitCreate.call(this, create); + } + // Implement our own create if not exists: + // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) + // SqlServer: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END + var table = this._queryNode.table; + var col_nodes = table.columns.map(function(col) { return col.toNode(); }); + var tableResult=this.visit(table.toNode()); + + this._visitingCreate = true; + var createResult = ['CREATE TABLE']; + createResult.push(tableResult); + createResult.push('(' + col_nodes.map(this.visit.bind(this)).join(', ') + ')'); + this._visitingCreate = false; + + var whereClause='WHERE TABLE_NAME = '+tableResult.join(' '); + // TODO: need to add schema check, sudo code: + // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} + // Add some tests for this as well + + return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; +}; + SqlServer.prototype.visitAlter = function(alter) { var _this=this; var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; @@ -115,22 +140,6 @@ SqlServer.prototype.visitAlter = function(alter) { return SqlServer.super_.prototype.visitAlter.call(this, alter); }; -//Mysql.prototype.visitCreate = function(create) { -// var result = Mysql.super_.prototype.visitCreate.call(this, create); -// var engine = this._queryNode.table._initialConfig.engine; -// var charset = this._queryNode.table._initialConfig.charset; -// -// if ( !! engine) { -// result.push('ENGINE=' + engine); -// } -// -// if ( !! charset) { -// result.push('DEFAULT CHARSET=' + charset); -// } -// -// return result; -//}; - //Mysql.prototype.visitRenameColumn = function(renameColumn) { // var dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; // assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + @@ -183,4 +192,10 @@ function isCountStarExpression(columnNode){ return true; }; +function isCreateIfNotExists(create){ + if (create.nodes.length==0) return false; + if (create.nodes[0].type!='IF NOT EXISTS') return false; + return true; +}; + module.exports = SqlServer; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index d6d9d45f..ddef6cf1 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -29,6 +29,10 @@ Harness.test({ text : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', string: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))' }, + sqlserver: { + text : 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))', + string: 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))' + }, params: [] }); @@ -46,6 +50,10 @@ Harness.test({ text : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', string: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))' }, + sqlserver: { + text : 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END', + string: 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END' + }, params: [] }); @@ -70,6 +78,10 @@ Harness.test({ mysql: { text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' + }, + sqlserver: { + text : 'CREATE TABLE [user] ([id] varchar(100))', + string: 'CREATE TABLE [user] ([id] varchar(100))' } }); @@ -94,6 +106,10 @@ Harness.test({ mysql: { text : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', string: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' + }, + sqlserver: { + text : 'CREATE TABLE [user] ([id] varchar(100))', + string: 'CREATE TABLE [user] ([id] varchar(100))' } }); @@ -119,6 +135,10 @@ Harness.test({ mysql: { text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1', string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' + }, + sqlserver: { + text : 'CREATE TABLE [user] ([id] varchar(100))', + string: 'CREATE TABLE [user] ([id] varchar(100))' } }); @@ -142,5 +162,9 @@ Harness.test({ mysql: { text : 'CREATE TABLE `user` (`id` int PRIMARY KEY)', string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' + }, + sqlserver: { + text : 'CREATE TABLE [user] ([id] int PRIMARY KEY)', + string: 'CREATE TABLE [user] ([id] int PRIMARY KEY)' } }); From dca77fa370cd31dc5755abe0ed31f7265a8ffcbc Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 5 Sep 2013 01:11:09 -0400 Subject: [PATCH 016/248] Added tostring-tests for SqlServer. --- lib/dialect/sqlserver.js | 65 ++++++++++++++++++++------------- test/dialects/tostring-tests.js | 24 ++++++++++++ 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 79838b65..f944c43d 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -24,6 +24,16 @@ SqlServer.prototype._getParameterPlaceholder = function(index, value) { return '?'; }; +SqlServer.prototype.visitBinary = function(binary) { + if (!isRightSideArray(binary)){ + return SqlServer.super_.prototype.visitBinary.call(this, binary); + } + if (binary.operator=='IN'){ + return SqlServer.super_.prototype.visitBinary.call(this, binary); + } + throw new Error('SQL Sever does not support arrays in this type of expression.'); +}; + SqlServer.prototype.visitColumn = function(columnNode) { if (!isCountStarExpression(columnNode)){ return SqlServer.super_.prototype.visitColumn.call(this, columnNode); @@ -37,31 +47,6 @@ SqlServer.prototype.visitColumn = function(columnNode) { return result; }; -SqlServer.prototype.visitCreate = function(create) { - if (!isCreateIfNotExists(create)) { - return SqlServer.super_.prototype.visitCreate.call(this, create); - } - // Implement our own create if not exists: - // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) - // SqlServer: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END - var table = this._queryNode.table; - var col_nodes = table.columns.map(function(col) { return col.toNode(); }); - var tableResult=this.visit(table.toNode()); - - this._visitingCreate = true; - var createResult = ['CREATE TABLE']; - createResult.push(tableResult); - createResult.push('(' + col_nodes.map(this.visit.bind(this)).join(', ') + ')'); - this._visitingCreate = false; - - var whereClause='WHERE TABLE_NAME = '+tableResult.join(' '); - // TODO: need to add schema check, sudo code: - // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} - // Add some tests for this as well - - return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; -}; - SqlServer.prototype.visitAlter = function(alter) { var _this=this; var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; @@ -140,6 +125,31 @@ SqlServer.prototype.visitAlter = function(alter) { return SqlServer.super_.prototype.visitAlter.call(this, alter); }; +SqlServer.prototype.visitCreate = function(create) { + if (!isCreateIfNotExists(create)) { + return SqlServer.super_.prototype.visitCreate.call(this, create); + } + // Implement our own create if not exists: + // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) + // SqlServer: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END + var table = this._queryNode.table; + var col_nodes = table.columns.map(function(col) { return col.toNode(); }); + var tableResult=this.visit(table.toNode()); + + this._visitingCreate = true; + var createResult = ['CREATE TABLE']; + createResult.push(tableResult); + createResult.push('(' + col_nodes.map(this.visit.bind(this)).join(', ') + ')'); + this._visitingCreate = false; + + var whereClause='WHERE TABLE_NAME = '+tableResult.join(' '); + // TODO: need to add schema check, sudo code: + // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} + // Add some tests for this as well + + return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; +}; + //Mysql.prototype.visitRenameColumn = function(renameColumn) { // var dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; // assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + @@ -198,4 +208,9 @@ function isCreateIfNotExists(create){ return true; }; +// SQL Server does not support array expressions except in the IN clause. +function isRightSideArray(binary){ + return Array.isArray(binary.right); +}; + module.exports = SqlServer; diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index d5e56cc8..e1d5c5f4 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -19,6 +19,10 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = NULL)' }, + sqlserver: { + text : '([post].[content] = ?)', + string: '([post].[content] = NULL)' + }, params: [null] }); @@ -37,6 +41,10 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = 3.14)' }, + sqlserver: { + text : '([post].[content] = ?)', + string: '([post].[content] = 3.14)' + }, params: [3.14] }); @@ -55,6 +63,10 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = \'hello\'\'\')' }, + sqlserver: { + text : '([post].[content] = ?)', + string: '([post].[content] = \'hello\'\'\')' + }, params: ['hello\''] }); @@ -73,6 +85,10 @@ Harness.test({ text : '(`post`.`content` = (?, ?, ?))', string: '(`post`.`content` = (1, \'2\', NULL))' }, + sqlserver: { + text : 'SQL Server does not support arrays.', + throws: true + }, params: [1, '2', null] }); @@ -91,6 +107,10 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' }, + sqlserver: { + text : '([post].[content] = ?)', + string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' + }, params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] }); @@ -115,6 +135,10 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = \'secretMessage\')' }, + sqlserver: { + text : '([post].[content] = ?)', + string: '([post].[content] = \'secretMessage\')' + }, params: [customObject] }); From b436853075d295f628827d01bf84b183e68521ba Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 5 Sep 2013 01:32:51 -0400 Subject: [PATCH 017/248] Added distinct-tests for SqlServer. --- test/dialects/distinct-tests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js index 5a767183..9f0c1a69 100644 --- a/test/dialects/distinct-tests.js +++ b/test/dialects/distinct-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT DISTINCT(`user`.`id`) FROM `user`', string: 'SELECT DISTINCT(`user`.`id`) FROM `user`' }, + sqlserver: { + text : 'SELECT DISTINCT([user].[id]) FROM [user]', + string: 'SELECT DISTINCT([user].[id]) FROM [user]' + }, params: [] }); @@ -34,5 +38,9 @@ Harness.test({ text : 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', string: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`' }, + sqlserver: { + text : 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]', + string: 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]' + }, params: [] }); From 5cd5e694b04f41d67400c14350488ad960446c45 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 5 Sep 2013 01:36:03 -0400 Subject: [PATCH 018/248] Added delete-tests for SqlServer. --- test/dialects/delete-tests.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 71c27d95..ce81f243 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'hello\'\'s world\')' }, + sqlserver: { + text : 'DELETE FROM [post] WHERE ([post].[content] = ?)', + string: "DELETE FROM [post] WHERE ([post].[content] = 'hello''s world')" + }, params: ["hello's world"] }); @@ -36,6 +40,10 @@ Harness.test({ text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, + sqlserver: { + text : 'DELETE FROM [post] WHERE ([post].[content] = ?)', + string: "DELETE FROM [post] WHERE ([post].[content] = '')" + }, params: [''] }); @@ -55,6 +63,10 @@ Harness.test({ text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, + sqlserver: { + text : 'DELETE FROM [post] WHERE ([post].[content] = ?)', + string: "DELETE FROM [post] WHERE ([post].[content] = '')" + }, params: [''] }); @@ -74,5 +86,9 @@ Harness.test({ text : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', string: 'DELETE FROM `post` WHERE ((`post`.`content` = \'\') OR (`post`.`content` IS NULL))' }, + sqlserver: { + text : 'DELETE FROM [post] WHERE (([post].[content] = ?) OR ([post].[content] IS NULL))', + string: "DELETE FROM [post] WHERE (([post].[content] = '') OR ([post].[content] IS NULL))" + }, params: [''] }); From 7e70f4ae84cd4f85ef45575987900d0a81512cd5 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 5 Sep 2013 01:44:09 -0400 Subject: [PATCH 019/248] Added drop-table-tests for SqlServer. - Still needs to support schemas. --- lib/dialect/sqlserver.js | 54 +++++++++++++++++++++++-------- test/dialects/drop-table-tests.js | 8 +++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index f944c43d..a6385890 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -1,4 +1,5 @@ // TODO: visitCreate needs to support schemas +// TODO: visitDrop needs to support schemas 'use strict'; @@ -34,19 +35,6 @@ SqlServer.prototype.visitBinary = function(binary) { throw new Error('SQL Sever does not support arrays in this type of expression.'); }; -SqlServer.prototype.visitColumn = function(columnNode) { - if (!isCountStarExpression(columnNode)){ - return SqlServer.super_.prototype.visitColumn.call(this, columnNode); - } - // Implement our own since count(table.*) is invalid in SqlServer - var inSelectClause = !this._selectOrDeleteEndIndex; - var result='COUNT(*)' - if(inSelectClause && columnNode.alias) { - result += ' AS ' + this.quote(columnNode.alias); - } - return result; -}; - SqlServer.prototype.visitAlter = function(alter) { var _this=this; var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; @@ -125,6 +113,19 @@ SqlServer.prototype.visitAlter = function(alter) { return SqlServer.super_.prototype.visitAlter.call(this, alter); }; +SqlServer.prototype.visitColumn = function(columnNode) { + if (!isCountStarExpression(columnNode)){ + return SqlServer.super_.prototype.visitColumn.call(this, columnNode); + } + // Implement our own since count(table.*) is invalid in SqlServer + var inSelectClause = !this._selectOrDeleteEndIndex; + var result='COUNT(*)' + if(inSelectClause && columnNode.alias) { + result += ' AS ' + this.quote(columnNode.alias); + } + return result; +}; + SqlServer.prototype.visitCreate = function(create) { if (!isCreateIfNotExists(create)) { return SqlServer.super_.prototype.visitCreate.call(this, create); @@ -150,6 +151,27 @@ SqlServer.prototype.visitCreate = function(create) { return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; }; +SqlServer.prototype.visitDrop = function(drop) { + if (!isDropIfExists(drop)) { + return SqlServer.super_.prototype.visitDrop.call(this, drop); + } + // Implement our own drop if exists: + // PostgreSQL: DROP TABLE IF EXISTS "group" + // SqlServer: IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END + var table = this._queryNode.table; + var tableResult=this.visit(table.toNode()); + + var dropResult = ['DROP TABLE']; + dropResult.push(tableResult); + + var whereClause='WHERE TABLE_NAME = '+tableResult.join(' '); + // TODO: need to add schema check, sudo code: + // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} + // Add some tests for this as well + + return ['IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+dropResult.join(' ')+' END']; +}; + //Mysql.prototype.visitRenameColumn = function(renameColumn) { // var dataType = renameColumn.nodes[1].dataType || renameColumn.nodes[0].dataType; // assert(dataType, 'dataType missing for column ' + (renameColumn.nodes[1].name || renameColumn.nodes[0].name || '') + @@ -208,6 +230,12 @@ function isCreateIfNotExists(create){ return true; }; +function isDropIfExists(drop){ + if (drop.nodes.length==0) return false; + if (drop.nodes[0].type!='IF EXISTS') return false; + return true; +}; + // SQL Server does not support array expressions except in the IN clause. function isRightSideArray(binary){ return Array.isArray(binary.right); diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index 6e8943b5..d55e3cf9 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'DROP TABLE `post`', string: 'DROP TABLE `post`' }, + sqlserver: { + text : 'DROP TABLE [post]', + string: 'DROP TABLE [post]' + }, params: [] }); @@ -34,5 +38,9 @@ Harness.test({ text : 'DROP TABLE IF EXISTS `post`', string: 'DROP TABLE IF EXISTS `post`' }, + sqlserver: { + text : 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END', + string: 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END' + }, params: [] }); From 57a7989b28dddd9542c2b53d6cff9d557454efbc Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 5 Sep 2013 01:45:59 -0400 Subject: [PATCH 020/248] Added from-clause-tests for SqlServer. --- test/dialects/from-clause-tests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js index d0d8fc01..c8afa48d 100644 --- a/test/dialects/from-clause-tests.js +++ b/test/dialects/from-clause-tests.js @@ -17,6 +17,10 @@ Harness.test({ mysql: { text : 'SELECT `user`.* FROM `user` , `post`', string: 'SELECT `user`.* FROM `user` , `post`' + }, + sqlserver: { + text : 'SELECT [user].* FROM [user] , [post]', + string: 'SELECT [user].* FROM [user] , [post]' } }); @@ -33,5 +37,9 @@ Harness.test({ mysql: { text : 'SELECT `user`.*, `post`.* FROM `user` , `post`', string: 'SELECT `user`.*, `post`.* FROM `user` , `post`' + }, + sqlserver: { + text : 'SELECT [user].*, [post].* FROM [user] , [post]', + string: 'SELECT [user].*, [post].* FROM [user] , [post]' } }); From 3d000f1a2fa32eeb054bd79b9c042dccaaaa731c Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Fri, 6 Sep 2013 03:49:20 -0400 Subject: [PATCH 021/248] Added group-by-tests for SqlServer. - SqlServer will throw an error on the arrayAgg function since it is not supported. - Did some other misc cleanup. --- lib/dialect/sqlserver.js | 94 +++++++++++++++++++-------------- test/dialects/group-by-tests.js | 20 +++++++ 2 files changed, 74 insertions(+), 40 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index a6385890..243b8a43 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -19,7 +19,7 @@ SqlServer.prototype._myClass = SqlServer; SqlServer.prototype._quoteCharacter = '['; -SqlServer.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; +SqlServer.prototype._arrayAggFunctionName = ''; SqlServer.prototype._getParameterPlaceholder = function(index, value) { return '?'; @@ -36,96 +36,110 @@ SqlServer.prototype.visitBinary = function(binary) { }; SqlServer.prototype.visitAlter = function(alter) { - var _this=this; + var self=this; var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; // Implement our own add column: // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" // SqlServer: ALTER TABLE [name] ADD [col1], [col2] - function addColumn(){ - _this._visitingAlter = true; - var table = _this._queryNode.table; - _this._visitingAddColumn = true; - var result='ALTER TABLE '+_this.visit(table.toNode())+' ADD '+_this.visit(alter.nodes[0].nodes[0]); + function _addColumn(){ + self._visitingAlter = true; + var table = self._queryNode.table; + self._visitingAddColumn = true; + var result='ALTER TABLE '+self.visit(table.toNode())+' ADD '+self.visit(alter.nodes[0].nodes[0]); for (var i= 1,len=alter.nodes.length; i Date: Fri, 6 Sep 2013 03:51:13 -0400 Subject: [PATCH 022/248] Added having-tests for SqlServer. --- test/dialects/having-tests.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/dialects/having-tests.js b/test/dialects/having-tests.js index b06190e3..87d7bf55 100644 --- a/test/dialects/having-tests.js +++ b/test/dialects/having-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10)' }, + sqlserver : { + text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > ?)', + string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10)' + }, params: [10] }); @@ -34,6 +38,10 @@ Harness.test({ text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' }, + sqlserver : { + text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > ?) AND ([post].[userId] < ?)', + string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' + }, params: [10, 100] }); @@ -51,5 +59,9 @@ Harness.test({ text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' }, + sqlserver : { + text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > ?) AND ([post].[userId] < ?)', + string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' + }, params: [10, 100] }); From 48e5e48f357ee7e45482991e92e8eea145945fd0 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Fri, 6 Sep 2013 03:55:29 -0400 Subject: [PATCH 023/248] Added namespace-tests for SqlServer. --- test/dialects/namespace-tests.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 2ebeb086..33534b7a 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -20,6 +20,10 @@ Harness.test({ text : 'SELECT `u`.`name` FROM `user` AS `u`', string: 'SELECT `u`.`name` FROM `user` AS `u`' }, + sqlserver: { + text : 'SELECT [u].[name] FROM [user] AS [u]', + string: 'SELECT [u].[name] FROM [user] AS [u]' + }, params: [] }); @@ -37,6 +41,10 @@ Harness.test({ text : 'SELECT `u`.* FROM `user` AS `u`', string: 'SELECT `u`.* FROM `user` AS `u`' }, + sqlserver: { + text : 'SELECT [u].* FROM [user] AS [u]', + string: 'SELECT [u].* FROM [user] AS [u]' + }, params: [] }); @@ -55,6 +63,10 @@ Harness.test({ text : 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', string: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = 3))' }, + sqlserver: { + text : 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = ?))', + string: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = 3))' + }, params: [3] }); @@ -72,6 +84,10 @@ Harness.test({ text : 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))', string: 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))' }, + sqlserver: { + text : 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))', + string: 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))' + }, params: [] }); @@ -102,5 +118,9 @@ Harness.test({ text : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', string: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' }, + sqlserver: { + text : 'SELECT [comment].[text], [comment].[userId] FROM [comment]', + string: 'SELECT [comment].[text], [comment].[userId] FROM [comment]' + }, params: [] }); From 47ec5b99e9da478633b220a8fa6a2ea5521a3460 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Fri, 6 Sep 2013 04:00:52 -0400 Subject: [PATCH 024/248] Added order-tests for SqlServer. --- test/dialects/order-tests.js | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 297ce99d..aa29d1c0 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -18,6 +18,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' + }, params: [] }); @@ -35,6 +39,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, params: [] }); @@ -52,6 +60,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, params: [] }); @@ -69,6 +81,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, params: [] }); @@ -86,6 +102,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' + }, params: [] }); @@ -103,6 +123,10 @@ Harness.test({ text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' }, + sqlserver: { + text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', + string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' + }, params: [] }); @@ -120,6 +144,10 @@ Harness.test({ text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC', string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC' }, + sqlserver: { + text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC', + string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC' + }, params: [] }); @@ -137,6 +165,10 @@ Harness.test({ text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' }, + sqlserver: { + text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', + string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' + }, params: [] }); @@ -154,6 +186,10 @@ Harness.test({ text : 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)', string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)' }, + sqlserver: { + text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])', + string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])' + }, params: [] }); @@ -171,5 +207,9 @@ Harness.test({ text : 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC', string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC' }, + sqlserver: { + text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC', + string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC' + }, params: [] }); From 44a45788c99c9f282eafd17f0f885f6706fddd44 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Tue, 10 Sep 2013 04:43:42 -0400 Subject: [PATCH 025/248] Added join-tests for MS SqlServer. --- test/dialects/join-tests.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index d4e242af..3048f986 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -19,6 +19,10 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, + sqlserver: { + text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' + }, params: [] }); @@ -36,6 +40,10 @@ Harness.test({ text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, + sqlserver: { + text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', + string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' + }, params: [] }); @@ -58,6 +66,10 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', string: 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }, + sqlserver: { + text : 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])', + string: 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])' + }, params: [] }); @@ -75,6 +87,10 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, + sqlserver: { + text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])' + }, params: [] }); @@ -97,6 +113,10 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }, + sqlserver: { + text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])', + string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])' + }, params: [] }); @@ -124,5 +144,9 @@ Harness.test({ text : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)', string: 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)' }, + sqlserver: { + text : 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) subposts ON ([user].[id] = [subposts].[subpostUserId])', + string: 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) subposts ON ([user].[id] = [subposts].[subpostUserId])' + }, params: [] }); From 7d39d8349c260831aee9f60c8cd7459efb887c87 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Tue, 10 Sep 2013 04:46:21 -0400 Subject: [PATCH 026/248] Added join-to-tests for MS SqlServer. --- test/dialects/join-to-tests.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/dialects/join-to-tests.js b/test/dialects/join-to-tests.js index 5aca7e39..e4d1f6ae 100644 --- a/test/dialects/join-to-tests.js +++ b/test/dialects/join-to-tests.js @@ -50,6 +50,10 @@ Harness.test({ text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' }, + sqlserver: { + text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])', + string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])' + }, params: [] }); @@ -67,6 +71,10 @@ Harness.test({ text : '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', string: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' }, + sqlserver: { + text : '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])', + string: '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])' + }, params: [] }); @@ -84,5 +92,9 @@ Harness.test({ text : '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)', string: '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)' }, + sqlserver: { + text : '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])', + string: '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])' + }, params: [] }); From 48d44d0d69a265f6b0499eaada1aa8138cbea208 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sun, 15 Sep 2013 01:46:10 -0400 Subject: [PATCH 027/248] Added shortcut-tests for MS SqlServer. --- test/dialects/shortcut-tests.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 62e27574..a101824c 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -19,6 +19,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user`', string: 'SELECT `user`.* FROM `user`' }, + sqlserver: { + text : 'SELECT [user].* FROM [user]', + string: 'SELECT [user].* FROM [user]' + }, params: [] }); @@ -36,6 +40,10 @@ Harness.test({ text : 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' }, + sqlserver: { + text : 'SELECT * FROM [user] WHERE ([user].[name] = ?)', + string: 'SELECT * FROM [user] WHERE ([user].[name] = 3)' + }, params: [3] }); @@ -53,6 +61,10 @@ Harness.test({ text : 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', string: 'SELECT * FROM `user` WHERE ((`user`.`name` = 3) AND (`user`.`id` = 1))' }, + sqlserver: { + text : 'SELECT * FROM [user] WHERE (([user].[name] = ?) AND ([user].[id] = ?))', + string: 'SELECT * FROM [user] WHERE (([user].[name] = 3) AND ([user].[id] = 1))' + }, params: [3, 1] }); @@ -71,6 +83,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post`', string: 'SELECT `post`.`content` FROM `post`' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post]', + string: 'SELECT [post].[content] FROM [post]' + }, params: [] }); @@ -88,6 +104,10 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' }, + sqlserver: { + text : 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = ?)', + string: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = 1)' + }, params: [1] }); @@ -109,5 +129,9 @@ Harness.test({ text : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', string: 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = \'\')) AND (`post`.`userId` = 1))' }, + sqlserver: { + text : 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = ?)) AND ([post].[userId] = ?))', + string: 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = \'\')) AND ([post].[userId] = 1))' + }, params: ['', 1] }); From ba24e39f6caaf497c3656beb2bd64dacfc3f0f84 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sun, 15 Sep 2013 01:54:18 -0400 Subject: [PATCH 028/248] Added subquery-tests for MS SqlServer. --- test/dialects/subquery-tests.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 5c60c271..5aa6cf5f 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -40,6 +40,10 @@ Harness.test({ text : 'SELECT * FROM (SELECT * FROM `user`)', string: 'SELECT * FROM (SELECT * FROM `user`)' }, + sqlserver: { + text : 'SELECT * FROM (SELECT * FROM [user])', + string: 'SELECT * FROM (SELECT * FROM [user])' + }, params: [] }); @@ -57,6 +61,10 @@ Harness.test({ text : 'SELECT * FROM (SELECT * FROM `customer`) T1 , (SELECT * FROM `user`) T2', string: 'SELECT * FROM (SELECT * FROM `customer`) T1 , (SELECT * FROM `user`) T2' }, + sqlserver: { + text : 'SELECT * FROM (SELECT * FROM [customer]) T1 , (SELECT * FROM [user]) T2', + string: 'SELECT * FROM (SELECT * FROM [customer]) T1 , (SELECT * FROM [user]) T2' + }, params: [] }); @@ -77,6 +85,10 @@ Harness.test({ text : '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))', string: '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))' }, + sqlserver: { + text : '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))', + string: '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))' + }, params: [] }); @@ -94,5 +106,9 @@ Harness.test({ text : '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))', string: '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))' }, + sqlserver: { + text : '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))', + string: '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))' + }, params: [] }); From af3e80836f81157311d38ad5d62232404fe115bf Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sun, 15 Sep 2013 01:56:43 -0400 Subject: [PATCH 029/248] Added update-tests for MS SqlServer. --- test/dialects/update-tests.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index bd4f6e46..fc98c550 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -20,6 +20,10 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?', string: 'UPDATE `post` SET `content` = \'test\'' }, + sqlserver: { + text : 'UPDATE [post] SET [content] = ?', + string: 'UPDATE [post] SET [content] = \'test\'' + }, params: ['test'] }); @@ -40,6 +44,10 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?, `userId` = ?', string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3' }, + sqlserver: { + text : 'UPDATE [post] SET [content] = ?, [userId] = ?', + string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3' + }, params: ['test', 3] }); @@ -60,6 +68,10 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?, `userId` = ?', string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' }, + sqlserver: { + text : 'UPDATE [post] SET [content] = ?, [userId] = ?', + string: 'UPDATE [post] SET [content] = NULL, [userId] = 3' + }, params: [null, 3] }); @@ -80,6 +92,10 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3 WHERE (`post`.`content` = \'no\')' }, + sqlserver: { + text : 'UPDATE [post] SET [content] = ?, [userId] = ? WHERE ([post].[content] = ?)', + string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3 WHERE ([post].[content] = \'no\')' + }, params: ['test', 3, 'no'] }); @@ -99,6 +115,10 @@ Harness.test({ text : 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', string: 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' }, + sqlserver: { + text : 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])', + string: 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])' + }, params: [] }); @@ -119,5 +139,9 @@ Harness.test({ text : 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', string: 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' }, + sqlserver: { + text : 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])', + string: 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])' + }, params: [] }); From 037002582b26fb12f15cbce8cf45fcf67a19e330 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sun, 15 Sep 2013 02:02:31 -0400 Subject: [PATCH 030/248] Added schema-tests for MS SqlServer. --- test/dialects/schema-tests.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index a0fca635..7024ad4d 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -24,6 +24,10 @@ Harness.test({ text : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', string: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' }, + sqlserver: { + text : 'SELECT [staging].[user].[id] FROM [staging].[user]', + string: 'SELECT [staging].[user].[id] FROM [staging].[user]' + }, params: [] }); @@ -41,6 +45,10 @@ Harness.test({ text : 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`', string: 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`' }, + sqlserver: { + text : 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]', + string: 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]' + }, params: [] }); @@ -58,6 +66,10 @@ Harness.test({ text : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', string: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' }, + sqlserver: { + text : 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]', + string: 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]' + }, params: [] }); @@ -76,6 +88,10 @@ Harness.test({ text : 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', string: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' }, + sqlserver: { + text : 'SELECT [uws].[name] FROM [staging].[user] AS [uws]', + string: 'SELECT [uws].[name] FROM [staging].[user] AS [uws]' + }, params: [] }); @@ -99,6 +115,10 @@ Harness.test({ text : 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)', string: 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' }, + sqlserver: { + text : 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])', + string: 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])' + }, params: [] }); @@ -116,5 +136,9 @@ Harness.test({ text : 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)', string: 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)' }, + sqlserver: { + text : 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])', + string: 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])' + }, params: [] }); From 1bf9ae167c7666b3467b68ccca83b2a8358a0fd0 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 28 Sep 2013 00:42:29 -0400 Subject: [PATCH 031/248] - Changed the parameter placeholder from ? to @xxx where xxx is the index of the parameter (1 based). The .NET SQL Server adaptor does not support the question mark. --- lib/dialect/sqlserver.js | 2 +- test/dialects/alias-tests.js | 4 ++-- test/dialects/binary-clause-tests.js | 4 ++-- test/dialects/cast-tests.js | 2 +- test/dialects/clause-ordering-tests.js | 6 +++--- test/dialects/delete-tests.js | 8 ++++---- test/dialects/having-tests.js | 6 +++--- test/dialects/namespace-tests.js | 2 +- test/dialects/shortcut-tests.js | 8 ++++---- test/dialects/subquery-tests.js | 4 ++++ test/dialects/table-tests.js | 24 ++++++++++++------------ test/dialects/ternary-clause-tests.js | 2 +- test/dialects/tostring-tests.js | 10 +++++----- test/dialects/update-tests.js | 8 ++++---- test/dialects/value-expression-tests.js | 6 +++--- 15 files changed, 50 insertions(+), 46 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 243b8a43..e19c5ace 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -22,7 +22,7 @@ SqlServer.prototype._quoteCharacter = '['; SqlServer.prototype._arrayAggFunctionName = ''; SqlServer.prototype._getParameterPlaceholder = function(index, value) { - return '?'; + return '@' + index; }; SqlServer.prototype.visitBinary = function(binary) { diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index 87f56f36..89ade344 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -39,7 +39,7 @@ Harness.test({ string: 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > 10) AND (`customer`.`age` < 20))' }, sqlserver: { - text : 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > ?) AND ([customer].[age] < ?))', + text : 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > @1) AND ([customer].[age] < @2))', string: 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > 10) AND ([customer].[age] < 20))' }, params: [10, 20] @@ -60,7 +60,7 @@ Harness.test({ string: 'SELECT (`customer`.`age` BETWEEN 10 AND 20) AS `ageBetween` FROM `customer`' }, sqlserver: { - text : 'SELECT ([customer].[age] BETWEEN ? AND ?) AS [ageBetween] FROM [customer]', + text : 'SELECT ([customer].[age] BETWEEN @1 AND @2) AS [ageBetween] FROM [customer]', string: 'SELECT ([customer].[age] BETWEEN 10 AND 20) AS [ageBetween] FROM [customer]' }, params: [10, 20] diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index e78bb657..01cf2971 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -40,7 +40,7 @@ Harness.test({ string: 'SELECT (`post`.`content` + \'!\') FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))' }, sqlserver: { - text : 'SELECT ([post].[content] + ?) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', + text : 'SELECT ([post].[content] + @1) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', string: 'SELECT ([post].[content] + \'!\') FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))' }, params: ['!'] @@ -61,7 +61,7 @@ Harness.test({ string: 'SELECT ((`post`.`id` + \': \') + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))' }, sqlserver: { - text : 'SELECT (([post].[id] + ?) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', + text : 'SELECT (([post].[id] + @1) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', string: 'SELECT (([post].[id] + \': \') + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))' }, params: [': '] diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js index 8bae1383..b73b1f43 100644 --- a/test/dialects/cast-tests.js +++ b/test/dialects/cast-tests.js @@ -106,7 +106,7 @@ Harness.test({ string: 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' }, sqlserver: { - text : 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + ?) = ?)', + text : 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', string: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' }, params: [100, 150] diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index e4cc5c63..3a2d0afd 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -44,7 +44,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = ?)', + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' }, params: [''] @@ -71,7 +71,7 @@ Harness.test({ string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = \'\')' }, sqlserver: { - text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = ?)', + text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = @1)', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = \'\')' }, params: [''] @@ -95,7 +95,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = ?)', + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' }, params: [''] diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index ce81f243..011a70c7 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -18,7 +18,7 @@ Harness.test({ string: 'DELETE FROM `post` WHERE (`post`.`content` = \'hello\'\'s world\')' }, sqlserver: { - text : 'DELETE FROM [post] WHERE ([post].[content] = ?)', + text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = 'hello''s world')" }, params: ["hello's world"] @@ -41,7 +41,7 @@ Harness.test({ string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, sqlserver: { - text : 'DELETE FROM [post] WHERE ([post].[content] = ?)', + text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = '')" }, params: [''] @@ -64,7 +64,7 @@ Harness.test({ string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, sqlserver: { - text : 'DELETE FROM [post] WHERE ([post].[content] = ?)', + text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = '')" }, params: [''] @@ -87,7 +87,7 @@ Harness.test({ string: 'DELETE FROM `post` WHERE ((`post`.`content` = \'\') OR (`post`.`content` IS NULL))' }, sqlserver: { - text : 'DELETE FROM [post] WHERE (([post].[content] = ?) OR ([post].[content] IS NULL))', + text : 'DELETE FROM [post] WHERE (([post].[content] = @1) OR ([post].[content] IS NULL))', string: "DELETE FROM [post] WHERE (([post].[content] = '') OR ([post].[content] IS NULL))" }, params: [''] diff --git a/test/dialects/having-tests.js b/test/dialects/having-tests.js index 87d7bf55..1a3c49cf 100644 --- a/test/dialects/having-tests.js +++ b/test/dialects/having-tests.js @@ -18,7 +18,7 @@ Harness.test({ string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10)' }, sqlserver : { - text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > ?)', + text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10)' }, params: [10] @@ -39,7 +39,7 @@ Harness.test({ string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' }, sqlserver : { - text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > ?) AND ([post].[userId] < ?)', + text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' }, params: [10, 100] @@ -60,7 +60,7 @@ Harness.test({ string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' }, sqlserver : { - text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > ?) AND ([post].[userId] < ?)', + text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' }, params: [10, 100] diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 33534b7a..4f23b3c4 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -64,7 +64,7 @@ Harness.test({ string: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = 3))' }, sqlserver: { - text : 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = ?))', + text : 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = @1))', string: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = 3))' }, params: [3] diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index a101824c..7bed5dd3 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -41,7 +41,7 @@ Harness.test({ string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' }, sqlserver: { - text : 'SELECT * FROM [user] WHERE ([user].[name] = ?)', + text : 'SELECT * FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT * FROM [user] WHERE ([user].[name] = 3)' }, params: [3] @@ -62,7 +62,7 @@ Harness.test({ string: 'SELECT * FROM `user` WHERE ((`user`.`name` = 3) AND (`user`.`id` = 1))' }, sqlserver: { - text : 'SELECT * FROM [user] WHERE (([user].[name] = ?) AND ([user].[id] = ?))', + text : 'SELECT * FROM [user] WHERE (([user].[name] = @1) AND ([user].[id] = @2))', string: 'SELECT * FROM [user] WHERE (([user].[name] = 3) AND ([user].[id] = 1))' }, params: [3, 1] @@ -105,7 +105,7 @@ Harness.test({ string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' }, sqlserver: { - text : 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = ?)', + text : 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = @1)', string: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = 1)' }, params: [1] @@ -130,7 +130,7 @@ Harness.test({ string: 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = \'\')) AND (`post`.`userId` = 1))' }, sqlserver: { - text : 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = ?)) AND ([post].[userId] = ?))', + text : 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = @1)) AND ([post].[userId] = @2))', string: 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = \'\')) AND ([post].[userId] = 1))' }, params: ['', 1] diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 5aa6cf5f..cadd57da 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -23,6 +23,10 @@ Harness.test({ text : '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE ?)))))', string: '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE \'%HELLO%\')))))' }, + sqlserver: { + text : '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE @1)))))', + string: '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE \'%HELLO%\')))))' + }, params: ['%HELLO%'] }); diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index e10ba782..fe68d88b 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -81,7 +81,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'foo\')' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = ?)', + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'foo\')' }, params: ['foo'] @@ -102,7 +102,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = ?) OR ([user].[name] = ?))', + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' }, params: ['foo', 'bar'] @@ -123,7 +123,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') AND (`user`.`name` = \'bar\'))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = ?) AND ([user].[name] = ?))', + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) AND ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') AND ([user].[name] = \'bar\'))' }, params: ['foo', 'bar'] @@ -144,7 +144,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = ?) OR ([user].[name] = ?))', + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' }, params: ['foo', 'bar'] @@ -165,7 +165,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'foo\') OR (`user`.`name` = \'baz\')) AND (`user`.`name` = \'bar\'))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = ?) OR ([user].[name] = ?)) AND ([user].[name] = ?))', + text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) OR ([user].[name] = @2)) AND ([user].[name] = @3))', string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'foo\') OR ([user].[name] = \'baz\')) AND ([user].[name] = \'bar\'))' }, params: ['foo', 'baz', 'bar'] @@ -186,7 +186,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (\'foo\', \'bar\'))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (?, ?))', + text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (@1, @2))', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (\'foo\', \'bar\'))' }, params: ['foo', 'bar'] @@ -207,7 +207,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (\'foo\', \'bar\')) AND (`user`.`id` = 1))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (?, ?)) AND ([user].[id] = ?))', + text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (@1, @2)) AND ([user].[id] = @3))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (\'foo\', \'bar\')) AND ([user].[id] = 1))' }, params: ['foo', 'bar', 1] @@ -256,7 +256,7 @@ Harness.test({ string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'boom\') AND (`user`.`id` = 1)) OR ((`user`.`name` = \'bang\') AND (`user`.`id` = 2)))' }, sqlserver: { - text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = ?) AND ([user].[id] = ?)) OR (([user].[name] = ?) AND ([user].[id] = ?)))', + text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) AND ([user].[id] = @2)) OR (([user].[name] = @3) AND ([user].[id] = @4)))', string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'boom\') AND ([user].[id] = 1)) OR (([user].[name] = \'bang\') AND ([user].[id] = 2)))' }, params: ['boom', 1, 'bang', 2] @@ -298,7 +298,7 @@ Harness.test({ string: 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, sqlsever: { - text : 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = ?)', + text : 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = \'brian\')' }, params: ['brian'] @@ -319,7 +319,7 @@ Harness.test({ string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, sqlserver: { - text : 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = ?)', + text : 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = \'brian\')' }, params: ['brian'] @@ -426,7 +426,7 @@ Harness.test({ string: 'SELECT name FROM user WHERE (`user`.`name` = \'brian\')' }, sqlserver: { - text : 'SELECT name FROM user WHERE ([user].[name] = ?)', + text : 'SELECT name FROM user WHERE ([user].[name] = @1)', string: 'SELECT name FROM user WHERE ([user].[name] = \'brian\')' }, params: ['brian'] @@ -450,7 +450,7 @@ Harness.test({ string: 'SELECT name FROM user WHERE ((`user`.`name` = \'brian\') AND (`user`.`id` = 1))' }, sqlserver: { - text : 'SELECT name FROM user WHERE (([user].[name] = ?) AND ([user].[id] = ?))', + text : 'SELECT name FROM user WHERE (([user].[name] = @1) AND ([user].[id] = @2))', string: 'SELECT name FROM user WHERE (([user].[name] = \'brian\') AND ([user].[id] = 1))' }, params: ['brian', 1] diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js index fe2f52cf..a14bb1ce 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -19,7 +19,7 @@ Harness.test({ string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN 18 AND 25)' }, sqlserver: { - text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN ? AND ?)', + text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN @1 AND @2)', string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN 18 AND 25)' }, params: [18, 25] diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index e1d5c5f4..7b2b819d 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -20,7 +20,7 @@ Harness.test({ string: '(`post`.`content` = NULL)' }, sqlserver: { - text : '([post].[content] = ?)', + text : '([post].[content] = @1)', string: '([post].[content] = NULL)' }, params: [null] @@ -42,7 +42,7 @@ Harness.test({ string: '(`post`.`content` = 3.14)' }, sqlserver: { - text : '([post].[content] = ?)', + text : '([post].[content] = @1)', string: '([post].[content] = 3.14)' }, params: [3.14] @@ -64,7 +64,7 @@ Harness.test({ string: '(`post`.`content` = \'hello\'\'\')' }, sqlserver: { - text : '([post].[content] = ?)', + text : '([post].[content] = @1)', string: '([post].[content] = \'hello\'\'\')' }, params: ['hello\''] @@ -108,7 +108,7 @@ Harness.test({ string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' }, sqlserver: { - text : '([post].[content] = ?)', + text : '([post].[content] = @1)', string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' }, params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] @@ -136,7 +136,7 @@ Harness.test({ string: '(`post`.`content` = \'secretMessage\')' }, sqlserver: { - text : '([post].[content] = ?)', + text : '([post].[content] = @1)', string: '([post].[content] = \'secretMessage\')' }, params: [customObject] diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index fc98c550..964b4538 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -21,7 +21,7 @@ Harness.test({ string: 'UPDATE `post` SET `content` = \'test\'' }, sqlserver: { - text : 'UPDATE [post] SET [content] = ?', + text : 'UPDATE [post] SET [content] = @1', string: 'UPDATE [post] SET [content] = \'test\'' }, params: ['test'] @@ -45,7 +45,7 @@ Harness.test({ string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3' }, sqlserver: { - text : 'UPDATE [post] SET [content] = ?, [userId] = ?', + text : 'UPDATE [post] SET [content] = @1, [userId] = @2', string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3' }, params: ['test', 3] @@ -69,7 +69,7 @@ Harness.test({ string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' }, sqlserver: { - text : 'UPDATE [post] SET [content] = ?, [userId] = ?', + text : 'UPDATE [post] SET [content] = @1, [userId] = @2', string: 'UPDATE [post] SET [content] = NULL, [userId] = 3' }, params: [null, 3] @@ -93,7 +93,7 @@ Harness.test({ string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3 WHERE (`post`.`content` = \'no\')' }, sqlserver: { - text : 'UPDATE [post] SET [content] = ?, [userId] = ? WHERE ([post].[content] = ?)', + text : 'UPDATE [post] SET [content] = @1, [userId] = @2 WHERE ([post].[content] = @3)', string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3 WHERE ([post].[content] = \'no\')' }, params: ['test', 3, 'no'] diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 7acfe96e..341d924b 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -20,7 +20,7 @@ Harness.test({ string: 'SELECT `customer`.`name`, (`customer`.`income` % 100) FROM `customer` WHERE (((`customer`.`age` + 5) * (`customer`.`age` - 2)) = 10)' }, sqlserver: { - text : 'SELECT [customer].[name], ([customer].[income] % ?) FROM [customer] WHERE ((([customer].[age] + ?) * ([customer].[age] - ?)) = ?)', + text : 'SELECT [customer].[name], ([customer].[income] % @1) FROM [customer] WHERE ((([customer].[age] + @2) * ([customer].[age] - @3)) = @4)', string: 'SELECT [customer].[name], ([customer].[income] % 100) FROM [customer] WHERE ((([customer].[age] + 5) * ([customer].[age] - 2)) = 10)' }, params: [100, 5, 2, 10] @@ -42,7 +42,7 @@ Harness.test({ string: 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + \'hello\'))' }, sqlserver: { - text : 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + ?))', + text : 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + @1))', string: 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + \'hello\'))' }, params: ['hello'] @@ -65,7 +65,7 @@ Harness.test({ string: 'SELECT ((((`variable`.`a` * `variable`.`a`) / 2) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`' }, sqlserver: { - text : 'SELECT (((([variable].[a] * [variable].[a]) / ?) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', + text : 'SELECT (((([variable].[a] * [variable].[a]) / @1) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', string: 'SELECT (((([variable].[a] * [variable].[a]) / 2) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]' }, params: [2] From 69d2405030af59463e67a83573cf35202462adc8 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 28 Sep 2013 01:00:21 -0400 Subject: [PATCH 032/248] - Added commented-out test cases for limit-and-offset-tests for mssql. Commented out because they all currently fail, but it's what the output should look like. --- test/dialects/limit-and-offset-tests.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js index aa83033c..bf299303 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -20,6 +20,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' }, +// sqlserver: { +// text : 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]', +// string: 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]' +// }, params: [] }); @@ -37,6 +41,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' }, +// sqlserver: { +// text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY', +// string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY' +// }, params: [] }); @@ -54,6 +62,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }, +// sqlserver: { +// text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS', +// string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' +// }, params: [] }); @@ -75,5 +87,11 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT 1', string: 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = \'John\')) LIMIT 1' }, +// sqlserver: { +// text : 'Microsoft SQL Server does not support OFFSET without and ORDER BY.', +// throws: true +// }, values: ['John', 'John'] }); + +// TODO: Should probably have a test case like the one above but including an ORDER BY clause so the mssql case can be tested \ No newline at end of file From d062b1ed22a3ca7c143715aebd4bd0d4e6ad34d4 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 30 Sep 2013 03:30:57 -0400 Subject: [PATCH 033/248] - Fixed bug in the "create table if not exists" ms sql server code generation. --- lib/dialect/sqlserver.js | 7 +++++-- test/dialects/create-table-tests.js | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index e19c5ace..038c62f3 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -146,7 +146,7 @@ SqlServer.prototype.visitCreate = function(create) { } // Implement our own create if not exists: // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) - // SqlServer: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END + // SqlServer: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'group') BEGIN ... END var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); var tableResult=this.visit(table.toNode()); @@ -157,7 +157,10 @@ SqlServer.prototype.visitCreate = function(create) { createResult.push('(' + col_nodes.map(this.visit.bind(this)).join(', ') + ')'); this._visitingCreate = false; - var whereClause='WHERE TABLE_NAME = '+tableResult.join(' '); + var tableStr=tableResult.join(' '); + tableStr=tableStr.replace("'","''"); + tableStr="'"+tableStr.substring(1,tableStr.length-1)+"'"; + var whereClause='WHERE TABLE_NAME = '+tableStr; // TODO: need to add schema check, sudo code: // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} // Add some tests for this as well diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index ddef6cf1..47d68cce 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -51,8 +51,8 @@ Harness.test({ string: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))' }, sqlserver: { - text : 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END', - string: 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END' + text : 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END', + string: 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END' }, params: [] }); From ce1731beee86307df0fe4aaf45a116bd8f944948 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 19 Oct 2013 15:27:17 -0400 Subject: [PATCH 034/248] - Got LIMIT working in MSSQL. OFFSET still needs a bit of work. --- lib/dialect/postgres.js | 31 ++++--- lib/dialect/sqlserver.js | 107 +++++++++++++++++++++++- lib/node/orderByValue.js | 3 + lib/node/select.js | 4 +- test/dialects/limit-and-offset-tests.js | 16 ++-- 5 files changed, 141 insertions(+), 20 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index f57ac34e..3b7dfc64 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -364,7 +364,6 @@ Postgres.prototype.visitQuery = function(queryNode) { this._queryNode = queryNode; // need to sort the top level query nodes on visitation priority // so select/insert/update/delete comes before from comes before where - var sortedNodes = []; var missingFrom = true; var hasFrom = false; var actions = []; @@ -404,15 +403,27 @@ Postgres.prototype.visitQuery = function(queryNode) { if(missingFrom) { targets.push(new From().add(queryNode.table)); } - // lazy-man sorting - sortedNodes = actions.concat(targets).concat(filters); - for(i = 0; i < sortedNodes.length; i++) { - var res = this.visit(sortedNodes[i]); - this.output = this.output.concat(res); - } - // implicit 'from' - return this.output; -}; + return this.visitQueryHelper(actions,targets,filters) +}; + +/** + * We separate out this part of query building so it can be overridden by other implementations. + * + * @param {Node[]} actions + * @param {Node[]} targets + * @param {Node[]} filters + * @returns {String[]} + */ +Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ + // lazy-man sorting + var sortedNodes = actions.concat(targets).concat(filters); + for(var i = 0; i < sortedNodes.length; i++) { + var res = this.visit(sortedNodes[i]); + this.output = this.output.concat(res); + } + // implicit 'from' + return this.output; +} Postgres.prototype.visitSubquery = function(queryNode) { // create another query builder of the current class to build the subquery diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 038c62f3..860bffc1 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -136,7 +136,7 @@ SqlServer.prototype.visitColumn = function(columnNode) { if (isCountStarExpression(columnNode)) return _countStar(); if (inSelectClause && !table.alias && columnNode.asArray) return _arrayAgg(); return SqlServer.super_.prototype.visitColumn.call(this, columnNode); - + }; @@ -189,6 +189,94 @@ SqlServer.prototype.visitDrop = function(drop) { return ['IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+dropResult.join(' ')+' END']; }; +/** + * We override this so that we can deal with the LIMIT and OFFSET clauses specially since they have to become + * part of the SELECT and ORDER BY clauses. + * + * Basically if there's an ORDER BY clause we attach OFFSET and LIMIT to it so that it can be processed by the + * ORDER BY handler later. + * + * If there's a LIMIT clause without OFFSET, we attach it to the SELECT clause so we can process it later. + * + * @param {Node[]} actions + * @param {Node[]} targets + * @param {Node[]} filters + * @returns {String[]} + */ +SqlServer.prototype.visitQueryHelper=function(actions,targets,filters){ + /** + * + * @param {Node[]} list + * @param {String} type + * @returns {Object|undefined} {index:number, node:Node} + * @private + */ + function _findNode(list,type){ + for (var i= 0, len=list.length; i Date: Sat, 19 Oct 2013 15:50:23 -0400 Subject: [PATCH 035/248] - Got OFFSET working in MSSQL. --- lib/dialect/sqlserver.js | 16 ++++++++++++++-- test/dialects/limit-and-offset-tests.js | 16 ++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/dialect/sqlserver.js b/lib/dialect/sqlserver.js index 860bffc1..0b972a57 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/sqlserver.js @@ -189,6 +189,18 @@ SqlServer.prototype.visitDrop = function(drop) { return ['IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+dropResult.join(' ')+' END']; }; +SqlServer.prototype.visitOrderBy = function(orderBy) { + var result=SqlServer.super_.prototype.visitOrderBy.call(this, orderBy); + var offsetNode=orderBy.msSQLOffsetNode; + var limitNode=orderBy.msSQLLimitNode; + if (!offsetNode && !limitNode) return result; + assert(offsetNode,"Something bad happened, should have had an msSQLOffsetNode here."); + result.push("OFFSET "+getModifierValue(this,offsetNode)+" ROWS"); + if (!limitNode) return result; + result.push("FETCH NEXT "+getModifierValue(this,limitNode)+" ROWS ONLY"); + return result; +}; + /** * We override this so that we can deal with the LIMIT and OFFSET clauses specially since they have to become * part of the SELECT and ORDER BY clauses. @@ -228,8 +240,8 @@ SqlServer.prototype.visitQueryHelper=function(actions,targets,filters){ if (!offsetInfo && !limitInfo) return; // ORDER BY with OFFSET we have work to do, may consume LIMIT as well if (orderByInfo && offsetInfo) _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo); - if (offsetInfo) throw new Error("MS SQL Server does not allow OFFSET without ORDER BY"); - if (limitInfo) _processLimit(limitInfo); + else if (offsetInfo) throw new Error("MS SQL Server does not allow OFFSET without ORDER BY"); + else if (limitInfo) _processLimit(limitInfo); } /** diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js index e26bde50..fc9c0201 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -41,10 +41,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' }, -// sqlserver: { -// text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY', -// string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY' -// }, + sqlserver: { + text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY', + string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY' + }, params: [] }); @@ -62,10 +62,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }, -// sqlserver: { -// text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS', -// string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' -// }, + sqlserver: { + text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS', + string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' + }, params: [] }); From cf1d697638b30ab6d70c48ed0948420b0d282795 Mon Sep 17 00:00:00 2001 From: thadclay Date: Thu, 24 Apr 2014 17:45:15 -0400 Subject: [PATCH 036/248] Add support for Postgres ILIKE. --- lib/node/valueExpression.js | 2 ++ test/binary-clause-tests.js | 2 ++ test/dialects/ilike-tests.js | 45 ++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 test/dialects/ilike-tests.js diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 6ec2543f..459f5918 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -146,6 +146,8 @@ var ValueExpressionMixin = function() { pathText : binaryMethod('#>>'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), + ilike : binaryMethod('ILIKE'), + notiLike : binaryMethod('NOT ILIKE'), in : inMethod, notIn : notInMethod, between : ternaryMethod('BETWEEN', 'AND'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 438a3761..1f17c6d1 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -34,4 +34,6 @@ test('operators', function() { assert.equal(Foo.baz.modulo(1).operator, '%'); assert.equal(Foo.baz.regex(1).operator, '~'); assert.equal(Foo.baz.notRegex(1).operator, '!~'); + assert.equal(Foo.baz.ilike('asdf').operator, 'ILIKE'); + assert.equal(Foo.baz.notiLike('asdf').operator, 'NOT ILIKE'); }); diff --git a/test/dialects/ilike-tests.js b/test/dialects/ilike-tests.js new file mode 100644 index 00000000..e0014f77 --- /dev/null +++ b/test/dialects/ilike-tests.js @@ -0,0 +1,45 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); +var user = Harness.defineUserTable(); +var Sql = require('../../lib').setDialect('postgres'); + +Harness.test({ + query: post.select(post.content, post.userId).where(post.content.ilike('A%')), + pg: { + text : 'SELECT "post"."content", "post"."userId" FROM "post" WHERE ("post"."content" ILIKE $1)', + string: 'SELECT "post"."content", "post"."userId" FROM "post" WHERE ("post"."content" ILIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post.insert(post.content, post.userId) + .select('\'test\'', user.id).from(user).where(user.name.ilike('A%')), + pg: { + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post.insert([post.content, post.userId]) + .select('\'test\'', user.id).from(user).where(user.name.ilike('A%')), + pg: { + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE \'A%\')' + }, + params: ['A%'] +}); + +Harness.test({ + query: post.insert(post.userId) + .select(user.id).from(user).where(user.name.ilike('A%')), + pg: { + text : 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" ILIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" ILIKE \'A%\')' + }, + params: ['A%'] +}); From abbc9bde2fe96181484fc5d000fd0e5ec533701b Mon Sep 17 00:00:00 2001 From: thadclay Date: Sat, 26 Apr 2014 08:19:20 -0400 Subject: [PATCH 037/248] Change notiLike to notIlike --- lib/node/valueExpression.js | 2 +- test/binary-clause-tests.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 459f5918..50c7a26e 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -147,7 +147,7 @@ var ValueExpressionMixin = function() { like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), ilike : binaryMethod('ILIKE'), - notiLike : binaryMethod('NOT ILIKE'), + notIlike : binaryMethod('NOT ILIKE'), in : inMethod, notIn : notInMethod, between : ternaryMethod('BETWEEN', 'AND'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 1f17c6d1..271cb15c 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -35,5 +35,5 @@ test('operators', function() { assert.equal(Foo.baz.regex(1).operator, '~'); assert.equal(Foo.baz.notRegex(1).operator, '!~'); assert.equal(Foo.baz.ilike('asdf').operator, 'ILIKE'); - assert.equal(Foo.baz.notiLike('asdf').operator, 'NOT ILIKE'); + assert.equal(Foo.baz.notIlike('asdf').operator, 'NOT ILIKE'); }); From a5beccee0a6501340bd32bd2d0013fd2994c8380 Mon Sep 17 00:00:00 2001 From: Lyman Gillispie Date: Thu, 8 May 2014 21:05:49 -0400 Subject: [PATCH 038/248] Added support for REFERENCES in CREATE TABLE and ALTER TABLE operations. --- lib/dialect/postgres.js | 21 ++++++++ lib/node/column.js | 1 + test/dialects/alter-table-tests.js | 50 ++++++++++++++++++ test/dialects/create-table-tests.js | 82 +++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7ba997b5..64db5ad3 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -664,6 +664,27 @@ Postgres.prototype.visitColumn = function(columnNode) { // creating a column as a primary key txt.push(' PRIMARY KEY'); } + + if (!!columnNode.references) { + assert.equal(typeof (columnNode.references), 'object', + 'references is not a object for column ' + columnNode.name + + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + + ' require refrences to be expressed as an object)'); + + //Empty refrence objects are ok + if (Object.keys(columnNode.references).length > 0){ + assert(columnNode.references.table, 'reference.table missing for column ' + + columnNode.name + + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + + ' require a table and column)'); + assert(columnNode.references.table, 'reference.column missing for column ' + + columnNode.name + + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + + ' require a table and column)'); + txt.push(' REFERENCES ' + columnNode.references.table + '(' + + columnNode.references.column + ')'); + } + } } return [txt.join('')]; }; diff --git a/lib/node/column.js b/lib/node/column.js index 98baa363..60724940 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -17,6 +17,7 @@ module.exports = Node.define({ this.dataType = config.dataType; this.distinct = config.distinct; this.primaryKey = config.primaryKey; + this.references = config.references; this.autoGenerated = !!config.autoGenerated; }, as: function(alias) { diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 71a5c396..f14c30af 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -210,3 +210,53 @@ Harness.test({ throws: true } }); + +var post = Table.define({ + name: 'post', + columns: [{ + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id' + } + }, { + name: 'picture', + dataType: 'varchar(100)', + references: {} + }] +}); + +Harness.test({ + query: post.alter().addColumn(post.userId), + pg: { + text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)' + }, + sqlite: { + text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)' + }, + mysql: { + text : 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES user(id)', + string: 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES user(id)' + }, + params: [] +}); + +Harness.test({ + query: post.alter().addColumn(post.picture), + pg: { + text : 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', + string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' + }, + sqlite: { + text : 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', + string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' + }, + mysql: { + text : 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)', + string: 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)' + }, + params: [] +}); diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index d6d9d45f..8ba5d01e 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -144,3 +144,85 @@ Harness.test({ string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' } }); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id' + } + }] + }).create(), + pg: { + text : 'CREATE TABLE "post" ("userId" int REFERENCES user(id))', + string: 'CREATE TABLE "post" ("userId" int REFERENCES user(id))' + }, + sqlite: { + text : 'CREATE TABLE "post" ("userId" int REFERENCES user(id))', + string: 'CREATE TABLE "post" ("userId" int REFERENCES user(id))' + }, + mysql: { + text : 'CREATE TABLE `post` (`userId` int REFERENCES user(id))', + string: 'CREATE TABLE `post` (`userId` int REFERENCES user(id))' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'picture', + columns: [{ + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id' + } + }, { + name: 'caption', + dataType: 'varchar(100)', + references: {} + }] + }).create(), + pg: { + text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))' + }, + sqlite: { + text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))' + }, + mysql: { + text : 'CREATE TABLE `picture` (`userId` int REFERENCES user(id), `caption` varchar(100))', + string: 'CREATE TABLE `picture` (`userId` int REFERENCES user(id), `caption` varchar(100))' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'userId', + dataType: 'int', + references: 'user' + }] + }).create(), + pg: { + text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + sqlite: { + text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + mysql: { + text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, + params: [] +}); From 571fa2cf84e56341283603abaee2e9a974496b01 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sun, 11 May 2014 11:00:16 -0400 Subject: [PATCH 039/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e344a719..8e56c401 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.38.0", + "version": "0.39.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 81e13be6d833b747172302ddf584a981675aa3ad Mon Sep 17 00:00:00 2001 From: Huibing Yin Date: Thu, 24 Jul 2014 13:41:12 -0500 Subject: [PATCH 040/248] Update valueExpression.js Adding two operator for mysql: regexp for 'REGEXP' and rlike for 'RLIKE'. --- lib/node/valueExpression.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 6ec2543f..f6b117e7 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -138,6 +138,7 @@ var ValueExpressionMixin = function() { bitwiseOr : binaryMethod('|'), bitwiseXor : binaryMethod('#'), regex : binaryMethod('~'), + regexp : binaryMethod('REGEXP'), notRegex : binaryMethod('!~'), concat : binaryMethod('||'), key : binaryMethod('->'), @@ -145,6 +146,7 @@ var ValueExpressionMixin = function() { path : binaryMethod('#>'), pathText : binaryMethod('#>>'), like : binaryMethod('LIKE'), + rlike : binaryMethod('RLIKE'), notLike : binaryMethod('NOT LIKE'), in : inMethod, notIn : notInMethod, From 8ecf9a66e488d22a929061abd7c81173175a5dfb Mon Sep 17 00:00:00 2001 From: Huibing Yin Date: Thu, 24 Jul 2014 13:59:47 -0500 Subject: [PATCH 041/248] Adding unit test for regexp and rlike. --- test/binary-clause-tests.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 438a3761..9b51ac7b 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -34,4 +34,6 @@ test('operators', function() { assert.equal(Foo.baz.modulo(1).operator, '%'); assert.equal(Foo.baz.regex(1).operator, '~'); assert.equal(Foo.baz.notRegex(1).operator, '!~'); + assert.equal(Foo.baz.regexp(1).operator, 'REGEXP'); + assert.equal(Foo.baz.rlike(1).operator, 'RLIKE'); }); From f77ed5253f819382c6850a66d41ad633038af623 Mon Sep 17 00:00:00 2001 From: bgag Date: Tue, 26 Aug 2014 10:30:16 +0200 Subject: [PATCH 042/248] accept arrays in where clause --- lib/node/where.js | 11 +++++++++++ test/dialects/where-clause-tests.js | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lib/node/where.js b/lib/node/where.js index b7f2be1b..89e9b9a8 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -9,6 +9,17 @@ var normalizeNode = function(table, node) { if(typeof node === 'string') { result = new TextNode('(' + node + ')'); } + else if (Array.isArray(node)) { + result = false; + + node.forEach(function (subNode) { + if (!result) { + result = subNode; + } else { + result = result.and(subNode); + } + }); + } else if (!node.toNode && typeof node === 'object'){ result = false; for (var colName in node) { diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index 7fef43f2..7d5e70cb 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -36,3 +36,20 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: user.where([user.id.isNotNull(), user.name.isNotNull()]), + pg: { + text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + mysql: { + text : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', + string: 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))' + }, + sqlite: { + text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, + params: [] +}); \ No newline at end of file From d7bfcb7f163bf6ff62224ee5a1ba3eabf5b366b3 Mon Sep 17 00:00:00 2001 From: bgag Date: Tue, 26 Aug 2014 10:31:14 +0200 Subject: [PATCH 043/248] accept arrays and multiple arguments in from clause --- lib/node/query.js | 15 +++++++++++--- test/dialects/from-clause-tests.js | 32 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 0613d1a3..5a407b9e 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -109,9 +109,18 @@ var Query = Node.define({ }); }, - from: function(tableNode) { - var from = new From().add(tableNode); - return this.add(from); + from: function() { + var tableNodes = arguments; + + if (Array.isArray(arguments[0])) { + tableNodes = arguments[0]; + } + + for (var i=0; i Date: Tue, 26 Aug 2014 10:35:45 +0200 Subject: [PATCH 044/248] don't list column aliases in count --- lib/dialect/postgres.js | 12 +++++++----- test/dialects/aggregate-tests.js | 19 +++++++++++++++++++ test/dialects/support.js | 13 +++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 64db5ad3..c4faa951 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -636,11 +636,13 @@ Postgres.prototype.visitColumn = function(columnNode) { if (columnNode.star) { var allCols = []; var hasAliases = false; - for(var i = 0; i < table.columns.length; ++i){ - var col = table.columns[i]; - var aliased = col.name !== (col.alias || col.property); - hasAliases = hasAliases || aliased; - allCols.push(this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : '')); + if(columnNode.aggregator !== 'COUNT') { + for (var i = 0; i < table.columns.length; ++i) { + var col = table.columns[i]; + var aliased = col.name !== (col.alias || col.property); + hasAliases = hasAliases || aliased; + allCols.push(this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : '')); + } } txt.push(hasAliases ? allCols.join(', ') : '*'); } diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 4eff37b3..300c38d8 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -2,6 +2,8 @@ var Harness = require('./support'); var post = Harness.definePostTable(); +var customerAlias = Harness.defineCustomerAliasTable(); + Harness.test({ query: post.select(post.count()), @@ -105,6 +107,23 @@ Harness.test({ params: [] }); +Harness.test({ + query: customerAlias.select(customerAlias.count()), + pg: { + text : 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"', + string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' + }, + sqlite: { + text : 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"', + string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' + }, + mysql: { + text : 'SELECT COUNT(`customer`.*) AS `customer_count` FROM `customer`', + string: 'SELECT COUNT(`customer`.*) AS `customer_count` FROM `customer`' + }, + params: [] +}); + Harness.test({ query: post.select(post.id.min()), pg: { diff --git a/test/dialects/support.js b/test/dialects/support.js index a85fabe7..b9a44b01 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -92,6 +92,19 @@ module.exports = { }); }, + defineCustomerAliasTable: function() { + return Table.define({ + name: 'customer', + columns: { + id: {property: 'id_alias'}, + name: {property: 'name_alias'}, + age: {property: 'age_alias'}, + income: {property: 'income_alias'}, + metadata: {property: 'metadata_alias'} + } + }); + }, + // This table contains column names that correspond to popularly used variables in formulas. defineVariableTable: function() { return Table.define({ From e4dbf25ce97d1291e7dc6e0583515fab06fe373b Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Fri, 12 Sep 2014 11:18:38 -0400 Subject: [PATCH 045/248] Remove travis 0.8.x support because npm is broken there --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ceb35c2..05d299e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,4 @@ language: node_js node_js: - - "0.8" - "0.10" - "0.11" - -matrix: - allow_failures: - - node_js: "0.11" From 925b3504ed162eb8a9ac1eb751b621d8f93e5f1b Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Fri, 12 Sep 2014 11:24:01 -0400 Subject: [PATCH 046/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e56c401..de75d862 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.39.0", + "version": "0.40.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From e5ebead9c8ce38a666656592a12d48d725191edb Mon Sep 17 00:00:00 2001 From: Maria Chapman Date: Tue, 18 Nov 2014 23:52:44 +0000 Subject: [PATCH 047/248] Add support for NOT NULL in create statement --- lib/dialect/postgres.js | 10 ++++-- lib/node/column.js | 1 + test/dialects/create-table-tests.js | 47 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index c4faa951..d908260c 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -662,9 +662,13 @@ Postgres.prototype.visitColumn = function(columnNode) { ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); txt.push(' ' + columnNode.dataType); - if (this._visitingCreate && columnNode.primaryKey) { - // creating a column as a primary key - txt.push(' PRIMARY KEY'); + if (this._visitingCreate) { + if (columnNode.primaryKey) { + // creating a column as a primary key + txt.push(' PRIMARY KEY'); + } else if (columnNode.notNull) { + txt.push(' NOT NULL'); + } } if (!!columnNode.references) { diff --git a/lib/node/column.js b/lib/node/column.js index 60724940..6234b2f2 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -17,6 +17,7 @@ module.exports = Node.define({ this.dataType = config.dataType; this.distinct = config.distinct; this.primaryKey = config.primaryKey; + this.notNull = config.notNull; this.references = config.references; this.autoGenerated = !!config.autoGenerated; }, diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 8ba5d01e..bfc567cd 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -145,6 +145,53 @@ Harness.test({ } }); +Harness.test({ + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'int', + notNull: true + }] + }).create(), + pg: { + text : 'CREATE TABLE "user" ("id" int NOT NULL)', + string: 'CREATE TABLE "user" ("id" int NOT NULL)' + }, + sqlite: { + text : 'CREATE TABLE "user" ("id" int NOT NULL)', + string: 'CREATE TABLE "user" ("id" int NOT NULL)' + }, + mysql: { + text : 'CREATE TABLE `user` (`id` int NOT NULL)', + string: 'CREATE TABLE `user` (`id` int NOT NULL)' + } +}); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'int', + primaryKey: true, + notNull: true + }] + }).create(), + pg: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + }, + sqlite: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' + }, + mysql: { + text : 'CREATE TABLE `user` (`id` int PRIMARY KEY)', + string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' + } +}); + Harness.test({ query: Table.define({ name: 'post', From 281ef851da7510540d0af43cb7211e7bb85d76e9 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Wed, 19 Nov 2014 21:29:24 -0500 Subject: [PATCH 048/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index de75d862..5f8ecf13 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.40.0", + "version": "0.41.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From e15bfd16b42099eb03d8abb5fcb8ee36dc8c604f Mon Sep 17 00:00:00 2001 From: soliton4 Date: Sun, 23 Nov 2014 21:11:35 +0100 Subject: [PATCH 049/248] index select including namespace - with test --- lib/dialect/postgres.js | 6 ++++-- test/dialects/indexes-tests.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d908260c..decdf13d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -792,14 +792,16 @@ Postgres.prototype.visitModifier = function(node) { Postgres.prototype.visitIndexes = function(node) { /* jshint unused: false */ - var tableName = this.visit(this._queryNode.table.toNode())[0]; + var tableName = this._queryNode.table.getName(); + var schemaName = this._queryNode.table.getSchema() || "public"; return [ "SELECT relname", "FROM pg_class", "WHERE oid IN (", "SELECT indexrelid", - "FROM pg_index, pg_class WHERE pg_class.relname=" + tableName.replace(/"/g, "'"), + "FROM pg_index, pg_class WHERE pg_class.relname='" + tableName + "'", + "AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = '" + schemaName + "')", "AND pg_class.oid=pg_index.indrelid)" ].join(' '); }; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 132c01fb..482e0d6d 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -6,8 +6,8 @@ var post = Harness.definePostTable(); Harness.test({ query: post.indexes(), pg: { - text : 'SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname=\'post\' AND pg_class.oid=pg_index.indrelid)', - string: 'SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname=\'post\' AND pg_class.oid=pg_index.indrelid)' + text : 'SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname=\'post\' AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = \'public\') AND pg_class.oid=pg_index.indrelid)', + string: 'SELECT relname FROM pg_class WHERE oid IN ( SELECT indexrelid FROM pg_index, pg_class WHERE pg_class.relname=\'post\' AND pg_class.relnamespace IN (SELECT pg_namespace.oid FROM pg_namespace WHERE nspname = \'public\') AND pg_class.oid=pg_index.indrelid)' }, mysql: { text : 'SHOW INDEX FROM `post`', From b669e0ab3dcef04b4e427a724656ccead3389fcd Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 24 Nov 2014 13:36:42 -0500 Subject: [PATCH 050/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f8ecf13..d98a5061 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.41.0", + "version": "0.42.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From fff8d89963984b8433e11bfb5f5530b8ab538515 Mon Sep 17 00:00:00 2001 From: Hitesh Date: Thu, 18 Dec 2014 18:51:09 +0530 Subject: [PATCH 051/248] Check to avoid select statement in case of empty insert --- lib/node/query.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/node/query.js b/lib/node/query.js index 5a407b9e..b58d854e 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -189,6 +189,7 @@ var Query = Node.define({ args.push(col.value(o[key])); }); } else if (o.forEach) { + if(!o.length) throw new Error('Insert values missing.'); o.forEach(function(arg) { return self.insert.call(self, arg); }); From 5872105e13ae08a8b399547b52e13c7c079386c1 Mon Sep 17 00:00:00 2001 From: Hitesh Date: Thu, 18 Dec 2014 19:03:00 +0530 Subject: [PATCH 052/248] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d98a5061..a2b3ea54 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.42.0", + "version": "0.43.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 3fee9df52171e50fc073372b8422236ab9bdd530 Mon Sep 17 00:00:00 2001 From: Gorgi Kosev Date: Mon, 22 Dec 2014 14:12:41 +0100 Subject: [PATCH 053/248] Add support for compound primary keys This patch adds support for compound primary keys. If multiple columns are specified with `primaryKey: true`, the generated table create query will contain a separate `PRIMARY KEY` section --- lib/dialect/postgres.js | 17 +++++++++++++++-- test/dialects/create-table-tests.js | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index decdf13d..8ddecc00 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -246,7 +246,20 @@ Postgres.prototype.visitCreate = function(create) { var result = ['CREATE TABLE']; result = result.concat(create.nodes.map(this.visit.bind(this))); result.push(this.visit(table.toNode())); - result.push('(' + col_nodes.map(this.visit.bind(this)).join(', ') + ')'); + this._visitCreateCompoundPrimaryKey = col_nodes.filter(function(n) { + return n.primaryKey; + }).length > 1; + var colspec = '(' + col_nodes.map(this.visit.bind(this)).join(', '); + if (this._visitCreateCompoundPrimaryKey) { + colspec += ', PRIMARY KEY ('; + colspec += col_nodes.map(function(node) { + return this.quote(node.name); + }.bind(this)).join(', '); + colspec += ')'; + } + colspec += ')'; + result.push(colspec); + this._visitCreateCompoundPrimaryKey = false; this._visitingCreate = false; return result; }; @@ -663,7 +676,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push(' ' + columnNode.dataType); if (this._visitingCreate) { - if (columnNode.primaryKey) { + if (columnNode.primaryKey && !this._visitCreateCompoundPrimaryKey) { // creating a column as a primary key txt.push(' PRIMARY KEY'); } else if (columnNode.notNull) { diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index bfc567cd..9d67db65 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -273,3 +273,25 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: Table.define({ + name: 'membership', + columns: { + group_id: { dataType: 'int', primaryKey: true}, + user_id: { dataType: 'int', primaryKey: true}, + } + }).create(), + pg: { + text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', + string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', + }, + sqlite: { + text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', + string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', + }, + mysql: { + text : 'CREATE TABLE `membership` (`group_id` int, `user_id` int, PRIMARY KEY (`group_id`, `user_id`))', + string: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, PRIMARY KEY (`group_id`, `user_id`))', + } +}); From 2ad2ba181c87d9633eddb7838e5336f442586cff Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 22 Dec 2014 14:32:40 -0500 Subject: [PATCH 054/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d98a5061..a2b3ea54 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.42.0", + "version": "0.43.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 91238f8965863c852ba393c03486692f4c036779 Mon Sep 17 00:00:00 2001 From: Hitesh Date: Sat, 3 Jan 2015 00:28:17 +0530 Subject: [PATCH 055/248] Handling case for empty array in insert --- lib/node/query.js | 4 +++- test/dialects/insert-tests.js | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/node/query.js b/lib/node/query.js index b58d854e..b624424c 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -180,6 +180,9 @@ var Query = Node.define({ var self = this; var args = sliced(arguments); + if (o.length == 0) { + o = {}; + } // object literal if (arguments.length === 1 && !o.toNode && !o.forEach) { args = []; @@ -189,7 +192,6 @@ var Query = Node.define({ args.push(col.value(o[key])); }); } else if (o.forEach) { - if(!o.length) throw new Error('Insert values missing.'); o.forEach(function(arg) { return self.insert.call(self, arg); }); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 69daa9f8..24b38a91 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -405,3 +405,12 @@ Harness.test({ }, params: [new Buffer('whoah'), new Buffer('hey')] }); +Harness.test({ + query: post.insert([]), + + mysql: { + text : 'INSERT INTO `post` () VALUES ()', + string: 'INSERT INTO `post` () VALUES ()' + }, + params: [] +}); \ No newline at end of file From db2e1c6cff7d4d882e8d65c98d3ea715cf6796e0 Mon Sep 17 00:00:00 2001 From: Christian Schuhmann Date: Wed, 7 Jan 2015 13:12:23 +0100 Subject: [PATCH 056/248] Add method table.clone([config]) --- lib/table.js | 11 +++++++++++ test/table-tests.js | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index 1a7338f7..0f719655 100644 --- a/lib/table.js +++ b/lib/table.js @@ -47,6 +47,17 @@ Table.define = function(config) { return table; }; +Table.prototype.clone = function(config) { + return Table.define(lodash.extend({ + schema: this._schema, + name: this._name, + sql: this.sql, + columnWhiteList: !!this.columnWhiteList, + snakeToCamel: !!this.snakeToCamel, + columns: this.columns + }, config || {})); +}; + Table.prototype.createColumn = function(col) { if(!(col instanceof Column)) { if(typeof col === 'string') { diff --git a/test/table-tests.js b/test/table-tests.js index 43c13791..e6570901 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -187,6 +187,40 @@ test('set and get schema', function () { assert.equal(table.getSchema(), 'barbarz'); }); +suite('table.clone', function() { + test('check if it is a copy, not just a reference', function() { + var table = Table.define({ name: 'foo', columns: [] }); + var copy = table.clone(); + assert.notEqual(table, copy); + }); + + test('copy columns', function() { + var table = Table.define({ name: 'foo', columns: ['bar'] }); + var copy = table.clone(); + assert(copy.get('bar') instanceof Column); + }); + + test('overwrite config while copying', function() { + var table = Table.define({ + name: 'foo', + schema: 'foobar', + columns: ['bar'], + snakeToCamel: true, + columnWhiteList: true + }); + + var copy = table.clone({ + schema: 'test', + snakeToCamel: false, + columnWhiteList: false + }); + + assert.equal(copy.getSchema(), 'test'); + assert.equal(copy.snakeToCamel, false); + assert.equal(copy.columnWhiteList, false); + }); +}); + test('dialects', function () { var sql = new Sql.Sql('mysql'); var foo = sql.define({ name: 'foo', columns: [ 'id' ] }), @@ -200,4 +234,4 @@ test('dialects', function () { bar = sql.define({ name: 'bar', columns: [ 'id' ] }); actual = foo.join(bar).on(bar.id.equals(1)).toString(); assert.equal(actual, '"foo" INNER JOIN "bar" ON ("bar"."id" = 1)'); -}); \ No newline at end of file +}); From 372e29a12d5291355b36dfb10e30f655a7d28790 Mon Sep 17 00:00:00 2001 From: Christian Schuhmann Date: Wed, 7 Jan 2015 13:13:19 +0100 Subject: [PATCH 057/248] Fix missing semicolons --- lib/table.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/table.js b/lib/table.js index 0f719655..429c89b5 100644 --- a/lib/table.js +++ b/lib/table.js @@ -146,7 +146,7 @@ Table.prototype.star = function(options) { Table.prototype.literal = function(literal) { return new LiteralNode(literal); -} +}; Table.prototype.count = function(alias) { var name = this.alias || this._name, @@ -177,9 +177,9 @@ Table.prototype.subQuery = function(alias) { var query = new Query(this); query.type = 'SUBQUERY'; query.alias = alias; - query.join = function(other) { - return new JoinNode('INNER', this.toNode(), other.toNode(), other); - } + query.join = function(other) { + return new JoinNode('INNER', this.toNode(), other.toNode(), other); + }; return query; }; From 233e3529fc0be210a1b0a41090f951a23db946c4 Mon Sep 17 00:00:00 2001 From: Bergwinkl Thomas Date: Tue, 13 Jan 2015 11:19:10 +0100 Subject: [PATCH 058/248] support empty array where clause --- lib/node/where.js | 18 +++++++++++------- test/dialects/where-clause-tests.js | 17 +++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/node/where.js b/lib/node/where.js index 89e9b9a8..b542807d 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -12,13 +12,17 @@ var normalizeNode = function(table, node) { else if (Array.isArray(node)) { result = false; - node.forEach(function (subNode) { - if (!result) { - result = subNode; - } else { - result = result.and(subNode); - } - }); + if (node.length === 0) { + result = new TextNode('(1 = 1)'); + } else { + node.forEach(function (subNode) { + if (!result) { + result = subNode; + } else { + result = result.and(subNode); + } + }); + } } else if (!node.toNode && typeof node === 'object'){ result = false; diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index 7d5e70cb..b296ef84 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -52,4 +52,21 @@ Harness.test({ string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' }, params: [] +}); + +Harness.test({ + query: user.where([]), + pg: { + text : 'SELECT * FROM "user" WHERE (1 = 1)', + string: 'SELECT * FROM "user" WHERE (1 = 1)' + }, + mysql: { + text : 'SELECT * FROM `user` WHERE (1 = 1)', + string: 'SELECT * FROM `user` WHERE (1 = 1)' + }, + sqlite: { + text : 'SELECT * FROM "user" WHERE (1 = 1)', + string: 'SELECT * FROM "user" WHERE (1 = 1)' + }, + params: [] }); \ No newline at end of file From 5a14c5f62b17e9080df55eff0fa59438ec67bd64 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 13 Jan 2015 16:15:33 -0500 Subject: [PATCH 059/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2b3ea54..0e1ebdef 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.43.0", + "version": "0.43.1", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 728fe06afd72424904fb20a3a9f8ccbcb8e72c19 Mon Sep 17 00:00:00 2001 From: Bergwinkl Thomas Date: Wed, 14 Jan 2015 10:13:28 +0100 Subject: [PATCH 060/248] fixed missing table name for .star() with alias case --- lib/dialect/postgres.js | 10 ++++++++-- test/dialects/select-tests.js | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 8ddecc00..c1bce725 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -650,14 +650,20 @@ Postgres.prototype.visitColumn = function(columnNode) { var allCols = []; var hasAliases = false; if(columnNode.aggregator !== 'COUNT') { + var tableName = txt.join(''); for (var i = 0; i < table.columns.length; ++i) { var col = table.columns[i]; var aliased = col.name !== (col.alias || col.property); hasAliases = hasAliases || aliased; - allCols.push(this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : '')); + allCols.push(tableName + this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : '')); } } - txt.push(hasAliases ? allCols.join(', ') : '*'); + if(hasAliases) { + txt = [allCols.join(', ')]; + } + else { + txt.push('*'); + } } else { txt.push(this.quote(columnNode.name)); diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 0809574c..ef187e88 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); +var customerAlias = Harness.defineCustomerAliasTable(); Harness.test({ query: post.select(post.id).select(post.content), @@ -19,3 +20,20 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: customerAlias.select(customerAlias.star()), + pg: { + text : 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', + string: 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' + }, + sqlite: { + text : 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"', + string: 'SELECT "customer"."id" AS "id_alias", "customer"."name" AS "name_alias", "customer"."age" AS "age_alias", "customer"."income" AS "income_alias", "customer"."metadata" AS "metadata_alias" FROM "customer"' + }, + mysql: { + text : 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`', + string: 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`' + }, + params: [] +}); \ No newline at end of file From 005d230b90978c82b204cc55e4937422243847f3 Mon Sep 17 00:00:00 2001 From: Hiteshm01 Date: Thu, 15 Jan 2015 01:05:35 +0530 Subject: [PATCH 061/248] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2b3ea54..0e1ebdef 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.43.0", + "version": "0.43.1", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 1f25ed6cc8241009ec127b530cca2d6608ab67e5 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Wed, 14 Jan 2015 14:43:41 -0500 Subject: [PATCH 062/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e1ebdef..bfb5acc6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.43.1", + "version": "0.43.2", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 62f154dff4c52175c1b93f78c11fd6523901ba46 Mon Sep 17 00:00:00 2001 From: Hitesh Date: Sat, 17 Jan 2015 01:16:31 +0530 Subject: [PATCH 063/248] Harmless select in case of invalid insert attempt --- lib/node/query.js | 3 --- lib/table.js | 7 ++++++- test/dialects/insert-tests.js | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index b624424c..5a407b9e 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -180,9 +180,6 @@ var Query = Node.define({ var self = this; var args = sliced(arguments); - if (o.length == 0) { - o = {}; - } // object literal if (arguments.length === 1 && !o.toNode && !o.forEach) { args = []; diff --git a/lib/table.js b/lib/table.js index 1a7338f7..044e42c6 100644 --- a/lib/table.js +++ b/lib/table.js @@ -174,7 +174,12 @@ Table.prototype.subQuery = function(alias) { Table.prototype.insert = function() { var query = new Query(this); - query.insert.apply(query, arguments); + if(arguments[0].length == 0){ + query.select.call(query, this.star()); + query.where.apply(query,["1=2"]); + } else { + query.insert.apply(query, arguments); + } return query; }; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 24b38a91..86b32040 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -409,8 +409,8 @@ Harness.test({ query: post.insert([]), mysql: { - text : 'INSERT INTO `post` () VALUES ()', - string: 'INSERT INTO `post` () VALUES ()' + text : 'SELECT `post`.* FROM `post` WHERE (1=2)', + string: 'SELECT `post`.* FROM `post` WHERE (1=2)' }, params: [] }); \ No newline at end of file From af47d3ccb0084097a4139546926985c7ad7d3bf8 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 19 Jan 2015 16:25:26 -0500 Subject: [PATCH 064/248] Renamed "sqlserver" to "mssql" as per the suggestion by sdepold. --- lib/dialect/index.js | 4 +- lib/dialect/{sqlserver.js => mssql.js} | 62 ++++++++++++------------- test/dialects/aggregate-tests.js | 36 +++++++------- test/dialects/alias-tests.js | 6 +-- test/dialects/alter-table-tests.js | 30 ++++++------ test/dialects/binary-clause-tests.js | 6 +-- test/dialects/cast-tests.js | 12 ++--- test/dialects/clause-ordering-tests.js | 8 ++-- test/dialects/create-table-tests.js | 12 ++--- test/dialects/delete-tests.js | 8 ++-- test/dialects/distinct-tests.js | 4 +- test/dialects/drop-table-tests.js | 4 +- test/dialects/from-clause-tests.js | 4 +- test/dialects/group-by-tests.js | 10 ++-- test/dialects/having-tests.js | 6 +-- test/dialects/join-tests.js | 12 ++--- test/dialects/join-to-tests.js | 6 +-- test/dialects/limit-and-offset-tests.js | 8 ++-- test/dialects/namespace-tests.js | 10 ++-- test/dialects/order-tests.js | 20 ++++---- test/dialects/schema-tests.js | 12 ++--- test/dialects/select-tests.js | 2 +- test/dialects/shortcut-tests.js | 12 ++--- test/dialects/subquery-tests.js | 10 ++-- test/dialects/support.js | 2 +- test/dialects/table-tests.js | 44 +++++++++--------- test/dialects/ternary-clause-tests.js | 4 +- test/dialects/tostring-tests.js | 12 ++--- test/dialects/unary-clause-tests.js | 4 +- test/dialects/update-tests.js | 12 ++--- test/dialects/value-expression-tests.js | 8 ++-- test/dialects/where-clause-tests.js | 4 +- test/index-tests.js | 22 ++++----- 33 files changed, 208 insertions(+), 208 deletions(-) rename lib/dialect/{sqlserver.js => mssql.js} (85%) diff --git a/lib/dialect/index.js b/lib/dialect/index.js index 68ae5857..ac4dcb91 100644 --- a/lib/dialect/index.js +++ b/lib/dialect/index.js @@ -9,8 +9,8 @@ var getDialect = function(dialect) { return require('./mysql'); case 'sqlite': return require('./sqlite'); - case 'sqlserver': - return require('./sqlserver'); + case 'mssql': + return require('./mssql'); default: throw new Error(dialect + ' is unsupported'); } diff --git a/lib/dialect/sqlserver.js b/lib/dialect/mssql.js similarity index 85% rename from lib/dialect/sqlserver.js rename to lib/dialect/mssql.js index 0b972a57..8062f976 100644 --- a/lib/dialect/sqlserver.js +++ b/lib/dialect/mssql.js @@ -6,42 +6,42 @@ var util = require('util'); var assert = require('assert'); -var SqlServer = function() { +var Mssql = function() { this.output = []; this.params = []; }; var Postgres = require(__dirname + '/postgres'); -util.inherits(SqlServer, Postgres); +util.inherits(Mssql, Postgres); -SqlServer.prototype._myClass = SqlServer; +Mssql.prototype._myClass = Mssql; -SqlServer.prototype._quoteCharacter = '['; +Mssql.prototype._quoteCharacter = '['; -SqlServer.prototype._arrayAggFunctionName = ''; +Mssql.prototype._arrayAggFunctionName = ''; -SqlServer.prototype._getParameterPlaceholder = function(index, value) { +Mssql.prototype._getParameterPlaceholder = function(index, value) { return '@' + index; }; -SqlServer.prototype.visitBinary = function(binary) { +Mssql.prototype.visitBinary = function(binary) { if (!isRightSideArray(binary)){ - return SqlServer.super_.prototype.visitBinary.call(this, binary); + return Mssql.super_.prototype.visitBinary.call(this, binary); } if (binary.operator=='IN'){ - return SqlServer.super_.prototype.visitBinary.call(this, binary); + return Mssql.super_.prototype.visitBinary.call(this, binary); } throw new Error('SQL Sever does not support arrays in this type of expression.'); }; -SqlServer.prototype.visitAlter = function(alter) { +Mssql.prototype.visitAlter = function(alter) { var self=this; var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; // Implement our own add column: // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" - // SqlServer: ALTER TABLE [name] ADD [col1], [col2] + // Mssql: ALTER TABLE [name] ADD [col1], [col2] function _addColumn(){ self._visitingAlter = true; var table = self._queryNode.table; @@ -59,7 +59,7 @@ SqlServer.prototype.visitAlter = function(alter) { // Implement our own drop column: // PostgreSQL: ALTER TABLE "name" DROP COLUMN "col1", DROP COLUMN "col2" - // SqlServer: ALTER TABLE [name] DROP COLUMN [col1], [col2] + // Mssql: ALTER TABLE [name] DROP COLUMN [col1], [col2] function _dropColumn(){ self._visitingAlter = true; var table = self._queryNode.table; @@ -80,7 +80,7 @@ SqlServer.prototype.visitAlter = function(alter) { // Implement our own rename table: // PostgreSQL: ALTER TABLE "post" RENAME TO "posts" - // SqlServer: EXEC sp_rename [post], [posts] + // Mssql: EXEC sp_rename [post], [posts] function _rename(){ self._visitingAlter = true; var table = self._queryNode.table; @@ -91,10 +91,10 @@ SqlServer.prototype.visitAlter = function(alter) { // Implement our own rename column: // PostgreSQL: ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId" - // SqlServer: EXEC sp_rename [group], [userId], [newUserId] + // Mssql: EXEC sp_rename [group], [userId], [newUserId] function _renameColumn(){ // TODO: implement this. Need to be able to get the [tableName.Column], which is hard to do with the current way visitXxx works - throw new Error('SqlServer renaming columns not yet implemented'); + throw new Error('Mssql renaming columns not yet implemented'); // self._visitingAlter = true; // var table = self._queryNode.table; // var result = ['EXEC sp_rename '+ @@ -110,10 +110,10 @@ SqlServer.prototype.visitAlter = function(alter) { if (isAlterDropColumn(alter)) return _dropColumn(); if (isAlterRename(alter)) return _rename(); if (isAlterRenameColumn(alter)) return _renameColumn(); - return SqlServer.super_.prototype.visitAlter.call(this, alter); + return Mssql.super_.prototype.visitAlter.call(this, alter); }; -SqlServer.prototype.visitColumn = function(columnNode) { +Mssql.prototype.visitColumn = function(columnNode) { var self=this; var table; var inSelectClause; @@ -123,7 +123,7 @@ SqlServer.prototype.visitColumn = function(columnNode) { } function _countStar(){ - // Implement our own since count(table.*) is invalid in SqlServer + // Implement our own since count(table.*) is invalid in Mssql var result='COUNT(*)' if(inSelectClause && columnNode.alias) { result += ' AS ' + self.quote(columnNode.alias); @@ -135,18 +135,18 @@ SqlServer.prototype.visitColumn = function(columnNode) { inSelectClause = !this._selectOrDeleteEndIndex; if (isCountStarExpression(columnNode)) return _countStar(); if (inSelectClause && !table.alias && columnNode.asArray) return _arrayAgg(); - return SqlServer.super_.prototype.visitColumn.call(this, columnNode); + return Mssql.super_.prototype.visitColumn.call(this, columnNode); }; -SqlServer.prototype.visitCreate = function(create) { +Mssql.prototype.visitCreate = function(create) { if (!isCreateIfNotExists(create)) { - return SqlServer.super_.prototype.visitCreate.call(this, create); + return Mssql.super_.prototype.visitCreate.call(this, create); } // Implement our own create if not exists: // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) - // SqlServer: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'group') BEGIN ... END + // Mssql: IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'group') BEGIN ... END var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); var tableResult=this.visit(table.toNode()); @@ -168,13 +168,13 @@ SqlServer.prototype.visitCreate = function(create) { return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; }; -SqlServer.prototype.visitDrop = function(drop) { +Mssql.prototype.visitDrop = function(drop) { if (!isDropIfExists(drop)) { - return SqlServer.super_.prototype.visitDrop.call(this, drop); + return Mssql.super_.prototype.visitDrop.call(this, drop); } // Implement our own drop if exists: // PostgreSQL: DROP TABLE IF EXISTS "group" - // SqlServer: IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END + // Mssql: IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [group]) BEGIN ... END var table = this._queryNode.table; var tableResult=this.visit(table.toNode()); @@ -189,8 +189,8 @@ SqlServer.prototype.visitDrop = function(drop) { return ['IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+dropResult.join(' ')+' END']; }; -SqlServer.prototype.visitOrderBy = function(orderBy) { - var result=SqlServer.super_.prototype.visitOrderBy.call(this, orderBy); +Mssql.prototype.visitOrderBy = function(orderBy) { + var result=Mssql.super_.prototype.visitOrderBy.call(this, orderBy); var offsetNode=orderBy.msSQLOffsetNode; var limitNode=orderBy.msSQLLimitNode; if (!offsetNode && !limitNode) return result; @@ -215,7 +215,7 @@ SqlServer.prototype.visitOrderBy = function(orderBy) { * @param {Node[]} filters * @returns {String[]} */ -SqlServer.prototype.visitQueryHelper=function(actions,targets,filters){ +Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ /** * * @param {Node[]} list @@ -311,8 +311,8 @@ SqlServer.prototype.visitQueryHelper=function(actions,targets,filters){ //}; // We deal with SELECT specially so we can add the TOP clause if needed -SqlServer.prototype.visitSelect = function(select) { - if (!select.msSQLLimitNode) return SqlServer.super_.prototype.visitSelect.call(this, select); +Mssql.prototype.visitSelect = function(select) { + if (!select.msSQLLimitNode) return Mssql.super_.prototype.visitSelect.call(this, select); var result=[ 'SELECT', 'TOP('+getModifierValue(this,select.msSQLLimitNode)+')', @@ -375,4 +375,4 @@ function isRightSideArray(binary){ return Array.isArray(binary.right); }; -module.exports = SqlServer; +module.exports = Mssql; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index b0f0d6ff..42de5286 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT(*) AS [post_count] FROM [post]', string: 'SELECT COUNT(*) AS [post_count] FROM [post]' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT(*) AS [post_count] FROM [post]', string: 'SELECT COUNT(*) AS [post_count] FROM [post]' }, @@ -59,7 +59,7 @@ Harness.test({ text : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT(*) AS [post_amount] FROM [post]', string: 'SELECT COUNT(*) AS [post_amount] FROM [post]' }, @@ -80,7 +80,7 @@ Harness.test({ text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' }, @@ -101,7 +101,7 @@ Harness.test({ text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' }, @@ -122,7 +122,7 @@ Harness.test({ text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' }, @@ -143,7 +143,7 @@ Harness.test({ text : 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT MIN([post].[id]) AS [id_min] FROM [post]', string: 'SELECT MIN([post].[id]) AS [id_min] FROM [post]' }, @@ -164,7 +164,7 @@ Harness.test({ text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' }, @@ -185,7 +185,7 @@ Harness.test({ text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' }, @@ -206,7 +206,7 @@ Harness.test({ text : 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT MAX([post].[id]) AS [id_max] FROM [post]', string: 'SELECT MAX([post].[id]) AS [id_max] FROM [post]' }, @@ -227,7 +227,7 @@ Harness.test({ text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' }, @@ -248,7 +248,7 @@ Harness.test({ text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' }, @@ -269,7 +269,7 @@ Harness.test({ text : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]', string: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]' }, @@ -290,7 +290,7 @@ Harness.test({ text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' }, @@ -311,7 +311,7 @@ Harness.test({ text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' }, @@ -332,7 +332,7 @@ Harness.test({ text : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]', string: 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]' }, @@ -353,7 +353,7 @@ Harness.test({ text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' }, @@ -374,7 +374,7 @@ Harness.test({ text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' }, diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index 89ade344..a6a5a09f 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', string: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]', string: 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > ?) AND (`customer`.`age` < ?))', string: 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > 10) AND (`customer`.`age` < 20))' }, - sqlserver: { + mssql: { text : 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > @1) AND ([customer].[age] < @2))', string: 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > 10) AND ([customer].[age] < 20))' }, @@ -59,7 +59,7 @@ Harness.test({ text : 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', string: 'SELECT (`customer`.`age` BETWEEN 10 AND 20) AS `ageBetween` FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT ([customer].[age] BETWEEN @1 AND @2) AS [ageBetween] FROM [customer]', string: 'SELECT ([customer].[age] BETWEEN 10 AND 20) AS [ageBetween] FROM [customer]' }, diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index e81a4977..5109a02a 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'ALTER TABLE `post` DROP COLUMN `content`', string: 'ALTER TABLE `post` DROP COLUMN `content`' }, - sqlserver: { + mssql: { text : 'ALTER TABLE [post] DROP COLUMN [content]', string: 'ALTER TABLE [post] DROP COLUMN [content]' }, @@ -39,7 +39,7 @@ Harness.test({ text : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' }, - sqlserver: { + mssql: { text : 'ALTER TABLE [post] DROP COLUMN [content], [userId]', string: 'ALTER TABLE [post] DROP COLUMN [content], [userId]' }, @@ -60,7 +60,7 @@ Harness.test({ text : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' }, - sqlserver: { + mssql: { text : 'ALTER TABLE [post] DROP COLUMN [content], [userId]', string: 'ALTER TABLE [post] DROP COLUMN [content], [userId]' }, @@ -81,7 +81,7 @@ Harness.test({ text : 'ALTER TABLE `post` RENAME TO `posts`', string: 'ALTER TABLE `post` RENAME TO `posts`' }, - sqlserver: { + mssql: { text : 'EXEC sp_rename [post], [posts]', string: 'EXEC sp_rename [post], [posts]' }, @@ -114,7 +114,7 @@ Harness.test({ text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)' }, - sqlserver: { + mssql: { text : 'ALTER TABLE [group] ADD [id] varchar(100)', string: 'ALTER TABLE [group] ADD [id] varchar(100)' }, @@ -135,7 +135,7 @@ Harness.test({ text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)' }, - sqlserver: { + mssql: { text : 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)', string: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)' }, @@ -156,7 +156,7 @@ Harness.test({ text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)' }, - sqlserver: { + mssql: { text : 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)', string: 'ALTER TABLE [group] ADD [id] varchar(100), [userId] varchar(100)' }, @@ -177,8 +177,8 @@ Harness.test({ text : 'Sqlite cannot rename columns', throws: true }, - sqlserver: { - text : 'SqlServer renaming columns not yet implemented', + mssql: { + text : 'Mssql renaming columns not yet implemented', throws: true // text : 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'', // string: 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'' @@ -200,8 +200,8 @@ Harness.test({ text : 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)' }, - sqlserver: { - text : 'SqlServer renaming columns not yet implemented', + mssql: { + text : 'Mssql renaming columns not yet implemented', throws: true // text : 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'', // string: 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'' @@ -223,8 +223,8 @@ Harness.test({ text : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)' }, - sqlserver: { - text : 'SqlServer renaming columns not yet implemented', + mssql: { + text : 'Mssql renaming columns not yet implemented', throws: true // text : 'EXEC sp_rename [group.userId], [id], \'COLUMN\'', // string: 'EXEC sp_rename [group.userId], [id], \'COLUMN\'' @@ -255,8 +255,8 @@ Harness.test({ text : 'Sqlite cannot rename columns', throws: true }, - sqlserver: { - text : 'SqlServer renaming columns not yet implemented', + mssql: { + text : 'Mssql renaming columns not yet implemented', throws: true // text : 'EXEC sp_rename [UserWithSignature.Signature], [sig], \'COLUMN\'', // string: 'EXEC sp_rename [UserWithSignature.Signature], [sig], \'COLUMN\'' diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 01cf2971..28b4a155 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' }, @@ -39,7 +39,7 @@ Harness.test({ text : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', string: 'SELECT (`post`.`content` + \'!\') FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))' }, - sqlserver: { + mssql: { text : 'SELECT ([post].[content] + @1) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', string: 'SELECT ([post].[content] + \'!\') FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))' }, @@ -60,7 +60,7 @@ Harness.test({ text : 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', string: 'SELECT ((`post`.`id` + \': \') + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))' }, - sqlserver: { + mssql: { text : 'SELECT (([post].[id] + @1) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', string: 'SELECT (([post].[id] + \': \') + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))' }, diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js index b73b1f43..4bf14c22 100644 --- a/test/dialects/cast-tests.js +++ b/test/dialects/cast-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT CAST([customer].[age] AS int) FROM [customer]', string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' }, @@ -39,7 +39,7 @@ Harness.test({ text : 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' }, @@ -61,7 +61,7 @@ Harness.test({ text : 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' }, @@ -83,7 +83,7 @@ Harness.test({ text : 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' }, @@ -105,7 +105,7 @@ Harness.test({ text : 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', string: 'SELECT `customer`.`name` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' }, - sqlserver: { + mssql: { text : 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', string: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' }, @@ -127,7 +127,7 @@ Harness.test({ text : 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' }, - sqlserver: { + mssql: { text : 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' }, diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index 3a2d0afd..baf7ac58 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -19,7 +19,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' }, @@ -43,7 +43,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' }, @@ -70,7 +70,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = \'\')' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = @1)', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = \'\')' }, @@ -94,7 +94,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' }, diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 47d68cce..ba1a4729 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -29,7 +29,7 @@ Harness.test({ text : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', string: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))' }, - sqlserver: { + mssql: { text : 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))', string: 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))' }, @@ -50,7 +50,7 @@ Harness.test({ text : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', string: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))' }, - sqlserver: { + mssql: { text : 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END', string: 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END' }, @@ -79,7 +79,7 @@ Harness.test({ text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' }, - sqlserver: { + mssql: { text : 'CREATE TABLE [user] ([id] varchar(100))', string: 'CREATE TABLE [user] ([id] varchar(100))' } @@ -107,7 +107,7 @@ Harness.test({ text : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', string: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' }, - sqlserver: { + mssql: { text : 'CREATE TABLE [user] ([id] varchar(100))', string: 'CREATE TABLE [user] ([id] varchar(100))' } @@ -136,7 +136,7 @@ Harness.test({ text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1', string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' }, - sqlserver: { + mssql: { text : 'CREATE TABLE [user] ([id] varchar(100))', string: 'CREATE TABLE [user] ([id] varchar(100))' } @@ -163,7 +163,7 @@ Harness.test({ text : 'CREATE TABLE `user` (`id` int PRIMARY KEY)', string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' }, - sqlserver: { + mssql: { text : 'CREATE TABLE [user] ([id] int PRIMARY KEY)', string: 'CREATE TABLE [user] ([id] int PRIMARY KEY)' } diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 011a70c7..0f136c55 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'hello\'\'s world\')' }, - sqlserver: { + mssql: { text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = 'hello''s world')" }, @@ -40,7 +40,7 @@ Harness.test({ text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, - sqlserver: { + mssql: { text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = '')" }, @@ -63,7 +63,7 @@ Harness.test({ text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, - sqlserver: { + mssql: { text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = '')" }, @@ -86,7 +86,7 @@ Harness.test({ text : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', string: 'DELETE FROM `post` WHERE ((`post`.`content` = \'\') OR (`post`.`content` IS NULL))' }, - sqlserver: { + mssql: { text : 'DELETE FROM [post] WHERE (([post].[content] = @1) OR ([post].[content] IS NULL))', string: "DELETE FROM [post] WHERE (([post].[content] = '') OR ([post].[content] IS NULL))" }, diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js index 9f0c1a69..97635b9d 100644 --- a/test/dialects/distinct-tests.js +++ b/test/dialects/distinct-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT DISTINCT(`user`.`id`) FROM `user`', string: 'SELECT DISTINCT(`user`.`id`) FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT DISTINCT([user].[id]) FROM [user]', string: 'SELECT DISTINCT([user].[id]) FROM [user]' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', string: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]', string: 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]' }, diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index d55e3cf9..e0998439 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'DROP TABLE `post`', string: 'DROP TABLE `post`' }, - sqlserver: { + mssql: { text : 'DROP TABLE [post]', string: 'DROP TABLE [post]' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'DROP TABLE IF EXISTS `post`', string: 'DROP TABLE IF EXISTS `post`' }, - sqlserver: { + mssql: { text : 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END', string: 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END' }, diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js index c8afa48d..4b363503 100644 --- a/test/dialects/from-clause-tests.js +++ b/test/dialects/from-clause-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` , `post`', string: 'SELECT `user`.* FROM `user` , `post`' }, - sqlserver: { + mssql: { text : 'SELECT [user].* FROM [user] , [post]', string: 'SELECT [user].* FROM [user] , [post]' } @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT `user`.*, `post`.* FROM `user` , `post`', string: 'SELECT `user`.*, `post`.* FROM `user` , `post`' }, - sqlserver: { + mssql: { text : 'SELECT [user].*, [post].* FROM [user] , [post]', string: 'SELECT [user].*, [post].* FROM [user] , [post]' } diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index 6a538289..d0d4c1eb 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]', string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' }, @@ -59,7 +59,7 @@ Harness.test({ text : 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', string: 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`' }, - sqlserver: { + mssql: { text : 'SQL Server does not support array_agg.', throws: true }, @@ -80,7 +80,7 @@ Harness.test({ text : 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', string: 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`' }, - sqlserver: { + mssql: { text : 'SQL Server does not support array_agg.', throws: true }, @@ -101,7 +101,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' }, diff --git a/test/dialects/having-tests.js b/test/dialects/having-tests.js index 1a3c49cf..ad315c6e 100644 --- a/test/dialects/having-tests.js +++ b/test/dialects/having-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10)' }, - sqlserver : { + mssql : { text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10)' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' }, - sqlserver : { + mssql : { text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' }, @@ -59,7 +59,7 @@ Harness.test({ text : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10) AND (`post`.`userId` < 100)' }, - sqlserver : { + mssql : { text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' }, diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index 3048f986..88792acf 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -19,7 +19,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' }, @@ -40,7 +40,7 @@ Harness.test({ text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, - sqlserver: { + mssql: { text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' }, @@ -66,7 +66,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', string: 'SELECT `user`.`name`, `post`.`content`, `comment`.`text` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) INNER JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])', string: 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])' }, @@ -87,7 +87,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])', string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])' }, @@ -113,7 +113,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])', string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])' }, @@ -144,7 +144,7 @@ Harness.test({ text : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)', string: 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) subposts ON ([user].[id] = [subposts].[subpostUserId])', string: 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) subposts ON ([user].[id] = [subposts].[subpostUserId])' }, diff --git a/test/dialects/join-to-tests.js b/test/dialects/join-to-tests.js index e4d1f6ae..e2d98cf0 100644 --- a/test/dialects/join-to-tests.js +++ b/test/dialects/join-to-tests.js @@ -50,7 +50,7 @@ Harness.test({ text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' }, - sqlserver: { + mssql: { text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])', string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])' }, @@ -71,7 +71,7 @@ Harness.test({ text : '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', string: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' }, - sqlserver: { + mssql: { text : '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])', string: '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])' }, @@ -92,7 +92,7 @@ Harness.test({ text : '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)', string: '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)' }, - sqlserver: { + mssql: { text : '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])', string: '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])' }, diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js index fc9c0201..39ffc7d6 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -20,7 +20,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' }, - sqlserver: { + mssql: { text : 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]', string: 'SELECT TOP(1) [user].* FROM [user] ORDER BY [user].[name]' }, @@ -41,7 +41,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' }, - sqlserver: { + mssql: { text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY', string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 6 ROWS FETCH NEXT 3 ROWS ONLY' }, @@ -62,7 +62,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }, - sqlserver: { + mssql: { text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS', string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' }, @@ -87,7 +87,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT 1', string: 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = \'John\')) LIMIT 1' }, - sqlserver: { + mssql: { text : 'Microsoft SQL Server does not support OFFSET without and ORDER BY.', throws: true }, diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 4f23b3c4..9954c3f7 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -20,7 +20,7 @@ Harness.test({ text : 'SELECT `u`.`name` FROM `user` AS `u`', string: 'SELECT `u`.`name` FROM `user` AS `u`' }, - sqlserver: { + mssql: { text : 'SELECT [u].[name] FROM [user] AS [u]', string: 'SELECT [u].[name] FROM [user] AS [u]' }, @@ -41,7 +41,7 @@ Harness.test({ text : 'SELECT `u`.* FROM `user` AS `u`', string: 'SELECT `u`.* FROM `user` AS `u`' }, - sqlserver: { + mssql: { text : 'SELECT [u].* FROM [user] AS [u]', string: 'SELECT [u].* FROM [user] AS [u]' }, @@ -63,7 +63,7 @@ Harness.test({ text : 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', string: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = 3))' }, - sqlserver: { + mssql: { text : 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = @1))', string: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = 3))' }, @@ -84,7 +84,7 @@ Harness.test({ text : 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))', string: 'SELECT `p`.`content`, `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`content` IS NOT NULL))' }, - sqlserver: { + mssql: { text : 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))', string: 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))' }, @@ -118,7 +118,7 @@ Harness.test({ text : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', string: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' }, - sqlserver: { + mssql: { text : 'SELECT [comment].[text], [comment].[userId] FROM [comment]', string: 'SELECT [comment].[text], [comment].[userId] FROM [comment]' }, diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index aa29d1c0..107f0da4 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' }, @@ -39,7 +39,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, @@ -60,7 +60,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, @@ -81,7 +81,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, @@ -102,7 +102,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, @@ -123,7 +123,7 @@ Harness.test({ text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' }, - sqlserver: { + mssql: { text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' }, @@ -144,7 +144,7 @@ Harness.test({ text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC', string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL) DESC' }, - sqlserver: { + mssql: { text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC', string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC' }, @@ -165,7 +165,7 @@ Harness.test({ text : 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)', string: 'SELECT (`post`.`content` IS NULL) FROM `post` ORDER BY (`post`.`content` IS NULL)' }, - sqlserver: { + mssql: { text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' }, @@ -186,7 +186,7 @@ Harness.test({ text : 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)', string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`)' }, - sqlserver: { + mssql: { text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])', string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])' }, @@ -207,7 +207,7 @@ Harness.test({ text : 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC', string: 'SELECT RTRIM(`post`.`content`) FROM `post` ORDER BY RTRIM(`post`.`content`) DESC' }, - sqlserver: { + mssql: { text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC', string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC' }, diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index 7024ad4d..417037f5 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -24,7 +24,7 @@ Harness.test({ text : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', string: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' }, - sqlserver: { + mssql: { text : 'SELECT [staging].[user].[id] FROM [staging].[user]', string: 'SELECT [staging].[user].[id] FROM [staging].[user]' }, @@ -45,7 +45,7 @@ Harness.test({ text : 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`', string: 'SELECT COUNT(`staging`.`user`.`id`) AS `id_count` FROM `staging`.`user`' }, - sqlserver: { + mssql: { text : 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]', string: 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]' }, @@ -66,7 +66,7 @@ Harness.test({ text : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', string: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' }, - sqlserver: { + mssql: { text : 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]', string: 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]' }, @@ -88,7 +88,7 @@ Harness.test({ text : 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', string: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' }, - sqlserver: { + mssql: { text : 'SELECT [uws].[name] FROM [staging].[user] AS [uws]', string: 'SELECT [uws].[name] FROM [staging].[user] AS [uws]' }, @@ -115,7 +115,7 @@ Harness.test({ text : 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)', string: 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' }, - sqlserver: { + mssql: { text : 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])', string: 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])' }, @@ -136,7 +136,7 @@ Harness.test({ text : 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)', string: 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)' }, - sqlserver: { + mssql: { text : 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])', string: 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])' }, diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 9e0c0979..7169cbb3 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT `post`.`id`, `post`.`content` FROM `post`', string: 'SELECT `post`.`id`, `post`.`content` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT [post].[id], [post].[content] FROM [post]', string: 'SELECT [post].[id], [post].[content] FROM [post]' }, diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 7bed5dd3..1c6efc2c 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -19,7 +19,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user`', string: 'SELECT `user`.* FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].* FROM [user]', string: 'SELECT [user].* FROM [user]' }, @@ -40,7 +40,7 @@ Harness.test({ text : 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' }, - sqlserver: { + mssql: { text : 'SELECT * FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT * FROM [user] WHERE ([user].[name] = 3)' }, @@ -61,7 +61,7 @@ Harness.test({ text : 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', string: 'SELECT * FROM `user` WHERE ((`user`.`name` = 3) AND (`user`.`id` = 1))' }, - sqlserver: { + mssql: { text : 'SELECT * FROM [user] WHERE (([user].[name] = @1) AND ([user].[id] = @2))', string: 'SELECT * FROM [user] WHERE (([user].[name] = 3) AND ([user].[id] = 1))' }, @@ -83,7 +83,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post`', string: 'SELECT `post`.`content` FROM `post`' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post]', string: 'SELECT [post].[content] FROM [post]' }, @@ -104,7 +104,7 @@ Harness.test({ text : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' }, - sqlserver: { + mssql: { text : 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = @1)', string: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = 1)' }, @@ -129,7 +129,7 @@ Harness.test({ text : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', string: 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = \'\')) AND (`post`.`userId` = 1))' }, - sqlserver: { + mssql: { text : 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = @1)) AND ([post].[userId] = @2))', string: 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = \'\')) AND ([post].[userId] = 1))' }, diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index cadd57da..8a5aa16e 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -23,7 +23,7 @@ Harness.test({ text : '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE ?)))))', string: '(`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` IN (SELECT `customer`.`name` FROM `customer` WHERE (`user`.`name` LIKE \'%HELLO%\')))))' }, - sqlserver: { + mssql: { text : '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE @1)))))', string: '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE \'%HELLO%\')))))' }, @@ -44,7 +44,7 @@ Harness.test({ text : 'SELECT * FROM (SELECT * FROM `user`)', string: 'SELECT * FROM (SELECT * FROM `user`)' }, - sqlserver: { + mssql: { text : 'SELECT * FROM (SELECT * FROM [user])', string: 'SELECT * FROM (SELECT * FROM [user])' }, @@ -65,7 +65,7 @@ Harness.test({ text : 'SELECT * FROM (SELECT * FROM `customer`) T1 , (SELECT * FROM `user`) T2', string: 'SELECT * FROM (SELECT * FROM `customer`) T1 , (SELECT * FROM `user`) T2' }, - sqlserver: { + mssql: { text : 'SELECT * FROM (SELECT * FROM [customer]) T1 , (SELECT * FROM [user]) T2', string: 'SELECT * FROM (SELECT * FROM [customer]) T1 , (SELECT * FROM [user]) T2' }, @@ -89,7 +89,7 @@ Harness.test({ text : '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))', string: '(`customer`.`name` BETWEEN (SELECT MIN(`customer`.`name`) FROM `customer`) AND (SELECT MAX(`customer`.`name`) FROM `customer`))' }, - sqlserver: { + mssql: { text : '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))', string: '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))' }, @@ -110,7 +110,7 @@ Harness.test({ text : '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))', string: '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))' }, - sqlserver: { + mssql: { text : '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))', string: '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))' }, diff --git a/test/dialects/support.js b/test/dialects/support.js index 2596f328..292d323d 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -8,7 +8,7 @@ var dialects = { pg : require('../../lib/dialect/postgres'), sqlite : require('../../lib/dialect/sqlite'), mysql : require('../../lib/dialect/mysql'), - sqlserver : require('../../lib/dialect/sqlserver') + mssql : require('../../lib/dialect/mssql') }; module.exports = { diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index fe68d88b..51a63db9 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user`', string: 'SELECT `user`.`id` FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user]', string: 'SELECT [user].[id] FROM [user]' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id], [user].[name] FROM [user]', string: 'SELECT [user].[id], [user].[name] FROM [user]' }, @@ -59,7 +59,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user`', string: 'SELECT `user`.* FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].* FROM [user]', string: 'SELECT [user].* FROM [user]' }, @@ -80,7 +80,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'foo\')' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'foo\')' }, @@ -101,7 +101,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' }, @@ -122,7 +122,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') AND (`user`.`name` = \'bar\'))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) AND ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') AND ([user].[name] = \'bar\'))' }, @@ -143,7 +143,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = \'foo\') OR (`user`.`name` = \'bar\'))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' }, @@ -164,7 +164,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'foo\') OR (`user`.`name` = \'baz\')) AND (`user`.`name` = \'bar\'))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) OR ([user].[name] = @2)) AND ([user].[name] = @3))', string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'foo\') OR ([user].[name] = \'baz\')) AND ([user].[name] = \'bar\'))' }, @@ -185,7 +185,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (\'foo\', \'bar\'))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (@1, @2))', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (\'foo\', \'bar\'))' }, @@ -206,7 +206,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', string: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (\'foo\', \'bar\')) AND (`user`.`id` = 1))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (@1, @2)) AND ([user].[id] = @3))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (\'foo\', \'bar\')) AND ([user].[id] = 1))' }, @@ -227,7 +227,7 @@ Harness.test({ text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id], [user].[name] FROM [user]', string: 'SELECT [user].[id], [user].[name] FROM [user]' }, @@ -255,7 +255,7 @@ Harness.test({ text : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', string: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = \'boom\') AND (`user`.`id` = 1)) OR ((`user`.`name` = \'bang\') AND (`user`.`id` = 2)))' }, - sqlserver: { + mssql: { text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) AND ([user].[id] = @2)) OR (([user].[name] = @3) AND ([user].[id] = @4)))', string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'boom\') AND ([user].[id] = 1)) OR (([user].[name] = \'bang\') AND ([user].[id] = 2)))' }, @@ -276,7 +276,7 @@ Harness.test({ text : 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`', string: 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]', string: 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]' }, @@ -318,7 +318,7 @@ Harness.test({ text : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = \'brian\')' }, @@ -339,7 +339,7 @@ Harness.test({ text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, - sqlserver: { + mssql: { text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, @@ -360,7 +360,7 @@ Harness.test({ text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, - sqlserver: { + mssql: { text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, @@ -381,7 +381,7 @@ Harness.test({ text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, - sqlserver: { + mssql: { text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, @@ -402,7 +402,7 @@ Harness.test({ text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' }, - sqlserver: { + mssql: { text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' }, @@ -425,7 +425,7 @@ Harness.test({ text : 'SELECT name FROM user WHERE (`user`.`name` = ?)', string: 'SELECT name FROM user WHERE (`user`.`name` = \'brian\')' }, - sqlserver: { + mssql: { text : 'SELECT name FROM user WHERE ([user].[name] = @1)', string: 'SELECT name FROM user WHERE ([user].[name] = \'brian\')' }, @@ -449,7 +449,7 @@ Harness.test({ text : 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', string: 'SELECT name FROM user WHERE ((`user`.`name` = \'brian\') AND (`user`.`id` = 1))' }, - sqlserver: { + mssql: { text : 'SELECT name FROM user WHERE (([user].[name] = @1) AND ([user].[id] = @2))', string: 'SELECT name FROM user WHERE (([user].[name] = \'brian\') AND ([user].[id] = 1))' }, @@ -470,7 +470,7 @@ Harness.test({ text : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', string: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`' }, - sqlserver: { + mssql: { text : 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]', string: 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]' }, @@ -491,7 +491,7 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))' }, - sqlserver: { + mssql: { text : 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))', string: 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))' }, diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js index a14bb1ce..60c369b8 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN 18 AND 25)' }, - sqlserver: { + mssql: { text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN @1 AND @2)', string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN 18 AND 25)' }, @@ -39,7 +39,7 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` BETWEEN (SELECT MIN(`customer`.`id`) AS `id_min` FROM `customer`) AND (SELECT MAX(`customer`.`id`) AS `id_max` FROM `customer`))' }, - sqlserver: { + mssql: { text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))', string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))' }, diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index 7b2b819d..47b60367 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -19,7 +19,7 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = NULL)' }, - sqlserver: { + mssql: { text : '([post].[content] = @1)', string: '([post].[content] = NULL)' }, @@ -41,7 +41,7 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = 3.14)' }, - sqlserver: { + mssql: { text : '([post].[content] = @1)', string: '([post].[content] = 3.14)' }, @@ -63,7 +63,7 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = \'hello\'\'\')' }, - sqlserver: { + mssql: { text : '([post].[content] = @1)', string: '([post].[content] = \'hello\'\'\')' }, @@ -85,7 +85,7 @@ Harness.test({ text : '(`post`.`content` = (?, ?, ?))', string: '(`post`.`content` = (1, \'2\', NULL))' }, - sqlserver: { + mssql: { text : 'SQL Server does not support arrays.', throws: true }, @@ -107,7 +107,7 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' }, - sqlserver: { + mssql: { text : '([post].[content] = @1)', string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' }, @@ -135,7 +135,7 @@ Harness.test({ text : '(`post`.`content` = ?)', string: '(`post`.`content` = \'secretMessage\')' }, - sqlserver: { + mssql: { text : '([post].[content] = @1)', string: '([post].[content] = \'secretMessage\')' }, diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js index c16c4dc7..02352545 100644 --- a/test/dialects/unary-clause-tests.js +++ b/test/dialects/unary-clause-tests.js @@ -18,7 +18,7 @@ Harness.test({ text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)' }, - sqlserver: { + mssql: { text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)', string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)' }, @@ -39,7 +39,7 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))' }, - sqlserver: { + mssql: { text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))', string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))' }, diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index 964b4538..ef14a497 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -20,7 +20,7 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?', string: 'UPDATE `post` SET `content` = \'test\'' }, - sqlserver: { + mssql: { text : 'UPDATE [post] SET [content] = @1', string: 'UPDATE [post] SET [content] = \'test\'' }, @@ -44,7 +44,7 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?, `userId` = ?', string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3' }, - sqlserver: { + mssql: { text : 'UPDATE [post] SET [content] = @1, [userId] = @2', string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3' }, @@ -68,7 +68,7 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?, `userId` = ?', string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' }, - sqlserver: { + mssql: { text : 'UPDATE [post] SET [content] = @1, [userId] = @2', string: 'UPDATE [post] SET [content] = NULL, [userId] = 3' }, @@ -92,7 +92,7 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3 WHERE (`post`.`content` = \'no\')' }, - sqlserver: { + mssql: { text : 'UPDATE [post] SET [content] = @1, [userId] = @2 WHERE ([post].[content] = @3)', string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3 WHERE ([post].[content] = \'no\')' }, @@ -115,7 +115,7 @@ Harness.test({ text : 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', string: 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' }, - sqlserver: { + mssql: { text : 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])', string: 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])' }, @@ -139,7 +139,7 @@ Harness.test({ text : 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', string: 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)' }, - sqlserver: { + mssql: { text : 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])', string: 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])' }, diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 341d924b..324ac1c4 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -19,7 +19,7 @@ Harness.test({ text : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', string: 'SELECT `customer`.`name`, (`customer`.`income` % 100) FROM `customer` WHERE (((`customer`.`age` + 5) * (`customer`.`age` - 2)) = 10)' }, - sqlserver: { + mssql: { text : 'SELECT [customer].[name], ([customer].[income] % @1) FROM [customer] WHERE ((([customer].[age] + @2) * ([customer].[age] - @3)) = @4)', string: 'SELECT [customer].[name], ([customer].[income] % 100) FROM [customer] WHERE ((([customer].[age] + 5) * ([customer].[age] - 2)) = 10)' }, @@ -41,7 +41,7 @@ Harness.test({ text : 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', string: 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + \'hello\'))' }, - sqlserver: { + mssql: { text : 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + @1))', string: 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + \'hello\'))' }, @@ -64,7 +64,7 @@ Harness.test({ text : 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', string: 'SELECT ((((`variable`.`a` * `variable`.`a`) / 2) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`' }, - sqlserver: { + mssql: { text : 'SELECT (((([variable].[a] * [variable].[a]) / @1) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', string: 'SELECT (((([variable].[a] * [variable].[a]) / 2) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]' }, @@ -86,7 +86,7 @@ Harness.test({ text : 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', string: 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`' }, - sqlserver: { + mssql: { text : 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]', string: 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]' }, diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index c63362a3..b8257d22 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -17,7 +17,7 @@ Harness.test({ text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' }, - sqlserver: { + mssql: { text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' }, @@ -38,7 +38,7 @@ Harness.test({ text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' }, - sqlserver: { + mssql: { text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' }, diff --git a/test/index-tests.js b/test/index-tests.js index 2c30a537..d59f53ec 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -27,8 +27,8 @@ suite('index', function() { assert.equal(sql.create('mysql').dialectName, 'mysql'); }); - test('stores the sqlserver dialect', function() { - assert.equal(sql.create('sqlserver').dialectName, 'sqlserver'); + test('stores the mssql dialect', function() { + assert.equal(sql.create('mssql').dialectName, 'mssql'); }); test('can create a query using the default dialect', function() { @@ -53,46 +53,46 @@ suite('index', function() { }); test('sql.define for parallel dialects work independently', function() { + var mssql = sql.create('mssql'); var mysql = sql.create('mysql'); var postgres = sql.create('postgres'); var sqlite = sql.create('sqlite'); - var sqlserver = sql.create('sqlserver'); + var mssqlTable = mssql.define({name: 'table', columns: ['column']}); var mysqlTable = mysql.define({name: 'table', columns: ['column']}); var postgresTable = postgres.define({name: 'table', columns: ['column']}); var sqliteTable = sqlite.define({name: 'table', columns: ['column']}); - var sqlserverTable = sqlserver.define({name: 'table', columns: ['column']}); assert.equal(mysqlTable.sql, mysql); assert.equal(postgresTable.sql, postgres); assert.equal(sqliteTable.sql, sqlite); - assert.equal(sqlserverTable.sql, sqlserver); + assert.equal(mssqlTable.sql, mssql); }); test('using Sql as a class', function() { var Sql = sql.Sql; + var mssql = new Sql('mssql'); var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); - var sqlserver = new Sql('sqlserver'); assert.equal(mysql.dialect, require(__dirname + '/../lib/dialect/mysql')); assert.equal(postgres.dialect, require(__dirname + '/../lib/dialect/postgres')); assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); - assert.equal(sqlserver.dialect, require(__dirname + '/../lib/dialect/sqlserver')); + assert.equal(mssql.dialect, require(__dirname + '/../lib/dialect/mssql')); }); test('override dialect for toQuery using dialect name', function() { var Sql = sql.Sql; + var mssql = new Sql('mssql'); var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); - var sqlserver = new Sql('sqlserver'); var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlite'); var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('postgres'); var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mysql'); - var sqlserverQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlserver'); + var mssqlQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mssql'); var values = ['brian.m.carlson@gmail.com']; assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); @@ -104,8 +104,8 @@ suite('index', function() { assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); assert.deepEqual(mysqlQuery.values, values); -// assert.equal(sqlserverQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = ?)'); -// assert.deepEqual(sqlserverQuery.values, values); + assert.equal(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); + assert.deepEqual(mssqlQuery.values, values); }); test('override dialect for toQuery using invalid dialect name', function() { From b3a0206ce1a1c2ab46ec8ade0fda50530d0598d2 Mon Sep 17 00:00:00 2001 From: danrzeppa Date: Mon, 19 Jan 2015 17:40:27 -0500 Subject: [PATCH 065/248] Fix indents. --- lib/node/orderByValue.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/node/orderByValue.js b/lib/node/orderByValue.js index d54b015b..51d44567 100644 --- a/lib/node/orderByValue.js +++ b/lib/node/orderByValue.js @@ -8,9 +8,9 @@ var OrderByColumn = Node.define({ Node.call(this); this.value = config.value; this.direction = config.direction; - // used when processing OFFSET and LIMIT clauses in MSSQL - this.msSQLOffsetNode=undefined; - this.msSQLLimitNode=undefined; + // used when processing OFFSET and LIMIT clauses in MSSQL + this.msSQLOffsetNode=undefined; + this.msSQLLimitNode=undefined; } }); From d7ba4ff1f63085983e89ceab9ebdde1b8502475f Mon Sep 17 00:00:00 2001 From: danrzeppa Date: Mon, 19 Jan 2015 17:42:37 -0500 Subject: [PATCH 066/248] Fix indents in index-tests.js --- test/index-tests.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/index-tests.js b/test/index-tests.js index d59f53ec..63b85ea1 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -45,20 +45,19 @@ suite('index', function() { }); test('sql.create creates an instance with a new dialect', function() { - var mysql = sql.create('mysql'); - var query = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - assert.equal(query.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); - assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); - + var mysql = sql.create('mysql'); + var query = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); + assert.equal(query.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); + assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); }); test('sql.define for parallel dialects work independently', function() { - var mssql = sql.create('mssql'); + var mssql = sql.create('mssql'); var mysql = sql.create('mysql'); var postgres = sql.create('postgres'); var sqlite = sql.create('sqlite'); - var mssqlTable = mssql.define({name: 'table', columns: ['column']}); + var mssqlTable = mssql.define({name: 'table', columns: ['column']}); var mysqlTable = mysql.define({name: 'table', columns: ['column']}); var postgresTable = postgres.define({name: 'table', columns: ['column']}); var sqliteTable = sqlite.define({name: 'table', columns: ['column']}); @@ -71,7 +70,7 @@ suite('index', function() { test('using Sql as a class', function() { var Sql = sql.Sql; - var mssql = new Sql('mssql'); + var mssql = new Sql('mssql'); var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); @@ -84,7 +83,7 @@ suite('index', function() { test('override dialect for toQuery using dialect name', function() { var Sql = sql.Sql; - var mssql = new Sql('mssql'); + var mssql = new Sql('mssql'); var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); @@ -92,7 +91,7 @@ suite('index', function() { var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlite'); var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('postgres'); var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mysql'); - var mssqlQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mssql'); + var mssqlQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mssql'); var values = ['brian.m.carlson@gmail.com']; assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); From 13ab4aac0e266583265e0139063efa5fe22b21f1 Mon Sep 17 00:00:00 2001 From: danrzeppa Date: Mon, 19 Jan 2015 17:44:47 -0500 Subject: [PATCH 067/248] Fixed indents in posgres.js --- lib/dialect/postgres.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 3b7dfc64..bd5c50bd 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -418,8 +418,8 @@ Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ // lazy-man sorting var sortedNodes = actions.concat(targets).concat(filters); for(var i = 0; i < sortedNodes.length; i++) { - var res = this.visit(sortedNodes[i]); - this.output = this.output.concat(res); + var res = this.visit(sortedNodes[i]); + this.output = this.output.concat(res); } // implicit 'from' return this.output; From 3c065b5615dd51e9c0829980a481110898f4e9c9 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 19 Jan 2015 18:12:14 -0500 Subject: [PATCH 068/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bfb5acc6..f225a2a8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.43.2", + "version": "0.44.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 8e263f6a79f9fe3e4324229874e10b77968107a7 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 19 Jan 2015 18:21:30 -0500 Subject: [PATCH 069/248] Updated some tests to include coverage for Microsoft SQL Server. --- test/dialects/where-clause-tests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index 4e0320d3..888941bc 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -59,6 +59,10 @@ Harness.test({ text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' }, + mssql: { + text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', + string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' + }, params: [] }); @@ -76,5 +80,9 @@ Harness.test({ text : 'SELECT * FROM "user" WHERE (1 = 1)', string: 'SELECT * FROM "user" WHERE (1 = 1)' }, + mssql: { + text : 'SELECT * FROM [user] WHERE (1 = 1)', + string: 'SELECT * FROM [user] WHERE (1 = 1)' + }, params: [] }); \ No newline at end of file From 0990d770e82d96040c4a300cc771377670358bdf Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 19 Jan 2015 18:38:51 -0500 Subject: [PATCH 070/248] Support for AND and OR without having to first use WHERE --- lib/node/query.js | 2 + test/dialects/where-clause-tests.js | 87 ++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/lib/node/query.js b/lib/node/query.js index 5a407b9e..255332fd 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -142,11 +142,13 @@ var Query = Node.define({ }, or: function(node) { + if (!this.whereClause) return this.where(node); this.whereClause.or(node); return this; }, and: function(node) { + if (!this.whereClause) return this.where(node); this.whereClause.and(node); return this; }, diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index 888941bc..b25f1f35 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -85,4 +85,89 @@ Harness.test({ string: 'SELECT * FROM [user] WHERE (1 = 1)' }, params: [] -}); \ No newline at end of file +}); + +Harness.test({ + query: user.select().where(user.id.equals(1)).and(user.name.equals('a')), + pg: { + text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) AND ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' + }, + mysql: { + text : 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = ?) AND (`user`.`name` = ?))', + string: 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = 1) AND (`user`.`name` = \'a\'))' + }, + sqlite: { + text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) AND ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' + }, + mssql: { + text : 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) AND ([user].[name] = @2))', + string: 'SELECT [user].* FROM [user] WHERE (([user].[id] = 1) AND ([user].[name] = \'a\'))' + }, + params: [1,'a'] +}); + +Harness.test({ + query: user.select().and(user.id.equals(1)), + pg: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mysql: { + text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = ?)', + string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' + }, + sqlite: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mssql: { + text : 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', + string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' + }, + params: [1] +}); + +Harness.test({ + query: user.select().or(user.id.equals(1)), + pg: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mysql: { + text : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = ?)', + string: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' + }, + sqlite: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = $1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mssql: { + text : 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', + string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' + }, + params: [1] +}); + +Harness.test({ + query: user.select().and(user.id.equals(1)).or(user.name.equals('a')), + pg: { + text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' + }, + mysql: { + text : 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = ?) OR (`user`.`name` = ?))', + string: 'SELECT `user`.* FROM `user` WHERE ((`user`.`id` = 1) OR (`user`.`name` = \'a\'))' + }, + sqlite: { + text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = $1) OR ("user"."name" = $2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' + }, + mssql: { + text : 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) OR ([user].[name] = @2))', + string: 'SELECT [user].* FROM [user] WHERE (([user].[id] = 1) OR ([user].[name] = \'a\'))' + }, + params: [1,'a'] +}); + From 8eb55e1959cc9321a4756e79df46b432ffaf943d Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 19 Jan 2015 20:41:19 -0500 Subject: [PATCH 071/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f225a2a8..ff0dd645 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.44.0", + "version": "0.45.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 94960cf83911ae48d5d43a86e7157025ad113eb9 Mon Sep 17 00:00:00 2001 From: Brian C Date: Mon, 19 Jan 2015 20:42:48 -0500 Subject: [PATCH 072/248] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b16559e..3a5493b8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # node-sql -_sql string builder for node_ - supports PostgreSQL, mysql, and sqlite dialects. +_sql string builder for node_ - supports PostgreSQL, mysql, Microsoft SQL Server, and sqlite dialects. Building SQL statements by hand is no fun, especially in a language which has clumsy support for multi-line strings. From 334933502142421f0efec851db9f33d1549a2124 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 19 Jan 2015 21:55:41 -0500 Subject: [PATCH 073/248] - Fixed issue with MSSQL NOT IN statement. - Added tests for IN clauses for MSSQL. - Added tests for NOT IN clauses for MSSQL. --- lib/dialect/mssql.js | 2 +- test/dialects/in-clause-tests.js | 28 ++++++++++++++++++++++++++++ test/dialects/not-in-clause-tests.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 8062f976..2bab878f 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -29,7 +29,7 @@ Mssql.prototype.visitBinary = function(binary) { if (!isRightSideArray(binary)){ return Mssql.super_.prototype.visitBinary.call(this, binary); } - if (binary.operator=='IN'){ + if (binary.operator=='IN' || binary.operator=='NOT IN'){ return Mssql.super_.prototype.visitBinary.call(this, binary); } throw new Error('SQL Sever does not support arrays in this type of expression.'); diff --git a/test/dialects/in-clause-tests.js b/test/dialects/in-clause-tests.js index a8410e14..374ca6fd 100644 --- a/test/dialects/in-clause-tests.js +++ b/test/dialects/in-clause-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (1=0)', string: 'SELECT `post`.* FROM `post` WHERE (1=0)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE (1=0)', + string: 'SELECT [post].* FROM [post] WHERE (1=0)' + }, params: [] }); @@ -34,6 +38,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1))' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1))' + }, params: [1] }); @@ -51,6 +59,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' + }, params: [] }); @@ -68,6 +80,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2))' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2))' + }, params: [1, 2] }); @@ -85,6 +101,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' + }, params: [] }); @@ -102,6 +122,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL)', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' + }, params: [1, 2] }); @@ -119,5 +143,9 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL)', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' + }, params: [1, 2] }); diff --git a/test/dialects/not-in-clause-tests.js b/test/dialects/not-in-clause-tests.js index b6655e3a..a16c8887 100644 --- a/test/dialects/not-in-clause-tests.js +++ b/test/dialects/not-in-clause-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (1=1)', string: 'SELECT `post`.* FROM `post` WHERE (1=1)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE (1=1)', + string: 'SELECT [post].* FROM [post] WHERE (1=1)' + }, params: [] }); @@ -34,6 +38,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1))' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1))' + }, params: [1] }); @@ -51,6 +59,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' + }, params: [] }); @@ -68,6 +80,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?, ?))', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1, 2))' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1, @2))', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1, 2))' + }, params: [1, 2] }); @@ -85,6 +101,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', + string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' + }, params: [] }); @@ -102,6 +122,10 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL))', string: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL))' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', + string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' + }, params: [1, 2] }); @@ -119,5 +143,9 @@ Harness.test({ text : 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (?, ?) OR `post`.`id` IS NULL))', string: 'SELECT `post`.* FROM `post` WHERE (NOT (`post`.`id` IN (1, 2) OR `post`.`id` IS NULL))' }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', + string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' + }, params: [1, 2] }); From dd58d01aa1ab16e31e9136f9fb6c89a33c5673a1 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 19 Jan 2015 22:22:25 -0500 Subject: [PATCH 074/248] Added test cases for Microsoft SQL Server CASE statement. The syntax is the same as the other flavors so no real modifications to the code generator where necessary. --- test/dialects/case-tests.js | 74 ++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/test/dialects/case-tests.js b/test/dialects/case-tests.js index 61f193ec..f1e08411 100644 --- a/test/dialects/case-tests.js +++ b/test/dialects/case-tests.js @@ -8,15 +8,19 @@ Harness.test({ query: customer.select(customer.age.case([true, false], [0, 1], 2)), pg: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"' }, sqlite: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) FROM `customer`', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM `customer`', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM `customer`' + }, + mssql: { + text : 'SELECT (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE @5 END) FROM [customer]', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM [customer]' }, params: [true, 0, false, 1, 2] }); @@ -26,15 +30,19 @@ Harness.test({ query: customer.select(customer.age.plus(customer.age.case([true, false], [0, 1], 2))), pg: { text : 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', - string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"', + string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"' }, sqlite: { text : 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', - string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"', + string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"' }, mysql: { text : 'SELECT (`customer`.`age` + (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END)) FROM `customer`', - string: 'SELECT (`customer`.`age` + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM `customer`', + string: 'SELECT (`customer`.`age` + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM `customer`' + }, + mssql: { + text : 'SELECT ([customer].[age] + (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE @5 END)) FROM [customer]', + string: 'SELECT ([customer].[age] + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM [customer]' }, params: [true, 0, false, 1, 2] }); @@ -48,11 +56,15 @@ Harness.test({ }, sqlite: { text : 'SELECT ((CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) + $6) FROM "customer"', - string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM "customer"', + string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM "customer"' }, mysql: { text : 'SELECT ((CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) + ?) FROM `customer`', - string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM `customer`', + string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM `customer`' + }, + mssql: { + text : 'SELECT ((CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE @5 END) + @6) FROM [customer]', + string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM [customer]' }, params: [true, 0, false, 1, 2, 3] }); @@ -66,11 +78,15 @@ Harness.test({ }, sqlite: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE ("customer"."age" BETWEEN $5 AND $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE (`customer`.`age` BETWEEN ? AND ?) END) FROM `customer`', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE (`customer`.`age` BETWEEN 10 AND 20) END) FROM `customer`', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE (`customer`.`age` BETWEEN 10 AND 20) END) FROM `customer`' + }, + mssql: { + text : 'SELECT (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE ([customer].[age] BETWEEN @5 AND @6) END) FROM [customer]', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ([customer].[age] BETWEEN 10 AND 20) END) FROM [customer]' }, params: [true, 0, false, 1, 10, 20] }); @@ -84,11 +100,15 @@ Harness.test({ }, sqlite: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM "customer"', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? END) FROM `customer`', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM `customer`', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM `customer`' + }, + mssql: { + text : 'SELECT (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 END) FROM [customer]', + string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM [customer]' }, params: [true, 0, false, 1] }); @@ -98,15 +118,19 @@ Harness.test({ query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [0, 1], 2)), pg: { text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 ELSE $7 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' }, sqlite: { text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 ELSE $7 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN ? WHEN (`customer`.`age` <= ?) THEN ? ELSE ? END) FROM `customer`', - string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 ELSE 2 END) FROM `customer`', + string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 ELSE 2 END) FROM `customer`' + }, + mssql: { + text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 ELSE @7 END) FROM [customer]', + string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 ELSE 2 END) FROM [customer]' }, params: [10, 20, 30, 0, 60, 1, 2] }); @@ -116,15 +140,19 @@ Harness.test({ query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [0, 1])), pg: { text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' }, sqlite: { text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN $4 WHEN ("customer"."age" <= $5) THEN $6 END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN ? WHEN (`customer`.`age` <= ?) THEN ? END) FROM `customer`', - string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 END) FROM `customer`', + string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN 0 WHEN (`customer`.`age` <= 60) THEN 1 END) FROM `customer`' + }, + mssql: { + text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 END) FROM [customer]', + string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 END) FROM [customer]' }, params: [10, 20, 30, 0, 60, 1] }); @@ -134,15 +162,19 @@ Harness.test({ query: customer.select(customer.age.case([customer.age.in([10, 20, 30]), customer.age.lte(60)], [customer.age.plus(5), customer.age.minus(1)])), pg: { text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN ("customer"."age" + $4) WHEN ("customer"."age" <= $5) THEN ("customer"."age" - $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' }, sqlite: { text : 'SELECT (CASE WHEN ("customer"."age" IN ($1, $2, $3)) THEN ("customer"."age" + $4) WHEN ("customer"."age" <= $5) THEN ("customer"."age" - $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN (`customer`.`age` IN (?, ?, ?)) THEN (`customer`.`age` + ?) WHEN (`customer`.`age` <= ?) THEN (`customer`.`age` - ?) END) FROM `customer`', - string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN (`customer`.`age` + 5) WHEN (`customer`.`age` <= 60) THEN (`customer`.`age` - 1) END) FROM `customer`', + string: 'SELECT (CASE WHEN (`customer`.`age` IN (10, 20, 30)) THEN (`customer`.`age` + 5) WHEN (`customer`.`age` <= 60) THEN (`customer`.`age` - 1) END) FROM `customer`' + }, + mssql: { + text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN ([customer].[age] + @4) WHEN ([customer].[age] <= @5) THEN ([customer].[age] - @6) END) FROM [customer]', + string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN ([customer].[age] + 5) WHEN ([customer].[age] <= 60) THEN ([customer].[age] - 1) END) FROM [customer]' }, params: [10, 20, 30, 5, 60, 1] }); From 43ae833821551dd71031d31d76db8e7701d40ac5 Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 20 Jan 2015 01:01:20 -0500 Subject: [PATCH 075/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff0dd645..4e18c068 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.45.0", + "version": "0.45.1", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 072dc4ddc767a55edf7dff689426ee7a2932f8f7 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Tue, 20 Jan 2015 15:10:15 -0500 Subject: [PATCH 076/248] Updates to the CASE expression logic so that it actually works with SQL Server. --- lib/dialect/mssql.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 2bab878f..024804d7 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -113,6 +113,42 @@ Mssql.prototype.visitAlter = function(alter) { return Mssql.super_.prototype.visitAlter.call(this, alter); }; +// Need to implement a special version of CASE since SQL doesn't support +// CASE WHEN true THEN xxx END +// the "true" has to be a boolean expression like 1=1 +Mssql.prototype.visitCase = function(caseExp) { + var _this=this + + function _whenValue(node){ + if (node.type!='PARAMETER') return _this.visit(node); + // dealing with a true/false value + var val=node.value(); + if (val==true) return '1=1'; else return '0=1'; + } + + assert(caseExp.whenList.length == caseExp.thenList.length); + + var self = this; + var text = '(CASE'; + + this.visitingCase = true; + + for (var i = 0; i < caseExp.whenList.length; i++) { + var whenExp = ' WHEN ' + _whenValue(caseExp.whenList[i]); + var thenExp = ' THEN ' + this.visit(caseExp.thenList[i]); + text += whenExp + thenExp; + } + + if (null != caseExp.else && undefined != caseExp.else) { + text += ' ELSE ' + this.visit(caseExp.else); + } + + this.visitingCase = false; + + text += ' END)'; + return [text]; +} + Mssql.prototype.visitColumn = function(columnNode) { var self=this; var table; From c14a8691f1f9eacdaa82210171177ff2e2562025 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Tue, 20 Jan 2015 15:19:59 -0500 Subject: [PATCH 077/248] Updated case-tests to test the syntax required by Microsoft SQL Server. --- test/dialects/case-tests.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/test/dialects/case-tests.js b/test/dialects/case-tests.js index f1e08411..f07bb0a7 100644 --- a/test/dialects/case-tests.js +++ b/test/dialects/case-tests.js @@ -19,8 +19,9 @@ Harness.test({ string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM `customer`' }, mssql: { - text : 'SELECT (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE @5 END) FROM [customer]', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM [customer]' + text : 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END) FROM [customer]', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM [customer]', + params: [0, 1, 2] }, params: [true, 0, false, 1, 2] }); @@ -41,8 +42,9 @@ Harness.test({ string: 'SELECT (`customer`.`age` + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM `customer`' }, mssql: { - text : 'SELECT ([customer].[age] + (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE @5 END)) FROM [customer]', - string: 'SELECT ([customer].[age] + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM [customer]' + text : 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END)) FROM [customer]', + string: 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM [customer]', + params: [0, 1, 2] }, params: [true, 0, false, 1, 2] }); @@ -63,8 +65,9 @@ Harness.test({ string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM `customer`' }, mssql: { - text : 'SELECT ((CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE @5 END) + @6) FROM [customer]', - string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM [customer]' + text : 'SELECT ((CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE @3 END) + @4) FROM [customer]', + string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM [customer]', + params: [0, 1, 2, 3] }, params: [true, 0, false, 1, 2, 3] }); @@ -85,8 +88,9 @@ Harness.test({ string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE (`customer`.`age` BETWEEN 10 AND 20) END) FROM `customer`' }, mssql: { - text : 'SELECT (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 ELSE ([customer].[age] BETWEEN @5 AND @6) END) FROM [customer]', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ([customer].[age] BETWEEN 10 AND 20) END) FROM [customer]' + text : 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 ELSE ([customer].[age] BETWEEN @3 AND @4) END) FROM [customer]', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ([customer].[age] BETWEEN 10 AND 20) END) FROM [customer]', + params: [0, 1, 10, 20] }, params: [true, 0, false, 1, 10, 20] }); @@ -107,8 +111,9 @@ Harness.test({ string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM `customer`' }, mssql: { - text : 'SELECT (CASE WHEN @1 THEN @2 WHEN @3 THEN @4 END) FROM [customer]', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM [customer]' + text : 'SELECT (CASE WHEN 1=1 THEN @1 WHEN 0=1 THEN @2 END) FROM [customer]', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM [customer]', + params: [0, 1] }, params: [true, 0, false, 1] }); From 28b1ca349316c8d56a525950997c3d41d4ba377b Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 21 Jan 2015 10:20:33 -0500 Subject: [PATCH 078/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4e18c068..cd08c0bf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.45.1", + "version": "0.45.2", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From b23ac3ee0d516c34e7be18cd2ae8bc3563f18d2a Mon Sep 17 00:00:00 2001 From: Jean-Felix Girard Date: Wed, 28 Jan 2015 13:38:32 -0500 Subject: [PATCH 079/248] add match operator for text search --- lib/dialect/mssql.js | 8 +++++++ lib/dialect/mysql.js | 11 +++++++++ lib/dialect/sqlite.js | 10 ++++++++ lib/functions.js | 5 +++- lib/node/valueExpression.js | 1 + test/binary-clause-tests.js | 1 + test/dialects/matches-test.js | 45 +++++++++++++++++++++++++++++++++++ 7 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/dialects/matches-test.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 024804d7..1b02af2d 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -26,6 +26,14 @@ Mssql.prototype._getParameterPlaceholder = function(index, value) { }; Mssql.prototype.visitBinary = function(binary) { + if(binary.operator === '@@'){ + var self = this; + var text = '(CONTAINS (' + this.visit(binary.left) + ', '; + text += this.visit(binary.right); + text += '))'; + return [text]; + } + if (!isRightSideArray(binary)){ return Mssql.super_.prototype.visitBinary.call(this, binary); } diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index f8d31890..0cc24fb2 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -76,4 +76,15 @@ Mysql.prototype.visitIndexes = function(node) { return "SHOW INDEX FROM " + tableName; }; +Mysql.prototype.visitBinary = function(binary) { + if (binary.operator === '@@') { + var self = this; + var text = '(MATCH ' + this.visit(binary.left) + ' AGAINST '; + text += this.visit(binary.right); + text += ')'; + return [text]; + } + return Mysql.super_.prototype.visitBinary.call(this, binary); +} + module.exports = Mysql; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 33dedc89..63da1354 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -70,4 +70,14 @@ Sqlite.prototype.visitRestrict = function() { throw new Error('Sqlite do not support RESTRICT in DROP TABLE'); }; +Sqlite.prototype.visitBinary = function(binary) { + if(binary.operator === '@@'){ + binary.operator = 'MATCH'; + var ret = Sqlite.super_.prototype.visitBinary.call(this, binary); + binary.operator = '@@'; + return ret; + } + return Sqlite.super_.prototype.visitBinary.call(this, binary); +} + module.exports = Sqlite; diff --git a/lib/functions.js b/lib/functions.js index 8186161a..199325f8 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -50,7 +50,10 @@ var scalarFunctions = [ // hstore function available to Postgres var hstoreFunction = 'HSTORE'; -var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction); +//text search functions available to Postgres +var textsearchFunctions = ['TS_RANK','TS_RANK_CD', 'PLAINTO_TSQUERY', 'TO_TSQUERY', 'TO_TSVECTOR', 'SETWEIGHT']; + +var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction).concat(textsearchFunctions); // creates a hash of standard functions for a sql instance var getStandardFunctions = function(sql) { diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 169fb89f..876872cd 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -150,6 +150,7 @@ var ValueExpressionMixin = function() { notLike : binaryMethod('NOT LIKE'), ilike : binaryMethod('ILIKE'), notIlike : binaryMethod('NOT ILIKE'), + match : binaryMethod('@@'), in : inMethod, notIn : notInMethod, between : ternaryMethod('BETWEEN', 'AND'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index db36c139..f4affdc6 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -38,4 +38,5 @@ test('operators', function() { assert.equal(Foo.baz.rlike(1).operator, 'RLIKE'); assert.equal(Foo.baz.ilike('asdf').operator, 'ILIKE'); assert.equal(Foo.baz.notIlike('asdf').operator, 'NOT ILIKE'); + assert.equal(Foo.baz.match('asdf').operator, '@@'); }); diff --git a/test/dialects/matches-test.js b/test/dialects/matches-test.js new file mode 100644 index 00000000..4ce21406 --- /dev/null +++ b/test/dialects/matches-test.js @@ -0,0 +1,45 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); +var customerAlias = Harness.defineCustomerAliasTable(); +var sql = require(__dirname + '/../../lib').setDialect('postgres'); + +//Postgres needs the to_tsquery function to use with @@ operator +Harness.test({ + query: post.select(post.star()).where(post.content.match(sql.functions.TO_TSQUERY('hello'))), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."content" @@ TO_TSQUERY($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."content" @@ TO_TSQUERY(\'hello\'))' + }, + params: ['hello'] +}); + + +Harness.test({ + query: post.select(post.star()).where(post.content.match('hello')), + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."content" MATCH $1)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."content" MATCH \'hello\')' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (MATCH `post`.`content` AGAINST ?)', + string: 'SELECT `post`.* FROM `post` WHERE (MATCH `post`.`content` AGAINST \'hello\')' + }, + mssql: { + text : 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], @1))', + string: 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], \'hello\'))' + }, + params: ['hello'] +}); + +//matches, ordered by best rank first +Harness.test({ + query: post.select(post.id, sql.functions.TS_RANK_CD(post.content, sql.functions.TO_TSQUERY('hello')).as('rank')). + where(post.content.match(sql.functions.TO_TSQUERY('hello'))).order(sql.functions.TS_RANK_CD(post.content, sql.functions.TO_TSQUERY('hello')).descending()), + pg: { + text : 'SELECT "post"."id", TS_RANK_CD("post"."content", TO_TSQUERY($1)) AS "rank" FROM "post" WHERE ("post"."content" @@ TO_TSQUERY($2)) ORDER BY TS_RANK_CD("post"."content", TO_TSQUERY($3)) DESC', + string: 'SELECT "post"."id", TS_RANK_CD("post"."content", TO_TSQUERY(\'hello\')) AS "rank" FROM "post" WHERE ("post"."content" @@ TO_TSQUERY(\'hello\')) ORDER BY TS_RANK_CD("post"."content", TO_TSQUERY(\'hello\')) DESC' + }, + params: ['hello','hello','hello'] +}); From 02adb9d3e77d1b069ce8feb7c0657892c22db1c8 Mon Sep 17 00:00:00 2001 From: soliton4 Date: Thu, 5 Feb 2015 22:59:52 +0100 Subject: [PATCH 080/248] fixes drop index statement for pg --- lib/dialect/postgres.js | 4 +--- test/dialects/indexes-tests.js | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 3c9ff184..3d50a7af 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -877,9 +877,7 @@ Postgres.prototype.visitCreateIndex = function(node) { Postgres.prototype.visitDropIndex = function(node) { var result = [ 'DROP INDEX' ]; - result.push(this.quote(node.options.indexName)); - result.push("ON"); - result.push(this.visit(node.table.toNode())); + result.push(this.quote(node.table.getSchema() || "public") + "." + this.quote(node.options.indexName)); return result; }; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 482e0d6d..9ea75ef8 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -124,16 +124,16 @@ Harness.test({ Harness.test({ query: post.indexes().drop('index_name'), pg: { - text : 'DROP INDEX "index_name" ON "post"', - string: 'DROP INDEX "index_name" ON "post"' + text : 'DROP INDEX "public"."index_name"', + string: 'DROP INDEX "public"."index_name"' }, mysql: { - text : 'DROP INDEX `index_name` ON `post`', - string: 'DROP INDEX `index_name` ON `post`' + text : 'DROP INDEX "public"."index_name"', + string: 'DROP INDEX "public"."index_name"' }, sqlite: { - text : 'DROP INDEX "index_name" ON "post"', - string: 'DROP INDEX "index_name" ON "post"' + text : 'DROP INDEX "public"."index_name"', + string: 'DROP INDEX "public"."index_name"' }, params: [] }); @@ -141,16 +141,16 @@ Harness.test({ Harness.test({ query: post.indexes().drop(post.userId, post.id), pg: { - text : 'DROP INDEX "post_id_userId" ON "post"', - string: 'DROP INDEX "post_id_userId" ON "post"' + text : 'DROP INDEX "public"."post_id_userId"', + string: 'DROP INDEX "public"."post_id_userId"' }, mysql: { - text : 'DROP INDEX `post_id_userId` ON `post`', - string: 'DROP INDEX `post_id_userId` ON `post`' + text : 'DROP INDEX "public"."post_id_userId"', + string: 'DROP INDEX "public"."post_id_userId"' }, sqlite: { - text : 'DROP INDEX "post_id_userId" ON "post"', - string: 'DROP INDEX "post_id_userId" ON "post"' + text : 'DROP INDEX "public"."post_id_userId"', + string: 'DROP INDEX "public"."post_id_userId"' }, params: [] }); From 4e77f319dbcdb7b53378fdb52ab4d221aeb6ff3c Mon Sep 17 00:00:00 2001 From: soliton4 Date: Sun, 22 Feb 2015 01:18:17 +0100 Subject: [PATCH 081/248] changed " to ` for mysql --- test/dialects/indexes-tests.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 9ea75ef8..b950e832 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -128,8 +128,8 @@ Harness.test({ string: 'DROP INDEX "public"."index_name"' }, mysql: { - text : 'DROP INDEX "public"."index_name"', - string: 'DROP INDEX "public"."index_name"' + text : 'DROP INDEX `public`.`index_name`', + string: 'DROP INDEX `public`.`index_name`' }, sqlite: { text : 'DROP INDEX "public"."index_name"', @@ -145,8 +145,8 @@ Harness.test({ string: 'DROP INDEX "public"."post_id_userId"' }, mysql: { - text : 'DROP INDEX "public"."post_id_userId"', - string: 'DROP INDEX "public"."post_id_userId"' + text : 'DROP INDEX `public`.`post_id_userId`', + string: 'DROP INDEX `public`.`post_id_userId`' }, sqlite: { text : 'DROP INDEX "public"."post_id_userId"', From df67681542027756f7d3394ff24c609a7891fec6 Mon Sep 17 00:00:00 2001 From: Luis Lebolo Date: Mon, 23 Feb 2015 17:15:05 -0500 Subject: [PATCH 082/248] Fix a bug that added all columns as composite primary keys (instead of just those with `primaryKey: true`). --- lib/dialect/postgres.js | 7 ++++--- test/dialects/create-table-tests.js | 13 +++++++------ test/dialects/support.js | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 3c9ff184..a698030f 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -250,13 +250,14 @@ Postgres.prototype.visitCreate = function(create) { var result = ['CREATE TABLE']; result = result.concat(create.nodes.map(this.visit.bind(this))); result.push(this.visit(table.toNode())); - this._visitCreateCompoundPrimaryKey = col_nodes.filter(function(n) { + var primary_col_nodes = col_nodes.filter(function(n) { return n.primaryKey; - }).length > 1; + }); + this._visitCreateCompoundPrimaryKey = primary_col_nodes.length > 1; var colspec = '(' + col_nodes.map(this.visit.bind(this)).join(', '); if (this._visitCreateCompoundPrimaryKey) { colspec += ', PRIMARY KEY ('; - colspec += col_nodes.map(function(node) { + colspec += primary_col_nodes.map(function(node) { return this.quote(node.name); }.bind(this)).join(', '); colspec += ')'; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index c1b07e53..9993a2fa 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -304,18 +304,19 @@ Harness.test({ columns: { group_id: { dataType: 'int', primaryKey: true}, user_id: { dataType: 'int', primaryKey: true}, + desc: { dataType: 'varchar'} } }).create(), pg: { - text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', - string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', + text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', + string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', }, sqlite: { - text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', - string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, PRIMARY KEY ("group_id", "user_id"))', + text : 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', + string: 'CREATE TABLE "membership" ("group_id" int, "user_id" int, "desc" varchar, PRIMARY KEY ("group_id", "user_id"))', }, mysql: { - text : 'CREATE TABLE `membership` (`group_id` int, `user_id` int, PRIMARY KEY (`group_id`, `user_id`))', - string: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, PRIMARY KEY (`group_id`, `user_id`))', + text : 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))', + string: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))', } }); diff --git a/test/dialects/support.js b/test/dialects/support.js index 0cf264c8..e985a2da 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -34,7 +34,7 @@ module.exports = { // test result is correct var expectedText = expectedObject.text || expectedObject; - assert.equal(compiledQuery.text, expectedText, 'query result'); + assert.equal(compiledQuery.text, expectedText); // if params are specified then test these are correct var expectedParams = expectedObject.params || expected.params; From 4f77faaec555e51387c1a32bc5a3b9d2bdb6f985 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 23 Feb 2015 18:22:58 -0500 Subject: [PATCH 083/248] Trying to get the tests to run cross-platform with the usual "npm test" --- package.json | 2 +- runtests.js | 15 +++++++++++++++ test/mocha.opts | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 runtests.js diff --git a/package.json b/package.json index cd08c0bf..d40cc6b6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "main": "lib/", "scripts": { - "test": "NODE_ENV=test ./node_modules/.bin/mocha" + "test": "node ./runtests" }, "engines": { "node": "*" diff --git a/runtests.js b/runtests.js new file mode 100644 index 00000000..15e4573e --- /dev/null +++ b/runtests.js @@ -0,0 +1,15 @@ +var childProcess = require("child_process") +var path = require("path") + +var env = process.env +env.NODE_ENV = "test" + +var options={ + env:env, + stdio:"inherit" +} + +var command = path.join(".","node_modules",".bin","mocha") +try { +childProcess.execSync(command,options) +}catch(ex){} diff --git a/test/mocha.opts b/test/mocha.opts index 5efaf24d..850a6c2f 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1 +1,2 @@ +--reporter dot --ui tdd From bfc76889e97abb487086a88522df70f56b1624b0 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 23 Feb 2015 18:25:11 -0500 Subject: [PATCH 084/248] Formatting --- runtests.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtests.js b/runtests.js index 15e4573e..63d878f0 100644 --- a/runtests.js +++ b/runtests.js @@ -10,6 +10,7 @@ var options={ } var command = path.join(".","node_modules",".bin","mocha") + try { -childProcess.execSync(command,options) + childProcess.execSync(command,options) }catch(ex){} From 63ccaa4e14a96cbf4d2b38ce8e304f4e86781966 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 25 Feb 2015 07:11:07 -0400 Subject: [PATCH 085/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cd08c0bf..13991338 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.45.2", + "version": "0.45.3", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From d0c2a251a7146af6c01d9815c6a516c79a2a2ec9 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 25 Feb 2015 09:47:04 -0400 Subject: [PATCH 086/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13991338..8e54f3c5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.45.3", + "version": "0.46.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From c34cf576d3014ce0222b7c0840281d02cc5c95d1 Mon Sep 17 00:00:00 2001 From: Luis Lebolo Date: Wed, 25 Feb 2015 10:11:44 -0500 Subject: [PATCH 087/248] Minor bug fix to assert existence of columnNode.references.column (previously checked for columnNode.references.table twice) --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a698030f..ecaabe34 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -718,7 +718,7 @@ Postgres.prototype.visitColumn = function(columnNode) { columnNode.name + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + ' require a table and column)'); - assert(columnNode.references.table, 'reference.column missing for column ' + + assert(columnNode.references.column, 'reference.column missing for column ' + columnNode.name + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + ' require a table and column)'); From 70d74318a70fb0496c7f44bf35630b1fecb9e9c5 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Wed, 25 Feb 2015 21:30:28 -0500 Subject: [PATCH 088/248] - Use the spawn method in the script so that it will still work on version of node older than 0.12. --- runtests.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/runtests.js b/runtests.js index 63d878f0..6681858e 100644 --- a/runtests.js +++ b/runtests.js @@ -4,13 +4,13 @@ var path = require("path") var env = process.env env.NODE_ENV = "test" -var options={ - env:env, - stdio:"inherit" +var options = { + env: env, + stdio: "inherit", } -var command = path.join(".","node_modules",".bin","mocha") - +var command = path.join(".", "node_modules", ".bin", "mocha") +if (process.platform == "win32") command += ".cmd" try { - childProcess.execSync(command,options) -}catch(ex){} + childProcess.spawn(command, options) +} catch (ex) {} From 722c536a135c631608cb48afbd56fc656ae9fa37 Mon Sep 17 00:00:00 2001 From: brianc Date: Thu, 26 Feb 2015 08:44:06 -0500 Subject: [PATCH 089/248] Fix up test runner for windows --- runtests.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/runtests.js b/runtests.js index 6681858e..8b722efe 100644 --- a/runtests.js +++ b/runtests.js @@ -5,12 +5,14 @@ var env = process.env env.NODE_ENV = "test" var options = { - env: env, - stdio: "inherit", + env: env } var command = path.join(".", "node_modules", ".bin", "mocha") if (process.platform == "win32") command += ".cmd" -try { - childProcess.spawn(command, options) -} catch (ex) {} +var run = childProcess.spawn(command, [], options) +run.stdout.pipe(process.stdout) +run.stderr.pipe(process.stderr) +run.on('close', function(code) { + process.exit(code) +}) From c62f481e5279f619631367181720eb7dd0fe95a8 Mon Sep 17 00:00:00 2001 From: brianc Date: Thu, 26 Feb 2015 08:44:12 -0500 Subject: [PATCH 090/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f1e6cd9e..d7bcc7d7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.46.0", + "version": "0.47.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From de351c46f8267c14d9427dae8ce67bc4a3ff8cdc Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 28 Feb 2015 14:25:03 -0500 Subject: [PATCH 091/248] Added insert-tests for Microsoft SQL Server. Right now we are throwing an exception for the RETURNING statement since it's not implemented in MS SQL the same way as PostgreSQL. --- lib/dialect/mssql.js | 6 ++++ test/dialects/insert-tests.js | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 1b02af2d..2b7bc0a7 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -354,6 +354,12 @@ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ // return "SHOW INDEX FROM " + tableName; //}; +Mssql.prototype.visitReturning = function() { + // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause + // in MS SQL which appears before the values, not at the end of the statement. + throw new Error('Returning clause is not yet supported for MS SQL.'); +}; + // We deal with SELECT specially so we can add the TOP clause if needed Mssql.prototype.visitSelect = function(select) { if (!select.msSQLLimitNode) return Mssql.super_.prototype.visitSelect.call(this, select); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 86b32040..d7aee20d 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -147,6 +147,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' }, + mssql: { + text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, @4)', + string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'whoah\', 1), (\'hey\', 2)' + }, params: ['whoah', 1, 'hey', 2] }); @@ -164,6 +168,10 @@ Harness.test({ text : 'INSERT INTO `post` () VALUES ()', string: 'INSERT INTO `post` () VALUES ()' }, + mssql: { + text : 'INSERT INTO [post] DEFAULT VALUES', + string: 'INSERT INTO [post] DEFAULT VALUES' + }, params: [] }); @@ -179,6 +187,9 @@ Harness.test({ mysql: { throws: true }, + mssql: { + throws: true + }, params: [] }); @@ -194,6 +205,9 @@ Harness.test({ mysql: { throws: true }, + mssql: { + throws: true + }, params: [] }); @@ -209,6 +223,9 @@ Harness.test({ mysql: { throws: true }, + mssql: { + throws: true + }, params: [] }); @@ -224,6 +241,9 @@ Harness.test({ mysql: { throws: true }, + mssql: { + throws: true + }, params: [] }); @@ -239,6 +259,9 @@ Harness.test({ mysql: { throws: true }, + mssql: { + throws: true + }, params: [] }); @@ -264,6 +287,11 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', params: ['whoah', 1, 'hey'] + }, + mssql: { + text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, DEFAULT)', + string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', + params: ['whoah', 1, 'hey'] } }); @@ -288,6 +316,11 @@ Harness.test({ text : 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', string: 'INSERT INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, \'hey\')', params: [1, 2, 'hey'] + }, + mssql: { + text : 'INSERT INTO [post] ([userId], [content]) VALUES (@1, DEFAULT), (@2, @3)', + string: 'INSERT INTO [post] ([userId], [content]) VALUES (1, DEFAULT), (2, \'hey\')', + params: [1, 2, 'hey'] } }); @@ -306,6 +339,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE ?)', string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE \'A%\')' }, + mssql: { + text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE @1)', + string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE \'A%\')' + }, params: ['A%'] }); @@ -324,6 +361,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE ?)', string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE \'A%\')' }, + mssql: { + text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE @1)', + string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE \'A%\')' + }, params: ['A%'] }); @@ -342,6 +383,10 @@ Harness.test({ text : 'INSERT INTO `post` (`userId`) SELECT `id` FROM `user` WHERE (`name` LIKE ?)', string: 'INSERT INTO `post` (`userId`) SELECT `id` FROM `user` WHERE (`name` LIKE \'A%\')' }, + mssql: { + text : 'INSERT INTO [post] ([userId]) SELECT [id] FROM [user] WHERE ([name] LIKE @1)', + string: 'INSERT INTO [post] ([userId]) SELECT [id] FROM [user] WHERE ([name] LIKE \'A%\')' + }, params: ['A%'] }); @@ -360,6 +405,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' }, + mssql: { + text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', + string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'\\x74657374\', 2)' + }, params: [new Buffer('test'), 2] }); @@ -380,6 +429,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' }, + mssql: { + text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', + string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'\\x74657374\', 2)' + }, params: [new Buffer('test'), 2] }); @@ -403,8 +456,13 @@ Harness.test({ text : 'INSERT INTO `post` (`content`) VALUES (?), (?)', string: 'INSERT INTO `post` (`content`) VALUES (x\'77686f6168\'), (x\'686579\')' }, + mssql: { + text : 'INSERT INTO [post] ([content]) VALUES (@1), (@2)', + string: 'INSERT INTO [post] ([content]) VALUES (\'\\x77686f6168\'), (\'\\x686579\')' + }, params: [new Buffer('whoah'), new Buffer('hey')] }); + Harness.test({ query: post.insert([]), From 63e3cbb349832fab73c2a55c6f2342dd797fde00 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 28 Feb 2015 15:53:03 -0500 Subject: [PATCH 092/248] Support for temporary tables. --- lib/dialect/mssql.js | 9 ++++- lib/dialect/postgres.js | 3 +- lib/node/create.js | 9 ++++- lib/node/query.js | 2 +- lib/table.js | 2 + test/dialects/create-table-tests.js | 61 +++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 1b02af2d..534a4b2c 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -185,7 +185,9 @@ Mssql.prototype.visitColumn = function(columnNode) { Mssql.prototype.visitCreate = function(create) { - if (!isCreateIfNotExists(create)) { + var isNotExists=isCreateIfNotExists(create) + var isTemporary=isCreateTemporary(create) + if (!isNotExists && !isTemporary) { return Mssql.super_.prototype.visitCreate.call(this, create); } // Implement our own create if not exists: @@ -209,6 +211,7 @@ Mssql.prototype.visitCreate = function(create) { // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} // Add some tests for this as well + if (!isNotExists) return createResult return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; }; @@ -408,6 +411,10 @@ function isCreateIfNotExists(create){ return true; }; +function isCreateTemporary(create){ + return create.options.isTemporary +}; + function isDropIfExists(drop){ if (drop.nodes.length==0) return false; if (drop.nodes[0].type!='IF EXISTS') return false; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a698030f..f57b7441 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -247,7 +247,8 @@ Postgres.prototype.visitCreate = function(create) { var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); - var result = ['CREATE TABLE']; + var result = ['CREATE TABLE']; + if (create.options.isTemporary) result=['CREATE TEMPORARY TABLE'] result = result.concat(create.nodes.map(this.visit.bind(this))); result.push(this.visit(table.toNode())); var primary_col_nodes = col_nodes.filter(function(n) { diff --git a/lib/node/create.js b/lib/node/create.js index bf535f6a..c048c3ce 100644 --- a/lib/node/create.js +++ b/lib/node/create.js @@ -3,5 +3,12 @@ var Node = require(__dirname); module.exports = Node.define({ - type: 'CREATE' + type: 'CREATE', + + constructor: function(isTemporary) { + Node.call(this); + + this.options = { isTemporary: isTemporary}; + }, + }); diff --git a/lib/node/query.js b/lib/node/query.js index 255332fd..fe91c98d 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -276,7 +276,7 @@ var Query = Node.define({ this.add(createIndex); return createIndex; } else { - return this.add(new Create()); + return this.add(new Create(this.table.isTemporary)); } }, diff --git a/lib/table.js b/lib/table.js index 5763ecf7..2ed1d6be 100644 --- a/lib/table.js +++ b/lib/table.js @@ -15,6 +15,7 @@ var Table = function(config) { this._name = config.name; this._initialConfig = config; this.columnWhiteList = !!config.columnWhiteList; + this.isTemporary=!!config.isTemporary this.snakeToCamel = !!config.snakeToCamel; this.columns = []; this.table = this; @@ -130,6 +131,7 @@ Table.prototype.setSchema = function(schema) { }; Table.prototype.getName = function() { + if (this.sql && this.sql.dialectName=="mssql" && this.isTemporary) return "#"+this._name; return this._name; }; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 9993a2fa..33ba0f8d 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -320,3 +320,64 @@ Harness.test({ string: 'CREATE TABLE `membership` (`group_id` int, `user_id` int, `desc` varchar, PRIMARY KEY (`group_id`, `user_id`))', } }); + +// TEMPORARY TABLE TESTS + +// This tests explicitly setting the isTemporary flag to false, as opposed to all the test above here which have it +// as undefined. +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'id', + dataType: 'int' + }], + isTemporary:false + }).create(), + pg: { + text : 'CREATE TABLE "post" ("id" int)', + string: 'CREATE TABLE "post" ("id" int)' + }, + sqlite: { + text : 'CREATE TABLE "post" ("id" int)', + string: 'CREATE TABLE "post" ("id" int)' + }, + mysql: { + text : 'CREATE TABLE `post` (`id` int)', + string: 'CREATE TABLE `post` (`id` int)' + }, + mssql: { + text : 'CREATE TABLE [post] ([id] int)', + string: 'CREATE TABLE [post] ([id] int)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'id', + dataType: 'int' + }], + isTemporary:true + }).create(), + pg: { + text : 'CREATE TEMPORARY TABLE "post" ("id" int)', + string: 'CREATE TEMPORARY TABLE "post" ("id" int)' + }, + sqlite: { + text : 'CREATE TEMPORARY TABLE "post" ("id" int)', + string: 'CREATE TEMPORARY TABLE "post" ("id" int)' + }, + mysql: { + text : 'CREATE TEMPORARY TABLE `post` (`id` int)', + string: 'CREATE TEMPORARY TABLE `post` (`id` int)' + }, + //mssql: { + // text : 'CREATE TABLE [#post] ([id] int)', + // string: 'CREATE TABLE [#post] ([id] int)' + //}, + params: [] +}); + From 08152c75824d4c8dee05c93770399885b7c64980 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Mar 2015 22:38:06 -0500 Subject: [PATCH 093/248] - Fixes an issue with INSERT statements using a SELECT for the values where the columns in the SELECT statement were not being qualified. --- lib/dialect/postgres.js | 4 +++- test/column-tests.js | 2 +- test/dialects/ilike-tests.js | 12 ++++++------ test/dialects/insert-tests.js | 36 +++++++++++++++++------------------ 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a698030f..b6ad0d96 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -210,6 +210,8 @@ Postgres.prototype.visitInsert = function(insert) { } } + this._visitedInsert = false; + return result; }; @@ -650,7 +652,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push('DISTINCT('); } } - if(!inInsertUpdateClause && !this._visitingCreate && !this._visitingAlter) { + if(!inInsertUpdateClause && !this.visitingReturning && !this._visitingCreate && !this._visitingAlter) { if(table.alias) { txt.push(this.quote(table.alias)); } else { diff --git a/test/column-tests.js b/test/column-tests.js index f8b47d12..9bcc15ac 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -120,7 +120,7 @@ describe('column', function() { }); it('respects AS rename in RETURNING clause', function() { assert.equal(table.update({makeMeCamel:0}).returning(table.makeMeCamel.as('rename')).toQuery().text, - 'UPDATE "sc" SET "make_me_camel" = $1 RETURNING "sc"."make_me_camel" AS "rename"'); + 'UPDATE "sc" SET "make_me_camel" = $1 RETURNING "make_me_camel" AS "rename"'); }); }); }); diff --git a/test/dialects/ilike-tests.js b/test/dialects/ilike-tests.js index e0014f77..aba487ee 100644 --- a/test/dialects/ilike-tests.js +++ b/test/dialects/ilike-tests.js @@ -18,8 +18,8 @@ Harness.test({ query: post.insert(post.content, post.userId) .select('\'test\'', user.id).from(user).where(user.name.ilike('A%')), pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE \'A%\')' + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' }, params: ['A%'] }); @@ -28,8 +28,8 @@ Harness.test({ query: post.insert([post.content, post.userId]) .select('\'test\'', user.id).from(user).where(user.name.ilike('A%')), pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" ILIKE \'A%\')' + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' }, params: ['A%'] }); @@ -38,8 +38,8 @@ Harness.test({ query: post.insert(post.userId) .select(user.id).from(user).where(user.name.ilike('A%')), pg: { - text : 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" ILIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" ILIKE \'A%\')' + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" ILIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" ILIKE \'A%\')' }, params: ['A%'] }); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 86b32040..7471cc99 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -295,16 +295,16 @@ Harness.test({ query: post.insert(post.content, post.userId) .select('\'test\'', user.id).from(user).where(user.name.like('A%')), pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE \'A%\')' + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' }, sqlite: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE \'A%\')' + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' }, mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE ?)', - string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE \'A%\')' + text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', + string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' }, params: ['A%'] }); @@ -313,16 +313,16 @@ Harness.test({ query: post.insert([post.content, post.userId]) .select('\'test\'', user.id).from(user).where(user.name.like('A%')), pg: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE \'A%\')' + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' }, sqlite: { - text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE $1)', - string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "id" FROM "user" WHERE ("name" LIKE \'A%\')' + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' }, mysql: { - text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE ?)', - string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `id` FROM `user` WHERE (`name` LIKE \'A%\')' + text : 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', + string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' }, params: ['A%'] }); @@ -331,16 +331,16 @@ Harness.test({ query: post.insert(post.userId) .select(user.id).from(user).where(user.name.like('A%')), pg: { - text : 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" LIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" LIKE \'A%\')' + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' }, sqlite: { - text : 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" LIKE $1)', - string: 'INSERT INTO "post" ("userId") SELECT "id" FROM "user" WHERE ("name" LIKE \'A%\')' + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' }, mysql: { - text : 'INSERT INTO `post` (`userId`) SELECT `id` FROM `user` WHERE (`name` LIKE ?)', - string: 'INSERT INTO `post` (`userId`) SELECT `id` FROM `user` WHERE (`name` LIKE \'A%\')' + text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' }, params: ['A%'] }); From a10743d5a2d13466fe02828075d3cf6520b771cf Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Mar 2015 23:06:50 -0500 Subject: [PATCH 094/248] - Added a test case to better illustrate and test what this pull request is trying to accomplish. --- test/dialects/insert-tests.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 7471cc99..f9fc601b 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -345,6 +345,24 @@ Harness.test({ params: ['A%'] }); +Harness.test({ + query: post.insert(post.userId) + .select(post.userId).from(user.join(post).on(user.id.equals(post.userId))).where(post.tags.like('A%')), + pg: { + text : 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + sqlite: { + text : 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', + string: 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + mysql: { + text : 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE ?)', + string: 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE \'A%\')' + }, + params: ['A%'] +}); + // Binary inserts Harness.test({ query: post.insert(post.content.value(new Buffer('test')), post.userId.value(2)), From 2763a670ba0c92fd88a38de5a50b132f67fb81cf Mon Sep 17 00:00:00 2001 From: Bill Li Date: Tue, 3 Mar 2015 13:20:29 -0500 Subject: [PATCH 095/248] Fixed a bug --- lib/functions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/functions.js b/lib/functions.js index 199325f8..084eaa4c 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -35,7 +35,7 @@ var aggregateFunctions = [ // common scalar functions available to most databases var scalarFunctions = [ 'ABS', - 'COALESC', + 'COALESCE', 'LENGTH', 'LOWER', 'LTRIM', From d3f6522cdb85759fd996d74ac5423dfb6f27470e Mon Sep 17 00:00:00 2001 From: Thaddaeus Clay Date: Wed, 4 Mar 2015 14:48:58 -0500 Subject: [PATCH 096/248] Add _visitingJoin check to visitColumn. --- lib/dialect/postgres.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a698030f..4ce7c3fe 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -631,6 +631,7 @@ Postgres.prototype.visitColumn = function(columnNode) { && !inInsertUpdateClause && !inDdlClause && !this.visitingCase + && !this._visitingJoin ); var txt = []; var closeParen = 0; @@ -797,6 +798,7 @@ Postgres.prototype.visitForShare = function() { Postgres.prototype.visitJoin = function(join) { var result = []; + this._visitingJoin = true; result = result.concat(this.visit(join.from)); result = result.concat(join.subType + ' JOIN'); result = result.concat(this.visit(join.to)); From 0bbe3619af5b3be4c8a18cbb5f7dd951104cb140 Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 6 Mar 2015 10:39:02 -0700 Subject: [PATCH 097/248] Start fixing 216 tests --- test/dialects/insert-tests.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 8f8ceb41..c927f2f6 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -340,8 +340,8 @@ Harness.test({ string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' }, mssql: { - text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE @1)', - string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE \'A%\')' + text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)', + string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE \'A%\')' }, params: ['A%'] }); @@ -362,8 +362,8 @@ Harness.test({ string: 'INSERT INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' }, mssql: { - text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE @1)', - string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [id] FROM [user] WHERE ([name] LIKE \'A%\')' + text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)', + string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE \'A%\')' }, params: ['A%'] }); @@ -402,8 +402,8 @@ Harness.test({ string: 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE \'A%\')' }, mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [id] FROM [user] WHERE ([name] LIKE @1)', - string: 'INSERT INTO [post] ([userId]) SELECT [id] FROM [user] WHERE ([name] LIKE \'A%\')' + text : 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] WHERE ([user].[name] LIKE @1)', + string: 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] WHERE ([user].[name] LIKE \'A%\')' }, params: ['A%'] }); @@ -489,4 +489,4 @@ Harness.test({ string: 'SELECT `post`.* FROM `post` WHERE (1=2)' }, params: [] -}); \ No newline at end of file +}); From b39346355d410f73692b16f385f3e8fb3e19b05c Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Fri, 6 Mar 2015 14:05:35 -0500 Subject: [PATCH 098/248] Fixed failing insert-test for or mssql. --- test/dialects/insert-tests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index c927f2f6..f9ef0efb 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -402,8 +402,8 @@ Harness.test({ string: 'INSERT INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE \'A%\')' }, mssql: { - text : 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] WHERE ([user].[name] LIKE @1)', - string: 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] WHERE ([user].[name] LIKE \'A%\')' + text : 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE @1)', + string: 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE \'A%\')' }, params: ['A%'] }); From 2987e139c8ded57e686aa772475d56cfdca1c086 Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 10 Mar 2015 12:11:34 -0400 Subject: [PATCH 099/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7bcc7d7..76f388b9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.47.0", + "version": "0.48.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 5566e04b046e83d3d8d05bd920d836554ae38ebe Mon Sep 17 00:00:00 2001 From: Dorian Johnson <2014@dorianj.net> Date: Tue, 17 Mar 2015 11:16:42 -0500 Subject: [PATCH 100/248] Add support for accessing PG composite types (UDT) As per http://www.postgresql.org/docs/9.4/static/rowtypes.html#AEN7836 No attempt at supporting these in UPDATE is attempted here. --- lib/dialect/postgres.js | 5 +++- lib/node/column.js | 4 ++++ lib/table.js | 14 +++++++++++ test/dialects/subfield-tests.js | 42 +++++++++++++++++++++++++++++++++ test/dialects/support.js | 11 +++++++++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 test/dialects/subfield-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7c650507..1fd2dec2 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -654,7 +654,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push('DISTINCT('); } } - if(!inInsertUpdateClause && !this.visitingReturning && !this._visitingCreate && !this._visitingAlter) { + if(!inInsertUpdateClause && !this.visitingReturning && !this._visitingCreate && !this._visitingAlter && !columnNode.subfieldContainer) { if(table.alias) { txt.push(this.quote(table.alias)); } else { @@ -686,6 +686,9 @@ Postgres.prototype.visitColumn = function(columnNode) { } } else { + if (columnNode.subfieldContainer) { + txt.push('(' + this.visitColumn(columnNode.subfieldContainer) + ').'); + } txt.push(this.quote(columnNode.name)); } if(closeParen) { diff --git a/lib/node/column.js b/lib/node/column.js index 6234b2f2..03b58ad5 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -19,6 +19,10 @@ module.exports = Node.define({ this.primaryKey = config.primaryKey; this.notNull = config.notNull; this.references = config.references; + // If subfieldContainer is present, this is a subfield and subfieldContainer + // is the parent Column + this.subfieldContainer = config.subfieldContainer; + this.subfields = config.subfields; this.autoGenerated = !!config.autoGenerated; }, as: function(alias) { diff --git a/lib/table.js b/lib/table.js index 2ed1d6be..cafbf213 100644 --- a/lib/table.js +++ b/lib/table.js @@ -67,6 +67,20 @@ Table.prototype.createColumn = function(col) { col.table = this; col = new Column(col); + + // Load subfields from array into an object of form name: Column + if(util.isArray(col.subfields)) { + col.subfields = lodash.chain(col.subfields) + .map(lodash.bind(function (subfield) { + return [subfield, new Column({ + table: this, + subfieldContainer: col, + name: subfield + })] + }, this)) + .object() + .value() + } } return col; diff --git a/test/dialects/subfield-tests.js b/test/dialects/subfield-tests.js new file mode 100644 index 00000000..aeaab51d --- /dev/null +++ b/test/dialects/subfield-tests.js @@ -0,0 +1,42 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerCompositeTable(); +var Sql = require('../../lib').setDialect('postgres'); + +Harness.test({ + query: customer.select(customer.info.subfields.age), + pg: { + text : 'SELECT ("customer"."info")."age" FROM "customer"', + string: 'SELECT ("customer"."info")."age" FROM "customer"' + }, + params: [] +}); + + +Harness.test({ + query: customer.select(customer.info.subfields.age.as('years')), + pg: { + text : 'SELECT ("customer"."info")."age" AS "years" FROM "customer"', + string: 'SELECT ("customer"."info")."age" AS "years" FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(customer.id).where(customer.info.subfields.salary.equals(10)), + pg: { + text : 'SELECT "customer"."id" FROM "customer" WHERE (("customer"."info")."salary" = $1)', + string: 'SELECT "customer"."id" FROM "customer" WHERE (("customer"."info")."salary" = 10)' + }, + params: [10] +}); + +Harness.test({ + query: customer.select(customer.info.subfields.name.distinct()), + pg: { + text : 'SELECT DISTINCT(("customer"."info")."name") FROM "customer"', + string: 'SELECT DISTINCT(("customer"."info")."name") FROM "customer"' + }, + params: [] +}); diff --git a/test/dialects/support.js b/test/dialects/support.js index e985a2da..e95e3175 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -93,6 +93,17 @@ module.exports = { }); }, + // This table defines the customer attributes as a composite field + defineCustomerCompositeTable: function() { + return Table.define({ + name: 'customer', + columns: { + id: {}, + info: {subfields: ['name', 'age', 'salary']} + } + }); + }, + defineCustomerAliasTable: function() { return Table.define({ name: 'customer', From 9334290f62f95673297ec9022bb8981257ad33dd Mon Sep 17 00:00:00 2001 From: klaemo Date: Tue, 24 Mar 2015 11:06:26 +0100 Subject: [PATCH 101/248] readme: mention dialects --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 3a5493b8..454466bc 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ Maybe it's still not fun, but at least it's _less not fun_. //require the module var sql = require('sql'); +//(optionally) set the SQL dialect +sql.setDialect('postgres'); +//possible dialects: mssql, mysql, postgres (default), sqlite + //first we define our tables var user = sql.define({ name: 'user', From 1385c77cf94ff326d86d93afb7ee4ceafc953ea6 Mon Sep 17 00:00:00 2001 From: Dick Fickling Date: Thu, 26 Mar 2015 14:32:55 -0700 Subject: [PATCH 102/248] Add ON DUPLICATE KEY support for MySQL --- lib/dialect/mssql.js | 4 ++++ lib/dialect/mysql.js | 14 ++++++++++++++ lib/dialect/postgres.js | 5 +++++ lib/dialect/sqlite.js | 4 ++++ lib/node/onDuplicate.js | 7 +++++++ lib/node/query.js | 16 ++++++++++++++++ test/dialects/insert-tests.js | 23 +++++++++++++++++++++++ 7 files changed, 73 insertions(+) create mode 100644 lib/node/onDuplicate.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index c15d615e..056a962f 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -357,6 +357,10 @@ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ // return "SHOW INDEX FROM " + tableName; //}; +Mssql.prototype.visitOnDuplicate = function(onDuplicate) { + throw new Error('MSSQL does not allow onDuplicate clause.'); +}; + Mssql.prototype.visitReturning = function() { // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause // in MS SQL which appears before the values, not at the end of the statement. diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 0cc24fb2..fc4c6cfc 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -31,6 +31,20 @@ Mysql.prototype._getParameterValue = function(value) { return value; }; +Mysql.prototype.visitOnDuplicate = function(onDuplicate) { + var params = []; + /* jshint boss: true */ + for(var i = 0, node; node = onDuplicate.nodes[i]; i++) { + var target_col = this.visit(node); + params = params.concat(target_col + ' = ' + this.visit(node.value)); + } + var result = [ + 'ON DUPLICATE KEY UPDATE', + params.join(', ') + ]; + return result; +}; + Mysql.prototype.visitReturning = function() { throw new Error('MySQL does not allow returning clause.'); }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7c650507..893c3ff0 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -117,6 +117,7 @@ Postgres.prototype.visit = function(node) { case 'GROUP BY' : return this.visitGroupBy(node); case 'HAVING' : return this.visitHaving(node); case 'RETURNING' : return this.visitReturning(node); + case 'ONDUPLICATE' : return this.visitOnDuplicate(node); case 'FOR UPDATE' : return this.visitForUpdate(); case 'FOR SHARE' : return this.visitForShare(); case 'TABLE' : return this.visitTable(node); @@ -826,6 +827,10 @@ Postgres.prototype.visitReturning = function(returning) { return r; }; +Postgres.prototype.visitOnDuplicate = function(onDuplicate) { + throw new Error('PostgreSQL does not allow onDuplicate clause.'); +}; + Postgres.prototype.visitModifier = function(node) { return [node.type, node.count.type ? this.visit(node.count) : node.count]; }; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 63da1354..0f210390 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -38,6 +38,10 @@ Sqlite.prototype.visitRenameColumn = function() { throw new Error('SQLite does not allow renaming columns.'); }; +Sqlite.prototype.visitOnDuplicate = function() { + throw new Error('SQLite does not allow onDuplicate clause.'); +}; + Sqlite.prototype.visitReturning = function() { throw new Error('SQLite does not allow returning clause.'); }; diff --git a/lib/node/onDuplicate.js b/lib/node/onDuplicate.js new file mode 100644 index 00000000..38146793 --- /dev/null +++ b/lib/node/onDuplicate.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'ONDUPLICATE' +}); diff --git a/lib/node/query.js b/lib/node/query.js index fe91c98d..53802f90 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -15,6 +15,7 @@ var Insert = require('./insert'); var Update = require('./update'); var Delete = require('./delete'); var Returning = require('./returning'); +var OnDuplicate = require('./onDuplicate'); var ForUpdate = require('./forUpdate'); var ForShare = require('./forShare'); var Create = require('./create'); @@ -258,6 +259,21 @@ var Query = Node.define({ return this.add(returning); }, + onDuplicate: function(o) { + var self = this; + + var onDuplicate = new OnDuplicate(); + Object.keys(o).forEach(function(key) { + var col = self.table.get(key); + if(col && !col.autoGenerated) + var val = o[key]; + onDuplicate.add(col.value(ParameterNode.getNodeOrParameterNode(val))); + }); + + return self.add(onDuplicate); + }, + + forUpdate: function() { assert(typeof this._select !== 'undefined', 'FOR UPDATE can be used only in a select statement'); this.add(new ForUpdate()); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index f9ef0efb..cb18458d 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -481,6 +481,29 @@ Harness.test({ params: [new Buffer('whoah'), new Buffer('hey')] }); +Harness.test({ + query: post.insert({ + content: 'test', + userId: 2 + }).onDuplicate({ + content: 'testupdate', + }), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `post`.`content` = ?', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 2) ON DUPLICATE KEY UPDATE `post`.`content` = \'testupdate\'' + }, + mssql: { + throws: true + }, + params: ['test', 2, 'testupdate'] +}); + Harness.test({ query: post.insert([]), From e2c4c9f3c0f944e8d33d9bd5d5c1269fee909cd8 Mon Sep 17 00:00:00 2001 From: Paul King Date: Mon, 13 Apr 2015 09:42:32 -0600 Subject: [PATCH 103/248] Adding iRegex and notIRegex. --- lib/node/valueExpression.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 876872cd..6933fa11 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -138,8 +138,10 @@ var ValueExpressionMixin = function() { bitwiseOr : binaryMethod('|'), bitwiseXor : binaryMethod('#'), regex : binaryMethod('~'), + iregex : binaryMethod('~*'), regexp : binaryMethod('REGEXP'), notRegex : binaryMethod('!~'), + notIregex : binaryMethod('!~*'), concat : binaryMethod('||'), key : binaryMethod('->'), keyText : binaryMethod('->>'), From fc20418628ffd34a3627bb93b52cf4f81fca85a9 Mon Sep 17 00:00:00 2001 From: Paul King Date: Mon, 13 Apr 2015 11:31:04 -0600 Subject: [PATCH 104/248] Tests for iregex and notIregex. --- test/binary-clause-tests.js | 2 ++ test/dialects/regex-tests.js | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index f4affdc6..10c50737 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -33,7 +33,9 @@ test('operators', function() { assert.equal(Foo.baz.divide(1).operator, '/'); assert.equal(Foo.baz.modulo(1).operator, '%'); assert.equal(Foo.baz.regex(1).operator, '~'); + assert.equal(Foo.baz.iregex(1).operator, '~*'); assert.equal(Foo.baz.notRegex(1).operator, '!~'); + assert.equal(Foo.baz.notIregex(1).operator, '!~*'); assert.equal(Foo.baz.regexp(1).operator, 'REGEXP'); assert.equal(Foo.baz.rlike(1).operator, 'RLIKE'); assert.equal(Foo.baz.ilike('asdf').operator, 'ILIKE'); diff --git a/test/dialects/regex-tests.js b/test/dialects/regex-tests.js index afddce99..40dde618 100644 --- a/test/dialects/regex-tests.js +++ b/test/dialects/regex-tests.js @@ -13,6 +13,15 @@ Harness.test({ params: ['age'] }); +Harness.test({ + query: customer.select(customer.metadata.iregex('age')), + pg: { + text : 'SELECT ("customer"."metadata" ~* $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" ~* \'age\') FROM "customer"' + }, + params: ['age'] +}); + Harness.test({ query: customer.select(customer.metadata.notRegex('age')), pg: { @@ -21,3 +30,12 @@ Harness.test({ }, params: ['age'] }); + +Harness.test({ + query: customer.select(customer.metadata.notIregex('age')), + pg: { + text : 'SELECT ("customer"."metadata" !~* $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" !~* \'age\') FROM "customer"' + }, + params: ['age'] +}); From 158a09f1af22cc2a9c19d3ffe7b9dc4e4751bfb0 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 15 Apr 2015 09:37:01 -0400 Subject: [PATCH 105/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 76f388b9..8fa320c8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.48.0", + "version": "0.49.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 79a138be0fcb1ec38d2a9f33743c1652b4c4e213 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 15 Apr 2015 09:55:28 -0400 Subject: [PATCH 106/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8fa320c8..2ba0905b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.49.0", + "version": "0.50.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 2ccd60eabb4fa2af89f37cc3752dd7351b4e8844 Mon Sep 17 00:00:00 2001 From: Benjamin Diemert Date: Thu, 16 Apr 2015 18:24:55 +0200 Subject: [PATCH 107/248] Define specific constraint on references column (Postgres only) When you're defining columns in a table that references others columns in you database, you can now add a specific constraint such as "ON DELETE CASCADE". The definition will looks like : references: { table: "another_table", column: "another_table_primary_key", constraint: "ON DELETE CASCADE" } --- lib/dialect/postgres.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index cd560aac..0d4652cb 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -730,8 +730,12 @@ Postgres.prototype.visitColumn = function(columnNode) { columnNode.name + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + ' require a table and column)'); - txt.push(' REFERENCES ' + columnNode.references.table + '(' + - columnNode.references.column + ')'); + txt.push(columnNode.references.hasOwnProperty('constraint') + ? ' REFERENCES ' + columnNode.references.table + '(' + + columnNode.references.column + ') ' + columnNode.references.constraint + : ' REFERENCES ' + columnNode.references.table + '(' + + columnNode.references.column + ')' + ); } } } From 01fe04ab9fe7e00c8957f541692e80db64958cd3 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Thu, 30 Apr 2015 11:05:41 -0400 Subject: [PATCH 108/248] Added TRUNCATE TABLE command. --- lib/dialect/postgres.js | 8 ++++++++ lib/dialect/sqlite.js | 6 ++++++ lib/node/query.js | 5 +++++ lib/node/truncate.js | 12 ++++++++++++ lib/table.js | 6 ++++++ test/dialects/truncate-table-tests.js | 25 +++++++++++++++++++++++++ 6 files changed, 62 insertions(+) create mode 100644 lib/node/truncate.js create mode 100644 test/dialects/truncate-table-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index cd560aac..31b9bb3c 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -107,6 +107,7 @@ Postgres.prototype.visit = function(node) { case 'DELETE' : return this.visitDelete(node); case 'CREATE' : return this.visitCreate(node); case 'DROP' : return this.visitDrop(node); + case 'TRUNCATE' : return this.visitTruncate(node); case 'ALIAS' : return this.visitAlias(node); case 'ALTER' : return this.visitAlter(node); case 'CAST' : return this.visitCast(node); @@ -280,6 +281,12 @@ Postgres.prototype.visitDrop = function(drop) { return result; }; +Postgres.prototype.visitTruncate = function(truncate) { + var result = ['TRUNCATE TABLE']; + result = result.concat(truncate.nodes.map(this.visit.bind(this))); + return result; +}; + Postgres.prototype.visitAlias = function(alias) { var result = [this.visit(alias.value) + ' AS ' + this.quote(alias.alias)]; return result; @@ -545,6 +552,7 @@ Postgres.prototype.visitQuery = function(queryNode) { case "UPDATE": case "CREATE": case "DROP": + case "TRUNCATE": case "ALTER": actions.push(node); missingFrom = false; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 0f210390..8530159f 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -34,6 +34,12 @@ Sqlite.prototype.visitDropColumn = function() { throw new Error('SQLite does not allow dropping columns.'); }; +Sqlite.prototype.visitTruncate = function(truncate) { + var result = ['DELETE FROM']; + result = result.concat(truncate.nodes.map(this.visit.bind(this))); + return result; +}; + Sqlite.prototype.visitRenameColumn = function() { throw new Error('SQLite does not allow renaming columns.'); }; diff --git a/lib/node/query.js b/lib/node/query.js index 53802f90..40309d5a 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -20,6 +20,7 @@ var ForUpdate = require('./forUpdate'); var ForShare = require('./forShare'); var Create = require('./create'); var Drop = require('./drop'); +var Truncate = require('./truncate'); var Alter = require('./alter'); var AddColumn = require('./addColumn'); var DropColumn = require('./dropColumn'); @@ -307,6 +308,10 @@ var Query = Node.define({ } }, + truncate: function() { + return this.add(new Truncate(this.table)); + }, + alter: function() { return this.add(new Alter()); }, diff --git a/lib/node/truncate.js b/lib/node/truncate.js new file mode 100644 index 00000000..24bc168d --- /dev/null +++ b/lib/node/truncate.js @@ -0,0 +1,12 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'TRUNCATE', + + constructor: function(table) { + Node.call(this); + this.add(table); + } +}); diff --git a/lib/table.js b/lib/table.js index cafbf213..a5407c32 100644 --- a/lib/table.js +++ b/lib/table.js @@ -234,6 +234,12 @@ Table.prototype.drop = function() { return query; }; +Table.prototype.truncate = function() { + var query = new Query(this); + query.truncate.apply(query, arguments); + return query; +}; + Table.prototype.alter = function() { var query = new Query(this); query.alter.apply(query, arguments); diff --git a/test/dialects/truncate-table-tests.js b/test/dialects/truncate-table-tests.js new file mode 100644 index 00000000..a6197b9c --- /dev/null +++ b/test/dialects/truncate-table-tests.js @@ -0,0 +1,25 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); + +Harness.test({ + query: post.truncate(), + pg: { + text : 'TRUNCATE TABLE "post"', + string: 'TRUNCATE TABLE "post"' + }, + sqlite: { + text : 'DELETE FROM "post"', + string: 'DELETE FROM "post"' + }, + mysql: { + text : 'TRUNCATE TABLE `post`', + string: 'TRUNCATE TABLE `post`' + }, + mssql: { + text : 'TRUNCATE TABLE [post]', + string: 'TRUNCATE TABLE [post]' + }, + params: [] +}); From 01c046ab2d01e2185e0138ed6dc1d5fb891b9700 Mon Sep 17 00:00:00 2001 From: brianc Date: Sun, 3 May 2015 14:44:11 -0400 Subject: [PATCH 109/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ba0905b..9c8520d2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.50.0", + "version": "0.51.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From ef5433b3a6a0e58249c4f39f2791e51f1813c428 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Wed, 13 May 2015 11:09:05 -0400 Subject: [PATCH 110/248] - Added proper DISTINCT functionality. --- lib/dialect/mssql.js | 24 +++--------- lib/dialect/postgres.js | 41 +++++++++++++++++++- lib/node/distinct.js | 7 ++++ lib/node/query.js | 5 +++ lib/node/select.js | 4 +- test/dialects/distinct-tests.js | 66 +++++++++++++++++++++++++++++++++ test/dialects/insert-tests.js | 21 +++++++++++ 7 files changed, 147 insertions(+), 21 deletions(-) create mode 100644 lib/node/distinct.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 056a962f..5b60ab64 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -263,25 +263,10 @@ Mssql.prototype.visitOrderBy = function(orderBy) { * @returns {String[]} */ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ - /** - * - * @param {Node[]} list - * @param {String} type - * @returns {Object|undefined} {index:number, node:Node} - * @private - */ - function _findNode(list,type){ - for (var i= 0, len=list.length; i Date: Wed, 13 May 2015 09:19:00 -0700 Subject: [PATCH 111/248] Add scripts to makefile --- Makefile | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 6cde1304..4d56d98a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,17 @@ -.PHONY: jshint test - -jshint: - ./node_modules/.bin/jshint lib test +.PHONY: jshint test publish-patch test test: npm test + +patch: test + npm version patch -m "Bump version" + git push origin master --tags + npm publish + +minor: test + npm version minor -m "Bump version" + git push origin master --tags + npm publish + +jshint: + ./node_modules/.bin/jshint lib From a0b3461915d65c64638f58e1616a57cd2d70151a Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 13 May 2015 09:19:04 -0700 Subject: [PATCH 112/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c8520d2..4c1ce65f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.51.0", + "version": "0.52.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 4912b080a389695ef66e4af1b55503389222260f Mon Sep 17 00:00:00 2001 From: Brian C Date: Wed, 13 May 2015 09:30:33 -0700 Subject: [PATCH 113/248] Update README.md --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 454466bc..23e66ef5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,13 @@ Maybe it's still not fun, but at least it's _less not fun_. [![Build Status](https://secure.travis-ci.org/brianc/node-sql.png)](http://travis-ci.org/brianc/node-sql) -## examples +## install + +```sh +$ npm install sql +``` + +## use ```js //require the module @@ -102,7 +108,7 @@ console.log(user.select().where(user.state.equals('WA')).toQuery().text); // "SELECT "user".* FROM "user" WHERE ("user"."state_or_province" = $1)" ``` -There are a __lot__ more examples included in the `test/dialects` folder. +There are a __lot__ more examples included in the [test/dialects](https://github.com/brianc/node-sql/tree/master/test/dialects) folder. We encourage you to read through them if you have any questions on usage! ## from the command line You can use the [sql-generate module](https://github.com/tmont/node-sql-generate) From 2a2bf5e6f6f305e5a5c6ef5bef9dffbb93361833 Mon Sep 17 00:00:00 2001 From: Bergwinkl Thomas Date: Tue, 19 May 2015 13:38:53 +0200 Subject: [PATCH 114/248] don't use alias in binary clause --- lib/dialect/postgres.js | 4 ++++ test/dialects/binary-clause-tests.js | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 09c148e1..b37cbf58 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -373,6 +373,10 @@ Postgres.prototype.visitPostfixUnary = function(unary) { Postgres.prototype.visitBinary = function(binary) { var self = this; + + binary.left.property = binary.left.name; + binary.right.property = binary.right.name; + var text = '(' + this.visit(binary.left) + ' ' + binary.operator + ' '; if (Array.isArray(binary.right)) { text += '(' + binary.right.map(function (node) { diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 28b4a155..31c271e6 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -2,8 +2,10 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); +var customerAlias = Harness.defineCustomerAliasTable(); var post = Harness.definePostTable(); + Harness.test({ query: customer.select(customer.name.plus(customer.age)), pg: { @@ -25,6 +27,27 @@ Harness.test({ params: [] }); +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.plus(customerAlias.age_alias)), + pg: { + text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + sqlite: { + text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, + mysql: { + text : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', + string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' + }, + mssql: { + text : 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', + string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' + }, + params: [] +}); + Harness.test({ query: post.select(post.content.plus('!')).where(post.userId. in (customer.subQuery().select(customer.id))), pg: { From 853a549bddf3d121fc9859639fd7fcacedd537fb Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Sun, 7 Jun 2015 19:23:59 +0800 Subject: [PATCH 115/248] add quote to named subquery alias --- lib/dialect/postgres.js | 2 +- package.json | 2 +- test/dialects/join-tests.js | 16 ++++++++-------- test/dialects/literal-tests.js | 12 ++++++------ test/dialects/subquery-tests.js | 16 ++++++++-------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 09c148e1..19830dd8 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -624,7 +624,7 @@ Postgres.prototype.visitSubquery = function(queryNode) { } var alias = queryNode.alias; - return ['(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + alias : '')]; + return ['(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + this.quote(alias) : '')]; }; Postgres.prototype.visitTable = function(tableNode) { diff --git a/package.json b/package.json index 4c1ce65f..dd389f0c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.52.0", + "version": "0.53.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index 88792acf..bd5fc3b6 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -133,20 +133,20 @@ Harness.test({ .from(user.join(subposts) .on(user.id.equals(subposts.subpostUserId))), pg: { - text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")', - string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")' + text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', + string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' }, sqlite: { - text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")', - string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")' + text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', + string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" AS "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' }, mysql: { - text : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)', - string: 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)' + text : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) `subposts` ON (`user`.`id` = `subposts`.`subpostUserId`)', + string: 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) `subposts` ON (`user`.`id` = `subposts`.`subpostUserId`)' }, mssql: { - text : 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) subposts ON ([user].[id] = [subposts].[subpostUserId])', - string: 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) subposts ON ([user].[id] = [subposts].[subpostUserId])' + text : 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])', + string: 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])' }, params: [] }); diff --git a/test/dialects/literal-tests.js b/test/dialects/literal-tests.js index e1940f5a..424bedcf 100644 --- a/test/dialects/literal-tests.js +++ b/test/dialects/literal-tests.js @@ -45,16 +45,16 @@ var subquery = user.subQuery('subquery_for_count').select(user.literal(1).as('co Harness.test({ query: user.select(subquery.count_column.count()).from(subquery), pg: { - text : 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) subquery_for_count', - string: 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) subquery_for_count' + text : 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"', + string: 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"' }, sqlite: { - text : 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) subquery_for_count', - string: 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) subquery_for_count' + text : 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"', + string: 'SELECT COUNT("subquery_for_count"."count_column") AS "count_column_count" FROM (SELECT 1 AS "count_column" FROM "user" LIMIT 10 OFFSET 20) "subquery_for_count"' }, mysql: { - text : 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) subquery_for_count', - string: 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) subquery_for_count' + text : 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`', + string: 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`' }, params: [] }); diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 8a5aa16e..89e141b1 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -54,20 +54,20 @@ Harness.test({ Harness.test({ query: Sql.select('*').from(customer.subQuery('T1')).from(user.subQuery('T2')), pg: { - text : 'SELECT * FROM (SELECT * FROM "customer") T1 , (SELECT * FROM "user") T2', - string: 'SELECT * FROM (SELECT * FROM "customer") T1 , (SELECT * FROM "user") T2' + text : 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', + string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' }, sqlite: { - text : 'SELECT * FROM (SELECT * FROM "customer") T1 , (SELECT * FROM "user") T2', - string: 'SELECT * FROM (SELECT * FROM "customer") T1 , (SELECT * FROM "user") T2' + text : 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', + string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' }, mysql: { - text : 'SELECT * FROM (SELECT * FROM `customer`) T1 , (SELECT * FROM `user`) T2', - string: 'SELECT * FROM (SELECT * FROM `customer`) T1 , (SELECT * FROM `user`) T2' + text : 'SELECT * FROM (SELECT * FROM `customer`) `T1` , (SELECT * FROM `user`) `T2`', + string: 'SELECT * FROM (SELECT * FROM `customer`) `T1` , (SELECT * FROM `user`) `T2`' }, mssql: { - text : 'SELECT * FROM (SELECT * FROM [customer]) T1 , (SELECT * FROM [user]) T2', - string: 'SELECT * FROM (SELECT * FROM [customer]) T1 , (SELECT * FROM [user]) T2' + text : 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]', + string: 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]' }, params: [] }); From a7783455343c2b36e359540008869a1630841171 Mon Sep 17 00:00:00 2001 From: John Shen Date: Sat, 11 Jul 2015 17:20:18 -0400 Subject: [PATCH 116/248] adding on-delete constraints to create table --- lib/dialect/postgres.js | 3 +++ test/dialects/create-table-tests.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 09c148e1..85eaf232 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -749,6 +749,9 @@ Postgres.prototype.visitColumn = function(columnNode) { ' require a table and column)'); txt.push(' REFERENCES ' + columnNode.references.table + '(' + columnNode.references.column + ')'); + if (!!columnNode.references.onDelete) { + txt.push(' ON DELETE ' + columnNode.references.onDelete.toUpperCase()) + } } } } diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 33ba0f8d..af50af1c 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -274,6 +274,34 @@ Harness.test({ params: [] }); +Harness.test({ + query: Table.define({ + name: 'picture', + columns: [{ + name: 'userId', + dataType: 'int', + references: { + table: 'user', + column: 'id', + onDelete: 'cascade' + } + }] + }).create(), + pg: { + text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)' + }, + sqlite: { + text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)' + }, + mysql: { + text : 'CREATE TABLE `picture` (`userId` int REFERENCES user(id) ON DELETE CASCADE)', + string: 'CREATE TABLE `picture` (`userId` int REFERENCES user(id) ON DELETE CASCADE)' + }, + params: [] +}); + Harness.test({ query: Table.define({ name: 'post', From f3664f30e5a7c0455252ffe79df21682ece75bfd Mon Sep 17 00:00:00 2001 From: John Shen Date: Sat, 11 Jul 2015 17:42:40 -0400 Subject: [PATCH 117/248] ensure that only cascade/restrict options are available for on delete clauses --- lib/dialect/postgres.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 85eaf232..fdae849b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -750,7 +750,10 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push(' REFERENCES ' + columnNode.references.table + '(' + columnNode.references.column + ')'); if (!!columnNode.references.onDelete) { + if (columnNode.references.onDelete.toUpperCase() === "CASCADE" || + columnNode.references.onDelete.toUpperCase() === "RESTRICT") { txt.push(' ON DELETE ' + columnNode.references.onDelete.toUpperCase()) + } } } } From d75f204cfba1be00572dc38f135592e172a1e04f Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Wed, 15 Jul 2015 10:53:01 -0300 Subject: [PATCH 118/248] Implemented Rename Columns for MSSQL --- lib/dialect/mssql.js | 22 ++++++++++------------ test/dialects/alter-table-tests.js | 24 ++++++++---------------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 5b60ab64..c859ac82 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -99,19 +99,17 @@ Mssql.prototype.visitAlter = function(alter) { // Implement our own rename column: // PostgreSQL: ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId" - // Mssql: EXEC sp_rename [group], [userId], [newUserId] + // Mssql: EXEC sp_rename '[group].[userId]', [newUserId] function _renameColumn(){ - // TODO: implement this. Need to be able to get the [tableName.Column], which is hard to do with the current way visitXxx works - throw new Error('Mssql renaming columns not yet implemented'); -// self._visitingAlter = true; -// var table = self._queryNode.table; -// var result = ['EXEC sp_rename '+ -// self.visit(table.toNode())+'.'+self.visit(alter.nodes[0].nodes[0])+', '+ -// self.visit(alter.nodes[0].nodes[1])+', '+ -// "'COLUMN'" -// ]; -// self._visitingAlter = false; -// return result + self._visitingAlter = true; + var table = self._queryNode.table; + var result = ["EXEC sp_rename '"+ + self.visit(table.toNode())+'.'+self.visit(alter.nodes[0].nodes[0])+"', "+ + self.visit(alter.nodes[0].nodes[1])+', '+ + "'COLUMN'" + ]; + self._visitingAlter = false; + return result } if (isAlterAddColumn(alter)) return _addColumn(); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index d9e83d94..423ee029 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -178,10 +178,8 @@ Harness.test({ throws: true }, mssql: { - text : 'Mssql renaming columns not yet implemented', - throws: true -// text : 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'', -// string: 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'' + text : 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'', + string: 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'' }, params: [] }); @@ -201,10 +199,8 @@ Harness.test({ string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)' }, mssql: { - text : 'Mssql renaming columns not yet implemented', - throws: true -// text : 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'', -// string: 'EXEC sp_rename [group.userId], [newUserId], \'COLUMN\'' + text : 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'', + string: 'EXEC sp_rename \'[group].[userId]\', [newUserId], \'COLUMN\'' }, params: [] }); @@ -224,10 +220,8 @@ Harness.test({ string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)' }, mssql: { - text : 'Mssql renaming columns not yet implemented', - throws: true -// text : 'EXEC sp_rename [group.userId], [id], \'COLUMN\'', -// string: 'EXEC sp_rename [group.userId], [id], \'COLUMN\'' + text : 'EXEC sp_rename \'[group].[userId]\', [id], \'COLUMN\'', + string: 'EXEC sp_rename \'[group].[userId]\', [id], \'COLUMN\'' }, params: [] }); @@ -256,10 +250,8 @@ Harness.test({ throws: true }, mssql: { - text : 'Mssql renaming columns not yet implemented', - throws: true -// text : 'EXEC sp_rename [UserWithSignature.Signature], [sig], \'COLUMN\'', -// string: 'EXEC sp_rename [UserWithSignature.Signature], [sig], \'COLUMN\'' + text : 'EXEC sp_rename \'[UserWithSignature].[Signature]\', [sig], \'COLUMN\'', + string: 'EXEC sp_rename \'[UserWithSignature].[Signature]\', [sig], \'COLUMN\'' } }); From 62d87d1baa9fc1c7f6250b6e2197e88d4551b4c1 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 15 Jul 2015 09:30:02 -0500 Subject: [PATCH 119/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd389f0c..8e8a7fde 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.53.0", + "version": "0.54.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 395114a75f8e1d77c77edd2a266c6355188bbfdc Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 15 Jul 2015 09:35:16 -0500 Subject: [PATCH 120/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e8a7fde..22864027 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.54.0", + "version": "0.55.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From b89604b4e4347f7c7366272ee96b2a35eb37038e Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Thu, 16 Jul 2015 19:40:19 -0300 Subject: [PATCH 121/248] basic queries working --- README.md | 2 +- lib/dialect/index.js | 2 ++ lib/dialect/oracle.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 lib/dialect/oracle.js diff --git a/README.md b/README.md index 23e66ef5..193ab2be 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # node-sql -_sql string builder for node_ - supports PostgreSQL, mysql, Microsoft SQL Server, and sqlite dialects. +_sql string builder for node_ - supports PostgreSQL, mysql, Microsoft SQL Server, Oracle and sqlite dialects. Building SQL statements by hand is no fun, especially in a language which has clumsy support for multi-line strings. diff --git a/lib/dialect/index.js b/lib/dialect/index.js index ac4dcb91..c26f15de 100644 --- a/lib/dialect/index.js +++ b/lib/dialect/index.js @@ -11,6 +11,8 @@ var getDialect = function(dialect) { return require('./sqlite'); case 'mssql': return require('./mssql'); + case 'oracle': + return require('./oracle'); default: throw new Error(dialect + ' is unsupported'); } diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js new file mode 100644 index 00000000..d0dc5271 --- /dev/null +++ b/lib/dialect/oracle.js @@ -0,0 +1,42 @@ +'use strict'; + +var util = require('util'); +var assert = require('assert'); + +var Oracle = function() { + this.output = []; + this.params = []; +}; + +var Postgres = require(__dirname + '/postgres'); + +util.inherits(Oracle, Postgres); + +Oracle.prototype._myClass = Oracle; + +Oracle.prototype._getParameterPlaceholder = function(index, value) { + /* jshint unused: false */ + return ':' + index; +}; + +Oracle.prototype.visitAlias = function(alias) { + var result = [this.visit(alias.value) + ' ' + this.quote(alias.alias)]; + return result; +}; + +Oracle.prototype.visitTable = function(tableNode) { + var table = tableNode.table; + var txt=""; + if(table.getSchema()) { + txt = this.quote(table.getSchema()); + txt += '.'; + } + txt += this.quote(table.getName()); + if(table.alias) { + txt += ' ' + this.quote(table.alias); + } + return [txt]; +}; + + +module.exports = Oracle; From 544d2526d715d0bad4efb91fad83d3db6ea81e9a Mon Sep 17 00:00:00 2001 From: Alex Jordan Date: Sat, 18 Jul 2015 17:55:42 -0700 Subject: [PATCH 122/248] Add license metadata in package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 22864027..0a4a51c8 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "sql builder", "version": "0.55.0", "homepage": "https://github.com/brianc/node-sql", + "license": "MIT", "repository": { "type": "git", "url": "git://github.com/brianc/node-sql.git" From fb0304ef25b1f5669e7a7c797cfb1267a309d614 Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Tue, 21 Jul 2015 09:13:50 -0300 Subject: [PATCH 123/248] Oracle - all tests done --- lib/dialect/oracle.js | 213 ++++++++++++++++++++++++ lib/dialect/postgres.js | 21 ++- test/dialects/aggregate-tests.js | 76 +++++++++ test/dialects/alias-tests.js | 12 ++ test/dialects/alter-table-tests.js | 20 ++- test/dialects/binary-clause-tests.js | 12 ++ test/dialects/case-tests.js | 37 ++++ test/dialects/cast-tests.js | 24 +++ test/dialects/clause-ordering-tests.js | 16 ++ test/dialects/create-table-tests.js | 88 ++++++++-- test/dialects/delete-tests.js | 20 +++ test/dialects/distinct-tests.js | 20 +++ test/dialects/drop-table-tests.js | 16 ++ test/dialects/from-clause-tests.js | 16 ++ test/dialects/group-by-tests.js | 20 +++ test/dialects/having-tests.js | 12 ++ test/dialects/in-clause-tests.js | 28 ++++ test/dialects/indexes-tests.js | 28 ++++ test/dialects/insert-tests.js | 98 ++++++++++- test/dialects/join-tests.js | 24 +++ test/dialects/join-to-tests.js | 12 ++ test/dialects/limit-and-offset-tests.js | 8 + test/dialects/literal-tests.js | 12 ++ test/dialects/matches-test.js | 4 + test/dialects/namespace-tests.js | 20 +++ test/dialects/not-in-clause-tests.js | 28 ++++ test/dialects/order-tests.js | 40 +++++ test/dialects/schema-tests.js | 24 +++ test/dialects/select-tests.js | 12 ++ test/dialects/shortcut-tests.js | 24 +++ test/dialects/subquery-tests.js | 20 +++ test/dialects/support.js | 3 +- test/dialects/table-tests.js | 110 +++++++++++- test/dialects/ternary-clause-tests.js | 8 + test/dialects/tostring-tests.js | 16 ++ test/index-tests.js | 28 ++++ 36 files changed, 1136 insertions(+), 34 deletions(-) diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index d0dc5271..763b2c5a 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -10,10 +10,13 @@ var Oracle = function() { var Postgres = require(__dirname + '/postgres'); +var Mssql = require(__dirname + '/mssql'); + util.inherits(Oracle, Postgres); Oracle.prototype._myClass = Oracle; +Oracle.prototype._aliasText = ' '; Oracle.prototype._getParameterPlaceholder = function(index, value) { /* jshint unused: false */ return ':' + index; @@ -38,5 +41,215 @@ Oracle.prototype.visitTable = function(tableNode) { return [txt]; }; +Oracle.prototype.visitCascade = function() { + return ['CASCADE CONSTRAINTS']; +}; + +Oracle.prototype.visitRestrict = function() { + throw new Error('Oracle do not support RESTRICT in DROP TABLE'); +}; + +Oracle.prototype.visitDrop = function(drop) { + if (!isDropIfExists(drop)) { + return Oracle.super_.prototype.visitDrop.call(this, drop); + } + // Implement our own drop if exists: + // PostgreSQL: DROP TABLE IF EXISTS "group" + // Oracle: + // BEGIN + // EXECUTE IMMEDIATE 'DROP TABLE POST'; + // EXCEPTION + // WHEN OTHERS THEN + // IF SQLCODE != -942 THEN + // RAISE; + // END IF; + // END; + var table = this._queryNode.table; + var tableResult=this.visit(table.toNode()); + + var dropResult = ['DROP TABLE']; + dropResult.push(tableResult); + + return ["BEGIN EXECUTE IMMEDIATE '"+dropResult.join(' ')+"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;"]; +}; + +Oracle.prototype.visitCreate = function(create) { + var isNotExists=isCreateIfNotExists(create) + //var isTemporary=isCreateTemporary(create) + var createText = Oracle.super_.prototype.visitCreate.call(this, create); + if (isNotExists) { + // Implement our own create if not exists: + // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) + // Oracle: + // BEGIN + // EXECUTE IMMEDIATE 'CREATE TABLE ...'; + // EXCEPTION + // WHEN OTHERS THEN + // IF SQLCODE != -955 THEN + // RAISE; + // END IF; + // END; + + createText = "BEGIN EXECUTE IMMEDIATE '"+createText.join(' ').replace(' IF NOT EXISTS','')+"'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;"; + } + + return createText; +}; + +Oracle.prototype.visitBinary = function(binary) { + if(binary.operator === '@@'){ + var self = this; + var text = '(INSTR (' + this.visit(binary.left) + ', '; + text += this.visit(binary.right); + text += ') > 0)'; + return [text]; + } + + if (!isRightSideArray(binary)){ + return Oracle.super_.prototype.visitBinary.call(this, binary); + } + if (binary.operator=='IN' || binary.operator=='NOT IN'){ + return Oracle.super_.prototype.visitBinary.call(this, binary); + } + throw new Error('Oracle does not support arrays in this type of expression.'); +}; + +Oracle.prototype.visitModifier = function(node) { + var ret = Oracle.super_.prototype.visitModifier.call(this, node); + if (ret.indexOf('OFFSET') >= 0) { + ret.push('ROWS'); + } + if (ret.indexOf('LIMIT') >= 0) { + ret[0] = 'FETCH NEXT'; + ret.push('ROWS ONLY'); + } + return ret; +}; + +Oracle.prototype.visitQueryHelper=function(actions,targets,filters){ + var output = Oracle.super_.prototype.visitQueryHelper.call(this,actions,targets,filters); + + //In Oracle, OFFSET must come before FETCH NEXT (limit) + //Change positions, if both are present and not done already + var offset = output.indexOf('OFFSET'); + var limit = output.indexOf('FETCH NEXT'); + if (offset != -1 && limit != -1 && offset > limit){ + var temp = [output[offset], output[offset+1], output[offset+2]]; + output[offset] = output[limit]; + output[offset+1] = output[limit+1]; + output[offset+2] = output[limit+2]; + output[limit] = temp[0]; + output[limit+1] = temp[1]; + output[limit+2] = temp[2]; + } + + return this.output; +} + +Oracle.prototype.visitColumn = function(columnNode) { + var self=this; + var table; + var inSelectClause; + + function _arrayAgg(){ + throw new Error("Oracle does not support array_agg.") + } + + function _countStar(){ + // Implement our own since count(table.*) is invalid in Oracle + var result='COUNT(*)' + if(inSelectClause && columnNode.alias) { + result += self._aliasText + self.quote(columnNode.alias); + } + return result; + } + + table = columnNode.table; + inSelectClause = !this._selectOrDeleteEndIndex; + if (isCountStarExpression(columnNode)) return _countStar(); + if (inSelectClause && !table.alias && columnNode.asArray) return _arrayAgg(); + return Oracle.super_.prototype.visitColumn.call(this, columnNode); +}; + + +Oracle.prototype.visitReturning = function() { + // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause + // in MS SQL which appears before the values, not at the end of the statement. + throw new Error('Returning clause is not yet supported for Oracle.'); +}; + + +Oracle.prototype._getParameterValue = function(value) { + if (Buffer.isBuffer(value)) { + value = "utl_raw.cast_to_varchar2(hextoraw('" + value.toString('hex') + "'))"; + } else { + value = Oracle.super_.prototype._getParameterValue.call(this, value); + //value = Postgres.prototype._getParameterValue.call(this, value); + } + return value; +}; + + +Oracle.prototype.visitIndexes = function(node) { + + var tableName = this._queryNode.table.getName(); + var schemaName = this._queryNode.table.getSchema(); + + var indexes = "SELECT * FROM USER_INDEXES WHERE TABLE_NAME = '" + tableName + "'"; + + if (schemaName) { + indexes += " AND TABLE_OWNER = '" + schemaName + "'"; + } + + return indexes; +}; + + +Oracle.prototype.visitDropIndex = function(node) { + var result = [ 'DROP INDEX' ]; + var schemaName = node.table.getSchema(); + if (schemaName) { + result.push(this.quote(schemaName) + "."); + } + + result.push(this.quote(node.options.indexName)); + + return result; +}; + +// Using same CASE implementation as MSSQL +Oracle.prototype.visitCase = function(caseExp) { + + return Mssql.prototype.visitCase.call(this, caseExp); +} + + +function isCreateIfNotExists(create){ + if (create.nodes.length==0) return false; + if (create.nodes[0].type!='IF NOT EXISTS') return false; + return true; +}; + +function isCreateTemporary(create){ + return create.options.isTemporary +}; + +function isDropIfExists(drop){ + if (drop.nodes.length==0) return false; + if (drop.nodes[0].type!='IF EXISTS') return false; + return true; +}; + +// SQL Server does not support array expressions except in the IN clause. +function isRightSideArray(binary){ + return Array.isArray(binary.right); +}; + +function isCountStarExpression(columnNode){ + if (!columnNode.aggregator) return false; + if (columnNode.aggregator.toLowerCase()!='count') return false; + if (!columnNode.star) return false; + return true; +}; module.exports = Oracle; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a6ff8a14..01e314cb 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -162,6 +162,8 @@ Postgres.prototype.visit = function(node) { }; Postgres.prototype._quoteCharacter = '"'; +Postgres.prototype._aliasText = ' AS '; + Postgres.prototype.quote = function(word, quoteCharacter) { var q; if (quoteCharacter) { @@ -296,7 +298,7 @@ Postgres.prototype.visitDistinct = function(truncate) { }; Postgres.prototype.visitAlias = function(alias) { - var result = [this.visit(alias.value) + ' AS ' + this.quote(alias.alias)]; + var result = [this.visit(alias.value) + this._aliasText + this.quote(alias.alias)]; return result; }; @@ -636,7 +638,7 @@ Postgres.prototype.visitTable = function(tableNode) { } txt += this.quote(table.getName()); if(table.alias) { - txt += ' AS ' + this.quote(table.alias); + txt += this._aliasText + this.quote(table.alias); } return [txt]; }; @@ -693,7 +695,7 @@ Postgres.prototype.visitColumn = function(columnNode) { var col = table.columns[i]; var aliased = col.name !== (col.alias || col.property); hasAliases = hasAliases || aliased; - allCols.push(tableName + this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : '')); + allCols.push(tableName + this.quote(col.name) + (aliased ? this._aliasText + this.quote(col.alias || col.property) : '')); } } if(hasAliases) { @@ -715,7 +717,7 @@ Postgres.prototype.visitColumn = function(columnNode) { } } if(inSelectClause && (columnNode.alias || columnNode.property !== columnNode.name)) { - txt.push(' AS ' + this.quote(columnNode.alias || columnNode.property)); + txt.push(this._aliasText + this.quote(columnNode.alias || columnNode.property)); } if(this._visitingCreate || this._visitingAddColumn) { assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + @@ -747,8 +749,13 @@ Postgres.prototype.visitColumn = function(columnNode) { columnNode.name + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + ' require a table and column)'); - txt.push(' REFERENCES ' + columnNode.references.table + '(' + - columnNode.references.column + ')'); + + txt.push(' REFERENCES '); + if(columnNode.references.schema) { + txt.push(this.quote(columnNode.references.schema) + '.'); + } + txt.push(this.quote(columnNode.references.table) + '(' + + this.quote(columnNode.references.column) + ')'); if (!!columnNode.references.onDelete) { if (columnNode.references.onDelete.toUpperCase() === "CASCADE" || columnNode.references.onDelete.toUpperCase() === "RESTRICT") { @@ -840,7 +847,7 @@ Postgres.prototype.visitJoin = function(join) { Postgres.prototype.visitLiteral = function(node) { var txt = [node.literal]; if(node.alias) { - txt.push(' AS ' + this.quote(node.alias)); + txt.push(this._aliasText + this.quote(node.alias)); } return [txt.join('')]; }; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index a58397cc..d67d775a 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -23,6 +23,10 @@ Harness.test({ text : 'SELECT COUNT(*) AS [post_count] FROM [post]', string: 'SELECT COUNT(*) AS [post_count] FROM [post]' }, + oracle: { + text : 'SELECT COUNT(*) "post_count" FROM "post"', + string: 'SELECT COUNT(*) "post_count" FROM "post"' + }, params: [] }); @@ -44,6 +48,10 @@ Harness.test({ text : 'SELECT COUNT(*) AS [post_count] FROM [post]', string: 'SELECT COUNT(*) AS [post_count] FROM [post]' }, + oracle: { + text : 'SELECT COUNT(*) "post_count" FROM "post"', + string: 'SELECT COUNT(*) "post_count" FROM "post"' + }, params: [] }); @@ -65,6 +73,10 @@ Harness.test({ text : 'SELECT COUNT(*) AS [post_amount] FROM [post]', string: 'SELECT COUNT(*) AS [post_amount] FROM [post]' }, + oracle: { + text : 'SELECT COUNT(*) "post_amount" FROM "post"', + string: 'SELECT COUNT(*) "post_amount" FROM "post"' + }, params: [] }); @@ -86,6 +98,10 @@ Harness.test({ text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' }, + oracle: { + text : 'SELECT COUNT("post"."content") "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' + }, params: [] }); @@ -107,6 +123,10 @@ Harness.test({ text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' }, + oracle: { + text : 'SELECT COUNT("post"."content") "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' + }, params: [] }); @@ -128,6 +148,10 @@ Harness.test({ text : 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]', string: 'SELECT COUNT([post].[content]) AS [content_count] FROM [post]' }, + oracle: { + text : 'SELECT COUNT("post"."content") "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") "content_count" FROM "post"' + }, params: [] }); @@ -145,6 +169,10 @@ Harness.test({ text : 'SELECT COUNT(`customer`.*) AS `customer_count` FROM `customer`', string: 'SELECT COUNT(`customer`.*) AS `customer_count` FROM `customer`' }, + oracle: { + text : 'SELECT COUNT(*) "customer_count" FROM "customer"', + string: 'SELECT COUNT(*) "customer_count" FROM "customer"' + }, params: [] }); @@ -166,6 +194,10 @@ Harness.test({ text : 'SELECT MIN([post].[id]) AS [id_min] FROM [post]', string: 'SELECT MIN([post].[id]) AS [id_min] FROM [post]' }, + oracle: { + text : 'SELECT MIN("post"."id") "id_min" FROM "post"', + string: 'SELECT MIN("post"."id") "id_min" FROM "post"' + }, params: [] }); @@ -187,6 +219,10 @@ Harness.test({ text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' }, + oracle: { + text : 'SELECT MIN("post"."id") "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") "min_id" FROM "post"' + }, params: [] }); @@ -208,6 +244,10 @@ Harness.test({ text : 'SELECT MIN([post].[id]) AS [min_id] FROM [post]', string: 'SELECT MIN([post].[id]) AS [min_id] FROM [post]' }, + oracle: { + text : 'SELECT MIN("post"."id") "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") "min_id" FROM "post"' + }, params: [] }); @@ -229,6 +269,10 @@ Harness.test({ text : 'SELECT MAX([post].[id]) AS [id_max] FROM [post]', string: 'SELECT MAX([post].[id]) AS [id_max] FROM [post]' }, + oracle: { + text : 'SELECT MAX("post"."id") "id_max" FROM "post"', + string: 'SELECT MAX("post"."id") "id_max" FROM "post"' + }, params: [] }); @@ -250,6 +294,10 @@ Harness.test({ text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' }, + oracle: { + text : 'SELECT MAX("post"."id") "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") "max_id" FROM "post"' + }, params: [] }); @@ -271,6 +319,10 @@ Harness.test({ text : 'SELECT MAX([post].[id]) AS [max_id] FROM [post]', string: 'SELECT MAX([post].[id]) AS [max_id] FROM [post]' }, + oracle: { + text : 'SELECT MAX("post"."id") "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") "max_id" FROM "post"' + }, params: [] }); @@ -292,6 +344,10 @@ Harness.test({ text : 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]', string: 'SELECT SUM([post].[id]) AS [id_sum] FROM [post]' }, + oracle: { + text : 'SELECT SUM("post"."id") "id_sum" FROM "post"', + string: 'SELECT SUM("post"."id") "id_sum" FROM "post"' + }, params: [] }); @@ -313,6 +369,10 @@ Harness.test({ text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' }, + oracle: { + text : 'SELECT SUM("post"."id") "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") "sum_id" FROM "post"' + }, params: [] }); @@ -334,6 +394,10 @@ Harness.test({ text : 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]', string: 'SELECT SUM([post].[id]) AS [sum_id] FROM [post]' }, + oracle: { + text : 'SELECT SUM("post"."id") "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") "sum_id" FROM "post"' + }, params: [] }); @@ -355,6 +419,10 @@ Harness.test({ text : 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]', string: 'SELECT AVG([post].[id]) AS [id_avg] FROM [post]' }, + oracle: { + text : 'SELECT AVG("post"."id") "id_avg" FROM "post"', + string: 'SELECT AVG("post"."id") "id_avg" FROM "post"' + }, params: [] }); @@ -376,6 +444,10 @@ Harness.test({ text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' }, + oracle: { + text : 'SELECT AVG("post"."id") "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") "avg_id" FROM "post"' + }, params: [] }); @@ -397,5 +469,9 @@ Harness.test({ text : 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]', string: 'SELECT AVG([post].[id]) AS [avg_id] FROM [post]' }, + oracle: { + text : 'SELECT AVG("post"."id") "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") "avg_id" FROM "post"' + }, params: [] }); diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index a6a5a09f..f558260b 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]', string: 'SELECT ([customer].[name] IS NULL) AS [nameIsNull] FROM [customer]' }, + oracle: { + text : 'SELECT ("customer"."name" IS NULL) "nameIsNull" FROM "customer"', + string: 'SELECT ("customer"."name" IS NULL) "nameIsNull" FROM "customer"' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > @1) AND ([customer].[age] < @2))', string: 'SELECT ([customer].[name] + [customer].[age]) AS [nameAndAge] FROM [customer] WHERE (([customer].[age] > 10) AND ([customer].[age] < 20))' }, + oracle: { + text : 'SELECT ("customer"."name" + "customer"."age") "nameAndAge" FROM "customer" WHERE (("customer"."age" > :1) AND ("customer"."age" < :2))', + string: 'SELECT ("customer"."name" + "customer"."age") "nameAndAge" FROM "customer" WHERE (("customer"."age" > 10) AND ("customer"."age" < 20))' + }, params: [10, 20] }); @@ -63,5 +71,9 @@ Harness.test({ text : 'SELECT ([customer].[age] BETWEEN @1 AND @2) AS [ageBetween] FROM [customer]', string: 'SELECT ([customer].[age] BETWEEN 10 AND 20) AS [ageBetween] FROM [customer]' }, + oracle: { + text : 'SELECT ("customer"."age" BETWEEN :1 AND :2) "ageBetween" FROM "customer"', + string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) "ageBetween" FROM "customer"' + }, params: [10, 20] }); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 423ee029..f733b2f2 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -274,16 +274,20 @@ var post = Table.define({ Harness.test({ query: post.alter().addColumn(post.userId), pg: { - text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)', - string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)' + text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' }, sqlite: { - text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)', - string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES user(id)' + text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' }, mysql: { - text : 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES user(id)', - string: 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES user(id)' + text : 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES `user`(`id`)', + string: 'ALTER TABLE `post` ADD COLUMN `userId` int REFERENCES `user`(`id`)' + }, + oracle: { + text : 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")', + string: 'ALTER TABLE "post" ADD COLUMN "userId" int REFERENCES "user"("id")' }, params: [] }); @@ -302,5 +306,9 @@ Harness.test({ text : 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)', string: 'ALTER TABLE `post` ADD COLUMN `picture` varchar(100)' }, + oracle: { + text : 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)', + string: 'ALTER TABLE "post" ADD COLUMN "picture" varchar(100)' + }, params: [] }); diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 28b4a155..88950e22 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]', string: 'SELECT ([customer].[name] + [customer].[age]) FROM [customer]' }, + oracle: { + text : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + string: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"' + }, params: [] }); @@ -43,6 +47,10 @@ Harness.test({ text : 'SELECT ([post].[content] + @1) FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))', string: 'SELECT ([post].[content] + \'!\') FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer]))' }, + oracle: { + text : 'SELECT ("post"."content" + :1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', + string: 'SELECT ("post"."content" + \'!\') FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))' + }, params: ['!'] }); @@ -64,5 +72,9 @@ Harness.test({ text : 'SELECT (([post].[id] + @1) + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))', string: 'SELECT (([post].[id] + \': \') + [post].[content]) FROM [post] WHERE ([post].[userId] NOT IN (SELECT [customer].[id] FROM [customer]))' }, + oracle: { + text : 'SELECT (("post"."id" + :1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', + string: 'SELECT (("post"."id" + \': \') + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))' + }, params: [': '] }); diff --git a/test/dialects/case-tests.js b/test/dialects/case-tests.js index f07bb0a7..046ee4b2 100644 --- a/test/dialects/case-tests.js +++ b/test/dialects/case-tests.js @@ -23,6 +23,11 @@ Harness.test({ string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM [customer]', params: [0, 1, 2] }, + oracle: { + text : 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END) FROM "customer"', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) FROM "customer"', + params: [0, 1, 2] + }, params: [true, 0, false, 1, 2] }); @@ -46,6 +51,11 @@ Harness.test({ string: 'SELECT ([customer].[age] + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM [customer]', params: [0, 1, 2] }, + oracle: { + text : 'SELECT ("customer"."age" + (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END)) FROM "customer"', + string: 'SELECT ("customer"."age" + (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END)) FROM "customer"', + params: [0, 1, 2] + }, params: [true, 0, false, 1, 2] }); @@ -69,6 +79,11 @@ Harness.test({ string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM [customer]', params: [0, 1, 2, 3] }, + oracle: { + text : 'SELECT ((CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE :3 END) + :4) FROM "customer"', + string: 'SELECT ((CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE 2 END) + 3) FROM "customer"', + params: [0, 1, 2, 3] + }, params: [true, 0, false, 1, 2, 3] }); @@ -92,6 +107,11 @@ Harness.test({ string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ([customer].[age] BETWEEN 10 AND 20) END) FROM [customer]', params: [0, 1, 10, 20] }, + oracle: { + text : 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 ELSE ("customer"."age" BETWEEN :3 AND :4) END) FROM "customer"', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"', + params: [0, 1, 10, 20] + }, params: [true, 0, false, 1, 10, 20] }); @@ -115,6 +135,11 @@ Harness.test({ string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM [customer]', params: [0, 1] }, + oracle: { + text : 'SELECT (CASE WHEN 1=1 THEN :1 WHEN 0=1 THEN :2 END) FROM "customer"', + string: 'SELECT (CASE WHEN 1=1 THEN 0 WHEN 0=1 THEN 1 END) FROM "customer"', + params: [0, 1] + }, params: [true, 0, false, 1] }); @@ -137,6 +162,10 @@ Harness.test({ text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 ELSE @7 END) FROM [customer]', string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 ELSE 2 END) FROM [customer]' }, + oracle: { + text : 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN :4 WHEN ("customer"."age" <= :5) THEN :6 ELSE :7 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 ELSE 2 END) FROM "customer"' + }, params: [10, 20, 30, 0, 60, 1, 2] }); @@ -159,6 +188,10 @@ Harness.test({ text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN @4 WHEN ([customer].[age] <= @5) THEN @6 END) FROM [customer]', string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN 0 WHEN ([customer].[age] <= 60) THEN 1 END) FROM [customer]' }, + oracle: { + text : 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN :4 WHEN ("customer"."age" <= :5) THEN :6 END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN 0 WHEN ("customer"."age" <= 60) THEN 1 END) FROM "customer"' + }, params: [10, 20, 30, 0, 60, 1] }); @@ -181,5 +214,9 @@ Harness.test({ text : 'SELECT (CASE WHEN ([customer].[age] IN (@1, @2, @3)) THEN ([customer].[age] + @4) WHEN ([customer].[age] <= @5) THEN ([customer].[age] - @6) END) FROM [customer]', string: 'SELECT (CASE WHEN ([customer].[age] IN (10, 20, 30)) THEN ([customer].[age] + 5) WHEN ([customer].[age] <= 60) THEN ([customer].[age] - 1) END) FROM [customer]' }, + oracle: { + text : 'SELECT (CASE WHEN ("customer"."age" IN (:1, :2, :3)) THEN ("customer"."age" + :4) WHEN ("customer"."age" <= :5) THEN ("customer"."age" - :6) END) FROM "customer"', + string: 'SELECT (CASE WHEN ("customer"."age" IN (10, 20, 30)) THEN ("customer"."age" + 5) WHEN ("customer"."age" <= 60) THEN ("customer"."age" - 1) END) FROM "customer"' + }, params: [10, 20, 30, 5, 60, 1] }); diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js index 4bf14c22..8f407f3d 100644 --- a/test/dialects/cast-tests.js +++ b/test/dialects/cast-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'SELECT CAST([customer].[age] AS int) FROM [customer]', string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' }, + oracle: { + text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, params: [] }); @@ -43,6 +47,10 @@ Harness.test({ text : 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' }, + oracle: { + text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, params: [] }); @@ -65,6 +73,10 @@ Harness.test({ text : 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' }, + oracle: { + text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, params: [] }); @@ -87,6 +99,10 @@ Harness.test({ text : 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' }, + oracle: { + text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, params: [] }); @@ -109,6 +125,10 @@ Harness.test({ text : 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', string: 'SELECT [customer].[name] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' }, + oracle: { + text : 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + :1) = :2)', + string: 'SELECT "customer"."name" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, params: [100, 150] }); @@ -131,5 +151,9 @@ Harness.test({ text : 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' }, + oracle: { + text : 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"' + }, params: [] }); diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index baf7ac58..83d2d28e 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -23,6 +23,10 @@ Harness.test({ text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' }, + oracle: { + text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, params: [] }); @@ -47,6 +51,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, params: [''] }); @@ -74,6 +82,10 @@ Harness.test({ text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = @1)', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([user].[name] = \'\')' }, + oracle: { + text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = :1)', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = \'\')' + }, params: [''] }); @@ -98,5 +110,9 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'\')' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, params: [''] }); diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index af50af1c..f9c3e2fa 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -33,6 +33,10 @@ Harness.test({ text : 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))', string: 'CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100))' }, + oracle: { + text : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' + }, params: [] }); @@ -54,6 +58,10 @@ Harness.test({ text : 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END', string: 'IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = \'group\') BEGIN CREATE TABLE [group] ([id] varchar(100), [user_id] varchar(100)) END' }, + oracle: { + text : 'BEGIN EXECUTE IMMEDIATE \'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;', + string: 'BEGIN EXECUTE IMMEDIATE \'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -955 THEN RAISE; END IF; END;' + }, params: [] }); @@ -82,6 +90,10 @@ Harness.test({ mssql: { text : 'CREATE TABLE [user] ([id] varchar(100))', string: 'CREATE TABLE [user] ([id] varchar(100))' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' } }); @@ -110,6 +122,10 @@ Harness.test({ mssql: { text : 'CREATE TABLE [user] ([id] varchar(100))', string: 'CREATE TABLE [user] ([id] varchar(100))' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' } }); @@ -139,6 +155,10 @@ Harness.test({ mssql: { text : 'CREATE TABLE [user] ([id] varchar(100))', string: 'CREATE TABLE [user] ([id] varchar(100))' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' } }); @@ -166,6 +186,10 @@ Harness.test({ mssql: { text : 'CREATE TABLE [user] ([id] int PRIMARY KEY)', string: 'CREATE TABLE [user] ([id] int PRIMARY KEY)' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' } }); @@ -189,6 +213,10 @@ Harness.test({ mysql: { text : 'CREATE TABLE `user` (`id` int NOT NULL)', string: 'CREATE TABLE `user` (`id` int NOT NULL)' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" int NOT NULL)', + string: 'CREATE TABLE "user" ("id" int NOT NULL)' } }); @@ -213,6 +241,10 @@ Harness.test({ mysql: { text : 'CREATE TABLE `user` (`id` int PRIMARY KEY)', string: 'CREATE TABLE `user` (`id` int PRIMARY KEY)' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY)' } }); @@ -229,16 +261,20 @@ Harness.test({ }] }).create(), pg: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES user(id))', - string: 'CREATE TABLE "post" ("userId" int REFERENCES user(id))' + text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))' }, sqlite: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES user(id))', - string: 'CREATE TABLE "post" ("userId" int REFERENCES user(id))' + text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))' }, mysql: { - text : 'CREATE TABLE `post` (`userId` int REFERENCES user(id))', - string: 'CREATE TABLE `post` (`userId` int REFERENCES user(id))' + text : 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`))', + string: 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`))' + }, + oracle: { + text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))' }, params: [] }); @@ -260,16 +296,20 @@ Harness.test({ }] }).create(), pg: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))' + text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' }, sqlite: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id), "caption" varchar(100))' + text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' }, mysql: { - text : 'CREATE TABLE `picture` (`userId` int REFERENCES user(id), `caption` varchar(100))', - string: 'CREATE TABLE `picture` (`userId` int REFERENCES user(id), `caption` varchar(100))' + text : 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`), `caption` varchar(100))', + string: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`), `caption` varchar(100))' + }, + oracle: { + text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id"), "caption" varchar(100))' }, params: [] }); @@ -288,16 +328,20 @@ Harness.test({ }] }).create(), pg: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)' + text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' }, sqlite: { - text : 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)', - string: 'CREATE TABLE "picture" ("userId" int REFERENCES user(id) ON DELETE CASCADE)' + text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' }, mysql: { - text : 'CREATE TABLE `picture` (`userId` int REFERENCES user(id) ON DELETE CASCADE)', - string: 'CREATE TABLE `picture` (`userId` int REFERENCES user(id) ON DELETE CASCADE)' + text : 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`) ON DELETE CASCADE)', + string: 'CREATE TABLE `picture` (`userId` int REFERENCES `user`(`id`) ON DELETE CASCADE)' + }, + oracle: { + text : 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)', + string: 'CREATE TABLE "picture" ("userId" int REFERENCES "user"("id") ON DELETE CASCADE)' }, params: [] }); @@ -323,6 +367,10 @@ Harness.test({ text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', throws: true }, + oracle: { + text : 'references is not a object for column userId (REFERENCES statements within CREATE TABLE and ADD COLUMN statements require refrences to be expressed as an object)', + throws: true + }, params: [] }); @@ -378,6 +426,10 @@ Harness.test({ text : 'CREATE TABLE [post] ([id] int)', string: 'CREATE TABLE [post] ([id] int)' }, + oracle: { + text : 'CREATE TABLE "post" ("id" int)', + string: 'CREATE TABLE "post" ("id" int)' + }, params: [] }); diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 3e1a3915..51fe3026 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = 'hello''s world')" }, + oracle: { + text : 'DELETE FROM "post" WHERE ("post"."content" = :1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' + }, params: ["hello's world"] }); @@ -76,6 +80,10 @@ Harness.test({ text: 'DELETE `user` FROM `user` INNER JOIN `post` ON (`post`.`userId` = `user`.`id`) WHERE (`post`.`content` = ?)', string: 'DELETE `user` FROM `user` INNER JOIN `post` ON (`post`.`userId` = `user`.`id`) WHERE (`post`.`content` = \'foo\')' }, + oracle: { + text: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = :1)', + string: 'DELETE "user" FROM "user" INNER JOIN "post" ON ("post"."userId" = "user"."id") WHERE ("post"."content" = \'foo\')' + }, params: [ 'foo' ] }); @@ -99,6 +107,10 @@ Harness.test({ text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = '')" }, + oracle: { + text : 'DELETE FROM "post" WHERE ("post"."content" = :1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, params: [''] }); @@ -122,6 +134,10 @@ Harness.test({ text : 'DELETE FROM [post] WHERE ([post].[content] = @1)', string: "DELETE FROM [post] WHERE ([post].[content] = '')" }, + oracle: { + text : 'DELETE FROM "post" WHERE ("post"."content" = :1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, params: [''] }); @@ -145,5 +161,9 @@ Harness.test({ text : 'DELETE FROM [post] WHERE (([post].[content] = @1) OR ([post].[content] IS NULL))', string: "DELETE FROM [post] WHERE (([post].[content] = '') OR ([post].[content] IS NULL))" }, + oracle: { + text : 'DELETE FROM "post" WHERE (("post"."content" = :1) OR ("post"."content" IS NULL))', + string: 'DELETE FROM "post" WHERE (("post"."content" = \'\') OR ("post"."content" IS NULL))' + }, params: [''] }); diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js index d340d400..9f922bff 100644 --- a/test/dialects/distinct-tests.js +++ b/test/dialects/distinct-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT DISTINCT([user].[id]) FROM [user]', string: 'SELECT DISTINCT([user].[id]) FROM [user]' }, + oracle: { + text : 'SELECT DISTINCT("user"."id") FROM "user"', + string: 'SELECT DISTINCT("user"."id") FROM "user"' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]', string: 'SELECT COUNT(DISTINCT([user].[id])) AS [count] FROM [user]' }, + oracle: { + text : 'SELECT COUNT(DISTINCT("user"."id")) "count" FROM "user"', + string: 'SELECT COUNT(DISTINCT("user"."id")) "count" FROM "user"' + }, params: [] }); @@ -65,6 +73,10 @@ Harness.test({ text : 'SELECT DISTINCT [user].* FROM [user]', string: 'SELECT DISTINCT [user].* FROM [user]' }, + oracle: { + text : 'SELECT DISTINCT "user".* FROM "user"', + string: 'SELECT DISTINCT "user".* FROM "user"' + }, params: [] }); @@ -86,6 +98,10 @@ Harness.test({ text : 'SELECT DISTINCT [user].[id] FROM [user]', string: 'SELECT DISTINCT [user].[id] FROM [user]' }, + oracle: { + text : 'SELECT DISTINCT "user"."id" FROM "user"', + string: 'SELECT DISTINCT "user"."id" FROM "user"' + }, params: [] }); @@ -107,6 +123,10 @@ Harness.test({ text : 'SELECT DISTINCT [user].[id], [user].[name] FROM [user]', string: 'SELECT DISTINCT [user].[id], [user].[name] FROM [user]' }, + oracle: { + text : 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"', + string: 'SELECT DISTINCT "user"."id", "user"."name" FROM "user"' + }, params: [] }); diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index 7812ac69..eb183e64 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'DROP TABLE [post]', string: 'DROP TABLE [post]' }, + oracle: { + text : 'DROP TABLE "post"', + string: 'DROP TABLE "post"' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END', string: 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = [post]) BEGIN DROP TABLE [post] END' }, + oracle: { + text : 'BEGIN EXECUTE IMMEDIATE \'DROP TABLE "post"\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;', + string: 'BEGIN EXECUTE IMMEDIATE \'DROP TABLE "post"\'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;' + }, params: [] }); @@ -59,6 +67,10 @@ Harness.test({ text : 'DROP TABLE `post` CASCADE', string: 'DROP TABLE `post` CASCADE' }, + oracle: { + text : 'DROP TABLE "post" CASCADE CONSTRAINTS', + string: 'DROP TABLE "post" CASCADE CONSTRAINTS' + }, params: [] }); @@ -76,5 +88,9 @@ Harness.test({ text : 'DROP TABLE `post` RESTRICT', string: 'DROP TABLE `post` RESTRICT' }, + oracle: { + text : 'Oracle do not support RESTRICT in DROP TABLE', + throws: true + }, params: [] }); diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js index 2e486747..673087db 100644 --- a/test/dialects/from-clause-tests.js +++ b/test/dialects/from-clause-tests.js @@ -21,6 +21,10 @@ Harness.test({ mssql: { text : 'SELECT [user].* FROM [user] , [post]', string: 'SELECT [user].* FROM [user] , [post]' + }, + oracle: { + text : 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' } }); @@ -41,6 +45,10 @@ Harness.test({ mssql: { text : 'SELECT [user].*, [post].* FROM [user] , [post]', string: 'SELECT [user].*, [post].* FROM [user] , [post]' + }, + oracle: { + text : 'SELECT "user".*, "post".* FROM "user" , "post"', + string: 'SELECT "user".*, "post".* FROM "user" , "post"' } }); @@ -57,6 +65,10 @@ Harness.test({ mysql: { text : 'SELECT `user`.* FROM `user` , `post`', string: 'SELECT `user`.* FROM `user` , `post`' + }, + oracle: { + text : 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' } }); @@ -73,5 +85,9 @@ Harness.test({ mysql: { text : 'SELECT `user`.* FROM `user` , `post`', string: 'SELECT `user`.* FROM `user` , `post`' + }, + oracle: { + text : 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' } }); \ No newline at end of file diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index d0d4c1eb..673b5639 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]', string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId]' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, params: [] }); @@ -63,6 +71,10 @@ Harness.test({ text : 'SQL Server does not support array_agg.', throws: true }, + oracle: { + text : 'Oracle does not support array_agg.', + throws: true + }, params: [] }); @@ -84,6 +96,10 @@ Harness.test({ text : 'SQL Server does not support array_agg.', throws: true }, + oracle: { + text : 'Oracle does not support array_agg.', + throws: true + }, params: [] }); @@ -105,5 +121,9 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]', string: 'SELECT [post].[content] FROM [post] GROUP BY [post].[userId], [post].[id]' }, + oracel: { + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, params: [] }); diff --git a/test/dialects/having-tests.js b/test/dialects/having-tests.js index ad315c6e..5f8f9cc7 100644 --- a/test/dialects/having-tests.js +++ b/test/dialects/having-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10)' }, + oracle: { + text : 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1)', + string: 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10)' + }, params: [10] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' }, + oracle: { + text : 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1) AND ("post"."userId" < :2)', + string: 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, params: [10, 100] }); @@ -63,5 +71,9 @@ Harness.test({ text : 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > @1) AND ([post].[userId] < @2)', string: 'SELECT [post].[userId], COUNT([post].[content]) AS [content_count] FROM [post] GROUP BY [post].[userId] HAVING ([post].[userId] > 10) AND ([post].[userId] < 100)' }, + oracle: { + text : 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > :1) AND ("post"."userId" < :2)', + string: 'SELECT "post"."userId", COUNT("post"."content") "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > 10) AND ("post"."userId" < 100)' + }, params: [10, 100] }); diff --git a/test/dialects/in-clause-tests.js b/test/dialects/in-clause-tests.js index 374ca6fd..513c7243 100644 --- a/test/dialects/in-clause-tests.js +++ b/test/dialects/in-clause-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE (1=0)', string: 'SELECT [post].* FROM [post] WHERE (1=0)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE (1=0)', + string: 'SELECT "post".* FROM "post" WHERE (1=0)' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1))', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' + }, params: [1] }); @@ -63,6 +71,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, params: [] }); @@ -84,6 +96,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2))', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' + }, params: [1, 2] }); @@ -105,6 +121,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NULL)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, params: [] }); @@ -126,6 +146,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, params: [1, 2] }); @@ -147,5 +171,9 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (@1, @2) OR [post].[id] IS NULL)', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IN (1, 2) OR [post].[id] IS NULL)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (:1, :2) OR "post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2) OR "post"."id" IS NULL)' + }, params: [1, 2] }); diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index b950e832..a32c235f 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'PRAGMA INDEX_LIST("post")', string: 'PRAGMA INDEX_LIST("post")' }, + oracle: { + text : 'SELECT * FROM USER_INDEXES WHERE TABLE_NAME = \'post\'', + string: 'SELECT * FROM USER_INDEXES WHERE TABLE_NAME = \'post\'' + }, params: [] }); @@ -34,6 +38,10 @@ Harness.test({ text : 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' }, + oracle: { + text : 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', + string: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo' + }, params: [] }); @@ -85,6 +93,10 @@ Harness.test({ text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' }, + oracle: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, params: [] }); @@ -102,6 +114,10 @@ Harness.test({ text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' }, + oracle: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, params: [] }); @@ -118,6 +134,10 @@ Harness.test({ sqlite: { text : 'No columns defined!', throws: true + }, + oracle: { + text : 'No columns defined!', + throws: true } }); @@ -135,6 +155,10 @@ Harness.test({ text : 'DROP INDEX "public"."index_name"', string: 'DROP INDEX "public"."index_name"' }, + oracle: { + text : 'DROP INDEX "index_name"', + string: 'DROP INDEX "index_name"' + }, params: [] }); @@ -152,5 +176,9 @@ Harness.test({ text : 'DROP INDEX "public"."post_id_userId"', string: 'DROP INDEX "public"."post_id_userId"' }, + oracle: { + text : 'DROP INDEX "post_id_userId"', + string: 'DROP INDEX "post_id_userId"' + }, params: [] }); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 6685e6f6..b472f51d 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -18,6 +18,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 1)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, params: ['test', 1] }); @@ -35,6 +39,14 @@ Harness.test({ text : 'INSERT INTO `post` (`content`) VALUES (?)', string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\')' }, + mssql: { + text : 'INSERT INTO [post] ([content]) VALUES (@1)', + string: 'INSERT INTO [post] ([content]) VALUES (\'whoah\')' + }, + oracle: { + text : 'INSERT INTO "post" ("content") VALUES (:1)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' + }, params: ['whoah'] }); @@ -55,6 +67,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 2)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, params: ['test', 2] }); @@ -75,6 +91,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(?), ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(\'TEST\'), 2)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(:1), :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, params: ['TEST', 2] }); @@ -98,6 +118,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`) VALUES (?), (?)', string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\'), (\'hey\')' }, + oracle: { + text : 'INSERT INTO "post" ("content") VALUES (:1), (:2)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, params: ['whoah', 'hey'] }); @@ -122,6 +146,10 @@ Harness.test({ text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, :4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, params: ['whoah', 1, 'hey', 2] }); @@ -151,6 +179,10 @@ Harness.test({ text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, @4)', string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'whoah\', 1), (\'hey\', 2)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, :4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, params: ['whoah', 1, 'hey', 2] }); @@ -172,6 +204,10 @@ Harness.test({ text : 'INSERT INTO [post] DEFAULT VALUES', string: 'INSERT INTO [post] DEFAULT VALUES' }, + oracle: { + text : 'INSERT INTO "post" DEFAULT VALUES', + string: 'INSERT INTO "post" DEFAULT VALUES' + }, params: [] }); @@ -190,6 +226,9 @@ Harness.test({ mssql: { throws: true }, + oracle: { + throws: true + }, params: [] }); @@ -208,6 +247,9 @@ Harness.test({ mssql: { throws: true }, + oracle: { + throws: true + }, params: [] }); @@ -226,6 +268,9 @@ Harness.test({ mssql: { throws: true }, + oracle: { + throws: true + }, params: [] }); @@ -244,6 +289,9 @@ Harness.test({ mssql: { throws: true }, + oracle: { + throws: true + }, params: [] }); @@ -262,6 +310,9 @@ Harness.test({ mssql: { throws: true }, + oracle: { + throws: true + }, params: [] }); @@ -292,7 +343,12 @@ Harness.test({ text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2), (@3, DEFAULT)', string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', params: ['whoah', 1, 'hey'] - } + }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2), (:3, DEFAULT)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', + params: ['whoah', 1, 'hey'] + }, }); Harness.test({ @@ -321,6 +377,11 @@ Harness.test({ text : 'INSERT INTO [post] ([userId], [content]) VALUES (@1, DEFAULT), (@2, @3)', string: 'INSERT INTO [post] ([userId], [content]) VALUES (1, DEFAULT), (2, \'hey\')', params: [1, 2, 'hey'] + }, + oracle: { + text : 'INSERT INTO "post" ("userId", "content") VALUES (:1, DEFAULT), (:2, :3)', + string: 'INSERT INTO "post" ("userId", "content") VALUES (1, DEFAULT), (2, \'hey\')', + params: [1, 2, 'hey'] } }); @@ -343,6 +404,10 @@ Harness.test({ text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)', string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE \'A%\')' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, params: ['A%'] }); @@ -365,6 +430,10 @@ Harness.test({ text : 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE @1)', string: 'INSERT INTO [post] ([content], [userId]) SELECT \'test\', [user].[id] FROM [user] WHERE ([user].[name] LIKE \'A%\')' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', + string: 'INSERT INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, params: ['A%'] }); @@ -383,6 +452,10 @@ Harness.test({ text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE :1)', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, params: ['A%'] }); @@ -405,6 +478,10 @@ Harness.test({ text : 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE @1)', string: 'INSERT INTO [post] ([userId]) SELECT [post].[userId] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) WHERE ([post].[tags] LIKE \'A%\')' }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE :1)', + string: 'INSERT INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, params: ['A%'] }); @@ -426,6 +503,10 @@ Harness.test({ text : 'INSERT INTO [post] ([userId]) SELECT DISTINCT [user].[id] FROM [user]', string: 'INSERT INTO [post] ([userId]) SELECT DISTINCT [user].[id] FROM [user]' }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' + }, params: [] }); @@ -448,6 +529,10 @@ Harness.test({ text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'\\x74657374\', 2)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'74657374\')), 2)' + }, params: [new Buffer('test'), 2] }); @@ -472,6 +557,10 @@ Harness.test({ text : 'INSERT INTO [post] ([content], [userId]) VALUES (@1, @2)', string: 'INSERT INTO [post] ([content], [userId]) VALUES (\'\\x74657374\', 2)' }, + oracle: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (:1, :2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'74657374\')), 2)' + }, params: [new Buffer('test'), 2] }); @@ -499,6 +588,10 @@ Harness.test({ text : 'INSERT INTO [post] ([content]) VALUES (@1), (@2)', string: 'INSERT INTO [post] ([content]) VALUES (\'\\x77686f6168\'), (\'\\x686579\')' }, + oracle: { + text : 'INSERT INTO "post" ("content") VALUES (:1), (:2)', + string: 'INSERT INTO "post" ("content") VALUES (utl_raw.cast_to_varchar2(hextoraw(\'77686f6168\'))), (utl_raw.cast_to_varchar2(hextoraw(\'686579\')))' + }, params: [new Buffer('whoah'), new Buffer('hey')] }); @@ -522,6 +615,9 @@ Harness.test({ mssql: { throws: true }, + oracle: { + throws: true + }, params: ['test', 2, 'testupdate'] }); diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index bd5fc3b6..abebdb01 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -23,6 +23,10 @@ Harness.test({ text : 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', string: 'SELECT [user].[name], [post].[content] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' }, + oracle: { + text : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, params: [] }); @@ -44,6 +48,10 @@ Harness.test({ text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])', string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[userId])' }, + oracle: { + text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, params: [] }); @@ -70,6 +78,10 @@ Harness.test({ text : 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])', string: 'SELECT [user].[name], [post].[content], [comment].[text] FROM [user] INNER JOIN [post] ON ([user].[id] = [post].[userId]) INNER JOIN [comment] ON ([post].[id] = [comment].[postId])' }, + oracle: { + text : 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: 'SELECT "user"."name", "post"."content", "comment"."text" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") INNER JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, params: [] }); @@ -91,6 +103,10 @@ Harness.test({ text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])', string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId])' }, + oracle: { + text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + }, params: [] }); @@ -117,6 +133,10 @@ Harness.test({ text : 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])', string: 'SELECT [user].[name], [post].[content] FROM [user] LEFT JOIN [post] ON ([user].[id] = [post].[userId]) LEFT JOIN [comment] ON ([post].[id] = [comment].[postId])' }, + oracle: { + text : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + string: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' + }, params: [] }); @@ -148,5 +168,9 @@ Harness.test({ text : 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])', string: 'SELECT [user].[name], [subposts].[content] FROM [user] INNER JOIN (SELECT [post].[content], [post].[userId] AS [subpostUserId] FROM [post]) [subposts] ON ([user].[id] = [subposts].[subpostUserId])' }, + oracle: { + text : 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")', + string: 'SELECT "user"."name", "subposts"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" "subpostUserId" FROM "post") "subposts" ON ("user"."id" = "subposts"."subpostUserId")' + }, params: [] }); diff --git a/test/dialects/join-to-tests.js b/test/dialects/join-to-tests.js index e2d98cf0..d50f8817 100644 --- a/test/dialects/join-to-tests.js +++ b/test/dialects/join-to-tests.js @@ -54,6 +54,10 @@ Harness.test({ text : '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])', string: '[user] INNER JOIN [post] ON ([user].[id] = [post].[ownerId])' }, + oracle: { + text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' + }, params: [] }); @@ -75,6 +79,10 @@ Harness.test({ text : '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])', string: '[post] INNER JOIN [user] ON ([user].[id] = [post].[ownerId])' }, + oracle: { + text : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' + }, params: [] }); @@ -96,5 +104,9 @@ Harness.test({ text : '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])', string: '[user] INNER JOIN [photo] ON ([user].[id] = [photo].[ownerId])' }, + oracle: { + text : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' + }, params: [] }); diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js index 39ffc7d6..6561c14b 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -66,6 +66,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS', string: 'SELECT [user].* FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS' }, + oracle: { + text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS' + }, params: [] }); @@ -91,6 +95,10 @@ Harness.test({ text : 'Microsoft SQL Server does not support OFFSET without and ORDER BY.', throws: true }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."name" = :1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = :2)) ROWS FETCH NEXT 1 ROWS ONLY', + string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) ROWS FETCH NEXT 1 ROWS ONLY' + }, values: ['John', 'John'] }); diff --git a/test/dialects/literal-tests.js b/test/dialects/literal-tests.js index 424bedcf..c31d4271 100644 --- a/test/dialects/literal-tests.js +++ b/test/dialects/literal-tests.js @@ -17,6 +17,10 @@ Harness.test({ text : 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`', string: 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`' }, + oracle: { + text : 'SELECT foo, "user"."name", 123 "onetwothree" FROM "user"', + string: 'SELECT foo, "user"."name", 123 "onetwothree" FROM "user"' + }, params: [] }); @@ -35,6 +39,10 @@ Harness.test({ text : 'SELECT `user`.* FROM `user` WHERE foo = bar', string: 'SELECT `user`.* FROM `user` WHERE foo = bar' }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE foo = bar', + string: 'SELECT "user".* FROM "user" WHERE foo = bar' + }, params: [] }); @@ -56,5 +64,9 @@ Harness.test({ text : 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`', string: 'SELECT COUNT(`subquery_for_count`.`count_column`) AS `count_column_count` FROM (SELECT 1 AS `count_column` FROM `user` LIMIT 10 OFFSET 20) `subquery_for_count`' }, + oracle: { + text : 'SELECT COUNT("subquery_for_count"."count_column") "count_column_count" FROM (SELECT 1 "count_column" FROM "user" OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY) "subquery_for_count"', + string: 'SELECT COUNT("subquery_for_count"."count_column") "count_column_count" FROM (SELECT 1 "count_column" FROM "user" OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY) "subquery_for_count"' + }, params: [] }); diff --git a/test/dialects/matches-test.js b/test/dialects/matches-test.js index 4ce21406..c385641c 100644 --- a/test/dialects/matches-test.js +++ b/test/dialects/matches-test.js @@ -30,6 +30,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], @1))', string: 'SELECT [post].* FROM [post] WHERE (CONTAINS ([post].[content], \'hello\'))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE (INSTR ("post"."content", :1) > 0)', + string: 'SELECT "post".* FROM "post" WHERE (INSTR ("post"."content", \'hello\') > 0)' + }, params: ['hello'] }); diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 9954c3f7..5f6b4a56 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -24,6 +24,10 @@ Harness.test({ text : 'SELECT [u].[name] FROM [user] AS [u]', string: 'SELECT [u].[name] FROM [user] AS [u]' }, + oracle: { + text : 'SELECT "u"."name" FROM "user" "u"', + string: 'SELECT "u"."name" FROM "user" "u"' + }, params: [] }); @@ -45,6 +49,10 @@ Harness.test({ text : 'SELECT [u].* FROM [user] AS [u]', string: 'SELECT [u].* FROM [user] AS [u]' }, + oracle: { + text : 'SELECT "u".* FROM "user" "u"', + string: 'SELECT "u".* FROM "user" "u"' + }, params: [] }); @@ -67,6 +75,10 @@ Harness.test({ text : 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = @1))', string: 'SELECT [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[id] = 3))' }, + oracle: { + text : 'SELECT "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = :1))', + string: 'SELECT "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = 3))' + }, params: [3] }); @@ -88,6 +100,10 @@ Harness.test({ text : 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))', string: 'SELECT [p].[content], [u].[name] FROM [user] AS [u] INNER JOIN [post] AS [p] ON (([u].[id] = [p].[userId]) AND ([p].[content] IS NOT NULL))' }, + oracle: { + text : 'SELECT "p"."content", "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))', + string: 'SELECT "p"."content", "u"."name" FROM "user" "u" INNER JOIN "post" "p" ON (("u"."id" = "p"."userId") AND ("p"."content" IS NOT NULL))' + }, params: [] }); @@ -122,5 +138,9 @@ Harness.test({ text : 'SELECT [comment].[text], [comment].[userId] FROM [comment]', string: 'SELECT [comment].[text], [comment].[userId] FROM [comment]' }, + orcle: { + text : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + }, params: [] }); diff --git a/test/dialects/not-in-clause-tests.js b/test/dialects/not-in-clause-tests.js index a16c8887..11647fee 100644 --- a/test/dialects/not-in-clause-tests.js +++ b/test/dialects/not-in-clause-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE (1=1)', string: 'SELECT [post].* FROM [post] WHERE (1=1)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE (1=1)', + string: 'SELECT "post".* FROM "post" WHERE (1=1)' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1))', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (:1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' + }, params: [1] }); @@ -63,6 +71,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, params: [] }); @@ -84,6 +96,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (@1, @2))', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] NOT IN (1, 2))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (:1, :2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' + }, params: [1, 2] }); @@ -105,6 +121,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)', string: 'SELECT [post].* FROM [post] WHERE ([post].[id] IS NOT NULL)' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, params: [] }); @@ -126,6 +146,10 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (:1, :2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, params: [1, 2] }); @@ -147,5 +171,9 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (@1, @2) OR [post].[id] IS NULL))', string: 'SELECT [post].* FROM [post] WHERE (NOT ([post].[id] IN (1, 2) OR [post].[id] IS NULL))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (:1, :2) OR "post"."id" IS NULL))', + string: 'SELECT "post".* FROM "post" WHERE (NOT ("post"."id" IN (1, 2) OR "post"."id" IS NULL))' + }, params: [1, 2] }); diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 107f0da4..888f27f3 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, params: [] }); @@ -43,6 +47,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, params: [] }); @@ -64,6 +72,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, params: [] }); @@ -85,6 +97,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, params: [] }); @@ -106,6 +122,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC', string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content], [post].[userId] DESC' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC' + }, params: [] }); @@ -127,6 +147,10 @@ Harness.test({ text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' }, + oracle: { + text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, params: [] }); @@ -148,6 +172,10 @@ Harness.test({ text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC', string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL) DESC' }, + oracle: { + text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL) DESC' + }, params: [] }); @@ -169,6 +197,10 @@ Harness.test({ text : 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)', string: 'SELECT ([post].[content] IS NULL) FROM [post] ORDER BY ([post].[content] IS NULL)' }, + oracle: { + text : 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)', + string: 'SELECT ("post"."content" IS NULL) FROM "post" ORDER BY ("post"."content" IS NULL)' + }, params: [] }); @@ -190,6 +222,10 @@ Harness.test({ text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])', string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content])' }, + oracle: { + text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' + }, params: [] }); @@ -211,5 +247,9 @@ Harness.test({ text : 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC', string: 'SELECT RTRIM([post].[content]) FROM [post] ORDER BY RTRIM([post].[content]) DESC' }, + oracle: { + text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content") DESC' + }, params: [] }); diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index 417037f5..11e330da 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -28,6 +28,10 @@ Harness.test({ text : 'SELECT [staging].[user].[id] FROM [staging].[user]', string: 'SELECT [staging].[user].[id] FROM [staging].[user]' }, + oracle: { + text : 'SELECT "staging"."user"."id" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id" FROM "staging"."user"' + }, params: [] }); @@ -49,6 +53,10 @@ Harness.test({ text : 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]', string: 'SELECT COUNT([staging].[user].[id]) AS [id_count] FROM [staging].[user]' }, + oracle: { + text : 'SELECT COUNT("staging"."user"."id") "id_count" FROM "staging"."user"', + string: 'SELECT COUNT("staging"."user"."id") "id_count" FROM "staging"."user"' + }, params: [] }); @@ -70,6 +78,10 @@ Harness.test({ text : 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]', string: 'SELECT [staging].[user].[id], [staging].[user].[name] FROM [staging].[user]' }, + oracle: { + text : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + }, params: [] }); @@ -92,6 +104,10 @@ Harness.test({ text : 'SELECT [uws].[name] FROM [staging].[user] AS [uws]', string: 'SELECT [uws].[name] FROM [staging].[user] AS [uws]' }, + oracle: { + text : 'SELECT "uws"."name" FROM "staging"."user" "uws"', + string: 'SELECT "uws"."name" FROM "staging"."user" "uws"' + }, params: [] }); @@ -119,6 +135,10 @@ Harness.test({ text : 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])', string: 'SELECT [staging].[user].[name], [dev].[post].[content] FROM [staging].[user] INNER JOIN [dev].[post] ON ([staging].[user].[id] = [dev].[post].[userId])' }, + oracle: { + text : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + string: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' + }, params: [] }); @@ -140,5 +160,9 @@ Harness.test({ text : 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])', string: 'SELECT [uws].[name], [dev].[post].[content] FROM [staging].[user] AS [uws] INNER JOIN [dev].[post] ON ([uws].[id] = [dev].[post].[userId])' }, + oracle: { + text : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + string: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")' + }, params: [] }); diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 37ba87de..59fdd786 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'SELECT [post].[id], [post].[content] FROM [post]', string: 'SELECT [post].[id], [post].[content] FROM [post]' }, + oracle: { + text : 'SELECT "post"."id", "post"."content" FROM "post"', + string: 'SELECT "post"."id", "post"."content" FROM "post"' + }, params: [] }); @@ -39,5 +43,13 @@ Harness.test({ text : 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`', string: 'SELECT `customer`.`id` AS `id_alias`, `customer`.`name` AS `name_alias`, `customer`.`age` AS `age_alias`, `customer`.`income` AS `income_alias`, `customer`.`metadata` AS `metadata_alias` FROM `customer`' }, + mssql: { + text : 'SELECT [customer].[id] AS [id_alias], [customer].[name] AS [name_alias], [customer].[age] AS [age_alias], [customer].[income] AS [income_alias], [customer].[metadata] AS [metadata_alias] FROM [customer]', + string: 'SELECT [customer].[id] AS [id_alias], [customer].[name] AS [name_alias], [customer].[age] AS [age_alias], [customer].[income] AS [income_alias], [customer].[metadata] AS [metadata_alias] FROM [customer]' + }, + oracle: { + text : 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"', + string: 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"' + }, params: [] }); \ No newline at end of file diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 1c6efc2c..35c9a90b 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -23,6 +23,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user]', string: 'SELECT [user].* FROM [user]' }, + oracle: { + text : 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, params: [] }); @@ -44,6 +48,10 @@ Harness.test({ text : 'SELECT * FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT * FROM [user] WHERE ([user].[name] = 3)' }, + oracle: { + text : 'SELECT * FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' + }, params: [3] }); @@ -65,6 +73,10 @@ Harness.test({ text : 'SELECT * FROM [user] WHERE (([user].[name] = @1) AND ([user].[id] = @2))', string: 'SELECT * FROM [user] WHERE (([user].[name] = 3) AND ([user].[id] = 1))' }, + oracle: { + text : 'SELECT * FROM "user" WHERE (("user"."name" = :1) AND ("user"."id" = :2))', + string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' + }, params: [3, 1] }); @@ -87,6 +99,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post]', string: 'SELECT [post].[content] FROM [post]' }, + oracle: { + text : 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, params: [] }); @@ -108,6 +124,10 @@ Harness.test({ text : 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = @1)', string: 'SELECT [post].[content] FROM [post] WHERE ([post].[userId] = 1)' }, + oracle: { + text : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = :1)', + string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' + }, params: [1] }); @@ -133,5 +153,9 @@ Harness.test({ text : 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = @1)) AND ([post].[userId] = @2))', string: 'SELECT * FROM [post] WHERE ((([post].[content] IS NULL) OR ([post].[content] = \'\')) AND ([post].[userId] = 1))' }, + oracle: { + text : 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = :1)) AND ("post"."userId" = :2))', + string: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = \'\')) AND ("post"."userId" = 1))' + }, params: ['', 1] }); diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 89e141b1..2d5df342 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -27,6 +27,10 @@ Harness.test({ text : '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE @1)))))', string: '([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] IN (SELECT [customer].[name] FROM [customer] WHERE ([user].[name] LIKE \'%HELLO%\')))))' }, + oracle: { + text : '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE :1)))))', + string: '("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" IN (SELECT "customer"."name" FROM "customer" WHERE ("user"."name" LIKE \'%HELLO%\')))))' + }, params: ['%HELLO%'] }); @@ -48,6 +52,10 @@ Harness.test({ text : 'SELECT * FROM (SELECT * FROM [user])', string: 'SELECT * FROM (SELECT * FROM [user])' }, + oracle: { + text : 'SELECT * FROM (SELECT * FROM "user")', + string: 'SELECT * FROM (SELECT * FROM "user")' + }, params: [] }); @@ -69,6 +77,10 @@ Harness.test({ text : 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]', string: 'SELECT * FROM (SELECT * FROM [customer]) [T1] , (SELECT * FROM [user]) [T2]' }, + oracle: { + text : 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"', + string: 'SELECT * FROM (SELECT * FROM "customer") "T1" , (SELECT * FROM "user") "T2"' + }, params: [] }); @@ -93,6 +105,10 @@ Harness.test({ text : '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))', string: '([customer].[name] BETWEEN (SELECT MIN([customer].[name]) FROM [customer]) AND (SELECT MAX([customer].[name]) FROM [customer]))' }, + oracle: { + text : '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))', + string: '("customer"."name" BETWEEN (SELECT MIN("customer"."name") FROM "customer") AND (SELECT MAX("customer"."name") FROM "customer"))' + }, params: [] }); @@ -114,5 +130,9 @@ Harness.test({ text : '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))', string: '(EXISTS (SELECT * FROM [user] WHERE ([user].[name] = [customer].[name])))' }, + oracle: { + text : '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', + string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' + }, params: [] }); diff --git a/test/dialects/support.js b/test/dialects/support.js index e95e3175..e8c68837 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -8,7 +8,8 @@ var dialects = { pg : require('../../lib/dialect/postgres'), sqlite : require('../../lib/dialect/sqlite'), mysql : require('../../lib/dialect/mysql'), - mssql : require('../../lib/dialect/mssql') + mssql : require('../../lib/dialect/mssql'), + oracle : require('../../lib/dialect/oracle') }; module.exports = { diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 26c5d26d..6740a7c8 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user]', string: 'SELECT [user].[id] FROM [user]' }, + oracle: { + text : 'SELECT "user"."id" FROM "user"', + string: 'SELECT "user"."id" FROM "user"' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT [user].[id], [user].[name] FROM [user]', string: 'SELECT [user].[id], [user].[name] FROM [user]' }, + oracle: { + text : 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, params: [] }); @@ -63,6 +71,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user]', string: 'SELECT [user].* FROM [user]' }, + oracle: { + text : 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, params: [] }); @@ -80,6 +92,10 @@ Harness.test({ text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, params: [] }); @@ -97,6 +113,10 @@ Harness.test({ text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, params: [] }); @@ -114,6 +134,10 @@ Harness.test({ text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, + oracle: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, params: [] }); @@ -131,6 +155,10 @@ Harness.test({ text: 'SELECT `user`.*, `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name`, `user`.`id` AS `bar_id`, `user`.`name` AS `bar_name` FROM `user`', string: 'SELECT `user`.*, `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name`, `user`.`id` AS `bar_id`, `user`.`name` AS `bar_name` FROM `user`' }, + oracle: { + text: 'SELECT "user".*, "user"."id" "foo_id", "user"."name" "foo_name", "user"."id" "bar_id", "user"."name" "bar_name" FROM "user"', + string: 'SELECT "user".*, "user"."id" "foo_id", "user"."name" "foo_name", "user"."id" "bar_id", "user"."name" "bar_name" FROM "user"' + }, params: [] }); @@ -152,6 +180,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] = \'foo\')' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' + }, params: ['foo'] }); @@ -173,6 +205,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) OR ("user"."name" = :2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -194,6 +230,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) AND ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') AND ([user].[name] = \'bar\'))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) AND ("user"."name" = :2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') AND ("user"."name" = \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -215,6 +255,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] = \'foo\') OR ([user].[name] = \'bar\'))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = :1) OR ("user"."name" = :2))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = \'foo\') OR ("user"."name" = \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -236,6 +280,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) OR ([user].[name] = @2)) AND ([user].[name] = @3))', string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'foo\') OR ([user].[name] = \'baz\')) AND ([user].[name] = \'bar\'))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = :1) OR ("user"."name" = :2)) AND ("user"."name" = :3))', + string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'foo\') OR ("user"."name" = \'baz\')) AND ("user"."name" = \'bar\'))' + }, params: ['foo', 'baz', 'bar'] }); @@ -257,6 +305,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (@1, @2))', string: 'SELECT [user].[id] FROM [user] WHERE ([user].[name] IN (\'foo\', \'bar\'))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (:1, :2))', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' + }, params: ['foo', 'bar'] }); @@ -278,6 +330,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (@1, @2)) AND ([user].[id] = @3))', string: 'SELECT [user].[id] FROM [user] WHERE (([user].[name] IN (\'foo\', \'bar\')) AND ([user].[id] = 1))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (:1, :2)) AND ("user"."id" = :3))', + string: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN (\'foo\', \'bar\')) AND ("user"."id" = 1))' + }, params: ['foo', 'bar', 1] }); @@ -299,6 +355,10 @@ Harness.test({ text : 'SELECT [user].[id], [user].[name] FROM [user]', string: 'SELECT [user].[id], [user].[name] FROM [user]' }, + oracle: { + text : 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, params: [] }); @@ -327,6 +387,10 @@ Harness.test({ text : 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = @1) AND ([user].[id] = @2)) OR (([user].[name] = @3) AND ([user].[id] = @4)))', string: 'SELECT [user].[id] FROM [user] WHERE ((([user].[name] = \'boom\') AND ([user].[id] = 1)) OR (([user].[name] = \'bang\') AND ([user].[id] = 2)))' }, + oracle: { + text : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = :1) AND ("user"."id" = :2)) OR (("user"."name" = :3) AND ("user"."id" = :4)))', + string: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = \'boom\') AND ("user"."id" = 1)) OR (("user"."name" = \'bang\') AND ("user"."id" = 2)))' + }, params: ['boom', 1, 'bang', 2] }); @@ -348,6 +412,10 @@ Harness.test({ text : 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]', string: 'SELECT [user].[name] AS [user name], [user].[id] AS [user id] FROM [user]' }, + oracle: { + text : 'SELECT "user"."name" "user name", "user"."id" "user id" FROM "user"', + string: 'SELECT "user"."name" "user name", "user"."id" "user id" FROM "user"' + }, params: [] }); @@ -365,10 +433,14 @@ Harness.test({ text : 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, - sqlsever: { + mssql: { text : 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[name] AS [user name] FROM [user] WHERE ([user].[name] = \'brian\')' }, + oracle: { + text : 'SELECT "user"."name" "user name" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."name" "user name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, params: ['brian'] }); @@ -390,6 +462,10 @@ Harness.test({ text : 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = @1)', string: 'SELECT [user].[name] FROM [user] WHERE ([user].[name] = \'brian\')' }, + oracle: { + text : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = :1)', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, params: ['brian'] }); @@ -411,6 +487,10 @@ Harness.test({ text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, + oracle: { + text : 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, params: [] }); @@ -432,6 +512,10 @@ Harness.test({ text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, + oracle: { + text : 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, params: [] }); @@ -453,6 +537,10 @@ Harness.test({ text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, + oracle: { + text : 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, params: [] }); @@ -474,6 +562,10 @@ Harness.test({ text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' }, + oracle: { + text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, params: [] }); @@ -497,6 +589,10 @@ Harness.test({ text : 'SELECT name FROM user WHERE ([user].[name] = @1)', string: 'SELECT name FROM user WHERE ([user].[name] = \'brian\')' }, + oracle: { + text : 'SELECT name FROM user WHERE ("user"."name" = :1)', + string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' + }, params: ['brian'] }); @@ -521,6 +617,10 @@ Harness.test({ text : 'SELECT name FROM user WHERE (([user].[name] = @1) AND ([user].[id] = @2))', string: 'SELECT name FROM user WHERE (([user].[name] = \'brian\') AND ([user].[id] = 1))' }, + oracle: { + text : 'SELECT name FROM user WHERE (("user"."name" = :1) AND ("user"."id" = :2))', + string: 'SELECT name FROM user WHERE (("user"."name" = \'brian\') AND ("user"."id" = 1))' + }, params: ['brian', 1] }); @@ -542,6 +642,10 @@ Harness.test({ text : 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]', string: 'SELECT [user].[name] AS [quote"quote"tick`tick`] FROM [user]' }, + oracle: { + text : 'SELECT "user"."name" "quote""quote""tick`tick`" FROM "user"', + string: 'SELECT "user"."name" "quote""quote""tick`tick`" FROM "user"' + }, params: [] }); @@ -563,5 +667,9 @@ Harness.test({ text : 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))', string: 'SELECT [user].* FROM [user] WHERE ([user].[id] IN (SELECT [user].[id] FROM [user]))' }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))' + }, params: [] }); diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js index 60c369b8..04832fbc 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN @1 AND @2)', string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] BETWEEN 18 AND 25)' }, + oracle: { + text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN :1 AND :2)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' + }, params: [18, 25] }); @@ -43,5 +47,9 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))', string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] BETWEEN (SELECT MIN([customer].[id]) AS [id_min] FROM [customer]) AND (SELECT MAX([customer].[id]) AS [id_max] FROM [customer]))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") "id_min" FROM "customer") AND (SELECT MAX("customer"."id") "id_max" FROM "customer"))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" BETWEEN (SELECT MIN("customer"."id") "id_min" FROM "customer") AND (SELECT MAX("customer"."id") "id_max" FROM "customer"))' + }, params: [] }); diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index 47b60367..8b9763b4 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -23,6 +23,10 @@ Harness.test({ text : '([post].[content] = @1)', string: '([post].[content] = NULL)' }, + oracle: { + text : '("post"."content" = :1)', + string: '("post"."content" = NULL)' + }, params: [null] }); @@ -45,6 +49,10 @@ Harness.test({ text : '([post].[content] = @1)', string: '([post].[content] = 3.14)' }, + oracle: { + text : '("post"."content" = :1)', + string: '("post"."content" = 3.14)' + }, params: [3.14] }); @@ -67,6 +75,10 @@ Harness.test({ text : '([post].[content] = @1)', string: '([post].[content] = \'hello\'\'\')' }, + oracle: { + text : '("post"."content" = :1)', + string: '("post"."content" = \'hello\'\'\')' + }, params: ['hello\''] }); @@ -89,6 +101,10 @@ Harness.test({ text : 'SQL Server does not support arrays.', throws: true }, + oracle: { + text : 'SQL Server does not support arrays.', + throws: true + }, params: [1, '2', null] }); diff --git a/test/index-tests.js b/test/index-tests.js index e5076f17..0893a7ef 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -30,6 +30,11 @@ suite('index', function() { test('stores the mssql dialect', function() { assert.equal(sql.create('mssql').dialectName, 'mssql'); }); + + test('stores the oracle dialect', function() { + assert.equal(sql.create('oracle').dialectName, 'oracle'); + }); + test('can create a query using the default dialect', function() { var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); @@ -56,16 +61,19 @@ suite('index', function() { var mysql = sql.create('mysql'); var postgres = sql.create('postgres'); var sqlite = sql.create('sqlite'); + var oracle = sql.create('oracle'); var mssqlTable = mssql.define({name: 'table', columns: ['column']}); var mysqlTable = mysql.define({name: 'table', columns: ['column']}); var postgresTable = postgres.define({name: 'table', columns: ['column']}); var sqliteTable = sqlite.define({name: 'table', columns: ['column']}); + var oracleTable = oracle.define({name: 'table', columns: ['column']}); assert.equal(mysqlTable.sql, mysql); assert.equal(postgresTable.sql, postgres); assert.equal(sqliteTable.sql, sqlite); assert.equal(mssqlTable.sql, mssql); + assert.equal(oracleTable.sql, oracle); }); test('using Sql as a class', function() { @@ -74,11 +82,13 @@ suite('index', function() { var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); + var oracle = new Sql('oracle'); assert.equal(mysql.dialect, require(__dirname + '/../lib/dialect/mysql')); assert.equal(postgres.dialect, require(__dirname + '/../lib/dialect/postgres')); assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); assert.equal(mssql.dialect, require(__dirname + '/../lib/dialect/mssql')); + assert.equal(oracle.dialect, require(__dirname + '/../lib/dialect/oracle')); }); test('override dialect for toQuery using dialect name', function() { @@ -87,11 +97,13 @@ suite('index', function() { var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); + var oracle = new Sql('oracle'); var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('sqlite'); var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('postgres'); var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mysql'); var mssqlQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('mssql'); + var oracleQuery = oracle.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery('oracle'); var values = ['brian.m.carlson@gmail.com']; assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); @@ -105,6 +117,9 @@ suite('index', function() { assert.equal(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); assert.deepEqual(mssqlQuery.values, values); + + assert.equal(oracleQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = :1)'); + assert.deepEqual(oracleQuery.values, values); }); test('override dialect for toQuery using invalid dialect name', function() { @@ -140,10 +155,15 @@ suite('index', function() { var mysql = new Sql('mysql'); var postgres = new Sql('postgres'); var sqlite = new Sql('sqlite'); + var mssql = new Sql('mssql'); + var oracle = new Sql('oracle'); var sqliteQuery = mysql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','sqlite'); var postgresQuery = sqlite.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','postgres'); var mysqlQuery = postgres.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','mysql'); + var oracleQuery = mssql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','oracle'); + var mssqlQuery = oracle.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('user.select_brian','mssql'); + var values = ['brian.m.carlson@gmail.com']; assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); @@ -157,6 +177,14 @@ suite('index', function() { assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); assert.deepEqual(mysqlQuery.values, values); assert.equal('user.select_brian', mysqlQuery.name); + + assert.equal(mssqlQuery.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); + assert.deepEqual(mssqlQuery.values, values); + assert.equal('user.select_brian', mssqlQuery.name); + + assert.equal(oracleQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = :1)'); + assert.deepEqual(oracleQuery.values, values); + assert.equal('user.select_brian', oracleQuery.name); }); From 2751e77264f75dfc101a7313cfec27ee11ab904c Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Tue, 21 Jul 2015 10:19:54 -0300 Subject: [PATCH 124/248] oracle dialect implementaion complete --- test/dialects/tostring-tests.js | 8 +++++++ test/dialects/truncate-table-tests.js | 4 ++++ test/dialects/unary-clause-tests.js | 8 +++++++ test/dialects/update-tests.js | 28 ++++++++++++++++++++++ test/dialects/value-expression-tests.js | 20 ++++++++++++++++ test/dialects/where-clause-tests.js | 32 +++++++++++++++++++++++++ 6 files changed, 100 insertions(+) diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index 8b9763b4..215cb05b 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -127,6 +127,10 @@ Harness.test({ text : '([post].[content] = @1)', string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' }, + oracle: { + text : '("post"."content" = :1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] }); @@ -155,6 +159,10 @@ Harness.test({ text : '([post].[content] = @1)', string: '([post].[content] = \'secretMessage\')' }, + oracle: { + text : '("post"."content" = :1)', + string: '("post"."content" = \'secretMessage\')' + }, params: [customObject] }); diff --git a/test/dialects/truncate-table-tests.js b/test/dialects/truncate-table-tests.js index a6197b9c..cfdb04da 100644 --- a/test/dialects/truncate-table-tests.js +++ b/test/dialects/truncate-table-tests.js @@ -21,5 +21,9 @@ Harness.test({ text : 'TRUNCATE TABLE [post]', string: 'TRUNCATE TABLE [post]' }, + oracle: { + text : 'TRUNCATE TABLE "post"', + string: 'TRUNCATE TABLE "post"' + }, params: [] }); diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js index 02352545..875de382 100644 --- a/test/dialects/unary-clause-tests.js +++ b/test/dialects/unary-clause-tests.js @@ -22,6 +22,10 @@ Harness.test({ text : 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)', string: 'SELECT [customer].* FROM [customer] WHERE ([customer].[age] IS NOT NULL)' }, + oracle: { + text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' + }, params: [] }); @@ -43,5 +47,9 @@ Harness.test({ text : 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))', string: 'SELECT [post].* FROM [post] WHERE ([post].[userId] IN (SELECT [customer].[id] FROM [customer] WHERE ([customer].[age] IS NULL)))' }, + oracle: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))' + }, params: [] }); diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index 090ab9ee..5639c3a3 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -24,6 +24,10 @@ Harness.test({ text : 'UPDATE [post] SET [content] = @1', string: 'UPDATE [post] SET [content] = \'test\'' }, + oracle: { + text : 'UPDATE "post" SET "content" = :1', + string: 'UPDATE "post" SET "content" = \'test\'' + }, params: ['test'] }); @@ -48,6 +52,10 @@ Harness.test({ text : 'UPDATE [post] SET [content] = @1, [userId] = @2', string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3' }, + oracle: { + text : 'UPDATE "post" SET "content" = :1, "userId" = :2', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' + }, params: ['test', 3] }); @@ -72,6 +80,10 @@ Harness.test({ text : 'UPDATE [post] SET [content] = @1, [userId] = @2', string: 'UPDATE [post] SET [content] = NULL, [userId] = 3' }, + oracle: { + text : 'UPDATE "post" SET "content" = :1, "userId" = :2', + string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' + }, params: [null, 3] }); @@ -96,6 +108,10 @@ Harness.test({ text : 'UPDATE [post] SET [content] = @1, [userId] = @2 WHERE ([post].[content] = @3)', string: 'UPDATE [post] SET [content] = \'test\', [userId] = 3 WHERE ([post].[content] = \'no\')' }, + oracle: { + text : 'UPDATE "post" SET "content" = :1, "userId" = :2 WHERE ("post"."content" = :3)', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' + }, params: ['test', 3, 'no'] }); @@ -119,6 +135,10 @@ Harness.test({ text : 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])', string: 'UPDATE [post] SET [content] = [user].[name] FROM [user] WHERE ([post].[userId] = [user].[id])' }, + oracle: { + text : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, params: [] }); @@ -143,6 +163,10 @@ Harness.test({ text : 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])', string: 'UPDATE [post] SET [userId] = [user].[id] FROM [user] WHERE ([post].[userId] = [user].[id])' }, + oracle: { + text : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + string: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")' + }, params: [] }); @@ -163,5 +187,9 @@ Harness.test({ text : 'UPDATE `post` SET `content` = ?', string: 'UPDATE `post` SET `content` = x\'74657374\'' }, + oracle: { + text : 'UPDATE "post" SET "content" = :1', + string: 'UPDATE "post" SET "content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\'))' + }, params: [new Buffer('test')] }); diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 1a842257..5eaae5ae 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -24,6 +24,10 @@ Harness.test({ text : 'SELECT [customer].[name], ([customer].[income] % @1) FROM [customer] WHERE ((([customer].[age] + @2) * ([customer].[age] - @3)) = @4)', string: 'SELECT [customer].[name], ([customer].[income] % 100) FROM [customer] WHERE ((([customer].[age] + 5) * ([customer].[age] - 2)) = 10)' }, + oracle: { + text : 'SELECT "customer"."name", ("customer"."income" % :1) FROM "customer" WHERE ((("customer"."age" + :2) * ("customer"."age" - :3)) = :4)', + string: 'SELECT "customer"."name", ("customer"."income" % 100) FROM "customer" WHERE ((("customer"."age" + 5) * ("customer"."age" - 2)) = 10)' + }, params: [100, 5, 2, 10] }); @@ -46,6 +50,10 @@ Harness.test({ text : 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + @1))', string: 'SELECT [customer].[name] FROM [customer] WHERE ([customer].[name] LIKE ([customer].[id] + \'hello\'))' }, + oracle: { + text : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + :1))', + string: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + \'hello\'))' + }, params: ['hello'] }); @@ -69,6 +77,10 @@ Harness.test({ text : 'SELECT (((([variable].[a] * [variable].[a]) / @1) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]', string: 'SELECT (((([variable].[a] * [variable].[a]) / 2) + ([variable].[v] * [variable].[t])) = [variable].[d]) FROM [variable]' }, + oracle: { + text : 'SELECT (((("variable"."a" * "variable"."a") / :1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', + string: 'SELECT (((("variable"."a" * "variable"."a") / 2) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"' + }, params: [2] }); @@ -91,6 +103,10 @@ Harness.test({ text : 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]', string: 'SELECT ((([variable].[a] * [variable].[a]) + ([variable].[b] * [variable].[b])) = ([variable].[c] * [variable].[c])) FROM [variable]' }, + oracle: { + text : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + string: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"' + }, params: [] }); @@ -108,6 +124,10 @@ Harness.test({ text : 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = ?)', string: 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = x\'74657374\')', }, + oracle: { + text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = :1)', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\')))', + }, params: [new Buffer('test')] }); diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index b25f1f35..3282b7d9 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -21,6 +21,10 @@ Harness.test({ text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' }, + oracle: { + text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, params: [] }); @@ -42,6 +46,10 @@ Harness.test({ text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' }, + oracle: { + text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, params: [] }); @@ -63,6 +71,10 @@ Harness.test({ text : 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))', string: 'SELECT * FROM [user] WHERE (([user].[id] IS NOT NULL) AND ([user].[name] IS NOT NULL))' }, + oracle: { + text : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + string: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + }, params: [] }); @@ -84,6 +96,10 @@ Harness.test({ text : 'SELECT * FROM [user] WHERE (1 = 1)', string: 'SELECT * FROM [user] WHERE (1 = 1)' }, + oracle: { + text : 'SELECT * FROM "user" WHERE (1 = 1)', + string: 'SELECT * FROM "user" WHERE (1 = 1)' + }, params: [] }); @@ -105,6 +121,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) AND ([user].[name] = @2))', string: 'SELECT [user].* FROM [user] WHERE (([user].[id] = 1) AND ([user].[name] = \'a\'))' }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = :1) AND ("user"."name" = :2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) AND ("user"."name" = \'a\'))' + }, params: [1,'a'] }); @@ -126,6 +146,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = :1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, params: [1] }); @@ -147,6 +171,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user] WHERE ([user].[id] = @1)', string: 'SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE ("user"."id" = :1)', + string: 'SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, params: [1] }); @@ -168,6 +196,10 @@ Harness.test({ text : 'SELECT [user].* FROM [user] WHERE (([user].[id] = @1) OR ([user].[name] = @2))', string: 'SELECT [user].* FROM [user] WHERE (([user].[id] = 1) OR ([user].[name] = \'a\'))' }, + oracle: { + text : 'SELECT "user".* FROM "user" WHERE (("user"."id" = :1) OR ("user"."name" = :2))', + string: 'SELECT "user".* FROM "user" WHERE (("user"."id" = 1) OR ("user"."name" = \'a\'))' + }, params: [1,'a'] }); From d42d02448e8ddeb3f337f490469cb738a55978ad Mon Sep 17 00:00:00 2001 From: Bergwinkl Thomas Date: Wed, 29 Jul 2015 16:11:24 +0200 Subject: [PATCH 125/248] add DISTINCT ON support for Postgres --- lib/dialect/postgres.js | 18 +++++++++++++++++- lib/node/distinctOn.js | 7 +++++++ lib/node/query.js | 28 ++++++++++++++++++++++++++++ test/dialects/distinct-on-tests.js | 24 ++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 lib/node/distinctOn.js create mode 100644 test/dialects/distinct-on-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index ac6e96c1..15a57f73 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -109,6 +109,7 @@ Postgres.prototype.visit = function(node) { case 'DROP' : return this.visitDrop(node); case 'TRUNCATE' : return this.visitTruncate(node); case 'DISTINCT' : return this.visitDistinct(node); + case 'DISTINCT ON' : return this.visitDistinctOn(node); case 'ALIAS' : return this.visitAlias(node); case 'ALTER' : return this.visitAlter(node); case 'CAST' : return this.visitCast(node); @@ -180,9 +181,20 @@ Postgres.prototype.quote = function(word, quoteCharacter) { Postgres.prototype.visitSelect = function(select) { var result = ['SELECT'] + if (select.isDistinct) result.push('DISTINCT'); - result.push(select.nodes.map(this.visit.bind(this)).join(', ')); + + var distinctOnNode = select.nodes.filter(function (node) {return node.type === 'DISTINCT ON';}).shift(); + var nonDistinctOnNodes = select.nodes.filter(function (node) {return node.type !== 'DISTINCT ON';}); + + if (distinctOnNode) { + result.push(this.visit(distinctOnNode)); + } + + result.push(nonDistinctOnNodes.map(this.visit.bind(this)).join(', ')); + this._selectOrDeleteEndIndex = this.output.length + result.length; + return result; }; @@ -295,6 +307,10 @@ Postgres.prototype.visitDistinct = function(truncate) { return []; }; +Postgres.prototype.visitDistinctOn = function(distinctOn) { + return ['DISTINCT ON('+distinctOn.nodes.map(this.visit.bind(this)).join(', ')+')']; +}; + Postgres.prototype.visitAlias = function(alias) { var result = [this.visit(alias.value) + ' AS ' + this.quote(alias.alias)]; return result; diff --git a/lib/node/distinctOn.js b/lib/node/distinctOn.js new file mode 100644 index 00000000..a208dfde --- /dev/null +++ b/lib/node/distinctOn.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'DISTINCT ON', +}); diff --git a/lib/node/query.js b/lib/node/query.js index d32b6379..5672259c 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -22,6 +22,7 @@ var Create = require('./create'); var Drop = require('./drop'); var Truncate = require('./truncate'); var Distinct = require('./distinct'); +var DistinctOn = require('./distinctOn'); var Alter = require('./alter'); var AddColumn = require('./addColumn'); var DropColumn = require('./dropColumn'); @@ -317,6 +318,33 @@ var Query = Node.define({ return this.add(new Distinct()); }, + distinctOn: function() { + var distinctOn; + if (this._distinctOn) { + distinctOn = this._distinctOn; + } else { + var select = this.nodes.filter(function (node) {return node.type === 'SELECT';}).shift(); + + distinctOn = this._distinctOn = new DistinctOn(); + select.add(distinctOn); + } + + //allow things like .distinctOn(a.star(), [ a.id, a.name ]) + //this will flatten them into a single array + var args = sliced(arguments).reduce(function(cur, next) { + if (util.isArray(next)) { + return cur.concat(next); + } + + cur.push(next); + return cur; + }, []); + + distinctOn.addAll(args); + + return this; + }, + alter: function() { return this.add(new Alter()); }, diff --git a/test/dialects/distinct-on-tests.js b/test/dialects/distinct-on-tests.js new file mode 100644 index 00000000..d238f928 --- /dev/null +++ b/test/dialects/distinct-on-tests.js @@ -0,0 +1,24 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); +var Sql = require('../../lib').setDialect('postgres'); + +Harness.test({ + query: user.select().distinctOn(user.id), + pg: { + text : 'SELECT DISTINCT ON("user"."id") "user".* FROM "user"', + string: 'SELECT DISTINCT ON("user"."id") "user".* FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: user.select(user.id,user.name).distinctOn(user.id), + pg: { + text : 'SELECT DISTINCT ON("user"."id") "user"."id", "user"."name" FROM "user"', + string: 'SELECT DISTINCT ON("user"."id") "user"."id", "user"."name" FROM "user"' + }, + params: [] +}); + From 393c8d2b8f5357073d3483c738f49a7dc82e7793 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 29 Jul 2015 23:20:56 -0500 Subject: [PATCH 126/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 22864027..f8ae3e0c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.55.0", + "version": "0.56.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 40272b541d7944336285689cb767ceddcf293764 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 29 Jul 2015 23:21:28 -0500 Subject: [PATCH 127/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 838c25f5..9650363e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.56.0", + "version": "0.57.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From e7f039e92acbd8f923389337f54bfc686d775e66 Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Wed, 12 Aug 2015 12:37:10 -0300 Subject: [PATCH 128/248] Fix #224 --- lib/dialect/postgres.js | 5 ++++- test/dialects/alias-tests.js | 26 ++++++++++++++++++++++++++ test/function-tests.js | 15 ++++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 01e314cb..d7b93b59 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -656,6 +656,7 @@ Postgres.prototype.visitColumn = function(columnNode) { && !this.visitingCase && !this._visitingJoin ); + var inFunctionCall = this._visitingFunctionCall; var txt = []; var closeParen = 0; if(inSelectClause && (!table.alias || !!columnNode.alias)) { @@ -716,7 +717,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push(')'); } } - if(inSelectClause && (columnNode.alias || columnNode.property !== columnNode.name)) { + if(inSelectClause && !inFunctionCall && (columnNode.alias || columnNode.property !== columnNode.name)) { txt.push(this._aliasText + this.quote(columnNode.alias || columnNode.property)); } if(this._visitingCreate || this._visitingAddColumn) { @@ -769,7 +770,9 @@ Postgres.prototype.visitColumn = function(columnNode) { }; Postgres.prototype.visitFunctionCall = function(functionCall) { + this._visitingFunctionCall = true; var txt = functionCall.name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + this._visitingFunctionCall = false; return [txt]; }; diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index f558260b..f650cd5a 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); +var Sql = require('../../lib').setDialect('postgres'); Harness.test({ query: customer.select(customer.name.isNull().as('nameIsNull')), @@ -77,3 +78,28 @@ Harness.test({ }, params: [10, 20] }); + +Harness.test({ + query: customer.select(Sql.functions.ROUND(customer.age.as('ageBetween'), 2)), + pg: { + text : 'SELECT ROUND("customer"."age", $1) FROM "customer"', + string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' + }, + sqlite: { + text : 'SELECT ROUND("customer"."age", $1) FROM "customer"', + string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' + }, + mysql: { + text : 'SELECT ROUND(`customer`.`age`, ?) FROM `customer`', + string: 'SELECT ROUND(`customer`.`age`, 2) FROM `customer`' + }, + mssql: { + text : 'SELECT ROUND([customer].[age], @1) FROM [customer]', + string: 'SELECT ROUND([customer].[age], 2) FROM [customer]' + }, + oracle: { + text : 'SELECT ROUND("customer"."age", :1) FROM "customer"', + string: 'SELECT ROUND("customer"."age", 2) FROM "customer"' + }, + params: [2] +}); diff --git a/test/function-tests.js b/test/function-tests.js index 076c2ed5..77ef0087 100644 --- a/test/function-tests.js +++ b/test/function-tests.js @@ -5,7 +5,12 @@ var sql = require(__dirname + '/../lib').setDialect('postgres'); var user = sql.define({ name: 'user', - columns: ['id', 'email', 'name'] + columns: [ + {name: 'id'}, + {name:'email'}, + {name: 'name'}, + {name: 'age', property: 'howOld'} + ] }); suite('function', function() { @@ -16,6 +21,14 @@ suite('function', function() { assert.equal(aliasedUpper.text, 'UPPER("user"."email") AS "upperAlias"'); }); + test('function call on aliased column', function() { + var round = sql.functions.ROUND; + var aliasedRound = round(user.howOld, 2).toQuery(); + + assert.equal(aliasedRound.text, 'ROUND("user"."age", $1)'); + assert.equal(aliasedRound.values[0], 2); + }); + test('creating function call works', function() { var upper = sql.functionCallCreator('UPPER'); var functionCall = upper('hello', 'world').toQuery(); From 967c0411faee516a75870e03af5ddb73e84e84da Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Wed, 12 Aug 2015 15:11:08 -0300 Subject: [PATCH 129/248] Fix #186 --- lib/dialect/postgres.js | 5 +- test/dialects/cast-tests.js | 155 ++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d7b93b59..85e5ccde 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -316,7 +316,9 @@ Postgres.prototype.visitAlter = function(alter) { }; Postgres.prototype.visitCast = function(cast) { + this._visitingCast = true; var result = ['CAST(' + this.visit(cast.value) + ' AS ' + cast.dataType + ')']; + this._visitingCast = false; return result; }; @@ -657,6 +659,7 @@ Postgres.prototype.visitColumn = function(columnNode) { && !this._visitingJoin ); var inFunctionCall = this._visitingFunctionCall; + var inCast = this._visitingCast; var txt = []; var closeParen = 0; if(inSelectClause && (!table.alias || !!columnNode.alias)) { @@ -717,7 +720,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push(')'); } } - if(inSelectClause && !inFunctionCall && (columnNode.alias || columnNode.property !== columnNode.name)) { + if(inSelectClause && !inFunctionCall && !inCast && (columnNode.alias || columnNode.property !== columnNode.name)) { txt.push(this._aliasText + this.quote(columnNode.alias || columnNode.property)); } if(this._visitingCreate || this._visitingAddColumn) { diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js index 8f407f3d..2295d720 100644 --- a/test/dialects/cast-tests.js +++ b/test/dialects/cast-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); +var customerAlias = Harness.defineCustomerAliasTable(); // Cast columns. Harness.test({ @@ -157,3 +158,157 @@ Harness.test({ }, params: [] }); + +// Cast Aliased columns. +Harness.test({ + query: customerAlias.select(customerAlias.age_alias.cast('int')), + pg: { + text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + sqlite: { + text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + mysql: { + text : 'SELECT CAST(`customer`.`age` AS int) FROM `customer`', + string: 'SELECT CAST(`customer`.`age` AS int) FROM `customer`' + }, + mssql: { + text : 'SELECT CAST([customer].[age] AS int) FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) FROM [customer]' + }, + oracle: { + text : 'SELECT CAST("customer"."age" AS int) FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.cast('varchar(10)')), + pg: { + text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + sqlite: { + text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + mysql: { + text : 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`', + string: 'SELECT CAST(`customer`.`name` AS varchar(10)) FROM `customer`' + }, + mssql: { + text : 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]', + string: 'SELECT CAST([customer].[name] AS varchar(10)) FROM [customer]' + }, + oracle: { + text : 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"', + string: 'SELECT CAST("customer"."name" AS varchar(10)) FROM "customer"' + }, + params: [] +}); +// Cast binary expressions for Aliased Column. +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.plus(customerAlias.age_alias).cast('varchar(15)')), + pg: { + text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + sqlite: { + text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + mysql: { + text : 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`', + string: 'SELECT CAST((`customer`.`name` + `customer`.`age`) AS varchar(15)) FROM `customer`' + }, + mssql: { + text : 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]', + string: 'SELECT CAST(([customer].[name] + [customer].[age]) AS varchar(15)) FROM [customer]' + }, + oracle: { + text : 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"', + string: 'SELECT CAST(("customer"."name" + "customer"."age") AS varchar(15)) FROM "customer"' + }, + params: [] +}); + +// Cast cast expressions for aliased columns. +Harness.test({ + query: customerAlias.select(customerAlias.name_alias.cast('varchar(15)').cast('varchar(10)')), + pg: { + text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + sqlite: { + text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + mysql: { + text : 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`', + string: 'SELECT CAST(CAST(`customer`.`name` AS varchar(15)) AS varchar(10)) FROM `customer`' + }, + mssql: { + text : 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]', + string: 'SELECT CAST(CAST([customer].[name] AS varchar(15)) AS varchar(10)) FROM [customer]' + }, + oracle: { + text : 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"', + string: 'SELECT CAST(CAST("customer"."name" AS varchar(15)) AS varchar(10)) FROM "customer"' + }, + params: [] +}); + +// Cast in WHERE for aliased columns. +Harness.test({ + query: customerAlias.select(customerAlias.name_alias).where(customerAlias.age_alias.cast('int').plus(100).equals(150)), + pg: { + text : 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', + string: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + sqlite: { + text : 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + $1) = $2)', + string: 'SELECT "customer"."name" AS "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + mysql: { + text : 'SELECT `customer`.`name` AS `name_alias` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + ?) = ?)', + string: 'SELECT `customer`.`name` AS `name_alias` FROM `customer` WHERE ((CAST(`customer`.`age` AS int) + 100) = 150)' + }, + mssql: { + text : 'SELECT [customer].[name] AS [name_alias] FROM [customer] WHERE ((CAST([customer].[age] AS int) + @1) = @2)', + string: 'SELECT [customer].[name] AS [name_alias] FROM [customer] WHERE ((CAST([customer].[age] AS int) + 100) = 150)' + }, + oracle: { + text : 'SELECT "customer"."name" "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + :1) = :2)', + string: 'SELECT "customer"."name" "name_alias" FROM "customer" WHERE ((CAST("customer"."age" AS int) + 100) = 150)' + }, + params: [100, 150] +}); + +// Alias cast. +Harness.test({ + query: customerAlias.select(customerAlias.age_alias.cast('int').as('age_int')), + pg: { + text : 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' + }, + sqlite: { + text : 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) AS "age_int" FROM "customer"' + }, + mysql: { + text : 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`', + string: 'SELECT CAST(`customer`.`age` AS int) AS `age_int` FROM `customer`' + }, + mssql: { + text : 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]', + string: 'SELECT CAST([customer].[age] AS int) AS [age_int] FROM [customer]' + }, + oracle: { + text : 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"', + string: 'SELECT CAST("customer"."age" AS int) "age_int" FROM "customer"' + }, + params: [] +}); From 45b929795bde084dc0ce252f23de0efaaa8f09c9 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Wed, 12 Aug 2015 15:20:56 -0400 Subject: [PATCH 130/248] Override the implementation of the standard LENGTH function for mssql which calls it LEN. --- lib/dialect/mssql.js | 8 ++++++++ test/dialects/function-tests.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 test/dialects/function-tests.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index c859ac82..f03d1ae2 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -234,6 +234,14 @@ Mssql.prototype.visitDrop = function(drop) { return ['IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+dropResult.join(' ')+' END']; }; +Mssql.prototype.visitFunctionCall = function(functionCall) { + var name=functionCall.name + // override the LENGTH function since mssql calls it LEN + if (name=="LENGTH") name="LEN" + var txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + return [txt]; +}; + Mssql.prototype.visitOrderBy = function(orderBy) { var result=Mssql.super_.prototype.visitOrderBy.call(this, orderBy); var offsetNode=orderBy.msSQLOffsetNode; diff --git a/test/dialects/function-tests.js b/test/dialects/function-tests.js new file mode 100644 index 00000000..da826dc9 --- /dev/null +++ b/test/dialects/function-tests.js @@ -0,0 +1,32 @@ +'use strict'; + +var Harness = require('./support'); +var Sql = require('../../lib'); + +var post = Harness.definePostTable(); + +Harness.test({ + query: post.select(Sql.functions.LENGTH(post.content)), + pg: { + text : 'SELECT LENGTH("post"."content") FROM "post"', + string: 'SELECT LENGTH("post"."content") FROM "post"' + }, + sqlite: { + text : 'SELECT LENGTH("post"."content") FROM "post"', + string: 'SELECT LENGTH("post"."content") FROM "post"' + }, + mysql: { + text : 'SELECT LENGTH(`post`.`content`) FROM `post`', + string: 'SELECT LENGTH(`post`.`content`) FROM `post`' + }, + mssql: { + text : 'SELECT LEN([post].[content]) FROM [post]', + string: 'SELECT LEN([post].[content]) FROM [post]' + }, + oracle: { + text : 'SELECT LENGTH("post"."content") FROM "post"', + string: 'SELECT LENGTH("post"."content") FROM "post"' + }, + params: [] +}); + From 761ebd4a3de16125929d0b2eb8d0471217fa104b Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 12 Aug 2015 14:53:48 -0500 Subject: [PATCH 131/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9650363e..4354f1d1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.57.0", + "version": "0.58.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 279600a10e16c12641d98124a5f142612f31a6b5 Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Wed, 12 Aug 2015 17:05:48 -0300 Subject: [PATCH 132/248] implements creation of index with columns in descending direction as proposed in #178. Added unit tests to this case. Closes #178 --- lib/dialect/postgres.js | 5 +++- lib/node/createIndex.js | 3 +- test/dialects/indexes-tests.js | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 85e5ccde..3eb76b70 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -912,7 +912,10 @@ Postgres.prototype.visitCreateIndex = function(node) { "ON", tableName, "(" + node.options.columns.reduce(function(result, col) { - return result.concat(this.quote(col.name)); + var column = col.name ? col.name : col.value.name; + var direction = col.direction ? ' ' + col.direction.text : ''; + var res = result.concat(this.quote(column) + direction); + return res; }.bind(this), []) + ")" ]); diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index 2384ab8e..8f8f0d04 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -49,7 +49,8 @@ module.exports = Node.define({ if (!result) { var columns = this.options.columns.map(function(col) { - return col.name; + var column = col.name ? col.name : col.value.name; + return column; }).sort(); result = [this.table._name]; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index a32c235f..86b50449 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -121,6 +121,57 @@ Harness.test({ params: [] }); +Harness.test({ + query: post.indexes().create().on(post.userId, post.id.desc), + pg: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + mysql: { + text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)' + }, + sqlite: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + mssql: { + text : 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)', + string: 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)' + }, + oracle: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + params: [] +}); + +Harness.test({ + query: post.indexes().create().on(post.userId).on(post.id.descending), + pg: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + mysql: { + text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id` DESC)' + }, + sqlite: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + mssql: { + text : 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)', + string: 'CREATE INDEX [post_id_userId] ON [post] ([userId],[id] DESC)' + }, + oracle: { + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id" DESC)' + }, + params: [] +}); + + Harness.test({ query: post.indexes().create(), pg: { From 6ccdf829c2ec80f33e6310f581f5a18fca696616 Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Wed, 12 Aug 2015 17:58:20 -0300 Subject: [PATCH 133/248] Merged with master to get changes of PR #256 --- lib/dialect/mssql.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index f03d1ae2..1d5f30df 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -235,10 +235,12 @@ Mssql.prototype.visitDrop = function(drop) { }; Mssql.prototype.visitFunctionCall = function(functionCall) { + this._visitingFunctionCall = true; var name=functionCall.name // override the LENGTH function since mssql calls it LEN if (name=="LENGTH") name="LEN" var txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + this._visitingFunctionCall = false; return [txt]; }; From c9500b505ec0669bfadef93df9312b7ba7a328ea Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Wed, 12 Aug 2015 22:01:04 -0400 Subject: [PATCH 134/248] Add limit function to tables. --- lib/table.js | 6 ++++++ test/table-tests.js | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/table.js b/lib/table.js index a5407c32..8532a30a 100644 --- a/lib/table.js +++ b/lib/table.js @@ -297,4 +297,10 @@ Table.prototype.indexes = function() { return new Query(this).indexes(); }; +Table.prototype.limit = function () { + var query = new Query(this); + query.limit.apply(query, arguments); + return query; +}; + module.exports = Table; diff --git a/test/table-tests.js b/test/table-tests.js index e6570901..d0ecdf35 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -235,3 +235,14 @@ test('dialects', function () { actual = foo.join(bar).on(bar.id.equals(1)).toString(); assert.equal(actual, '"foo" INNER JOIN "bar" ON ("bar"."id" = 1)'); }); + +test('limit', function () { + var user = Table.define({ + name: 'user', + columns: ['id', 'name'] + }); + var query = user.limit(3); + assert.equal(query.nodes.length, 1); + assert.equal(query.nodes[0].type, 'LIMIT'); + assert.equal(query.nodes[0].count, 3); +}); From da6150eefe8ffd22117a825790696fa2badf2b4f Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Thu, 13 Aug 2015 16:55:01 -0300 Subject: [PATCH 135/248] Addes Create View Support - closes #245 --- lib/dialect/postgres.js | 37 ++++++++++++++++++-- lib/node/createView.js | 13 +++++++ lib/node/query.js | 6 ++++ test/dialects/create-view-tests.js | 54 ++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 lib/node/createView.js create mode 100644 test/dialects/create-view-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 01e314cb..e542fb9f 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -71,10 +71,20 @@ Postgres.prototype.getQuery = function(queryNode) { queryNode = queryNode.select(queryNode.star()); } this.output = this.visit(queryNode); - + + //if is a create view, must replace paramaters with values + if (this.output.indexOf('CREATE VIEW') > -1) { + var previousFlagStatus = this._disableParameterPlaceholders; + this._disableParameterPlaceholders = true; + this.output = []; + this.output = this.visit(queryNode); + this.params = []; + this._disableParameterPlaceholders = previousFlagStatus; + } + // create the query object var query = { text: this.output.join(' '), values: this.params }; - + // reset the internal state of this builder this.output = []; this.params = []; @@ -142,7 +152,8 @@ Postgres.prototype.visit = function(node) { case 'DROP INDEX' : return this.visitDropIndex(node); case 'FUNCTION CALL' : return this.visitFunctionCall(node); case 'ARRAY CALL' : return this.visitArrayCall(node); - + case 'CREATE VIEW' : return this.visitCreateView(node); + case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); case 'PREFIX UNARY' : return this.visitPrefixUnary(node); case 'BINARY' : return this.visitBinary(node); @@ -547,6 +558,8 @@ Postgres.prototype.visitQuery = function(queryNode) { // so select/insert/update/delete comes before from comes before where var missingFrom = true; var hasFrom = false; + var createView; + var isSelect = false; var actions = []; var targets = []; var filters = []; @@ -554,6 +567,7 @@ Postgres.prototype.visitQuery = function(queryNode) { var node = queryNode.nodes[i]; switch(node.type) { case "SELECT": + isSelect = true; case "DELETE": actions.push(node); break; @@ -573,6 +587,9 @@ Postgres.prototype.visitQuery = function(queryNode) { missingFrom = false; targets.push(node); break; + case "CREATE VIEW": + createView = node; + break; default: filters.push(node); break; @@ -581,10 +598,18 @@ Postgres.prototype.visitQuery = function(queryNode) { if(!actions.length) { // if no actions are given, guess it's a select actions.push(new Select().add('*')); + isSelect = true; } if(missingFrom) { targets.push(new From().add(queryNode.table)); } + if (createView) { + if (isSelect) { + actions.unshift(createView); + } else { + throw new Error('Create View requires a Select.'); + } + } return this.visitQueryHelper(actions,targets,filters) }; @@ -926,6 +951,12 @@ Postgres.prototype.visitDropIndex = function(node) { return result; }; +Postgres.prototype.visitCreateView = function(createView) { + //console.log('createView: ' + createView); + var result = ['CREATE VIEW', this.quote(createView.options.viewName), 'AS']; + return result; +}; + /** * Broken out as a separate function so that dialects that derive from this class can still use this functionality. * diff --git a/lib/node/createView.js b/lib/node/createView.js new file mode 100644 index 00000000..bc52684f --- /dev/null +++ b/lib/node/createView.js @@ -0,0 +1,13 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'CREATE VIEW', + + constructor: function(viewName) { + Node.call(this); + + this.options = { viewName: viewName}; + } +}); diff --git a/lib/node/query.js b/lib/node/query.js index d32b6379..4fb88091 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -38,6 +38,7 @@ var Indexes = require('./indexes'); var CreateIndex = require('./createIndex'); var DropIndex = require('./dropIndex'); var Table = require('./table'); +var CreateView = require('./createView'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -432,6 +433,11 @@ var Query = Node.define({ table: this.table }); return this.add(this.indexesClause); + }, + + createView: function(viewName) { + this.add(new CreateView(viewName)); + return this; } }); diff --git a/test/dialects/create-view-tests.js b/test/dialects/create-view-tests.js new file mode 100644 index 00000000..314d0192 --- /dev/null +++ b/test/dialects/create-view-tests.js @@ -0,0 +1,54 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); + +//simple view create +Harness.test({ + query: user.select(user.star()).createView('allUsersView'), + pg: { + text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"', + string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"' + }, + sqlite: { + text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"', + string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"' + }, + mysql: { + text : 'CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`', + string: 'CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`' + }, + mssql: { + text : 'CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user]', + string: 'CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user]' + }, + oracle: { + text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"', + string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"' + } +}); + +//create view with parameters +Harness.test({ + query: user.select(user.star()).where(user.id.equals(1)).createView('oneUserView'), + pg: { + text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)', + string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + sqlite: { + text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)', + string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + }, + mysql: { + text : 'CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)', + string: 'CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' + }, + mssql: { + text : 'CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1)', + string: 'CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' + }, + oracle: { + text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)', + string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + } +}); From ac98e770a3be8037531b75684de5fce2c9d1da79 Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Thu, 13 Aug 2015 17:34:20 -0300 Subject: [PATCH 136/248] Added tests for error raised in non-SELECT create view attempts --- test/dialects/create-view-tests.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/dialects/create-view-tests.js b/test/dialects/create-view-tests.js index 314d0192..786158b1 100644 --- a/test/dialects/create-view-tests.js +++ b/test/dialects/create-view-tests.js @@ -52,3 +52,29 @@ Harness.test({ string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' } }); + +//Tests error raised for non-SELECT create view attempts +Harness.test({ + query: user.delete().where(user.id.equals(1)).createView('oneUserView'), + pg: { + text : 'Create View requires a Select.', + throws: true + }, + sqlite: { + text : 'Create View requires a Select.', + throws: true + }, + mysql: { + text : 'Create View requires a Select.', + throws: true + }, + mssql: { + text : 'Create View requires a Select.', + throws: true + }, + oracle: { + text : 'Create View requires a Select.', + throws: true + }, + params: [] +}); From 5255605cfd981bc0662dbf5b4e7c8da036e5ea30 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 22 Aug 2015 02:23:40 -0400 Subject: [PATCH 137/248] Added LEFT and RIGHT functions. --- lib/dialect/sqlite.js | 28 ++++++++++++++++++ lib/functions.js | 2 ++ test/dialects/function-tests.js | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 8530159f..17874ec5 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -34,6 +34,34 @@ Sqlite.prototype.visitDropColumn = function() { throw new Error('SQLite does not allow dropping columns.'); }; +Sqlite.prototype.visitFunctionCall = function(functionCall) { + var _this=this + + function _left() { + // convert LEFT(column,4) to SUBSTR(column,1,4) + var nodes = functionCall.nodes.map(_this.visit.bind(_this)) + if (nodes.length != 2) throw new Error('Not enough parameters passed to LEFT function.') + var txt = "SUBSTR(" + (nodes[0]+'') + ', 1, ' + (nodes[1]+'') + ')'; + return txt + } + + function _right() { + // convert RIGHT(column,4) to SUBSTR(column,-4) + var nodes = functionCall.nodes.map(_this.visit.bind(_this)) + if (nodes.length != 2) throw new Error('Not enough parameters passed to RIGHT function.') + var txt = "SUBSTR(" + (nodes[0]+'') + ', -' + (nodes[1]+'') + ')'; + return txt + } + + var txt="" + var name=functionCall.name + // Override LEFT and RIGHT and convert to SUBSTR + if (name == "LEFT") txt = _left(); + else if (name == "RIGHT") txt = _right(); + else txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + return [txt]; +}; + Sqlite.prototype.visitTruncate = function(truncate) { var result = ['DELETE FROM']; result = result.concat(truncate.nodes.map(this.visit.bind(this))); diff --git a/lib/functions.js b/lib/functions.js index 084eaa4c..6a39c9b0 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -36,10 +36,12 @@ var aggregateFunctions = [ var scalarFunctions = [ 'ABS', 'COALESCE', + 'LEFT', 'LENGTH', 'LOWER', 'LTRIM', 'RANDOM', + 'RIGHT', 'ROUND', 'RTRIM', 'SUBSTR', diff --git a/test/dialects/function-tests.js b/test/dialects/function-tests.js index da826dc9..702d8c63 100644 --- a/test/dialects/function-tests.js +++ b/test/dialects/function-tests.js @@ -30,3 +30,53 @@ Harness.test({ params: [] }); +Harness.test({ + query: post.select(Sql.functions.LEFT(post.content,4)), + pg: { + text : 'SELECT LEFT("post"."content", $1) FROM "post"', + string: 'SELECT LEFT("post"."content", 4) FROM "post"' + }, + sqlite: { + text : 'SELECT SUBSTR("post"."content", 1, $1) FROM "post"', + string: 'SELECT SUBSTR("post"."content", 1, 4) FROM "post"' + }, + mysql: { + text : 'SELECT LEFT(`post`.`content`, ?) FROM `post`', + string: 'SELECT LEFT(`post`.`content`, 4) FROM `post`' + }, + mssql: { + text : 'SELECT LEFT([post].[content], @1) FROM [post]', + string: 'SELECT LEFT([post].[content], 4) FROM [post]' + }, + oracle: { + text : 'SELECT LEFT("post"."content", :1) FROM "post"', + string: 'SELECT LEFT("post"."content", 4) FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(Sql.functions.RIGHT(post.content,4)), + pg: { + text : 'SELECT RIGHT("post"."content", $1) FROM "post"', + string: 'SELECT RIGHT("post"."content", 4) FROM "post"' + }, + sqlite: { + text : 'SELECT SUBSTR("post"."content", -$1) FROM "post"', + string: 'SELECT SUBSTR("post"."content", -4) FROM "post"' + }, + mysql: { + text : 'SELECT RIGHT(`post`.`content`, ?) FROM `post`', + string: 'SELECT RIGHT(`post`.`content`, 4) FROM `post`' + }, + mssql: { + text : 'SELECT RIGHT([post].[content], @1) FROM [post]', + string: 'SELECT RIGHT([post].[content], 4) FROM [post]' + }, + oracle: { + text : 'SELECT RIGHT("post"."content", :1) FROM "post"', + string: 'SELECT RIGHT("post"."content", 4) FROM "post"' + }, + params: [4] +}); + From a7114582354ec6d1bf1cd915927653deb50e806a Mon Sep 17 00:00:00 2001 From: Nikhil Ranjan Date: Mon, 31 Aug 2015 18:04:00 +0530 Subject: [PATCH 138/248] Added notBeteen dialect --- lib/node/valueExpression.js | 1 + test/dialects/alias-tests.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 169fb89f..428af90d 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -153,6 +153,7 @@ var ValueExpressionMixin = function() { in : inMethod, notIn : notInMethod, between : ternaryMethod('BETWEEN', 'AND'), + notBetween : ternaryMethod('NOT BETWEEN', 'AND'), at : atMethod, contains : binaryMethod('@>'), containedBy : binaryMethod('<@'), diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index 6981aaa6..a8540846 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -53,3 +53,20 @@ Harness.test({ }, params: [10, 20] }); + +Harness.test({ + query: customer.select(customer.age.notBetween(10, 20).as('ageNotBetween')), + pg: { + text : 'SELECT ("customer"."age" NOT BETWEEN $1 AND $2) AS "ageNotBetween" FROM "customer"', + string: 'SELECT ("customer"."age" NOT BETWEEN 10 AND 20) AS "ageNotBetween" FROM "customer"' + }, + sqlite: { + text : 'SELECT ("customer"."age" NOT BETWEEN $1 AND $2) AS "ageNotBetween" FROM "customer"', + string: 'SELECT ("customer"."age" NOT BETWEEN 10 AND 20) AS "ageNotBetween" FROM "customer"' + }, + mysql: { + text : 'SELECT (`customer`.`age` NOT BETWEEN ? AND ?) AS `ageNotBetween` FROM `customer`', + string: 'SELECT (`customer`.`age` NOT BETWEEN 10 AND 20) AS `ageNotBetween` FROM `customer`' + }, + params: [10, 20] +}); From a486c9f32be41c36be9331dc83cf4f556711f979 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Mon, 31 Aug 2015 13:32:57 -0400 Subject: [PATCH 139/248] Simplify onDelete conditional. Put onDelete in a variable and only call #toUpperCase once. --- lib/dialect/postgres.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 01e314cb..af17e37a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -749,19 +749,19 @@ Postgres.prototype.visitColumn = function(columnNode) { columnNode.name + ' (REFERENCES statements within CREATE TABLE and ADD COLUMN statements' + ' require a table and column)'); - + txt.push(' REFERENCES '); if(columnNode.references.schema) { txt.push(this.quote(columnNode.references.schema) + '.'); } txt.push(this.quote(columnNode.references.table) + '(' + this.quote(columnNode.references.column) + ')'); - if (!!columnNode.references.onDelete) { - if (columnNode.references.onDelete.toUpperCase() === "CASCADE" || - columnNode.references.onDelete.toUpperCase() === "RESTRICT") { - txt.push(' ON DELETE ' + columnNode.references.onDelete.toUpperCase()) - } - } + + var onDelete = columnNode.references.onDelete; + if (onDelete) onDelete = onDelete.toUpperCase(); + if (onDelete === 'CASCADE' || onDelete === 'RESTRICT') { + txt.push(' ON DELETE ' + onDelete) + } } } } From d0c15622624f974d1fc30660aee640a441fa3df5 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Mon, 31 Aug 2015 13:50:09 -0400 Subject: [PATCH 140/248] Allow passing plain query as subquery. --- lib/dialect/postgres.js | 1 + test/dialects/subquery-tests.js | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 01e314cb..588d382a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -542,6 +542,7 @@ Postgres.prototype.visitOverlap = function(overlap) { }; Postgres.prototype.visitQuery = function(queryNode) { + if (this._queryNode) return this.visitSubquery(queryNode); this._queryNode = queryNode; // need to sort the top level query nodes on visitation priority // so select/insert/update/delete comes before from comes before where diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 2d5df342..e27beecf 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -3,8 +3,34 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); var user = Harness.defineUserTable(); +var post = Harness.definePostTable(); var Sql = require('../../lib'); +Harness.test({ + query: user.select(user.name).where(user.id.in(post.select(post.userId))), + pg: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' + }, + sqlite: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' + }, + mysql: { + text: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`id` IN (SELECT `post`.`userId` FROM `post`))', + string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`id` IN (SELECT `post`.`userId` FROM `post`))' + }, + mssql: { + text: 'SELECT [user].[name] FROM [user] WHERE ([user].[id] IN (SELECT [post].[userId] FROM [post]))', + string: 'SELECT [user].[name] FROM [user] WHERE ([user].[id] IN (SELECT [post].[userId] FROM [post]))', + }, + oracle: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' + }, + params: [] +}) + Harness.test({ query: user.name.in( customer.subQuery().select(customer.name).where( From 4034ce2033d9df3779a4a4eb87dfc9d4d49608a8 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Mon, 31 Aug 2015 21:57:31 -0400 Subject: [PATCH 141/248] Consolidate, add two more methods. --- lib/table.js | 81 ++++++++++++--------------------------------- test/table-tests.js | 20 ++++++++--- 2 files changed, 38 insertions(+), 63 deletions(-) diff --git a/lib/table.js b/lib/table.js index 8532a30a..f9c0b88c 100644 --- a/lib/table.js +++ b/lib/table.js @@ -182,12 +182,6 @@ Table.prototype.select = function() { return query; }; -Table.prototype.from = function() { - var query = new Query(this); - query.from.apply(query, arguments); - return query; -}; - Table.prototype.subQuery = function(alias) { // create the query and pass it off var query = new Query(this); @@ -210,42 +204,6 @@ Table.prototype.insert = function() { return query; }; -Table.prototype.update = function() { - var query = new Query(this); - query.update.apply(query, arguments); - return query; -}; - -Table.prototype['delete'] = function() { - var query = new Query(this); - query['delete'].apply(query, arguments); - return query; -}; - -Table.prototype.create = function() { - var query = new Query(this); - query.create.apply(query, arguments); - return query; -}; - -Table.prototype.drop = function() { - var query = new Query(this); - query.drop.apply(query, arguments); - return query; -}; - -Table.prototype.truncate = function() { - var query = new Query(this); - query.truncate.apply(query, arguments); - return query; -}; - -Table.prototype.alter = function() { - var query = new Query(this); - query.alter.apply(query, arguments); - return query; -}; - Table.prototype.toNode = function() { return new TableNode(this); }; @@ -275,32 +233,37 @@ Table.prototype.__defineGetter__("nodes", function() { return this.select(this.star()).nodes; }); -Table.prototype.where = function() { - var query = new Query(this); - query.where.apply(query, arguments); - return query; -}; - Table.prototype.and = function() { var query = new Query(this); query.where.apply(query, arguments); return query; }; -Table.prototype.or = function() { - var query = new Query(this); - query.or.apply(query, arguments); - return query; -}; - Table.prototype.indexes = function() { return new Query(this).indexes(); }; -Table.prototype.limit = function () { - var query = new Query(this); - query.limit.apply(query, arguments); - return query; -}; +var queryMethods = [ + 'alter', + 'create', + 'delete', + 'drop', + 'from', + 'limit', + 'offset', + 'or', + 'order', + 'truncate', + 'update', + 'where' +]; + +queryMethods.forEach(function (method) { + Table.prototype[method] = function () { + var query = new Query(this); + query[method].apply(query, arguments); + return query; + }; +}); module.exports = Table; diff --git a/test/table-tests.js b/test/table-tests.js index d0ecdf35..66c3bdd3 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -237,12 +237,24 @@ test('dialects', function () { }); test('limit', function () { - var user = Table.define({ - name: 'user', - columns: ['id', 'name'] - }); + var user = Table.define({name: 'user', columns: ['id', 'name']}); var query = user.limit(3); assert.equal(query.nodes.length, 1); assert.equal(query.nodes[0].type, 'LIMIT'); assert.equal(query.nodes[0].count, 3); }); + +test('offset', function () { + var user = Table.define({name: 'user', columns: ['id', 'name']}); + var query = user.offset(20); + assert.equal(query.nodes.length, 1); + assert.equal(query.nodes[0].type, 'OFFSET'); + assert.equal(query.nodes[0].count, 20); +}); + +test('order', function () { + var user = Table.define({name: 'user', columns: ['id', 'name']}); + var query = user.order(user.name); + assert.equal(query.nodes.length, 1); + assert.equal(query.nodes[0].type, 'ORDER BY'); +}); From 63a8f99e61eb45f3cee99e758eeb13480288b3a1 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Fri, 11 Sep 2015 06:41:12 -0400 Subject: [PATCH 142/248] Function calls don't need the sql instance. --- lib/functions.js | 14 ++++++-------- lib/index.js | 7 ++----- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/lib/functions.js b/lib/functions.js index 084eaa4c..b5d1bf5e 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -4,19 +4,17 @@ var sliced = require('sliced'); var FunctionCall = require(__dirname + '/node/functionCall'); // create a function that creates a function call of the specific name, using the specified sql instance -var getFunctionCallCreator = function(name, sql) { +var getFunctionCallCreator = function(name) { return function() { // turn array-like arguments object into a true array - var functionCall = new FunctionCall(name, sliced(arguments)); - functionCall.sql = sql; - return functionCall; + return new FunctionCall(name, sliced(arguments)); }; }; // creates a hash of functions for a sql instance -var getFunctions = function(functionNames, sql) { +var getFunctions = function(functionNames) { var functions = _.reduce(functionNames, function(reducer, name) { - reducer[name] = getFunctionCallCreator(name, sql); + reducer[name] = getFunctionCallCreator(name); return reducer; }, {}); return functions; @@ -56,8 +54,8 @@ var textsearchFunctions = ['TS_RANK','TS_RANK_CD', 'PLAINTO_TSQUERY', 'TO_TSQUER var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction).concat(textsearchFunctions); // creates a hash of standard functions for a sql instance -var getStandardFunctions = function(sql) { - return getFunctions(standardFunctionNames, sql); +var getStandardFunctions = function() { + return getFunctions(standardFunctionNames); }; module.exports.getStandardFunctions = getStandardFunctions; diff --git a/lib/index.js b/lib/index.js index 75d1c2e7..372de60d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -16,7 +16,7 @@ var Sql = function(dialect) { this.setDialect(dialect || DEFAULT_DIALECT); // attach the standard SQL functions to this instance - this.functions = functions.getStandardFunctions(this); + this.functions = functions.getStandardFunctions(); }; // Define a table @@ -30,11 +30,8 @@ Sql.prototype.define = function(def) { // Returns a function call creator Sql.prototype.functionCallCreator = function(name) { - var sql = this; return function() { - var functionCall = new FunctionCall(name, sliced(arguments)); - functionCall.sql = sql; - return functionCall; + return new FunctionCall(name, sliced(arguments)); }; }; From 76b1d591fffbcac7308e0c166cc128e794c4c357 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 14 Sep 2015 10:10:14 -0700 Subject: [PATCH 143/248] Add parens to tests --- test/dialects/create-view-tests.js | 40 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/test/dialects/create-view-tests.js b/test/dialects/create-view-tests.js index 786158b1..977f540a 100644 --- a/test/dialects/create-view-tests.js +++ b/test/dialects/create-view-tests.js @@ -7,24 +7,24 @@ var user = Harness.defineUserTable(); Harness.test({ query: user.select(user.star()).createView('allUsersView'), pg: { - text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"', - string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"' + text : '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', + string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' }, sqlite: { - text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"', - string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"' + text : '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', + string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' }, mysql: { - text : 'CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`', - string: 'CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`' + text : '(CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`)', + string: '(CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`)' }, mssql: { - text : 'CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user]', - string: 'CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user]' + text : '(CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user])', + string: '(CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user])' }, oracle: { - text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"', - string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"' + text : '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")', + string: '(CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user")' } }); @@ -32,24 +32,24 @@ Harness.test({ Harness.test({ query: user.select(user.star()).where(user.id.equals(1)).createView('oneUserView'), pg: { - text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)', - string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + text : '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', + string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' }, sqlite: { - text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)', - string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + text : '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', + string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' }, mysql: { - text : 'CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)', - string: 'CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)' + text : '(CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1))', + string: '(CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1))' }, mssql: { - text : 'CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1)', - string: 'CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1)' + text : '(CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1))', + string: '(CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1))' }, oracle: { - text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)', - string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)' + text : '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))', + string: '(CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1))' } }); From 9d5937b86d1b9673e05c37689af26b6136d78918 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 14 Sep 2015 10:10:30 -0700 Subject: [PATCH 144/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4354f1d1..761075e7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.58.0", + "version": "0.59.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 4bbf8432f2158f1d1b5ef3cb70b72b444c80ef90 Mon Sep 17 00:00:00 2001 From: Eduardo Dutra Date: Mon, 14 Sep 2015 14:58:38 -0300 Subject: [PATCH 145/248] merge conflict resolves for fix-186 --- lib/dialect/sqlite.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 17874ec5..fdabf71a 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -37,6 +37,8 @@ Sqlite.prototype.visitDropColumn = function() { Sqlite.prototype.visitFunctionCall = function(functionCall) { var _this=this + this._visitingFunctionCall = true; + function _left() { // convert LEFT(column,4) to SUBSTR(column,1,4) var nodes = functionCall.nodes.map(_this.visit.bind(_this)) @@ -59,6 +61,8 @@ Sqlite.prototype.visitFunctionCall = function(functionCall) { if (name == "LEFT") txt = _left(); else if (name == "RIGHT") txt = _right(); else txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + + this._visitingFunctionCall = false; return [txt]; }; From fd68ea98b0cb7464978d1b55878121b980d394a7 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 14 Sep 2015 11:13:10 -0700 Subject: [PATCH 146/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 761075e7..d811eae5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.59.0", + "version": "0.60.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 0ee3d2cf1ac6e321322dc832a9f7377fff4aa7c4 Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Tue, 27 Oct 2015 17:04:29 -0400 Subject: [PATCH 147/248] Added configurability for dialects --- lib/dialect/sqlite.js | 5 ++++- lib/index.js | 13 +++++++------ lib/node/index.js | 9 +++++++-- test/dialects/support.js | 8 ++++---- test/dialects/tostring-tests.js | 29 +++++++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index fdabf71a..611112e8 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -3,10 +3,11 @@ var util = require('util'); var assert = require('assert'); -var Sqlite = function() { +var Sqlite = function(config) { this.output = []; this.params = []; this._hasAddedAColumn = false; + this.config = config || {}; }; var Postgres = require(__dirname + '/postgres'); @@ -20,6 +21,8 @@ Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; Sqlite.prototype._getParameterValue = function(value) { if (Buffer.isBuffer(value)) { value = 'x' + this._getParameterValue(value.toString('hex')); + } else if (value instanceof Date && this.config.dateTimeMillis) { + value = value.getTime(); } else { value = Postgres.prototype._getParameterValue.call(this, value); } diff --git a/lib/index.js b/lib/index.js index 372de60d..6f609570 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,8 +12,8 @@ var Table = require('./table'); // default dialect is postgres var DEFAULT_DIALECT = 'postgres'; -var Sql = function(dialect) { - this.setDialect(dialect || DEFAULT_DIALECT); +var Sql = function(dialect, config) { + this.setDialect(dialect || DEFAULT_DIALECT, config); // attach the standard SQL functions to this instance this.functions = functions.getStandardFunctions(); @@ -50,19 +50,20 @@ Sql.prototype.select = function() { }; // Set the dialect -Sql.prototype.setDialect = function(dialect) { +Sql.prototype.setDialect = function(dialect, config) { this.dialect = getDialect(dialect); this.dialectName = dialect; + this.config = config; return this; }; // back compat shim for the Sql class constructor -var create = function(dialect) { - return new Sql(dialect); +var create = function(dialect, config) { + return new Sql(dialect, {}); }; -module.exports = new Sql(DEFAULT_DIALECT); +module.exports = new Sql(DEFAULT_DIALECT, {}); module.exports.create = create; module.exports.Sql = Sql; module.exports.Table = Table; diff --git a/lib/node/index.js b/lib/node/index.js index e0dabff5..b500ab39 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -45,9 +45,14 @@ var determineDialect = function(query, dialect) { return Dialect; }; +var initializeDialect = function(Dialect, query) { + var config = query.sql ? query.sql.config : {}; + return new Dialect(config); +}; + Node.prototype.toQuery = function(dialect) { var Dialect = determineDialect(this, dialect); - return new Dialect().getQuery(this); + return initializeDialect(Dialect, this).getQuery(this); }; Node.prototype.toNamedQuery = function(name, dialect) { @@ -61,7 +66,7 @@ Node.prototype.toNamedQuery = function(name, dialect) { Node.prototype.toString = function(dialect) { var Dialect = determineDialect(this, dialect); - return new Dialect().getString(this); + return initializeDialect(Dialect, this).getString(this); }; Node.prototype.addAll = function(nodes) { diff --git a/test/dialects/support.js b/test/dialects/support.js index e8c68837..f1d926e9 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -27,11 +27,11 @@ module.exports = { // check if this query is expected to throw if (expectedObject.throws) { assert.throws(function() { - new DialectClass().getQuery(expected.query); + new DialectClass(expectedObject.config).getQuery(expected.query); }); } else { // build query for dialect - var compiledQuery = new DialectClass().getQuery(expected.query); + var compiledQuery = new DialectClass(expectedObject.config).getQuery(expected.query); // test result is correct var expectedText = expectedObject.text || expectedObject; @@ -51,10 +51,10 @@ module.exports = { // test the toString if (expectedObject.throws) { assert.throws(function() { - new DialectClass().getString(expected.query); + new DialectClass(expectedObject.config).getString(expected.query); }); } else { - var compiledString = new DialectClass().getString(expected.query); + var compiledString = new DialectClass(expectedObject.config).getString(expected.query); // test result is correct assert.equal(compiledString, expectedObject.string); diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index 215cb05b..53d413e8 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -134,6 +134,35 @@ Harness.test({ params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] }); +// Date to milliseconds +Harness.test({ + query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), + pg: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + sqlite: { + text : '("post"."content" = $1)', + string: '("post"."content" = 946684800000)', + config: { + dateTimeMillis: true + } + }, + mysql: { + text : '(`post`.`content` = ?)', + string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' + }, + mssql: { + text : '([post].[content] = @1)', + string: '([post].[content] = \'2000-01-01T00:00:00.000Z\')' + }, + oracle: { + text : '("post"."content" = :1)', + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' + }, + params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] +}); + // Object var customObject = { toString: function() { From bf212de3422841e220acf2bd84c37511306c7b54 Mon Sep 17 00:00:00 2001 From: Alexey Zabrodsky Date: Thu, 29 Oct 2015 18:59:33 +0500 Subject: [PATCH 148/248] returning() defaults to '*' --- lib/node/query.js | 9 ++++++--- test/dialects/returning-tests.js | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 test/dialects/returning-tests.js diff --git a/lib/node/query.js b/lib/node/query.js index 7b870aea..26bc7227 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -257,9 +257,12 @@ var Query = Node.define({ }, returning: function() { - var args = getArrayOrArgsAsArray(arguments); var returning = new Returning(); - returning.addAll(args); + if (arguments.length === 0) + returning.add('*'); + else + returning.addAll(getArrayOrArgsAsArray(arguments)); + return this.add(returning); }, @@ -462,7 +465,7 @@ var Query = Node.define({ }); return this.add(this.indexesClause); }, - + createView: function(viewName) { this.add(new CreateView(viewName)); return this; diff --git a/test/dialects/returning-tests.js b/test/dialects/returning-tests.js new file mode 100644 index 00000000..ebbb0b2e --- /dev/null +++ b/test/dialects/returning-tests.js @@ -0,0 +1,20 @@ +var Harness = require('./support'); +var user = Harness.defineUserTable(); + +Harness.test({ + query: user.insert({name: 'joe'}).returning(), + pg: { + text : 'INSERT INTO "user" ("name") VALUES ($1) RETURNING *', + string: 'INSERT INTO "user" ("name") VALUES (\'joe\') RETURNING *' + }, + params: ['joe'] +}); + +Harness.test({ + query: user.insert({name: 'joe'}).returning('id'), + pg: { + text : 'INSERT INTO "user" ("name") VALUES ($1) RETURNING id', + string: 'INSERT INTO "user" ("name") VALUES (\'joe\') RETURNING id' + }, + params: ['joe'] +}); From c4aacfbb272b02e5fb7dd8e44bfdcde0e02fd030 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 2 Nov 2015 10:27:08 -0600 Subject: [PATCH 149/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d811eae5..f860204a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.60.0", + "version": "0.61.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 8deb5c5ff9a3a155ea62f593467b151b2b31d335 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 2 Nov 2015 10:32:49 -0600 Subject: [PATCH 150/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f860204a..9912ac7a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.61.0", + "version": "0.62.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From d98ce456dd35fe44116fdd44b3e18574888204eb Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Fri, 13 Nov 2015 11:14:25 -0500 Subject: [PATCH 151/248] Added configuration for NULLS LAST in postgres --- lib/dialect/mssql.js | 3 +- lib/dialect/mysql.js | 3 +- lib/dialect/oracle.js | 19 ++++++------ lib/dialect/postgres.js | 14 +++++---- test/dialects/order-tests.js | 56 ++++++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 16 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 1d5f30df..daf64938 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -6,9 +6,10 @@ var util = require('util'); var assert = require('assert'); -var Mssql = function() { +var Mssql = function(config) { this.output = []; this.params = []; + this.config = config || {}; }; var Postgres = require(__dirname + '/postgres'); diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index fc4c6cfc..b4e8249c 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -3,9 +3,10 @@ var util = require('util'); var assert = require('assert'); -var Mysql = function() { +var Mysql = function(config) { this.output = []; this.params = []; + this.config = config || {}; }; var Postgres = require(__dirname + '/postgres'); diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index 763b2c5a..ce912b2c 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -3,9 +3,10 @@ var util = require('util'); var assert = require('assert'); -var Oracle = function() { +var Oracle = function(config) { this.output = []; this.params = []; + this.config = config || {}; }; var Postgres = require(__dirname + '/postgres'); @@ -55,7 +56,7 @@ Oracle.prototype.visitDrop = function(drop) { } // Implement our own drop if exists: // PostgreSQL: DROP TABLE IF EXISTS "group" - // Oracle: + // Oracle: // BEGIN // EXECUTE IMMEDIATE 'DROP TABLE POST'; // EXCEPTION @@ -80,7 +81,7 @@ Oracle.prototype.visitCreate = function(create) { if (isNotExists) { // Implement our own create if not exists: // PostgreSQL: CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100)) - // Oracle: + // Oracle: // BEGIN // EXECUTE IMMEDIATE 'CREATE TABLE ...'; // EXCEPTION @@ -128,7 +129,7 @@ Oracle.prototype.visitModifier = function(node) { Oracle.prototype.visitQueryHelper=function(actions,targets,filters){ var output = Oracle.super_.prototype.visitQueryHelper.call(this,actions,targets,filters); - + //In Oracle, OFFSET must come before FETCH NEXT (limit) //Change positions, if both are present and not done already var offset = output.indexOf('OFFSET'); @@ -154,7 +155,7 @@ Oracle.prototype.visitColumn = function(columnNode) { function _arrayAgg(){ throw new Error("Oracle does not support array_agg.") } - + function _countStar(){ // Implement our own since count(table.*) is invalid in Oracle var result='COUNT(*)' @@ -196,11 +197,11 @@ Oracle.prototype.visitIndexes = function(node) { var schemaName = this._queryNode.table.getSchema(); var indexes = "SELECT * FROM USER_INDEXES WHERE TABLE_NAME = '" + tableName + "'"; - + if (schemaName) { indexes += " AND TABLE_OWNER = '" + schemaName + "'"; } - + return indexes; }; @@ -219,9 +220,9 @@ Oracle.prototype.visitDropIndex = function(node) { // Using same CASE implementation as MSSQL Oracle.prototype.visitCase = function(caseExp) { - + return Mssql.prototype.visitCase.call(this, caseExp); -} +} function isCreateIfNotExists(create){ diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 90daf4a1..0dc5f97a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -6,9 +6,10 @@ var From = require('../node/from'); var Select = require('../node/select'); var Table = require('../table'); -var Postgres = function() { +var Postgres = function(config) { this.output = []; this.params = []; + this.config = config || {}; }; Postgres.prototype._myClass = Postgres; @@ -71,7 +72,7 @@ Postgres.prototype.getQuery = function(queryNode) { queryNode = queryNode.select(queryNode.star()); } this.output = this.visit(queryNode); - + //if is a create view, must replace paramaters with values if (this.output.indexOf('CREATE VIEW') > -1) { var previousFlagStatus = this._disableParameterPlaceholders; @@ -81,10 +82,10 @@ Postgres.prototype.getQuery = function(queryNode) { this.params = []; this._disableParameterPlaceholders = previousFlagStatus; } - + // create the query object var query = { text: this.output.join(' '), values: this.params }; - + // reset the internal state of this builder this.output = []; this.params = []; @@ -154,7 +155,7 @@ Postgres.prototype.visit = function(node) { case 'FUNCTION CALL' : return this.visitFunctionCall(node); case 'ARRAY CALL' : return this.visitArrayCall(node); case 'CREATE VIEW' : return this.visitCreateView(node); - + case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); case 'PREFIX UNARY' : return this.visitPrefixUnary(node); case 'BINARY' : return this.visitBinary(node); @@ -371,6 +372,9 @@ Postgres.prototype.visitWhere = function(where) { Postgres.prototype.visitOrderBy = function(orderBy) { var result = ['ORDER BY', orderBy.nodes.map(this.visit.bind(this)).join(', ')]; + if (this._myClass === Postgres && this.config.nullsLast) { + result.push('NULLS LAST'); + } return result; }; diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 888f27f3..476d625e 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -253,3 +253,59 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: post.select(post.content).order(post.content.descending), + pg: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', + config: { + nullsLast: true + } + }, + sqlite: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC' + }, + mysql: { + text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content` DESC', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content` DESC' + }, + mssql: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content] DESC', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content] DESC' + }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content), + pg: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', + config: { + nullsLast: true + } + }, + sqlite: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + mysql: { + text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' + }, + mssql: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' + }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + params: [] +}); \ No newline at end of file From 3c150c00d38fe0eeb1d6955cc18c5696efc594a7 Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Fri, 13 Nov 2015 11:19:42 -0500 Subject: [PATCH 152/248] Changed null order so either 'first' or 'last' can be specified --- lib/dialect/postgres.js | 4 ++-- test/dialects/order-tests.js | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 0dc5f97a..c46a44d2 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -372,8 +372,8 @@ Postgres.prototype.visitWhere = function(where) { Postgres.prototype.visitOrderBy = function(orderBy) { var result = ['ORDER BY', orderBy.nodes.map(this.visit.bind(this)).join(', ')]; - if (this._myClass === Postgres && this.config.nullsLast) { - result.push('NULLS LAST'); + if (this._myClass === Postgres && this.config.nullOrder) { + result.push('NULLS ' + this.config.nullOrder.toUpperCase()); } return result; }; diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 476d625e..2c4803f5 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -260,7 +260,7 @@ Harness.test({ text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" DESC NULLS LAST', config: { - nullsLast: true + nullOrder: "last" } }, sqlite: { @@ -288,7 +288,35 @@ Harness.test({ text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS LAST', config: { - nullsLast: true + nullOrder: "last" + } + }, + sqlite: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + mysql: { + text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', + string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' + }, + mssql: { + text : 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]', + string: 'SELECT [post].[content] FROM [post] ORDER BY [post].[content]' + }, + oracle: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.content).order(post.content.asc), + pg: { + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS FIRST', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content" NULLS FIRST', + config: { + nullOrder: "first" } }, sqlite: { From fb67977497f9f37a88c8da7b53fb4df79233f86c Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 13 Nov 2015 10:43:15 -0600 Subject: [PATCH 153/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9912ac7a..7bd6325f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.62.0", + "version": "0.63.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From c6b0d101814d8fcb9cb2afaf4043399032656476 Mon Sep 17 00:00:00 2001 From: Barry Hammen Date: Fri, 13 Nov 2015 15:33:52 -0500 Subject: [PATCH 154/248] Add left-join support to subQuery --- lib/node/query.js | 6 ++++++ test/dialects/subquery-tests.js | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/node/query.js b/lib/node/query.js index 26bc7227..85cfa9e5 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -40,6 +40,7 @@ var CreateIndex = require('./createIndex'); var DropIndex = require('./dropIndex'); var Table = require('./table'); var CreateView = require('./createView'); +var JoinNode = require('./join'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -128,6 +129,11 @@ var Query = Node.define({ return this; }, + leftJoin: function(other) { + assert(this.type === 'SUBQUERY', 'leftJoin() can only be used on a subQuery'); + return new JoinNode('LEFT', this, other.toNode()); + }, + where: function(node) { if (arguments.length > 1) { // allow multiple where clause arguments diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index e27beecf..1458c6e1 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -162,3 +162,30 @@ Harness.test({ }, params: [] }); + +var limitUsers = user.subQuery('limit-users').select(user.id, user.name).from(user).order(user.name).limit(10).offset(10); +Harness.test({ + query: Sql.select(limitUsers.name, post.tags).from(limitUsers.leftJoin(post).on(post.userId.equals(limitUsers.id))), + pg: { + text : 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + sqlite: { + text : 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" LIMIT 10 OFFSET 10) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + mysql: { + text : 'SELECT `limit-users`.`name`, `post`.`tags` FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT 10 OFFSET 10) `limit-users` LEFT JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)', + string: 'SELECT `limit-users`.`name`, `post`.`tags` FROM (SELECT `user`.`id`, `user`.`name` FROM `user` ORDER BY `user`.`name` LIMIT 10 OFFSET 10) `limit-users` LEFT JOIN `post` ON (`post`.`userId` = `limit-users`.`id`)' + }, + mssql: { + text : 'SELECT [limit-users].[name], [post].[tags] FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) [limit-users] LEFT JOIN [post] ON ([post].[userId] = [limit-users].[id])', + string: 'SELECT [limit-users].[name], [post].[tags] FROM (SELECT [user].[id], [user].[name] FROM [user] ORDER BY [user].[name] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) [limit-users] LEFT JOIN [post] ON ([post].[userId] = [limit-users].[id])' + }, + oracle: { + text : 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")', + string: 'SELECT "limit-users"."name", "post"."tags" FROM (SELECT "user"."id", "user"."name" FROM "user" ORDER BY "user"."name" OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY) "limit-users" LEFT JOIN "post" ON ("post"."userId" = "limit-users"."id")' + }, + params: [] +}); + From 8cb528094c3c91feb26afec6849c83a49d5895f4 Mon Sep 17 00:00:00 2001 From: Barry Hammen Date: Mon, 16 Nov 2015 10:29:36 -0500 Subject: [PATCH 155/248] Fixed passing config to subquery --- lib/dialect/postgres.js | 2 +- test/dialects/subquery-tests.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index c46a44d2..deae9716 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -662,7 +662,7 @@ Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ Postgres.prototype.visitSubquery = function(queryNode) { // create another query builder of the current class to build the subquery - var subQuery = new this._myClass(); + var subQuery = new this._myClass(this.config); // let the subquery modify this instance's params array subQuery.params = this.params; diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index e27beecf..dd2f27e8 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -85,6 +85,36 @@ Harness.test({ params: [] }); +// Subquery with a date +Harness.test({ + query: Sql.select('*').from(post.subQuery().where(post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')))), + pg: { + text : 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = $1))', + string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = \'2000-01-01T00:00:00.000Z\'))' + }, + sqlite: { + text : 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = $1))', + string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = 946684800000))', + config: { + dateTimeMillis: true + } + }, + mysql: { + text : 'SELECT * FROM (SELECT * FROM `post` WHERE (`post`.`content` = ?))', + string: 'SELECT * FROM (SELECT * FROM `post` WHERE (`post`.`content` = \'2000-01-01T00:00:00.000Z\'))' + }, + mssql: { + text : 'SELECT * FROM (SELECT * FROM [post] WHERE ([post].[content] = @1))', + string: 'SELECT * FROM (SELECT * FROM [post] WHERE ([post].[content] = \'2000-01-01T00:00:00.000Z\'))' + }, + oracle: { + text : 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = :1))', + string: 'SELECT * FROM (SELECT * FROM "post" WHERE ("post"."content" = \'2000-01-01T00:00:00.000Z\'))' + }, + params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] +}); + + Harness.test({ query: Sql.select('*').from(customer.subQuery('T1')).from(user.subQuery('T2')), pg: { From ea5cf415e8252f73b9ffa1b667e79399772df5f4 Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 17 Nov 2015 10:01:50 -0700 Subject: [PATCH 156/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7bd6325f..bf9f0476 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.63.0", + "version": "0.63.1", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 8012e59e977938394c9565ce0d2a52d8a98bbc2d Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Fri, 11 Dec 2015 23:31:59 -0800 Subject: [PATCH 157/248] updated value exists to type check --- lib/dialect/postgres.js | 2 +- test/column-tests.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index deae9716..35cc0fae 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -729,7 +729,7 @@ Postgres.prototype.visitColumn = function(columnNode) { } } if(!inInsertUpdateClause && !this.visitingReturning && !this._visitingCreate && !this._visitingAlter && !columnNode.subfieldContainer) { - if(table.alias) { + if(typeof table.alias === 'string') { txt.push(this.quote(table.alias)); } else { if(table.getSchema()) { diff --git a/test/column-tests.js b/test/column-tests.js index 9bcc15ac..6fb61559 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -6,7 +6,7 @@ var sql = require(__dirname + '/../lib'); describe('column', function() { var table = sql.define({ name: 'user', - columns: ['id', 'created'] + columns: ['id', 'created', 'alias'] }); it('can be accessed by property and array', function() { @@ -18,6 +18,10 @@ describe('column', function() { assert.equal(table.id.toQuery().text, '"user"."id"'); }); + it('works with a column name of "alias"', function() { + assert.equal(table.alias.toQuery().text, '"user"."alias"'); + }); + it('respects AS rename', function() { assert.equal(table.id.as('userId').toQuery().text, '"user"."id" AS "userId"'); }); From aa98ea9ae8137475cf3c7ff7e41f146f4bc7f245 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Mon, 14 Dec 2015 13:07:34 -0800 Subject: [PATCH 158/248] additional check of alias as string --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 35cc0fae..2c65f6f5 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -689,7 +689,7 @@ Postgres.prototype.visitTable = function(tableNode) { txt += '.'; } txt += this.quote(table.getName()); - if(table.alias) { + if(typeof table.alias === 'string') { txt += this._aliasText + this.quote(table.alias); } return [txt]; From 6b4ec4a91294e94a8b986cdd01e1a0a69b2a7aa3 Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 18 Dec 2015 23:02:16 -0600 Subject: [PATCH 159/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bf9f0476..abed9bab 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.63.1", + "version": "0.64.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 96b0b771ebde964f2fd0d652772d6748c5d9d4db Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 18 Dec 2015 23:37:13 -0600 Subject: [PATCH 160/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index abed9bab..57213252 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.64.0", + "version": "0.64.1", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From da3975cf67251b6dd180ee02361be59016598698 Mon Sep 17 00:00:00 2001 From: beedi Date: Wed, 30 Dec 2015 22:21:34 +0100 Subject: [PATCH 161/248] Added Tests for specific constraint on references column, e.g. DEFERRABLE --- test/dialects/create-table-tests.js | 79 +++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index f9c3e2fa..798a077d 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -461,3 +461,82 @@ Harness.test({ params: [] }); +const users = Table.define({ + name: 'users', + columns: { + id: { + primaryKey: true, + dataType: 'int', + references: { + table: "entity", + column: "id", + constraint: "DEFERRABLE INITIALLY DEFERRED" + } + } + } +}); + +Harness.test({ + query: users.create(), + pg: { + text : 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' + }, + sqlite: { + text : 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' + }, + mysql: { + text : 'CREATE TABLE `users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`) DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE `users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`) DEFERRABLE INITIALLY DEFERRED)' + }, + mssql: { + text : 'CREATE TABLE [users] ([id] int PRIMARY KEY REFERENCES [entity]([id]) DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE [users] ([id] int PRIMARY KEY REFERENCES [entity]([id]) DEFERRABLE INITIALLY DEFERRED)' + }, + oracle: { + text : 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)', + string: 'CREATE TABLE "users" ("id" int PRIMARY KEY REFERENCES "entity"("id") DEFERRABLE INITIALLY DEFERRED)' + }, + params: [] +}); + +const noUsers = Table.define({ + name: 'no_users', + columns: { + id: { + primaryKey: true, + dataType: 'int', + references: { + table: "entity", + column: "id", + constraint: "" + } + } + } +}); + +Harness.test({ + query: noUsers.create(), + pg: { + text : 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', + string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' + }, + sqlite: { + text : 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', + string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' + }, + mysql: { + text : 'CREATE TABLE `no_users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`))', + string: 'CREATE TABLE `no_users` (`id` int PRIMARY KEY REFERENCES `entity`(`id`))' + }, + mssql: { + text : 'CREATE TABLE [no_users] ([id] int PRIMARY KEY REFERENCES [entity]([id]))', + string: 'CREATE TABLE [no_users] ([id] int PRIMARY KEY REFERENCES [entity]([id]))' + }, + oracle: { + text : 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))', + string: 'CREATE TABLE "no_users" ("id" int PRIMARY KEY REFERENCES "entity"("id"))' + }, + params: [] +}); \ No newline at end of file From 642592efaa1c1a5738911b353e7ea81dca0af78e Mon Sep 17 00:00:00 2001 From: beedi Date: Wed, 30 Dec 2015 22:37:06 +0100 Subject: [PATCH 162/248] Fix typo in test --- test/dialects/create-table-tests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 798a077d..160e7262 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -461,7 +461,7 @@ Harness.test({ params: [] }); -const users = Table.define({ +var users = Table.define({ name: 'users', columns: { id: { @@ -501,7 +501,7 @@ Harness.test({ params: [] }); -const noUsers = Table.define({ +var noUsers = Table.define({ name: 'no_users', columns: { id: { From f41c5f53adad06480aca59af878179c2a5606c78 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 2 Jan 2016 08:45:18 -0500 Subject: [PATCH 163/248] Adds ability to override the default parameter place holder of @index and use ? instead. Addresses #285. --- lib/dialect/mssql.js | 9 +++++++++ test/index-tests.js | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index daf64938..2cb73b40 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -6,6 +6,14 @@ var util = require('util'); var assert = require('assert'); +/** + * Config can contain: + * + * questionMarkParameterPlaceholder:true which will use a "?" for the parameter placeholder instead of the @index. + * + * @param config + * @constructor + */ var Mssql = function(config) { this.output = []; this.params = []; @@ -23,6 +31,7 @@ Mssql.prototype._quoteCharacter = '['; Mssql.prototype._arrayAggFunctionName = ''; Mssql.prototype._getParameterPlaceholder = function(index, value) { + if (this.config.questionMarkParameterPlaceholder) return '?'; return '@' + index; }; diff --git a/test/index-tests.js b/test/index-tests.js index 0893a7ef..f25839e1 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -195,4 +195,20 @@ suite('index', function() { }); }); + test('mssql default parameter place holder is @index', function() { + var Sql = sql.Sql; + var mssql = new Sql('mssql'); + var query = mssql.select(user.id).from(user).where(user.email.equals('x@y.com')).toQuery(); + assert.equal(query.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = @1)'); + assert.equal(query.values[0], 'x@y.com'); + }); + + test('mssql override default parameter placeholder with ?', function() { + var Sql = sql.Sql; + var mssql = new Sql('mssql',{questionMarkParameterPlaceholder:true}); + var query = mssql.select(user.id).from(user).where(user.email.equals('x@y.com')).toQuery(); + assert.equal(query.text, 'SELECT [user].[id] FROM [user] WHERE ([user].[email] = ?)'); + assert.equal(query.values[0], 'x@y.com'); + }); + }); From bc2c205557b45e02a995cc80294a0c1a18ea32b3 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Sun, 3 Jan 2016 01:00:15 -0800 Subject: [PATCH 164/248] Issue-266: on create added UNIQUE column constraint --- lib/dialect/postgres.js | 3 + lib/node/column.js | 1 + test/dialects/create-table-tests.js | 102 ++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 2c65f6f5..c4b9eae8 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -785,6 +785,9 @@ Postgres.prototype.visitColumn = function(columnNode) { } else if (columnNode.notNull) { txt.push(' NOT NULL'); } + if (!columnNode.primaryKey && columnNode.unique) { + txt.push(' UNIQUE') + } } if (!!columnNode.references) { diff --git a/lib/node/column.js b/lib/node/column.js index 03b58ad5..6fa999fb 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -24,6 +24,7 @@ module.exports = Node.define({ this.subfieldContainer = config.subfieldContainer; this.subfields = config.subfields; this.autoGenerated = !!config.autoGenerated; + this.unique = !!config.unique; }, as: function(alias) { this.alias = alias; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index f9c3e2fa..80d65fbc 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -461,3 +461,105 @@ Harness.test({ params: [] }); +// UNIQUE COLUMN TESTS +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'id', + dataType: 'int', + //primaryKey: true, + //notNull: true, + unique: true + }] + }).create(), + pg: { + text : 'CREATE TABLE "post" ("id" int UNIQUE)', + string: 'CREATE TABLE "post" ("id" int UNIQUE)' + }, + sqlite: { + text : 'CREATE TABLE "post" ("id" int UNIQUE)', + string: 'CREATE TABLE "post" ("id" int UNIQUE)' + }, + mysql: { + text : 'CREATE TABLE `post` (`id` int UNIQUE)', + string: 'CREATE TABLE `post` (`id` int UNIQUE)' + }, + mssql: { + text : 'CREATE TABLE [post] ([id] int UNIQUE)', + string: 'CREATE TABLE [post] ([id] int UNIQUE)' + }, + oracle: { + text : 'CREATE TABLE "post" ("id" int UNIQUE)', + string: 'CREATE TABLE "post" ("id" int UNIQUE)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'id', + dataType: 'int', + //primaryKey: true, + notNull: true, + unique: true + }] + }).create(), + pg: { + text : 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', + string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' + }, + sqlite: { + text : 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', + string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' + }, + mysql: { + text : 'CREATE TABLE `post` (`id` int NOT NULL UNIQUE)', + string: 'CREATE TABLE `post` (`id` int NOT NULL UNIQUE)' + }, + mssql: { + text : 'CREATE TABLE [post] ([id] int NOT NULL UNIQUE)', + string: 'CREATE TABLE [post] ([id] int NOT NULL UNIQUE)' + }, + oracle: { + text : 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)', + string: 'CREATE TABLE "post" ("id" int NOT NULL UNIQUE)' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'id', + dataType: 'int', + primaryKey: true, + //notNull: true, + unique: true + }] + }).create(), + pg: { + text : 'CREATE TABLE "post" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' + }, + sqlite: { + text : 'CREATE TABLE "post" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' + }, + mysql: { + text : 'CREATE TABLE `post` (`id` int PRIMARY KEY)', + string: 'CREATE TABLE `post` (`id` int PRIMARY KEY)' + }, + mssql: { + text : 'CREATE TABLE [post] ([id] int PRIMARY KEY)', + string: 'CREATE TABLE [post] ([id] int PRIMARY KEY)' + }, + oracle: { + text : 'CREATE TABLE "post" ("id" int PRIMARY KEY)', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' + }, + params: [] +}); From 3b850e85ee75119a3bdd79b5dcd96a4c12601bba Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 4 Jan 2016 15:03:51 -0600 Subject: [PATCH 165/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 57213252..c99ef1ea 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.64.1", + "version": "0.65.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 93afffea186c451f47525c6f22ef6732a7b174eb Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 00:34:31 -0800 Subject: [PATCH 166/248] jshint: missing semicolon --- lib/dialect/mssql.js | 26 +++++++++++++------------- lib/dialect/mysql.js | 2 +- lib/dialect/oracle.js | 12 ++++++------ lib/dialect/postgres.js | 28 ++++++++++++++-------------- lib/dialect/sqlite.js | 20 ++++++++++---------- lib/node/valueExpression.js | 4 ++-- lib/table.js | 6 +++--- runtests.js | 24 ++++++++++++------------ test/column-tests.js | 4 ++-- test/dialects/subquery-tests.js | 2 +- 10 files changed, 64 insertions(+), 64 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 2cb73b40..c5673371 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -104,7 +104,7 @@ Mssql.prototype.visitAlter = function(alter) { var table = self._queryNode.table; var result = ['EXEC sp_rename '+self.visit(table.toNode())+', '+self.visit(alter.nodes[0].nodes[0])]; self._visitingAlter = false; - return result + return result; } // Implement our own rename column: @@ -119,7 +119,7 @@ Mssql.prototype.visitAlter = function(alter) { "'COLUMN'" ]; self._visitingAlter = false; - return result + return result; } if (isAlterAddColumn(alter)) return _addColumn(); @@ -133,7 +133,7 @@ Mssql.prototype.visitAlter = function(alter) { // CASE WHEN true THEN xxx END // the "true" has to be a boolean expression like 1=1 Mssql.prototype.visitCase = function(caseExp) { - var _this=this + var _this=this; function _whenValue(node){ if (node.type!='PARAMETER') return _this.visit(node); @@ -163,7 +163,7 @@ Mssql.prototype.visitCase = function(caseExp) { text += ' END)'; return [text]; -} +}; Mssql.prototype.visitColumn = function(columnNode) { var self=this; @@ -171,12 +171,12 @@ Mssql.prototype.visitColumn = function(columnNode) { var inSelectClause; function _arrayAgg(){ - throw new Error("SQL Server does not support array_agg.") + throw new Error("SQL Server does not support array_agg."); } function _countStar(){ // Implement our own since count(table.*) is invalid in Mssql - var result='COUNT(*)' + var result='COUNT(*)'; if(inSelectClause && columnNode.alias) { result += ' AS ' + self.quote(columnNode.alias); } @@ -193,8 +193,8 @@ Mssql.prototype.visitColumn = function(columnNode) { Mssql.prototype.visitCreate = function(create) { - var isNotExists=isCreateIfNotExists(create) - var isTemporary=isCreateTemporary(create) + var isNotExists=isCreateIfNotExists(create); + var isTemporary=isCreateTemporary(create); if (!isNotExists && !isTemporary) { return Mssql.super_.prototype.visitCreate.call(this, create); } @@ -219,7 +219,7 @@ Mssql.prototype.visitCreate = function(create) { // if (schema) { whereClause+=' AND TABLE_SCHEMA = schemaResult.join(' ')} // Add some tests for this as well - if (!isNotExists) return createResult + if (!isNotExists) return createResult; return ['IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES '+whereClause+') BEGIN '+createResult.join(' ')+' END']; }; @@ -246,9 +246,9 @@ Mssql.prototype.visitDrop = function(drop) { Mssql.prototype.visitFunctionCall = function(functionCall) { this._visitingFunctionCall = true; - var name=functionCall.name + var name=functionCall.name; // override the LENGTH function since mssql calls it LEN - if (name=="LENGTH") name="LEN" + if (name=="LENGTH") name="LEN"; var txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; this._visitingFunctionCall = false; return [txt]; @@ -385,7 +385,7 @@ Mssql.prototype.visitSelect = function(select) { // Node is either an OFFSET or LIMIT node function getModifierValue(dialect,node){ - return node.count.type ? dialect.visit(node.count) : node.count + return node.count.type ? dialect.visit(node.count) : node.count; } function isAlterAddColumn(alter){ @@ -426,7 +426,7 @@ function isCreateIfNotExists(create){ }; function isCreateTemporary(create){ - return create.options.isTemporary + return create.options.isTemporary; }; function isDropIfExists(drop){ diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index b4e8249c..9d582ce7 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -100,6 +100,6 @@ Mysql.prototype.visitBinary = function(binary) { return [text]; } return Mysql.super_.prototype.visitBinary.call(this, binary); -} +}; module.exports = Mysql; diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index ce912b2c..de52342e 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -75,7 +75,7 @@ Oracle.prototype.visitDrop = function(drop) { }; Oracle.prototype.visitCreate = function(create) { - var isNotExists=isCreateIfNotExists(create) + var isNotExists=isCreateIfNotExists(create); //var isTemporary=isCreateTemporary(create) var createText = Oracle.super_.prototype.visitCreate.call(this, create); if (isNotExists) { @@ -145,7 +145,7 @@ Oracle.prototype.visitQueryHelper=function(actions,targets,filters){ } return this.output; -} +}; Oracle.prototype.visitColumn = function(columnNode) { var self=this; @@ -153,12 +153,12 @@ Oracle.prototype.visitColumn = function(columnNode) { var inSelectClause; function _arrayAgg(){ - throw new Error("Oracle does not support array_agg.") + throw new Error("Oracle does not support array_agg."); } function _countStar(){ // Implement our own since count(table.*) is invalid in Oracle - var result='COUNT(*)' + var result='COUNT(*)'; if(inSelectClause && columnNode.alias) { result += self._aliasText + self.quote(columnNode.alias); } @@ -222,7 +222,7 @@ Oracle.prototype.visitDropIndex = function(node) { Oracle.prototype.visitCase = function(caseExp) { return Mssql.prototype.visitCase.call(this, caseExp); -} +}; function isCreateIfNotExists(create){ @@ -232,7 +232,7 @@ function isCreateIfNotExists(create){ }; function isCreateTemporary(create){ - return create.options.isTemporary + return create.options.isTemporary; }; function isDropIfExists(drop){ diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index c4b9eae8..a5f0f413 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -187,14 +187,14 @@ Postgres.prototype.quote = function(word, quoteCharacter) { } // handle square brackets specially if (q=='['){ - return '['+word+']' + return '['+word+']'; } else { return q + word.replace(new RegExp(q,'g'),q+q) + q; } }; Postgres.prototype.visitSelect = function(select) { - var result = ['SELECT'] + var result = ['SELECT']; if (select.isDistinct) result.push('DISTINCT'); @@ -281,7 +281,7 @@ Postgres.prototype.visitCreate = function(create) { var col_nodes = table.columns.map(function(col) { return col.toNode(); }); var result = ['CREATE TABLE']; - if (create.options.isTemporary) result=['CREATE TEMPORARY TABLE'] + if (create.options.isTemporary) result=['CREATE TEMPORARY TABLE']; result = result.concat(create.nodes.map(this.visit.bind(this))); result.push(this.visit(table.toNode())); var primary_col_nodes = col_nodes.filter(function(n) { @@ -547,7 +547,7 @@ Postgres.prototype.visitCase = function(caseExp) { text += ' END)'; return [text]; -} +}; Postgres.prototype.visitAt = function(at) { var text = '(' + this.visit(at.value) + ')[' + this.visit(at.index) + ']'; @@ -637,7 +637,7 @@ Postgres.prototype.visitQuery = function(queryNode) { throw new Error('Create View requires a Select.'); } } - return this.visitQueryHelper(actions,targets,filters) + return this.visitQueryHelper(actions,targets,filters); }; /** @@ -649,7 +649,7 @@ Postgres.prototype.visitQuery = function(queryNode) { * @returns {String[]} */ Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ - this.handleDistinct(actions, filters) + this.handleDistinct(actions, filters); // lazy-man sorting var sortedNodes = actions.concat(targets).concat(filters); for(var i = 0; i < sortedNodes.length; i++) { @@ -658,7 +658,7 @@ Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ } // implicit 'from' return this.output; -} +}; Postgres.prototype.visitSubquery = function(queryNode) { // create another query builder of the current class to build the subquery @@ -786,7 +786,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push(' NOT NULL'); } if (!columnNode.primaryKey && columnNode.unique) { - txt.push(' UNIQUE') + txt.push(' UNIQUE'); } } @@ -817,7 +817,7 @@ Postgres.prototype.visitColumn = function(columnNode) { var onDelete = columnNode.references.onDelete; if (onDelete) onDelete = onDelete.toUpperCase(); if (onDelete === 'CASCADE' || onDelete === 'RESTRICT') { - txt.push(' ON DELETE ' + onDelete) + txt.push(' ON DELETE ' + onDelete); } } } @@ -1006,8 +1006,8 @@ Postgres.prototype.findNode=function(list,type) { var n=list[i]; if (n.type==type) return {index:i,node:n}; } - return undefined -} + return undefined; +}; /** * pulls the DISTINCT node out of the filters and flags the SELECT node that it should be distinct. @@ -1017,11 +1017,11 @@ Postgres.prototype.handleDistinct = function(actions,filters) { var distinctNode = this.findNode(filters,"DISTINCT"); //if (!distinctNode) distinctNode = _findNode(targets,"DISTINCT"); //if (!distinctNode) distinctNode = _findNode(actions,"DISTINCT"); - if (!distinctNode) return + if (!distinctNode) return; var selectInfo = this.findNode(actions,"SELECT"); - if (!selectInfo) return // there should be one by now, I think + if (!selectInfo) return; // there should be one by now, I think // mark the SELECT node that it's distinct selectInfo.node.isDistinct = true; -} +}; module.exports = Postgres; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 611112e8..6f487719 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -38,28 +38,28 @@ Sqlite.prototype.visitDropColumn = function() { }; Sqlite.prototype.visitFunctionCall = function(functionCall) { - var _this=this + var _this=this; this._visitingFunctionCall = true; function _left() { // convert LEFT(column,4) to SUBSTR(column,1,4) - var nodes = functionCall.nodes.map(_this.visit.bind(_this)) - if (nodes.length != 2) throw new Error('Not enough parameters passed to LEFT function.') + var nodes = functionCall.nodes.map(_this.visit.bind(_this)); + if (nodes.length != 2) throw new Error('Not enough parameters passed to LEFT function.'); var txt = "SUBSTR(" + (nodes[0]+'') + ', 1, ' + (nodes[1]+'') + ')'; - return txt + return txt; } function _right() { // convert RIGHT(column,4) to SUBSTR(column,-4) - var nodes = functionCall.nodes.map(_this.visit.bind(_this)) - if (nodes.length != 2) throw new Error('Not enough parameters passed to RIGHT function.') + var nodes = functionCall.nodes.map(_this.visit.bind(_this)); + if (nodes.length != 2) throw new Error('Not enough parameters passed to RIGHT function.'); var txt = "SUBSTR(" + (nodes[0]+'') + ', -' + (nodes[1]+'') + ')'; - return txt + return txt; } - var txt="" - var name=functionCall.name + var txt=""; + var name=functionCall.name; // Override LEFT and RIGHT and convert to SUBSTR if (name == "LEFT") txt = _left(); else if (name == "RIGHT") txt = _right(); @@ -123,6 +123,6 @@ Sqlite.prototype.visitBinary = function(binary) { return ret; } return Sqlite.super_.prototype.visitBinary.call(this, binary); -} +}; module.exports = Sqlite; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index e04ba5ff..34f6e896 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -110,8 +110,8 @@ var ValueExpressionMixin = function() { whenList : processParams(whenList), thenList : processParams(thenList), else : elseBranch - }) - } + }); + }; return { isNull : postfixUnaryMethod('IS NULL'), diff --git a/lib/table.js b/lib/table.js index f9c0b88c..c702a6e3 100644 --- a/lib/table.js +++ b/lib/table.js @@ -15,7 +15,7 @@ var Table = function(config) { this._name = config.name; this._initialConfig = config; this.columnWhiteList = !!config.columnWhiteList; - this.isTemporary=!!config.isTemporary + this.isTemporary=!!config.isTemporary; this.snakeToCamel = !!config.snakeToCamel; this.columns = []; this.table = this; @@ -76,10 +76,10 @@ Table.prototype.createColumn = function(col) { table: this, subfieldContainer: col, name: subfield - })] + })]; }, this)) .object() - .value() + .value(); } } diff --git a/runtests.js b/runtests.js index 8b722efe..ac89769b 100644 --- a/runtests.js +++ b/runtests.js @@ -1,18 +1,18 @@ -var childProcess = require("child_process") -var path = require("path") +var childProcess = require("child_process"); +var path = require("path"); -var env = process.env -env.NODE_ENV = "test" +var env = process.env; +env.NODE_ENV = "test"; var options = { env: env -} +}; -var command = path.join(".", "node_modules", ".bin", "mocha") -if (process.platform == "win32") command += ".cmd" -var run = childProcess.spawn(command, [], options) -run.stdout.pipe(process.stdout) -run.stderr.pipe(process.stderr) +var command = path.join(".", "node_modules", ".bin", "mocha"); +if (process.platform == "win32") command += ".cmd"; +var run = childProcess.spawn(command, [], options); +run.stdout.pipe(process.stdout); +run.stderr.pipe(process.stderr); run.on('close', function(code) { - process.exit(code) -}) + process.exit(code); +}); diff --git a/test/column-tests.js b/test/column-tests.js index 6fb61559..f1a6f1a5 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -96,10 +96,10 @@ describe('column', function() { columns: ['id', 'name'] }); it('throws for insert properties that are not a column', function() { - assert.throws(function() { table.insert({id:0, _private:'_private', name:'name'}) }, Error); + assert.throws(function() { table.insert({id:0, _private:'_private', name:'name'}); }, Error); }); it('throws for update properties that are not a column', function() { - assert.throws(function() { table.update({id:0, _private:'_private', name:'name'}) }, Error); + assert.throws(function() { table.update({id:0, _private:'_private', name:'name'}); }, Error); }); }); diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 1c79c283..fe5b2aad 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -29,7 +29,7 @@ Harness.test({ string: 'SELECT "user"."name" FROM "user" WHERE ("user"."id" IN (SELECT "post"."userId" FROM "post"))' }, params: [] -}) +}); Harness.test({ query: user.name.in( From 66f2ce0b4e89c675554b8917dcc8faf719b5bc59 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 00:39:42 -0800 Subject: [PATCH 167/248] jshint: Unnecessary semicolon --- lib/dialect/mssql.js | 18 +++++++++--------- lib/dialect/oracle.js | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index c5673371..2845ce42 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -392,52 +392,52 @@ function isAlterAddColumn(alter){ if (alter.nodes.length==0) return false; if (alter.nodes[0].type!='ADD COLUMN') return false; return true; -}; +} function isAlterDropColumn(alter){ if (alter.nodes.length==0) return false; if (alter.nodes[0].type!='DROP COLUMN') return false; return true; -}; +} function isAlterRename(alter){ if (alter.nodes.length==0) return false; if (alter.nodes[0].type!='RENAME') return false; return true; -}; +} function isAlterRenameColumn(alter){ if (alter.nodes.length==0) return false; if (alter.nodes[0].type!='RENAME COLUMN') return false; return true; -}; +} function isCountStarExpression(columnNode){ if (!columnNode.aggregator) return false; if (columnNode.aggregator.toLowerCase()!='count') return false; if (!columnNode.star) return false; return true; -}; +} function isCreateIfNotExists(create){ if (create.nodes.length==0) return false; if (create.nodes[0].type!='IF NOT EXISTS') return false; return true; -}; +} function isCreateTemporary(create){ return create.options.isTemporary; -}; +} function isDropIfExists(drop){ if (drop.nodes.length==0) return false; if (drop.nodes[0].type!='IF EXISTS') return false; return true; -}; +} // SQL Server does not support array expressions except in the IN clause. function isRightSideArray(binary){ return Array.isArray(binary.right); -}; +} module.exports = Mssql; diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index de52342e..f1e3567e 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -229,28 +229,28 @@ function isCreateIfNotExists(create){ if (create.nodes.length==0) return false; if (create.nodes[0].type!='IF NOT EXISTS') return false; return true; -}; +} function isCreateTemporary(create){ return create.options.isTemporary; -}; +} function isDropIfExists(drop){ if (drop.nodes.length==0) return false; if (drop.nodes[0].type!='IF EXISTS') return false; return true; -}; +} // SQL Server does not support array expressions except in the IN clause. function isRightSideArray(binary){ return Array.isArray(binary.right); -}; +} function isCountStarExpression(columnNode){ if (!columnNode.aggregator) return false; if (columnNode.aggregator.toLowerCase()!='count') return false; if (!columnNode.star) return false; return true; -}; +} module.exports = Oracle; From 43c1ceee0f00bd7abc54e7464b5d9ea8e869e217 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 00:45:53 -0800 Subject: [PATCH 168/248] jshint: Use '===' to compare with '0' --- lib/dialect/mssql.js | 12 ++++++------ lib/dialect/oracle.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 2845ce42..ca1286af 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -389,25 +389,25 @@ function getModifierValue(dialect,node){ } function isAlterAddColumn(alter){ - if (alter.nodes.length==0) return false; + if (alter.nodes.length===0) return false; if (alter.nodes[0].type!='ADD COLUMN') return false; return true; } function isAlterDropColumn(alter){ - if (alter.nodes.length==0) return false; + if (alter.nodes.length===0) return false; if (alter.nodes[0].type!='DROP COLUMN') return false; return true; } function isAlterRename(alter){ - if (alter.nodes.length==0) return false; + if (alter.nodes.length===0) return false; if (alter.nodes[0].type!='RENAME') return false; return true; } function isAlterRenameColumn(alter){ - if (alter.nodes.length==0) return false; + if (alter.nodes.length===0) return false; if (alter.nodes[0].type!='RENAME COLUMN') return false; return true; } @@ -420,7 +420,7 @@ function isCountStarExpression(columnNode){ } function isCreateIfNotExists(create){ - if (create.nodes.length==0) return false; + if (create.nodes.length===0) return false; if (create.nodes[0].type!='IF NOT EXISTS') return false; return true; } @@ -430,7 +430,7 @@ function isCreateTemporary(create){ } function isDropIfExists(drop){ - if (drop.nodes.length==0) return false; + if (drop.nodes.length===0) return false; if (drop.nodes[0].type!='IF EXISTS') return false; return true; } diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index f1e3567e..54343717 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -226,7 +226,7 @@ Oracle.prototype.visitCase = function(caseExp) { function isCreateIfNotExists(create){ - if (create.nodes.length==0) return false; + if (create.nodes.length===0) return false; if (create.nodes[0].type!='IF NOT EXISTS') return false; return true; } @@ -236,7 +236,7 @@ function isCreateTemporary(create){ } function isDropIfExists(drop){ - if (drop.nodes.length==0) return false; + if (drop.nodes.length===0) return false; if (drop.nodes[0].type!='IF EXISTS') return false; return true; } From 2fdd98404f46a598fcfff6db7a5d52d410f5ba59 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 00:56:07 -0800 Subject: [PATCH 169/248] jhint: Use '===' to compare with 'true' --- lib/dialect/mssql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index ca1286af..8f11150f 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -139,7 +139,7 @@ Mssql.prototype.visitCase = function(caseExp) { if (node.type!='PARAMETER') return _this.visit(node); // dealing with a true/false value var val=node.value(); - if (val==true) return '1=1'; else return '0=1'; + if (val===true) return '1=1'; else return '0=1'; } assert(caseExp.whenList.length == caseExp.thenList.length); From 31f388ae612ff271cbc4a2e38a092fd6a3913bca Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:00:07 -0800 Subject: [PATCH 170/248] jshit: Use '!==' to compare with 'null' --- lib/dialect/mssql.js | 2 +- lib/dialect/postgres.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 8f11150f..84c0b839 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -155,7 +155,7 @@ Mssql.prototype.visitCase = function(caseExp) { text += whenExp + thenExp; } - if (null != caseExp.else && undefined != caseExp.else) { + if (null !== caseExp.else && undefined != caseExp.else) { text += ' ELSE ' + this.visit(caseExp.else); } diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a5f0f413..a0683686 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -539,7 +539,7 @@ Postgres.prototype.visitCase = function(caseExp) { text += whenExp + thenExp; } - if (null != caseExp.else && undefined != caseExp.else) { + if (null !== caseExp.else && undefined != caseExp.else) { text += ' ELSE ' + this.visit(caseExp.else); } From 930ec220c78d7688f19fc6cd7a97da4a49044e67 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:04:17 -0800 Subject: [PATCH 171/248] jshint: Use '!==' to compare with 'undefined' --- lib/dialect/mssql.js | 4 ++-- lib/dialect/postgres.js | 2 +- lib/node/valueExpression.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 84c0b839..7b0d52d3 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -155,7 +155,7 @@ Mssql.prototype.visitCase = function(caseExp) { text += whenExp + thenExp; } - if (null !== caseExp.else && undefined != caseExp.else) { + if (null !== caseExp.else && undefined !== caseExp.else) { text += ' ELSE ' + this.visit(caseExp.else); } @@ -302,7 +302,7 @@ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ */ function _processLimit(limitInfo){ var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); - assert(selectInfo!=undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); + assert(selectInfo!==undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); // save the LIMIT node with the SELECT node selectInfo.node.msSQLLimitNode=limitInfo.node; // remove the LIMIT node from the filters so it doesn't get processed later. diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a0683686..23f5a236 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -539,7 +539,7 @@ Postgres.prototype.visitCase = function(caseExp) { text += whenExp + thenExp; } - if (null !== caseExp.else && undefined != caseExp.else) { + if (null !== caseExp.else && undefined !== caseExp.else) { text += ' ELSE ' + this.visit(caseExp.else); } diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 34f6e896..9be50e7a 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -103,7 +103,7 @@ var ValueExpressionMixin = function() { }; var caseMethod = function(whenList, thenList, elseBranch) { - if (undefined != elseBranch) { + if (undefined !== elseBranch) { elseBranch = processParams(elseBranch); } return new CaseNode({ From 0aceecbcc1cfbd9b57a9b3246faea122900d11fe Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:06:27 -0800 Subject: [PATCH 172/248] jshint: Use '===' to compare with '0' --- lib/table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index c702a6e3..86e8adbe 100644 --- a/lib/table.js +++ b/lib/table.js @@ -195,7 +195,7 @@ Table.prototype.subQuery = function(alias) { Table.prototype.insert = function() { var query = new Query(this); - if(arguments[0].length == 0){ + if(arguments[0].length === 0){ query.select.call(query, this.star()); query.where.apply(query,["1=2"]); } else { From f2016acc24339a06b322e89b2a368701bd24fb57 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:18:36 -0800 Subject: [PATCH 173/248] jshint: unused variables --- lib/node/valueExpression.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 9be50e7a..faad8033 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -77,18 +77,6 @@ var ValueExpressionMixin = function() { return new SliceNode(this.toNode(), processParams(start), processParams(end)); }; - var containsMethod = function(set) { - return new ContainsNode(this.toNode(), processParams(set)); - }; - - var containedByMethod = function(set) { - return new ContainedByNode(this.toNode(), processParams(set)); - }; - - var overlapMethod = function(set) { - return new OverlapNode(this.toNode(), processParams(set)); - }; - var castMethod = function(dataType) { return new CastNode(this.toNode(), dataType); }; From 888c4e5681df66785999932e3fedc4a7536fab0b Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:36:00 -0800 Subject: [PATCH 174/248] jshint: ignore:line --- lib/dialect/postgres.js | 2 +- lib/node/query.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 23f5a236..74e3769a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -594,7 +594,7 @@ Postgres.prototype.visitQuery = function(queryNode) { var node = queryNode.nodes[i]; switch(node.type) { case "SELECT": - isSelect = true; + isSelect = true; // jshint ignore:line case "DELETE": actions.push(node); break; diff --git a/lib/node/query.js b/lib/node/query.js index 85cfa9e5..0e05985f 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -280,7 +280,7 @@ var Query = Node.define({ var col = self.table.get(key); if(col && !col.autoGenerated) var val = o[key]; - onDuplicate.add(col.value(ParameterNode.getNodeOrParameterNode(val))); + onDuplicate.add(col.value(ParameterNode.getNodeOrParameterNode(val))); // jshint ignore:line }); return self.add(onDuplicate); From e0643275c9c5dd1a2b48a7ed58fb069283cbd6c1 Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:39:40 -0800 Subject: [PATCH 175/248] jshint: Possible strict violation --- lib/dialect/mssql.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 7b0d52d3..5c547f49 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -282,9 +282,9 @@ Mssql.prototype.visitOrderBy = function(orderBy) { */ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ function _handleLimitAndOffset(){ - var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); - var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); - var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); + var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); // jshint ignore:line + var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); // jshint ignore:line + var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); // jshint ignore:line // no OFFSET or LIMIT then there's nothing special to do if (!offsetInfo && !limitInfo) return; @@ -301,7 +301,7 @@ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ * @private */ function _processLimit(limitInfo){ - var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); + var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); // jshint ignore:line assert(selectInfo!==undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); // save the LIMIT node with the SELECT node selectInfo.node.msSQLLimitNode=limitInfo.node; From 1c55b0ecdadf4e131e27437367632893295a4dda Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:43:22 -0800 Subject: [PATCH 176/248] jshint: 'i' is already defined --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 74e3769a..6af424d9 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -766,7 +766,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push(this.quote(columnNode.name)); } if(closeParen) { - for(var i = 0; i < closeParen; i++) { + for(var j = 0; j < closeParen; j++) { txt.push(')'); } } From b6e7e7140160be1a1d81179705ec5c7a6ab6f22c Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 01:49:29 -0800 Subject: [PATCH 177/248] jshint: Bad line breaking before '&&' --- lib/dialect/postgres.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6af424d9..764289b5 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -702,11 +702,11 @@ Postgres.prototype.visitColumn = function(columnNode) { var inSelectClause = this.visitingReturning || (!this._selectOrDeleteEndIndex - && !this._visitingWhere - && !inInsertUpdateClause - && !inDdlClause - && !this.visitingCase - && !this._visitingJoin + && !this._visitingWhere // jshint ignore:line + && !inInsertUpdateClause // jshint ignore:line + && !inDdlClause // jshint ignore:line + && !this.visitingCase // jshint ignore:line + && !this._visitingJoin // jshint ignore:line ); var inFunctionCall = this._visitingFunctionCall; var inCast = this._visitingCast; From c7a36a39cfb769fd95427bc9e070416e034b904b Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Tue, 5 Jan 2016 09:44:31 -0800 Subject: [PATCH 178/248] jshint: tabs to spaces --- lib/dialect/mssql.js | 154 ++++++++++++++++++++-------------------- lib/dialect/oracle.js | 2 +- lib/dialect/postgres.js | 44 ++++++------ lib/dialect/sqlite.js | 46 ++++++------ lib/node/drop.js | 4 +- lib/node/parameter.js | 2 +- lib/node/query.js | 8 +-- lib/node/truncate.js | 4 +- test/column-tests.js | 46 ++++++------ 9 files changed, 155 insertions(+), 155 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 5c547f49..48c1ad45 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -31,7 +31,7 @@ Mssql.prototype._quoteCharacter = '['; Mssql.prototype._arrayAggFunctionName = ''; Mssql.prototype._getParameterPlaceholder = function(index, value) { - if (this.config.questionMarkParameterPlaceholder) return '?'; + if (this.config.questionMarkParameterPlaceholder) return '?'; return '@' + index; }; @@ -246,24 +246,24 @@ Mssql.prototype.visitDrop = function(drop) { Mssql.prototype.visitFunctionCall = function(functionCall) { this._visitingFunctionCall = true; - var name=functionCall.name; - // override the LENGTH function since mssql calls it LEN - if (name=="LENGTH") name="LEN"; + var name=functionCall.name; + // override the LENGTH function since mssql calls it LEN + if (name=="LENGTH") name="LEN"; var txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; this._visitingFunctionCall = false; return [txt]; }; Mssql.prototype.visitOrderBy = function(orderBy) { - var result=Mssql.super_.prototype.visitOrderBy.call(this, orderBy); - var offsetNode=orderBy.msSQLOffsetNode; - var limitNode=orderBy.msSQLLimitNode; - if (!offsetNode && !limitNode) return result; - assert(offsetNode,"Something bad happened, should have had an msSQLOffsetNode here."); - result.push("OFFSET "+getModifierValue(this,offsetNode)+" ROWS"); - if (!limitNode) return result; - result.push("FETCH NEXT "+getModifierValue(this,limitNode)+" ROWS ONLY"); - return result; + var result=Mssql.super_.prototype.visitOrderBy.call(this, orderBy); + var offsetNode=orderBy.msSQLOffsetNode; + var limitNode=orderBy.msSQLLimitNode; + if (!offsetNode && !limitNode) return result; + assert(offsetNode,"Something bad happened, should have had an msSQLOffsetNode here."); + result.push("OFFSET "+getModifierValue(this,offsetNode)+" ROWS"); + if (!limitNode) return result; + result.push("FETCH NEXT "+getModifierValue(this,limitNode)+" ROWS ONLY"); + return result; }; /** @@ -281,63 +281,63 @@ Mssql.prototype.visitOrderBy = function(orderBy) { * @returns {String[]} */ Mssql.prototype.visitQueryHelper=function(actions,targets,filters){ - function _handleLimitAndOffset(){ - var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); // jshint ignore:line - var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); // jshint ignore:line - var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); // jshint ignore:line - - // no OFFSET or LIMIT then there's nothing special to do - if (!offsetInfo && !limitInfo) return; - // ORDER BY with OFFSET we have work to do, may consume LIMIT as well - if (orderByInfo && offsetInfo) _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo); - else if (offsetInfo) throw new Error("MS SQL Server does not allow OFFSET without ORDER BY"); - else if (limitInfo) _processLimit(limitInfo); - } - - /** - * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT - * - * @param limitInfo - * @private - */ - function _processLimit(limitInfo){ - var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); // jshint ignore:line - assert(selectInfo!==undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); - // save the LIMIT node with the SELECT node - selectInfo.node.msSQLLimitNode=limitInfo.node; - // remove the LIMIT node from the filters so it doesn't get processed later. - filters.splice(limitInfo.index,1); - } - - /** - * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT - * - * @param orderByInfo - * @param offsetInfo - * @param limitInfo - * @private - */ - function _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo){ - // save the OFFSET AND LIMIT nodes with the ORDER BY node - orderByInfo.node.msSQLOffsetNode=offsetInfo.node; - if (limitInfo) orderByInfo.node.msSQLLimitNode=limitInfo.node; - // remove the OFFSET and LIMIT nodes from the filters so they don't get processed later. - filters.splice(offsetInfo.index,1); - if (limitInfo) filters.splice(limitInfo.index,1); - } - - // MAIN + function _handleLimitAndOffset(){ + var limitInfo=Mssql.super_.prototype.findNode.call(this, filters, "LIMIT"); // jshint ignore:line + var offsetInfo=Mssql.super_.prototype.findNode.call(this, filters, "OFFSET"); // jshint ignore:line + var orderByInfo=Mssql.super_.prototype.findNode.call(this, filters, "ORDER BY"); // jshint ignore:line + + // no OFFSET or LIMIT then there's nothing special to do + if (!offsetInfo && !limitInfo) return; + // ORDER BY with OFFSET we have work to do, may consume LIMIT as well + if (orderByInfo && offsetInfo) _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo); + else if (offsetInfo) throw new Error("MS SQL Server does not allow OFFSET without ORDER BY"); + else if (limitInfo) _processLimit(limitInfo); + } + + /** + * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT + * + * @param limitInfo + * @private + */ + function _processLimit(limitInfo){ + var selectInfo=Mssql.super_.prototype.findNode.call(this, actions, "SELECT"); // jshint ignore:line + assert(selectInfo!==undefined,"MS SQL Server requires a SELECT clause when using LIMIT"); + // save the LIMIT node with the SELECT node + selectInfo.node.msSQLLimitNode=limitInfo.node; + // remove the LIMIT node from the filters so it doesn't get processed later. + filters.splice(limitInfo.index,1); + } + + /** + * We need to turn LIMIT into a TOP clause on the SELECT STATEMENT + * + * @param orderByInfo + * @param offsetInfo + * @param limitInfo + * @private + */ + function _processOrderByOffsetLimit(orderByInfo,offsetInfo,limitInfo){ + // save the OFFSET AND LIMIT nodes with the ORDER BY node + orderByInfo.node.msSQLOffsetNode=offsetInfo.node; + if (limitInfo) orderByInfo.node.msSQLLimitNode=limitInfo.node; + // remove the OFFSET and LIMIT nodes from the filters so they don't get processed later. + filters.splice(offsetInfo.index,1); + if (limitInfo) filters.splice(limitInfo.index,1); + } + + // MAIN Mssql.super_.prototype.handleDistinct.call(this, actions, filters); - _handleLimitAndOffset(); - - // lazy-man sorting - var sortedNodes = actions.concat(targets).concat(filters); - for(var i = 0; i < sortedNodes.length; i++) { - var res = this.visit(sortedNodes[i]); - this.output = this.output.concat(res); - } - return this.output; + _handleLimitAndOffset(); + + // lazy-man sorting + var sortedNodes = actions.concat(targets).concat(filters); + for(var i = 0; i < sortedNodes.length; i++) { + var res = this.visit(sortedNodes[i]); + this.output = this.output.concat(res); + } + return this.output; }; //Mysql.prototype.visitRenameColumn = function(renameColumn) { @@ -373,19 +373,19 @@ Mssql.prototype.visitReturning = function() { // We deal with SELECT specially so we can add the TOP clause if needed Mssql.prototype.visitSelect = function(select) { - if (!select.msSQLLimitNode) return Mssql.super_.prototype.visitSelect.call(this, select); - var result=[ - 'SELECT', - 'TOP('+getModifierValue(this,select.msSQLLimitNode)+')', - select.nodes.map(this.visit.bind(this)).join(', ') - ]; - this._selectOrDeleteEndIndex = this.output.length + result.length; - return result; + if (!select.msSQLLimitNode) return Mssql.super_.prototype.visitSelect.call(this, select); + var result=[ + 'SELECT', + 'TOP('+getModifierValue(this,select.msSQLLimitNode)+')', + select.nodes.map(this.visit.bind(this)).join(', ') + ]; + this._selectOrDeleteEndIndex = this.output.length + result.length; + return result; }; // Node is either an OFFSET or LIMIT node function getModifierValue(dialect,node){ - return node.count.type ? dialect.visit(node.count) : node.count; + return node.count.type ? dialect.visit(node.count) : node.count; } function isAlterAddColumn(alter){ diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index 54343717..6b597154 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -144,7 +144,7 @@ Oracle.prototype.visitQueryHelper=function(actions,targets,filters){ output[limit+2] = temp[2]; } - return this.output; + return this.output; }; Oracle.prototype.visitColumn = function(columnNode) { diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 764289b5..2e6c35de 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -649,15 +649,15 @@ Postgres.prototype.visitQuery = function(queryNode) { * @returns {String[]} */ Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ - this.handleDistinct(actions, filters); - // lazy-man sorting - var sortedNodes = actions.concat(targets).concat(filters); - for(var i = 0; i < sortedNodes.length; i++) { - var res = this.visit(sortedNodes[i]); - this.output = this.output.concat(res); - } - // implicit 'from' - return this.output; + this.handleDistinct(actions, filters); + // lazy-man sorting + var sortedNodes = actions.concat(targets).concat(filters); + for(var i = 0; i < sortedNodes.length; i++) { + var res = this.visit(sortedNodes[i]); + this.output = this.output.concat(res); + } + // implicit 'from' + return this.output; }; Postgres.prototype.visitSubquery = function(queryNode) { @@ -1002,11 +1002,11 @@ Postgres.prototype.visitCreateView = function(createView) { * @returns {Object|undefined} {index:number, node:Node} */ Postgres.prototype.findNode=function(list,type) { - for (var i= 0, len=list.length; i Date: Tue, 5 Jan 2016 10:21:55 -0800 Subject: [PATCH 179/248] jshint: added npm posttest lint --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c99ef1ea..08d5a618 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,9 @@ }, "main": "lib/", "scripts": { - "test": "node ./runtests" + "test": "node ./runtests", + "lint": "jshint lib test runtests.js", + "posttest": "jshint lib test runtests.js" }, "engines": { "node": "*" From 3553fd23f185d2838ea08c91a6d41afdeb35dfc3 Mon Sep 17 00:00:00 2001 From: Barry Hammen Date: Mon, 11 Jan 2016 12:25:21 -0500 Subject: [PATCH 180/248] Fix booleans and objects --- lib/dialect/postgres.js | 3 ++- lib/dialect/sqlite.js | 5 ++++ test/dialects/case-tests.js | 10 +++---- test/dialects/update-tests.js | 51 +++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 6 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index c4b9eae8..c452f414 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -51,7 +51,8 @@ Postgres.prototype._getParameterValue = function(value) { value = this._getParameterValue('\\x' + value.toString('hex')); } else { // rich object represent with string - value = this._getParameterValue(value.toString()); + var strValue = value.toString(); + value = strValue === '[object Object]' ? this._getParameterValue(JSON.stringify(value)) : this._getParameterValue(strValue); } } else { throw new Error('Unable to use ' + value + ' in query'); diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 611112e8..94a975e4 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -1,5 +1,6 @@ 'use strict'; +var _ = require('lodash'); var util = require('util'); var assert = require('assert'); @@ -23,6 +24,10 @@ Sqlite.prototype._getParameterValue = function(value) { value = 'x' + this._getParameterValue(value.toString('hex')); } else if (value instanceof Date && this.config.dateTimeMillis) { value = value.getTime(); + } else if('boolean' === typeof value) { + value = value ? 1 : 0; + } else if(_.isArray(value)) { + value = Postgres.prototype._getParameterValue.call(this, JSON.stringify(value)); } else { value = Postgres.prototype._getParameterValue.call(this, value); } diff --git a/test/dialects/case-tests.js b/test/dialects/case-tests.js index 046ee4b2..f492a4f5 100644 --- a/test/dialects/case-tests.js +++ b/test/dialects/case-tests.js @@ -12,7 +12,7 @@ Harness.test({ }, sqlite: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) FROM "customer"' + string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) FROM `customer`', @@ -40,7 +40,7 @@ Harness.test({ }, sqlite: { text : 'SELECT ("customer"."age" + (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END)) FROM "customer"', - string: 'SELECT ("customer"."age" + (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END)) FROM "customer"' + string: 'SELECT ("customer"."age" + (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END)) FROM "customer"' }, mysql: { text : 'SELECT (`customer`.`age` + (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END)) FROM `customer`', @@ -68,7 +68,7 @@ Harness.test({ }, sqlite: { text : 'SELECT ((CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE $5 END) + $6) FROM "customer"', - string: 'SELECT ((CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE 2 END) + 3) FROM "customer"' + string: 'SELECT ((CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE 2 END) + 3) FROM "customer"' }, mysql: { text : 'SELECT ((CASE WHEN ? THEN ? WHEN ? THEN ? ELSE ? END) + ?) FROM `customer`', @@ -96,7 +96,7 @@ Harness.test({ }, sqlite: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 ELSE ("customer"."age" BETWEEN $5 AND $6) END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"' + string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 ELSE ("customer"."age" BETWEEN 10 AND 20) END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? ELSE (`customer`.`age` BETWEEN ? AND ?) END) FROM `customer`', @@ -124,7 +124,7 @@ Harness.test({ }, sqlite: { text : 'SELECT (CASE WHEN $1 THEN $2 WHEN $3 THEN $4 END) FROM "customer"', - string: 'SELECT (CASE WHEN TRUE THEN 0 WHEN FALSE THEN 1 END) FROM "customer"' + string: 'SELECT (CASE WHEN 1 THEN 0 WHEN 0 THEN 1 END) FROM "customer"' }, mysql: { text : 'SELECT (CASE WHEN ? THEN ? WHEN ? THEN ? END) FROM `customer`', diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index 5639c3a3..decfb4a5 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -3,6 +3,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); var user = Harness.defineUserTable(); +var variable = Harness.defineVariableTable(); Harness.test({ query: post.update({ @@ -193,3 +194,53 @@ Harness.test({ }, params: [new Buffer('test')] }); + +// Boolean updates +Harness.test({ + query: variable.update({ + a: true, + b: false + }), + pg: { + text : 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = TRUE, "b" = FALSE' + }, + sqlite: { + text : 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = 1, "b" = 0' + }, + mysql: { + text : 'UPDATE `variable` SET `a` = ?, `b` = ?', + string: 'UPDATE `variable` SET `a` = TRUE, `b` = FALSE' + }, + oracle: { + text : 'UPDATE "variable" SET "a" = :1, "b" = :2', + string: 'UPDATE "variable" SET "a" = TRUE, "b" = FALSE' + }, + params: [true, false] +}); + +// Object updates +Harness.test({ + query: variable.update({ + a: {"id": 1, "value": 2}, + b: [{"id": 2, "value": 3}, {"id": 3, "value": 4}] + }), + pg: { + text : 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' + }, + sqlite: { + text : 'UPDATE "variable" SET "a" = $1, "b" = $2', + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = \'[{"id":2,"value":3},{"id":3,"value":4}]\'' + }, + mysql: { + text : 'UPDATE `variable` SET `a` = ?, `b` = ?', + string: 'UPDATE `variable` SET `a` = \'{"id":1,"value":2}\', `b` = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' + }, + oracle: { + text : 'UPDATE "variable" SET "a" = :1, "b" = :2', + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' + }, + params: [{"id": 1, "value": 2}, [{"id": 2, "value": 3}, {"id": 3, "value": 4}]] +}); \ No newline at end of file From dcd3f4bad1e9b27cc425902273a9ca7e3965e2ba Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Tue, 12 Jan 2016 12:06:26 -0500 Subject: [PATCH 181/248] Fixed Postgres array syntax --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index c4b9eae8..182d04ec 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -42,7 +42,7 @@ Postgres.prototype._getParameterValue = function(value) { if (_.isArray(value)) { // convert each element of the array value = _.map(value, this._getParameterValue, this); - value = '(' + value.join(', ') + ')'; + value = '{' + value.join(', ') + '}'; } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well // Handle date like objects using toISOString From 83428c872fcb8bb2e2a1b5cb5ffff5ad135aaeb5 Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Tue, 12 Jan 2016 12:31:07 -0500 Subject: [PATCH 182/248] Add quotes around array --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 182d04ec..7464ebfb 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -42,7 +42,7 @@ Postgres.prototype._getParameterValue = function(value) { if (_.isArray(value)) { // convert each element of the array value = _.map(value, this._getParameterValue, this); - value = '{' + value.join(', ') + '}'; + value = '\'{' + value.join(',') + '}\''; } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well // Handle date like objects using toISOString From f6885792b09fcca737b7bbc8ade4c09397443f17 Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Tue, 12 Jan 2016 12:39:40 -0500 Subject: [PATCH 183/248] Correctly double quote strings within arrays for PG --- lib/dialect/postgres.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7464ebfb..764c98e6 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -26,7 +26,7 @@ Postgres.prototype._getParameterText = function(index, value) { } }; -Postgres.prototype._getParameterValue = function(value) { +Postgres.prototype._getParameterValue = function(value, quoteChar) { // handle primitives if (null === value) { value = 'NULL'; @@ -36,12 +36,15 @@ Postgres.prototype._getParameterValue = function(value) { // number is just number value = value; } else if ('string' === typeof value) { - // string uses single quote - value = this.quote(value, "'"); + // string uses single quote by default + value = this.quote(value, quoteChar || "'"); } else if ('object' === typeof value) { if (_.isArray(value)) { // convert each element of the array - value = _.map(value, this._getParameterValue, this); + value = value.map(function (item) { + // In a Postgres array, strings must be double-quoted + return this._getParameterValue(item, '"'); + }); value = '\'{' + value.join(',') + '}\''; } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well From bc10263b423d5e0680b349ce62bf3f3cd2cd351b Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Tue, 12 Jan 2016 12:41:42 -0500 Subject: [PATCH 184/248] Alias 'this' because we're in a closure --- lib/dialect/postgres.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 764c98e6..a8dbc449 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -41,9 +41,10 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { } else if ('object' === typeof value) { if (_.isArray(value)) { // convert each element of the array + var self = this; value = value.map(function (item) { // In a Postgres array, strings must be double-quoted - return this._getParameterValue(item, '"'); + return self._getParameterValue(item, '"'); }); value = '\'{' + value.join(',') + '}\''; } else if (_.isFunction(value.toISOString)) { From 74079157f6ba6c5786cc912e67d6d5a0c34018e6 Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Wed, 13 Jan 2016 11:10:19 -0500 Subject: [PATCH 185/248] Added tests for postgres array insert --- lib/dialect/postgres.js | 15 ++++++++---- test/dialects/insert-tests.js | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a8dbc449..28628ea6 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -42,11 +42,16 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { if (_.isArray(value)) { // convert each element of the array var self = this; - value = value.map(function (item) { - // In a Postgres array, strings must be double-quoted - return self._getParameterValue(item, '"'); - }); - value = '\'{' + value.join(',') + '}\''; + if (this._myClass === Postgres) { + value = value.map(function (item) { + // In a Postgres array, strings must be double-quoted + return self._getParameterValue(item, '"'); + }); + value = '\'{' + value.join(',') + '}\''; + } else { + value = _.map(value, this._getParameterValue, this); + value = '(' + value.join(', ') + ')'; + } } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well // Handle date like objects using toISOString diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index b472f51d..b847020e 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -1,9 +1,15 @@ 'use strict'; +var Table = require(__dirname + '/../../lib/table'); var Harness = require('./support'); var post = Harness.definePostTable(); var user = Harness.defineUserTable(); +var arrayTable = Table.define({ + name: 'arraytest', + columns: ['id', 'numbers'] +}); + Harness.test({ query: post.insert(post.content.value('test'), post.userId.value(1)), pg: { @@ -630,3 +636,43 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), + pg: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{2,3,4}\')' + }, + sqlite: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' + }, + mysql: { + text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', + string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (2, 3, 4))' + }, + oracle: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' + } +}); + +Harness.test({ + query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value(["one", "two", "three"])), + pg: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{"one","two","three"}\')' + }, + sqlite: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' + }, + mysql: { + text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', + string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (\'one\', \'two\', \'three\'))' + }, + oracle: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' + } +}); \ No newline at end of file From a84041c1250db2a269e032ae23298a9436c1fd3c Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Wed, 13 Jan 2016 11:14:13 -0500 Subject: [PATCH 186/248] Moved variable declaration --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 28628ea6..09297c51 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -41,8 +41,8 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { } else if ('object' === typeof value) { if (_.isArray(value)) { // convert each element of the array - var self = this; if (this._myClass === Postgres) { + var self = this; value = value.map(function (item) { // In a Postgres array, strings must be double-quoted return self._getParameterValue(item, '"'); From 6926e2166b212e044a1774dc2cf5e81e518650b4 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 27 Jan 2016 11:30:43 -0600 Subject: [PATCH 187/248] Call mocha directly --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 08d5a618..2f63aac7 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,9 @@ }, "main": "lib/", "scripts": { - "test": "node ./runtests", - "lint": "jshint lib test runtests.js", - "posttest": "jshint lib test runtests.js" + "test": "node_modules/.bin/mocha", + "lint": "jshint lib test", + "posttest": "jshint lib test" }, "engines": { "node": "*" From 51ccfa32606965d76159be01e81ec47409ba1d64 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 27 Jan 2016 11:31:39 -0600 Subject: [PATCH 188/248] Test on more node versions --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 05d299e6..f04dabe6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: node_js node_js: + - "5.0" + - "4.2" - "0.10" - "0.11" From 7f072ae52e9dba40a10fc5cdff487e8183358739 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 27 Jan 2016 11:33:14 -0600 Subject: [PATCH 189/248] Revert "Merge pull request #290 from ericjperry/master" This reverts commit 7a640319d304f4f70ef831ca60050226a93f73c6, reversing changes made to cbd17ea230fb21c56aa7c19115d3ccbd7f9431a5. --- lib/dialect/postgres.js | 19 ++++----------- test/dialects/insert-tests.js | 46 ----------------------------------- 2 files changed, 5 insertions(+), 60 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d6c8a412..6dd4f8dc 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -26,7 +26,7 @@ Postgres.prototype._getParameterText = function(index, value) { } }; -Postgres.prototype._getParameterValue = function(value, quoteChar) { +Postgres.prototype._getParameterValue = function(value) { // handle primitives if (null === value) { value = 'NULL'; @@ -36,22 +36,13 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { // number is just number value = value; } else if ('string' === typeof value) { - // string uses single quote by default - value = this.quote(value, quoteChar || "'"); + // string uses single quote + value = this.quote(value, "'"); } else if ('object' === typeof value) { if (_.isArray(value)) { // convert each element of the array - if (this._myClass === Postgres) { - var self = this; - value = value.map(function (item) { - // In a Postgres array, strings must be double-quoted - return self._getParameterValue(item, '"'); - }); - value = '\'{' + value.join(',') + '}\''; - } else { - value = _.map(value, this._getParameterValue, this); - value = '(' + value.join(', ') + ')'; - } + value = _.map(value, this._getParameterValue, this); + value = '(' + value.join(', ') + ')'; } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well // Handle date like objects using toISOString diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index b847020e..b472f51d 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -1,15 +1,9 @@ 'use strict'; -var Table = require(__dirname + '/../../lib/table'); var Harness = require('./support'); var post = Harness.definePostTable(); var user = Harness.defineUserTable(); -var arrayTable = Table.define({ - name: 'arraytest', - columns: ['id', 'numbers'] -}); - Harness.test({ query: post.insert(post.content.value('test'), post.userId.value(1)), pg: { @@ -636,43 +630,3 @@ Harness.test({ }, params: [] }); - -Harness.test({ - query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), - pg: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{2,3,4}\')' - }, - sqlite: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' - }, - mysql: { - text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', - string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (2, 3, 4))' - }, - oracle: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' - } -}); - -Harness.test({ - query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value(["one", "two", "three"])), - pg: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{"one","two","three"}\')' - }, - sqlite: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' - }, - mysql: { - text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', - string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (\'one\', \'two\', \'three\'))' - }, - oracle: { - text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', - string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' - } -}); \ No newline at end of file From 8af5b48679e86d4a8e055208705682ed1d498dcd Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 27 Jan 2016 11:42:31 -0600 Subject: [PATCH 190/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f63aac7..c6e2766f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.65.0", + "version": "0.66.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From e0bd0630f1fcaf628dec5f8e5c937312750e1e1a Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Thu, 28 Jan 2016 17:22:59 -0500 Subject: [PATCH 191/248] Updated array tests that Barry changed and fixed insertion of arrays of objects in Postgres --- lib/dialect/postgres.js | 22 ++++++++++++++--- test/dialects/insert-tests.js | 45 +++++++++++++++++++++++++++++++++++ test/dialects/update-tests.js | 2 +- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6dd4f8dc..0efad5bc 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -40,9 +40,25 @@ Postgres.prototype._getParameterValue = function(value) { value = this.quote(value, "'"); } else if ('object' === typeof value) { if (_.isArray(value)) { - // convert each element of the array - value = _.map(value, this._getParameterValue, this); - value = '(' + value.join(', ') + ')'; + if (this._myClass === Postgres) { + // naive check to see if this is an array of objects, which + // is handled differently than an array of primitives + if (value.length && 'object' === typeof value[0] && + !_.isFunction(value[0].toISOString) && + !_.isArray(value[0])) { + value = "'" + JSON.stringify(value) + "'"; + } else { + var self = this; + value = value.map(function (item) { + // In a Postgres array, strings must be double-quoted + return self._getParameterValue(item, '"'); + }); + value = '\'{' + value.join(',') + '}\''; + } + } else { + value = _.map(value, this._getParameterValue, this); + value = '(' + value.join(', ') + ')'; + } } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well // Handle date like objects using toISOString diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index b472f51d..f9a08912 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -4,6 +4,11 @@ var Harness = require('./support'); var post = Harness.definePostTable(); var user = Harness.defineUserTable(); +var arrayTable = Table.define({ + name: 'arraytest', + columns: ['id', 'numbers'] +}); + Harness.test({ query: post.insert(post.content.value('test'), post.userId.value(1)), pg: { @@ -630,3 +635,43 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), + pg: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{2,3,4}\')' + }, + sqlite: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'[2,3,4]\')' + }, + mysql: { + text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', + string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (2, 3, 4))' + }, + oracle: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (2, 3, 4))' + } +}); + +Harness.test({ + query: arrayTable.insert(arrayTable.id.value(1), arrayTable.numbers.value(["one", "two", "three"])), + pg: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'{"one","two","three"}\')' + }, + sqlite: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, \'["one","two","three"]\')' + }, + mysql: { + text : 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (?, ?)', + string: 'INSERT INTO `arraytest` (`id`, `numbers`) VALUES (1, (\'one\', \'two\', \'three\'))' + }, + oracle: { + text : 'INSERT INTO "arraytest" ("id", "numbers") VALUES (:1, :2)', + string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' + } +}); diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index decfb4a5..eb3d0b3e 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -228,7 +228,7 @@ Harness.test({ }), pg: { text : 'UPDATE "variable" SET "a" = $1, "b" = $2', - string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = (\'{"id":2,"value":3}\', \'{"id":3,"value":4}\')' + string: 'UPDATE "variable" SET "a" = \'{"id":1,"value":2}\', "b" = \'[{"id":2,"value":3},{"id":3,"value":4}]\'' }, sqlite: { text : 'UPDATE "variable" SET "a" = $1, "b" = $2', From 91b34eceafc2774c46f2a1a052472d179dc7d70e Mon Sep 17 00:00:00 2001 From: Eric Perry Date: Thu, 28 Jan 2016 17:29:00 -0500 Subject: [PATCH 192/248] Fixed some rebase issues --- lib/dialect/postgres.js | 6 +++--- test/dialects/insert-tests.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 0efad5bc..d92fa060 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -26,7 +26,7 @@ Postgres.prototype._getParameterText = function(index, value) { } }; -Postgres.prototype._getParameterValue = function(value) { +Postgres.prototype._getParameterValue = function(value, quoteChar) { // handle primitives if (null === value) { value = 'NULL'; @@ -36,8 +36,8 @@ Postgres.prototype._getParameterValue = function(value) { // number is just number value = value; } else if ('string' === typeof value) { - // string uses single quote - value = this.quote(value, "'"); + // string uses single quote by default + value = this.quote(value, quoteChar || "'"); } else if ('object' === typeof value) { if (_.isArray(value)) { if (this._myClass === Postgres) { diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index f9a08912..804daa06 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -4,7 +4,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); var user = Harness.defineUserTable(); -var arrayTable = Table.define({ +var arrayTable = require('../../lib/table').define({ name: 'arraytest', columns: ['id', 'numbers'] }); From d0cc3c7449230dd4b3058b9eba172f8a681365a3 Mon Sep 17 00:00:00 2001 From: brianc Date: Fri, 29 Jan 2016 10:57:44 -0600 Subject: [PATCH 193/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c6e2766f..b2d7af1c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.66.0", + "version": "0.67.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From e734df273cfb174d4d88fc2078818297b27855b3 Mon Sep 17 00:00:00 2001 From: tmont Date: Mon, 1 Feb 2016 11:25:54 -0800 Subject: [PATCH 194/248] upgraded to lodash@4.1.x fixed #296 --- lib/dialect/postgres.js | 2 +- lib/table.js | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d92fa060..d29894d9 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -56,7 +56,7 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { value = '\'{' + value.join(',') + '}\''; } } else { - value = _.map(value, this._getParameterValue, this); + value = _.map(value, this._getParameterValue.bind(this)); value = '(' + value.join(', ') + ')'; } } else if (_.isFunction(value.toISOString)) { diff --git a/lib/table.js b/lib/table.js index 86e8adbe..debafa24 100644 --- a/lib/table.js +++ b/lib/table.js @@ -78,7 +78,7 @@ Table.prototype.createColumn = function(col) { name: subfield })]; }, this)) - .object() + .fromPairs() .value(); } } diff --git a/package.json b/package.json index b2d7af1c..941b3329 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "sliced": "0.0.x", - "lodash": "1.3.x" + "lodash": "4.1.x" }, "devDependencies": { "jshint": "*", From 02b6f064c586efba3a4a0435670ccc4bd7ab77f9 Mon Sep 17 00:00:00 2001 From: tmont Date: Mon, 1 Feb 2016 11:31:01 -0800 Subject: [PATCH 195/248] removed dead code --- lib/dialect/postgres.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d92fa060..520dc7ab 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1006,7 +1006,6 @@ Postgres.prototype.visitDropIndex = function(node) { }; Postgres.prototype.visitCreateView = function(createView) { - //console.log('createView: ' + createView); var result = ['CREATE VIEW', this.quote(createView.options.viewName), 'AS']; return result; }; From 2e00b11f5c4aab77938ada67472efefab3e25521 Mon Sep 17 00:00:00 2001 From: tmont Date: Mon, 1 Feb 2016 11:31:17 -0800 Subject: [PATCH 196/248] only log stuff to the console if NODE_ENV=debug fixes #275 --- lib/table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index 86e8adbe..725d6666 100644 --- a/lib/table.js +++ b/lib/table.js @@ -98,7 +98,7 @@ Table.prototype.addColumn = function(col, options) { } else { return this; } - } else if(!!this[col.name] && (process.env.NODE_ENV !== 'test')) { + } else if(!!this[col.name] && (process.env.NODE_ENV === 'debug')) { console.log('Please notice that you have just defined the column "' + col.name + '". In order to access it, you need to use "table.getColumn(\'' + col.name + '\');"!'); } this.columns.push(col); From 775e93829a5a0d57c5e0d22302fd04cac9d8764b Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 8 Feb 2016 13:10:32 -0500 Subject: [PATCH 197/248] Extend query with value expressions to create allow creating select statements that can be joined together with expressions. --- lib/dialect/postgres.js | 3 +- lib/node/index.js | 6 +- lib/node/query.js | 14 +++++ test/dialects/select-tests.js | 104 +++++++++++++++++++++++++++++++++- 4 files changed, 124 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d29894d9..254511a3 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -644,7 +644,8 @@ Postgres.prototype.visitQuery = function(queryNode) { actions.push(new Select().add('*')); isSelect = true; } - if(missingFrom) { + if(missingFrom && queryNode.table instanceof Table) { + // the instanceof handles the situation where a sql.select(some expression) is used and there should be no FROM clause targets.push(new From().add(queryNode.table)); } if (createView) { diff --git a/lib/node/index.js b/lib/node/index.js index b500ab39..0bff1586 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -15,7 +15,11 @@ Node.prototype.toNode = function() { Node.prototype.add = function(node) { assert(node, 'Error while trying to add a non-existant node to a query'); - this.nodes.push(typeof node === 'string' ? new TextNode(node) : node.toNode()); + var newNode + if (typeof node === 'string') newNode = new TextNode(node) + else if (node.toNode) newNode = node.toNode() + else newNode = node + this.nodes.push(newNode); return this; }; diff --git a/lib/node/query.js b/lib/node/query.js index 4f13ebd1..46ec6cad 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,8 +1,10 @@ 'use strict'; +var _ = require('lodash'); var assert = require('assert'); var sliced = require('sliced'); var util = require('util'); +var valueExpressionMixin = require(__dirname + '/valueExpression'); var Node = require('./'); var Select = require('./select'); @@ -478,4 +480,16 @@ var Query = Node.define({ } }); +// Here we are extending query with valueExpressions so that it's possible to write queries like +// var query=sql.select(a.select(a.x.sum()).plus(b.select(b.y.sum())) +// which generates: +// SELECT (SELECT SUM(a.x) FROM a) + (SELECT SUM(b.y) FROM b) +// We need to remove "or" and "and" from here because it conflicts with the already existing functionality of appending +// to the where clause like so: +// var query=a.select().where(a.name.equals("joe")).or(a.name.equals("sam")) +var valueExpressions=valueExpressionMixin(); +delete valueExpressions["or"]; +delete valueExpressions["and"]; +_.extend(Query.prototype, valueExpressions); + module.exports = Query; diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 59fdd786..0825f95a 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -3,6 +3,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); var customerAlias = Harness.defineCustomerAliasTable(); +var Sql = require('../../lib'); Harness.test({ query: post.select(post.id).select(post.content), @@ -52,4 +53,105 @@ Harness.test({ string: 'SELECT "customer"."id" "id_alias", "customer"."name" "name_alias", "customer"."age" "age_alias", "customer"."income" "income_alias", "customer"."metadata" "metadata_alias" FROM "customer"' }, params: [] -}); \ No newline at end of file +}); + +// Test that we can generate a SELECT claus without a FROM clause +Harness.test({ + query: Sql.select(), + pg: { + text : 'SELECT ', + string: 'SELECT ' + }, + sqlite: { + text : 'SELECT ', + string: 'SELECT ' + }, + mysql: { + text : 'SELECT ', + string: 'SELECT ' + }, + mssql: { + text : 'SELECT ', + string: 'SELECT ' + }, + oracle: { + text : 'SELECT ', + string: 'SELECT ' + }, + params: [] +}); + +Harness.test({ + query: Sql.select("1").where("1=1"), + pg: { + text : 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + sqlite: { + text : 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + mysql: { + text : 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + mssql: { + text : 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + oracle: { + text : 'SELECT 1 WHERE (1=1)', + string: 'SELECT 1 WHERE (1=1)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(post.select(post.id)), + pg: { + text : 'SELECT (SELECT "post"."id" FROM "post")', + string: 'SELECT (SELECT "post"."id" FROM "post")' + }, + sqlite: { + text : 'SELECT (SELECT "post"."id" FROM "post")', + string: 'SELECT (SELECT "post"."id" FROM "post")' + }, + mysql: { + text : 'SELECT (SELECT `post`.`id` FROM `post`)', + string: 'SELECT (SELECT `post`.`id` FROM `post`)' + }, + mssql: { + text : 'SELECT (SELECT [post].[id] FROM [post])', + string: 'SELECT (SELECT [post].[id] FROM [post])' + }, + oracle: { + text : 'SELECT (SELECT "post"."id" FROM "post")', + string: 'SELECT (SELECT "post"."id" FROM "post")' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(post.select(post.content).plus(post.select(post.content))), + pg: { + text : 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', + string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' + }, + sqlite: { + text : 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', + string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' + }, + mysql: { + text : 'SELECT ((SELECT `post`.`content` FROM `post`) + (SELECT `post`.`content` FROM `post`))', + string: 'SELECT ((SELECT `post`.`content` FROM `post`) + (SELECT `post`.`content` FROM `post`))' + }, + mssql: { + text : 'SELECT ((SELECT [post].[content] FROM [post]) + (SELECT [post].[content] FROM [post]))', + string: 'SELECT ((SELECT [post].[content] FROM [post]) + (SELECT [post].[content] FROM [post]))' + }, + oracle: { + text : 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))', + string: 'SELECT ((SELECT "post"."content" FROM "post") + (SELECT "post"."content" FROM "post"))' + }, + params: [] +}); From 69b3173577f09dbd6e534115952c758851349072 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 8 Feb 2016 13:14:37 -0500 Subject: [PATCH 198/248] Added another test for generating select clauses without from clauses. --- test/dialects/select-tests.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 0825f95a..baa3eb40 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -81,6 +81,32 @@ Harness.test({ params: [] }); +// Test that we can generate a SELECT claus without a FROM clause +Harness.test({ + query: Sql.select("1"), + pg: { + text : 'SELECT 1', + string: 'SELECT 1' + }, + sqlite: { + text : 'SELECT 1', + string: 'SELECT 1' + }, + mysql: { + text : 'SELECT 1', + string: 'SELECT 1' + }, + mssql: { + text : 'SELECT 1', + string: 'SELECT 1' + }, + oracle: { + text : 'SELECT 1', + string: 'SELECT 1' + }, + params: [] +}); + Harness.test({ query: Sql.select("1").where("1=1"), pg: { From 50e184c62af3e16eb20168fe7f359ece44cca353 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 8 Feb 2016 18:23:29 -0500 Subject: [PATCH 199/248] Fixed a couple of jshint errors. --- lib/node/index.js | 8 ++++---- lib/node/query.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/node/index.js b/lib/node/index.js index 0bff1586..d519466f 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -15,10 +15,10 @@ Node.prototype.toNode = function() { Node.prototype.add = function(node) { assert(node, 'Error while trying to add a non-existant node to a query'); - var newNode - if (typeof node === 'string') newNode = new TextNode(node) - else if (node.toNode) newNode = node.toNode() - else newNode = node + var newNode; + if (typeof node === 'string') newNode = new TextNode(node); + else if (node.toNode) newNode = node.toNode(); + else newNode = node; this.nodes.push(newNode); return this; }; diff --git a/lib/node/query.js b/lib/node/query.js index 46ec6cad..cec925e5 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -488,8 +488,8 @@ var Query = Node.define({ // to the where clause like so: // var query=a.select().where(a.name.equals("joe")).or(a.name.equals("sam")) var valueExpressions=valueExpressionMixin(); -delete valueExpressions["or"]; -delete valueExpressions["and"]; +delete valueExpressions.or; +delete valueExpressions.and; _.extend(Query.prototype, valueExpressions); module.exports = Query; From 687eecf3504062c4a697b49e1931ebd4bff6bd4a Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 20 Feb 2016 10:36:33 -0500 Subject: [PATCH 200/248] Addresses issue when generating INSERT INTO ... SELECT statements created using the .add() function. --- lib/dialect/postgres.js | 25 ++++++++- test/dialects/insert-tests.js | 101 ++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index cbc7ece6..1b664504 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -596,7 +596,7 @@ Postgres.prototype.visitOverlap = function(overlap) { }; Postgres.prototype.visitQuery = function(queryNode) { - if (this._queryNode) return this.visitSubquery(queryNode); + if (this._queryNode) return this.visitSubquery(queryNode,dontParenthesizeSubQuery(this._queryNode)); this._queryNode = queryNode; // need to sort the top level query nodes on visitation priority // so select/insert/update/delete comes before from comes before where @@ -678,7 +678,7 @@ Postgres.prototype.visitQueryHelper=function(actions,targets,filters){ return this.output; }; -Postgres.prototype.visitSubquery = function(queryNode) { +Postgres.prototype.visitSubquery = function(queryNode,dontParenthesize) { // create another query builder of the current class to build the subquery var subQuery = new this._myClass(this.config); @@ -696,6 +696,9 @@ Postgres.prototype.visitSubquery = function(queryNode) { } var alias = queryNode.alias; + if (dontParenthesize) { + return [subQuery.output.join(' ') + (alias ? ' ' + this.quote(alias) : '')]; + } return ['(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + this.quote(alias) : '')]; }; @@ -1041,4 +1044,22 @@ Postgres.prototype.handleDistinct = function(actions,filters) { selectInfo.node.isDistinct = true; }; +/** + * If the parent of the subquery is an INSERT we don't want to parenthesize. + * This happens when you create the query like so: + * + * var query=post.insert(post.id) + * var select=user.select(user.id) + * query.add(select) + * + * @param parentQuery + * @returns {boolean} + */ +function dontParenthesizeSubQuery(parentQuery){ + if (!parentQuery) return false; + if (parentQuery.nodes.length == 0) return false; + if (parentQuery.nodes[0].type != 'INSERT') return false; + return true; +} + module.exports = Postgres; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 804daa06..73517b48 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -675,3 +675,104 @@ Harness.test({ string: 'INSERT INTO "arraytest" ("id", "numbers") VALUES (1, (\'one\', \'two\', \'three\'))' } }); + +Harness.test({ + query: post.insert(post.userId).select(user.id).from(user), + pg: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + sqlite: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' + }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: post.insert(post.userId).add(user.select(user.id)), + pg: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + sqlite: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' + }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: post.insert(post.userId).add(user.select(user.id).from(user)), + pg: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + sqlite: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user]' + }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + params: [] +}); + +Harness.test({ + query: post.insert(post.userId).add(user.select(user.id).order(user.id)), + pg: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + sqlite: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + mysql: { + text : 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`', + string: 'INSERT INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`' + }, + mssql: { + text : 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user] ORDER BY [user].[id]', + string: 'INSERT INTO [post] ([userId]) SELECT [user].[id] FROM [user] ORDER BY [user].[id]' + }, + oracle: { + text : 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'INSERT INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + params: [] +}); + From 046d6dc19f712f1b7f3683ffabf15210d9ee7c5e Mon Sep 17 00:00:00 2001 From: iamcharliegoddard Date: Fri, 18 Mar 2016 22:00:46 -0700 Subject: [PATCH 201/248] jshint-fix: fix for jshint error --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6539a54f..50f78233 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1061,7 +1061,7 @@ Postgres.prototype.handleDistinct = function(actions,filters) { */ function dontParenthesizeSubQuery(parentQuery){ if (!parentQuery) return false; - if (parentQuery.nodes.length == 0) return false; + if (parentQuery.nodes.length === 0) return false; if (parentQuery.nodes[0].type != 'INSERT') return false; return true; } From 43b6c350950b70f340cc22ca0ce2668b6626073b Mon Sep 17 00:00:00 2001 From: Kevin Anthoney Date: Fri, 1 Apr 2016 20:43:15 +0100 Subject: [PATCH 202/248] Add table level foreign keys * Add table level foreign keys * Make refColumns optional in foreign keys * Add constraint name to foreign keys * Add on update clause to foreign keys, and also to column references while I was at it * Add actions SET NULL, SET DEFAULT and NO ACTION for onDelete and onUpdate for foreign keys and column references --- lib/dialect/postgres.js | 67 +++++++++++++++++- lib/node/foreignKey.js | 19 ++++++ lib/table.js | 15 +++- test/dialects/create-table-tests.js | 102 +++++++++++++++++++++++++--- 4 files changed, 191 insertions(+), 12 deletions(-) create mode 100644 lib/node/foreignKey.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 50f78233..6a7c0dc7 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -153,6 +153,7 @@ Postgres.prototype.visit = function(node) { case 'FOR SHARE' : return this.visitForShare(); case 'TABLE' : return this.visitTable(node); case 'COLUMN' : return this.visitColumn(node); + case 'FOREIGN KEY' : return this.visitForeignKey(node); case 'JOIN' : return this.visitJoin(node); case 'LITERAL' : return this.visitLiteral(node); case 'TEXT' : return node.text; @@ -296,6 +297,7 @@ Postgres.prototype.visitCreate = function(create) { // don't auto-generate from clause var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); + var foreign_key_nodes = table.foreignKeys; var result = ['CREATE TABLE']; if (create.options.isTemporary) result=['CREATE TEMPORARY TABLE']; @@ -313,6 +315,9 @@ Postgres.prototype.visitCreate = function(create) { }.bind(this)).join(', '); colspec += ')'; } + if(foreign_key_nodes.length > 0) { + colspec += ', ' + foreign_key_nodes.map(this.visit.bind(this)).join(', '); + } colspec += ')'; result.push(colspec); this._visitCreateCompoundPrimaryKey = false; @@ -836,9 +841,14 @@ Postgres.prototype.visitColumn = function(columnNode) { var onDelete = columnNode.references.onDelete; if (onDelete) onDelete = onDelete.toUpperCase(); - if (onDelete === 'CASCADE' || onDelete === 'RESTRICT') { + if (onDelete === 'CASCADE' || onDelete === 'RESTRICT' || onDelete === 'SET NULL' || onDelete === 'SET DEFAULT' || onDelete === 'NO ACTION') { txt.push(' ON DELETE ' + onDelete); } + var onUpdate = columnNode.references.onUpdate; + if (onUpdate) onUpdate = onUpdate.toUpperCase(); + if (onUpdate === 'CASCADE' || onUpdate === 'RESTRICT' || onUpdate === 'SET NULL' || onUpdate === 'SET DEFAULT' || onUpdate === 'NO ACTION') { + txt.push(' ON UPDATE ' + onUpdate); + } var constraint = columnNode.references.constraint; if (constraint) { constraint = ' ' + constraint.toUpperCase(); @@ -850,6 +860,61 @@ Postgres.prototype.visitColumn = function(columnNode) { return [txt.join('')]; }; +Postgres.prototype.visitForeignKey = function(foreignKeyNode) +{ + var txt = []; + if(this._visitingCreate) { + assert(foreignKeyNode.table, 'Foreign table missing for table reference'); + assert(foreignKeyNode.columns, 'Columns missing for table reference'); + if(foreignKeyNode.refColumns !== undefined) { + assert.equal(foreignKeyNode.columns.length, foreignKeyNode.refColumns.length, 'Number of local columns and foreign columns differ in table reference'); + } + if(foreignKeyNode.name !== undefined) { + txt.push('CONSTRAINT ' + this.quote(foreignKeyNode.name) + ' '); + } + txt.push('FOREIGN KEY ( '); + for(var i = 0; i < foreignKeyNode.columns.length; i++) { + if(i>0) { + txt.push(', '); + } + txt.push(this.quote(foreignKeyNode.columns[i])); + } + txt.push(' ) REFERENCES '); + if(foreignKeyNode.schema !== undefined) { + txt.push(this.quote(foreignKeyNode.schema) + '.'); + } + txt.push(this.quote(foreignKeyNode.table)); + if(foreignKeyNode.refColumns !== undefined) { + txt.push(' ( '); + for(i = 0; i < foreignKeyNode.refColumns.length; i++) { + if(i>0) { + txt.push(', '); + } + txt.push(this.quote(foreignKeyNode.refColumns[i])); + } + txt.push(' )'); + } + var onDelete = foreignKeyNode.onDelete; + if(onDelete) { + onDelete = onDelete.toUpperCase(); + if(onDelete === 'CASCADE' || onDelete === 'RESTRICT' || onDelete === 'SET NULL' || onDelete === 'SET DEFAULT' || onDelete === 'NO ACTION') { + txt.push(' ON DELETE ' + onDelete); + } + } + var onUpdate = foreignKeyNode.onUpdate; + if(onUpdate) { + onUpdate = onUpdate.toUpperCase(); + if(onUpdate === 'CASCADE' || onUpdate === 'RESTRICT' || onUpdate === 'SET NULL' || onUpdate === 'SET DEFAULT' || onUpdate === 'NO ACTION') { + txt.push(' ON UPDATE ' + onUpdate); + } + } + if(foreignKeyNode.constraint) { + txt.push(' ' + foreignKeyNode.constraint.toUpperCase()); + } + } + return [txt.join('')]; +}; + Postgres.prototype.visitFunctionCall = function(functionCall) { this._visitingFunctionCall = true; var txt = functionCall.name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; diff --git a/lib/node/foreignKey.js b/lib/node/foreignKey.js new file mode 100644 index 00000000..c738d842 --- /dev/null +++ b/lib/node/foreignKey.js @@ -0,0 +1,19 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'FOREIGN KEY', + constructor: function(config) { + Node.call(this); + this.name = config.name; + this.columns = config.columns; + this.schema = config.schema; + this.table = config.table; + this.refColumns = config.refColumns; + this.onUpdate = config.onUpdate; + this.onDelete = config.onDelete; + this.constraint = config.constraint; + } +}); + diff --git a/lib/table.js b/lib/table.js index b810283c..21895aea 100644 --- a/lib/table.js +++ b/lib/table.js @@ -9,6 +9,7 @@ var TableNode = require(__dirname + '/node/table'); var JoinNode = require(__dirname + '/node/join'); var LiteralNode = require(__dirname + '/node/literal'); var Joiner = require(__dirname + '/joiner'); +var ForeignKeyNode = require(__dirname + '/node/foreignKey'); var Table = function(config) { this._schema = config.schema; @@ -18,6 +19,7 @@ var Table = function(config) { this.isTemporary=!!config.isTemporary; this.snakeToCamel = !!config.snakeToCamel; this.columns = []; + this.foreignKeys = []; this.table = this; if (!config.sql) { config.sql = require('./index'); @@ -45,6 +47,16 @@ Table.define = function(config) { for (var i = 0; i < config.columns.length; i++) { table.addColumn(config.columns[i]); } + + if(config.foreignKeys !== undefined) { + if(util.isArray(config.foreignKeys)) { + for(i = 0; i < config.foreignKeys.length; i++) { + table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys[i])); + } + } else { + table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys)); + } + } return table; }; @@ -55,7 +67,8 @@ Table.prototype.clone = function(config) { sql: this.sql, columnWhiteList: !!this.columnWhiteList, snakeToCamel: !!this.snakeToCamel, - columns: this.columns + columns: this.columns, + foreignKeys: this.foreignKeys }, config || {})); }; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 872d51fa..97f6a1fd 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -256,25 +256,27 @@ Harness.test({ dataType: 'int', references: { table: 'user', - column: 'id' + column: 'id', + onDelete: 'restrict', + onUpdate: 'set null' } }] }).create(), pg: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))', - string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))' + text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' }, sqlite: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))', - string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))' + text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' }, mysql: { - text : 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`))', - string: 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`))' + text : 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE `post` (`userId` int REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE SET NULL)' }, oracle: { - text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))', - string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id"))' + text : 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)', + string: 'CREATE TABLE "post" ("userId" int REFERENCES "user"("id") ON DELETE RESTRICT ON UPDATE SET NULL)' }, params: [] }); @@ -643,4 +645,84 @@ Harness.test({ string: 'CREATE TABLE "post" ("id" int PRIMARY KEY)' }, params: [] -}); \ No newline at end of file +}); + +Harness.test({ + query: Table.define({ + name: 'post', + columns: [{ + name: 'id', + dataType: 'int', + primaryKey: true + }, { + name: 'blog_id', + dataType: 'int' + }, { + name: 'user_id', + dataType: 'int' + }], + foreignKeys: { + table: 'users', + columns: [ 'blog_id', 'user_id' ], + refColumns: [ 'id', 'user_id' ] + } + }).create(), + pg: { + text : 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))' + }, + sqlite: { + text : 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))', + string: 'CREATE TABLE "post" ("id" int PRIMARY KEY, "blog_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ( "id", "user_id" ))' + }, + mysql: { + text : 'CREATE TABLE `post` (`id` int PRIMARY KEY, `blog_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ( `id`, `user_id` ))', + string: 'CREATE TABLE `post` (`id` int PRIMARY KEY, `blog_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ( `id`, `user_id` ))' + }, + params: [] +}); + +Harness.test({ + query: Table.define({ + name: 'replies', + columns: [{ + name: 'id', + dataType: 'int', + primaryKey: true + }, { + name: 'blog_id', + dataType: 'int' + }, { + name: 'post_id', + dataType: 'int' + }, { + name: 'user_id', + dataType: 'int' + }], + foreignKeys: [{ + table: 'users', + columns: [ 'blog_id', 'user_id' ], + onDelete: 'no action' + }, { + name: 'posts_idx', + table: 'posts', + columns: [ 'blog_id', 'post_id' ], + refColumns: [ 'blog_id', 'id' ], + onDelete: 'cascade', + onUpdate: 'set default' + }] + }).create(), + pg: { + text : 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', + string: 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' + }, + sqlite: { + text : 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', + string: 'CREATE TABLE "replies" ("id" int PRIMARY KEY, "blog_id" int, "post_id" int, "user_id" int, FOREIGN KEY ( "blog_id", "user_id" ) REFERENCES "users" ON DELETE NO ACTION, CONSTRAINT "posts_idx" FOREIGN KEY ( "blog_id", "post_id" ) REFERENCES "posts" ( "blog_id", "id" ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' + }, + mysql: { + text : 'CREATE TABLE `replies` (`id` int PRIMARY KEY, `blog_id` int, `post_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ON DELETE NO ACTION, CONSTRAINT `posts_idx` FOREIGN KEY ( `blog_id`, `post_id` ) REFERENCES `posts` ( `blog_id`, `id` ) ON DELETE CASCADE ON UPDATE SET DEFAULT)', + string: 'CREATE TABLE `replies` (`id` int PRIMARY KEY, `blog_id` int, `post_id` int, `user_id` int, FOREIGN KEY ( `blog_id`, `user_id` ) REFERENCES `users` ON DELETE NO ACTION, CONSTRAINT `posts_idx` FOREIGN KEY ( `blog_id`, `post_id` ) REFERENCES `posts` ( `blog_id`, `id` ) ON DELETE CASCADE ON UPDATE SET DEFAULT)' + }, + params: [] +}); From 297daf305f12e14e6053bdef9d1ad17af8df7a0c Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 18 May 2016 17:52:10 -0400 Subject: [PATCH 203/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 941b3329..0e0cb5cd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.67.0", + "version": "0.68.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From e00acabe5662fa80dc12da6b2581279e992e8e7b Mon Sep 17 00:00:00 2001 From: Barry Hammen Date: Mon, 23 May 2016 15:29:34 -0400 Subject: [PATCH 204/248] Add support for basic date functions (#318) --- lib/dialect/mssql.js | 24 +++++-- lib/dialect/mysql.js | 25 +++++++ lib/dialect/postgres.js | 16 ++++- lib/dialect/sqlite.js | 41 +++++++++--- lib/functions.js | 10 ++- test/dialects/date-tests.js | 130 ++++++++++++++++++++++++++++++++++++ 6 files changed, 232 insertions(+), 14 deletions(-) create mode 100644 test/dialects/date-tests.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 48c1ad45..d8e299e8 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -246,10 +246,26 @@ Mssql.prototype.visitDrop = function(drop) { Mssql.prototype.visitFunctionCall = function(functionCall) { this._visitingFunctionCall = true; - var name=functionCall.name; - // override the LENGTH function since mssql calls it LEN - if (name=="LENGTH") name="LEN"; - var txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + var _this = this; + + function _extract() { + var nodes = functionCall.nodes.map(_this.visit.bind(_this)); + if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); + var txt = 'DATEPART(' + functionCall.name.toLowerCase() + ', ' + (nodes[0]+'') + ')'; + return txt; + } + + var txt; + // Override date functions since mssql uses datepart + if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); + // Override CURRENT_TIMESTAMP function to remove parens + else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; + else { + var name = functionCall.name; + // override the LENGTH function since mssql calls it LEN + if (name == "LENGTH") name = "LEN"; + txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + } this._visitingFunctionCall = false; return [txt]; }; diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 9d582ce7..225ea6be 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -102,4 +102,29 @@ Mysql.prototype.visitBinary = function(binary) { return Mysql.super_.prototype.visitBinary.call(this, binary); }; +Mysql.prototype.visitFunctionCall = function(functionCall) { + var _this=this; + + this._visitingFunctionCall = true; + + function _extract() { + var nodes = functionCall.nodes.map(_this.visit.bind(_this)); + if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); + var txt = functionCall.name + '(' + (nodes[0]+'') + ')'; + return txt; + } + + var txt=""; + var name = functionCall.name; + // Override date functions since mysql is different than postgres + if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); + // Override CURRENT_TIMESTAMP function to remove parens + else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; + else txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + + this._visitingFunctionCall = false; + return [txt]; +}; + + module.exports = Mysql; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6a7c0dc7..ab12869d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -917,7 +917,21 @@ Postgres.prototype.visitForeignKey = function(foreignKeyNode) Postgres.prototype.visitFunctionCall = function(functionCall) { this._visitingFunctionCall = true; - var txt = functionCall.name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + var _this = this; + + function _extract() { + var nodes = functionCall.nodes.map(_this.visit.bind(_this)); + if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); + var txt = 'EXTRACT(' + functionCall.name + ' FROM ' + (nodes[0]+'') + ')'; + return txt; + } + + var txt = ""; + // Override date functions since postgres (and others) uses extract + if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); + // Override CURRENT_TIMESTAMP function to remove parens + else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; + else txt = functionCall.name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; this._visitingFunctionCall = false; return [txt]; }; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 81b452c0..d2885c2f 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -42,16 +42,16 @@ Sqlite.prototype.visitDropColumn = function() { throw new Error('SQLite does not allow dropping columns.'); }; -Sqlite.prototype.visitFunctionCall = function(functionCall) { - var _this=this; +Sqlite.prototype.visitFunctionCall = function (functionCall) { + var _this = this; - this._visitingFunctionCall = true; + this._visitingFunctionCall = true; function _left() { // convert LEFT(column,4) to SUBSTR(column,1,4) var nodes = functionCall.nodes.map(_this.visit.bind(_this)); if (nodes.length != 2) throw new Error('Not enough parameters passed to LEFT function.'); - var txt = "SUBSTR(" + (nodes[0]+'') + ', 1, ' + (nodes[1]+'') + ')'; + var txt = "SUBSTR(" + (nodes[0] + '') + ', 1, ' + (nodes[1] + '') + ')'; return txt; } @@ -59,18 +59,43 @@ Sqlite.prototype.visitFunctionCall = function(functionCall) { // convert RIGHT(column,4) to SUBSTR(column,-4) var nodes = functionCall.nodes.map(_this.visit.bind(_this)); if (nodes.length != 2) throw new Error('Not enough parameters passed to RIGHT function.'); - var txt = "SUBSTR(" + (nodes[0]+'') + ', -' + (nodes[1]+'') + ')'; + var txt = "SUBSTR(" + (nodes[0] + '') + ', -' + (nodes[1] + '') + ')'; return txt; } - var txt=""; - var name=functionCall.name; + function _extract() { + var nodes = functionCall.nodes.map(_this.visit.bind(_this)); + if (nodes.length != 1) throw new Error('Not enough parameters passed to ' + functionCall.name + ' function'); + var format; + switch (functionCall.name) { + case 'YEAR': + format = "'%Y'"; + break; + case 'MONTH': + format = "'%m'"; + break; + case 'DAY': + format = "'%d'"; + break; + case 'HOUR': + format = "'%H'"; + break; + } + var txt = 'strftime(' + format + ', ' + (nodes[0] + '') + ')'; + return txt; + } + + var txt = ""; + var name = functionCall.name; // Override LEFT and RIGHT and convert to SUBSTR if (name == "LEFT") txt = _left(); else if (name == "RIGHT") txt = _right(); + // Override date functions since sqlite uses strftime + else if (['YEAR', 'MONTH', 'DAY', 'HOUR'].indexOf(functionCall.name) >= 0) txt = _extract(); + else if ('CURRENT_TIMESTAMP' == functionCall.name) txt = functionCall.name; else txt = name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; - this._visitingFunctionCall = false; + this._visitingFunctionCall = false; return [txt]; }; diff --git a/lib/functions.js b/lib/functions.js index ef9b6f81..b0abcf54 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -47,13 +47,21 @@ var scalarFunctions = [ 'UPPER' ]; +var dateFunctions = [ + 'YEAR', + 'MONTH', + 'DAY', + 'HOUR', + 'CURRENT_TIMESTAMP' +]; + // hstore function available to Postgres var hstoreFunction = 'HSTORE'; //text search functions available to Postgres var textsearchFunctions = ['TS_RANK','TS_RANK_CD', 'PLAINTO_TSQUERY', 'TO_TSQUERY', 'TO_TSVECTOR', 'SETWEIGHT']; -var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction).concat(textsearchFunctions); +var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction).concat(textsearchFunctions).concat(dateFunctions); // creates a hash of standard functions for a sql instance var getStandardFunctions = function() { diff --git a/test/dialects/date-tests.js b/test/dialects/date-tests.js new file mode 100644 index 00000000..6eaf9851 --- /dev/null +++ b/test/dialects/date-tests.js @@ -0,0 +1,130 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var Sql = require('../../lib'); + +Harness.test({ + query: customer.select(Sql.functions.YEAR(customer.metadata)), + pg: { + text : 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text : 'SELECT strftime(\'%Y\', "customer"."metadata") FROM "customer"', + string: 'SELECT strftime(\'%Y\', "customer"."metadata") FROM "customer"' + }, + mysql: { + text : 'SELECT YEAR(`customer`.`metadata`) FROM `customer`', + string: 'SELECT YEAR(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text : 'SELECT DATEPART(year, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(year, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text : 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(YEAR FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(Sql.functions.MONTH(customer.metadata)), + pg: { + text : 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text : 'SELECT strftime(\'%m\', "customer"."metadata") FROM "customer"', + string: 'SELECT strftime(\'%m\', "customer"."metadata") FROM "customer"' + }, + mysql: { + text : 'SELECT MONTH(`customer`.`metadata`) FROM `customer`', + string: 'SELECT MONTH(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text : 'SELECT DATEPART(month, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(month, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text : 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(Sql.functions.DAY(customer.metadata)), + pg: { + text : 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text : 'SELECT strftime(\'%d\', "customer"."metadata") FROM "customer"', + string: 'SELECT strftime(\'%d\', "customer"."metadata") FROM "customer"' + }, + mysql: { + text : 'SELECT DAY(`customer`.`metadata`) FROM `customer`', + string: 'SELECT DAY(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text : 'SELECT DATEPART(day, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(day, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text : 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(DAY FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(Sql.functions.HOUR(customer.metadata)), + pg: { + text : 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' + }, + sqlite: { + text : 'SELECT strftime(\'%H\', "customer"."metadata") FROM "customer"', + string: 'SELECT strftime(\'%H\', "customer"."metadata") FROM "customer"' + }, + mysql: { + text : 'SELECT HOUR(`customer`.`metadata`) FROM `customer`', + string: 'SELECT HOUR(`customer`.`metadata`) FROM `customer`' + }, + mssql: { + text : 'SELECT DATEPART(hour, [customer].[metadata]) FROM [customer]', + string: 'SELECT DATEPART(hour, [customer].[metadata]) FROM [customer]' + }, + oracle: { + text : 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"', + string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' + }, + params: [] +}); + +Harness.test({ + query: customer.select(Sql.functions.CURRENT_TIMESTAMP()), + pg: { + text : 'SELECT CURRENT_TIMESTAMP FROM "customer"', + string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' + }, + sqlite: { + text : 'SELECT CURRENT_TIMESTAMP FROM "customer"', + string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' + }, + mysql: { + text : 'SELECT CURRENT_TIMESTAMP FROM `customer`', + string: 'SELECT CURRENT_TIMESTAMP FROM `customer`' + }, + mssql: { + text : 'SELECT CURRENT_TIMESTAMP FROM [customer]', + string: 'SELECT CURRENT_TIMESTAMP FROM [customer]' + }, + oracle: { + text : 'SELECT CURRENT_TIMESTAMP FROM "customer"', + string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' + }, + params: [] +}); \ No newline at end of file From eec86e41ed0dfcbf51891dfed97df1d93995a3b3 Mon Sep 17 00:00:00 2001 From: brianc Date: Mon, 23 May 2016 14:30:07 -0500 Subject: [PATCH 205/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e0cb5cd..06159cf6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.68.0", + "version": "0.69.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From bc4d8d9dd00cf4e4ff8b69e5e2cca13f896e70fa Mon Sep 17 00:00:00 2001 From: Barry Hammen Date: Thu, 26 May 2016 13:14:28 -0400 Subject: [PATCH 206/248] Fix sqlite date functions for epoch (#319) --- lib/dialect/sqlite.js | 8 +++++++- test/dialects/date-tests.js | 14 ++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index d2885c2f..6085ba21 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -81,7 +81,13 @@ Sqlite.prototype.visitFunctionCall = function (functionCall) { format = "'%H'"; break; } - var txt = 'strftime(' + format + ', ' + (nodes[0] + '') + ')'; + var col = (nodes[0] + ''); + if (_this.config.dateTimeMillis) { + // Convert to a datetime before running the strftime function + // Sqlite unix epoch is in seconds, but javascript is milliseconds. + col = 'datetime(' + col + '/1000, "unixepoch")'; + } + var txt = 'strftime(' + format + ', ' + col + ')'; return txt; } diff --git a/test/dialects/date-tests.js b/test/dialects/date-tests.js index 6eaf9851..5a5fadda 100644 --- a/test/dialects/date-tests.js +++ b/test/dialects/date-tests.js @@ -36,8 +36,11 @@ Harness.test({ string: 'SELECT EXTRACT(MONTH FROM "customer"."metadata") FROM "customer"' }, sqlite: { - text : 'SELECT strftime(\'%m\', "customer"."metadata") FROM "customer"', - string: 'SELECT strftime(\'%m\', "customer"."metadata") FROM "customer"' + text: 'SELECT strftime(\'%m\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + string: 'SELECT strftime(\'%m\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + config: { + dateTimeMillis: true + } }, mysql: { text : 'SELECT MONTH(`customer`.`metadata`) FROM `customer`', @@ -86,8 +89,11 @@ Harness.test({ string: 'SELECT EXTRACT(HOUR FROM "customer"."metadata") FROM "customer"' }, sqlite: { - text : 'SELECT strftime(\'%H\', "customer"."metadata") FROM "customer"', - string: 'SELECT strftime(\'%H\', "customer"."metadata") FROM "customer"' + text: 'SELECT strftime(\'%H\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + string: 'SELECT strftime(\'%H\', datetime("customer"."metadata"/1000, "unixepoch")) FROM "customer"', + config: { + dateTimeMillis: true + } }, mysql: { text : 'SELECT HOUR(`customer`.`metadata`) FROM `customer`', From e6b40a96683cfe4bdd079a096243c3ba877035cf Mon Sep 17 00:00:00 2001 From: brianc Date: Thu, 26 May 2016 12:14:41 -0500 Subject: [PATCH 207/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06159cf6..3503e59d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.69.0", + "version": "0.70.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From cf928eeb2bd4305ed576ba32d1bcc01c55630a17 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Thu, 16 Jun 2016 18:44:28 -0400 Subject: [PATCH 208/248] _.isArray -> Array.isArray (#309) --- lib/dialect/postgres.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index ab12869d..fb7fb4d4 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -39,13 +39,13 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { // string uses single quote by default value = this.quote(value, quoteChar || "'"); } else if ('object' === typeof value) { - if (_.isArray(value)) { + if (Array.isArray(value)) { if (this._myClass === Postgres) { // naive check to see if this is an array of objects, which // is handled differently than an array of primitives if (value.length && 'object' === typeof value[0] && !_.isFunction(value[0].toISOString) && - !_.isArray(value[0])) { + !Array.isArray(value[0])) { value = "'" + JSON.stringify(value) + "'"; } else { var self = this; From 6786f50b89489a311e1a5f3e045f0e0a6078d629 Mon Sep 17 00:00:00 2001 From: Kevin Anthoney Date: Wed, 20 Jul 2016 20:14:41 +0100 Subject: [PATCH 209/248] Use count(*) syntax for MySQL instead of count(`table`.*) (#325) --- lib/dialect/mysql.js | 24 ++++++++++++++++++++++++ test/dialects/aggregate-tests.js | 16 ++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 225ea6be..86416fcf 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -126,5 +126,29 @@ Mysql.prototype.visitFunctionCall = function(functionCall) { return [txt]; }; +Mysql.prototype.visitColumn = function(columnNode) { + var self = this; + var inSelectClause; + + function isCountStarExpression(columnNode){ + if (!columnNode.aggregator) return false; + if (columnNode.aggregator.toLowerCase()!='count') return false; + if (!columnNode.star) return false; + return true; + } + + function _countStar(){ + // Implement our own since count(table.*) is invalid in Mysql + var result='COUNT(*)'; + if(inSelectClause && columnNode.alias) { + result += ' AS ' + self.quote(columnNode.alias); + } + return result; + } + + inSelectClause = !this._selectOrDeleteEndIndex; + if(isCountStarExpression(columnNode)) return _countStar(); + return Mysql.super_.prototype.visitColumn.call(this, columnNode); +}; module.exports = Mysql; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index d67d775a..59d48d57 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -16,8 +16,8 @@ Harness.test({ string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' }, mysql: { - text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', - string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' + text : 'SELECT COUNT(*) AS `post_count` FROM `post`', + string: 'SELECT COUNT(*) AS `post_count` FROM `post`' }, mssql: { text : 'SELECT COUNT(*) AS [post_count] FROM [post]', @@ -41,8 +41,8 @@ Harness.test({ string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' }, msyql: { - text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', - string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' + text : 'SELECT COUNT(*) AS `post_count` FROM `post`', + string: 'SELECT COUNT(*) AS `post_count` FROM `post`' }, mssql: { text : 'SELECT COUNT(*) AS [post_count] FROM [post]', @@ -66,8 +66,8 @@ Harness.test({ string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' }, mysql: { - text : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', - string: 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`' + text : 'SELECT COUNT(*) AS `post_amount` FROM `post`', + string: 'SELECT COUNT(*) AS `post_amount` FROM `post`' }, mssql: { text : 'SELECT COUNT(*) AS [post_amount] FROM [post]', @@ -166,8 +166,8 @@ Harness.test({ string: 'SELECT COUNT("customer".*) AS "customer_count" FROM "customer"' }, mysql: { - text : 'SELECT COUNT(`customer`.*) AS `customer_count` FROM `customer`', - string: 'SELECT COUNT(`customer`.*) AS `customer_count` FROM `customer`' + text : 'SELECT COUNT(*) AS `customer_count` FROM `customer`', + string: 'SELECT COUNT(*) AS `customer_count` FROM `customer`' }, oracle: { text : 'SELECT COUNT(*) "customer_count" FROM "customer"', From b987e5c9dbd14cd8d4a34a9d245c1daf8a8b65e1 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 20 Jul 2016 14:14:56 -0500 Subject: [PATCH 210/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3503e59d..5a82fb8d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.70.0", + "version": "0.70.1", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From eba2de6dc7a6b272ee94a7ad56eb6434a5a50305 Mon Sep 17 00:00:00 2001 From: danrzeppa Date: Tue, 30 Aug 2016 09:30:25 -0400 Subject: [PATCH 211/248] Alias a query with AS (#329) * Added a sql.literalColumn function for selecting literal/constant values. * - Added tests for function call on a literal column * Converted tabs to spaces. * Renamed "literalColumn" to "constant" * Added missing semicolons causing the Travis build to fail. * Added missing semicolon * Added ability to attach AS to a query. --- lib/dialect/mssql.js | 2 +- lib/dialect/oracle.js | 2 +- lib/dialect/postgres.js | 28 ++-- lib/index.js | 31 +++- lib/node/column.js | 2 + lib/node/query.js | 7 + test/dialects/select-tests.js | 278 ++++++++++++++++++++++++++++++++++ 7 files changed, 331 insertions(+), 19 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index d8e299e8..2cb95d9d 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -186,7 +186,7 @@ Mssql.prototype.visitColumn = function(columnNode) { table = columnNode.table; inSelectClause = !this._selectOrDeleteEndIndex; if (isCountStarExpression(columnNode)) return _countStar(); - if (inSelectClause && !table.alias && columnNode.asArray) return _arrayAgg(); + if (inSelectClause && table && !table.alias && columnNode.asArray) return _arrayAgg(); return Mssql.super_.prototype.visitColumn.call(this, columnNode); }; diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index 6b597154..ea2cb85e 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -168,7 +168,7 @@ Oracle.prototype.visitColumn = function(columnNode) { table = columnNode.table; inSelectClause = !this._selectOrDeleteEndIndex; if (isCountStarExpression(columnNode)) return _countStar(); - if (inSelectClause && !table.alias && columnNode.asArray) return _arrayAgg(); + if (inSelectClause && table && !table.alias && columnNode.asArray) return _arrayAgg(); return Oracle.super_.prototype.visitColumn.call(this, columnNode); }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index fb7fb4d4..a57e6402 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -738,7 +738,7 @@ Postgres.prototype.visitColumn = function(columnNode) { var inCast = this._visitingCast; var txt = []; var closeParen = 0; - if(inSelectClause && (!table.alias || !!columnNode.alias)) { + if(inSelectClause && (table && !table.alias || !!columnNode.alias)) { if (columnNode.asArray) { closeParen++; txt.push(this._arrayAggFunctionName+'('); @@ -755,16 +755,18 @@ Postgres.prototype.visitColumn = function(columnNode) { } } if(!inInsertUpdateClause && !this.visitingReturning && !this._visitingCreate && !this._visitingAlter && !columnNode.subfieldContainer) { - if(typeof table.alias === 'string') { - txt.push(this.quote(table.alias)); - } else { - if(table.getSchema()) { - txt.push(this.quote(table.getSchema())); - txt.push('.'); + if (table) { + if (typeof table.alias === 'string') { + txt.push(this.quote(table.alias)); + } else { + if (table.getSchema()) { + txt.push(this.quote(table.getSchema())); + txt.push('.'); + } + txt.push(this.quote(table.getName())); } - txt.push(this.quote(table.getName())); + txt.push('.'); } - txt.push('.'); } if (columnNode.star) { var allCols = []; @@ -785,6 +787,14 @@ Postgres.prototype.visitColumn = function(columnNode) { txt.push('*'); } } + else if (columnNode.isConstant) { + // this injects directly into SELECT statement rather than creating a parameter + // txt.push(this._getParameterValue(columnNode.literalValue)) + // currently thinking it is better to generate a parameter + var value = columnNode.constantValue; + this.params.push(value); + txt.push(this._getParameterText(this.params.length, value)); + } else { if (columnNode.subfieldContainer) { txt.push('(' + this.visitColumn(columnNode.subfieldContainer) + ').'); diff --git a/lib/index.js b/lib/index.js index 6f609570..1309fcf7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,13 +1,15 @@ 'use strict'; -var _ = require('lodash'); -var FunctionCall = require('./node/functionCall'); -var ArrayCall = require('./node/arrayCall'); -var functions = require('./functions'); -var getDialect = require('./dialect'); -var Query = require('./node/query'); -var sliced = require('sliced'); -var Table = require('./table'); +var _ = require('lodash'); +var Column = require("./column"); +var FunctionCall = require('./node/functionCall'); +var ArrayCall = require('./node/arrayCall'); +var functions = require('./functions'); +var getDialect = require('./dialect'); +var ParameterNode = require('./node/parameter'); +var Query = require('./node/query'); +var sliced = require('sliced'); +var Table = require('./table'); // default dialect is postgres var DEFAULT_DIALECT = 'postgres'; @@ -58,6 +60,19 @@ Sql.prototype.setDialect = function(dialect, config) { return this; }; +// Create a constant Column (for use in SELECT) +Sql.prototype.constant = function(value) { + var config={ + name:"constant", + property:"constant", + isConstant:true, + constantValue:value, + }; + var cn = new Column(config); + return cn; +}; + + // back compat shim for the Sql class constructor var create = function(dialect, config) { return new Sql(dialect, {}); diff --git a/lib/node/column.js b/lib/node/column.js index 6fa999fb..6a5f7284 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -10,6 +10,8 @@ module.exports = Node.define({ this.property = config.property || config.name; this.alias = config.alias; this.star = config.star; + this.isConstant = config.isConstant; + this.constantValue = config.constantValue; this.asArray = config.asArray; this.aggregator = config.aggregator; this.table = config.table; diff --git a/lib/node/query.js b/lib/node/query.js index cec925e5..6c7ca8fd 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,6 +1,7 @@ 'use strict'; var _ = require('lodash'); +var alias = require(__dirname + '/alias'); var assert = require('assert'); var sliced = require('sliced'); var util = require('util'); @@ -492,4 +493,10 @@ delete valueExpressions.or; delete valueExpressions.and; _.extend(Query.prototype, valueExpressions); +// Extend the query with the aliasMixin so that it's possible to write queries like +// var query=sql.select(a.select(a.count()).as("column1")) +// which generates: +// SELECT (SELECT COUNT(*) FROM a) AS "column1" +_.extend(Query.prototype, alias.AliasMixin); + module.exports = Query; diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index baa3eb40..2892c8ae 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); +var user = Harness.defineUserTable(); var customerAlias = Harness.defineCustomerAliasTable(); var Sql = require('../../lib'); @@ -181,3 +182,280 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: post.select(post.id.as('col1')), + pg: { + text : 'SELECT "post"."id" AS "col1" FROM "post"', + string: 'SELECT "post"."id" AS "col1" FROM "post"' + }, + sqlite: { + text : 'SELECT "post"."id" AS "col1" FROM "post"', + string: 'SELECT "post"."id" AS "col1" FROM "post"' + }, + mysql: { + text : 'SELECT `post`.`id` AS `col1` FROM `post`', + string: 'SELECT `post`.`id` AS `col1` FROM `post`' + }, + mssql: { + text : 'SELECT [post].[id] AS [col1] FROM [post]', + string: 'SELECT [post].[id] AS [col1] FROM [post]' + }, + oracle: { + text : 'SELECT "post"."id" "col1" FROM "post"', + string: 'SELECT "post"."id" "col1" FROM "post"' + }, + params: [] +}); + +Harness.test({ + query: post.select(Sql.constant(4)), + pg: { + text : 'SELECT $1 FROM "post"', + string: 'SELECT 4 FROM "post"' + }, + sqlite: { + text : 'SELECT $1 FROM "post"', + string: 'SELECT 4 FROM "post"' + }, + mysql: { + text : 'SELECT ? FROM `post`', + string: 'SELECT 4 FROM `post`' + }, + mssql: { + text : 'SELECT @1 FROM [post]', + string: 'SELECT 4 FROM [post]' + }, + oracle: { + text : 'SELECT :1 FROM "post"', + string: 'SELECT 4 FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(post.id,Sql.constant(4)), + pg: { + text : 'SELECT "post"."id", $1 FROM "post"', + string: 'SELECT "post"."id", 4 FROM "post"' + }, + sqlite: { + text : 'SELECT "post"."id", $1 FROM "post"', + string: 'SELECT "post"."id", 4 FROM "post"' + }, + mysql: { + text : 'SELECT `post`.`id`, ? FROM `post`', + string: 'SELECT `post`.`id`, 4 FROM `post`' + }, + mssql: { + text : 'SELECT [post].[id], @1 FROM [post]', + string: 'SELECT [post].[id], 4 FROM [post]' + }, + oracle: { + text : 'SELECT "post"."id", :1 FROM "post"', + string: 'SELECT "post"."id", 4 FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(Sql.constant(4).as('col1')), + pg: { + text : 'SELECT $1 AS "col1" FROM "post"', + string: 'SELECT 4 AS "col1" FROM "post"' + }, + sqlite: { + text : 'SELECT $1 AS "col1" FROM "post"', + string: 'SELECT 4 AS "col1" FROM "post"' + }, + mysql: { + text : 'SELECT ? AS `col1` FROM `post`', + string: 'SELECT 4 AS `col1` FROM `post`' + }, + mssql: { + text : 'SELECT @1 AS [col1] FROM [post]', + string: 'SELECT 4 AS [col1] FROM [post]' + }, + oracle: { + text : 'SELECT :1 "col1" FROM "post"', + string: 'SELECT 4 "col1" FROM "post"' + }, + params: [4] +}); + +Harness.test({ + query: post.select(Sql.constant(4).plus(5)), + pg: { + text : 'SELECT ($1 + $2) FROM "post"', + string: 'SELECT (4 + 5) FROM "post"' + }, + sqlite: { + text : 'SELECT ($1 + $2) FROM "post"', + string: 'SELECT (4 + 5) FROM "post"' + }, + mysql: { + text : 'SELECT (? + ?) FROM `post`', + string: 'SELECT (4 + 5) FROM `post`' + }, + mssql: { + text : 'SELECT (@1 + @2) FROM [post]', + string: 'SELECT (4 + 5) FROM [post]' + }, + oracle: { + text : 'SELECT (:1 + :2) FROM "post"', + string: 'SELECT (4 + 5) FROM "post"' + }, + params: [4,5] +}); + +Harness.test({ + query: post.select(Sql.constant(4).plus(5).as('col1')), + pg: { + text : 'SELECT ($1 + $2) AS "col1" FROM "post"', + string: 'SELECT (4 + 5) AS "col1" FROM "post"' + }, + sqlite: { + text : 'SELECT ($1 + $2) AS "col1" FROM "post"', + string: 'SELECT (4 + 5) AS "col1" FROM "post"' + }, + mysql: { + text : 'SELECT (? + ?) AS `col1` FROM `post`', + string: 'SELECT (4 + 5) AS `col1` FROM `post`' + }, + mssql: { + text : 'SELECT (@1 + @2) AS [col1] FROM [post]', + string: 'SELECT (4 + 5) AS [col1] FROM [post]' + }, + oracle: { + text : 'SELECT (:1 + :2) "col1" FROM "post"', + string: 'SELECT (4 + 5) "col1" FROM "post"' + }, + params: [4,5] +}); + +Harness.test({ + query: post.select(Sql.constant(4),Sql.constant("abc"),Sql.constant(true)), + pg: { + text : 'SELECT $1, $2, $3 FROM "post"', + string: 'SELECT 4, \'abc\', TRUE FROM "post"' + }, + sqlite: { + text : 'SELECT $1, $2, $3 FROM "post"', + string: 'SELECT 4, \'abc\', 1 FROM "post"' + }, + mysql: { + text : 'SELECT ?, ?, ? FROM `post`', + string: 'SELECT 4, \'abc\', TRUE FROM `post`' + }, + mssql: { + text : 'SELECT @1, @2, @3 FROM [post]', + string: 'SELECT 4, \'abc\', TRUE FROM [post]' + }, + oracle: { + text : 'SELECT :1, :2, :3 FROM "post"', + string: 'SELECT 4, \'abc\', TRUE FROM "post"' + }, + params: [4,'abc',true] +}); + +Harness.test({ + query: post.select(Sql.constant(1).sum()), + pg: { + text : 'SELECT SUM($1) AS "constant_sum" FROM "post"', + string: 'SELECT SUM(1) AS "constant_sum" FROM "post"' + }, + sqlite: { + text : 'SELECT SUM($1) AS "constant_sum" FROM "post"', + string: 'SELECT SUM(1) AS "constant_sum" FROM "post"' + }, + mysql: { + text : 'SELECT SUM(?) AS `constant_sum` FROM `post`', + string: 'SELECT SUM(1) AS `constant_sum` FROM `post`' + }, + mssql: { + text : 'SELECT SUM(@1) AS [constant_sum] FROM [post]', + string: 'SELECT SUM(1) AS [constant_sum] FROM [post]' + }, + oracle: { + text : 'SELECT SUM(:1) "constant_sum" FROM "post"', + string: 'SELECT SUM(1) "constant_sum" FROM "post"' + }, + params: [1] +}); + +Harness.test({ + query: Sql.select(post.select(post.id).as("column1")), + pg: { + text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"' + }, + sqlite: { + text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1"' + }, + mysql: { + text : 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`', + string: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`' + }, + mssql: { + text : 'SELECT (SELECT [post].[id] FROM [post]) AS [column1]', + string: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1]' + }, + oracle: { + text : 'SELECT (SELECT "post"."id" FROM "post") "column1"', + string: 'SELECT (SELECT "post"."id" FROM "post") "column1"' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(post.select(post.count()).as("column1")), + pg: { + text : 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"', + string: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"' + }, + sqlite: { + text : 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"', + string: 'SELECT (SELECT COUNT("post".*) AS "post_count" FROM "post") AS "column1"' + }, + mysql: { + text : 'SELECT (SELECT COUNT(*) AS `post_count` FROM `post`) AS `column1`', + string: 'SELECT (SELECT COUNT(*) AS `post_count` FROM `post`) AS `column1`' + }, + mssql: { + text : 'SELECT (SELECT COUNT(*) AS [post_count] FROM [post]) AS [column1]', + string: 'SELECT (SELECT COUNT(*) AS [post_count] FROM [post]) AS [column1]' + }, + oracle: { + text : 'SELECT (SELECT COUNT(*) "post_count" FROM "post") "column1"', + string: 'SELECT (SELECT COUNT(*) "post_count" FROM "post") "column1"' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(post.select(post.id).as("column1"),user.select(user.id).as("column2")), + pg: { + text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"' + }, + sqlite: { + text : 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"', + string: 'SELECT (SELECT "post"."id" FROM "post") AS "column1", (SELECT "user"."id" FROM "user") AS "column2"' + }, + mysql: { + text : 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`, (SELECT `user`.`id` FROM `user`) AS `column2`', + string: 'SELECT (SELECT `post`.`id` FROM `post`) AS `column1`, (SELECT `user`.`id` FROM `user`) AS `column2`' + }, + mssql: { + text : 'SELECT (SELECT [post].[id] FROM [post]) AS [column1], (SELECT [user].[id] FROM [user]) AS [column2]', + string: 'SELECT (SELECT [post].[id] FROM [post]) AS [column1], (SELECT [user].[id] FROM [user]) AS [column2]' + }, + oracle: { + text : 'SELECT (SELECT "post"."id" FROM "post") "column1", (SELECT "user"."id" FROM "user") "column2"', + string: 'SELECT (SELECT "post"."id" FROM "post") "column1", (SELECT "user"."id" FROM "user") "column2"' + }, + params: [] +}); + + From 5ec7827cf637a4fe6b930fd4e8d27e6a8cb5289f Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 30 Aug 2016 03:32:46 -0500 Subject: [PATCH 212/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a82fb8d..64e2f317 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.70.1", + "version": "0.71.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From f10abbed79a61e05c0a608095b76b9cf0e44b4fb Mon Sep 17 00:00:00 2001 From: Rohit Singh Date: Wed, 19 Oct 2016 16:54:02 +0200 Subject: [PATCH 213/248] Add support for ON CONFLICT as a support for upserts in PostgreSQL (#335) * Add support for ON CONFLICT as a support for upserts in PostgreSQL PostgreSQL supports upserts by ON CONFLICT clause provided in versions 9.5 and above. This should fix issue #333 * avoid redefining variable * fix scope --- lib/dialect/mssql.js | 4 + lib/dialect/mysql.js | 4 + lib/dialect/oracle.js | 4 + lib/dialect/postgres.js | 31 ++++++ lib/dialect/sqlite.js | 4 + lib/node/onConflict.js | 7 ++ lib/node/query.js | 10 ++ test/dialects/insert-tests.js | 184 ++++++++++++++++++++++++++++++++++ 8 files changed, 248 insertions(+) create mode 100644 lib/node/onConflict.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 2cb95d9d..e93fc45a 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -381,6 +381,10 @@ Mssql.prototype.visitOnDuplicate = function(onDuplicate) { throw new Error('MSSQL does not allow onDuplicate clause.'); }; +Mssql.prototype.visitOnConflict = function(onConflict) { + throw new Error('MSSQL does not allow onConflict clause.'); +}; + Mssql.prototype.visitReturning = function() { // TODO: need to add some code to the INSERT clause to support this since its the equivalent of the OUTPUT clause // in MS SQL which appears before the values, not at the end of the statement. diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 86416fcf..4d054564 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -46,6 +46,10 @@ Mysql.prototype.visitOnDuplicate = function(onDuplicate) { return result; }; +Mysql.prototype.visitOnConflict = function(onConflict) { + throw new Error('Mysql does not allow onConflict clause.'); +}; + Mysql.prototype.visitReturning = function() { throw new Error('MySQL does not allow returning clause.'); }; diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index ea2cb85e..d791b8f7 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -224,6 +224,9 @@ Oracle.prototype.visitCase = function(caseExp) { return Mssql.prototype.visitCase.call(this, caseExp); }; +Oracle.prototype.visitOnConflict = function(onConflict) { + throw new Error('Oracle does not allow onConflict clause.'); +}; function isCreateIfNotExists(create){ if (create.nodes.length===0) return false; @@ -253,4 +256,5 @@ function isCountStarExpression(columnNode){ return true; } + module.exports = Oracle; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a57e6402..a55f343d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -149,6 +149,7 @@ Postgres.prototype.visit = function(node) { case 'HAVING' : return this.visitHaving(node); case 'RETURNING' : return this.visitReturning(node); case 'ONDUPLICATE' : return this.visitOnDuplicate(node); + case 'ONCONFLICT' : return this.visitOnConflict(node); case 'FOR UPDATE' : return this.visitForUpdate(); case 'FOR SHARE' : return this.visitForShare(); case 'TABLE' : return this.visitTable(node); @@ -1037,6 +1038,36 @@ Postgres.prototype.visitOnDuplicate = function(onDuplicate) { throw new Error('PostgreSQL does not allow onDuplicate clause.'); }; +Postgres.prototype.visitOnConflict = function(onConflict) { + var result = ['ON CONFLICT']; + var columns = []; + var updateClause = [], i; + + if(onConflict.constraint) + result.push(['ON CONSTRAINT', this.quote(onConflict.constraint)].join(' ')); + else if(onConflict.columns) { + for(i=0; i < onConflict.columns.length; i++) { + columns.push(this.quote(onConflict.columns[i])); + } + result.push( '(' + columns.join(', ') + ')' ); + } + + if(onConflict.update){ + updateClause.push("DO UPDATE SET"); + var update = onConflict.update; + var setClause = []; + for(i=0; i Date: Wed, 19 Oct 2016 09:57:45 -0500 Subject: [PATCH 214/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64e2f317..6f2b9d02 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.71.0", + "version": "0.72.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From cc897ca79340758f1f10f30ef847d496d781e22e Mon Sep 17 00:00:00 2001 From: Rohit Singh Date: Tue, 20 Dec 2016 19:45:49 +0100 Subject: [PATCH 215/248] =?UTF-8?q?the=20ON=20CONFLICT=20feature=20for=20#?= =?UTF-8?q?PostgreSQL=20was=20missing=20camelcase=20support=E2=80=A6=20(#3?= =?UTF-8?q?42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * the ON CONFLICT feature for #PostgreSQL was missing camelcase support of column names this commit fixes that and takes care of issue #341 it now honours snakeToCamel set to true * we can quote the column name only once and save extra operation --- lib/dialect/postgres.js | 9 ++-- test/dialects/insert-tests.js | 83 +++++++++++++++++++++++++++++++++++ test/dialects/support.js | 9 ++++ 3 files changed, 97 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a55f343d..9d9f547a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1041,13 +1041,13 @@ Postgres.prototype.visitOnDuplicate = function(onDuplicate) { Postgres.prototype.visitOnConflict = function(onConflict) { var result = ['ON CONFLICT']; var columns = []; - var updateClause = [], i; - + var updateClause = [], i, col; + var table = this._queryNode.table; if(onConflict.constraint) result.push(['ON CONSTRAINT', this.quote(onConflict.constraint)].join(' ')); else if(onConflict.columns) { for(i=0; i < onConflict.columns.length; i++) { - columns.push(this.quote(onConflict.columns[i])); + columns.push(this.quote(table.getColumn(onConflict.columns[i]).name)); } result.push( '(' + columns.join(', ') + ')' ); } @@ -1057,7 +1057,8 @@ Postgres.prototype.visitOnConflict = function(onConflict) { var update = onConflict.update; var setClause = []; for(i=0; i Date: Tue, 20 Dec 2016 13:46:06 -0500 Subject: [PATCH 216/248] Fix adding/dropping columns with oracle. (#338) --- lib/dialect/oracle.js | 61 ++++++++++++++++++++++++++++++ test/dialects/alter-table-tests.js | 32 ++++++++++++++-- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index d791b8f7..9a9f6caa 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -28,6 +28,56 @@ Oracle.prototype.visitAlias = function(alias) { return result; }; +Oracle.prototype.visitAlter = function(alter) { + var self=this; + var errMsg='ALTER TABLE cannot be used to perform multiple different operations in the same statement.'; + + // Implement our own add column: + // PostgreSQL: ALTER TABLE "name" ADD COLUMN "col1", ADD COLUMN "col2" + // Oracle: ALTER TABLE "name" ADD ("col1", "col2") + function _addColumn(){ + self._visitingAlter = true; + var table = self._queryNode.table; + self._visitingAddColumn = true; + var result='ALTER TABLE '+self.visit(table.toNode())+' ADD ('+self.visit(alter.nodes[0].nodes[0]); + for (var i= 1,len=alter.nodes.length; i Date: Tue, 20 Dec 2016 13:46:21 -0500 Subject: [PATCH 217/248] Fix issue when calling insert with an object that has a length property instead of an array. (#337) --- lib/table.js | 2 +- test/dialects/insert-tests.js | 25 +++++++++++++++++++++++++ test/dialects/support.js | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/table.js b/lib/table.js index 21895aea..0b75c5fe 100644 --- a/lib/table.js +++ b/lib/table.js @@ -208,7 +208,7 @@ Table.prototype.subQuery = function(alias) { Table.prototype.insert = function() { var query = new Query(this); - if(arguments[0].length === 0){ + if(!arguments[0] || (util.isArray(arguments[0]) && arguments[0].length === 0)){ query.select.call(query, this.star()); query.where.apply(query,["1=2"]); } else { diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 30f83712..aca6be7b 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -57,6 +57,31 @@ Harness.test({ params: ['whoah'] }); +Harness.test({ + query: post.insert({length: 0}), + pg: { + text : 'INSERT INTO "post" ("length") VALUES ($1)', + string: 'INSERT INTO "post" ("length") VALUES (0)' + }, + sqlite: { + text : 'INSERT INTO "post" ("length") VALUES ($1)', + string: 'INSERT INTO "post" ("length") VALUES (0)' + }, + mysql: { + text : 'INSERT INTO `post` (`length`) VALUES (?)', + string: 'INSERT INTO `post` (`length`) VALUES (0)' + }, + mssql: { + text : 'INSERT INTO [post] ([length]) VALUES (@1)', + string: 'INSERT INTO [post] ([length]) VALUES (0)' + }, + oracle: { + text : 'INSERT INTO "post" ("length") VALUES (:1)', + string: 'INSERT INTO "post" ("length") VALUES (0)' + }, + params: [0] +}); + Harness.test({ query: post.insert({ content: 'test', diff --git a/test/dialects/support.js b/test/dialects/support.js index 83da378f..4a9fa427 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -76,7 +76,7 @@ module.exports = { definePostTable: function() { return Table.define({ name: 'post', - columns: ['id', 'userId', 'content', 'tags'] + columns: ['id', 'userId', 'content', 'tags', 'length'] }); }, From 1049cd7508d0ff86cb6fc314d6eaba89ad8ae98a Mon Sep 17 00:00:00 2001 From: petrovi4 Date: Tue, 20 Dec 2016 21:46:43 +0300 Subject: [PATCH 218/248] Added value expression for ? operator "contain key" (#334) --- lib/node/valueExpression.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index faad8033..2fa741a9 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -148,6 +148,7 @@ var ValueExpressionMixin = function() { at : atMethod, contains : binaryMethod('@>'), containedBy : binaryMethod('<@'), + containsKey : binaryMethod('?'), overlap : binaryMethod('&&'), slice : sliceMethod, cast : castMethod, From 72aff9012a3f4339892d6283a6b872d682faef11 Mon Sep 17 00:00:00 2001 From: Kevin Anthoney Date: Tue, 20 Dec 2016 18:47:03 +0000 Subject: [PATCH 219/248] Add date time interval functionality to postgres and mysql dialects (#326) * Add date time interval functionality to postgres and mysql dialects * Add date interval test involving years and months --- lib/dialect/mysql.js | 27 +++++++++++ lib/dialect/postgres.js | 21 +++++++++ lib/index.js | 26 ++++++---- lib/node/interval.js | 21 +++++++++ test/dialects/date-tests.js | 94 ++++++++++++++++++++++++++++++++++++- 5 files changed, 178 insertions(+), 11 deletions(-) create mode 100644 lib/node/interval.js diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 4d054564..5212ba5b 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -2,6 +2,7 @@ var util = require('util'); var assert = require('assert'); +var _ = require('lodash'); var Mysql = function(config) { this.output = []; @@ -155,4 +156,30 @@ Mysql.prototype.visitColumn = function(columnNode) { return Mysql.super_.prototype.visitColumn.call(this, columnNode); }; +Mysql.prototype.visitInterval = function(interval) { + var parameter; + if(_.isNumber(interval.years)) { + if(_.isNumber(interval.months)) { + parameter = "'" + interval.years + '-' + interval.months + "' YEAR_MONTH"; + } else { + parameter = interval.years + ' YEAR'; + } + } else if(_.isNumber(interval.months)) { + parameter = interval.months + ' MONTH'; + } else if(_.isNumber(interval.days)) { + parameter = "'" + interval.days + ' ' + + (_.isNumber(interval.hours)?interval.hours:0) + ':' + + (_.isNumber(interval.minutes)?interval.minutes:0) + ':' + + (_.isNumber(interval.seconds)?interval.seconds:0) + "' DAY_SECOND"; + } else { + parameter = "'" + (_.isNumber(interval.hours)?interval.hours:0) + ':' + + (_.isNumber(interval.minutes)?interval.minutes:0) + ':' + + (_.isNumber(interval.seconds)?interval.seconds:0) + "' HOUR_SECOND"; + } + var result = "INTERVAL " + parameter; + return result; +}; + + + module.exports = Mysql; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 9d9f547a..6520e1cc 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -174,6 +174,7 @@ Postgres.prototype.visit = function(node) { case 'FUNCTION CALL' : return this.visitFunctionCall(node); case 'ARRAY CALL' : return this.visitArrayCall(node); case 'CREATE VIEW' : return this.visitCreateView(node); + case 'INTERVAL' : return this.visitInterval(node); case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); case 'PREFIX UNARY' : return this.visitPrefixUnary(node); @@ -1139,6 +1140,26 @@ Postgres.prototype.visitCreateView = function(createView) { return result; }; +Postgres.prototype.visitInterval = function(interval) { + var parameter = ''; + function _add(n, unit) { + if(!_.isNumber(n)) return; + if(parameter !== '') { + parameter += ' '; + } + parameter += n + ' ' + unit; + } + _add(interval.years, 'YEAR'); + _add(interval.months, 'MONTH'); + _add(interval.days, 'DAY'); + _add(interval.hours, 'HOUR'); + _add(interval.minutes, 'MINUTE'); + _add(interval.seconds, 'SECOND'); + if(parameter === '') parameter = '0 SECOND'; + var result = "INTERVAL '" + parameter + "'"; + return result; +}; + /** * Broken out as a separate function so that dialects that derive from this class can still use this functionality. * diff --git a/lib/index.js b/lib/index.js index 1309fcf7..3a1cdfdc 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,15 +1,15 @@ 'use strict'; -var _ = require('lodash'); -var Column = require("./column"); -var FunctionCall = require('./node/functionCall'); -var ArrayCall = require('./node/arrayCall'); -var functions = require('./functions'); -var getDialect = require('./dialect'); -var ParameterNode = require('./node/parameter'); -var Query = require('./node/query'); -var sliced = require('sliced'); -var Table = require('./table'); +var _ = require('lodash'); +var Column = require("./column"); +var FunctionCall = require('./node/functionCall'); +var ArrayCall = require('./node/arrayCall'); +var functions = require('./functions'); +var getDialect = require('./dialect'); +var Query = require('./node/query'); +var sliced = require('sliced'); +var Table = require('./table'); +var Interval = require('./node/interval'); // default dialect is postgres var DEFAULT_DIALECT = 'postgres'; @@ -51,6 +51,12 @@ Sql.prototype.select = function() { return query; }; +// Returns an interval clause +Sql.prototype.interval = function() { + var interval = new Interval(sliced(arguments)); + return interval; +}; + // Set the dialect Sql.prototype.setDialect = function(dialect, config) { this.dialect = getDialect(dialect); diff --git a/lib/node/interval.js b/lib/node/interval.js new file mode 100644 index 00000000..231e0d0d --- /dev/null +++ b/lib/node/interval.js @@ -0,0 +1,21 @@ +'use strict'; + +var Node = require(__dirname); +var ParameterNode = require(__dirname + '/parameter'); + +var IntervalNode = Node.define({ + type: 'INTERVAL', + constructor: function(args) { + Node.call(this); + var interval = args[0] || {}; + this.years = interval.years; + this.months = interval.months; + this.days = interval.days; + this.hours = interval.hours; + this.minutes = interval.minutes; + this.seconds = interval.seconds; + } +}); + +module.exports = IntervalNode; + diff --git a/test/dialects/date-tests.js b/test/dialects/date-tests.js index 5a5fadda..dd2c4d64 100644 --- a/test/dialects/date-tests.js +++ b/test/dialects/date-tests.js @@ -133,4 +133,96 @@ Harness.test({ string: 'SELECT CURRENT_TIMESTAMP FROM "customer"' }, params: [] -}); \ No newline at end of file +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().plus(Sql.interval({hours:1}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR\')', + string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:0:0\' HOUR_SECOND)', + string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:0:0\' HOUR_SECOND)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({years:3}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR\')', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL 3 YEAR)', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL 3 YEAR)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({years:3, months:2}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR 2 MONTH\')', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3 YEAR 2 MONTH\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3-2\' YEAR_MONTH)', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'3-2\' YEAR_MONTH)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().plus(Sql.interval({hours:1, minutes:20}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR 20 MINUTE\')', + string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1 HOUR 20 MINUTE\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:20:0\' HOUR_SECOND)', + string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'1:20:0\' HOUR_SECOND)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().plus(Sql.interval({hours:'sql\'injection', minutes:20}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'20 MINUTE\')', + string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'20 MINUTE\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'0:20:0\' HOUR_SECOND)', + string: 'SELECT (CURRENT_TIMESTAMP + INTERVAL \'0:20:0\' HOUR_SECOND)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({days: 1, hours:5, minutes: 'sql\'injection'}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 DAY 5 HOUR\')', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 DAY 5 HOUR\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 5:0:0\' DAY_SECOND)', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'1 5:0:0\' DAY_SECOND)' + }, + params: [] +}); + +Harness.test({ + query: Sql.select(Sql.functions.CURRENT_TIMESTAMP().minus(Sql.interval({years: 2, months: 5}))), + pg: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2 YEAR 5 MONTH\')', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2 YEAR 5 MONTH\')' + }, + mysql: { + text : 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2-5\' YEAR_MONTH)', + string: 'SELECT (CURRENT_TIMESTAMP - INTERVAL \'2-5\' YEAR_MONTH)' + }, + params: [] +}); + From f941c74561e8a1fe31ca0baec4a9ffbbb7cac6f4 Mon Sep 17 00:00:00 2001 From: Christian Schuhmann Date: Tue, 20 Dec 2016 19:47:27 +0100 Subject: [PATCH 220/248] Fix Table.hasColumn for columns with custom property names (#322) There was a bug which caused Table.hasColumn to return false when passed a property name (defined via column.property) instead of a column name. --- lib/table.js | 9 +++------ test/table-tests.js | 13 +++++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/table.js b/lib/table.js index 0b75c5fe..0f657236 100644 --- a/lib/table.js +++ b/lib/table.js @@ -126,13 +126,10 @@ Table.prototype.addColumn = function(col, options) { }; Table.prototype.hasColumn = function(col) { - col = this.createColumn(col); - - var cols = this.columns.filter(function(column) { - return column.property === col.property || column.name === col.name; + var columnName = col instanceof Column ? col.name : col; + return this.columns.some(function(column) { + return column.property === columnName || column.name === columnName; }); - - return cols.length > 0; }; Table.prototype.getColumn = diff --git a/test/table-tests.js b/test/table-tests.js index 66c3bdd3..73d43367 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -167,6 +167,19 @@ test('hasColumn', function() { assert.equal(table.hasColumn('baz'), true); }); +test('hasColumn with user-defined column property', function() { + var table = Table.define({ + name: 'blah', + columns: [{ + name: 'id', + property: 'theId' + }, {name: 'foo'}] + }); + + assert.equal(table.hasColumn('id'), true); + assert.equal(table.hasColumn('theId'), true); +}); + test('the column "from" does not overwrite the from method', function() { var table = Table.define({ name: 'foo', columns: [] }); table.addColumn('from'); From 2808409da82cd4d5bda5577a64de5f11dcb43a62 Mon Sep 17 00:00:00 2001 From: Kevin Anthoney Date: Tue, 20 Dec 2016 18:47:57 +0000 Subject: [PATCH 221/248] add defaultValue parameter when creating tables (#311) --- lib/column.js | 1 + lib/dialect/postgres.js | 3 +++ lib/node/column.js | 1 + test/dialects/create-table-tests.js | 33 +++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/lib/column.js b/lib/column.js index 3c5e70f5..55a3da18 100644 --- a/lib/column.js +++ b/lib/column.js @@ -20,6 +20,7 @@ var Column = function(config) { direction : new TextNode('DESC') }); this.dataType = config.dataType; + this.defaultValue = config.defaultValue; }; // mix in value expression diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6520e1cc..20c4edab 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -826,6 +826,9 @@ Postgres.prototype.visitColumn = function(columnNode) { if (!columnNode.primaryKey && columnNode.unique) { txt.push(' UNIQUE'); } + if (columnNode.defaultValue !== undefined) { + txt.push(' DEFAULT ' + this._getParameterValue(columnNode.defaultValue)); + } } if (!!columnNode.references) { diff --git a/lib/node/column.js b/lib/node/column.js index 6a5f7284..3fda47b0 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -20,6 +20,7 @@ module.exports = Node.define({ this.distinct = config.distinct; this.primaryKey = config.primaryKey; this.notNull = config.notNull; + this.defaultValue = config.defaultValue; this.references = config.references; // If subfieldContainer is present, this is a subfield and subfieldContainer // is the parent Column diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 97f6a1fd..b1150617 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -248,6 +248,39 @@ Harness.test({ } }); +Harness.test({ + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'int', + primaryKey: true, + notNull: true + }, { + name: 'posts', + dataType: 'int', + notNull: true, + defaultValue: 0 + }] + }).create(), + pg: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' + }, + sqlite: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' + }, + mysql: { + text : 'CREATE TABLE `user` (`id` int PRIMARY KEY, `posts` int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE `user` (`id` int PRIMARY KEY, `posts` int NOT NULL DEFAULT 0)' + }, + oracle: { + text : 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)', + string: 'CREATE TABLE "user" ("id" int PRIMARY KEY, "posts" int NOT NULL DEFAULT 0)' + } +}); + Harness.test({ query: Table.define({ name: 'post', From 4533b3636ef43ac2a0656ba05d4765ce41ddc6c0 Mon Sep 17 00:00:00 2001 From: Brad Dunbar Date: Tue, 20 Dec 2016 13:48:14 -0500 Subject: [PATCH 222/248] Check instanceof Date. (#310) Since we just need to know if this value is a Date, we can check it directly. --- lib/dialect/postgres.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 20c4edab..9628f85d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -59,9 +59,9 @@ Postgres.prototype._getParameterValue = function(value, quoteChar) { value = _.map(value, this._getParameterValue.bind(this)); value = '(' + value.join(', ') + ')'; } - } else if (_.isFunction(value.toISOString)) { + } else if (value instanceof Date) { // Date object's default toString format does not get parsed well - // Handle date like objects using toISOString + // Handle dates using toISOString value = this._getParameterValue(value.toISOString()); } else if (Buffer.isBuffer(value)) { value = this._getParameterValue('\\x' + value.toString('hex')); From bc02f7850245964e15e63b4d904fa43114ec36a0 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 20 Dec 2016 12:49:20 -0600 Subject: [PATCH 223/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6f2b9d02..2dc3a8e8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.72.0", + "version": "0.73.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 73bf26079feabb31d6f2258b58d0abb47e95fd00 Mon Sep 17 00:00:00 2001 From: Andy Katz Date: Wed, 8 Feb 2017 09:34:32 -0600 Subject: [PATCH 224/248] add OR IGNORE for sqlite (#347) * add OR IGNORE for sqlite * add missing semicolon --- lib/dialect/postgres.js | 14 +++++++++----- lib/dialect/sqlite.js | 4 ++++ lib/node/orIgnore.js | 7 +++++++ lib/node/query.js | 6 ++++++ test/dialects/insert-tests.js | 24 ++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 lib/node/orIgnore.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 9628f85d..6e67c38e 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -162,6 +162,7 @@ Postgres.prototype.visit = function(node) { case 'DEFAULT' : return this.visitDefault(node); case 'IF EXISTS' : return this.visitIfExists(); case 'IF NOT EXISTS' : return this.visitIfNotExists(); + case 'OR IGNORE' : return this.visitOrIgnore(); case 'CASCADE' : return this.visitCascade(); case 'RESTRICT' : return this.visitRestrict(); case 'RENAME' : return this.visitRename(node); @@ -237,11 +238,10 @@ Postgres.prototype.visitInsert = function(insert) { // don't use table.column for inserts this._visitedInsert = true; - var result = [ - 'INSERT INTO', - this.visit(this._queryNode.table.toNode()), - '(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')' - ]; + var result = ['INSERT']; + result = result.concat(insert.nodes.map(this.visit.bind(this))); + result.push('INTO ' + this.visit(this._queryNode.table.toNode())); + result.push('(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')'); var paramNodes = insert.getParameters(); @@ -995,6 +995,10 @@ Postgres.prototype.visitIfNotExists = function() { return ['IF NOT EXISTS']; }; +Postgres.prototype.visitOrIgnore = function() { + throw new Error('PostgreSQL does not allow orIgnore clause.'); +}; + Postgres.prototype.visitCascade = function() { return ['CASCADE']; }; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 0cd31335..fb2450d4 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -165,4 +165,8 @@ Sqlite.prototype.visitBinary = function(binary) { return Sqlite.super_.prototype.visitBinary.call(this, binary); }; +Sqlite.prototype.visitOrIgnore = function() { + return ['OR IGNORE']; +}; + module.exports = Sqlite; diff --git a/lib/node/orIgnore.js b/lib/node/orIgnore.js new file mode 100644 index 00000000..849750bc --- /dev/null +++ b/lib/node/orIgnore.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'OR IGNORE' +}); diff --git a/lib/node/query.js b/lib/node/query.js index 9abc9b64..1927dbe9 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -37,6 +37,7 @@ var ParameterNode = require('./parameter'); var PrefixUnaryNode = require('./prefixUnary'); var IfExists = require('./ifExists'); var IfNotExists = require('./ifNotExists'); +var OrIgnore = require('./orIgnore'); var Cascade = require('./cascade'); var Restrict = require('./restrict'); var Indexes = require('./indexes'); @@ -468,6 +469,11 @@ var Query = Node.define({ return this; }, + orIgnore: function() { + this.nodes[0].unshift(new OrIgnore()); + return this; + }, + cascade: function() { this.nodes[0].add(new Cascade()); return this; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index aca6be7b..60ba6a62 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -680,6 +680,30 @@ Harness.test({ params: [2, 'test'] }); +Harness.test({ + query: customerAliasTable.insert({ + id : 2, + name : 'test' + }).orIgnore(), + mysql: { + throws: true + }, + sqlite: { + text : 'INSERT OR IGNORE INTO "customer" ("id", "name") VALUES ($1, $2)', + string: 'INSERT OR IGNORE INTO "customer" ("id", "name") VALUES (2, \'test\')' + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + Harness.test({ query: post.insert({ content: 'test', From 6d20ddd55e26c8d43032d35b874c87614cae13e8 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 8 Feb 2017 09:34:43 -0600 Subject: [PATCH 225/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2dc3a8e8..6b984199 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.73.0", + "version": "0.74.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 1af2a33c4b69972de90df7e4cf8f535753d3098d Mon Sep 17 00:00:00 2001 From: Lorenzo Giuliani Date: Sat, 15 Apr 2017 00:59:11 +0200 Subject: [PATCH 226/248] use browserify-safe require statements (#352) all boils down to _not_ using `__dirname` inside a require call --- lib/dialect/mssql.js | 2 +- lib/dialect/mysql.js | 2 +- lib/dialect/oracle.js | 4 ++-- lib/dialect/sqlite.js | 2 +- lib/functions.js | 2 +- lib/node/addColumn.js | 2 +- lib/node/alias.js | 2 +- lib/node/alter.js | 2 +- lib/node/arrayCall.js | 8 ++++---- lib/node/at.js | 6 +++--- lib/node/binary.js | 6 +++--- lib/node/cascade.js | 2 +- lib/node/case.js | 6 +++--- lib/node/cast.js | 6 +++--- lib/node/column.js | 2 +- lib/node/create.js | 2 +- lib/node/createView.js | 2 +- lib/node/default.js | 2 +- lib/node/delete.js | 2 +- lib/node/distinct.js | 2 +- lib/node/distinctOn.js | 2 +- lib/node/drop.js | 2 +- lib/node/dropColumn.js | 2 +- lib/node/forShare.js | 2 +- lib/node/forUpdate.js | 2 +- lib/node/foreignKey.js | 2 +- lib/node/from.js | 2 +- lib/node/functionCall.js | 8 ++++---- lib/node/groupBy.js | 2 +- lib/node/having.js | 2 +- lib/node/ifExists.js | 2 +- lib/node/ifNotExists.js | 2 +- lib/node/in.js | 6 +++--- lib/node/index.js | 2 +- lib/node/interval.js | 4 ++-- lib/node/join.js | 2 +- lib/node/literal.js | 2 +- lib/node/notIn.js | 6 +++--- lib/node/onConflict.js | 2 +- lib/node/onDuplicate.js | 2 +- lib/node/orIgnore.js | 2 +- lib/node/orderBy.js | 2 +- lib/node/orderByValue.js | 2 +- lib/node/parameter.js | 2 +- lib/node/postfixUnary.js | 6 +++--- lib/node/prefixUnary.js | 6 +++--- lib/node/query.js | 4 ++-- lib/node/rename.js | 2 +- lib/node/renameColumn.js | 2 +- lib/node/restrict.js | 2 +- lib/node/returning.js | 2 +- lib/node/select.js | 2 +- lib/node/slice.js | 6 +++--- lib/node/table.js | 2 +- lib/node/ternary.js | 6 +++--- lib/node/text.js | 2 +- lib/node/truncate.js | 2 +- lib/node/update.js | 2 +- lib/node/where.js | 6 +++--- lib/table.js | 14 +++++++------- 60 files changed, 97 insertions(+), 97 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index e93fc45a..3606f5b6 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -20,7 +20,7 @@ var Mssql = function(config) { this.config = config || {}; }; -var Postgres = require(__dirname + '/postgres'); +var Postgres = require('./postgres'); util.inherits(Mssql, Postgres); diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 5212ba5b..b2fc2c26 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -10,7 +10,7 @@ var Mysql = function(config) { this.config = config || {}; }; -var Postgres = require(__dirname + '/postgres'); +var Postgres = require('./postgres'); util.inherits(Mysql, Postgres); diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index 9a9f6caa..b1f95eec 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -9,9 +9,9 @@ var Oracle = function(config) { this.config = config || {}; }; -var Postgres = require(__dirname + '/postgres'); +var Postgres = require('./postgres'); -var Mssql = require(__dirname + '/mssql'); +var Mssql = require('./mssql'); util.inherits(Oracle, Postgres); diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index fb2450d4..af2c3ef4 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -11,7 +11,7 @@ var Sqlite = function(config) { this.config = config || {}; }; -var Postgres = require(__dirname + '/postgres'); +var Postgres = require('./postgres'); util.inherits(Sqlite, Postgres); diff --git a/lib/functions.js b/lib/functions.js index b0abcf54..4362b706 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -1,7 +1,7 @@ 'use strict'; var _ = require('lodash'); var sliced = require('sliced'); -var FunctionCall = require(__dirname + '/node/functionCall'); +var FunctionCall = require('./node/functionCall'); // create a function that creates a function call of the specific name, using the specified sql instance var getFunctionCallCreator = function(name) { diff --git a/lib/node/addColumn.js b/lib/node/addColumn.js index 273d8836..3d7d4066 100644 --- a/lib/node/addColumn.js +++ b/lib/node/addColumn.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'ADD COLUMN' diff --git a/lib/node/alias.js b/lib/node/alias.js index 78f01323..9f9855f5 100644 --- a/lib/node/alias.js +++ b/lib/node/alias.js @@ -1,7 +1,7 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); +var Node = require('./index'); var AliasNode = Node.define({ type: 'ALIAS', diff --git a/lib/node/alter.js b/lib/node/alter.js index ce53623c..4aae4d83 100644 --- a/lib/node/alter.js +++ b/lib/node/alter.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'ALTER' diff --git a/lib/node/arrayCall.js b/lib/node/arrayCall.js index 4f2f657b..7533190d 100644 --- a/lib/node/arrayCall.js +++ b/lib/node/arrayCall.js @@ -1,9 +1,9 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var ParameterNode = require(__dirname + '/parameter'); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var ParameterNode = require('./parameter'); +var valueExpressionMixin = require('./valueExpression'); var ArrayCallNode = Node.define({ type: 'ARRAY CALL', @@ -18,7 +18,7 @@ var ArrayCallNode = Node.define({ _.extend(ArrayCallNode.prototype, valueExpressionMixin()); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(ArrayCallNode.prototype, AliasNode.AliasMixin); module.exports = ArrayCallNode; diff --git a/lib/node/at.js b/lib/node/at.js index 2ded9362..5e8ca47b 100644 --- a/lib/node/at.js +++ b/lib/node/at.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var AtNode = Node.define({ @@ -21,7 +21,7 @@ var AtNode = Node.define({ }); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(AtNode.prototype, AliasNode.AliasMixin); module.exports = AtNode; diff --git a/lib/node/binary.js b/lib/node/binary.js index 7b721650..da8eb8bd 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var BinaryNode = Node.define(_.extend({ @@ -23,7 +23,7 @@ var BinaryNode = Node.define(_.extend({ })); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(BinaryNode.prototype, AliasNode.AliasMixin); module.exports = BinaryNode; diff --git a/lib/node/cascade.js b/lib/node/cascade.js index 1dea1eef..4b6646fd 100644 --- a/lib/node/cascade.js +++ b/lib/node/cascade.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'CASCADE' diff --git a/lib/node/case.js b/lib/node/case.js index b8729314..ac3bf214 100644 --- a/lib/node/case.js +++ b/lib/node/case.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var CaseNode = Node.define(_.extend({ @@ -23,7 +23,7 @@ var CaseNode = Node.define(_.extend({ })); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(CaseNode.prototype, AliasNode.AliasMixin); module.exports = CaseNode; diff --git a/lib/node/cast.js b/lib/node/cast.js index 60966ea9..be915b1e 100644 --- a/lib/node/cast.js +++ b/lib/node/cast.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var CastNode = Node.define({ @@ -21,7 +21,7 @@ var CastNode = Node.define({ }); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(CastNode.prototype, AliasNode.AliasMixin); module.exports = CastNode; diff --git a/lib/node/column.js b/lib/node/column.js index 3fda47b0..6b145d74 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'COLUMN', diff --git a/lib/node/create.js b/lib/node/create.js index c048c3ce..67cd9b3d 100644 --- a/lib/node/create.js +++ b/lib/node/create.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'CREATE', diff --git a/lib/node/createView.js b/lib/node/createView.js index bc52684f..7d456d90 100644 --- a/lib/node/createView.js +++ b/lib/node/createView.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'CREATE VIEW', diff --git a/lib/node/default.js b/lib/node/default.js index 49bd7ebd..b5adc894 100644 --- a/lib/node/default.js +++ b/lib/node/default.js @@ -1,6 +1,6 @@ 'use strict'; -module.exports = require(__dirname).define({ +module.exports = require('./index').define({ type: 'DEFAULT', value: function() { return; diff --git a/lib/node/delete.js b/lib/node/delete.js index 2acb5872..0d02ebab 100644 --- a/lib/node/delete.js +++ b/lib/node/delete.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'DELETE' diff --git a/lib/node/distinct.js b/lib/node/distinct.js index a115f148..8c681551 100644 --- a/lib/node/distinct.js +++ b/lib/node/distinct.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'DISTINCT', diff --git a/lib/node/distinctOn.js b/lib/node/distinctOn.js index a208dfde..72c430e8 100644 --- a/lib/node/distinctOn.js +++ b/lib/node/distinctOn.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'DISTINCT ON', diff --git a/lib/node/drop.js b/lib/node/drop.js index 177b6d1a..b0428347 100644 --- a/lib/node/drop.js +++ b/lib/node/drop.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'DROP', diff --git a/lib/node/dropColumn.js b/lib/node/dropColumn.js index 60ad4219..01fe36c5 100644 --- a/lib/node/dropColumn.js +++ b/lib/node/dropColumn.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'DROP COLUMN' diff --git a/lib/node/forShare.js b/lib/node/forShare.js index 328a4ebe..68a83678 100644 --- a/lib/node/forShare.js +++ b/lib/node/forShare.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'FOR SHARE' diff --git a/lib/node/forUpdate.js b/lib/node/forUpdate.js index c869f981..da4a2518 100644 --- a/lib/node/forUpdate.js +++ b/lib/node/forUpdate.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'FOR UPDATE' diff --git a/lib/node/foreignKey.js b/lib/node/foreignKey.js index c738d842..a0ad99c1 100644 --- a/lib/node/foreignKey.js +++ b/lib/node/foreignKey.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'FOREIGN KEY', diff --git a/lib/node/from.js b/lib/node/from.js index 84a6010f..12b54565 100644 --- a/lib/node/from.js +++ b/lib/node/from.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); var From = Node.define({ type: 'FROM' diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js index 6d43c279..608a3c1e 100644 --- a/lib/node/functionCall.js +++ b/lib/node/functionCall.js @@ -1,9 +1,9 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var ParameterNode = require(__dirname + '/parameter'); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var ParameterNode = require('./parameter'); +var valueExpressionMixin = require('./valueExpression'); var FunctionCallNode = Node.define({ type: 'FUNCTION CALL', @@ -18,7 +18,7 @@ var FunctionCallNode = Node.define({ _.extend(FunctionCallNode.prototype, valueExpressionMixin()); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(FunctionCallNode.prototype, AliasNode.AliasMixin); module.exports = FunctionCallNode; diff --git a/lib/node/groupBy.js b/lib/node/groupBy.js index 6e5888d1..53f63e94 100644 --- a/lib/node/groupBy.js +++ b/lib/node/groupBy.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'GROUP BY' diff --git a/lib/node/having.js b/lib/node/having.js index 7dcf3434..6f1523ac 100644 --- a/lib/node/having.js +++ b/lib/node/having.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'HAVING' diff --git a/lib/node/ifExists.js b/lib/node/ifExists.js index 9b759779..c26df660 100644 --- a/lib/node/ifExists.js +++ b/lib/node/ifExists.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'IF EXISTS' diff --git a/lib/node/ifNotExists.js b/lib/node/ifNotExists.js index ef414551..d731ccb2 100644 --- a/lib/node/ifNotExists.js +++ b/lib/node/ifNotExists.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'IF NOT EXISTS' diff --git a/lib/node/in.js b/lib/node/in.js index 4c807331..233b7c28 100644 --- a/lib/node/in.js +++ b/lib/node/in.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var InNode = Node.define(_.extend({ @@ -22,7 +22,7 @@ var InNode = Node.define(_.extend({ })); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(InNode.prototype, AliasNode.AliasMixin); module.exports = InNode; diff --git a/lib/node/index.js b/lib/node/index.js index d519466f..66c0e481 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -98,4 +98,4 @@ Node.define = function(def) { }; module.exports = Node; -var TextNode = require(__dirname + '/text'); +var TextNode = require('./text'); diff --git a/lib/node/interval.js b/lib/node/interval.js index 231e0d0d..9f46f9ab 100644 --- a/lib/node/interval.js +++ b/lib/node/interval.js @@ -1,7 +1,7 @@ 'use strict'; -var Node = require(__dirname); -var ParameterNode = require(__dirname + '/parameter'); +var Node = require('./index'); +var ParameterNode = require('./parameter'); var IntervalNode = Node.define({ type: 'INTERVAL', diff --git a/lib/node/join.js b/lib/node/join.js index 7186f694..bbc1f93a 100644 --- a/lib/node/join.js +++ b/lib/node/join.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); var JoinNode = module.exports = Node.define({ type: 'JOIN', constructor: function(subType, from, to) { diff --git a/lib/node/literal.js b/lib/node/literal.js index c4f539bb..f5a1ea58 100644 --- a/lib/node/literal.js +++ b/lib/node/literal.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'LITERAL', diff --git a/lib/node/notIn.js b/lib/node/notIn.js index e363f7f3..c50976c3 100644 --- a/lib/node/notIn.js +++ b/lib/node/notIn.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var NotInNode = Node.define(_.extend({ @@ -22,7 +22,7 @@ var NotInNode = Node.define(_.extend({ })); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(NotInNode.prototype, AliasNode.AliasMixin); module.exports = NotInNode; diff --git a/lib/node/onConflict.js b/lib/node/onConflict.js index cd785120..cc71ac47 100644 --- a/lib/node/onConflict.js +++ b/lib/node/onConflict.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'ONCONFLICT' diff --git a/lib/node/onDuplicate.js b/lib/node/onDuplicate.js index 38146793..cd653cb3 100644 --- a/lib/node/onDuplicate.js +++ b/lib/node/onDuplicate.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'ONDUPLICATE' diff --git a/lib/node/orIgnore.js b/lib/node/orIgnore.js index 849750bc..e23c9d6d 100644 --- a/lib/node/orIgnore.js +++ b/lib/node/orIgnore.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'OR IGNORE' diff --git a/lib/node/orderBy.js b/lib/node/orderBy.js index 6db2a978..b97fb891 100644 --- a/lib/node/orderBy.js +++ b/lib/node/orderBy.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'ORDER BY' diff --git a/lib/node/orderByValue.js b/lib/node/orderByValue.js index 51d44567..47a8d5c0 100644 --- a/lib/node/orderByValue.js +++ b/lib/node/orderByValue.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); var OrderByColumn = Node.define({ type: 'ORDER BY VALUE', diff --git a/lib/node/parameter.js b/lib/node/parameter.js index c2276710..051ed852 100644 --- a/lib/node/parameter.js +++ b/lib/node/parameter.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); var ParameterNode = module.exports = Node.define({ type: 'PARAMETER', diff --git a/lib/node/postfixUnary.js b/lib/node/postfixUnary.js index 0c132f8a..8c66b89f 100644 --- a/lib/node/postfixUnary.js +++ b/lib/node/postfixUnary.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var PostfixUnaryNode = Node.define({ @@ -22,7 +22,7 @@ var PostfixUnaryNode = Node.define({ }); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(PostfixUnaryNode.prototype, AliasNode.AliasMixin); module.exports = PostfixUnaryNode; diff --git a/lib/node/prefixUnary.js b/lib/node/prefixUnary.js index 67a59fa1..fbde69c0 100644 --- a/lib/node/prefixUnary.js +++ b/lib/node/prefixUnary.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var PrefixUnaryNode = Node.define({ @@ -22,7 +22,7 @@ var PrefixUnaryNode = Node.define({ }); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(PrefixUnaryNode.prototype, AliasNode.AliasMixin); module.exports = PrefixUnaryNode; diff --git a/lib/node/query.js b/lib/node/query.js index 1927dbe9..674d07b7 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,11 +1,11 @@ 'use strict'; var _ = require('lodash'); -var alias = require(__dirname + '/alias'); +var alias = require('./alias'); var assert = require('assert'); var sliced = require('sliced'); var util = require('util'); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var valueExpressionMixin = require('./valueExpression'); var Node = require('./'); var Select = require('./select'); diff --git a/lib/node/rename.js b/lib/node/rename.js index 9767a528..c87bcfb3 100644 --- a/lib/node/rename.js +++ b/lib/node/rename.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'RENAME' diff --git a/lib/node/renameColumn.js b/lib/node/renameColumn.js index f886a11d..c3c66865 100644 --- a/lib/node/renameColumn.js +++ b/lib/node/renameColumn.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'RENAME COLUMN' diff --git a/lib/node/restrict.js b/lib/node/restrict.js index f7c63c15..942f4112 100644 --- a/lib/node/restrict.js +++ b/lib/node/restrict.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'RESTRICT' diff --git a/lib/node/returning.js b/lib/node/returning.js index 35ea0a18..2f27d067 100644 --- a/lib/node/returning.js +++ b/lib/node/returning.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'RETURNING' diff --git a/lib/node/select.js b/lib/node/select.js index a485b814..93e22538 100644 --- a/lib/node/select.js +++ b/lib/node/select.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'SELECT', diff --git a/lib/node/slice.js b/lib/node/slice.js index ab32f314..86c1ce21 100644 --- a/lib/node/slice.js +++ b/lib/node/slice.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var SliceNode = Node.define({ @@ -22,7 +22,7 @@ var SliceNode = Node.define({ }); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(SliceNode.prototype, AliasNode.AliasMixin); module.exports = SliceNode; diff --git a/lib/node/table.js b/lib/node/table.js index b1257105..4fca70d1 100644 --- a/lib/node/table.js +++ b/lib/node/table.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'TABLE', constructor: function(table) { diff --git a/lib/node/ternary.js b/lib/node/ternary.js index 1ef5ce7b..3f688ba9 100644 --- a/lib/node/ternary.js +++ b/lib/node/ternary.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('lodash'); -var Node = require(__dirname); -var valueExpressionMixin = require(__dirname + '/valueExpression'); +var Node = require('./index'); +var valueExpressionMixin = require('./valueExpression'); var valueExpressionMixed = false; var TernaryNode = Node.define(_.extend({ @@ -25,7 +25,7 @@ var TernaryNode = Node.define(_.extend({ })); // allow aliasing -var AliasNode = require(__dirname + '/alias'); +var AliasNode = require('./alias'); _.extend(TernaryNode.prototype, AliasNode.AliasMixin); module.exports = TernaryNode; diff --git a/lib/node/text.js b/lib/node/text.js index ef1194b2..bf026151 100644 --- a/lib/node/text.js +++ b/lib/node/text.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'TEXT', diff --git a/lib/node/truncate.js b/lib/node/truncate.js index 790c26ca..165e0d9e 100644 --- a/lib/node/truncate.js +++ b/lib/node/truncate.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'TRUNCATE', diff --git a/lib/node/update.js b/lib/node/update.js index 32a29ba9..890fbee9 100644 --- a/lib/node/update.js +++ b/lib/node/update.js @@ -1,6 +1,6 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./index'); module.exports = Node.define({ type: 'UPDATE' diff --git a/lib/node/where.js b/lib/node/where.js index b542807d..5c0465fc 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,8 +1,8 @@ 'use strict'; -var Node = require(__dirname); -var BinaryNode = require(__dirname + '/binary'); -var TextNode = require(__dirname + '/text'); +var Node = require('./index'); +var BinaryNode = require('./binary'); +var TextNode = require('./text'); var normalizeNode = function(table, node) { var result = node; diff --git a/lib/table.js b/lib/table.js index 0f657236..23e335a8 100644 --- a/lib/table.js +++ b/lib/table.js @@ -3,13 +3,13 @@ var util = require('util'); var lodash = require('lodash'); -var Query = require(__dirname + '/node/query'); -var Column = require(__dirname + '/column'); -var TableNode = require(__dirname + '/node/table'); -var JoinNode = require(__dirname + '/node/join'); -var LiteralNode = require(__dirname + '/node/literal'); -var Joiner = require(__dirname + '/joiner'); -var ForeignKeyNode = require(__dirname + '/node/foreignKey'); +var Query = require('./node/query'); +var Column = require('./column'); +var TableNode = require('./node/table'); +var JoinNode = require('./node/join'); +var LiteralNode = require('./node/literal'); +var Joiner = require('./joiner'); +var ForeignKeyNode = require('./node/foreignKey'); var Table = function(config) { this._schema = config.schema; From 7187f755da8dcd08a525ca3c9f5cf8e119288b11 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Fri, 14 Apr 2017 17:59:50 -0500 Subject: [PATCH 227/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b984199..8a61259b 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.74.0", + "version": "0.75.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 6defdca12271765a3aef057a94241527aa6bad1e Mon Sep 17 00:00:00 2001 From: Santiago Castro Date: Mon, 17 Apr 2017 13:42:29 -0300 Subject: [PATCH 228/248] Fix broken Markdown headings (#353) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 193ab2be..e1a3af8c 100644 --- a/README.md +++ b/README.md @@ -183,5 +183,5 @@ Usually after a few high-quality pull requests and friendly interactions we will After all, open source belongs to everyone. -##license +## license MIT From f9420542eddbb3479b21f635644617de7629e4b5 Mon Sep 17 00:00:00 2001 From: 3n-mb <3n-mb@users.noreply.github.com> Date: Tue, 23 May 2017 10:25:04 -0400 Subject: [PATCH 229/248] Adding types v1 (#357) * Create types.d.ts * Add types field --- lib/types.d.ts | 211 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 212 insertions(+) create mode 100644 lib/types.d.ts diff --git a/lib/types.d.ts b/lib/types.d.ts new file mode 100644 index 00000000..d75e59e8 --- /dev/null +++ b/lib/types.d.ts @@ -0,0 +1,211 @@ + +/** + * This is an adaptation of https://github.com/doxout/anydb-sql/blob/4e4c0ff4a7f2efb7f820baaafea1f624f1ae0399/d.ts/anydb-sql.d.ts + * Whole project is MIT licensed, so, we can use it. We also feed back any + * improvements, questions, concerns. + */ +declare module "sql" { + + interface OrderByValueNode {} + + interface Named { + name?: Name; + } + interface ColumnDefinition extends Named { + jsType?: Type; + dataType: string; + primaryKey?: boolean; + references?: { + table:string; + column: string; + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + }; + notNull?: boolean; + unique?: boolean; + defaultValue?: Type; + } + + interface TableDefinition { + name: Name; + schema: string; + columns: {[CName in keyof Row]: ColumnDefinition}; + isTemporary?: boolean; + foreignKeys?: { + table: string, + columns: (keyof Row)[], + refColumns: string[], + onDelete?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + onUpdate?: 'restrict' | 'cascade' | 'no action' | 'set null' | 'set default'; + } + } + + interface QueryLike { + values: any[] + text:string + } + + interface Executable { + toQuery():QueryLike; + } + + interface Queryable extends Executable { + where(...nodes:any[]):Query + delete():ModifyingQuery + select(star: Column): Query; + select(n1: Column):Query<{[N in N1]: T1}>; + select( + n1: Column, + n2: Column):Query<{[N in N1]: T1} & {[N in N2]: T2}> + select( + n1: Column, + n2: Column, + n3: Column):Query<{[N in N1]: T1} & {[N in N2]: T2} & {[N in N3]: T3}> + select(...nodesOrTables:any[]):Query + + } + + interface Query extends Executable, Queryable { + resultType: T; + + from(table:TableNode):Query + from(statement:string):Query + update(o:{[key: string]:any}):ModifyingQuery + update(o:{}):ModifyingQuery + group(...nodes:any[]):Query + order(...criteria:OrderByValueNode[]):Query + limit(l:number):Query + offset(o:number):Query + } + + interface SubQuery { + select(node:Column):SubQuery + select(...nodes: any[]):SubQuery + where(...nodes:any[]):SubQuery + from(table:TableNode):SubQuery + from(statement:string):SubQuery + group(...nodes:any[]):SubQuery + order(criteria:OrderByValueNode):SubQuery + exists():BinaryNode + notExists(): BinaryNode; + notExists(subQuery:SubQuery):BinaryNode + } + + + interface ModifyingQuery extends Executable { + returning(...nodes:any[]):Query + where(...nodes:any[]):ModifyingQuery + } + + interface TableNode { + join(table:TableNode):JoinTableNode + leftJoin(table:TableNode):JoinTableNode + } + + interface JoinTableNode extends TableNode { + on(filter:BinaryNode):TableNode + on(filter:string):TableNode + } + + interface CreateQuery extends Executable { + ifNotExists():Executable + } + interface DropQuery extends Executable { + ifExists():Executable + } + + type Columns = { + [Name in keyof T]: Column + } + type Table = TableNode & Queryable & Named & Columns & { + getName(): string; + getSchema(): string; + + literal(statement: string): any; + + create():CreateQuery + drop():DropQuery + as(name:OtherName):Table + update(o: Partial):ModifyingQuery + insert(row:T):ModifyingQuery + insert(rows:T[]):ModifyingQuery + select():Query + select(...nodes:any[]):Query + from(table:TableNode):Query + from(statement:string):Query + star():Column + subQuery():SubQuery + columns:Column[] + sql: SQL; + alter():AlterQuery; + indexes(): IndexQuery; + } + + interface AlterQuery extends Executable { + addColumn(column:Column): AlterQuery; + addColumn(name: string, options:string): AlterQuery; + dropColumn(column: Column|string): AlterQuery; + renameColumn(column: Column, newColumn: Column):AlterQuery; + renameColumn(column: Column, newName: string):AlterQuery; + renameColumn(name: string, newName: string):AlterQuery; + rename(newName: string): AlterQuery + } + interface IndexQuery { + create(): IndexCreationQuery; + create(indexName: string): IndexCreationQuery; + drop(indexName: string): Executable; + drop(...columns: Column[]): Executable + } + interface IndexCreationQuery extends Executable { + unique(): IndexCreationQuery; + using(name: string): IndexCreationQuery; + on(...columns: (Column|OrderByValueNode)[]): IndexCreationQuery; + withParser(parserName: string): IndexCreationQuery; + fulltext(): IndexCreationQuery; + spatial(): IndexCreationQuery; + } + + interface SQL { + functions: { + LOWER(c:Column):Column + } + } + + interface BinaryNode { + and(node:BinaryNode):BinaryNode + or(node:BinaryNode):BinaryNode + } + + interface Column { + name: Name + in(arr:T[]):BinaryNode + in(subQuery:SubQuery):BinaryNode + notIn(arr:T[]):BinaryNode + equals(node: T|Column):BinaryNode + notEquals(node: T|Column):BinaryNode + gte(node: T|Column):BinaryNode + lte(node: T|Column):BinaryNode + gt(node:T|Column):BinaryNode + lt(node: T|Column):BinaryNode + like(str:string):BinaryNode + multiply:{ + (node:Column):Column + (n:number):Column //todo check column names + } + isNull():BinaryNode + isNotNull():BinaryNode + //todo check column names + sum():Column + count():Column + count(name:string):Column + distinct():Column + as(name:OtherName):Column + ascending:OrderByValueNode + descending:OrderByValueNode + asc:OrderByValueNode + desc:OrderByValueNode + } + + function define(map:TableDefinition): Table; + +} diff --git a/package.json b/package.json index 8a61259b..be22764f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "url": "git://github.com/brianc/node-sql.git" }, "main": "lib/", + "types": "lib/types.d.ts", "scripts": { "test": "node_modules/.bin/mocha", "lint": "jshint lib test", From 0da386cec5348b5816688493ba36b68cd0600ce1 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 23 May 2017 11:57:06 -0500 Subject: [PATCH 230/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index be22764f..64cbac97 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.75.0", + "version": "0.76.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 3688b020749be9e0db8f8290ffcb284e447b06d7 Mon Sep 17 00:00:00 2001 From: Lorenzo Giuliani Date: Thu, 1 Jun 2017 21:10:58 +0200 Subject: [PATCH 231/248] add missing function `setDialect` (#359) add a new type definition: SQLDialects as Union of strings. --- lib/types.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/types.d.ts b/lib/types.d.ts index d75e59e8..84fb7ab3 100644 --- a/lib/types.d.ts +++ b/lib/types.d.ts @@ -6,6 +6,14 @@ */ declare module "sql" { + type SQLDialects = + | "mssql" + | "mysql" + | "oracle" + | "postgres" + | "sqlite" + ; + interface OrderByValueNode {} interface Named { @@ -30,6 +38,7 @@ declare module "sql" { name: Name; schema: string; columns: {[CName in keyof Row]: ColumnDefinition}; + dialect?: SQLDialects; isTemporary?: boolean; foreignKeys?: { table: string, @@ -207,5 +216,6 @@ declare module "sql" { } function define(map:TableDefinition): Table; + function setDialect(dialect: SQLDialects): void; } From f135dfc6ed49cbcf3dba31bcd5a02c815aa2a0f5 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Thu, 1 Jun 2017 14:11:31 -0500 Subject: [PATCH 232/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 64cbac97..b7c9b141 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.76.0", + "version": "0.76.1", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 1fbaf62b18c20651f2de6d53c2fd7828e9c49987 Mon Sep 17 00:00:00 2001 From: Luke Childs Date: Mon, 31 Jul 2017 15:00:44 +0100 Subject: [PATCH 233/248] Support REPLACE (#368) * Support REPLACE * Add REPLACE to default Postgres dialect * Make sure REPLACE doesn't get prepended with SELECT * * Make sure REPLACE doesn't use table.column syntax * REPLACE throws on unsupported dialects * Move replace to dialect prototypes * Copy MySQL insert syntax for repalce * Run insert tests against replace * Fix misplaced semicolon * Treat subquery parenthesis the same on INSERT and REPLACE --- lib/dialect/mssql.js | 4 + lib/dialect/mysql.js | 36 ++ lib/dialect/oracle.js | 4 + lib/dialect/postgres.js | 10 +- lib/dialect/sqlite.js | 33 ++ lib/node/query.js | 31 + lib/node/replace.js | 70 +++ lib/table.js | 11 + test/dialects/replace-tests.js | 1000 ++++++++++++++++++++++++++++++++ 9 files changed, 1197 insertions(+), 2 deletions(-) create mode 100644 lib/node/replace.js create mode 100644 test/dialects/replace-tests.js diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 3606f5b6..488f7fa2 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -30,6 +30,10 @@ Mssql.prototype._quoteCharacter = '['; Mssql.prototype._arrayAggFunctionName = ''; +Mssql.prototype.visitReplace = function(replace) { + throw new Error('Mssql does not support REPLACE.'); +}; + Mssql.prototype._getParameterPlaceholder = function(index, value) { if (this.config.questionMarkParameterPlaceholder) return '?'; return '@' + index; diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index b2fc2c26..0a63f3be 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -20,6 +20,42 @@ Mysql.prototype._quoteCharacter = '`'; Mysql.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; +Mysql.prototype.visitReplace = function(replace) { + var self = this; + // don't use table.column for replaces + this._visitedReplace = true; + + var result = ['REPLACE']; + result = result.concat(replace.nodes.map(this.visit.bind(this))); + result.push('INTO ' + this.visit(this._queryNode.table.toNode())); + result.push('(' + replace.columns.map(this.visit.bind(this)).join(', ') + ')'); + + var paramNodes = replace.getParameters(); + + if (paramNodes.length > 0) { + var paramText = paramNodes.map(function (paramSet) { + return paramSet.map(function (param) { + return self.visit(param); + }).join(', '); + }).map(function (param) { + return '('+param+')'; + }).join(', '); + + result.push('VALUES', paramText); + + if (result.slice(2, 5).join(' ') === '() VALUES ()') { + result.splice(2, 3, 'DEFAULT VALUES'); + } + } + + this._visitedReplace = false; + + if (result[2] === 'DEFAULT VALUES') { + result[2] = '() VALUES ()'; + } + return result; +}; + Mysql.prototype._getParameterPlaceholder = function() { return '?'; }; diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index b1f95eec..38267339 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -17,6 +17,10 @@ util.inherits(Oracle, Postgres); Oracle.prototype._myClass = Oracle; +Oracle.prototype.visitReplace = function(replace) { + throw new Error('Oracle does not support REPLACE.'); +}; + Oracle.prototype._aliasText = ' '; Oracle.prototype._getParameterPlaceholder = function(index, value) { /* jshint unused: false */ diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6e67c38e..2816c901 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -131,6 +131,7 @@ Postgres.prototype.visit = function(node) { case 'SUBQUERY' : return this.visitSubquery(node); case 'SELECT' : return this.visitSelect(node); case 'INSERT' : return this.visitInsert(node); + case 'REPLACE' : return this.visitReplace(node); case 'UPDATE' : return this.visitUpdate(node); case 'DELETE' : return this.visitDelete(node); case 'CREATE' : return this.visitCreate(node); @@ -266,6 +267,10 @@ Postgres.prototype.visitInsert = function(insert) { return result; }; +Postgres.prototype.visitReplace = function(replace) { + throw new Error('Postgres does not support REPLACE.'); +}; + Postgres.prototype.visitUpdate = function(update) { // don't auto-generate from clause var params = []; @@ -624,6 +629,7 @@ Postgres.prototype.visitQuery = function(queryNode) { break; case "INDEXES": case "INSERT": + case "REPLACE": case "UPDATE": case "CREATE": case "DROP": @@ -725,7 +731,7 @@ Postgres.prototype.visitTable = function(tableNode) { Postgres.prototype.visitColumn = function(columnNode) { var table = columnNode.table; - var inInsertUpdateClause = this._visitedInsert || this._visitingUpdateTargetColumn; + var inInsertUpdateClause = this._visitedInsert || this._visitedReplace || this._visitingUpdateTargetColumn; var inDdlClause = this._visitingAddColumn || this._visitingAlter || this._visitingCreate; var inSelectClause = this.visitingReturning || @@ -1211,7 +1217,7 @@ Postgres.prototype.handleDistinct = function(actions,filters) { function dontParenthesizeSubQuery(parentQuery){ if (!parentQuery) return false; if (parentQuery.nodes.length === 0) return false; - if (parentQuery.nodes[0].type != 'INSERT') return false; + if (['INSERT', 'REPLACE'].indexOf(parentQuery.nodes[0].type) === -1) return false; return true; } diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index af2c3ef4..60d46997 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -19,6 +19,39 @@ Sqlite.prototype._myClass = Sqlite; Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; +Sqlite.prototype.visitReplace = function(replace) { + var self = this; + // don't use table.column for replaces + this._visitedReplace = true; + + var result = ['REPLACE']; + result = result.concat(replace.nodes.map(this.visit.bind(this))); + result.push('INTO ' + this.visit(this._queryNode.table.toNode())); + result.push('(' + replace.columns.map(this.visit.bind(this)).join(', ') + ')'); + + var paramNodes = replace.getParameters(); + + if (paramNodes.length > 0) { + var paramText = paramNodes.map(function (paramSet) { + return paramSet.map(function (param) { + return self.visit(param); + }).join(', '); + }).map(function (param) { + return '('+param+')'; + }).join(', '); + + result.push('VALUES', paramText); + + if (result.slice(2, 5).join(' ') === '() VALUES ()') { + result.splice(2, 3, 'DEFAULT VALUES'); + } + } + + this._visitedReplace = false; + + return result; +}; + Sqlite.prototype._getParameterValue = function(value) { if (Buffer.isBuffer(value)) { value = 'x' + this._getParameterValue(value.toString('hex')); diff --git a/lib/node/query.js b/lib/node/query.js index 674d07b7..973267bc 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -15,6 +15,7 @@ var OrderBy = require('./orderBy'); var GroupBy = require('./groupBy'); var Having = require('./having'); var Insert = require('./insert'); +var Replace = require('./replace'); var Update = require('./update'); var Delete = require('./delete'); var Returning = require('./returning'); @@ -224,6 +225,36 @@ var Query = Node.define({ }, + replace: function(o) { + var self = this; + + var args = sliced(arguments); + // object literal + if (arguments.length === 1 && !o.toNode && !o.forEach) { + args = []; + Object.keys(o).forEach(function(key) { + var col = self.table.get(key); + if(col && !col.autoGenerated) + args.push(col.value(o[key])); + }); + } else if (o.forEach) { + o.forEach(function(arg) { + return self.replace.call(self, arg); + }); + return self; + } + + if (self.replaceClause) { + self.replaceClause.add(args); + return self; + } else { + self.replaceClause = new Replace(); + self.replaceClause.add(args); + return self.add(self.replaceClause); + } + + }, + update: function(o) { var self = this; var update = new Update(); diff --git a/lib/node/replace.js b/lib/node/replace.js new file mode 100644 index 00000000..d17099d2 --- /dev/null +++ b/lib/node/replace.js @@ -0,0 +1,70 @@ +'use strict'; + +var DefaultNode = require('./default'); +var Node = require('./'); +var ParameterNode = require('./parameter'); + +var Replace = Node.define({ + type: 'REPLACE', + constructor: function () { + Node.call(this); + this.names = []; + this.columns = []; + this.valueSets = []; + } +}); + +module.exports = Replace; + +Replace.prototype.add = function (nodes) { + var hasColumns = false; + var hasValues = false; + var self = this; + var values = {}; + nodes.forEach(function (node) { + var column = node.toNode(); + var name = column.name; + var idx = self.names.indexOf(name); + if (idx < 0) { + self.names.push(name); + self.columns.push(column); + } + hasColumns = true; + hasValues = hasValues || column.value !== undefined; + values[name] = column; + }); + + // When none of the columns have a value, it's ambiguous whether the user + // intends to replace a row of default values or append a SELECT statement + // later. Resolve the ambiguity by assuming that if no columns are specified + // it is a row of default values, otherwise a SELECT will be added. + if (hasValues || !hasColumns) { + this.valueSets.push(values); + } + + return self; +}; + +/* + * Get parameters for all values to be replaced. This function + * handles handles bulk replaces, where keys may be present + * in some objects and not others. When keys are not present, + * the replace should refer to the column value as DEFAULT. + */ +Replace.prototype.getParameters = function () { + var self = this; + return this.valueSets + .map(function (nodeDict) { + var set = []; + self.names.forEach(function (name) { + var node = nodeDict[name]; + if (node) { + set.push(ParameterNode.getNodeOrParameterNode(node.value)); + } + else { + set.push(new DefaultNode()); + } + }); + return set; + }); +}; diff --git a/lib/table.js b/lib/table.js index 23e335a8..3fae2710 100644 --- a/lib/table.js +++ b/lib/table.js @@ -214,6 +214,17 @@ Table.prototype.insert = function() { return query; }; +Table.prototype.replace = function() { + var query = new Query(this); + if(!arguments[0] || (util.isArray(arguments[0]) && arguments[0].length === 0)){ + query.select.call(query, this.star()); + query.where.apply(query,["1=2"]); + } else { + query.replace.apply(query, arguments); + } + return query; +}; + Table.prototype.toNode = function() { return new TableNode(this); }; diff --git a/test/dialects/replace-tests.js b/test/dialects/replace-tests.js new file mode 100644 index 00000000..72af0e4b --- /dev/null +++ b/test/dialects/replace-tests.js @@ -0,0 +1,1000 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); +var user = Harness.defineUserTable(); +var contentTable = Harness.defineContentTable(); +var customerAliasTable = Harness.defineCustomerAliasTable(); + +var arrayTable = require('../../lib/table').define({ + name: 'arraytest', + columns: ['id', 'numbers'] +}); + +Harness.test({ + query: post.replace(post.content.value('test'), post.userId.value(1)), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'test\', 1)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 1] +}); + +Harness.test({ + query: post.replace(post.content.value('whoah')), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content") VALUES ($1)', + string: 'REPLACE INTO "post" ("content") VALUES (\'whoah\')' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`) VALUES (?)', + string: 'REPLACE INTO `post` (`content`) VALUES (\'whoah\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah'] +}); + +Harness.test({ + query: post.replace({length: 0}), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("length") VALUES ($1)', + string: 'REPLACE INTO "post" ("length") VALUES (0)' + }, + mysql: { + text : 'REPLACE INTO `post` (`length`) VALUES (?)', + string: 'REPLACE INTO `post` (`length`) VALUES (0)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [0] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post.replace({ + content: post.sql.functions.LOWER('TEST'), + userId: 2 + }), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['TEST', 2] +}); + +// allow bulk replace +Harness.test({ + query: post.replace([{ + content: 'whoah' + }, { + content: 'hey' + } + ]), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content") VALUES ($1), ($2)', + string: 'REPLACE INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah', 'hey'] +}); + +Harness.test({ + query: post.replace([{ + content: 'whoah', + userId: 1 + }, { + content: 'hey', + userId: 2 + } + ]), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah', 1, 'hey', 2] +}); + +// consistent order +Harness.test({ + query: post.replace([{ + content: 'whoah', + userId: 1 + }, { + userId: 2, + content: 'hey' + } + ]), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['whoah', 1, 'hey', 2] +}); + +Harness.test({ + query: post.replace({}), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" DEFAULT VALUES', + string: 'REPLACE INTO "post" DEFAULT VALUES' + }, + mysql: { + text : 'REPLACE INTO `post` () VALUES ()', + string: 'REPLACE INTO `post` () VALUES ()' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning('*'), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning(post.star()), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning(post.id), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning(post.id, post.content), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace({}).returning([post.id, post.content]), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +// handle missing columns +Harness.test({ + query: post.replace([{ + content: 'whoah', + userId: 1 + }, { + content: 'hey' + } + ]), + pg: { + throws: true + }, + sqlite: { + text : 'Sqlite requires the same number of columns in each replace row', + throws: true + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', + string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', + params: ['whoah', 1, 'hey'] + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, +}); + +Harness.test({ + query: post.replace([{ + userId: 1 + }, { + content: 'hey', + userId: 2 + } + ]), + pg: { + throws: true + }, + sqlite: { + text : 'Sqlite requires the same number of columns in each replace row', + throws: true + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', + string: 'REPLACE INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, \'hey\')', + params: [1, 2, 'hey'] + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, +}); + +Harness.test({ + query: post.replace(post.content, post.userId) + .select('\'test\'', user.id).from(user).where(user.name.like('A%')), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', + string: 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post.replace([post.content, post.userId]) + .select('\'test\'', user.id).from(user).where(user.name.like('A%')), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'REPLACE INTO "post" ("content", "userId") SELECT \'test\', "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE ?)', + string: 'REPLACE INTO `post` (`content`, `userId`) SELECT \'test\', `user`.`id` FROM `user` WHERE (`user`.`name` LIKE \'A%\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post.replace(post.userId) + .select(user.id).from(user).where(user.name.like('A%')), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE $1)', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" WHERE ("user"."name" LIKE \'A%\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post.replace(post.userId) + .select(post.userId).from(user.join(post).on(user.id.equals(post.userId))).where(post.tags.like('A%')), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE $1)', + string: 'REPLACE INTO "post" ("userId") SELECT "post"."userId" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("post"."tags" LIKE \'A%\')' + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE ?)', + string: 'REPLACE INTO `post` (`userId`) SELECT `post`.`userId` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`tags` LIKE \'A%\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['A%'] +}); + +Harness.test({ + query: post.replace(post.userId).select(user.id).distinct().from(user), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT DISTINCT "user"."id" FROM "user"' + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT DISTINCT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +// Binary replaces +Harness.test({ + query: post.replace(post.content.value(new Buffer('test')), post.userId.value(2)), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [new Buffer('test'), 2] +}); + +Harness.test({ + query: post.replace({ + content: new Buffer('test'), + userId: 2 + }), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'REPLACE INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [new Buffer('test'), 2] +}); + +Harness.test({ + query: post.replace([{ + content: new Buffer('whoah') + }, { + content: new Buffer('hey') + } + ]), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("content") VALUES ($1), ($2)', + string: 'REPLACE INTO "post" ("content") VALUES (x\'77686f6168\'), (x\'686579\')' + }, + mysql: { + text : 'REPLACE INTO `post` (`content`) VALUES (?), (?)', + string: 'REPLACE INTO `post` (`content`) VALUES (x\'77686f6168\'), (x\'686579\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [new Buffer('whoah'), new Buffer('hey')] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onDuplicate({ + content: 'testupdate', + }), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + text : 'REPLACE INTO `post` (`content`, `userId`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `post`.`content` = ?', + string: 'REPLACE INTO `post` (`content`, `userId`) VALUES (\'test\', 2) ON DUPLICATE KEY UPDATE `post`.`content` = \'testupdate\'' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 'testupdate'] +}); + +Harness.test({ + query: customerAliasTable.replace({ + id : 2, + name : 'test' + }).onConflict({ + columns: ['id'], + update: ['name'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + +Harness.test({ + query: customerAliasTable.replace({ + id : 2, + name : 'test' + }).orIgnore(), + mysql: { + throws: true + }, + sqlite: { + text : 'REPLACE OR IGNORE INTO "customer" ("id", "name") VALUES ($1, $2)', + string: 'REPLACE OR IGNORE INTO "customer" ("id", "name") VALUES (2, \'test\')' + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [2, 'test'] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onConflict({ + columns: ['userId'], + update: ['content'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onConflict({ + columns: ['userId','content'], + update: ['content','userId'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onConflict({ + columns: ['userId'], + update: ['content'] + }).where(post.userId.equals(2)), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 2] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onConflict({ + constraint: 'conc_userId', + update: ['content'] + }).where(post.userId.equals(2)), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2, 2] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onConflict({ + columns: ['userId'], + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: post.replace({ + content: 'test', + userId: 2 + }).onConflict({ + constraint: 'conc_userId', + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: ['test', 2] +}); + +Harness.test({ + query: contentTable.replace({ + contentId: 20, + text : "something" + }).onConflict({ + columns: ['contentId'], + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [20, "something"] +}); + +Harness.test({ + query: contentTable.replace({ + contentId: 20, + text : "something", + contentPosts : "another thing", + }).onConflict({ + columns: ['contentId'], + update: ['contentPosts'] + }), + mysql: { + throws: true + }, + sqlite: { + throws: true + }, + pg: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [20, "something", "another thing"] +}); + +Harness.test({ + query: post.replace([]), + + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (1=2)', + string: 'SELECT `post`.* FROM `post` WHERE (1=2)' + }, + params: [] +}); + +Harness.test({ + query: arrayTable.replace(arrayTable.id.value(1), arrayTable.numbers.value([2, 3, 4])), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES (1, \'[2,3,4]\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + } +}); + +Harness.test({ + query: arrayTable.replace(arrayTable.id.value(1), arrayTable.numbers.value(["one", "two", "three"])), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "arraytest" ("id", "numbers") VALUES ($1, $2)', + string: 'REPLACE INTO "arraytest" ("id", "numbers") VALUES (1, \'["one","two","three"]\')' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + } +}); + +Harness.test({ + query: post.replace(post.userId).select(user.id).from(user), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).select(user.id).from(user).onConflict({ + columns: ['userId'], + update: ['content'] + }), + pg: { + throws: true + }, + sqlite: { + throws: true + }, + mysql: { + throws: true + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).add(user.select(user.id)), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).add(user.select(user.id).from(user)), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user"' + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); + +Harness.test({ + query: post.replace(post.userId).add(user.select(user.id).order(user.id)), + pg: { + throws: true + }, + sqlite: { + text : 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"', + string: 'REPLACE INTO "post" ("userId") SELECT "user"."id" FROM "user" ORDER BY "user"."id"' + }, + mysql: { + text : 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`', + string: 'REPLACE INTO `post` (`userId`) SELECT `user`.`id` FROM `user` ORDER BY `user`.`id`' + }, + mssql: { + throws: true + }, + oracle: { + throws: true + }, + params: [] +}); From 9173f92ea375ef86b315163ae1c2cb094ea98a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96rd=C3=B6gh=20L=C3=A1szl=C3=B3?= Date: Mon, 31 Jul 2017 16:01:10 +0200 Subject: [PATCH 234/248] Fix order method with empty array generates invalid SQL (#364) --- lib/node/query.js | 3 +++ test/dialects/order-tests.js | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/node/query.js b/lib/node/query.js index 973267bc..ebb3ecfa 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -173,6 +173,9 @@ var Query = Node.define({ order: function() { var args = getArrayOrArgsAsArray(arguments); var orderBy; + if (args.length === 0) { + return this; + } if (this._orderBy) { orderBy = this._orderBy; } else { diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 2c4803f5..a0813d8e 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -336,4 +336,30 @@ Harness.test({ string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' }, params: [] -}); \ No newline at end of file +}); + +Harness.test({ + query: post.select(post.content).order([]), + pg: { + text : 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + sqlite: { + text : 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + mysql: { + text : 'SELECT `post`.`content` FROM `post`', + string: 'SELECT `post`.`content` FROM `post`' + }, + mssql: { + text : 'SELECT [post].[content] FROM [post]', + string: 'SELECT [post].[content] FROM [post]' + }, + oracle: { + text : 'SELECT "post"."content" FROM "post"', + string: 'SELECT "post"."content" FROM "post"' + }, + params: [] +}); + From 9135b0bbfd44d5d5a326022096a83d78427598e3 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 31 Jul 2017 09:02:20 -0500 Subject: [PATCH 235/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7c9b141..36ce3057 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.76.1", + "version": "0.77.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From c7334f3e34006a8fd604eaf72f841c546db7751a Mon Sep 17 00:00:00 2001 From: hstanford <30746076+hstanford@users.noreply.github.com> Date: Sun, 6 Aug 2017 21:09:50 +0100 Subject: [PATCH 236/248] Exposes function creation to allow use of unsupported functions (#371) --- lib/functions.js | 4 ++++ lib/index.js | 1 + test/function-tests.js | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/lib/functions.js b/lib/functions.js index 4362b706..fe9cdaaf 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -13,6 +13,9 @@ var getFunctionCallCreator = function(name) { // creates a hash of functions for a sql instance var getFunctions = function(functionNames) { + if (typeof functionNames === 'string') + return getFunctionCallCreator(functionNames); + var functions = _.reduce(functionNames, function(reducer, name) { reducer[name] = getFunctionCallCreator(name); return reducer; @@ -68,4 +71,5 @@ var getStandardFunctions = function() { return getFunctions(standardFunctionNames); }; +module.exports.getFunctions = getFunctions; module.exports.getStandardFunctions = getStandardFunctions; diff --git a/lib/index.js b/lib/index.js index 3a1cdfdc..f6cf39e6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -19,6 +19,7 @@ var Sql = function(dialect, config) { // attach the standard SQL functions to this instance this.functions = functions.getStandardFunctions(); + this.function = functions.getFunctions; }; // Define a table diff --git a/test/function-tests.js b/test/function-tests.js index 77ef0087..6c53072d 100644 --- a/test/function-tests.js +++ b/test/function-tests.js @@ -84,4 +84,10 @@ suite('function', function() { assert.equal(query.text, 'SELECT (AVG((DISTINCT((COUNT("user"."id") + MAX("user"."id"))) - MIN("user"."id"))) * $1) FROM "user"'); assert.equal(query.values[0], 100); }); + + test('use custom function', function() { + var query = user.select(sql.function('PHRASE_TO_TSQUERY')('simple', user.name)).toQuery(); + assert.equal(query.text, 'SELECT PHRASE_TO_TSQUERY($1, "user"."name") FROM "user"'); + assert.equal(query.values[0], 'simple'); + }); }); From 95d775a9a10650c2de34edf23a1a859abf7744dc Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sun, 6 Aug 2017 15:10:02 -0500 Subject: [PATCH 237/248] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36ce3057..dc250c01 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.77.0", + "version": "0.78.0", "homepage": "https://github.com/brianc/node-sql", "license": "MIT", "repository": { From 6916535a96633548d5da31d8b74890ce2f087513 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 11:55:40 -0400 Subject: [PATCH 238/248] - Support for "left join lateral" in Postgres which converts to "outer apply" in Microsoft SQL Server and Oracle. --- lib/dialect/mssql.js | 10 +++++++ lib/dialect/oracle.js | 5 ++++ lib/dialect/postgres.js | 11 ++++++++ lib/node/join.js | 3 +++ lib/table.js | 4 +++ test/dialects/join-tests.js | 54 +++++++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 488f7fa2..6a19b564 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -274,6 +274,16 @@ Mssql.prototype.visitFunctionCall = function(functionCall) { return [txt]; }; +Mssql.prototype.visitJoin = function(join) { + if (join.subType !== 'LEFT LATERAL') return Mssql.super_.prototype.visitJoin.call(this, join); + var result = []; + this._visitingJoin = true; + result = result.concat(this.visit(join.from)); + result = result.concat('OUTER APPLY'); + result = result.concat(this.visit(join.to)); + return result; +}; + Mssql.prototype.visitOrderBy = function(orderBy) { var result=Mssql.super_.prototype.visitOrderBy.call(this, orderBy); var offsetNode=orderBy.msSQLOffsetNode; diff --git a/lib/dialect/oracle.js b/lib/dialect/oracle.js index 38267339..a55e7aca 100644 --- a/lib/dialect/oracle.js +++ b/lib/dialect/oracle.js @@ -278,6 +278,11 @@ Oracle.prototype.visitCase = function(caseExp) { return Mssql.prototype.visitCase.call(this, caseExp); }; +// Using same JOIN implementation as MSSQL +Oracle.prototype.visitJoin = function(joinExp) { + return Mssql.prototype.visitJoin.call(this, joinExp); +}; + Oracle.prototype.visitOnConflict = function(onConflict) { throw new Error('Oracle does not allow onConflict clause.'); }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 2816c901..87c7c9e9 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1022,6 +1022,7 @@ Postgres.prototype.visitForShare = function() { }; Postgres.prototype.visitJoin = function(join) { + if (join.subType === 'LEFT LATERAL') return this.visitLeftJoinLateral(join) var result = []; this._visitingJoin = true; result = result.concat(this.visit(join.from)); @@ -1032,6 +1033,16 @@ Postgres.prototype.visitJoin = function(join) { return result; }; +Postgres.prototype.visitLeftJoinLateral = function(join) { + var result = []; + this._visitingJoin = true; + result = result.concat(this.visit(join.from)); + result = result.concat('LEFT JOIN LATERAL'); + result = result.concat(this.visit(join.to)); + result = result.concat('ON true'); + return result; +}; + Postgres.prototype.visitLiteral = function(node) { var txt = [node.literal]; if(node.alias) { diff --git a/lib/node/join.js b/lib/node/join.js index bbc1f93a..f569997e 100644 --- a/lib/node/join.js +++ b/lib/node/join.js @@ -19,5 +19,8 @@ var JoinNode = module.exports = Node.define({ }, leftJoin: function(other) { return new JoinNode('LEFT', this, other); + }, + leftJoinLateral: function(other) { + return new JoinNode('LEFT LATERAL', this, other); } }); diff --git a/lib/table.js b/lib/table.js index 3fae2710..1408542b 100644 --- a/lib/table.js +++ b/lib/table.js @@ -237,6 +237,10 @@ Table.prototype.leftJoin = function(other) { return new JoinNode('LEFT', this.toNode(), other.toNode()); }; +Table.prototype.leftJoinLateral = function(other) { + return new JoinNode('LEFT LATERAL', this.toNode(), other.toNode()); +}; + // auto-join tables based on column intropsection Table.prototype.joinTo = function(other) { return Joiner.leftJoin(this, other); diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index abebdb01..2e0c6882 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -174,3 +174,57 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: user.select().from(user.leftJoinLateral(post.subQuery().select(post.userId))), + pg: { + text : 'SELECT "user".* FROM "user" LEFT JOIN LATERAL (SELECT "post"."userId" FROM "post") ON true', + string: 'SELECT "user".* FROM "user" LEFT JOIN LATERAL (SELECT "post"."userId" FROM "post") ON true' + }, + mssql: { + text : 'SELECT [user].* FROM [user] OUTER APPLY (SELECT [post].[userId] FROM [post])', + string: 'SELECT [user].* FROM [user] OUTER APPLY (SELECT [post].[userId] FROM [post])' + }, + oracle: { + text : 'SELECT "user".* FROM "user" OUTER APPLY (SELECT "post"."userId" FROM "post")', + string: 'SELECT "user".* FROM "user" OUTER APPLY (SELECT "post"."userId" FROM "post")' + }, + params: [] +}); + +Harness.test({ + query: user.select().from(user.leftJoinLateral(post.subQuery().select(post.userId).where(user.id.equals(post.userId)))), + pg: { + text : 'SELECT "user".* FROM "user" LEFT JOIN LATERAL (SELECT "post"."userId" FROM "post" WHERE ("user"."id" = "post"."userId")) ON true', + string: 'SELECT "user".* FROM "user" LEFT JOIN LATERAL (SELECT "post"."userId" FROM "post" WHERE ("user"."id" = "post"."userId")) ON true' + }, + mssql: { + text : 'SELECT [user].* FROM [user] OUTER APPLY (SELECT [post].[userId] FROM [post] WHERE ([user].[id] = [post].[userId]))', + string: 'SELECT [user].* FROM [user] OUTER APPLY (SELECT [post].[userId] FROM [post] WHERE ([user].[id] = [post].[userId]))' + }, + oracle: { + text : 'SELECT "user".* FROM "user" OUTER APPLY (SELECT "post"."userId" FROM "post" WHERE ("user"."id" = "post"."userId"))', + string: 'SELECT "user".* FROM "user" OUTER APPLY (SELECT "post"."userId" FROM "post" WHERE ("user"."id" = "post"."userId"))' + }, + params: [] +}); + +Harness.test({ + query: user.select().from(user + .leftJoinLateral(post.subQuery().select(post.userId)) + .leftJoinLateral(comment.subQuery().select(comment.postId))), + pg: { + text : 'SELECT "user".* FROM "user" LEFT JOIN LATERAL (SELECT "post"."userId" FROM "post") ON true LEFT JOIN LATERAL (SELECT "comment"."postId" FROM "comment") ON true', + string: 'SELECT "user".* FROM "user" LEFT JOIN LATERAL (SELECT "post"."userId" FROM "post") ON true LEFT JOIN LATERAL (SELECT "comment"."postId" FROM "comment") ON true' + }, + mssql: { + text : 'SELECT [user].* FROM [user] OUTER APPLY (SELECT [post].[userId] FROM [post]) OUTER APPLY (SELECT [comment].[postId] FROM [comment])', + string: 'SELECT [user].* FROM [user] OUTER APPLY (SELECT [post].[userId] FROM [post]) OUTER APPLY (SELECT [comment].[postId] FROM [comment])' + }, + oracle: { + text : 'SELECT "user".* FROM "user" OUTER APPLY (SELECT "post"."userId" FROM "post") OUTER APPLY (SELECT "comment"."postId" FROM "comment")', + string: 'SELECT "user".* FROM "user" OUTER APPLY (SELECT "post"."userId" FROM "post") OUTER APPLY (SELECT "comment"."postId" FROM "comment")' + }, + params: [] +}); + From ed315d24da96e5ed332a3ffcb9d82dfadc808e3e Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 12:08:55 -0400 Subject: [PATCH 239/248] - Override for Microsoft SQL Server concatenation operator. --- lib/dialect/mssql.js | 5 ++++ test/dialects/value-expression-tests.js | 34 ++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 488f7fa2..92229e06 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -48,6 +48,11 @@ Mssql.prototype.visitBinary = function(binary) { return [text]; } + if(binary.operator === '||'){ + var text = '(' + this.visit(binary.left) + ' + ' + this.visit(binary.right) + ')'; + return [text]; + } + if (!isRightSideArray(binary)){ return Mssql.super_.prototype.visitBinary.call(this, binary); } diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 5eaae5ae..d5c7fcd4 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -114,20 +114,46 @@ Harness.test({ query: post.select(post.id).where(post.content.equals(new Buffer('test'))), pg: { text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', - string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = \'\\x74657374\')', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = \'\\x74657374\')' }, sqlite: { text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', - string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = x\'74657374\')', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = x\'74657374\')' }, mysql: { text : 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = ?)', - string: 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = x\'74657374\')', + string: 'SELECT `post`.`id` FROM `post` WHERE (`post`.`content` = x\'74657374\')' }, oracle: { text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = :1)', - string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\')))', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = utl_raw.cast_to_varchar2(hextoraw(\'74657374\')))' }, params: [new Buffer('test')] }); +// concat tests +Harness.test({ + query: post.select(post.content.concat(post.tags)), + pg: { + text : 'SELECT ("post"."content" || "post"."tags") FROM "post"', + string: 'SELECT ("post"."content" || "post"."tags") FROM "post"' + }, + sqlite: { + text : 'SELECT ("post"."content" || "post"."tags") FROM "post"', + string: 'SELECT ("post"."content" || "post"."tags") FROM "post"' + }, + mysql: { + text : 'SELECT (`post`.`content` || `post`.`tags`) FROM `post`', + string: 'SELECT (`post`.`content` || `post`.`tags`) FROM `post`' + }, + mssql: { + text : 'SELECT ([post].[content] + [post].[tags]) FROM [post]', + string: 'SELECT ([post].[content] + [post].[tags]) FROM [post]' + }, + oracle: { + text : 'SELECT ("post"."content" || "post"."tags") FROM "post"', + string: 'SELECT ("post"."content" || "post"."tags") FROM "post"' + }, + params: [] +}); + From b0c1622ab53192b099db081b6bdbe58461a8d0f6 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 12:21:39 -0400 Subject: [PATCH 240/248] Tweak so that travis checks will pass --- lib/dialect/mssql.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/dialect/mssql.js b/lib/dialect/mssql.js index 92229e06..413ebd9b 100644 --- a/lib/dialect/mssql.js +++ b/lib/dialect/mssql.js @@ -49,8 +49,7 @@ Mssql.prototype.visitBinary = function(binary) { } if(binary.operator === '||'){ - var text = '(' + this.visit(binary.left) + ' + ' + this.visit(binary.right) + ')'; - return [text]; + return ['(' + this.visit(binary.left) + ' + ' + this.visit(binary.right) + ')']; } if (!isRightSideArray(binary)){ From 44f281f02ccda77b0a883fcc3a3c44c912f7f50d Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 12:23:21 -0400 Subject: [PATCH 241/248] Added missing semicolon. --- lib/dialect/postgres.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 87c7c9e9..9b81af25 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1022,7 +1022,7 @@ Postgres.prototype.visitForShare = function() { }; Postgres.prototype.visitJoin = function(join) { - if (join.subType === 'LEFT LATERAL') return this.visitLeftJoinLateral(join) + if (join.subType === 'LEFT LATERAL') return this.visitLeftJoinLateral(join); var result = []; this._visitingJoin = true; result = result.concat(this.visit(join.from)); From 845e4cc2986041c5c3459975e345701e0e65c692 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 12:31:01 -0400 Subject: [PATCH 242/248] - Update ".travis.yml" to allow failures on Node 0.10 and 0.11 since the mocha library is doing stuff that isn't allowed. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index f04dabe6..07becfb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,8 @@ node_js: - "4.2" - "0.10" - "0.11" + +matrix: + allow_failures: + - node_js: "0.10" + - node_js: "0.11" \ No newline at end of file From 8e5a36ba8691659e4820ff8ee31b2c0507f548cf Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 12:33:59 -0400 Subject: [PATCH 243/248] - Update ".travis.yml" to allow failures on Node 0.10 and 0.11 since the mocha library is doing stuff that isn't allowed. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index f04dabe6..07becfb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,8 @@ node_js: - "4.2" - "0.10" - "0.11" + +matrix: + allow_failures: + - node_js: "0.10" + - node_js: "0.11" \ No newline at end of file From 761469e033d35eefc1c97292be1b0bf58d61c317 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 13:27:58 -0400 Subject: [PATCH 244/248] Top-Level SubQuery support. --- lib/index.js | 12 ++++++++++++ test/dialects/subquery-tests.js | 26 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/lib/index.js b/lib/index.js index f6cf39e6..8e3d7cfa 100644 --- a/lib/index.js +++ b/lib/index.js @@ -52,6 +52,18 @@ Sql.prototype.select = function() { return query; }; +// Returns a subQuery clause +Sql.prototype.subQuery = function(alias) { + // create the query and pass it off + var query = new Query(this); + query.type = 'SUBQUERY'; + query.alias = alias; + query.join = function(other) { + return new JoinNode('INNER', this.toNode(), other.toNode(), other); + }; + return query; +}; + // Returns an interval clause Sql.prototype.interval = function() { var interval = new Interval(sliced(arguments)); diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index fe5b2aad..7d977b43 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -219,3 +219,29 @@ Harness.test({ params: [] }); +// Top-level subQuery +Harness.test({ + query: Sql.subQuery().select(user.id).from(user), + pg: { + text : '(SELECT "user"."id" FROM "user")', + string: '(SELECT "user"."id" FROM "user")' + }, + sqlite: { + text : '(SELECT "user"."id" FROM "user")', + string: '(SELECT "user"."id" FROM "user")' + }, + mysql: { + text : '(SELECT `user`.`id` FROM `user`)', + string: '(SELECT `user`.`id` FROM `user`)' + }, + mssql: { + text : '(SELECT [user].[id] FROM [user])', + string: '(SELECT [user].[id] FROM [user])' + }, + oracle: { + text : '(SELECT "user"."id" FROM "user")', + string: '(SELECT "user"."id" FROM "user")' + }, + params: [] +}); + From c5c2e666acd8401a6c91a4a6c93704a4aaa4b954 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 13:30:38 -0400 Subject: [PATCH 245/248] Added test for aliased top-level subQuery --- test/dialects/subquery-tests.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 7d977b43..05d76f1f 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -245,3 +245,29 @@ Harness.test({ params: [] }); +// Top-level subQuery with alias +Harness.test({ + query: Sql.subQuery("x").select(user.id).from(user), + pg: { + text : '(SELECT "user"."id" FROM "user") "x"', + string: '(SELECT "user"."id" FROM "user") "x"' + }, + sqlite: { + text : '(SELECT "user"."id" FROM "user") "x"', + string: '(SELECT "user"."id" FROM "user") "x"' + }, + mysql: { + text : '(SELECT `user`.`id` FROM `user`) `x`', + string: '(SELECT `user`.`id` FROM `user`) `x`' + }, + mssql: { + text : '(SELECT [user].[id] FROM [user]) [x]', + string: '(SELECT [user].[id] FROM [user]) [x]' + }, + oracle: { + text : '(SELECT "user"."id" FROM "user") "x"', + string: '(SELECT "user"."id" FROM "user") "x"' + }, + params: [] +}); + From e8f45252690249c532efd0e7b77f57a8a6553cf7 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 13:37:09 -0400 Subject: [PATCH 246/248] Added missing require. --- lib/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 8e3d7cfa..f26ad827 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,12 @@ 'use strict'; var _ = require('lodash'); -var Column = require("./column"); +var Column = require("./column"); var FunctionCall = require('./node/functionCall'); var ArrayCall = require('./node/arrayCall'); var functions = require('./functions'); var getDialect = require('./dialect'); +var JoinNode = require('./node/join'); var Query = require('./node/query'); var sliced = require('sliced'); var Table = require('./table'); From 3b8de4721b2404f4dd9a904be2af722c95588a68 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 9 Jun 2018 13:37:49 -0400 Subject: [PATCH 247/248] Update ".travis.yml" to allow failures on Node 0.10 and 0.11 since the mocha library is doing stuff that isn't allowed. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index f04dabe6..07becfb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,8 @@ node_js: - "4.2" - "0.10" - "0.11" + +matrix: + allow_failures: + - node_js: "0.10" + - node_js: "0.11" \ No newline at end of file From cc15b6720feefda627340838b986852546836130 Mon Sep 17 00:00:00 2001 From: 3n-mb <3n-mb@users.noreply.github.com> Date: Sat, 24 Aug 2024 16:44:34 -0400 Subject: [PATCH 248/248] Type change to allow typescript > 2.7.2 (#421) Typescript versions greater than 2.7.2, `keyof` produces `string|number|symbol`, failing on line 40. One fix is have on lines 19 and 22 `Name extends string|number|symbol` instead of `Name extends string`. But this work around may feel a bit not intuitive. Change directly on line 40, `&` with `string` does the trick of fitting types. --- lib/types.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/types.d.ts b/lib/types.d.ts index 84fb7ab3..a7011f99 100644 --- a/lib/types.d.ts +++ b/lib/types.d.ts @@ -37,7 +37,7 @@ declare module "sql" { interface TableDefinition { name: Name; schema: string; - columns: {[CName in keyof Row]: ColumnDefinition}; + columns: {[CName in ((keyof Row) & string)]: ColumnDefinition}; dialect?: SQLDialects; isTemporary?: boolean; foreignKeys?: {