From d3af81674827b87dd589df43e47f2f5ea622e2d4 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 6 Feb 2013 15:22:04 -0800 Subject: [PATCH 001/507] Added support for passing an object to .where() --- lib/dialect/postgres.js | 6 +++++- lib/node/query.js | 17 +++++++++++++++++ test/postgres/table-tests.js | 5 +++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4059232d..80f6d16a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1,4 +1,5 @@ var util = require('util'); +var assert = require('assert'); var From = require(__dirname + '/../node/from'); var Parameter = require(__dirname + '/../node/parameter'); var Postgres = function() { @@ -263,8 +264,11 @@ Postgres.prototype.visitColumn = function(columnNode) { else if(inSelectClause && columnNode.alias) { txt += ' as ' + this.quote(columnNode.alias); } - if(this._visitingCreate || this._visitingAddColumn) + if(this._visitingCreate || this._visitingAddColumn) { + assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + + ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); txt += ' ' + columnNode.dataType; + } return txt; } diff --git a/lib/node/query.js b/lib/node/query.js index aed65f3f..4c971a2b 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -16,6 +16,7 @@ var DropColumn = require(__dirname + '/dropColumn'); var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); +var Column = require(__dirname + '/../column'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -44,12 +45,28 @@ var Query = Node.define({ return this.add(from); }, where: function(node) { + if (!node.toNode && typeof node == 'object') + node = this._whereObject(node); + //calling #where twice functions like calling #where & then #and if(this.whereClause) return this.and(node); this.whereClause = new Where(); this.whereClause.add(node); return this.add(this.whereClause); }, + _whereObject: function(node) { + var result; + for (var colName in node) { + var column = new Column({name: colName, table: this.table}); + var query = column.equals(node[colName]); + + if (!result) + result = query; + else + result.and(query); + } + return result; + }, or: function(node) { this.whereClause.or(node); return this; diff --git a/test/postgres/table-tests.js b/test/postgres/table-tests.js index aa4c273c..2e9f7141 100644 --- a/test/postgres/table-tests.js +++ b/test/postgres/table-tests.js @@ -91,3 +91,8 @@ Harness.test({ query : user.select('name').from('user').where('name <> NULL'), pg : 'SELECT name FROM user WHERE name <> NULL' }); + +Harness.test({ + query : user.select('name').from('user').where({name: 'brian'}), + pg : 'SELECT name FROM user WHERE ("user"."name" = $1)' +}); \ No newline at end of file From 90a8516040528ab186a3a6badfe2332482fe39a6 Mon Sep 17 00:00:00 2001 From: benracine Date: Thu, 7 Feb 2013 15:02:09 -0800 Subject: [PATCH 002/507] add rename column functionality --- lib/dialect/postgres.js | 5 +++++ lib/node/query.js | 21 +++++++++++++++++++- lib/node/renameColumn.js | 5 +++++ test/postgres/alter-table-tests.js | 31 +++++++++++++++++++++++++++++- 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 lib/node/renameColumn.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4059232d..1f81aa79 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -40,6 +40,7 @@ Postgres.prototype.visit = function(node) { case 'IF NOT EXISTS': return this.visitIfNotExists(); case 'ADD COLUMN': return this.visitAddColumn(node); case 'DROP COLUMN': return this.visitDropColumn(node); + case 'RENAME COLUMN': return this.visitRenameColumn(node); case 'LIMIT': case 'OFFSET': return this.visitModifier(node); @@ -290,6 +291,10 @@ Postgres.prototype.visitDropColumn = function(dropColumn) { return ['DROP COLUMN ' + this.visit(dropColumn.nodes[0])]; } +Postgres.prototype.visitRenameColumn = function(renameColumn) { + return ['RENAME COLUMN ' + this.visit(renameColumn.nodes[0]) + ' TO ' + this.visit(renameColumn.nodes[1])]; +} + Postgres.prototype.visitIfExists = function() { return ['IF EXISTS']; } diff --git a/lib/node/query.js b/lib/node/query.js index aed65f3f..5923f9fe 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -13,6 +13,8 @@ var Drop = require(__dirname + '/drop'); var Alter = require(__dirname + '/alter'); var AddColumn = require(__dirname + '/addColumn'); var DropColumn = require(__dirname + '/dropColumn'); +var RenameColumn = require(__dirname + '/renameColumn'); +var Column = require(__dirname + '/../column'); var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); @@ -131,18 +133,35 @@ var Query = Node.define({ alter: function() { return this.add(new Alter()); }, - addColumn: function(column) { + addColumn: function(column, dataType) { var addClause = new AddColumn(); + if (!column.toNode) + column = new Column({name: column, table: this.table}); + if (dataType) + column.dataType = dataType; addClause.add(column.toNode()); this.nodes[0].add(addClause); return this; }, dropColumn: function(column) { var dropClause = new DropColumn(); + if (!column.toNode) + column = new Column({name: column, table: this.table}); dropClause.add(column.toNode()); this.nodes[0].add(dropClause); return this; }, + renameColumn: function(oldColumn, newColumn) { + var renameClause = new RenameColumn(); + if (!oldColumn.toNode) + oldColumn = new Column({name: oldColumn, table: this.table}); + if (!newColumn.toNode) + newColumn = new Column({name: newColumn, table: this.table}); + renameClause.add(oldColumn.toNode()); + renameClause.add(newColumn.toNode()); + this.nodes[0].add(renameClause); + return this; + }, limit: function(count) { return this.add(new Modifier(this, 'LIMIT', count)); }, diff --git a/lib/node/renameColumn.js b/lib/node/renameColumn.js new file mode 100644 index 00000000..8cf6e3ed --- /dev/null +++ b/lib/node/renameColumn.js @@ -0,0 +1,5 @@ +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'RENAME COLUMN' +}); diff --git a/test/postgres/alter-table-tests.js b/test/postgres/alter-table-tests.js index 9471e20d..68a03f7c 100644 --- a/test/postgres/alter-table-tests.js +++ b/test/postgres/alter-table-tests.js @@ -14,6 +14,11 @@ Harness.test({ params: [] }); +Harness.test({ + query : post.alter().dropColumn('content').dropColumn('userId'), + pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + params: [] +}); var group = Table.define({ name: 'group', @@ -36,4 +41,28 @@ Harness.test({ query : group.alter().addColumn(group.id).addColumn(group.userId), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', params: [] -}); \ No newline at end of file +}); + +Harness.test({ + query : group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), + pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + params: [] +}); + +Harness.test({ + query : group.alter().renameColumn('userId', 'newUserId'), + pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + params: [] +}); + +Harness.test({ + query : group.alter().renameColumn(group.userId, 'newUserId'), + pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + params: [] +}); + +Harness.test({ + query : group.alter().renameColumn('userId', group.id), + pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + params: [] +}); From e83e49164e024c5a7824b386e9bf47368511e094 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 6 Feb 2013 15:22:04 -0800 Subject: [PATCH 003/507] Added support for passing an object to .where() --- lib/dialect/postgres.js | 6 +++++- lib/node/query.js | 17 +++++++++++++++++ test/postgres/table-tests.js | 5 +++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4059232d..80f6d16a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1,4 +1,5 @@ var util = require('util'); +var assert = require('assert'); var From = require(__dirname + '/../node/from'); var Parameter = require(__dirname + '/../node/parameter'); var Postgres = function() { @@ -263,8 +264,11 @@ Postgres.prototype.visitColumn = function(columnNode) { else if(inSelectClause && columnNode.alias) { txt += ' as ' + this.quote(columnNode.alias); } - if(this._visitingCreate || this._visitingAddColumn) + if(this._visitingCreate || this._visitingAddColumn) { + assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + + ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); txt += ' ' + columnNode.dataType; + } return txt; } diff --git a/lib/node/query.js b/lib/node/query.js index aed65f3f..4c971a2b 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -16,6 +16,7 @@ var DropColumn = require(__dirname + '/dropColumn'); var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); +var Column = require(__dirname + '/../column'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -44,12 +45,28 @@ var Query = Node.define({ return this.add(from); }, where: function(node) { + if (!node.toNode && typeof node == 'object') + node = this._whereObject(node); + //calling #where twice functions like calling #where & then #and if(this.whereClause) return this.and(node); this.whereClause = new Where(); this.whereClause.add(node); return this.add(this.whereClause); }, + _whereObject: function(node) { + var result; + for (var colName in node) { + var column = new Column({name: colName, table: this.table}); + var query = column.equals(node[colName]); + + if (!result) + result = query; + else + result.and(query); + } + return result; + }, or: function(node) { this.whereClause.or(node); return this; diff --git a/test/postgres/table-tests.js b/test/postgres/table-tests.js index aa4c273c..2e9f7141 100644 --- a/test/postgres/table-tests.js +++ b/test/postgres/table-tests.js @@ -91,3 +91,8 @@ Harness.test({ query : user.select('name').from('user').where('name <> NULL'), pg : 'SELECT name FROM user WHERE name <> NULL' }); + +Harness.test({ + query : user.select('name').from('user').where({name: 'brian'}), + pg : 'SELECT name FROM user WHERE ("user"."name" = $1)' +}); \ No newline at end of file From 2ca7c423a1d5ef4f812ac1b6e14fa05ccd05e102 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Thu, 14 Feb 2013 12:28:52 -0800 Subject: [PATCH 004/507] Fixed update() so it would prefix ambiguous source columns --- lib/dialect/postgres.js | 10 +++++----- test/postgres/update-tests.js | 8 +++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a63390cf..7c2ee926 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -84,13 +84,14 @@ Postgres.prototype.visitInsert = function(insert) { } Postgres.prototype.visitUpdate = function(update) { - //don't prefix columns with table names - this._visitingUpdate = true; //don't auto-generate from clause this._visitedFrom = true; var params = []; for(var i = 0, node; node = update.nodes[i]; i++) { - params = params.concat(this.visit(node) + ' = ' + this.visit(node.value)); + this._visitingUpdateTargetColumn = true; + var target_col = this.visit(node); + this._visitingUpdateTargetColumn = false; + params = params.concat(target_col + ' = ' + this.visit(node.value)); } var result = [ 'UPDATE', @@ -98,7 +99,6 @@ Postgres.prototype.visitUpdate = function(update) { 'SET', params.join(', ') ]; - this._visitingUpdate = false; return result; } @@ -245,7 +245,7 @@ Postgres.prototype.visitColumn = function(columnNode) { if(inSelectClause && columnNode.asArray) { txt += 'array_agg('; } - if(!this._visitedInsert && !this._visitingUpdate && !this._visitingCreate && !this._visitingAlter) { + if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { if(table.alias) { txt = table.alias; } else { diff --git a/test/postgres/update-tests.js b/test/postgres/update-tests.js index 2df80389..334b2b8a 100644 --- a/test/postgres/update-tests.js +++ b/test/postgres/update-tests.js @@ -28,7 +28,13 @@ Harness.test({ Harness.test({ query : post.update({content: user.name}).from(user).where(post.userId.equals(user.id)), - pg : 'UPDATE "post" SET "content" = "name" FROM "user" WHERE ("post"."userId" = "user"."id")', + pg : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', params: [] }); +// update() needs to prefix ambiguous source columns; prefixing target columns is not allowed +Harness.test({ + query : post.update({userId: user.id}).from(user).where(post.userId.equals(user.id)), + pg : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + params: [] +}); \ No newline at end of file From 78a8cdda1327be6a708d6a6a6375bdbd31ab8562 Mon Sep 17 00:00:00 2001 From: bmc Date: Mon, 18 Feb 2013 09:24:44 -0600 Subject: [PATCH 005/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e61cb7f6..e4c62798 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.2.1", + "version": "0.2.2", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 318037be4d95641dea2114414b38e4e6491e8c5e Mon Sep 17 00:00:00 2001 From: Julian Lannigan Date: Wed, 20 Feb 2013 03:27:35 -0500 Subject: [PATCH 006/507] added the aggregate COUNT function small README.md update --- README.md | 8 ++++---- lib/column.js | 8 ++++++++ lib/dialect/postgres.js | 21 +++++++++++++------- lib/node/column.js | 6 ++++++ lib/table.js | 6 ++++++ test/postgres/aggregate-tests.js | 33 ++++++++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 test/postgres/aggregate-tests.js diff --git a/README.md b/README.md index e11f351d..0a55620e 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ var query = user ).or( user.name.equals('bang').and(user.id.equals(2)) ).toQuery(); - + //query is parameterized by default console.log(query.text); //SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4))) @@ -49,11 +49,11 @@ console.log(query.values); //['boom', 1, 'bang', 2] //how about a join? var query = user.select(user.name, post.content) .from(user.join(post).on(user.id.equals(post.userId))).toQuery(); - + console.log(query.text); //'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' ``` -There are a __lot__ more examples under `test/dialect-tests.js` +There are a __lot__ more examples included in the `test` folder. ## contributing @@ -75,7 +75,7 @@ Once the tests are passing, modify as you see fit. _Please_ make sure you write __As long as your pull request doesn't have completely off-the-wall changes and it does have tests I will almost always merge it right away and push it to npm__ -If you think your changes are too off-the-wall, open an issue or a pull-request without code so we can discuss them. +If you think your changes are too off-the-wall, open an issue or a pull-request without code so we can discuss them. __Seriously:__ diff --git a/lib/column.js b/lib/column.js index 5fa3e19e..99c37de6 100644 --- a/lib/column.js +++ b/lib/column.js @@ -6,6 +6,7 @@ var TextNode = require(__dirname + '/node/text'); var Column = function(config) { this.table = config.table; this.name = config.name; + this.star = config.star; this.asc = this.ascending = this; this.alias = null; this.desc = this.descending = new BinaryNode({ @@ -78,6 +79,13 @@ Column.prototype.arrayAgg = function(alias) { return new ColumnNode(context); } +Column.prototype.count = function(alias) { + var context = contextify(this); + context.aggCount = true; + context.alias = alias || context.name + '_count'; + return new ColumnNode(context); +} + binaryMethod('equals', '='); binaryMethod('equal', '='); binaryMethod('notEqual', '<>'); diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7c2ee926..7a79ead3 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -113,7 +113,7 @@ Postgres.prototype.visitCreate = function(create) { this._visitedFrom = true; var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); - + var result = ['CREATE TABLE']; result = result.concat(create.nodes.map(this.visit.bind(this))); result.push(this.visit(table.toNode())); @@ -242,8 +242,12 @@ Postgres.prototype.visitColumn = function(columnNode) { var table = columnNode.table; var inSelectClause = !this._selectOrDeleteEndIndex; var txt = ""; - if(inSelectClause && columnNode.asArray) { - txt += 'array_agg('; + if(inSelectClause) { + if (columnNode.asArray) { + txt += 'array_agg('; + } else if (columnNode.aggCount) { + txt += 'COUNT('; + } } if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { if(table.alias) { @@ -257,12 +261,15 @@ Postgres.prototype.visitColumn = function(columnNode) { } txt += '.'; } - txt += this.quote(columnNode.name); - if(inSelectClause && columnNode.asArray) { + if (columnNode.star) { + txt += '*'; + } else { + txt += this.quote(columnNode.name); + } + if(inSelectClause && (columnNode.asArray || columnNode.aggCount)) { txt += ')'; - txt += ' as ' + this.quote(columnNode.alias); } - else if(inSelectClause && columnNode.alias) { + if(inSelectClause && columnNode.alias) { txt += ' as ' + this.quote(columnNode.alias); } if(this._visitingCreate || this._visitingAddColumn) { diff --git a/lib/node/column.js b/lib/node/column.js index fa3f644b..8cf484d0 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -5,9 +5,15 @@ module.exports = Node.define({ constructor: function(config) { this.name = config.name; this.alias = config.alias; + this.star = config.star; this.asArray = config.asArray; + this.aggCount = config.aggCount; this.table = config.table; this.value = config.getValue(); this.dataType = config.dataType; + }, + as: function(alias) { + this.alias = alias; + return this; } }); diff --git a/lib/table.js b/lib/table.js index c0bc4937..f9b89b76 100644 --- a/lib/table.js +++ b/lib/table.js @@ -48,6 +48,12 @@ Table.prototype.star = function() { return new TextNode('"'+name+'".*'); } +Table.prototype.count = function(alias) { + var name = this.alias || this._name, + col = new Column({table: this, star: true}); + return col.count(alias || name + '_count'); //ColumnNode +} + Table.prototype.select = function() { //create the query and pass it off var query = new Query(this); diff --git a/test/postgres/aggregate-tests.js b/test/postgres/aggregate-tests.js new file mode 100644 index 00000000..6cf4b534 --- /dev/null +++ b/test/postgres/aggregate-tests.js @@ -0,0 +1,33 @@ +var Harness = require('./support'); +var user = Harness.defineUserTable(); +var post = Harness.definePostTable(); + +Harness.test({ + query : post.select(post.count()), + pg : 'SELECT COUNT("post".*) as "post_count" FROM "post"' +}); + +Harness.test({ + query : post.select(post.count('post_count')), + pg : 'SELECT COUNT("post".*) as "post_count" FROM "post"' +}); + +Harness.test({ + query : post.select(post.count().as('post_amount')), + pg : 'SELECT COUNT("post".*) as "post_amount" FROM "post"' +}); + +Harness.test({ + query : post.select(post.content.count()), + pg : 'SELECT COUNT("post"."content") as "content_count" FROM "post"' +}); + +Harness.test({ + query : post.select(post.content.count('content_count')), + pg : 'SELECT COUNT("post"."content") as "content_count" FROM "post"' +}); + +Harness.test({ + query : post.select(post.content.count().as('content_count')), + pg : 'SELECT COUNT("post"."content") as "content_count" FROM "post"' +}); From 66d100adbea8e73605f3c9b0628e616d581af822 Mon Sep 17 00:00:00 2001 From: bmc Date: Wed, 20 Feb 2013 11:30:57 -0600 Subject: [PATCH 007/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e4c62798..7aa322c2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.2.2", + "version": "0.2.3", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 479f28d107119e8771d376ed8eb9df768babaabc Mon Sep 17 00:00:00 2001 From: Brian C Date: Thu, 21 Feb 2013 15:09:45 -0600 Subject: [PATCH 008/507] Update README.md remove bad jokes from readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a55620e..7e859698 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # node-sql _sql string builder for node_ -Let's be honest - hand generating SQL is no fun, especially in a language which has clumsy support for multi-line strings. +Building SQL statements by hand is no fun, especially in a language which has clumsy support for multi-line strings. -But SQL is so good. We need SQL. So let's save the day and generate it with a jQuery-esque fluent interface. +So let's build it with JavaScript. -Maybe it's still not fun, but at least it's _less not fun_. That's at least worth a participation award. +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) From 12fb2dcb884bf6a9fb3a6a6c73b26256e1550b0c Mon Sep 17 00:00:00 2001 From: Eric Sessoms Date: Mon, 25 Feb 2013 13:29:31 -0500 Subject: [PATCH 009/507] should be able to chain leftJoin --- lib/node/join.js | 3 +++ test/postgres/join-tests.js | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/node/join.js b/lib/node/join.js index b4752154..94447a09 100644 --- a/lib/node/join.js +++ b/lib/node/join.js @@ -11,5 +11,8 @@ var JoinNode = module.exports = require(__dirname).define({ }, join: function(other) { return new JoinNode('INNER', this, other); + }, + leftJoin: function(other) { + return new JoinNode('LEFT', this, other); } }); diff --git a/test/postgres/join-tests.js b/test/postgres/join-tests.js index 48fb2ba1..5efb9f06 100644 --- a/test/postgres/join-tests.js +++ b/test/postgres/join-tests.js @@ -25,6 +25,18 @@ Harness.test({ pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' }); +Harness.test({ + query : user + .select(user.name, post.content) + .from( + user + .leftJoin(post).on(user.id.equals(post.userId)) + .leftJoin(comment).on(post.id.equals(comment.postId)) + ), + pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + + ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' +}); + Harness.test({ query : user .select(user.name, post.content) From ce775dc37fa9633db4e5b9bdee4e7a89033113a4 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 25 Feb 2013 14:12:59 -0600 Subject: [PATCH 010/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7aa322c2..4a59b3a0 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.2.3", + "version": "0.2.4", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From dc1987bdc8af87b9cc65b993f922df78cc70c7db Mon Sep 17 00:00:00 2001 From: Eric Sessoms Date: Sat, 2 Mar 2013 10:00:28 -0500 Subject: [PATCH 011/507] lints cleanly --- .jshintrc | 3 ++ Makefile | 7 +++ lib/column.js | 22 ++++---- lib/dialect/postgres.js | 71 +++++++++++++------------ lib/index.js | 2 + lib/node/addColumn.js | 2 + lib/node/alter.js | 2 + lib/node/binary.js | 4 +- lib/node/column.js | 2 + lib/node/create.js | 2 + lib/node/default.js | 2 + lib/node/delete.js | 2 + lib/node/drop.js | 2 + lib/node/dropColumn.js | 2 + lib/node/from.js | 2 + lib/node/groupBy.js | 2 + lib/node/ifExists.js | 2 + lib/node/ifNotExists.js | 2 + lib/node/index.js | 21 ++++---- lib/node/insert.js | 2 + lib/node/join.js | 2 + lib/node/orderBy.js | 2 + lib/node/parameter.js | 2 + lib/node/query.js | 15 +++--- lib/node/renameColumn.js | 2 + lib/node/returning.js | 2 + lib/node/select.js | 2 + lib/node/table.js | 4 +- lib/node/text.js | 2 + lib/node/unary.js | 4 +- lib/node/update.js | 2 + lib/node/where.js | 2 + lib/table.js | 52 +++++++++--------- test/binary-clause-tests.js | 6 ++- test/clause-definition.js | 6 ++- test/index-tests.js | 6 ++- test/index.js | 3 ++ test/postgres/aggregate-tests.js | 2 + test/postgres/alter-table-tests.js | 2 + test/postgres/create-table-tests.js | 2 + test/postgres/delete-tests.js | 4 +- test/postgres/drop-table-tests.js | 2 + test/postgres/group-by-tests.js | 2 + test/postgres/index.js | 1 + test/postgres/insert-tests.js | 2 + test/postgres/join-tests.js | 2 + test/postgres/limit-and-offset-tests.js | 2 + test/postgres/namespace-tests.js | 4 +- test/postgres/order-tests.js | 2 + test/postgres/schema-tests.js | 2 + test/postgres/shortcut-tests.js | 2 + test/postgres/support.js | 2 + test/postgres/table-tests.js | 8 +-- test/postgres/update-tests.js | 2 + test/select-tests.js | 2 + test/table-tests.js | 10 ++-- 56 files changed, 222 insertions(+), 103 deletions(-) create mode 100644 .jshintrc create mode 100644 Makefile diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..c1f2978b --- /dev/null +++ b/.jshintrc @@ -0,0 +1,3 @@ +{ + "node": true +} diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..3013fff4 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +.PHONY: jshint test + +jshint: + jshint lib test + +test: + npm test diff --git a/lib/column.js b/lib/column.js index 99c37de6..4e26099d 100644 --- a/lib/column.js +++ b/lib/column.js @@ -1,3 +1,5 @@ +'use strict'; + var ColumnNode = require(__dirname + '/node/column'); var ParameterNode = require(__dirname + '/node/parameter'); var BinaryNode = require(__dirname + '/node/binary'); @@ -41,50 +43,50 @@ var unaryMethod = function(name, operator) { left: this.toNode(), operator: operator }); - } -} + }; +}; var contextify = function(base) { var context = Object.create(Column.prototype); Object.keys(base).forEach(function (key) { context[key] = base[key]; - }) + }); return context; -} +}; Column.prototype.value = function(value) { this._value = value; return this; -} +}; Column.prototype.getValue = function() { return this._value; -} +}; Column.prototype.toNode = function() { //creates a query node from this column return new ColumnNode(contextify(this)); -} +}; Column.prototype.as = function(alias) { var context = contextify(this); context.alias = alias; return new ColumnNode(context); -} +}; Column.prototype.arrayAgg = function(alias) { var context = contextify(this); context.asArray = true; context.alias = alias || context.name + 's'; return new ColumnNode(context); -} +}; Column.prototype.count = function(alias) { var context = contextify(this); context.aggCount = true; context.alias = alias || context.name + '_count'; return new ColumnNode(context); -} +}; binaryMethod('equals', '='); binaryMethod('equal', '='); diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7a79ead3..4cc763fe 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1,3 +1,5 @@ +'use strict'; + var util = require('util'); var assert = require('assert'); var From = require(__dirname + '/../node/from'); @@ -5,12 +7,12 @@ var Parameter = require(__dirname + '/../node/parameter'); var Postgres = function() { this.output = []; this.params = []; -} +}; Postgres.prototype.getQuery = function(queryNode) { this.visitQuery(queryNode); return { text: this.output.join(' '), values: this.params }; -} +}; Postgres.prototype.visit = function(node) { @@ -47,17 +49,17 @@ Postgres.prototype.visit = function(node) { return this.visitModifier(node); default: throw new Error("Unrecognized node type " + node.type); } -} +}; Postgres.prototype.quote = function(word) { return '"' + word + '"'; -} +}; Postgres.prototype.visitSelect = function(select) { var result = ['SELECT', select.nodes.map(this.visit.bind(this)).join(', ')]; this._selectOrDeleteEndIndex = this.output.length + result.length; return result; -} +}; Postgres.prototype.visitInsert = function(insert) { var self = this; @@ -81,12 +83,13 @@ Postgres.prototype.visitInsert = function(insert) { 'VALUES', paramNodes ]; return result; -} +}; Postgres.prototype.visitUpdate = function(update) { //don't auto-generate from clause this._visitedFrom = true; var params = []; + /*jshint boss: true */ for(var i = 0, node; node = update.nodes[i]; i++) { this._visitingUpdateTargetColumn = true; var target_col = this.visit(node); @@ -100,12 +103,12 @@ Postgres.prototype.visitUpdate = function(update) { params.join(', ') ]; return result; -} +}; Postgres.prototype.visitDelete = function() { this._selectOrDeleteEndIndex = 1; return ['DELETE']; -} +}; Postgres.prototype.visitCreate = function(create) { this._visitingCreate = true; @@ -120,7 +123,7 @@ Postgres.prototype.visitCreate = function(create) { result.push('(' + col_nodes.map(this.visit.bind(this)).join(', ') + ')'); this._visitingCreate = false; return result; -} +}; Postgres.prototype.visitDrop = function(drop) { //don't auto-generate from clause @@ -129,7 +132,7 @@ Postgres.prototype.visitDrop = function(drop) { result = result.concat(drop.nodes.map(this.visit.bind(this))); result.push(this.visit(this._queryNode.table.toNode())); return result; -} +}; Postgres.prototype.visitAlter = function(alter) { this._visitingAlter = true; @@ -144,7 +147,7 @@ Postgres.prototype.visitAlter = function(alter) { ]; this._visitingAlter = false; return result; -} +}; Postgres.prototype.visitFrom = function(from) { this._visitedFrom = true; @@ -154,22 +157,22 @@ Postgres.prototype.visitFrom = function(from) { result = result.concat(this.visit(from.nodes[i])); } return result; -} +}; Postgres.prototype.visitWhere = function(where) { - var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')] + var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')]; return result; -} +}; Postgres.prototype.visitOrderBy = function(orderBy) { var result = ['ORDER BY', orderBy.nodes.map(this.visit.bind(this)).join(', ')]; return result; -} +}; Postgres.prototype.visitGroupBy = function(groupBy) { var result = ['GROUP BY', groupBy.nodes.map(this.visit.bind(this)).join(', ')]; return result; -} +}; Postgres.prototype.visitBinary = function(binary) { var self = this; @@ -184,11 +187,11 @@ Postgres.prototype.visitBinary = function(binary) { } result += ')'; return result; -} +}; Postgres.prototype.visitUnary = function(unary) { return '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; -} +}; Postgres.prototype.visitQuery = function(queryNode) { this._queryNode = queryNode; @@ -204,7 +207,7 @@ Postgres.prototype.visitQuery = function(queryNode) { this.output = select.concat(from).concat(rest); } return this; -} +}; Postgres.prototype.visitSubquery = function(queryNode) { var result = []; @@ -222,21 +225,21 @@ Postgres.prototype.visitSubquery = function(queryNode) { result[0] = '('+result[0]; result[result.length-1] = result[result.length-1] + ') ' + queryNode.alias; return result; -} +}; Postgres.prototype.visitTable = function(tableNode) { var table = tableNode.table; var txt=""; if(table.getSchema()) { txt = this.quote(table.getSchema()); - txt += '.' + txt += '.'; } txt += this.quote(table.getName()); if(table.alias) { txt += ' AS ' + table.alias; } return txt; -} +}; Postgres.prototype.visitColumn = function(columnNode) { var table = columnNode.table; @@ -278,41 +281,41 @@ Postgres.prototype.visitColumn = function(columnNode) { txt += ' ' + columnNode.dataType; } return txt; -} +}; Postgres.prototype.visitParameter = function(parameter) { this.params.push(parameter.value()); return "$"+this.params.length; -} +}; Postgres.prototype.visitDefault = function(parameter) { var params = this.params; this.params.push('DEFAULT'); return "$"+params.length; -} +}; Postgres.prototype.visitAddColumn = function(addColumn) { this._visitingAddColumn = true; - var result = ['ADD COLUMN ' + this.visit(addColumn.nodes[0])] + var result = ['ADD COLUMN ' + this.visit(addColumn.nodes[0])]; this._visitingAddColumn = false; return result; -} +}; Postgres.prototype.visitDropColumn = function(dropColumn) { return ['DROP COLUMN ' + this.visit(dropColumn.nodes[0])]; -} +}; Postgres.prototype.visitRenameColumn = function(renameColumn) { return ['RENAME COLUMN ' + this.visit(renameColumn.nodes[0]) + ' TO ' + this.visit(renameColumn.nodes[1])]; -} +}; Postgres.prototype.visitIfExists = function() { return ['IF EXISTS']; -} +}; Postgres.prototype.visitIfNotExists = function() { return ['IF NOT EXISTS']; -} +}; Postgres.prototype.visitJoin = function(join) { var result = []; @@ -322,14 +325,14 @@ Postgres.prototype.visitJoin = function(join) { result = result.concat('ON'); result = result.concat(this.visit(join.on)); return result; -} +}; Postgres.prototype.visitReturning = function(returning) { return ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; -} +}; Postgres.prototype.visitModifier = function(node) { return [node.type, node.count]; -} +}; module.exports = Postgres; diff --git a/lib/index.js b/lib/index.js index 8799f17f..ae9ac348 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,3 +1,5 @@ +'use strict'; + var Table = require(__dirname + '/table'); var sql = { diff --git a/lib/node/addColumn.js b/lib/node/addColumn.js index e12c13b3..273d8836 100644 --- a/lib/node/addColumn.js +++ b/lib/node/addColumn.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/alter.js b/lib/node/alter.js index 362f3892..ce53623c 100644 --- a/lib/node/alter.js +++ b/lib/node/alter.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/binary.js b/lib/node/binary.js index b057ca22..ea875b42 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -1,3 +1,5 @@ +'use strict'; + var BinaryNode = module.exports = require(__dirname).define({ type: 'BINARY', constructor: function(config) { @@ -19,4 +21,4 @@ var BinaryNode = module.exports = require(__dirname).define({ right: node }); } -}) +}); diff --git a/lib/node/column.js b/lib/node/column.js index 8cf484d0..257133c7 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/create.js b/lib/node/create.js index 22ed3811..bf535f6a 100644 --- a/lib/node/create.js +++ b/lib/node/create.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/default.js b/lib/node/default.js index bf0d362f..a139c169 100644 --- a/lib/node/default.js +++ b/lib/node/default.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = require(__dirname).define({ type: 'DEFAULT', constructor: function() { diff --git a/lib/node/delete.js b/lib/node/delete.js index 664899cf..2acb5872 100644 --- a/lib/node/delete.js +++ b/lib/node/delete.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/drop.js b/lib/node/drop.js index 98b9eeae..24e19062 100644 --- a/lib/node/drop.js +++ b/lib/node/drop.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/dropColumn.js b/lib/node/dropColumn.js index 87948d07..60ad4219 100644 --- a/lib/node/dropColumn.js +++ b/lib/node/dropColumn.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/from.js b/lib/node/from.js index 407eaf3f..84a6010f 100644 --- a/lib/node/from.js +++ b/lib/node/from.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); var From = Node.define({ diff --git a/lib/node/groupBy.js b/lib/node/groupBy.js index 2dac047f..6e5888d1 100644 --- a/lib/node/groupBy.js +++ b/lib/node/groupBy.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/ifExists.js b/lib/node/ifExists.js index 8e168204..9b759779 100644 --- a/lib/node/ifExists.js +++ b/lib/node/ifExists.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/ifNotExists.js b/lib/node/ifNotExists.js index fd0a034f..ef414551 100644 --- a/lib/node/ifNotExists.js +++ b/lib/node/ifNotExists.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/index.js b/lib/node/index.js index 9a727e3a..6eb8ad25 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,31 +1,34 @@ +'use strict'; + var Node = function(type) { this.nodes = []; -} +}; Node.prototype.toNode = function() { return this; -} +}; Node.prototype.add = function(node) { this.nodes.push(typeof node === 'string' ? new TextNode(node) : node.toNode()); return this; -} +}; Node.define = function(def) { var c = function() { - Node.apply(this, arguments) + Node.apply(this, arguments); if(def.constructor) { - def.constructor.apply(this, arguments) + def.constructor.apply(this, arguments); } - } - for(var key in Node.prototype) { + }; + var key; + for(key in Node.prototype) { c.prototype[key] = Node.prototype[key]; } - for(var key in def) { + for(key in def) { c.prototype[key] = def[key]; } return c; -} +}; module.exports = Node; var TextNode = require(__dirname + '/text'); diff --git a/lib/node/insert.js b/lib/node/insert.js index e200e49f..4873fa38 100644 --- a/lib/node/insert.js +++ b/lib/node/insert.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); var ParameterNode = require('./parameter'); var DefaultNode = require('./default'); diff --git a/lib/node/join.js b/lib/node/join.js index 94447a09..b6e21545 100644 --- a/lib/node/join.js +++ b/lib/node/join.js @@ -1,3 +1,5 @@ +'use strict'; + var JoinNode = module.exports = require(__dirname).define({ type: 'JOIN', constructor: function(subType, from, to) { diff --git a/lib/node/orderBy.js b/lib/node/orderBy.js index f3dff033..6db2a978 100644 --- a/lib/node/orderBy.js +++ b/lib/node/orderBy.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/parameter.js b/lib/node/parameter.js index 3610176c..7e45cbd3 100644 --- a/lib/node/parameter.js +++ b/lib/node/parameter.js @@ -1,3 +1,5 @@ +'use strict'; + module.exports = require(__dirname).define({ type: 'PARAMETER', constructor: function(val) { diff --git a/lib/node/query.js b/lib/node/query.js index d1a36f36..a449a067 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); var Select = require(__dirname + '/select'); var From = require(__dirname + '/from'); @@ -18,7 +20,6 @@ var Column = require(__dirname + '/../column'); var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); -var Column = require(__dirname + '/../column'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -40,7 +41,7 @@ var Query = Node.define({ //arg could be a column instead of a node select.add(args[i]); } - return this.add(select) + return this.add(select); }, from: function(tableNode) { var from = new From().add(tableNode); @@ -98,10 +99,10 @@ var Query = Node.define({ var args = Array.prototype.slice.call(arguments, 0); //object literal - if(arguments.length == 1 && !o["toNode"] && !o.forEach) { + if(arguments.length == 1 && !o.toNode && !o.forEach) { args = Object.keys(o).map(function(key) { return self.table[key].value(o[key]); - }) + }); } else if (o.forEach) { o.forEach(function (arg) { return self.insert.call(self, arg); @@ -129,7 +130,7 @@ var Query = Node.define({ }); return this.add(update); }, - delete: function() { + 'delete': function() { return this.add(new Delete()); }, returning: function() { @@ -139,7 +140,7 @@ var Query = Node.define({ //arg could be a column instead of a node returning.add(args[i]); } - return this.add(returning) + return this.add(returning); }, create: function() { return this.add(new Create()); @@ -197,6 +198,6 @@ var Query = Node.define({ var Dialect = require(__dirname + '/../').dialect; return new Dialect().getQuery(this); } -}) +}); module.exports = Query; diff --git a/lib/node/renameColumn.js b/lib/node/renameColumn.js index 8cf6e3ed..f886a11d 100644 --- a/lib/node/renameColumn.js +++ b/lib/node/renameColumn.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/returning.js b/lib/node/returning.js index 22cd0b49..35ea0a18 100644 --- a/lib/node/returning.js +++ b/lib/node/returning.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/select.js b/lib/node/select.js index 999a7436..847e1a74 100644 --- a/lib/node/select.js +++ b/lib/node/select.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/table.js b/lib/node/table.js index a02bbde0..407548d4 100644 --- a/lib/node/table.js +++ b/lib/node/table.js @@ -1,6 +1,8 @@ +'use strict'; + module.exports = require(__dirname).define({ type: 'TABLE', constructor: function(table) { this.table = table; } -}) +}); diff --git a/lib/node/text.js b/lib/node/text.js index e914e86b..538f31c9 100644 --- a/lib/node/text.js +++ b/lib/node/text.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/unary.js b/lib/node/unary.js index 905a8816..c98009fb 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -1,7 +1,9 @@ +'use strict'; + module.exports = require(__dirname).define({ type: 'UNARY', constructor: function(config) { this.left = config.left, - this.operator = config.operator + this.operator = config.operator; } }); diff --git a/lib/node/update.js b/lib/node/update.js index 09664781..32a29ba9 100644 --- a/lib/node/update.js +++ b/lib/node/update.js @@ -1,3 +1,5 @@ +'use strict'; + var Node = require(__dirname); module.exports = Node.define({ diff --git a/lib/node/where.js b/lib/node/where.js index e404d90a..ee26511c 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,3 +1,5 @@ +'use strict'; + var BinaryNode = require(__dirname + '/binary'); module.exports = require(__dirname).define({ type: 'WHERE', diff --git a/lib/table.js b/lib/table.js index f9b89b76..821d9f5d 100644 --- a/lib/table.js +++ b/lib/table.js @@ -1,3 +1,5 @@ +'use strict'; + var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); var TableNode = require(__dirname + '/node/table'); @@ -10,21 +12,21 @@ var Table = function(config) { this._initialConfig = config; this.columns = []; this.table = this; -} +}; Table.define = function(config) { var table = new Table(config); for (var i = 0; i < config.columns.length; i++) { var col = config.columns[i]; if(typeof col === 'string') { - col = { name: col } + col = { name: col }; } col.table = table; - var col = new Column(col); + col = new Column(col); table.addColumn(col); - }; + } return table; -} +}; Table.prototype.addColumn = function(col) { this.columns.push(col); @@ -33,33 +35,33 @@ Table.prototype.addColumn = function(col) { } this[col.name] = col; return this; -} +}; Table.prototype.getSchema = function() { return this._schema; -} +}; Table.prototype.getName = function() { return this._name; -} +}; Table.prototype.star = function() { var name = this.alias || this._name; return new TextNode('"'+name+'".*'); -} +}; Table.prototype.count = function(alias) { var name = this.alias || this._name, col = new Column({table: this, star: true}); return col.count(alias || name + '_count'); //ColumnNode -} +}; Table.prototype.select = function() { //create the query and pass it off var query = new Query(this); query.select.apply(query, arguments); return query; -} +}; Table.prototype.subQuery = function(alias) { //create the query and pass it off @@ -67,62 +69,62 @@ Table.prototype.subQuery = function(alias) { query.type = 'SUBQUERY'; query.alias = alias; return query; -} +}; Table.prototype.insert = function() { var query = new Query(this); query.insert.apply(query, arguments); return query; -} +}; Table.prototype.update = function() { var query = new Query(this); query.update.apply(query, arguments); return query; -} +}; -Table.prototype.delete = function() { +Table.prototype['delete'] = function() { var query = new Query(this); - query.delete.apply(query, arguments); + 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.alter = function() { var query = new Query(this); query.alter.apply(query, arguments); return query; -} +}; Table.prototype.toNode = function() { return new TableNode(this); -} +}; Table.prototype.join = function(other) { return new JoinNode('INNER', this.toNode(), other.toNode(), other); -} +}; Table.prototype.leftJoin = function(other) { return new JoinNode('LEFT', this.toNode(), other.toNode()); -} +}; Table.prototype.as = function(alias) { //TODO could this be cleaner? var t = Table.define(this._initialConfig); t.alias = alias; return t; -} +}; //called in shorthand when not calling select Table.prototype.__defineGetter__("nodes", function() { @@ -133,6 +135,6 @@ Table.prototype.where = function() { var query = this.select(this.star()); query.where.apply(query, arguments); return query; -} +}; module.exports = Table; diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 23307b0c..0b03ad44 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var test = require('tap').test; var Column = require(__dirname + '/../lib/column'); var Table = require(__dirname + '/../lib/table'); @@ -5,7 +7,7 @@ var Table = require(__dirname + '/../lib/table'); var Foo = Table.define({ name: 'foo', columns: ['baz','bar'] -}) +}); test('operators', function(t) { t.equal(Foo.baz.equals(1).operator, '='); @@ -20,4 +22,4 @@ test('operators', function(t) { t.equal(Foo.baz.lt(1).operator, '<'); t.equal(Foo.baz.lte(1).operator, '<='); t.end(); -}) +}); diff --git a/test/clause-definition.js b/test/clause-definition.js index 092bc835..15a8189e 100644 --- a/test/clause-definition.js +++ b/test/clause-definition.js @@ -1,10 +1,12 @@ +'use strict'; + var test = require('tap').test; var Node = require(__dirname + '/../lib/node/'); console.log('node definition'); var Bang = Node.define({ type: 'SELECT' -}) +}); var Boom = Node.define({ constructor: function(n) { @@ -26,4 +28,4 @@ test('clause definition', function(t) { t.equal(q2.nodes.length, 0); t.equal(q2.name, 'bai'); t.end(); -}) +}); diff --git a/test/index-tests.js b/test/index-tests.js index b8b5cb05..8d19f2b1 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var test = require('tap').test; var sql = require(__dirname + '/../lib'); @@ -10,7 +12,7 @@ test('unknown dialect', function(t) { console.log('unknown dialog throws exception'); t.throws(function() { sql.setDialect('asdf'); - }) + }); t.end(); }); @@ -26,6 +28,6 @@ test('setting dialect to postgres works', function(t) { sql.setDialect('postgres'); var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); t.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - t.equal(query.values[0], 'brian.m.carlson@gmail.com') + t.equal(query.values[0], 'brian.m.carlson@gmail.com'); t.end(); }); diff --git a/test/index.js b/test/index.js index acc8dcbb..a75ae2d1 100644 --- a/test/index.js +++ b/test/index.js @@ -1,3 +1,5 @@ +'use strict'; + var fs = require('fs'); var path = require('path'); @@ -11,6 +13,7 @@ var directories = [ directories.forEach(function (d) { fs.readdir(d, function(err, files) { if(err) throw err; + /*jshint boss: true */ for(var i = 0, file; file = files[i]; i++) { var filePath = path.join(d, file); require(filePath); diff --git a/test/postgres/aggregate-tests.js b/test/postgres/aggregate-tests.js index 6cf4b534..53587d68 100644 --- a/test/postgres/aggregate-tests.js +++ b/test/postgres/aggregate-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); diff --git a/test/postgres/alter-table-tests.js b/test/postgres/alter-table-tests.js index 68a03f7c..02ea81cf 100644 --- a/test/postgres/alter-table-tests.js +++ b/test/postgres/alter-table-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); diff --git a/test/postgres/create-table-tests.js b/test/postgres/create-table-tests.js index 96511ff1..d85c7acc 100644 --- a/test/postgres/create-table-tests.js +++ b/test/postgres/create-table-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Table = require(__dirname + '/../../lib/table'); var Harness = require('./support'); diff --git a/test/postgres/delete-tests.js b/test/postgres/delete-tests.js index 64676c5f..456c3a6e 100644 --- a/test/postgres/delete-tests.js +++ b/test/postgres/delete-tests.js @@ -1,8 +1,10 @@ +'use strict'; + var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.delete().where(post.content.equals('')), + query : post['delete']().where(post.content.equals('')), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', params: [''] }); diff --git a/test/postgres/drop-table-tests.js b/test/postgres/drop-table-tests.js index 1f720b4d..239aa148 100644 --- a/test/postgres/drop-table-tests.js +++ b/test/postgres/drop-table-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var post = Harness.definePostTable(); diff --git a/test/postgres/group-by-tests.js b/test/postgres/group-by-tests.js index e6bc31db..bfabcc69 100644 --- a/test/postgres/group-by-tests.js +++ b/test/postgres/group-by-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); diff --git a/test/postgres/index.js b/test/postgres/index.js index e69de29b..ad9a93a7 100644 --- a/test/postgres/index.js +++ b/test/postgres/index.js @@ -0,0 +1 @@ +'use strict'; diff --git a/test/postgres/insert-tests.js b/test/postgres/insert-tests.js index 380bf448..0494ada5 100644 --- a/test/postgres/insert-tests.js +++ b/test/postgres/insert-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var post = Harness.definePostTable(); diff --git a/test/postgres/join-tests.js b/test/postgres/join-tests.js index 5efb9f06..34b3c81b 100644 --- a/test/postgres/join-tests.js +++ b/test/postgres/join-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); diff --git a/test/postgres/limit-and-offset-tests.js b/test/postgres/limit-and-offset-tests.js index a03befbf..297638dc 100644 --- a/test/postgres/limit-and-offset-tests.js +++ b/test/postgres/limit-and-offset-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); diff --git a/test/postgres/namespace-tests.js b/test/postgres/namespace-tests.js index 15524c33..27ca9806 100644 --- a/test/postgres/namespace-tests.js +++ b/test/postgres/namespace-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var Table = require(__dirname + '/../../lib/table'); var user = Harness.defineUserTable(); @@ -38,7 +40,7 @@ var comment = Table.define({ Harness.test({ query : comment.select(comment.text, comment.userId), - pg : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + pg : 'SELECT "comment"."text", "comment"."userId" FROM "comment"' }); diff --git a/test/postgres/order-tests.js b/test/postgres/order-tests.js index 63278685..104f7b1a 100644 --- a/test/postgres/order-tests.js +++ b/test/postgres/order-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); diff --git a/test/postgres/schema-tests.js b/test/postgres/schema-tests.js index 455540b0..b19afbe5 100644 --- a/test/postgres/schema-tests.js +++ b/test/postgres/schema-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var Table = require(__dirname + '/../../lib/table'); diff --git a/test/postgres/shortcut-tests.js b/test/postgres/shortcut-tests.js index f52276df..0d30571f 100644 --- a/test/postgres/shortcut-tests.js +++ b/test/postgres/shortcut-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); diff --git a/test/postgres/support.js b/test/postgres/support.js index ce03bec4..b5f93130 100644 --- a/test/postgres/support.js +++ b/test/postgres/support.js @@ -1,3 +1,5 @@ +'use strict'; + var tap = require('tap').test; var Postgres = require('../../lib/dialect/postgres'); var Table = require(__dirname + '/../../lib/table'); diff --git a/test/postgres/table-tests.js b/test/postgres/table-tests.js index 2e9f7141..52a717eb 100644 --- a/test/postgres/table-tests.js +++ b/test/postgres/table-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var user = Harness.defineUserTable(); @@ -45,13 +47,13 @@ Harness.test({ }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.in(['foo', 'bar'])), + query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar'])), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', params: ['foo', 'bar'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.in(['foo', 'bar']).and(user.id.equals(1))), + query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar']).and(user.id.equals(1))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', params: ['foo', 'bar', 1] }); @@ -95,4 +97,4 @@ Harness.test({ Harness.test({ query : user.select('name').from('user').where({name: 'brian'}), pg : 'SELECT name FROM user WHERE ("user"."name" = $1)' -}); \ No newline at end of file +}); diff --git a/test/postgres/update-tests.js b/test/postgres/update-tests.js index 334b2b8a..b44721d8 100644 --- a/test/postgres/update-tests.js +++ b/test/postgres/update-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var Harness = require('./support'); var post = Harness.definePostTable(); var user = Harness.defineUserTable(); diff --git a/test/select-tests.js b/test/select-tests.js index ef287b9d..f60da93b 100644 --- a/test/select-tests.js +++ b/test/select-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var assert = require('assert'); var Select = require(__dirname + '/../lib/node/select'); diff --git a/test/table-tests.js b/test/table-tests.js index 05bf8760..728773d1 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var test = require('tap').test; var Table = require(__dirname + '/../lib/table'); var Column = require(__dirname + '/../lib/column'); @@ -5,7 +7,7 @@ var Column = require(__dirname + '/../lib/column'); test('table', function(t) { var table = new Table({ name: 'bang' - }) + }); t.equal(table.getName(), 'bang'); t.equal(table.columns.length, 0); @@ -13,7 +15,7 @@ test('table', function(t) { var col = new Column({ table: table, name: 'boom' - }) + }); t.equal(col.name, 'boom'); t.equal(col.table.getName(), 'bang'); @@ -30,13 +32,13 @@ test('table', function(t) { var user = Table.define({ name: 'user', columns: ['id', 'name'] - }) + }); t.equal(user.getName(), 'user'); t.equal(user.columns.length, 2); t.equal(user.columns[0].name, 'id'); t.equal(user.columns[1].name, 'name'); - t.equal(user.columns[0].name, user.id.name) + t.equal(user.columns[0].name, user.id.name); t.equal(user.id.table, user); t.equal(user.name.table, user); t.end(); From e55cb2f8784902653e351b67702e8f46d060c4f4 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Thu, 7 Mar 2013 00:09:13 +0000 Subject: [PATCH 012/507] add basic mysql support --- lib/dialect/mysql.js | 338 +++++++++++++++++++++++++++++++++++++++++++ lib/index.js | 54 +++---- lib/table.js | 4 +- 3 files changed, 369 insertions(+), 27 deletions(-) create mode 100644 lib/dialect/mysql.js diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js new file mode 100644 index 00000000..f06cd94a --- /dev/null +++ b/lib/dialect/mysql.js @@ -0,0 +1,338 @@ +'use strict'; + +var util = require('util'); +var assert = require('assert'); +var From = require(__dirname + '/../node/from'); +var Parameter = require(__dirname + '/../node/parameter'); +var Mysql = function() { + this.output = []; + this.params = []; +}; + +Mysql.prototype.getQuery = function(queryNode) { + this.visitQuery(queryNode); + return { text: this.output.join(' '), values: this.params }; +}; + + +Mysql.prototype.visit = function(node) { + switch(node.type) { + case 'QUERY': return this.visitQuery(node); + case 'SUBQUERY': return this.visitSubquery(node); + case 'SELECT': return this.visitSelect(node); + case 'INSERT': return this.visitInsert(node); + case 'UPDATE': return this.visitUpdate(node); + case 'DELETE': return this.visitDelete(); + case 'CREATE': return this.visitCreate(node); + case 'DROP': return this.visitDrop(node); + case 'ALTER': return this.visitAlter(node); + case 'FROM': return this.visitFrom(node); + case 'WHERE': return this.visitWhere(node); + case 'ORDER BY': return this.visitOrderBy(node); + case 'GROUP BY': return this.visitGroupBy(node); + case 'RETURNING': return this.visitReturning(node); + case 'BINARY': return this.visitBinary(node); + case 'TABLE': return this.visitTable(node); + case 'COLUMN': return this.visitColumn(node); + case 'JOIN': return this.visitJoin(node); + case 'TEXT': return node.text; + case 'UNARY': return this.visitUnary(node); + case 'PARAMETER': return this.visitParameter(node); + case 'DEFAULT': return this.visitDefault(node); + case 'IF EXISTS': return this.visitIfExists(); + case 'IF NOT EXISTS': return this.visitIfNotExists(); + case 'ADD COLUMN': return this.visitAddColumn(node); + case 'DROP COLUMN': return this.visitDropColumn(node); + case 'RENAME COLUMN': return this.visitRenameColumn(node); + case 'LIMIT': + case 'OFFSET': + return this.visitModifier(node); + default: throw new Error("Unrecognized node type " + node.type); + } +}; + +Mysql.prototype.quote = function(word) { + return '`' + word + '`'; +}; + +Mysql.prototype.visitSelect = function(select) { + var result = ['SELECT', select.nodes.map(this.visit.bind(this)).join(', ')]; + this._selectOrDeleteEndIndex = this.output.length + result.length; + return result; +}; + +Mysql.prototype.visitInsert = function(insert) { + var self = this; + this._visitedFrom = true; + //don't use table.column for inserts + this._visitedInsert = true; + + var paramNodes = insert.getParameters() + .map(function (paramSet) { + return paramSet.map(function (param) { + return self.visit(param); + }).join(', '); + }).map(function (param) { + return '('+param+')'; + }).join(', '); + + var result = [ + 'INSERT INTO', + this.visit(this._queryNode.table.toNode()), + '(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')', + 'VALUES', paramNodes + ]; + return result; +}; + +Mysql.prototype.visitUpdate = function(update) { + //don't auto-generate from clause + this._visitedFrom = true; + var params = []; + /*jshint boss: true */ + for(var i = 0, node; node = update.nodes[i]; i++) { + this._visitingUpdateTargetColumn = true; + var target_col = this.visit(node); + this._visitingUpdateTargetColumn = false; + params = params.concat(target_col + ' = ' + this.visit(node.value)); + } + var result = [ + 'UPDATE', + this.visit(this._queryNode.table.toNode()), + 'SET', + params.join(', ') + ]; + return result; +}; + +Mysql.prototype.visitDelete = function() { + this._selectOrDeleteEndIndex = 1; + return ['DELETE']; +}; + +Mysql.prototype.visitCreate = function(create) { + this._visitingCreate = true; + //don't auto-generate from clause + this._visitedFrom = true; + var table = this._queryNode.table; + var col_nodes = table.columns.map(function(col) { return col.toNode(); }); + + 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._visitingCreate = false; + return result; +}; + +Mysql.prototype.visitDrop = function(drop) { + //don't auto-generate from clause + this._visitedFrom = true; + var result = ['DROP TABLE']; + result = result.concat(drop.nodes.map(this.visit.bind(this))); + result.push(this.visit(this._queryNode.table.toNode())); + return result; +}; + +Mysql.prototype.visitAlter = function(alter) { + this._visitingAlter = true; + //don't auto-generate from clause + this._visitedFrom = true; + var table = this._queryNode.table; + var col_nodes = table.columns.map(function(col) { return col.toNode(); }); + var result = [ + 'ALTER TABLE', + this.visit(table.toNode()), + alter.nodes.map(this.visit.bind(this)).join(', ') + ]; + this._visitingAlter = false; + return result; +}; + +Mysql.prototype.visitFrom = function(from) { + this._visitedFrom = true; + var result = []; + result.push('FROM'); + for(var i = 0; i < from.nodes.length; i++) { + result = result.concat(this.visit(from.nodes[i])); + } + return result; +}; + +Mysql.prototype.visitWhere = function(where) { + var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')]; + return result; +}; + +Mysql.prototype.visitOrderBy = function(orderBy) { + var result = ['ORDER BY', orderBy.nodes.map(this.visit.bind(this)).join(', ')]; + return result; +}; + +Mysql.prototype.visitGroupBy = function(groupBy) { + var result = ['GROUP BY', groupBy.nodes.map(this.visit.bind(this)).join(', ')]; + return result; +}; + +Mysql.prototype.visitBinary = function(binary) { + var self = this; + var result = '(' + this.visit(binary.left) + ' ' + binary.operator + ' '; + if (Array.isArray(binary.right)) { + result += '(' + binary.right.map(function (node) { + return self.visit(node); + }).join(', ') + ')'; + } + else { + result += this.visit(binary.right); + } + result += ')'; + return result; +}; + +Mysql.prototype.visitUnary = function(unary) { + return '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; +}; + +Mysql.prototype.visitQuery = function(queryNode) { + this._queryNode = queryNode; + for(var i = 0; i < queryNode.nodes.length; i ++) { + var res = this.visit(queryNode.nodes[i]); + this.output = this.output.concat(res); + } + //implicit 'from' + if(!this._visitedFrom) { + var select = this.output.slice(0, this._selectOrDeleteEndIndex); + var from = this.visitFrom(new From().add(queryNode.table.toNode())); + var rest = this.output.slice(this._selectOrDeleteEndIndex); + this.output = select.concat(from).concat(rest); + } + return this; +}; + +Mysql.prototype.visitSubquery = function(queryNode) { + var result = []; + for(var i = 0; i < queryNode.nodes.length; i ++) { + var res = this.visit(queryNode.nodes[i]); + result = result.concat(res); + } + //implicit 'from' + if(!this._visitedFrom) { + var select = result.slice(0, this._selectOrDeleteEndIndex); + var from = this.visitFrom(new From().add(queryNode.table.toNode())); + var rest = result.slice(this._selectOrDeleteEndIndex); + result = select.concat(from).concat(rest); + } + result[0] = '('+result[0]; + result[result.length-1] = result[result.length-1] + ') ' + queryNode.alias; + return result; +}; + +Mysql.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 += ' AS ' + table.alias; + } + return txt; +}; + +Mysql.prototype.visitColumn = function(columnNode) { + var table = columnNode.table; + var inSelectClause = !this._selectOrDeleteEndIndex; + var txt = ""; + if(inSelectClause) { + if (columnNode.asArray) { + txt += 'array_agg('; + } else if (columnNode.aggCount) { + txt += 'COUNT('; + } + } + if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { + if(table.alias) { + txt = table.alias; + } else { + if(table.getSchema()) { + txt = this.quote(table.getSchema()); + txt += '.'; + } + txt += this.quote(table.getName()); + } + txt += '.'; + } + if (columnNode.star) { + txt += '*'; + } else { + txt += this.quote(columnNode.name); + } + if(inSelectClause && (columnNode.asArray || columnNode.aggCount)) { + txt += ')'; + } + if(inSelectClause && columnNode.alias) { + txt += ' as ' + this.quote(columnNode.alias); + } + if(this._visitingCreate || this._visitingAddColumn) { + assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + + ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); + txt += ' ' + columnNode.dataType; + } + return txt; +}; + +Mysql.prototype.visitParameter = function(parameter) { + this.params.push(parameter.value()); + return "?"; +}; + +Mysql.prototype.visitDefault = function(parameter) { + var params = this.params; + this.params.push('DEFAULT'); + return "?"; +}; + +Mysql.prototype.visitAddColumn = function(addColumn) { + this._visitingAddColumn = true; + var result = ['ADD COLUMN ' + this.visit(addColumn.nodes[0])]; + this._visitingAddColumn = false; + return result; +}; + +Mysql.prototype.visitDropColumn = function(dropColumn) { + return ['DROP COLUMN ' + this.visit(dropColumn.nodes[0])]; +}; + +Mysql.prototype.visitRenameColumn = function(renameColumn) { + return ['RENAME COLUMN ' + this.visit(renameColumn.nodes[0]) + ' TO ' + this.visit(renameColumn.nodes[1])]; +}; + +Mysql.prototype.visitIfExists = function() { + return ['IF EXISTS']; +}; + +Mysql.prototype.visitIfNotExists = function() { + return ['IF NOT EXISTS']; +}; + +Mysql.prototype.visitJoin = function(join) { + var result = []; + result = result.concat(this.visit(join.from)); + result = result.concat(join.subType + ' JOIN'); + result = result.concat(this.visit(join.to)); + result = result.concat('ON'); + result = result.concat(this.visit(join.on)); + return result; +}; + +Mysql.prototype.visitReturning = function(returning) { + return ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; +}; + +Mysql.prototype.visitModifier = function(node) { + return [node.type, node.count]; +}; + +module.exports = Mysql; diff --git a/lib/index.js b/lib/index.js index ae9ac348..6873185c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,26 +1,28 @@ -'use strict'; - -var Table = require(__dirname + '/table'); - -var sql = { - Table: Table, - define: Table.define, - select: function() { - var Query = require(__dirname + '/node/query'); - var query = new Query(); - query.select.apply(query, arguments); - return query; - }, - setDialect: function(dialect) { - switch(dialect.toLowerCase()) { - case 'postgres': - this.dialect = require(__dirname + '/dialect/postgres'); - break; - default: - throw new Error(dialect + ' is unsupported'); - } - return this; - } -}; - -module.exports = sql.setDialect('postgres'); +'use strict'; + +var Table = require(__dirname + '/table'); + +var sql = { + Table: Table, + define: Table.define, + select: function() { + var Query = require(__dirname + '/node/query'); + var query = new Query(); + query.select.apply(query, arguments); + return query; + }, + setDialect: function(dialect) { + switch(dialect.toLowerCase()) { + case 'postgres': + this.dialect = require(__dirname + '/dialect/postgres'); + case 'mysql': + this.dialect = require(__dirname + '/dialect/mysql'); + break; + default: + throw new Error(dialect + ' is unsupported'); + } + return this; + } +}; + +module.exports = sql.setDialect('postgres'); diff --git a/lib/table.js b/lib/table.js index 821d9f5d..2a4100dd 100644 --- a/lib/table.js +++ b/lib/table.js @@ -47,7 +47,9 @@ Table.prototype.getName = function() { Table.prototype.star = function() { var name = this.alias || this._name; - return new TextNode('"'+name+'".*'); + var Dialect = require(__dirname + '/../').dialect; + var dialect = new Dialect(); + return new TextNode(dialect.quote(name)+'.*'); }; Table.prototype.count = function(alias) { From 914ac2b5b4d83be0331aac4a40061617efa708f6 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Thu, 7 Mar 2013 00:13:17 +0000 Subject: [PATCH 013/507] make mysql dialect only contain the differences to postgres, for ease of maintenance --- lib/dialect/mysql.js | 315 +------------------------------------------ 1 file changed, 2 insertions(+), 313 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index f06cd94a..c8608925 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -1,288 +1,18 @@ 'use strict'; var util = require('util'); -var assert = require('assert'); -var From = require(__dirname + '/../node/from'); -var Parameter = require(__dirname + '/../node/parameter'); + var Mysql = function() { this.output = []; this.params = []; }; -Mysql.prototype.getQuery = function(queryNode) { - this.visitQuery(queryNode); - return { text: this.output.join(' '), values: this.params }; -}; - - -Mysql.prototype.visit = function(node) { - switch(node.type) { - case 'QUERY': return this.visitQuery(node); - case 'SUBQUERY': return this.visitSubquery(node); - case 'SELECT': return this.visitSelect(node); - case 'INSERT': return this.visitInsert(node); - case 'UPDATE': return this.visitUpdate(node); - case 'DELETE': return this.visitDelete(); - case 'CREATE': return this.visitCreate(node); - case 'DROP': return this.visitDrop(node); - case 'ALTER': return this.visitAlter(node); - case 'FROM': return this.visitFrom(node); - case 'WHERE': return this.visitWhere(node); - case 'ORDER BY': return this.visitOrderBy(node); - case 'GROUP BY': return this.visitGroupBy(node); - case 'RETURNING': return this.visitReturning(node); - case 'BINARY': return this.visitBinary(node); - case 'TABLE': return this.visitTable(node); - case 'COLUMN': return this.visitColumn(node); - case 'JOIN': return this.visitJoin(node); - case 'TEXT': return node.text; - case 'UNARY': return this.visitUnary(node); - case 'PARAMETER': return this.visitParameter(node); - case 'DEFAULT': return this.visitDefault(node); - case 'IF EXISTS': return this.visitIfExists(); - case 'IF NOT EXISTS': return this.visitIfNotExists(); - case 'ADD COLUMN': return this.visitAddColumn(node); - case 'DROP COLUMN': return this.visitDropColumn(node); - case 'RENAME COLUMN': return this.visitRenameColumn(node); - case 'LIMIT': - case 'OFFSET': - return this.visitModifier(node); - default: throw new Error("Unrecognized node type " + node.type); - } -}; +util.inherits(Mysql, require(__dirname + '/postgres')); Mysql.prototype.quote = function(word) { return '`' + word + '`'; }; -Mysql.prototype.visitSelect = function(select) { - var result = ['SELECT', select.nodes.map(this.visit.bind(this)).join(', ')]; - this._selectOrDeleteEndIndex = this.output.length + result.length; - return result; -}; - -Mysql.prototype.visitInsert = function(insert) { - var self = this; - this._visitedFrom = true; - //don't use table.column for inserts - this._visitedInsert = true; - - var paramNodes = insert.getParameters() - .map(function (paramSet) { - return paramSet.map(function (param) { - return self.visit(param); - }).join(', '); - }).map(function (param) { - return '('+param+')'; - }).join(', '); - - var result = [ - 'INSERT INTO', - this.visit(this._queryNode.table.toNode()), - '(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')', - 'VALUES', paramNodes - ]; - return result; -}; - -Mysql.prototype.visitUpdate = function(update) { - //don't auto-generate from clause - this._visitedFrom = true; - var params = []; - /*jshint boss: true */ - for(var i = 0, node; node = update.nodes[i]; i++) { - this._visitingUpdateTargetColumn = true; - var target_col = this.visit(node); - this._visitingUpdateTargetColumn = false; - params = params.concat(target_col + ' = ' + this.visit(node.value)); - } - var result = [ - 'UPDATE', - this.visit(this._queryNode.table.toNode()), - 'SET', - params.join(', ') - ]; - return result; -}; - -Mysql.prototype.visitDelete = function() { - this._selectOrDeleteEndIndex = 1; - return ['DELETE']; -}; - -Mysql.prototype.visitCreate = function(create) { - this._visitingCreate = true; - //don't auto-generate from clause - this._visitedFrom = true; - var table = this._queryNode.table; - var col_nodes = table.columns.map(function(col) { return col.toNode(); }); - - 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._visitingCreate = false; - return result; -}; - -Mysql.prototype.visitDrop = function(drop) { - //don't auto-generate from clause - this._visitedFrom = true; - var result = ['DROP TABLE']; - result = result.concat(drop.nodes.map(this.visit.bind(this))); - result.push(this.visit(this._queryNode.table.toNode())); - return result; -}; - -Mysql.prototype.visitAlter = function(alter) { - this._visitingAlter = true; - //don't auto-generate from clause - this._visitedFrom = true; - var table = this._queryNode.table; - var col_nodes = table.columns.map(function(col) { return col.toNode(); }); - var result = [ - 'ALTER TABLE', - this.visit(table.toNode()), - alter.nodes.map(this.visit.bind(this)).join(', ') - ]; - this._visitingAlter = false; - return result; -}; - -Mysql.prototype.visitFrom = function(from) { - this._visitedFrom = true; - var result = []; - result.push('FROM'); - for(var i = 0; i < from.nodes.length; i++) { - result = result.concat(this.visit(from.nodes[i])); - } - return result; -}; - -Mysql.prototype.visitWhere = function(where) { - var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')]; - return result; -}; - -Mysql.prototype.visitOrderBy = function(orderBy) { - var result = ['ORDER BY', orderBy.nodes.map(this.visit.bind(this)).join(', ')]; - return result; -}; - -Mysql.prototype.visitGroupBy = function(groupBy) { - var result = ['GROUP BY', groupBy.nodes.map(this.visit.bind(this)).join(', ')]; - return result; -}; - -Mysql.prototype.visitBinary = function(binary) { - var self = this; - var result = '(' + this.visit(binary.left) + ' ' + binary.operator + ' '; - if (Array.isArray(binary.right)) { - result += '(' + binary.right.map(function (node) { - return self.visit(node); - }).join(', ') + ')'; - } - else { - result += this.visit(binary.right); - } - result += ')'; - return result; -}; - -Mysql.prototype.visitUnary = function(unary) { - return '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; -}; - -Mysql.prototype.visitQuery = function(queryNode) { - this._queryNode = queryNode; - for(var i = 0; i < queryNode.nodes.length; i ++) { - var res = this.visit(queryNode.nodes[i]); - this.output = this.output.concat(res); - } - //implicit 'from' - if(!this._visitedFrom) { - var select = this.output.slice(0, this._selectOrDeleteEndIndex); - var from = this.visitFrom(new From().add(queryNode.table.toNode())); - var rest = this.output.slice(this._selectOrDeleteEndIndex); - this.output = select.concat(from).concat(rest); - } - return this; -}; - -Mysql.prototype.visitSubquery = function(queryNode) { - var result = []; - for(var i = 0; i < queryNode.nodes.length; i ++) { - var res = this.visit(queryNode.nodes[i]); - result = result.concat(res); - } - //implicit 'from' - if(!this._visitedFrom) { - var select = result.slice(0, this._selectOrDeleteEndIndex); - var from = this.visitFrom(new From().add(queryNode.table.toNode())); - var rest = result.slice(this._selectOrDeleteEndIndex); - result = select.concat(from).concat(rest); - } - result[0] = '('+result[0]; - result[result.length-1] = result[result.length-1] + ') ' + queryNode.alias; - return result; -}; - -Mysql.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 += ' AS ' + table.alias; - } - return txt; -}; - -Mysql.prototype.visitColumn = function(columnNode) { - var table = columnNode.table; - var inSelectClause = !this._selectOrDeleteEndIndex; - var txt = ""; - if(inSelectClause) { - if (columnNode.asArray) { - txt += 'array_agg('; - } else if (columnNode.aggCount) { - txt += 'COUNT('; - } - } - if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { - if(table.alias) { - txt = table.alias; - } else { - if(table.getSchema()) { - txt = this.quote(table.getSchema()); - txt += '.'; - } - txt += this.quote(table.getName()); - } - txt += '.'; - } - if (columnNode.star) { - txt += '*'; - } else { - txt += this.quote(columnNode.name); - } - if(inSelectClause && (columnNode.asArray || columnNode.aggCount)) { - txt += ')'; - } - if(inSelectClause && columnNode.alias) { - txt += ' as ' + this.quote(columnNode.alias); - } - if(this._visitingCreate || this._visitingAddColumn) { - assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + - ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); - txt += ' ' + columnNode.dataType; - } - return txt; -}; - Mysql.prototype.visitParameter = function(parameter) { this.params.push(parameter.value()); return "?"; @@ -294,45 +24,4 @@ Mysql.prototype.visitDefault = function(parameter) { return "?"; }; -Mysql.prototype.visitAddColumn = function(addColumn) { - this._visitingAddColumn = true; - var result = ['ADD COLUMN ' + this.visit(addColumn.nodes[0])]; - this._visitingAddColumn = false; - return result; -}; - -Mysql.prototype.visitDropColumn = function(dropColumn) { - return ['DROP COLUMN ' + this.visit(dropColumn.nodes[0])]; -}; - -Mysql.prototype.visitRenameColumn = function(renameColumn) { - return ['RENAME COLUMN ' + this.visit(renameColumn.nodes[0]) + ' TO ' + this.visit(renameColumn.nodes[1])]; -}; - -Mysql.prototype.visitIfExists = function() { - return ['IF EXISTS']; -}; - -Mysql.prototype.visitIfNotExists = function() { - return ['IF NOT EXISTS']; -}; - -Mysql.prototype.visitJoin = function(join) { - var result = []; - result = result.concat(this.visit(join.from)); - result = result.concat(join.subType + ' JOIN'); - result = result.concat(this.visit(join.to)); - result = result.concat('ON'); - result = result.concat(this.visit(join.on)); - return result; -}; - -Mysql.prototype.visitReturning = function(returning) { - return ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; -}; - -Mysql.prototype.visitModifier = function(node) { - return [node.type, node.count]; -}; - module.exports = Mysql; From f9735c459d8f8e7d50496a3f461e0dc57183ee7a Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Thu, 7 Mar 2013 13:20:23 +0000 Subject: [PATCH 014/507] missing break in setDialect --- lib/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/index.js b/lib/index.js index 6873185c..172ebfe6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -15,6 +15,7 @@ var sql = { switch(dialect.toLowerCase()) { case 'postgres': this.dialect = require(__dirname + '/dialect/postgres'); + break; case 'mysql': this.dialect = require(__dirname + '/dialect/mysql'); break; From 4ef13156ffffef081cc64e7b0ef2bbedf5f55f40 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Fri, 8 Mar 2013 12:56:51 +0000 Subject: [PATCH 015/507] add mysql order by column format. mysql doesn't allow brackets around the order items. --- lib/column.js | 8 ++++---- lib/dialect/mysql.js | 8 ++++++++ lib/dialect/postgres.js | 9 +++++++++ lib/node/orderByColumn.js | 9 +++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 lib/node/orderByColumn.js diff --git a/lib/column.js b/lib/column.js index 4e26099d..586ddf4c 100644 --- a/lib/column.js +++ b/lib/column.js @@ -3,6 +3,7 @@ var ColumnNode = require(__dirname + '/node/column'); var ParameterNode = require(__dirname + '/node/parameter'); var BinaryNode = require(__dirname + '/node/binary'); +var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); var Column = function(config) { @@ -11,10 +12,9 @@ var Column = function(config) { this.star = config.star; this.asc = this.ascending = this; this.alias = null; - this.desc = this.descending = new BinaryNode({ - left: this.toNode(), - right: new TextNode('DESC'), - operator: '' + this.desc = this.descending = new OrderByColumnNode({ + column: this.toNode(), + direction: new TextNode('DESC') }); this.dataType = config.dataType; }; diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index c8608925..127951eb 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -24,4 +24,12 @@ Mysql.prototype.visitDefault = function(parameter) { return "?"; }; +Mysql.prototype.visitOrderByColumn = function(column) { + if(column.direction) { + return this.visit(column.column) + ' ' + this.visit(column.direction); + } else { + return this.visit(column.column); + } +}; + module.exports = Mysql; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4cc763fe..660e21e4 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -29,6 +29,7 @@ Postgres.prototype.visit = function(node) { case 'FROM': return this.visitFrom(node); case 'WHERE': return this.visitWhere(node); case 'ORDER BY': return this.visitOrderBy(node); + case 'ORDER BY COLUMN': return this.visitOrderByColumn(node); case 'GROUP BY': return this.visitGroupBy(node); case 'RETURNING': return this.visitReturning(node); case 'BINARY': return this.visitBinary(node); @@ -169,6 +170,14 @@ Postgres.prototype.visitOrderBy = function(orderBy) { return result; }; +Postgres.prototype.visitOrderByColumn = function(column) { + if(column.direction) { + return '(' + this.visit(column.column) + ' ' + column.direction + ')'; + } else { + return this.visit(column.column); + } +}; + Postgres.prototype.visitGroupBy = function(groupBy) { var result = ['GROUP BY', groupBy.nodes.map(this.visit.bind(this)).join(', ')]; return result; diff --git a/lib/node/orderByColumn.js b/lib/node/orderByColumn.js new file mode 100644 index 00000000..8f662c1b --- /dev/null +++ b/lib/node/orderByColumn.js @@ -0,0 +1,9 @@ +'use strict'; + +var OrderByColumn = module.exports = require(__dirname).define({ + type: 'ORDER BY COLUMN', + constructor: function(config) { + this.column = config.column; + this.direction = config.direction; + } +}); From 7f53d5a69d3249b5994d15d9a33501e2a5983281 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Fri, 8 Mar 2013 13:04:07 +0000 Subject: [PATCH 016/507] correctly visit direction text node on postgres and correct test to only have one space before direction --- lib/dialect/postgres.js | 2 +- test/postgres/order-tests.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 660e21e4..84795528 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -172,7 +172,7 @@ Postgres.prototype.visitOrderBy = function(orderBy) { Postgres.prototype.visitOrderByColumn = function(column) { if(column.direction) { - return '(' + this.visit(column.column) + ' ' + column.direction + ')'; + return '(' + this.visit(column.column) + ' ' + this.visit(column.direction) + ')'; } else { return this.visit(column.column); } diff --git a/test/postgres/order-tests.js b/test/postgres/order-tests.js index 104f7b1a..4d1aedeb 100644 --- a/test/postgres/order-tests.js +++ b/test/postgres/order-tests.js @@ -11,10 +11,10 @@ Harness.test({ Harness.test({ query : post.select(post.content).order(post.content, post.userId.descending), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)' + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)' }); Harness.test({ query : post.select(post.content).order(post.content.asc, post.userId.desc), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)' + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)' }); From 1590255ac79c81cbff7a4f66ed3e4843ecc9fa3d Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sat, 9 Mar 2013 09:56:43 +0000 Subject: [PATCH 017/507] quote aliases, quote all table names and add more support for mysql --- lib/dialect/mysql.js | 19 +++++++++++++------ lib/dialect/postgres.js | 14 +++++++++----- lib/table.js | 5 +---- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 127951eb..b7a58715 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -1,6 +1,7 @@ 'use strict'; var util = require('util'); +var assert = require('assert'); var Mysql = function() { this.output = []; @@ -9,9 +10,9 @@ var Mysql = function() { util.inherits(Mysql, require(__dirname + '/postgres')); -Mysql.prototype.quote = function(word) { - return '`' + word + '`'; -}; +Mysql.prototype._quoteCharacter = '`'; + +Mysql.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; Mysql.prototype.visitParameter = function(parameter) { this.params.push(parameter.value()); @@ -19,9 +20,7 @@ Mysql.prototype.visitParameter = function(parameter) { }; Mysql.prototype.visitDefault = function(parameter) { - var params = this.params; - this.params.push('DEFAULT'); - return "?"; + return "DEFAULT"; }; Mysql.prototype.visitOrderByColumn = function(column) { @@ -32,4 +31,12 @@ Mysql.prototype.visitOrderByColumn = function(column) { } }; +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]; +}; + + module.exports = Mysql; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 84795528..114efdb8 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -9,6 +9,8 @@ var Postgres = function() { this.params = []; }; +Postgres.prototype._arrayAggFunctionName = 'array_agg'; + Postgres.prototype.getQuery = function(queryNode) { this.visitQuery(queryNode); return { text: this.output.join(' '), values: this.params }; @@ -52,8 +54,10 @@ Postgres.prototype.visit = function(node) { } }; +Postgres.prototype._quoteCharacter = '"'; Postgres.prototype.quote = function(word) { - return '"' + word + '"'; + var q = this._quoteCharacter; + return q + word.replace(q,q+q) + q; }; Postgres.prototype.visitSelect = function(select) { @@ -245,7 +249,7 @@ Postgres.prototype.visitTable = function(tableNode) { } txt += this.quote(table.getName()); if(table.alias) { - txt += ' AS ' + table.alias; + txt += ' AS ' + this.quote(table.alias); } return txt; }; @@ -256,14 +260,14 @@ Postgres.prototype.visitColumn = function(columnNode) { var txt = ""; if(inSelectClause) { if (columnNode.asArray) { - txt += 'array_agg('; + txt += this._arrayAggFunctionName+'('; } else if (columnNode.aggCount) { txt += 'COUNT('; } } if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { if(table.alias) { - txt = table.alias; + txt = this.quote(table.alias); } else { if(table.getSchema()) { txt = this.quote(table.getSchema()); @@ -282,7 +286,7 @@ Postgres.prototype.visitColumn = function(columnNode) { txt += ')'; } if(inSelectClause && columnNode.alias) { - txt += ' as ' + this.quote(columnNode.alias); + txt += ' AS ' + this.quote(columnNode.alias); } if(this._visitingCreate || this._visitingAddColumn) { assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + diff --git a/lib/table.js b/lib/table.js index 2a4100dd..b9c40530 100644 --- a/lib/table.js +++ b/lib/table.js @@ -46,10 +46,7 @@ Table.prototype.getName = function() { }; Table.prototype.star = function() { - var name = this.alias || this._name; - var Dialect = require(__dirname + '/../').dialect; - var dialect = new Dialect(); - return new TextNode(dialect.quote(name)+'.*'); + return new Column({table: this, star: true}); }; Table.prototype.count = function(alias) { From 1967e708986b3f0cc5d3b61d167374e788db14d4 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sat, 9 Mar 2013 09:58:13 +0000 Subject: [PATCH 018/507] alter tests to take quoted aliases into account, add support for testing more than one dialect, add all test cases for mysql. The test/postgres directory should probably be renamed to test/dialects --- test/index-tests.js | 2 +- test/postgres/aggregate-tests.js | 24 +++++++--- test/postgres/alter-table-tests.js | 12 +++++ test/postgres/create-table-tests.js | 2 + test/postgres/delete-tests.js | 1 + test/postgres/drop-table-tests.js | 2 + test/postgres/group-by-tests.js | 16 +++++-- test/postgres/insert-tests.js | 26 ++++++++-- test/postgres/join-tests.js | 17 +++++-- test/postgres/limit-and-offset-tests.js | 12 +++-- test/postgres/namespace-tests.js | 16 +++++-- test/postgres/order-tests.js | 9 ++-- test/postgres/schema-tests.js | 15 ++++-- test/postgres/shortcut-tests.js | 18 +++++-- test/postgres/support.js | 63 ++++++++++++++++++++----- test/postgres/table-tests.js | 53 +++++++++++++++++---- test/postgres/update-tests.js | 6 +++ 17 files changed, 230 insertions(+), 64 deletions(-) diff --git a/test/index-tests.js b/test/index-tests.js index 8d19f2b1..fe989b57 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -9,7 +9,7 @@ var user = sql.define({ }); test('unknown dialect', function(t) { - console.log('unknown dialog throws exception'); + console.log('unknown dialect throws exception'); t.throws(function() { sql.setDialect('asdf'); }); diff --git a/test/postgres/aggregate-tests.js b/test/postgres/aggregate-tests.js index 53587d68..163cbbf0 100644 --- a/test/postgres/aggregate-tests.js +++ b/test/postgres/aggregate-tests.js @@ -6,30 +6,42 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.count()), - pg : 'SELECT COUNT("post".*) as "post_count" FROM "post"' + pg : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + mysql : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', + params: [] }); Harness.test({ query : post.select(post.count('post_count')), - pg : 'SELECT COUNT("post".*) as "post_count" FROM "post"' + pg : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + msyql : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', + params: [] }); Harness.test({ query : post.select(post.count().as('post_amount')), - pg : 'SELECT COUNT("post".*) as "post_amount" FROM "post"' + pg : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + mysql : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', + params: [] }); Harness.test({ query : post.select(post.content.count()), - pg : 'SELECT COUNT("post"."content") as "content_count" FROM "post"' + pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + params: [] }); Harness.test({ query : post.select(post.content.count('content_count')), - pg : 'SELECT COUNT("post"."content") as "content_count" FROM "post"' + pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + params: [] }); Harness.test({ query : post.select(post.content.count().as('content_count')), - pg : 'SELECT COUNT("post"."content") as "content_count" FROM "post"' + pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + params: [] }); diff --git a/test/postgres/alter-table-tests.js b/test/postgres/alter-table-tests.js index 02ea81cf..d788290a 100644 --- a/test/postgres/alter-table-tests.js +++ b/test/postgres/alter-table-tests.js @@ -7,18 +7,21 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query : post.alter().dropColumn(post.content), pg : 'ALTER TABLE "post" DROP COLUMN "content"', + mysql : 'ALTER TABLE `post` DROP COLUMN `content`', params: [] }); Harness.test({ query : post.alter().dropColumn(post.content).dropColumn(post.userId), pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + mysql : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', params: [] }); Harness.test({ query : post.alter().dropColumn('content').dropColumn('userId'), pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + mysql : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', params: [] }); @@ -36,35 +39,44 @@ var group = Table.define({ Harness.test({ query : group.alter().addColumn(group.id), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', params: [] }); Harness.test({ query : group.alter().addColumn(group.id).addColumn(group.userId), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', params: [] }); Harness.test({ query : group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', params: [] }); Harness.test({ query : group.alter().renameColumn('userId', 'newUserId'), pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + mysql : { + text: 'Mysql requires data type for renaming a column', + throws: true + }, params: [] }); Harness.test({ query : group.alter().renameColumn(group.userId, 'newUserId'), pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', params: [] }); Harness.test({ query : group.alter().renameColumn('userId', group.id), pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', params: [] }); diff --git a/test/postgres/create-table-tests.js b/test/postgres/create-table-tests.js index d85c7acc..e2b88c76 100644 --- a/test/postgres/create-table-tests.js +++ b/test/postgres/create-table-tests.js @@ -17,11 +17,13 @@ var group = Table.define({ Harness.test({ query : group.create(), pg : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + mysql : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', params: [] }); Harness.test({ query : group.create().ifNotExists(), pg : 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', + mysql : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', params: [] }); \ No newline at end of file diff --git a/test/postgres/delete-tests.js b/test/postgres/delete-tests.js index 456c3a6e..256a5c6b 100644 --- a/test/postgres/delete-tests.js +++ b/test/postgres/delete-tests.js @@ -6,5 +6,6 @@ var post = Harness.definePostTable(); Harness.test({ query : post['delete']().where(post.content.equals('')), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', + mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', params: [''] }); diff --git a/test/postgres/drop-table-tests.js b/test/postgres/drop-table-tests.js index 239aa148..f8476187 100644 --- a/test/postgres/drop-table-tests.js +++ b/test/postgres/drop-table-tests.js @@ -6,11 +6,13 @@ var post = Harness.definePostTable(); Harness.test({ query : post.drop(), pg : 'DROP TABLE "post"', + mysql : 'DROP TABLE `post`', params: [] }); Harness.test({ query : post.drop().ifExists(), pg : 'DROP TABLE IF EXISTS "post"', + mysql : 'DROP TABLE IF EXISTS `post`', params: [] }); \ No newline at end of file diff --git a/test/postgres/group-by-tests.js b/test/postgres/group-by-tests.js index bfabcc69..2c643017 100644 --- a/test/postgres/group-by-tests.js +++ b/test/postgres/group-by-tests.js @@ -6,20 +6,28 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.content).group(post.userId), - pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', + params: [] }); Harness.test({ query : post.select(post.content).group(post.userId, post.id), - pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + params: [] }); Harness.test({ query : post.select(post.content.arrayAgg()).group(post.userId), - pg : 'SELECT array_agg("post"."content") as "contents" FROM "post" GROUP BY "post"."userId"' + pg : 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', + params: [] }); Harness.test({ query : post.select(post.content.arrayAgg('post contents')).group(post.userId), - pg : 'SELECT array_agg("post"."content") as "post contents" FROM "post" GROUP BY "post"."userId"' + pg : 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', + params: [] }); diff --git a/test/postgres/insert-tests.js b/test/postgres/insert-tests.js index 0494ada5..5837adbc 100644 --- a/test/postgres/insert-tests.js +++ b/test/postgres/insert-tests.js @@ -6,6 +6,7 @@ var post = Harness.definePostTable(); Harness.test({ query : post.insert(post.content.value('test'), post.userId.value(1)), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', params: ['test', 1] }); @@ -13,12 +14,14 @@ Harness.test({ Harness.test({ query : post.insert(post.content.value('whoah')), pg : 'INSERT INTO "post" ("content") VALUES ($1)', + mysql : 'INSERT INTO `post` (`content`) VALUES (?)', params: ['whoah'] }); Harness.test({ query : post.insert({content: 'test', userId: 2}), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', params: ['test', 2] }); @@ -26,12 +29,14 @@ Harness.test({ Harness.test({ query : post.insert([{content: 'whoah'}, {content: 'hey'}]), pg : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + mysql : 'INSERT INTO `post` (`content`) VALUES (?), (?)', params: ['whoah', 'hey'] }); Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey', userId: 2}]), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', params: ['whoah', 1, 'hey', 2] }); @@ -40,6 +45,7 @@ Harness.test({ Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {userId: 2, content: 'hey' }]), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', params: ['whoah', 1, 'hey', 2] }); @@ -47,14 +53,26 @@ Harness.test({ //handle missing columns Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey'}]), - pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - params: ['whoah', 1, 'hey', 'DEFAULT'] + pg : { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + params: ['whoah', 1, 'hey', 'DEFAULT'] + }, + mysql : { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', + params: ['whoah', 1, 'hey'] + } }); Harness.test({ query : post.insert([{userId: 1}, {content: 'hey', userId: 2}]), - pg : 'INSERT INTO "post" ("userId", "content") VALUES ($1, $2), ($3, $4)', - params: [1, 'DEFAULT', 2, 'hey'] + pg : { + text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, $2), ($3, $4)', + params: [1, 'DEFAULT', 2, 'hey'] + }, + mysql : { + text: 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', + params: [1, 2, 'hey'] + } }); diff --git a/test/postgres/join-tests.js b/test/postgres/join-tests.js index 34b3c81b..3b67408c 100644 --- a/test/postgres/join-tests.js +++ b/test/postgres/join-tests.js @@ -7,7 +7,8 @@ var comment = Harness.defineCommentTable(); Harness.test({ query : user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), - pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }); Harness.test({ @@ -19,12 +20,15 @@ Harness.test({ .join(comment).on(post.id.equals(comment.postId)) ), pg : '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")' + ' INNER JOIN "comment" ON ("post"."id" = "comment"."postId")', + mysql : '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`)' }); Harness.test({ query : user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), - pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' }); Harness.test({ @@ -36,7 +40,9 @@ Harness.test({ .leftJoin(comment).on(post.id.equals(comment.postId)) ), pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + - ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")' + ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' + + ' LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }); Harness.test({ @@ -48,5 +54,6 @@ Harness.test({ .select(post.content, post.userId) .from(post)) .on(user.id.equals(post.userId))), - pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" FROM "post") subposts ON ("user"."id" = "post"."userId")' + pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" FROM "post") subposts ON ("user"."id" = "post"."userId")', + mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` FROM `post`) subposts ON (`user`.`id` = `post`.`userId`)' }); diff --git a/test/postgres/limit-and-offset-tests.js b/test/postgres/limit-and-offset-tests.js index 297638dc..c9914db6 100644 --- a/test/postgres/limit-and-offset-tests.js +++ b/test/postgres/limit-and-offset-tests.js @@ -3,17 +3,23 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); +// For compatibility with PostgreSQL, MySQL also supports the LIMIT row_count OFFSET offset syntax. +// http://dev.mysql.com/doc/refman/5.0/en/select.html + Harness.test({ query : user.select(user.star()).from(user).order(user.name.asc).limit(1), - pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' + pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', + mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' }); Harness.test({ query : user.select(user.star()).from(user).order(user.name.asc).limit(3).offset(6), - pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6' + pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', + mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' }); Harness.test({ query : user.select(user.star()).from(user).order(user.name.asc).offset(10), - pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' + pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', + mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }); diff --git a/test/postgres/namespace-tests.js b/test/postgres/namespace-tests.js index 27ca9806..eaeae4fa 100644 --- a/test/postgres/namespace-tests.js +++ b/test/postgres/namespace-tests.js @@ -8,23 +8,28 @@ var post = Harness.definePostTable(); var u = user.as('u'); Harness.test({ query : u.select(u.name).from(u), - pg :'SELECT u."name" FROM "user" AS u' + pg :'SELECT "u"."name" FROM "user" AS "u"', + mysql :'SELECT `u`.`name` FROM `user` AS `u`' }); Harness.test({ query : u.select(u.star()).from(u), - pg : 'SELECT "u".* FROM "user" AS u' + pg : 'SELECT "u".* FROM "user" AS "u"', + mysql : 'SELECT `u`.* FROM `user` AS `u`' }); var p = post.as('p'); Harness.test({ query : u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), - pg : 'SELECT u."name" FROM "user" AS u INNER JOIN "post" AS p ON ((u."id" = p."userId") AND (p."id" = $1))' + pg : 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', + mysql : 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', + params : [3] }); Harness.test({ query : u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), - pg : '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))' + pg : '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))', + mysql : '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))' }); var comment = Table.define({ @@ -40,7 +45,8 @@ var comment = Table.define({ Harness.test({ query : comment.select(comment.text, comment.userId), - pg : 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + pg : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + mysql : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' }); diff --git a/test/postgres/order-tests.js b/test/postgres/order-tests.js index 4d1aedeb..78195e20 100644 --- a/test/postgres/order-tests.js +++ b/test/postgres/order-tests.js @@ -6,15 +6,18 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.content).order(post.content), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' }); Harness.test({ query : post.select(post.content).order(post.content, post.userId.descending), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)' + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)', + mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); Harness.test({ query : post.select(post.content).order(post.content.asc, post.userId.desc), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)' + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)', + mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); diff --git a/test/postgres/schema-tests.js b/test/postgres/schema-tests.js index b19afbe5..3ae643fc 100644 --- a/test/postgres/schema-tests.js +++ b/test/postgres/schema-tests.js @@ -12,18 +12,21 @@ var userWithSchema = Table.define({ Harness.test({ query : userWithSchema.select(userWithSchema.id).from(userWithSchema), - pg : 'SELECT "staging"."user"."id" FROM "staging"."user"' + pg : 'SELECT "staging"."user"."id" FROM "staging"."user"', + mysql : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' }); Harness.test({ query : userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), - pg : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + pg : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + mysql : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' }); var uws = userWithSchema.as('uws'); Harness.test({ query : uws.select(uws.name).from(uws), - pg :'SELECT uws."name" FROM "staging"."user" AS uws' + pg :'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + mysql :'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' }); var postWithSchema = Table.define({ @@ -34,10 +37,12 @@ var postWithSchema = Table.define({ Harness.test({ query : userWithSchema.select(userWithSchema.name, postWithSchema.content).from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), - pg : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")' + pg : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + mysql : 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' }); Harness.test({ query : uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), - pg : 'SELECT uws."name", "dev"."post"."content" FROM "staging"."user" AS uws INNER JOIN "dev"."post" ON (uws."id" = "dev"."post"."userId")' + pg : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + mysql : '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/postgres/shortcut-tests.js b/test/postgres/shortcut-tests.js index 0d30571f..41ece78c 100644 --- a/test/postgres/shortcut-tests.js +++ b/test/postgres/shortcut-tests.js @@ -7,28 +7,36 @@ var post = Harness.definePostTable(); //shortcut: 'select * from ' Harness.test({ query : user, - pg : 'SELECT "user".* FROM "user"' + pg : 'SELECT "user".* FROM "user"', + mysql : 'SELECT `user`.* FROM `user`' }); Harness.test({ query : user.where(user.name.equals(3)), - pg : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1)' + pg : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?)', + params : [3] }); Harness.test({ query : user.where(user.name.equals(3)).where(user.id.equals(1)), - pg : 'SELECT "user".* FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))' + pg : 'SELECT "user".* FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + mysql : 'SELECT `user`.* FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + params: [3,1] }); //shortcut: no 'from' Harness.test({ query : post.select(post.content), - pg : 'SELECT "post"."content" FROM "post"' + pg : 'SELECT "post"."content" FROM "post"', + mysql : 'SELECT `post`.`content` FROM `post`' }); Harness.test({ query : post.select(post.content).where(post.userId.equals(1)), - pg : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)' + pg : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + mysql : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', + params: [1] }); diff --git a/test/postgres/support.js b/test/postgres/support.js index b5f93130..dfb5f623 100644 --- a/test/postgres/support.js +++ b/test/postgres/support.js @@ -2,23 +2,60 @@ var tap = require('tap').test; var Postgres = require('../../lib/dialect/postgres'); +var Mysql = require('../../lib/dialect/mysql'); var Table = require(__dirname + '/../../lib/table'); +// specify dialect classes +var dialects = { + pg : require('../../lib/dialect/postgres'), + mysql : require('../../lib/dialect/mysql') +}; + module.exports = { test: function(expected) { - tap(expected.pg, function(t) { - var query = expected.query; - var pgQuery = new Postgres().getQuery(query); - var expectedPgText = expected.pg; - t.equal(pgQuery.text, expected.pg, 'Postgres text not equal\n actual: "' + pgQuery.text + '"\n expected: "' + expected.pg + '"'); - if(expected.params) { - t.equal(expected.params.length, pgQuery.values.length); - for(var i = 0; i < expected.params.length; i++) { - t.equal(expected.params[i], pgQuery.values[i]); - } - } - t.end(); - }); + + // for each dialect + Object.keys(dialects).forEach(function(dialect) { + if(expected[dialect]) { + + var DialectClass = dialects[dialect]; + + var title = DialectClass.name+': '+(expected.title || expected[dialect].text || expected[dialect]); + tap(title, function(t) { + + // check if this query is expected to throw + if(expected[dialect].throws) { + + t.throws(function() { + new DialectClass().getQuery(expected.query); + }); + + } else { + + // build query for dialect + var compiledQuery = new DialectClass().getQuery(expected.query); + + // test result is correct + var expectedText = expected[dialect].text || expected[dialect]; + t.equal(compiledQuery.text, expectedText,'query result'); + + // if params are specified then test these are correct + var expectedParams = expected[dialect].params || expected.params; + if(expectedParams) { + t.equal(expectedParams.length, compiledQuery.values.length, 'params length'); + for(var i = 0; i < expectedParams.length; i++) { + t.equal(expectedParams[i], compiledQuery.values[i], 'param '+(i+1)); + } + } + + } + t.end(); + }); + + + } // if + }); // forEach + }, defineUserTable: function () { diff --git a/test/postgres/table-tests.js b/test/postgres/table-tests.js index 52a717eb..7da1b464 100644 --- a/test/postgres/table-tests.js +++ b/test/postgres/table-tests.js @@ -5,56 +5,66 @@ var user = Harness.defineUserTable(); Harness.test({ query : user.select(user.id).from(user), - pg : 'SELECT "user"."id" FROM "user"' + pg : 'SELECT "user"."id" FROM "user"', + mysql : 'SELECT `user`.`id` FROM `user`' }); Harness.test({ query : user.select(user.id, user.name).from(user), - pg : 'SELECT "user"."id", "user"."name" FROM "user"' + pg : 'SELECT "user"."id", "user"."name" FROM "user"', + mysql : 'SELECT `user`.`id`, `user`.`name` FROM `user`' }); Harness.test({ query : user.select(user.star()).from(user), - pg : 'SELECT "user".* FROM "user"' + pg : 'SELECT "user".* FROM "user"', + mysql : 'SELECT `user`.* FROM `user`' }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo')), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', params: ['foo'] }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo').or(user.name.equals('bar'))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', params: ['foo', 'bar'] }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo').and(user.name.equals('bar'))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', params: ['foo', 'bar'] }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('bar')), - pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))' + pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))' }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('baz')).and(user.name.equals('bar')), - pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))' + pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))' }); Harness.test({ query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar'])), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', params: ['foo', 'bar'] }); Harness.test({ query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar']).and(user.id.equals(1))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', params: ['foo', 'bar', 1] }); @@ -70,31 +80,54 @@ Harness.test({ user.name.equals('bang').and(user.id.equals(2)) ), pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', + mysql : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', params: ['boom', 1, 'bang', 2] }); Harness.test({ query : user.select(user.name.as('user name'), user.id.as('user id')).from(user), - pg : 'SELECT "user"."name" as "user name", "user"."id" as "user id" FROM "user"' + pg : 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', + mysql : 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' }); Harness.test({ query : user.select(user.name.as('user name')).from(user).where(user.name.equals('brian')), - pg : 'SELECT "user"."name" as "user name" FROM "user" WHERE ("user"."name" = $1)' + pg : 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', + params: ['brian'] }); //Fix #10: prevent column state mutation Harness.test({ query : user.select(user.name).from(user).where(user.name.equals('brian')), - pg : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)' + pg : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)' }); Harness.test({ query : user.select('name').from('user').where('name <> NULL'), - pg : 'SELECT name FROM user WHERE name <> NULL' + pg : 'SELECT name FROM user WHERE name <> NULL', + mysql : 'SELECT name FROM user WHERE name <> NULL', + params: [] +}); + +Harness.test({ + query : user.select('name,id').from('user').where('name <> NULL'), + pg : 'SELECT name,id FROM user WHERE name <> NULL', + mysql : 'SELECT name,id FROM user WHERE name <> NULL', + params: [] +}); + +Harness.test({ + query : user.select('name','id').from('user').where('name <> NULL'), + pg : 'SELECT name, id FROM user WHERE name <> NULL', + mysql : 'SELECT name, id FROM user WHERE name <> NULL', + params: [] }); Harness.test({ query : user.select('name').from('user').where({name: 'brian'}), - pg : 'SELECT name FROM user WHERE ("user"."name" = $1)' + pg : 'SELECT name FROM user WHERE ("user"."name" = $1)', + mysql : 'SELECT name FROM user WHERE (`user`.`name` = ?)', + params: ['brian'] }); diff --git a/test/postgres/update-tests.js b/test/postgres/update-tests.js index b44721d8..2b922b34 100644 --- a/test/postgres/update-tests.js +++ b/test/postgres/update-tests.js @@ -7,30 +7,35 @@ var user = Harness.defineUserTable(); Harness.test({ query : post.update({content: 'test'}), pg : 'UPDATE "post" SET "content" = $1', + mysql : 'UPDATE `post` SET `content` = ?', params: ['test'] }); Harness.test({ query : post.update({content: 'test', userId: 3}), pg : 'UPDATE "post" SET "content" = $1, "userId" = $2', + mysql : 'UPDATE `post` SET `content` = ?, `userId` = ?', params: ['test', 3] }); Harness.test({ query : post.update({content: null, userId: 3}), pg : 'UPDATE "post" SET "content" = $1, "userId" = $2', + mysql : 'UPDATE `post` SET `content` = ?, `userId` = ?', params: [null, 3] }); Harness.test({ query : post.update({content: 'test', userId: 3}).where(post.content.equals('no')), pg : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + mysql : 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', params: ['test', 3, 'no'] }); Harness.test({ query : post.update({content: user.name}).from(user).where(post.userId.equals(user.id)), pg : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + mysql : 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', params: [] }); @@ -38,5 +43,6 @@ Harness.test({ Harness.test({ query : post.update({userId: user.id}).from(user).where(post.userId.equals(user.id)), pg : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + mysql : 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', params: [] }); \ No newline at end of file From 4bd577c54ef45502a69c2be2e9bc253f5172700c Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sat, 9 Mar 2013 10:10:39 +0000 Subject: [PATCH 019/507] remove duplicate requiring of dialects --- test/postgres/support.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/postgres/support.js b/test/postgres/support.js index dfb5f623..cf8b7ecf 100644 --- a/test/postgres/support.js +++ b/test/postgres/support.js @@ -1,8 +1,6 @@ 'use strict'; var tap = require('tap').test; -var Postgres = require('../../lib/dialect/postgres'); -var Mysql = require('../../lib/dialect/mysql'); var Table = require(__dirname + '/../../lib/table'); // specify dialect classes From b9a946f20ee02a6996297026ffe4f44582867cc1 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sat, 9 Mar 2013 10:17:35 +0000 Subject: [PATCH 020/507] let the tests say which dialect they are for --- test/postgres/support.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/postgres/support.js b/test/postgres/support.js index cf8b7ecf..c9935983 100644 --- a/test/postgres/support.js +++ b/test/postgres/support.js @@ -18,7 +18,7 @@ module.exports = { var DialectClass = dialects[dialect]; - var title = DialectClass.name+': '+(expected.title || expected[dialect].text || expected[dialect]); + var title = dialect+': '+(expected.title || expected[dialect].text || expected[dialect]); tap(title, function(t) { // check if this query is expected to throw From edb19ca4ff8b507afe3ea0ce2e343b99d76d9673 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sat, 9 Mar 2013 21:44:32 +0000 Subject: [PATCH 021/507] globally replace quote character in quoted identifiers, and add a test case for this --- lib/dialect/postgres.js | 2 +- test/postgres/table-tests.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 114efdb8..d185caec 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -57,7 +57,7 @@ Postgres.prototype.visit = function(node) { Postgres.prototype._quoteCharacter = '"'; Postgres.prototype.quote = function(word) { var q = this._quoteCharacter; - return q + word.replace(q,q+q) + q; + return q + word.replace(new RegExp(q,'g'),q+q) + q; }; Postgres.prototype.visitSelect = function(select) { diff --git a/test/postgres/table-tests.js b/test/postgres/table-tests.js index 7da1b464..3bc12e55 100644 --- a/test/postgres/table-tests.js +++ b/test/postgres/table-tests.js @@ -131,3 +131,10 @@ Harness.test({ mysql : 'SELECT name FROM user WHERE (`user`.`name` = ?)', params: ['brian'] }); + +Harness.test({ + query : user.select(user.name.as('quote"quote"tick`tick`')), + pg : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + mysql : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', + params: [] +}); From e5d789f0e33ae4ff70bae74dddc6310a2ae57128 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 9 Mar 2013 17:12:22 -0600 Subject: [PATCH 022/507] make all tests run via 'npm test' command --- test/index.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/index.js b/test/index.js index a75ae2d1..e346cae3 100644 --- a/test/index.js +++ b/test/index.js @@ -11,12 +11,11 @@ var directories = [ ]; directories.forEach(function (d) { - fs.readdir(d, function(err, files) { - if(err) throw err; - /*jshint boss: true */ - for(var i = 0, file; file = files[i]; i++) { - var filePath = path.join(d, file); - require(filePath); - } - }); + var files = fs.readdirSync(d); + /*jshint boss: true */ + for(var i = 0, file; file = files[i]; i++) { + var filePath = path.join(d, file); + console.log(filePath); + require(filePath); + } }); From 6d3dda68aa54a3d44092037f049acb84ad12524b Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 9 Mar 2013 17:14:25 -0600 Subject: [PATCH 023/507] rename 'postgres' dir to 'dialects' --- test/{postgres => dialects}/aggregate-tests.js | 0 test/{postgres => dialects}/alter-table-tests.js | 0 test/{postgres => dialects}/create-table-tests.js | 0 test/{postgres => dialects}/delete-tests.js | 0 test/{postgres => dialects}/drop-table-tests.js | 0 test/{postgres => dialects}/group-by-tests.js | 0 test/{postgres => dialects}/index.js | 0 test/{postgres => dialects}/insert-tests.js | 0 test/{postgres => dialects}/join-tests.js | 0 test/{postgres => dialects}/limit-and-offset-tests.js | 0 test/{postgres => dialects}/namespace-tests.js | 0 test/{postgres => dialects}/order-tests.js | 0 test/{postgres => dialects}/schema-tests.js | 0 test/{postgres => dialects}/shortcut-tests.js | 0 test/{postgres => dialects}/support.js | 0 test/{postgres => dialects}/table-tests.js | 0 test/{postgres => dialects}/update-tests.js | 0 test/index.js | 2 +- 18 files changed, 1 insertion(+), 1 deletion(-) rename test/{postgres => dialects}/aggregate-tests.js (100%) rename test/{postgres => dialects}/alter-table-tests.js (100%) rename test/{postgres => dialects}/create-table-tests.js (100%) rename test/{postgres => dialects}/delete-tests.js (100%) rename test/{postgres => dialects}/drop-table-tests.js (100%) rename test/{postgres => dialects}/group-by-tests.js (100%) rename test/{postgres => dialects}/index.js (100%) rename test/{postgres => dialects}/insert-tests.js (100%) rename test/{postgres => dialects}/join-tests.js (100%) rename test/{postgres => dialects}/limit-and-offset-tests.js (100%) rename test/{postgres => dialects}/namespace-tests.js (100%) rename test/{postgres => dialects}/order-tests.js (100%) rename test/{postgres => dialects}/schema-tests.js (100%) rename test/{postgres => dialects}/shortcut-tests.js (100%) rename test/{postgres => dialects}/support.js (100%) rename test/{postgres => dialects}/table-tests.js (100%) rename test/{postgres => dialects}/update-tests.js (100%) diff --git a/test/postgres/aggregate-tests.js b/test/dialects/aggregate-tests.js similarity index 100% rename from test/postgres/aggregate-tests.js rename to test/dialects/aggregate-tests.js diff --git a/test/postgres/alter-table-tests.js b/test/dialects/alter-table-tests.js similarity index 100% rename from test/postgres/alter-table-tests.js rename to test/dialects/alter-table-tests.js diff --git a/test/postgres/create-table-tests.js b/test/dialects/create-table-tests.js similarity index 100% rename from test/postgres/create-table-tests.js rename to test/dialects/create-table-tests.js diff --git a/test/postgres/delete-tests.js b/test/dialects/delete-tests.js similarity index 100% rename from test/postgres/delete-tests.js rename to test/dialects/delete-tests.js diff --git a/test/postgres/drop-table-tests.js b/test/dialects/drop-table-tests.js similarity index 100% rename from test/postgres/drop-table-tests.js rename to test/dialects/drop-table-tests.js diff --git a/test/postgres/group-by-tests.js b/test/dialects/group-by-tests.js similarity index 100% rename from test/postgres/group-by-tests.js rename to test/dialects/group-by-tests.js diff --git a/test/postgres/index.js b/test/dialects/index.js similarity index 100% rename from test/postgres/index.js rename to test/dialects/index.js diff --git a/test/postgres/insert-tests.js b/test/dialects/insert-tests.js similarity index 100% rename from test/postgres/insert-tests.js rename to test/dialects/insert-tests.js diff --git a/test/postgres/join-tests.js b/test/dialects/join-tests.js similarity index 100% rename from test/postgres/join-tests.js rename to test/dialects/join-tests.js diff --git a/test/postgres/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js similarity index 100% rename from test/postgres/limit-and-offset-tests.js rename to test/dialects/limit-and-offset-tests.js diff --git a/test/postgres/namespace-tests.js b/test/dialects/namespace-tests.js similarity index 100% rename from test/postgres/namespace-tests.js rename to test/dialects/namespace-tests.js diff --git a/test/postgres/order-tests.js b/test/dialects/order-tests.js similarity index 100% rename from test/postgres/order-tests.js rename to test/dialects/order-tests.js diff --git a/test/postgres/schema-tests.js b/test/dialects/schema-tests.js similarity index 100% rename from test/postgres/schema-tests.js rename to test/dialects/schema-tests.js diff --git a/test/postgres/shortcut-tests.js b/test/dialects/shortcut-tests.js similarity index 100% rename from test/postgres/shortcut-tests.js rename to test/dialects/shortcut-tests.js diff --git a/test/postgres/support.js b/test/dialects/support.js similarity index 100% rename from test/postgres/support.js rename to test/dialects/support.js diff --git a/test/postgres/table-tests.js b/test/dialects/table-tests.js similarity index 100% rename from test/postgres/table-tests.js rename to test/dialects/table-tests.js diff --git a/test/postgres/update-tests.js b/test/dialects/update-tests.js similarity index 100% rename from test/postgres/update-tests.js rename to test/dialects/update-tests.js diff --git a/test/index.js b/test/index.js index e346cae3..15d573f0 100644 --- a/test/index.js +++ b/test/index.js @@ -7,7 +7,7 @@ var testDir = path.dirname(require.main.filename); var directories = [ testDir, - testDir + '/postgres' + testDir + '/dialects' ]; directories.forEach(function (d) { From 0ca6445b041cfe8241cd77e0ad40ee103e26740f Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 9 Mar 2013 17:14:41 -0600 Subject: [PATCH 024/507] version bump - add mysql support --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a59b3a0..2f0c4850 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.2.4", + "version": "0.3.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From de4fb98266a4af74ea07e9e925aa0474e4bafa77 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sun, 10 Mar 2013 13:05:12 +0000 Subject: [PATCH 025/507] add beginnings for sqlite dialect --- lib/dialect/sqlite.js | 19 +++++++++++++++++++ lib/index.js | 3 +++ 2 files changed, 22 insertions(+) create mode 100644 lib/dialect/sqlite.js diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js new file mode 100644 index 00000000..1480f416 --- /dev/null +++ b/lib/dialect/sqlite.js @@ -0,0 +1,19 @@ +'use strict'; + +var util = require('util'); + +var Sqlite = function() { + this.output = []; + this.params = []; +}; + +util.inherits(Sqlite, require(__dirname + '/mysql')); + +Sqlite.prototype._quoteCharacter = '"'; + +Sqlite.prototype.visitRenameColumn = function(renameColumn) { + throw new Error(' (CHANGE COLUMN statements require a dataType)'); +}; + + +module.exports = Sqlite; diff --git a/lib/index.js b/lib/index.js index 172ebfe6..7e011337 100644 --- a/lib/index.js +++ b/lib/index.js @@ -19,6 +19,9 @@ var sql = { case 'mysql': this.dialect = require(__dirname + '/dialect/mysql'); break; + case 'sqlite': + this.dialect = require(__dirname + '/dialect/sqlite'); + break; default: throw new Error(dialect + ' is unsupported'); } From 5d2c302e050c8c8184cce38c48f65af182c9898f Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sun, 10 Mar 2013 13:06:29 +0000 Subject: [PATCH 026/507] add error message for renaming column --- lib/dialect/sqlite.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 1480f416..2e940144 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -12,7 +12,7 @@ util.inherits(Sqlite, require(__dirname + '/mysql')); Sqlite.prototype._quoteCharacter = '"'; Sqlite.prototype.visitRenameColumn = function(renameColumn) { - throw new Error(' (CHANGE COLUMN statements require a dataType)'); + throw new Error('SQLite does not allow renaming columns'); }; From a882f30722b1c96d91d3ce5851d6053e1d83ae9c Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Sun, 10 Mar 2013 21:12:55 +0000 Subject: [PATCH 027/507] base sqlite on postgres, instead of mysql. throw errors for unsupported features. --- lib/dialect/sqlite.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 2e940144..fb6fa7ac 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -7,13 +7,36 @@ var Sqlite = function() { this.params = []; }; -util.inherits(Sqlite, require(__dirname + '/mysql')); +util.inherits(Sqlite, require(__dirname + '/postgres')); -Sqlite.prototype._quoteCharacter = '"'; +Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; + +Sqlite.prototype.visitDefault = function(parameter) { + throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.'); +}; + +Sqlite.prototype.visitOrderByColumn = function(column) { + if(column.direction) { + return this.visit(column.column) + ' ' + this.visit(column.direction); + } else { + return this.visit(column.column); + } +}; + +Sqlite.prototype.visitDropColumn = function(dropColumn) { + throw new Error('SQLite does not allow dropping columns.'); +}; Sqlite.prototype.visitRenameColumn = function(renameColumn) { - throw new Error('SQLite does not allow renaming columns'); + throw new Error('SQLite does not allow renaming columns.'); +}; + +Sqlite.prototype.visitIfExists = function() { + throw new Error('SQLite does not support IF EXISTS.'); }; +Sqlite.prototype.visitIfNotExists = function() { + throw new Error('SQLite does not support IF NOT EXISTS.'); +}; module.exports = Sqlite; From 70252ff8868b8bd0dba9ebe68ff00fde425b41ae Mon Sep 17 00:00:00 2001 From: Casey Foster Date: Sun, 10 Mar 2013 17:28:22 -0500 Subject: [PATCH 028/507] Add DEFAULT VALUES support for PG INSERT --- lib/dialect/mysql.js | 9 ++++++++- lib/dialect/postgres.js | 4 ++++ test/dialects/insert-tests.js | 12 ++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index b7a58715..67c4e22f 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -8,7 +8,9 @@ var Mysql = function() { this.params = []; }; -util.inherits(Mysql, require(__dirname + '/postgres')); +var Postgres = require(__dirname + '/postgres'); + +util.inherits(Mysql, Postgres); Mysql.prototype._quoteCharacter = '`'; @@ -38,5 +40,10 @@ Mysql.prototype.visitRenameColumn = function(renameColumn) { 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; +}; module.exports = Mysql; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d185caec..15804dec 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -87,6 +87,10 @@ Postgres.prototype.visitInsert = function(insert) { '(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')', 'VALUES', paramNodes ]; + + if (result.slice(2, 5).join(' ') === '() VALUES ()') { + result.splice(2, 3, 'DEFAULT VALUES'); + } return result; }; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 5837adbc..c1c6b5e3 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -75,4 +75,16 @@ Harness.test({ } }); +Harness.test({ + query : post.insert({}), + pg : { + text: 'INSERT INTO "post" DEFAULT VALUES', + params: [] + }, + mysql : { + text: 'INSERT INTO `post` () VALUES ()', + params: [] + } +}); + From 250f5ecb50df65e042f5616b0d101a7d3702cf74 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Mon, 11 Mar 2013 09:31:17 +0000 Subject: [PATCH 029/507] sqlite dialect and all sqlite tests. subqueries can now have their columns selected as tables --- lib/dialect/mysql.js | 2 ++ lib/dialect/postgres.js | 26 +++++++++---------- lib/dialect/sqlite.js | 10 ++------ lib/node/index.js | 3 +++ lib/node/query.js | 16 ++++++++++++ test/dialects/aggregate-tests.js | 6 +++++ test/dialects/alter-table-tests.js | 33 +++++++++++++++++++++++++ test/dialects/create-table-tests.js | 2 ++ test/dialects/delete-tests.js | 1 + test/dialects/drop-table-tests.js | 2 ++ test/dialects/group-by-tests.js | 4 +++ test/dialects/insert-tests.js | 14 +++++++++++ test/dialects/join-tests.js | 27 ++++++++++++++++++++ test/dialects/limit-and-offset-tests.js | 3 +++ test/dialects/namespace-tests.js | 7 ++++++ test/dialects/order-tests.js | 3 +++ test/dialects/schema-tests.js | 5 ++++ test/dialects/shortcut-tests.js | 5 ++++ test/dialects/table-tests.js | 18 ++++++++++++++ test/dialects/update-tests.js | 8 +++++- 20 files changed, 173 insertions(+), 22 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index b7a58715..84ada39d 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -10,6 +10,8 @@ var Mysql = function() { util.inherits(Mysql, require(__dirname + '/postgres')); +Mysql.prototype._myClass = Mysql; + Mysql.prototype._quoteCharacter = '`'; Mysql.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d185caec..16ddc6da 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -9,6 +9,8 @@ var Postgres = function() { this.params = []; }; +Postgres.prototype._myClass = Postgres; + Postgres.prototype._arrayAggFunctionName = 'array_agg'; Postgres.prototype.getQuery = function(queryNode) { @@ -223,20 +225,18 @@ Postgres.prototype.visitQuery = function(queryNode) { }; Postgres.prototype.visitSubquery = function(queryNode) { - var result = []; - for(var i = 0; i < queryNode.nodes.length; i ++) { - var res = this.visit(queryNode.nodes[i]); - result = result.concat(res); - } - //implicit 'from' - if(!this._visitedFrom) { - var select = result.slice(0, this._selectOrDeleteEndIndex); - var from = this.visitFrom(new From().add(queryNode.table.toNode())); - var rest = result.slice(this._selectOrDeleteEndIndex); - result = select.concat(from).concat(rest); - } + var subQuery = new this._myClass(); + subQuery.visitQuery(queryNode); + this.params = this.params.concat(subQuery.params); + + var result = subQuery.output; + result[0] = '('+result[0]; - result[result.length-1] = result[result.length-1] + ') ' + queryNode.alias; + result[result.length-1] = result[result.length-1] + ')'; + if(queryNode.alias) { + result[result.length-1] = result[result.length-1] + ' ' + queryNode.alias; + } + return result; }; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index fb6fa7ac..ddd5d970 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -9,6 +9,8 @@ var Sqlite = function() { util.inherits(Sqlite, require(__dirname + '/postgres')); +Sqlite.prototype._myClass = Sqlite; + Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; Sqlite.prototype.visitDefault = function(parameter) { @@ -31,12 +33,4 @@ Sqlite.prototype.visitRenameColumn = function(renameColumn) { throw new Error('SQLite does not allow renaming columns.'); }; -Sqlite.prototype.visitIfExists = function() { - throw new Error('SQLite does not support IF EXISTS.'); -}; - -Sqlite.prototype.visitIfNotExists = function() { - throw new Error('SQLite does not support IF NOT EXISTS.'); -}; - module.exports = Sqlite; diff --git a/lib/node/index.js b/lib/node/index.js index 6eb8ad25..f0f4fb9f 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,5 +1,7 @@ 'use strict'; +var assert = require('assert'); + var Node = function(type) { this.nodes = []; }; @@ -9,6 +11,7 @@ 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()); return this; }; diff --git a/lib/node/query.js b/lib/node/query.js index a449a067..16153066 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -41,8 +41,24 @@ var Query = Node.define({ //arg could be a column instead of a node select.add(args[i]); } + // if this is a subquery then add reference to this column + if(this.type === 'SUBQUERY') { + for(var j = 0; j < select.nodes.length; j++) { + var name = select.nodes[j].alias || select.nodes[j].name; + var col = new Column(select.nodes[j]); + col.name = name; + col.table = this; + if( this[name] === undefined ) { + this[name] = col; + } + } + } return this.add(select); }, + star: function() { + assert( this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); + return new Column({table: this, star: true}); + }, from: function(tableNode) { var from = new From().add(tableNode); return this.add(from); diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 163cbbf0..494862d8 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -7,6 +7,7 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.count()), pg : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + sqlite: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', mysql : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', params: [] }); @@ -14,6 +15,7 @@ Harness.test({ Harness.test({ query : post.select(post.count('post_count')), pg : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + sqlite: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', msyql : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', params: [] }); @@ -21,6 +23,7 @@ Harness.test({ Harness.test({ query : post.select(post.count().as('post_amount')), pg : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + sqlite: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', mysql : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', params: [] }); @@ -28,6 +31,7 @@ Harness.test({ Harness.test({ query : post.select(post.content.count()), pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + sqlite: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', params: [] }); @@ -35,6 +39,7 @@ Harness.test({ Harness.test({ query : post.select(post.content.count('content_count')), pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + sqlite: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', params: [] }); @@ -42,6 +47,7 @@ Harness.test({ Harness.test({ query : post.select(post.content.count().as('content_count')), pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + sqlite: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', params: [] }); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index d788290a..14542572 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -7,6 +7,10 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query : post.alter().dropColumn(post.content), pg : 'ALTER TABLE "post" DROP COLUMN "content"', + sqlite: { + text : 'Sqlite cannot drop columns', + throws: true + }, mysql : 'ALTER TABLE `post` DROP COLUMN `content`', params: [] }); @@ -14,6 +18,10 @@ Harness.test({ Harness.test({ query : post.alter().dropColumn(post.content).dropColumn(post.userId), pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + sqlite: { + text : 'Sqlite cannot drop columns', + throws: true + }, mysql : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', params: [] }); @@ -21,6 +29,10 @@ Harness.test({ Harness.test({ query : post.alter().dropColumn('content').dropColumn('userId'), pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + sqlite: { + text : 'Sqlite cannot drop columns', + throws: true + }, mysql : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', params: [] }); @@ -39,6 +51,7 @@ var group = Table.define({ Harness.test({ query : group.alter().addColumn(group.id), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + sqlite: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', params: [] }); @@ -46,6 +59,10 @@ Harness.test({ Harness.test({ query : group.alter().addColumn(group.id).addColumn(group.userId), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + sqlite: { + text : 'Sqlite cannot add more than one column at a time', + throws: true + }, mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', params: [] }); @@ -53,6 +70,10 @@ Harness.test({ Harness.test({ query : group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + sqlite: { + text : 'Sqlite cannot add more than one column at a time', + throws: true + }, mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', params: [] }); @@ -64,12 +85,20 @@ Harness.test({ text: 'Mysql requires data type for renaming a column', throws: true }, + sqlite: { + text : 'Sqlite cannot rename columns', + throws: true + }, params: [] }); Harness.test({ query : group.alter().renameColumn(group.userId, 'newUserId'), pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + sqlite: { + text : 'Sqlite cannot rename columns', + throws: true + }, mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', params: [] }); @@ -77,6 +106,10 @@ Harness.test({ Harness.test({ query : group.alter().renameColumn('userId', group.id), pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + sqlite: { + text : 'Sqlite cannot rename columns', + throws: true + }, mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', params: [] }); diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index e2b88c76..0d17b05c 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -17,6 +17,7 @@ var group = Table.define({ Harness.test({ query : group.create(), pg : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + sqlite: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', mysql : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', params: [] }); @@ -24,6 +25,7 @@ Harness.test({ Harness.test({ query : group.create().ifNotExists(), pg : 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', + sqlite: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', mysql : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', params: [] }); \ No newline at end of file diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 256a5c6b..5e6fa435 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -6,6 +6,7 @@ var post = Harness.definePostTable(); Harness.test({ query : post['delete']().where(post.content.equals('')), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', + sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', params: [''] }); diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index f8476187..eb07196d 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -6,6 +6,7 @@ var post = Harness.definePostTable(); Harness.test({ query : post.drop(), pg : 'DROP TABLE "post"', + sqlite: 'DROP TABLE "post"', mysql : 'DROP TABLE `post`', params: [] }); @@ -13,6 +14,7 @@ Harness.test({ Harness.test({ query : post.drop().ifExists(), pg : 'DROP TABLE IF EXISTS "post"', + sqlite: 'DROP TABLE IF EXISTS "post"', mysql : 'DROP TABLE IF EXISTS `post`', params: [] }); \ No newline at end of file diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index 2c643017..383425bb 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -7,6 +7,7 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.content).group(post.userId), pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + sqlite: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', params: [] }); @@ -14,6 +15,7 @@ Harness.test({ Harness.test({ query : post.select(post.content).group(post.userId, post.id), pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + sqlite: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', params: [] }); @@ -21,6 +23,7 @@ Harness.test({ Harness.test({ query : post.select(post.content.arrayAgg()).group(post.userId), pg : 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + sqlite: 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', params: [] }); @@ -28,6 +31,7 @@ Harness.test({ Harness.test({ query : post.select(post.content.arrayAgg('post contents')).group(post.userId), pg : 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + sqlite: 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', params: [] }); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 5837adbc..77b1bb32 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -6,6 +6,7 @@ var post = Harness.definePostTable(); Harness.test({ query : post.insert(post.content.value('test'), post.userId.value(1)), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', params: ['test', 1] }); @@ -14,6 +15,7 @@ Harness.test({ Harness.test({ query : post.insert(post.content.value('whoah')), pg : 'INSERT INTO "post" ("content") VALUES ($1)', + sqlite: 'INSERT INTO "post" ("content") VALUES ($1)', mysql : 'INSERT INTO `post` (`content`) VALUES (?)', params: ['whoah'] }); @@ -21,6 +23,7 @@ Harness.test({ Harness.test({ query : post.insert({content: 'test', userId: 2}), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', params: ['test', 2] }); @@ -29,6 +32,7 @@ Harness.test({ Harness.test({ query : post.insert([{content: 'whoah'}, {content: 'hey'}]), pg : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + sqlite: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', mysql : 'INSERT INTO `post` (`content`) VALUES (?), (?)', params: ['whoah', 'hey'] }); @@ -36,6 +40,7 @@ Harness.test({ Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey', userId: 2}]), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', params: ['whoah', 1, 'hey', 2] }); @@ -45,6 +50,7 @@ Harness.test({ Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {userId: 2, content: 'hey' }]), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', params: ['whoah', 1, 'hey', 2] }); @@ -57,6 +63,10 @@ Harness.test({ text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', params: ['whoah', 1, 'hey', 'DEFAULT'] }, + sqlite: { + text: 'Sqlite requires the same number of columns in each insert row', + throws: true + }, mysql : { text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', params: ['whoah', 1, 'hey'] @@ -69,6 +79,10 @@ Harness.test({ text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, $2), ($3, $4)', params: [1, 'DEFAULT', 2, 'hey'] }, + sqlite: { + text: 'Sqlite requires the same number of columns in each insert row', + throws: true + }, mysql : { text: 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', params: [1, 2, 'hey'] diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index 3b67408c..5858a851 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -8,6 +8,7 @@ var comment = Harness.defineCommentTable(); Harness.test({ query : user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }); @@ -21,6 +22,8 @@ Harness.test({ ), pg : '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")', + sqlite: '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")', mysql : '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`)' }); @@ -28,6 +31,7 @@ Harness.test({ Harness.test({ query : user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + sqlite: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' }); @@ -41,10 +45,13 @@ Harness.test({ ), pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + sqlite: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + + ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' + ' LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }); +// this query won't create valid SQL because post is joined as subposts Harness.test({ query : user .select(user.name, post.content) @@ -55,5 +62,25 @@ Harness.test({ .from(post)) .on(user.id.equals(post.userId))), pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" FROM "post") subposts ON ("user"."id" = "post"."userId")', + sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" FROM "post") subposts ON ("user"."id" = "post"."userId")', mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` FROM `post`) subposts ON (`user`.`id` = `post`.`userId`)' }); + +// this would be the correct way to use a subquery +var subposts = post + .subQuery('subposts') + .select( + post.content.as('subpostContent'), + post.userId.as('subpostUserId')) + .from(post); + +Harness.test({ + query : user + .select(user.name, subposts.subpostContent) + .from(user.join(subposts) + .on(user.id.equals(subposts.subpostUserId))), + pg : 'SELECT "user"."name", "subposts"."subpostContent" FROM "user" INNER JOIN (SELECT "post"."content" AS "subpostContent", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")', + sqlite: 'SELECT "user"."name", "subposts"."subpostContent" FROM "user" INNER JOIN (SELECT "post"."content" AS "subpostContent", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")', + mysql : 'SELECT `user`.`name`, `subposts`.`subpostContent` FROM `user` INNER JOIN (SELECT `post`.`content` AS `subpostContent`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)' +}); + diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js index c9914db6..d09e1001 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -9,17 +9,20 @@ var user = Harness.defineUserTable(); Harness.test({ query : user.select(user.star()).from(user).order(user.name.asc).limit(1), pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', + sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' }); Harness.test({ query : user.select(user.star()).from(user).order(user.name.asc).limit(3).offset(6), pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', + sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' }); Harness.test({ query : user.select(user.star()).from(user).order(user.name.asc).offset(10), pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', + sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }); diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index eaeae4fa..9146ff99 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -9,12 +9,14 @@ var u = user.as('u'); Harness.test({ query : u.select(u.name).from(u), pg :'SELECT "u"."name" FROM "user" AS "u"', + sqlite:'SELECT "u"."name" FROM "user" AS "u"', mysql :'SELECT `u`.`name` FROM `user` AS `u`' }); Harness.test({ query : u.select(u.star()).from(u), pg : 'SELECT "u".* FROM "user" AS "u"', + sqlite: 'SELECT "u".* FROM "user" AS "u"', mysql : 'SELECT `u`.* FROM `user` AS `u`' }); @@ -22,6 +24,7 @@ var p = post.as('p'); Harness.test({ query : u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), pg : 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', + sqlite: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', mysql : 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', params : [3] }); @@ -29,9 +32,12 @@ Harness.test({ Harness.test({ query : u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), pg : '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))', + sqlite: '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))', mysql : '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))' }); + +// the quote property isn't implemented for columns, so all columns are quoted in generated queries var comment = Table.define({ name: 'comment', columns: [{ @@ -46,6 +52,7 @@ var comment = Table.define({ Harness.test({ query : comment.select(comment.text, comment.userId), pg : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + sqlite: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', mysql : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' }); diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 78195e20..65c619f4 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -7,17 +7,20 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.content).order(post.content), pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' }); Harness.test({ query : post.select(post.content).order(post.content, post.userId.descending), pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)', + sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); Harness.test({ query : post.select(post.content).order(post.content.asc, post.userId.desc), pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)', + sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index 3ae643fc..347cea7b 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -13,12 +13,14 @@ var userWithSchema = Table.define({ Harness.test({ query : userWithSchema.select(userWithSchema.id).from(userWithSchema), pg : 'SELECT "staging"."user"."id" FROM "staging"."user"', + sqlite: 'SELECT "staging"."user"."id" FROM "staging"."user"', mysql : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' }); Harness.test({ query : userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), pg : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + sqlite: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', mysql : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' }); @@ -26,6 +28,7 @@ var uws = userWithSchema.as('uws'); Harness.test({ query : uws.select(uws.name).from(uws), pg :'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + sqlite:'SELECT "uws"."name" FROM "staging"."user" AS "uws"', mysql :'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' }); @@ -38,11 +41,13 @@ var postWithSchema = Table.define({ Harness.test({ query : userWithSchema.select(userWithSchema.name, postWithSchema.content).from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), pg : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + sqlite: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', mysql : 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' }); Harness.test({ query : uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), pg : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + sqlite: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', mysql : '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/shortcut-tests.js b/test/dialects/shortcut-tests.js index 41ece78c..0a51dcef 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -8,12 +8,14 @@ var post = Harness.definePostTable(); Harness.test({ query : user, pg : 'SELECT "user".* FROM "user"', + sqlite: 'SELECT "user".* FROM "user"', mysql : 'SELECT `user`.* FROM `user`' }); Harness.test({ query : user.where(user.name.equals(3)), pg : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1)', mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?)', params : [3] }); @@ -21,6 +23,7 @@ Harness.test({ Harness.test({ query : user.where(user.name.equals(3)).where(user.id.equals(1)), pg : 'SELECT "user".* FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + sqlite: 'SELECT "user".* FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', mysql : 'SELECT `user`.* FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', params: [3,1] }); @@ -29,12 +32,14 @@ Harness.test({ Harness.test({ query : post.select(post.content), pg : 'SELECT "post"."content" FROM "post"', + sqlite: 'SELECT "post"."content" FROM "post"', mysql : 'SELECT `post`.`content` FROM `post`' }); Harness.test({ query : post.select(post.content).where(post.userId.equals(1)), pg : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + sqlite: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', mysql : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', params: [1] }); diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 3bc12e55..5492d4df 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -6,24 +6,28 @@ var user = Harness.defineUserTable(); Harness.test({ query : user.select(user.id).from(user), pg : 'SELECT "user"."id" FROM "user"', + sqlite: 'SELECT "user"."id" FROM "user"', mysql : 'SELECT `user`.`id` FROM `user`' }); Harness.test({ query : user.select(user.id, user.name).from(user), pg : 'SELECT "user"."id", "user"."name" FROM "user"', + sqlite: 'SELECT "user"."id", "user"."name" FROM "user"', mysql : 'SELECT `user`.`id`, `user`.`name` FROM `user`' }); Harness.test({ query : user.select(user.star()).from(user), pg : 'SELECT "user".* FROM "user"', + sqlite: 'SELECT "user".* FROM "user"', mysql : 'SELECT `user`.* FROM `user`' }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo')), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', params: ['foo'] }); @@ -31,6 +35,7 @@ Harness.test({ Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo').or(user.name.equals('bar'))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', params: ['foo', 'bar'] }); @@ -38,6 +43,7 @@ Harness.test({ Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo').and(user.name.equals('bar'))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', params: ['foo', 'bar'] }); @@ -45,18 +51,21 @@ Harness.test({ Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('bar')), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))' }); Harness.test({ query : user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('baz')).and(user.name.equals('bar')), pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', mysql : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))' }); Harness.test({ query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar'])), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', params: ['foo', 'bar'] }); @@ -64,6 +73,7 @@ Harness.test({ Harness.test({ query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar']).and(user.id.equals(1))), pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', params: ['foo', 'bar', 1] }); @@ -80,6 +90,7 @@ Harness.test({ user.name.equals('bang').and(user.id.equals(2)) ), pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', + sqlite: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', mysql : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', params: ['boom', 1, 'bang', 2] }); @@ -87,12 +98,14 @@ Harness.test({ Harness.test({ query : user.select(user.name.as('user name'), user.id.as('user id')).from(user), pg : 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', + sqlite: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', mysql : 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' }); Harness.test({ query : user.select(user.name.as('user name')).from(user).where(user.name.equals('brian')), pg : 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', mysql : 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', params: ['brian'] }); @@ -101,12 +114,14 @@ Harness.test({ Harness.test({ query : user.select(user.name).from(user).where(user.name.equals('brian')), pg : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', mysql : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)' }); Harness.test({ query : user.select('name').from('user').where('name <> NULL'), pg : 'SELECT name FROM user WHERE name <> NULL', + sqlite: 'SELECT name FROM user WHERE name <> NULL', mysql : 'SELECT name FROM user WHERE name <> NULL', params: [] }); @@ -114,6 +129,7 @@ Harness.test({ Harness.test({ query : user.select('name,id').from('user').where('name <> NULL'), pg : 'SELECT name,id FROM user WHERE name <> NULL', + sqlite: 'SELECT name,id FROM user WHERE name <> NULL', mysql : 'SELECT name,id FROM user WHERE name <> NULL', params: [] }); @@ -128,6 +144,7 @@ Harness.test({ Harness.test({ query : user.select('name').from('user').where({name: 'brian'}), pg : 'SELECT name FROM user WHERE ("user"."name" = $1)', + sqlite: 'SELECT name FROM user WHERE ("user"."name" = $1)', mysql : 'SELECT name FROM user WHERE (`user`.`name` = ?)', params: ['brian'] }); @@ -135,6 +152,7 @@ Harness.test({ Harness.test({ query : user.select(user.name.as('quote"quote"tick`tick`')), pg : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + sqlite: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', mysql : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', params: [] }); diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index 2b922b34..1e649fd7 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -7,6 +7,7 @@ var user = Harness.defineUserTable(); Harness.test({ query : post.update({content: 'test'}), pg : 'UPDATE "post" SET "content" = $1', + sqlite: 'UPDATE "post" SET "content" = $1', mysql : 'UPDATE `post` SET `content` = ?', params: ['test'] }); @@ -14,6 +15,7 @@ Harness.test({ Harness.test({ query : post.update({content: 'test', userId: 3}), pg : 'UPDATE "post" SET "content" = $1, "userId" = $2', + sqlite: 'UPDATE "post" SET "content" = $1, "userId" = $2', mysql : 'UPDATE `post` SET `content` = ?, `userId` = ?', params: ['test', 3] }); @@ -21,6 +23,7 @@ Harness.test({ Harness.test({ query : post.update({content: null, userId: 3}), pg : 'UPDATE "post" SET "content" = $1, "userId" = $2', + sqlite: 'UPDATE "post" SET "content" = $1, "userId" = $2', mysql : 'UPDATE `post` SET `content` = ?, `userId` = ?', params: [null, 3] }); @@ -28,12 +31,14 @@ Harness.test({ Harness.test({ query : post.update({content: 'test', userId: 3}).where(post.content.equals('no')), pg : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + sqlite: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', mysql : 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', params: ['test', 3, 'no'] }); Harness.test({ query : post.update({content: user.name}).from(user).where(post.userId.equals(user.id)), + sqlite: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', pg : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', mysql : 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', params: [] @@ -43,6 +48,7 @@ Harness.test({ Harness.test({ query : post.update({userId: user.id}).from(user).where(post.userId.equals(user.id)), pg : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + sqlite: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', mysql : 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', params: [] -}); \ No newline at end of file +}); From 7784a9eaf37392d314e49405196490e9efa50785 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Mon, 11 Mar 2013 17:59:17 +0000 Subject: [PATCH 030/507] SQLite cannot add more than one column per alter table statement. Call sqlite tests. --- lib/dialect/sqlite.js | 13 ++++++++++++- test/dialects/support.js | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index ddd5d970..23bb74ca 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -1,13 +1,17 @@ 'use strict'; var util = require('util'); +var assert = require('assert'); var Sqlite = function() { this.output = []; this.params = []; + this._hasAddedAColumn = false; }; -util.inherits(Sqlite, require(__dirname + '/postgres')); +var Postgres = require(__dirname + '/postgres'); + +util.inherits(Sqlite, Postgres); Sqlite.prototype._myClass = Sqlite; @@ -33,4 +37,11 @@ Sqlite.prototype.visitRenameColumn = function(renameColumn) { throw new Error('SQLite does not allow renaming columns.'); }; +Sqlite.prototype.visitAddColumn = function(addColumn) { + assert(!this._hasAddedAColumn, 'SQLite can not add more that one column at a time'); + var result = Postgres.prototype.visitAddColumn.call(this, addColumn); + this._hasAddedAColumn = true; + return result; +}; + module.exports = Sqlite; diff --git a/test/dialects/support.js b/test/dialects/support.js index c9935983..33337c9d 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -6,6 +6,7 @@ var Table = require(__dirname + '/../../lib/table'); // specify dialect classes var dialects = { pg : require('../../lib/dialect/postgres'), + sqlite: require('../../lib/dialect/sqlite'), mysql : require('../../lib/dialect/mysql') }; From cdf51d9dcd15aea3d3f6729dd63732de11c43fa4 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Fri, 15 Mar 2013 10:57:16 +0000 Subject: [PATCH 031/507] change test case to give a varied sub post request with and without AS --- test/dialects/join-tests.js | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index 5858a851..4edabad9 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -51,36 +51,20 @@ Harness.test({ ' LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' }); -// this query won't create valid SQL because post is joined as subposts -Harness.test({ - query : user - .select(user.name, post.content) - .from(user.join( - post - .subQuery('subposts') - .select(post.content, post.userId) - .from(post)) - .on(user.id.equals(post.userId))), - pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" FROM "post") subposts ON ("user"."id" = "post"."userId")', - sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN (SELECT "post"."content", "post"."userId" FROM "post") subposts ON ("user"."id" = "post"."userId")', - mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` FROM `post`) subposts ON (`user`.`id` = `post`.`userId`)' -}); - -// this would be the correct way to use a subquery var subposts = post .subQuery('subposts') .select( - post.content.as('subpostContent'), + post.content, post.userId.as('subpostUserId')) .from(post); Harness.test({ query : user - .select(user.name, subposts.subpostContent) + .select(user.name, subposts.content) .from(user.join(subposts) .on(user.id.equals(subposts.subpostUserId))), - pg : 'SELECT "user"."name", "subposts"."subpostContent" FROM "user" INNER JOIN (SELECT "post"."content" AS "subpostContent", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")', - sqlite: 'SELECT "user"."name", "subposts"."subpostContent" FROM "user" INNER JOIN (SELECT "post"."content" AS "subpostContent", "post"."userId" AS "subpostUserId" FROM "post") subposts ON ("user"."id" = "subposts"."subpostUserId")', - mysql : 'SELECT `user`.`name`, `subposts`.`subpostContent` FROM `user` INNER JOIN (SELECT `post`.`content` AS `subpostContent`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)' + pg : '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: '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 : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `subposts`.`subpostUserId`)' }); From e201e00dd5c2e56dc3e7c56a550f7e89a81f9e32 Mon Sep 17 00:00:00 2001 From: Paul Winkler Date: Fri, 15 Mar 2013 11:15:59 +0000 Subject: [PATCH 032/507] Allow arbitrary SQL text as TextNode in where / and / or clauses and surround by brackets --- lib/node/query.js | 2 +- lib/node/where.js | 8 ++++++-- test/dialects/table-tests.js | 25 +++++++++++++++++-------- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 16153066..01c75632 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -70,7 +70,7 @@ var Query = Node.define({ //calling #where twice functions like calling #where & then #and if(this.whereClause) return this.and(node); this.whereClause = new Where(); - this.whereClause.add(node); + this.whereClause.add( this.whereClause.expr(node) ); return this.add(this.whereClause); }, _whereObject: function(node) { diff --git a/lib/node/where.js b/lib/node/where.js index ee26511c..842ab91d 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,20 +1,24 @@ 'use strict'; var BinaryNode = require(__dirname + '/binary'); +var TextNode = require(__dirname + '/text'); module.exports = require(__dirname).define({ type: 'WHERE', + expr: function(other) { + return typeof other === 'string' ? new TextNode('('+other+')') : other; + }, or: function(other) { return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'OR', - right: other + right: this.expr(other) })); }, and: function(other) { return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'AND', - right: other + right: this.expr(other) })); } }); diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 5492d4df..381ca4e2 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -120,24 +120,33 @@ Harness.test({ Harness.test({ query : user.select('name').from('user').where('name <> NULL'), - pg : 'SELECT name FROM user WHERE name <> NULL', - sqlite: 'SELECT name FROM user WHERE name <> NULL', - mysql : 'SELECT name FROM user WHERE name <> NULL', + pg : 'SELECT name FROM user WHERE (name <> NULL)', + sqlite: 'SELECT name FROM user WHERE (name <> NULL)', + mysql : 'SELECT name FROM user WHERE (name <> NULL)', params: [] }); Harness.test({ query : user.select('name,id').from('user').where('name <> NULL'), - pg : 'SELECT name,id FROM user WHERE name <> NULL', - sqlite: 'SELECT name,id FROM user WHERE name <> NULL', - mysql : 'SELECT name,id FROM user WHERE name <> NULL', + pg : 'SELECT name,id FROM user WHERE (name <> NULL)', + sqlite: 'SELECT name,id FROM user WHERE (name <> NULL)', + mysql : 'SELECT name,id FROM user WHERE (name <> NULL)', params: [] }); Harness.test({ query : user.select('name','id').from('user').where('name <> NULL'), - pg : 'SELECT name, id FROM user WHERE name <> NULL', - mysql : 'SELECT name, id FROM user WHERE name <> NULL', + pg : 'SELECT name, id FROM user WHERE (name <> NULL)', + sqlite: 'SELECT name, id FROM user WHERE (name <> NULL)', + mysql : 'SELECT name, id FROM user WHERE (name <> NULL)', + params: [] +}); + +Harness.test({ + query : user.select('name','id').from('user').where('name <> NULL').and('id <> NULL'), + pg : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + sqlite: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + mysql : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', params: [] }); From 4fffaad6d6005638534b1de4aa123e9179ba5780 Mon Sep 17 00:00:00 2001 From: Casey Foster Date: Tue, 19 Mar 2013 01:58:24 -0500 Subject: [PATCH 033/507] Fix ORDER BY syntax error in PG --- lib/dialect/postgres.js | 2 +- test/dialects/order-tests.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index d185caec..0b131bc1 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -176,7 +176,7 @@ Postgres.prototype.visitOrderBy = function(orderBy) { Postgres.prototype.visitOrderByColumn = function(column) { if(column.direction) { - return '(' + this.visit(column.column) + ' ' + this.visit(column.direction) + ')'; + return this.visit(column.column) + ' ' + this.visit(column.direction); } else { return this.visit(column.column); } diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 78195e20..27d8928f 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -12,12 +12,12 @@ Harness.test({ Harness.test({ query : post.select(post.content).order(post.content, post.userId.descending), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)', + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); Harness.test({ query : post.select(post.content).order(post.content.asc, post.userId.desc), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", ("post"."userId" DESC)', + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); From d5faf6da4391f14a7a572252548be8e081b5d90b Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 19 Mar 2013 10:33:14 -0500 Subject: [PATCH 034/507] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2f0c4850..02238bd1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.3.0", + "version": "0.4.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From cd44a6816db50d851fa975a8534d400870647e26 Mon Sep 17 00:00:00 2001 From: brianc Date: Wed, 20 Mar 2013 13:12:32 -0500 Subject: [PATCH 035/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02238bd1..2bc5a539 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.4.0", + "version": "0.5.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 7711228c66caa94f31e4cac81dca940e88db1206 Mon Sep 17 00:00:00 2001 From: brianc Date: Thu, 21 Mar 2013 11:24:58 -0500 Subject: [PATCH 036/507] allow any arbitrary properties to be set on columns --- lib/column.js | 5 +++-- test/table-tests.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/lib/column.js b/lib/column.js index 586ddf4c..5bfa8dad 100644 --- a/lib/column.js +++ b/lib/column.js @@ -8,8 +8,9 @@ var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); var Column = function(config) { this.table = config.table; - this.name = config.name; - this.star = config.star; + for(var name in config) { + this[name] = config[name]; + } this.asc = this.ascending = this; this.alias = null; this.desc = this.descending = new OrderByColumnNode({ diff --git a/test/table-tests.js b/test/table-tests.js index 728773d1..7b0770ac 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -43,3 +43,35 @@ test('table', function(t) { t.equal(user.name.table, user); t.end(); }); + +test('table with fancier column definitions', function(t) { + var table = Table.define({ + name: 'blah', + columns: [{ + name: 'id', + type: 'serial', + notNull: true, + primaryKey: true + }, { + name: 'email', + type: 'text', + notNull: true, + unique: true, + anythingYouWant: 'awesome' + }] + }); + var cols = table.columns; + t.equals(cols.length, 2); + var id = cols[0]; + t.equals(id.name, 'id'); + t.equals(id.type, 'serial'); + t.equals(id.notNull, true); + t.equals(id.primaryKey, true); + var email = cols[1]; + t.equals(email.name, 'email'); + t.equals(email.type, 'text'); + t.equals(email.notNull, true); + t.equals(email.unique, true); + t.equals(email.anythingYouWant, 'awesome'); + t.end(); +}); From 3cbe540865d88322fc9ea09d2789c0ed23074347 Mon Sep 17 00:00:00 2001 From: brianc Date: Thu, 21 Mar 2013 11:27:23 -0500 Subject: [PATCH 037/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2bc5a539..350ec08d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.5.0", + "version": "0.6.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 7c44b1bc7a5d19d7735af3dcc4fb146b5981e2eb Mon Sep 17 00:00:00 2001 From: Casey Foster Date: Fri, 22 Mar 2013 22:55:30 -0500 Subject: [PATCH 038/507] Fix subQuery when used as a binary right --- lib/dialect/postgres.js | 12 ++---------- test/dialects/table-tests.js | 8 ++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 5229dd99..4f1b03d4 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -231,17 +231,9 @@ Postgres.prototype.visitQuery = function(queryNode) { Postgres.prototype.visitSubquery = function(queryNode) { var subQuery = new this._myClass(); subQuery.visitQuery(queryNode); + var alias = queryNode.alias; this.params = this.params.concat(subQuery.params); - - var result = subQuery.output; - - result[0] = '('+result[0]; - result[result.length-1] = result[result.length-1] + ')'; - if(queryNode.alias) { - result[result.length-1] = result[result.length-1] + ' ' + queryNode.alias; - } - - return result; + return '(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + alias : ''); }; Postgres.prototype.visitTable = function(tableNode) { diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 381ca4e2..4184511a 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -165,3 +165,11 @@ Harness.test({ mysql : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', params: [] }); + +Harness.test({ + query : user.select(user.star()).where(user.id['in'](user.subQuery().select(user.id))), + pg : 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + sqlite: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', + params: [] +}); From 9a77ca0d0fad26db39a830adb4d76797563f1142 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 14:20:24 -0500 Subject: [PATCH 039/507] make delete take where clause directly --- lib/node/query.js | 8 ++++++-- test/dialects/delete-tests.js | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 01c75632..46c4d0bb 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -146,8 +146,12 @@ var Query = Node.define({ }); return this.add(update); }, - 'delete': function() { - return this.add(new Delete()); + 'delete': function(params) { + var result = this.add(new Delete()); + if(params) { + result = this.where(params); + } + return result; }, returning: function() { var returning = new Returning(); diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 5e6fa435..4c16cfa2 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -10,3 +10,28 @@ Harness.test({ mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', params: [''] }); + +Harness.test({ + query : post.delete().where({content: ''}), + pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', + sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + params: [''] +}); + +Harness.test({ + query : post.delete({content: ''}), + pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', + sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + params: [''] +}); + +Harness.test({ + query : post.delete({content: ''}).or(post.content.isNull()), + pg : 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', + sqlite: 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', + mysql : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', + params: [''] +}); + From 779fcc6e46566f307b27022960671d90c6f5dd29 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 14:26:25 -0500 Subject: [PATCH 040/507] allow group to accept array of columns --- lib/node/query.js | 4 ++++ test/dialects/group-by-tests.js | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/node/query.js b/lib/node/query.js index 46c4d0bb..faa318d5 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,4 +1,5 @@ 'use strict'; +var util = require('util'); var Node = require(__dirname); var Select = require(__dirname + '/select'); @@ -104,6 +105,9 @@ var Query = Node.define({ }, group: function() { var args = Array.prototype.slice.call(arguments, 0); + if(util.isArray(args[0])) { + args = args[0]; + } var groupBy = new GroupBy(); var nodes = args.forEach(function(arg) { groupBy.add(arg.toNode()); diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index 383425bb..7672ee1e 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -35,3 +35,12 @@ Harness.test({ mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', params: [] }); + +Harness.test({ + query : post.select(post.content).group([post.userId, post.id]), + pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + sqlite: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + params: [] +}); + From 7647dc3911c2a84118c3713110d08d738e1a6fc6 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 14:32:13 -0500 Subject: [PATCH 041/507] cleanup trailing whitespace --- test/dialects/namespace-tests.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 9146ff99..85a81ee1 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -55,6 +55,3 @@ Harness.test({ sqlite: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', mysql : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' }); - - - From b76e8bd15a819826cc309cb5ff2d6a573c00ca99 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 14:35:06 -0500 Subject: [PATCH 042/507] allow order clause to accept array of columns --- lib/node/query.js | 11 +++++++---- test/dialects/order-tests.js | 7 +++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index faa318d5..3a0bd99b 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -96,7 +96,10 @@ var Query = Node.define({ return this; }, order: function() { - var args = Array.prototype.slice.call(arguments, 0); + var args = arguments[0]; + if(!util.isArray(args)) { + args = Array.prototype.slice.call(arguments, 0); + } var orderBy = new OrderBy(); var nodes = args.forEach(function(arg) { orderBy.add(arg.toNode()); @@ -104,9 +107,9 @@ var Query = Node.define({ return this.add(orderBy); }, group: function() { - var args = Array.prototype.slice.call(arguments, 0); - if(util.isArray(args[0])) { - args = args[0]; + var args = arguments[0]; + if(!util.isArray(args)) { + args = Array.prototype.slice.call(arguments, 0); } var groupBy = new GroupBy(); var nodes = args.forEach(function(arg) { diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 7c5461cf..4f3a2e94 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -24,3 +24,10 @@ Harness.test({ sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' }); + +Harness.test({ + query : post.select(post.content).order([post.content, post.userId.descending]), + pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' +}); From 2b884c3618c271a5f2090e478d537ec408b31ac0 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 14:40:31 -0500 Subject: [PATCH 043/507] remove copy/pasta looking code --- lib/node/index.js | 7 +++++++ lib/node/query.js | 10 ++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/node/index.js b/lib/node/index.js index f0f4fb9f..1aa58c7b 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -16,6 +16,13 @@ Node.prototype.add = function(node) { return this; }; +Node.prototype.addAll = function(nodes) { + for(var i = 0, len = nodes.length; i < len; i++) { + this.add(nodes[i]); + } + return this; +} + Node.define = function(def) { var c = function() { Node.apply(this, arguments); diff --git a/lib/node/query.js b/lib/node/query.js index 3a0bd99b..628f7b4d 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -100,10 +100,7 @@ var Query = Node.define({ if(!util.isArray(args)) { args = Array.prototype.slice.call(arguments, 0); } - var orderBy = new OrderBy(); - var nodes = args.forEach(function(arg) { - orderBy.add(arg.toNode()); - }); + var orderBy = new OrderBy().addAll(args); return this.add(orderBy); }, group: function() { @@ -111,10 +108,7 @@ var Query = Node.define({ if(!util.isArray(args)) { args = Array.prototype.slice.call(arguments, 0); } - var groupBy = new GroupBy(); - var nodes = args.forEach(function(arg) { - groupBy.add(arg.toNode()); - }); + var groupBy = new GroupBy().addAll(args); return this.add(groupBy); }, insert: function(o) { From e8c449d0f96aee70b6e8b08c414628f3fcdf8d22 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 14:45:46 -0500 Subject: [PATCH 044/507] add tests for 'returning' and make it accept array of columns --- test/dialects/insert-tests.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 6a28f7d2..6e19ce4c 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -97,4 +97,10 @@ Harness.test({ params: [] }); - +Harness.test({ + query : post.insert({}).returning('*'), + pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + mysql : 'INSERT INTO `post` () VALUES () RETURNING *', + params: [] +}) From 6a469fd5118def495d1940863c84f5fc40feab99 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 15:23:02 -0500 Subject: [PATCH 045/507] allow shortcut where clauses in 'and' and 'or' --- lib/node/index.js | 2 ++ lib/node/query.js | 28 ++++++-------------------- lib/node/where.js | 35 ++++++++++++++++++++++++++++++--- lib/table.js | 8 ++++++++ test/dialects/insert-tests.js | 34 +++++++++++++++++++++++++++++++- test/dialects/join-tests.js | 1 - test/dialects/shortcut-tests.js | 9 +++++++-- 7 files changed, 88 insertions(+), 29 deletions(-) diff --git a/lib/node/index.js b/lib/node/index.js index 1aa58c7b..e77f7878 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -24,6 +24,8 @@ Node.prototype.addAll = function(nodes) { } Node.define = function(def) { + //TODO - what was I thinking? + //ALSO TODO - start commenting my code more. :p var c = function() { Node.apply(this, arguments); if(def.constructor) { diff --git a/lib/node/query.js b/lib/node/query.js index 628f7b4d..a136cfc5 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -65,28 +65,12 @@ var Query = Node.define({ return this.add(from); }, where: function(node) { - if (!node.toNode && typeof node == 'object') - node = this._whereObject(node); - //calling #where twice functions like calling #where & then #and if(this.whereClause) return this.and(node); - this.whereClause = new Where(); - this.whereClause.add( this.whereClause.expr(node) ); + this.whereClause = new Where(this.table); + this.whereClause.add(node); return this.add(this.whereClause); }, - _whereObject: function(node) { - var result; - for (var colName in node) { - var column = new Column({name: colName, table: this.table}); - var query = column.equals(node[colName]); - - if (!result) - result = query; - else - result.and(query); - } - return result; - }, or: function(node) { this.whereClause.or(node); return this; @@ -156,11 +140,11 @@ var Query = Node.define({ }, returning: function() { var returning = new Returning(); - var args = Array.prototype.slice.call(arguments, 0); - for(var i = 0; i < args.length; i++) { - //arg could be a column instead of a node - returning.add(args[i]); + var args = arguments[0]; + if(!util.isArray(args)) { + args = Array.prototype.slice.call(arguments, 0); } + returning.addAll(args); return this.add(returning); }, create: function() { diff --git a/lib/node/where.js b/lib/node/where.js index 842ab91d..170c9b5c 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,24 +1,53 @@ 'use strict'; +var Node = require(__dirname); +var Column = require(__dirname + '/../column'); var BinaryNode = require(__dirname + '/binary'); var TextNode = require(__dirname + '/text'); -module.exports = require(__dirname).define({ + +var objectToNodes = function(table, node) { + var result = node; + if (!node.toNode && typeof node == 'object'){ + result = false; + for (var colName in node) { + var column = new Column({name: colName, table: table}); + var query = column.equals(node[colName]); + if (!result) + result = query; + else + result.and(query); + } + } + return result; + +}; + +module.exports = Node.define({ + constructor: function(table) { + this.table = table; + }, type: 'WHERE', expr: function(other) { return typeof other === 'string' ? new TextNode('('+other+')') : other; }, + add: function(node) { + var node = objectToNodes(this.table, node); + return Node.prototype.add.call(this, this.expr(node)); + }, or: function(other) { + var right = objectToNodes(this.table, other); return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'OR', - right: this.expr(other) + right: this.expr(right) })); }, and: function(other) { + var right = objectToNodes(this.table, other); return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'AND', - right: this.expr(other) + right: this.expr(right) })); } }); diff --git a/lib/table.js b/lib/table.js index b9c40530..9e46cbea 100644 --- a/lib/table.js +++ b/lib/table.js @@ -37,6 +37,14 @@ Table.prototype.addColumn = function(col) { return this; }; +Table.prototype.getColumn = function(colName) { + var col = this[colName]; + if(!col) { + throw new Error('Table ' + this._name + ' does not have a column named ' + colName); + } + return this; +} + Table.prototype.getSchema = function() { return this._schema; }; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 6e19ce4c..a131b274 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -103,4 +103,36 @@ Harness.test({ sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', mysql : 'INSERT INTO `post` () VALUES () RETURNING *', params: [] -}) +}); + +Harness.test({ + query : post.insert({}).returning(post.star()), + pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + mysql : 'INSERT INTO `post` () VALUES () RETURNING *', + params: [] +}); + +Harness.test({ + query : post.insert({}).returning(post.id), + pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + mysql : 'INSERT INTO `post` () VALUES () RETURNING `id`', + params: [] +}); + +Harness.test({ + query : post.insert({}).returning(post.id, post.content), + pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + mysql : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', + params: [] +}); + +Harness.test({ + query : post.insert({}).returning([post.id, post.content]), + pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + mysql : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', + params: [] +}); diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index 4edabad9..b4822bd3 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -67,4 +67,3 @@ Harness.test({ sqlite: '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 : '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/shortcut-tests.js b/test/dialects/shortcut-tests.js index 0a51dcef..6d87cfc4 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -44,5 +44,10 @@ Harness.test({ params: [1] }); - - +Harness.test({ + query : post.where(post.content.isNull()).or({content: ''}).and({userId: 1}), + pg : 'SELECT "post".* FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + sqlite: 'SELECT "post".* FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + mysql : 'SELECT `post`.* FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', + params: ['', 1] +}); From 8d897cd9c0bb202d494741bb938f18bc67b8fc33 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 15:27:04 -0500 Subject: [PATCH 046/507] cleanup where node --- lib/node/where.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/node/where.js b/lib/node/where.js index 170c9b5c..6edfac8e 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -5,9 +5,12 @@ var Column = require(__dirname + '/../column'); var BinaryNode = require(__dirname + '/binary'); var TextNode = require(__dirname + '/text'); -var objectToNodes = function(table, node) { +var normalizeNode = function(table, node) { var result = node; - if (!node.toNode && typeof node == 'object'){ + if(typeof node == 'string') { + result = new TextNode('(' + node + ')'); + } + else if (!node.toNode && typeof node == 'object'){ result = false; for (var colName in node) { var column = new Column({name: colName, table: table}); @@ -27,27 +30,24 @@ module.exports = Node.define({ this.table = table; }, type: 'WHERE', - expr: function(other) { - return typeof other === 'string' ? new TextNode('('+other+')') : other; - }, add: function(node) { - var node = objectToNodes(this.table, node); - return Node.prototype.add.call(this, this.expr(node)); + var node = normalizeNode(this.table, node); + return Node.prototype.add.call(this, node); }, or: function(other) { - var right = objectToNodes(this.table, other); + var right = normalizeNode(this.table, other); return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'OR', - right: this.expr(right) + right: right })); }, and: function(other) { - var right = objectToNodes(this.table, other); + var right = normalizeNode(this.table, other); return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'AND', - right: this.expr(right) + right: right })); } }); From ff928df3a30bae7379451bffe6f6e487b63b4909 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 15:37:10 -0500 Subject: [PATCH 047/507] make generated node constructors slightly less weird --- lib/node/default.js | 2 -- lib/node/index.js | 12 +++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/node/default.js b/lib/node/default.js index a139c169..49bd7ebd 100644 --- a/lib/node/default.js +++ b/lib/node/default.js @@ -2,8 +2,6 @@ module.exports = require(__dirname).define({ type: 'DEFAULT', - constructor: function() { - }, value: function() { return; } diff --git a/lib/node/index.js b/lib/node/index.js index e77f7878..424c2daa 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -24,14 +24,16 @@ Node.prototype.addAll = function(nodes) { } Node.define = function(def) { - //TODO - what was I thinking? - //ALSO TODO - start commenting my code more. :p var c = function() { Node.apply(this, arguments); - if(def.constructor) { - def.constructor.apply(this, arguments); - } }; + //allow custom sub-class constructor + if(def.constructor) { + c = function() { + Node.apply(this, arguments); + def.constructor.apply(this, arguments); + }; + } var key; for(key in Node.prototype) { c.prototype[key] = Node.prototype[key]; From 1f1f5cb25d32c6e9a437c95e917017b554b27488 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 15:47:12 -0500 Subject: [PATCH 048/507] allow select to take array of columns --- lib/node/query.js | 8 ++++---- test/dialects/table-tests.js | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index a136cfc5..30ff5583 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -37,11 +37,11 @@ var Query = Node.define({ }, select: function() { var select = new Select(); - var args = Array.prototype.slice.call(arguments, 0); - for(var i = 0; i < args.length; i++) { - //arg could be a column instead of a node - select.add(args[i]); + var args = arguments[0]; + if(!util.isArray(args)) { + args = Array.prototype.slice.call(arguments, 0); } + select.addAll(args); // if this is a subquery then add reference to this column if(this.type === 'SUBQUERY') { for(var j = 0; j < select.nodes.length; j++) { diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 4184511a..5e7a2b6d 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -78,6 +78,14 @@ Harness.test({ params: ['foo', 'bar', 1] }); +Harness.test({ + query : user.select(user.columns), + pg : 'SELECT "user"."id", "user"."name" FROM "user"', + sqlite: 'SELECT "user"."id", "user"."name" FROM "user"', + mysql : 'SELECT `user`.`id`, `user`.`name` FROM `user`', + params: [] +}); + Harness.test({ query : user From 7306e0e9114e2a5f4d32850aa20e6b9c786e2317 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 15:55:49 -0500 Subject: [PATCH 049/507] use sliced for argument slicing --- lib/node/query.js | 28 +++++++++++++++------------- package.json | 4 +++- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 30ff5583..2dfbf6f8 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,6 +1,8 @@ 'use strict'; var util = require('util'); +var sliced = require('sliced'); + var Node = require(__dirname); var Select = require(__dirname + '/select'); var From = require(__dirname + '/from'); @@ -37,9 +39,9 @@ var Query = Node.define({ }, select: function() { var select = new Select(); - var args = arguments[0]; - if(!util.isArray(args)) { - args = Array.prototype.slice.call(arguments, 0); + var args = sliced(arguments); + if(util.isArray(args[0])) { + args = args[0]; } select.addAll(args); // if this is a subquery then add reference to this column @@ -80,17 +82,17 @@ var Query = Node.define({ return this; }, order: function() { - var args = arguments[0]; - if(!util.isArray(args)) { - args = Array.prototype.slice.call(arguments, 0); + var args = sliced(arguments); + if(util.isArray(args[0])) { + var args = args[0] } var orderBy = new OrderBy().addAll(args); return this.add(orderBy); }, group: function() { - var args = arguments[0]; - if(!util.isArray(args)) { - args = Array.prototype.slice.call(arguments, 0); + var args = sliced(arguments); + if(util.isArray(args[0])) { + args = args[0]; } var groupBy = new GroupBy().addAll(args); return this.add(groupBy); @@ -98,7 +100,7 @@ var Query = Node.define({ insert: function(o) { var self = this; - var args = Array.prototype.slice.call(arguments, 0); + var args = sliced(arguments); //object literal if(arguments.length == 1 && !o.toNode && !o.forEach) { args = Object.keys(o).map(function(key) { @@ -140,9 +142,9 @@ var Query = Node.define({ }, returning: function() { var returning = new Returning(); - var args = arguments[0]; - if(!util.isArray(args)) { - args = Array.prototype.slice.call(arguments, 0); + var args = sliced(arguments); + if(util.isArray(args[0])) { + args = args[0]; } returning.addAll(args); return this.add(returning); diff --git a/package.json b/package.json index 350ec08d..dd108e85 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "engines": { "node": "*" }, - "dependencies": {}, + "dependencies": { + "sliced": "0.0.5" + }, "devDependencies": { "test-dir" : "*", "tap" : "*" From aeaf00996c2f70e694d75227fb367cbff385aaa2 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 16:06:25 -0500 Subject: [PATCH 050/507] cleanup node inheritance --- lib/node/binary.js | 5 +++-- lib/node/column.js | 1 + lib/node/index.js | 17 ++++++----------- lib/node/insert.js | 1 + lib/node/join.js | 4 +++- lib/node/orderByColumn.js | 4 +++- lib/node/parameter.js | 4 +++- lib/node/query.js | 1 + lib/node/table.js | 4 +++- lib/node/text.js | 1 + lib/node/unary.js | 4 +++- lib/node/where.js | 1 + test/clause-definition.js | 1 + 13 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/node/binary.js b/lib/node/binary.js index ea875b42..5f666995 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -1,8 +1,9 @@ 'use strict'; - -var BinaryNode = module.exports = require(__dirname).define({ +var Node = require(__dirname); +var BinaryNode = module.exports = Node.define({ type: 'BINARY', constructor: function(config) { + Node.call(this); this.left = config.left; this.operator = config.operator; this.right = config.right; diff --git a/lib/node/column.js b/lib/node/column.js index 257133c7..0bd0a21b 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -5,6 +5,7 @@ var Node = require(__dirname); module.exports = Node.define({ type: 'COLUMN', constructor: function(config) { + Node.call(this); this.name = config.name; this.alias = config.alias; this.star = config.star; diff --git a/lib/node/index.js b/lib/node/index.js index 424c2daa..e4a70030 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,5 +1,6 @@ 'use strict'; +var util = require('util'); var assert = require('assert'); var Node = function(type) { @@ -25,20 +26,14 @@ Node.prototype.addAll = function(nodes) { Node.define = function(def) { var c = function() { - Node.apply(this, arguments); + Node.call(this); }; //allow custom sub-class constructor - if(def.constructor) { - c = function() { - Node.apply(this, arguments); - def.constructor.apply(this, arguments); - }; + if(def.constructor && def.constructor != {}.constructor) { + c = def.constructor; } - var key; - for(key in Node.prototype) { - c.prototype[key] = Node.prototype[key]; - } - for(key in def) { + util.inherits(c, Node); + for(var key in def) { c.prototype[key] = def[key]; } return c; diff --git a/lib/node/insert.js b/lib/node/insert.js index 4873fa38..07156d8c 100644 --- a/lib/node/insert.js +++ b/lib/node/insert.js @@ -7,6 +7,7 @@ var DefaultNode = require('./default'); var Insert = Node.define({ type: 'INSERT', constructor: function () { + Node.call(this); this.names = []; this.columns = []; this.valueSets = []; diff --git a/lib/node/join.js b/lib/node/join.js index b6e21545..a16067e6 100644 --- a/lib/node/join.js +++ b/lib/node/join.js @@ -1,8 +1,10 @@ 'use strict'; -var JoinNode = module.exports = require(__dirname).define({ +var Node = require(__dirname); +var JoinNode = module.exports = Node.define({ type: 'JOIN', constructor: function(subType, from, to) { + Node.call(this); this.subType = subType; this.from = from.toNode(); this.to = to.toNode(); diff --git a/lib/node/orderByColumn.js b/lib/node/orderByColumn.js index 8f662c1b..376abc3f 100644 --- a/lib/node/orderByColumn.js +++ b/lib/node/orderByColumn.js @@ -1,8 +1,10 @@ 'use strict'; -var OrderByColumn = module.exports = require(__dirname).define({ +var Node = require(__dirname); +var OrderByColumn = module.exports = Node.define({ type: 'ORDER BY COLUMN', constructor: function(config) { + Node.call(this); this.column = config.column; this.direction = config.direction; } diff --git a/lib/node/parameter.js b/lib/node/parameter.js index 7e45cbd3..0b190d6e 100644 --- a/lib/node/parameter.js +++ b/lib/node/parameter.js @@ -1,8 +1,10 @@ 'use strict'; -module.exports = require(__dirname).define({ +var Node = require(__dirname); +module.exports = Node.define({ type: 'PARAMETER', constructor: function(val) { + Node.call(this); this._val = val; }, value: function() { diff --git a/lib/node/query.js b/lib/node/query.js index 2dfbf6f8..d900fd8c 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -35,6 +35,7 @@ var Modifier = Node.define({ var Query = Node.define({ type: 'QUERY', constructor: function(table) { + Node.call(this); this.table = table; }, select: function() { diff --git a/lib/node/table.js b/lib/node/table.js index 407548d4..b1257105 100644 --- a/lib/node/table.js +++ b/lib/node/table.js @@ -1,8 +1,10 @@ 'use strict'; -module.exports = require(__dirname).define({ +var Node = require(__dirname); +module.exports = Node.define({ type: 'TABLE', constructor: function(table) { + Node.call(this); this.table = table; } }); diff --git a/lib/node/text.js b/lib/node/text.js index 538f31c9..ef1194b2 100644 --- a/lib/node/text.js +++ b/lib/node/text.js @@ -5,6 +5,7 @@ var Node = require(__dirname); module.exports = Node.define({ type: 'TEXT', constructor: function(text) { + Node.call(this); this.text = text; } }); diff --git a/lib/node/unary.js b/lib/node/unary.js index c98009fb..11d6b80a 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -1,8 +1,10 @@ 'use strict'; -module.exports = require(__dirname).define({ +var Node = require(__dirname); +module.exports = Node.define({ type: 'UNARY', constructor: function(config) { + Node.call(this); this.left = config.left, this.operator = config.operator; } diff --git a/lib/node/where.js b/lib/node/where.js index 6edfac8e..43ca1d09 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -27,6 +27,7 @@ var normalizeNode = function(table, node) { module.exports = Node.define({ constructor: function(table) { + Node.call(this); this.table = table; }, type: 'WHERE', diff --git a/test/clause-definition.js b/test/clause-definition.js index 15a8189e..8e750b2f 100644 --- a/test/clause-definition.js +++ b/test/clause-definition.js @@ -10,6 +10,7 @@ var Bang = Node.define({ var Boom = Node.define({ constructor: function(n) { + Node.call(this); this.name = n; } }); From 1e240ed8edceccec4cd4a4b4b9456a0c61b59b7c Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 16:23:09 -0500 Subject: [PATCH 051/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd108e85..07361334 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.6.0", + "version": "0.7.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 60961c2d09fbf87e5b162c57264a118e948e65b7 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 16:28:07 -0500 Subject: [PATCH 052/507] fix table.getColumn --- lib/node/where.js | 3 +-- lib/table.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/node/where.js b/lib/node/where.js index 43ca1d09..cfd92215 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -13,7 +13,7 @@ var normalizeNode = function(table, node) { else if (!node.toNode && typeof node == 'object'){ result = false; for (var colName in node) { - var column = new Column({name: colName, table: table}); + var column = table.getColumn(colName); var query = column.equals(node[colName]); if (!result) result = query; @@ -22,7 +22,6 @@ var normalizeNode = function(table, node) { } } return result; - }; module.exports = Node.define({ diff --git a/lib/table.js b/lib/table.js index 9e46cbea..4d35348d 100644 --- a/lib/table.js +++ b/lib/table.js @@ -42,7 +42,7 @@ Table.prototype.getColumn = function(colName) { if(!col) { throw new Error('Table ' + this._name + ' does not have a column named ' + colName); } - return this; + return col; } Table.prototype.getSchema = function() { From 980207ebee9567c43ccff6f7cc8ed10eb562b1d8 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 16:28:56 -0500 Subject: [PATCH 053/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 07361334..9d8e170f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.7.0", + "version": "0.7.1", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 78f3221e30cbebf7828ef430e29ae27be0794e68 Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 19:08:40 -0500 Subject: [PATCH 054/507] allow SELECT/FROM/WHERE in any order --- lib/dialect/postgres.js | 59 ++++++++++++++++++++------ lib/table.js | 8 +++- package.json | 2 +- test/dialects/clause-ordering-tests.js | 22 ++++++++++ test/dialects/shortcut-tests.js | 18 ++++---- 5 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 test/dialects/clause-ordering-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4f1b03d4..dde76e10 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -3,6 +3,7 @@ var util = require('util'); var assert = require('assert'); var From = require(__dirname + '/../node/from'); +var Select = require(__dirname + '/../node/select'); var Parameter = require(__dirname + '/../node/parameter'); var Postgres = function() { this.output = []; @@ -70,7 +71,6 @@ Postgres.prototype.visitSelect = function(select) { Postgres.prototype.visitInsert = function(insert) { var self = this; - this._visitedFrom = true; //don't use table.column for inserts this._visitedInsert = true; @@ -98,7 +98,6 @@ Postgres.prototype.visitInsert = function(insert) { Postgres.prototype.visitUpdate = function(update) { //don't auto-generate from clause - this._visitedFrom = true; var params = []; /*jshint boss: true */ for(var i = 0, node; node = update.nodes[i]; i++) { @@ -124,7 +123,6 @@ Postgres.prototype.visitDelete = function() { Postgres.prototype.visitCreate = function(create) { this._visitingCreate = true; //don't auto-generate from clause - this._visitedFrom = true; var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); @@ -138,7 +136,6 @@ Postgres.prototype.visitCreate = function(create) { Postgres.prototype.visitDrop = function(drop) { //don't auto-generate from clause - this._visitedFrom = true; var result = ['DROP TABLE']; result = result.concat(drop.nodes.map(this.visit.bind(this))); result.push(this.visit(this._queryNode.table.toNode())); @@ -148,7 +145,6 @@ Postgres.prototype.visitDrop = function(drop) { Postgres.prototype.visitAlter = function(alter) { this._visitingAlter = true; //don't auto-generate from clause - this._visitedFrom = true; var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); var result = [ @@ -161,7 +157,6 @@ Postgres.prototype.visitAlter = function(alter) { }; Postgres.prototype.visitFrom = function(from) { - this._visitedFrom = true; var result = []; result.push('FROM'); for(var i = 0; i < from.nodes.length; i++) { @@ -214,17 +209,53 @@ Postgres.prototype.visitUnary = function(unary) { Postgres.prototype.visitQuery = function(queryNode) { this._queryNode = queryNode; - for(var i = 0; i < queryNode.nodes.length; i ++) { - var res = this.visit(queryNode.nodes[i]); + //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 actions = []; + var targets = []; + var filters = []; + for(var i = 0; i < queryNode.nodes.length; i++) { + var node = queryNode.nodes[i]; + switch(node.type) { + case "SELECT": + case "DELETE": + actions.push(node); + break; + case "INSERT": + case "UPDATE": + case "CREATE": + case "DROP": + case "ALTER": + actions.push(node); + missingFrom = false; + break; + case "FROM": + missingFrom = false; + targets.push(node); + break; + default: + filters.push(node); + break; + } + } + if(!actions.length) { + console.log('missing select') + //if no actions are given, guess it's a select + actions.push(new Select().add('*')); + } + if(missingFrom) { + console.log('missing from') + targets.push(new From().add(queryNode.table)); + } + //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' - if(!this._visitedFrom) { - var select = this.output.slice(0, this._selectOrDeleteEndIndex); - var from = this.visitFrom(new From().add(queryNode.table.toNode())); - var rest = this.output.slice(this._selectOrDeleteEndIndex); - this.output = select.concat(from).concat(rest); - } return this; }; diff --git a/lib/table.js b/lib/table.js index 4d35348d..0e821f8e 100644 --- a/lib/table.js +++ b/lib/table.js @@ -70,6 +70,12 @@ 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); @@ -139,7 +145,7 @@ Table.prototype.__defineGetter__("nodes", function() { }); Table.prototype.where = function() { - var query = this.select(this.star()); + var query = new Query(this); query.where.apply(query, arguments); return query; }; diff --git a/package.json b/package.json index 9d8e170f..1d88a343 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.7.1", + "version": "0.8.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js new file mode 100644 index 00000000..05a7518e --- /dev/null +++ b/test/dialects/clause-ordering-tests.js @@ -0,0 +1,22 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); +var post = Harness.definePostTable(); + +//FROM - SELECT +Harness.test({ + query : user.from(user.join(post).on(user.id.equals(post.userId))).select(user.name, post.content), + pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' +}); + +//WHERE - FROM - SELECT +Harness.test({ + query : user.where({name: ''}).from(user).select(user.id), + pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + params: [''] +}); diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 6d87cfc4..98952ed1 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -14,17 +14,17 @@ Harness.test({ Harness.test({ query : user.where(user.name.equals(3)), - pg : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?)', + pg : 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', params : [3] }); Harness.test({ query : user.where(user.name.equals(3)).where(user.id.equals(1)), - pg : 'SELECT "user".* FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - sqlite: 'SELECT "user".* FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - mysql : 'SELECT `user`.* FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + pg : 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + sqlite: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + mysql : 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', params: [3,1] }); @@ -46,8 +46,8 @@ Harness.test({ Harness.test({ query : post.where(post.content.isNull()).or({content: ''}).and({userId: 1}), - pg : 'SELECT "post".* FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', - sqlite: 'SELECT "post".* FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', - mysql : 'SELECT `post`.* FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', + pg : 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + sqlite: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + mysql : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', params: ['', 1] }); From 8b15905609f31d62753e3b851099c6a8352a4d3f Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 21:17:05 -0500 Subject: [PATCH 055/507] remove console.log statement --- lib/dialect/postgres.js | 1 - package.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index dde76e10..110c183c 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -241,7 +241,6 @@ Postgres.prototype.visitQuery = function(queryNode) { } } if(!actions.length) { - console.log('missing select') //if no actions are given, guess it's a select actions.push(new Select().add('*')); } diff --git a/package.json b/package.json index 1d88a343..be11c557 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.8.0", + "version": "0.8.1", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 3f5fd9098ae6672f281841ec9f35f2cac4317f7a Mon Sep 17 00:00:00 2001 From: brianc Date: Sat, 23 Mar 2013 21:20:13 -0500 Subject: [PATCH 056/507] remove another console.log statement --- lib/dialect/postgres.js | 1 - package.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 110c183c..a1b25fa0 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -245,7 +245,6 @@ Postgres.prototype.visitQuery = function(queryNode) { actions.push(new Select().add('*')); } if(missingFrom) { - console.log('missing from') targets.push(new From().add(queryNode.table)); } //lazy-man sorting diff --git a/package.json b/package.json index be11c557..17372cbe 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.8.1", + "version": "0.8.2", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 680fd909f6069aa8c1b246a1d7e116fe2fffaf98 Mon Sep 17 00:00:00 2001 From: Eric Sessoms Date: Tue, 26 Mar 2013 13:37:52 -0400 Subject: [PATCH 057/507] minor cleanup, mostly related to function vs block scoping --- lib/column.js | 2 ++ lib/dialect/mysql.js | 1 + lib/dialect/postgres.js | 7 +++---- lib/dialect/sqlite.js | 3 +++ lib/node/index.js | 3 ++- lib/node/query.js | 4 +++- lib/node/where.js | 3 +-- lib/table.js | 5 ++--- test/binary-clause-tests.js | 1 - test/dialects/aggregate-tests.js | 1 - test/dialects/delete-tests.js | 7 +++---- test/dialects/group-by-tests.js | 2 -- test/dialects/order-tests.js | 1 - test/dialects/support.js | 7 ------- 14 files changed, 20 insertions(+), 27 deletions(-) diff --git a/lib/column.js b/lib/column.js index 5bfa8dad..5f5a5425 100644 --- a/lib/column.js +++ b/lib/column.js @@ -6,6 +6,7 @@ var BinaryNode = require(__dirname + '/node/binary'); var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); + var Column = function(config) { this.table = config.table; for(var name in config) { @@ -39,6 +40,7 @@ var binaryMethod = function(name, operator) { }; var unaryMethod = function(name, operator) { + /*jshint unused: false */ Column.prototype[name] = function(val) { return new UnaryNode({ left: this.toNode(), diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 718a1005..a3b48f6e 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -23,6 +23,7 @@ Mysql.prototype.visitParameter = function(parameter) { return "?"; }; +/*jshint unused: false */ Mysql.prototype.visitDefault = function(parameter) { return "DEFAULT"; }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a1b25fa0..79214c79 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1,10 +1,8 @@ 'use strict'; -var util = require('util'); var assert = require('assert'); var From = require(__dirname + '/../node/from'); var Select = require(__dirname + '/../node/select'); -var Parameter = require(__dirname + '/../node/parameter'); var Postgres = function() { this.output = []; this.params = []; @@ -146,6 +144,7 @@ Postgres.prototype.visitAlter = function(alter) { this._visitingAlter = true; //don't auto-generate from clause var table = this._queryNode.table; + // TODO: col_nodes is unused? var col_nodes = table.columns.map(function(col) { return col.toNode(); }); var result = [ 'ALTER TABLE', @@ -248,8 +247,8 @@ Postgres.prototype.visitQuery = function(queryNode) { targets.push(new From().add(queryNode.table)); } //lazy-man sorting - var sortedNodes = actions.concat(targets).concat(filters); - for(var i = 0; i < sortedNodes.length; i++) { + 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); } diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index dfc6e3e2..321f28bf 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -17,14 +17,17 @@ Sqlite.prototype._myClass = Sqlite; Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; +/*jshint unused: false */ Sqlite.prototype.visitDefault = function(parameter) { throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.'); }; +/*jshint unused: false */ Sqlite.prototype.visitDropColumn = function(dropColumn) { throw new Error('SQLite does not allow dropping columns.'); }; +/*jshint unused: false */ Sqlite.prototype.visitRenameColumn = function(renameColumn) { throw new Error('SQLite does not allow renaming columns.'); }; diff --git a/lib/node/index.js b/lib/node/index.js index e4a70030..5f2ec33a 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -3,6 +3,7 @@ var util = require('util'); var assert = require('assert'); +/*jshint unused: false */ var Node = function(type) { this.nodes = []; }; @@ -22,7 +23,7 @@ Node.prototype.addAll = function(nodes) { this.add(nodes[i]); } return this; -} +}; Node.define = function(def) { var c = function() { diff --git a/lib/node/query.js b/lib/node/query.js index d900fd8c..0cf46b0e 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,4 +1,6 @@ 'use strict'; + +var assert = require('assert'); var util = require('util'); var sliced = require('sliced'); @@ -85,7 +87,7 @@ var Query = Node.define({ order: function() { var args = sliced(arguments); if(util.isArray(args[0])) { - var args = args[0] + args = args[0]; } var orderBy = new OrderBy().addAll(args); return this.add(orderBy); diff --git a/lib/node/where.js b/lib/node/where.js index cfd92215..f4520570 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,7 +1,6 @@ 'use strict'; var Node = require(__dirname); -var Column = require(__dirname + '/../column'); var BinaryNode = require(__dirname + '/binary'); var TextNode = require(__dirname + '/text'); @@ -31,7 +30,7 @@ module.exports = Node.define({ }, type: 'WHERE', add: function(node) { - var node = normalizeNode(this.table, node); + node = normalizeNode(this.table, node); return Node.prototype.add.call(this, node); }, or: function(other) { diff --git a/lib/table.js b/lib/table.js index 0e821f8e..c725b4ad 100644 --- a/lib/table.js +++ b/lib/table.js @@ -3,7 +3,6 @@ var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); var TableNode = require(__dirname + '/node/table'); -var TextNode = require(__dirname + '/node/text'); var JoinNode = require(__dirname + '/node/join'); var Table = function(config) { @@ -43,7 +42,7 @@ Table.prototype.getColumn = function(colName) { throw new Error('Table ' + this._name + ' does not have a column named ' + colName); } return col; -} +}; Table.prototype.getSchema = function() { return this._schema; @@ -74,7 +73,7 @@ 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 diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 0b03ad44..fab7848a 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -1,7 +1,6 @@ 'use strict'; var test = require('tap').test; -var Column = require(__dirname + '/../lib/column'); var Table = require(__dirname + '/../lib/table'); var Foo = Table.define({ diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 494862d8..fb89b258 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -1,7 +1,6 @@ 'use strict'; var Harness = require('./support'); -var user = Harness.defineUserTable(); var post = Harness.definePostTable(); Harness.test({ diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 4c16cfa2..663cd8cc 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -12,7 +12,7 @@ Harness.test({ }); Harness.test({ - query : post.delete().where({content: ''}), + query : post['delete']().where({content: ''}), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', @@ -20,7 +20,7 @@ Harness.test({ }); Harness.test({ - query : post.delete({content: ''}), + query : post['delete']({content: ''}), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', @@ -28,10 +28,9 @@ Harness.test({ }); Harness.test({ - query : post.delete({content: ''}).or(post.content.isNull()), + query : post['delete']({content: ''}).or(post.content.isNull()), pg : 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', sqlite: 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', mysql : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', params: [''] }); - diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index 7672ee1e..3d5dd756 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -1,7 +1,6 @@ 'use strict'; var Harness = require('./support'); -var user = Harness.defineUserTable(); var post = Harness.definePostTable(); Harness.test({ @@ -43,4 +42,3 @@ Harness.test({ mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', params: [] }); - diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 4f3a2e94..fea76528 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -1,7 +1,6 @@ 'use strict'; var Harness = require('./support'); -var user = Harness.defineUserTable(); var post = Harness.definePostTable(); Harness.test({ diff --git a/test/dialects/support.js b/test/dialects/support.js index 33337c9d..36ad6f8f 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -79,10 +79,3 @@ module.exports = { }); } }; - - - - - - - From c32b00b99b0332fa19ae32a4e3b73b5b8e3340ee Mon Sep 17 00:00:00 2001 From: Eric Sessoms Date: Fri, 29 Mar 2013 17:22:04 -0400 Subject: [PATCH 058/507] added more tests of clause ordering --- test/dialects/clause-ordering-tests.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index 05a7518e..4038f299 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -20,3 +20,24 @@ Harness.test({ mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', params: [''] }); + +//SELECT - FROM - WHERE +Harness.test({ + query : user + .select(user.name, post.content) + .from(user.join(post).on(user.id.equals(post.userId))) + .where({ name: '' }), + pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = ?)', + params: [''] +}); + +//SELECT - FROM - WHERE +Harness.test({ + query : user.select(user.id).from(user).where({name: ''}), + pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + params: [''] +}); From 270d7fb9256a700d4991db0cb1b58fa90fcb4b56 Mon Sep 17 00:00:00 2001 From: Casey Foster Date: Tue, 9 Apr 2013 23:43:17 -0500 Subject: [PATCH 059/507] LIMIT and OFFSET can accept a subQuery --- lib/dialect/postgres.js | 4 ++-- test/dialects/limit-and-offset-tests.js | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 79214c79..b79a7bbf 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -258,9 +258,9 @@ Postgres.prototype.visitQuery = function(queryNode) { Postgres.prototype.visitSubquery = function(queryNode) { var subQuery = new this._myClass(); + subQuery.params = this.params; subQuery.visitQuery(queryNode); var alias = queryNode.alias; - this.params = this.params.concat(subQuery.params); return '(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + alias : ''); }; @@ -369,7 +369,7 @@ Postgres.prototype.visitReturning = function(returning) { }; Postgres.prototype.visitModifier = function(node) { - return [node.type, node.count]; + return [node.type, node.count.type ? this.visit(node.count) : node.count]; }; module.exports = Postgres; diff --git a/test/dialects/limit-and-offset-tests.js b/test/dialects/limit-and-offset-tests.js index d09e1001..294d7315 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -26,3 +26,11 @@ Harness.test({ sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }); + +Harness.test({ + query : user.select(user.star()).where({name: 'John'}).offset(user.subQuery().select('FLOOR(RANDOM() * COUNT(*))').where({name: 'John'})).limit(1), + pg : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', + sqlite: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', + mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT 1', + values: ['John', 'John'] +}); From c7e2af451314a96ab402aaece654b81c563ad358 Mon Sep 17 00:00:00 2001 From: bmc Date: Sat, 13 Apr 2013 12:21:17 -0500 Subject: [PATCH 060/507] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 17372cbe..b38da9c1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.8.2", + "version": "0.9.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 5e614ebbaf88b11ddbe24e023c58409be2facba7 Mon Sep 17 00:00:00 2001 From: Brian C Date: Fri, 19 Apr 2013 09:55:03 -0500 Subject: [PATCH 061/507] Update README.md --- README.md | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7e859698..5bff9417 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # node-sql -_sql string builder for node_ +_sql string builder for node_ - supports PostgreSQL, mysql, and sqlite dialects. Building SQL statements by hand is no fun, especially in a language which has clumsy support for multi-line strings. @@ -24,7 +24,7 @@ var user = sql.define({ var post = sql.define({ name: 'post', columns: ['id', 'userId', 'date', 'title', 'body'] -}) +}); //now let's make a simple query var query = user.select(user.star()).from(user).toQuery(); @@ -49,11 +49,37 @@ console.log(query.values); //['boom', 1, 'bang', 2] //how about a join? var query = user.select(user.name, post.content) .from(user.join(post).on(user.id.equals(post.userId))).toQuery(); - + console.log(query.text); //'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + +//this also makes parts of your queries composable, which is handy + +var friendship = sql.define({ + name: 'friendship', + columns: ['userId', 'friendId'] +}); + +var friends = user.as('friends'); +var userToFriends = user + .leftJoin(friendship.on(user.id.equals(friendship.userId))) + .leftJoin(friends.on(friendship.friendId.equals(friends.id))); + +//and now...compose... +var friendsWhoHaveLoggedInQuery = userToFriends.where(friends.lastLogin.notNull()); +//SELECT * FROM "user" +//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +//LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") +//WHERE "friends"."lastLogin" IS NOT NULL + +var friendsWhoUseGmailQuery = userToFriends.where(friends.email.like('%@gmail.com')); +//SELECT * FROM "user" +//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +//LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") +//WHERE "friends"."lastLogin" LIKE %1 + ``` -There are a __lot__ more examples included in the `test` folder. +There are a __lot__ more examples included in the `test/dialects` folder. ## contributing From dbc89c9b4b0b5bb99f2d2d413725c84b15f5c75c Mon Sep 17 00:00:00 2001 From: Brian C Date: Fri, 19 Apr 2013 09:56:21 -0500 Subject: [PATCH 062/507] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5bff9417..443086bf 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ var friendsWhoUseGmailQuery = userToFriends.where(friends.email.like('%@gmail.co //SELECT * FROM "user" //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") -//WHERE "friends"."lastLogin" LIKE %1 +//WHERE "friends"."email" LIKE %1 ``` From bcf08b79c7ffc08b0dd1e640b0350688b2394659 Mon Sep 17 00:00:00 2001 From: Chaoran Yang Date: Sat, 20 Apr 2013 23:56:45 -0500 Subject: [PATCH 063/507] Add rename clause for alter table --- lib/dialect/postgres.js | 5 +++++ lib/node/query.js | 9 +++++++++ lib/node/rename.js | 7 +++++++ test/dialects/alter-table-tests.js | 8 ++++++++ 4 files changed, 29 insertions(+) create mode 100644 lib/node/rename.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index b79a7bbf..38103e1d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -45,6 +45,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 'RENAME': return this.visitRename(node); case 'ADD COLUMN': return this.visitAddColumn(node); case 'DROP COLUMN': return this.visitDropColumn(node); case 'RENAME COLUMN': return this.visitRenameColumn(node); @@ -346,6 +347,10 @@ Postgres.prototype.visitRenameColumn = function(renameColumn) { return ['RENAME COLUMN ' + this.visit(renameColumn.nodes[0]) + ' TO ' + this.visit(renameColumn.nodes[1])]; }; +Postgres.prototype.visitRename = function(rename) { + return ['RENAME TO ' + this.visit(rename.nodes[0])]; +}; + Postgres.prototype.visitIfExists = function() { return ['IF EXISTS']; }; diff --git a/lib/node/query.js b/lib/node/query.js index 0cf46b0e..a4003504 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -21,6 +21,7 @@ var Alter = require(__dirname + '/alter'); var AddColumn = require(__dirname + '/addColumn'); var DropColumn = require(__dirname + '/dropColumn'); var RenameColumn = require(__dirname + '/renameColumn'); +var Rename = require(__dirname + '/rename'); var Column = require(__dirname + '/../column'); var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); @@ -161,6 +162,14 @@ var Query = Node.define({ alter: function() { return this.add(new Alter()); }, + rename: function(newName) { + var renameClause = new Rename(); + if (!newName.toNode) + newName = new Column({ name: newName, table: this.table}); + renameClause.add(newName.toNode()); + this.nodes[0].add(renameClause); + return this; + }, addColumn: function(column, dataType) { var addClause = new AddColumn(); if (!column.toNode) diff --git a/lib/node/rename.js b/lib/node/rename.js new file mode 100644 index 00000000..9767a528 --- /dev/null +++ b/lib/node/rename.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'RENAME' +}); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 14542572..2eed1d09 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -37,6 +37,14 @@ Harness.test({ params: [] }); +Harness.test({ + query : post.alter().rename('posts'), + pg : 'ALTER TABLE "post" RENAME TO "posts"', + sqlite: 'ALTER TABLE "post" RENAME TO "posts"', + mysql : 'ALTER TABLE `post` RENAME TO `posts`', + params: [] +}); + var group = Table.define({ name: 'group', columns: [{ From a0cd41846f64fb039b9b9e1e940ce3626ec00211 Mon Sep 17 00:00:00 2001 From: bmc Date: Sun, 21 Apr 2013 12:12:17 -0500 Subject: [PATCH 064/507] Bump version --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b38da9c1..cb804086 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.9.0", + "version": "0.10.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", @@ -19,7 +19,7 @@ "sliced": "0.0.5" }, "devDependencies": { - "test-dir" : "*", - "tap" : "*" + "test-dir": "*", + "tap": "*" } } From d8027b0a5c35bc19236a4eb9cea155f8dac46706 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 3 May 2013 10:21:40 -0500 Subject: [PATCH 065/507] Allow non-query nodes to be turned into strings --- lib/dialect/postgres.js | 8 ++++++-- test/dialects/join-tests.js | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 38103e1d..1af0b7b1 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -13,7 +13,11 @@ Postgres.prototype._myClass = Postgres; Postgres.prototype._arrayAggFunctionName = 'array_agg'; Postgres.prototype.getQuery = function(queryNode) { - this.visitQuery(queryNode); + //passed in a table, not a query + if(queryNode.name) { + queryNode = queryNode.select(queryNode.star()); + } + this.output = this.visit(queryNode); return { text: this.output.join(' '), values: this.params }; }; @@ -254,7 +258,7 @@ Postgres.prototype.visitQuery = function(queryNode) { this.output = this.output.concat(res); } //implicit 'from' - return this; + return this.output; }; Postgres.prototype.visitSubquery = function(queryNode) { diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index b4822bd3..ba281781 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -12,6 +12,13 @@ Harness.test({ mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }); +Harness.test({ + query : user.join(post).on(user.id.equals(post.userId)), + pg : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + sqlite: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + mysql : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' +}); + Harness.test({ query : user .select(user.name, post.content, comment.text) From a093b4c07cd4c6c2a39b57606796d507fc060716 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 3 May 2013 10:26:17 -0500 Subject: [PATCH 066/507] Add 'toQuery' to the prototype of all nodes This allows doing something like this: `user.join(photos).toQuery().text` to build just a part of a query. --- lib/node/index.js | 5 +++++ lib/node/query.js | 4 ---- test/select-tests.js | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/node/index.js b/lib/node/index.js index 5f2ec33a..69fb287d 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -18,6 +18,11 @@ Node.prototype.add = function(node) { return this; }; +Node.prototype.toQuery = function() { + var Dialect = require(__dirname + '/../').dialect; + return new Dialect().getQuery(this); +}; + Node.prototype.addAll = function(nodes) { for(var i = 0, len = nodes.length; i < len; i++) { this.add(nodes[i]); diff --git a/lib/node/query.js b/lib/node/query.js index a4003504..c8201d89 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -212,10 +212,6 @@ var Query = Node.define({ ifNotExists: function() { this.nodes[0].add(new IfNotExists()); return this; - }, - toQuery: function() { - var Dialect = require(__dirname + '/../').dialect; - return new Dialect().getQuery(this); } }); diff --git a/test/select-tests.js b/test/select-tests.js index f60da93b..37325b13 100644 --- a/test/select-tests.js +++ b/test/select-tests.js @@ -5,3 +5,5 @@ var Select = require(__dirname + '/../lib/node/select'); var select = new Select(); assert.equal(select.type, 'SELECT'); + +assert.equal(select.toQuery().text, 'SELECT '); From 31ef80aeb957b2b06a2ec2158aa5924d27f94bd9 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 3 May 2013 10:50:05 -0500 Subject: [PATCH 067/507] Use mocha instead of weird 1/2 of tap for tests I kept having to scroll back several hundered lines when a test would fail and the output was ridiculously verbose. --- test/binary-clause-tests.js | 28 ++++++------ test/clause-definition.js | 20 ++++----- test/dialects/support.js | 13 +++--- test/index-tests.js | 34 +++++++-------- test/index.js | 4 +- test/mocha.opts | 1 + test/select-tests.js | 9 +++- test/table-tests.js | 85 ++++++++++++++++++++----------------- 8 files changed, 99 insertions(+), 95 deletions(-) create mode 100644 test/mocha.opts diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index fab7848a..9bf13a11 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -1,6 +1,5 @@ 'use strict'; - -var test = require('tap').test; +var assert = require('assert'); var Table = require(__dirname + '/../lib/table'); var Foo = Table.define({ @@ -8,17 +7,16 @@ var Foo = Table.define({ columns: ['baz','bar'] }); -test('operators', function(t) { - t.equal(Foo.baz.equals(1).operator, '='); - t.equal(Foo.baz.equal(1).operator, '='); - t.equal(Foo.baz.notEqual(1).operator, '<>'); - t.equal(Foo.baz.notEquals(1).operator, '<>'); - t.equal(Foo.baz.like('asdf').operator, 'LIKE'); - t.equal(Foo.baz.isNull().operator, 'IS NULL'); - t.equal(Foo.baz.isNotNull().operator, 'IS NOT NULL'); - t.equal(Foo.baz.gt(1).operator, '>'); - t.equal(Foo.baz.gte(1).operator, '>='); - t.equal(Foo.baz.lt(1).operator, '<'); - t.equal(Foo.baz.lte(1).operator, '<='); - t.end(); +test('operators', function() { + assert.equal(Foo.baz.equals(1).operator, '='); + assert.equal(Foo.baz.equal(1).operator, '='); + assert.equal(Foo.baz.notEqual(1).operator, '<>'); + assert.equal(Foo.baz.notEquals(1).operator, '<>'); + assert.equal(Foo.baz.like('asdf').operator, 'LIKE'); + assert.equal(Foo.baz.isNull().operator, 'IS NULL'); + assert.equal(Foo.baz.isNotNull().operator, 'IS NOT NULL'); + assert.equal(Foo.baz.gt(1).operator, '>'); + assert.equal(Foo.baz.gte(1).operator, '>='); + assert.equal(Foo.baz.lt(1).operator, '<'); + assert.equal(Foo.baz.lte(1).operator, '<='); }); diff --git a/test/clause-definition.js b/test/clause-definition.js index 8e750b2f..56afbade 100644 --- a/test/clause-definition.js +++ b/test/clause-definition.js @@ -1,9 +1,8 @@ 'use strict'; +var assert = require('assert'); -var test = require('tap').test; var Node = require(__dirname + '/../lib/node/'); -console.log('node definition'); var Bang = Node.define({ type: 'SELECT' }); @@ -15,18 +14,17 @@ var Boom = Node.define({ } }); -test('clause definition', function(t) { +test('clause definition', function() { var select = new Bang(); - t.equal(select.type, 'SELECT'); - t.equal(select.nodes.length, 0); + assert.equal(select.type, 'SELECT'); + assert.equal(select.nodes.length, 0); var q = new Boom('hai'); - t.equal(q.nodes.length, 0); + assert.equal(q.nodes.length, 0); var q2 = new Boom('bai'); q.nodes.push(1); - t.equal(q.nodes.length, 1); - t.equal(q.name, 'hai'); - t.equal(q2.nodes.length, 0); - t.equal(q2.name, 'bai'); - t.end(); + assert.equal(q.nodes.length, 1); + assert.equal(q.name, 'hai'); + assert.equal(q2.nodes.length, 0); + assert.equal(q2.name, 'bai'); }); diff --git a/test/dialects/support.js b/test/dialects/support.js index 36ad6f8f..04786055 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -1,6 +1,6 @@ 'use strict'; +var assert = require('assert'); -var tap = require('tap').test; var Table = require(__dirname + '/../../lib/table'); // specify dialect classes @@ -20,12 +20,12 @@ module.exports = { var DialectClass = dialects[dialect]; var title = dialect+': '+(expected.title || expected[dialect].text || expected[dialect]); - tap(title, function(t) { + test(title, function() { // check if this query is expected to throw if(expected[dialect].throws) { - t.throws(function() { + assert.throws(function() { new DialectClass().getQuery(expected.query); }); @@ -36,19 +36,18 @@ module.exports = { // test result is correct var expectedText = expected[dialect].text || expected[dialect]; - t.equal(compiledQuery.text, expectedText,'query result'); + assert.equal(compiledQuery.text, expectedText,'query result'); // if params are specified then test these are correct var expectedParams = expected[dialect].params || expected.params; if(expectedParams) { - t.equal(expectedParams.length, compiledQuery.values.length, 'params length'); + assert.equal(expectedParams.length, compiledQuery.values.length, 'params length'); for(var i = 0; i < expectedParams.length; i++) { - t.equal(expectedParams[i], compiledQuery.values[i], 'param '+(i+1)); + assert.equal(expectedParams[i], compiledQuery.values[i], 'param '+(i+1)); } } } - t.end(); }); diff --git a/test/index-tests.js b/test/index-tests.js index fe989b57..0ba1d463 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -1,6 +1,6 @@ 'use strict'; +var assert = require('assert'); -var test = require('tap').test; var sql = require(__dirname + '/../lib'); var user = sql.define({ @@ -8,26 +8,24 @@ var user = sql.define({ columns: ['id', 'email'] }); -test('unknown dialect', function(t) { - console.log('unknown dialect throws exception'); - t.throws(function() { - sql.setDialect('asdf'); +suite('index', function() { + test('unknown dialect throws exception', function() { + assert.throws(function() { + sql.setDialect('asdf'); + }); }); - t.end(); -}); -test('throws before dialect is set', function(t) { - t.throws(function() { - var query = sql.select(user.id).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); + test('throws before dialect is set', function() { + assert.throws(function() { + var query = sql.select(user.id).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); + }); }); - t.end(); -}); -test('setting dialect to postgres works', function(t) { - sql.setDialect('postgres'); - var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - t.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); - t.equal(query.values[0], 'brian.m.carlson@gmail.com'); - t.end(); + test('setting dialect to postgres works', function() { + sql.setDialect('postgres'); + 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)'); + assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); + }); }); diff --git a/test/index.js b/test/index.js index 15d573f0..20003ffc 100644 --- a/test/index.js +++ b/test/index.js @@ -3,10 +3,9 @@ var fs = require('fs'); var path = require('path'); -var testDir = path.dirname(require.main.filename); +var testDir = __dirname; var directories = [ - testDir, testDir + '/dialects' ]; @@ -15,7 +14,6 @@ directories.forEach(function (d) { /*jshint boss: true */ for(var i = 0, file; file = files[i]; i++) { var filePath = path.join(d, file); - console.log(filePath); require(filePath); } }); diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 00000000..5efaf24d --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1 @@ +--ui tdd diff --git a/test/select-tests.js b/test/select-tests.js index 37325b13..b771a831 100644 --- a/test/select-tests.js +++ b/test/select-tests.js @@ -4,6 +4,11 @@ var assert = require('assert'); var Select = require(__dirname + '/../lib/node/select'); var select = new Select(); -assert.equal(select.type, 'SELECT'); +test('has SELECT type', function() { + assert.equal(select.type, 'SELECT'); +}); -assert.equal(select.toQuery().text, 'SELECT '); + +test('can go toQuery', function() { + assert.equal(select.toQuery().text, 'SELECT '); +}); diff --git a/test/table-tests.js b/test/table-tests.js index 7b0770ac..11528a7d 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -1,50 +1,58 @@ 'use strict'; +var assert = require('assert'); -var test = require('tap').test; var Table = require(__dirname + '/../lib/table'); var Column = require(__dirname + '/../lib/column'); -test('table', function(t) { +suite('table', function() { var table = new Table({ name: 'bang' }); - t.equal(table.getName(), 'bang'); - t.equal(table.columns.length, 0); + test('has name', function() { + assert.equal(table.getName(), 'bang'); + }); - var col = new Column({ - table: table, - name: 'boom' + test('has no columns', function() { + assert.equal(table.columns.length, 0); }); - t.equal(col.name, 'boom'); - t.equal(col.table.getName(), 'bang'); + test('can add column', function() { + + var col = new Column({ + table: table, + name: 'boom' + }); - table.addColumn(col); - t.equal(table.columns.length, 1); - t.equal(table.boom, col); + assert.equal(col.name, 'boom'); + assert.equal(col.table.getName(), 'bang'); - console.log('table creates query node'); - var sel = table.select(table.boom); - t.equal(sel.type, 'QUERY'); + table.addColumn(col); + assert.equal(table.columns.length, 1); + assert.equal(table.boom, col); + }) - console.log('table can be defined'); - var user = Table.define({ - name: 'user', - columns: ['id', 'name'] + test('creates query node', function() { + var sel = table.select(table.boom); + assert.equal(sel.type, 'QUERY'); }); - t.equal(user.getName(), 'user'); - t.equal(user.columns.length, 2); - t.equal(user.columns[0].name, 'id'); - t.equal(user.columns[1].name, 'name'); - t.equal(user.columns[0].name, user.id.name); - t.equal(user.id.table, user); - t.equal(user.name.table, user); - t.end(); + test('can be defined', function() { + var user = Table.define({ + name: 'user', + columns: ['id', 'name'] + }); + assert.equal(user.getName(), 'user'); + assert.equal(user.columns.length, 2); + assert.equal(user.columns[0].name, 'id'); + assert.equal(user.columns[1].name, 'name'); + assert.equal(user.columns[0].name, user.id.name); + assert.equal(user.id.table, user); + assert.equal(user.name.table, user); + }); }); -test('table with fancier column definitions', function(t) { +test('table with fancier column definitions', function() { var table = Table.define({ name: 'blah', columns: [{ @@ -61,17 +69,16 @@ test('table with fancier column definitions', function(t) { }] }); var cols = table.columns; - t.equals(cols.length, 2); + assert.equal(cols.length, 2); var id = cols[0]; - t.equals(id.name, 'id'); - t.equals(id.type, 'serial'); - t.equals(id.notNull, true); - t.equals(id.primaryKey, true); + assert.equal(id.name, 'id'); + assert.equal(id.type, 'serial'); + assert.equal(id.notNull, true); + assert.equal(id.primaryKey, true); var email = cols[1]; - t.equals(email.name, 'email'); - t.equals(email.type, 'text'); - t.equals(email.notNull, true); - t.equals(email.unique, true); - t.equals(email.anythingYouWant, 'awesome'); - t.end(); + assert.equal(email.name, 'email'); + assert.equal(email.type, 'text'); + assert.equal(email.notNull, true); + assert.equal(email.unique, true); + assert.equal(email.anythingYouWant, 'awesome'); }); From 1fe89bc6e3ff653bc0218dfeb6aa4c7ef5a2d10e Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 3 May 2013 10:50:26 -0500 Subject: [PATCH 068/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb804086..47b69ade 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.10.0", + "version": "0.11.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 9ef6acbb7dd17002498ec5a2add4129ddedd3be6 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 3 May 2013 10:51:35 -0500 Subject: [PATCH 069/507] Update package.json to use mocha --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 47b69ade..cb821052 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "main": "lib/", "scripts": { - "test": "node test/" + "test": "./node_modules/.bin/mocha" }, "engines": { "node": "*" @@ -19,7 +19,6 @@ "sliced": "0.0.5" }, "devDependencies": { - "test-dir": "*", - "tap": "*" + "mocha": "*" } } From 5b3954585f38d18597cedd4e21aadc22e8e84df9 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 6 May 2013 10:33:29 -0500 Subject: [PATCH 070/507] Add ability to call #where with multiple arguments Initial work on buliding a more complex and feature-full where clause builder --- lib/node/query.js | 8 ++++++++ lib/node/where.js | 4 ++++ lib/table.js | 12 ++++++++++++ test/dialects/where-clause-tests.js | 18 ++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 test/dialects/where-clause-tests.js diff --git a/lib/node/query.js b/lib/node/query.js index c8201d89..720efbbc 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -71,6 +71,14 @@ var Query = Node.define({ return this.add(from); }, where: function(node) { + if(arguments.length > 1) { + //allow multiple where clause arguments + var args = sliced(arguments); + for(var i = 0; i < args.length; i++) { + this.where(args[i]); + } + return this; + } //calling #where twice functions like calling #where & then #and if(this.whereClause) return this.and(node); this.whereClause = new Where(this.table); diff --git a/lib/node/where.js b/lib/node/where.js index f4520570..67f7be2c 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -35,6 +35,10 @@ module.exports = Node.define({ }, or: function(other) { var right = normalizeNode(this.table, other); + //calling 'or' without an initial 'where' + if(!this.nodes.length) { + return this.add(other); + } return this.nodes.push(new BinaryNode({ left: this.nodes.pop(), operator: 'OR', diff --git a/lib/table.js b/lib/table.js index c725b4ad..9f1a0b8b 100644 --- a/lib/table.js +++ b/lib/table.js @@ -149,4 +149,16 @@ Table.prototype.where = function() { 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; +}; + module.exports = Table; diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js new file mode 100644 index 00000000..e9bcc7f4 --- /dev/null +++ b/test/dialects/where-clause-tests.js @@ -0,0 +1,18 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); + +Harness.test({ + query : user.where(user.id.isNotNull(), user.name.isNotNull()), + pg : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + mysql : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', + sqlite: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' +}); + +Harness.test({ + query : user.and(user.id.isNotNull(), user.name.isNotNull()), + pg : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + mysql : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', + sqlite: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' +}); From a9a8a9983b6fffc4be4fdaedd91149bf4bb5d217 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 6 May 2013 12:56:51 -0500 Subject: [PATCH 071/507] Add support for DISTINCT usage: `users.select(users.email.distinct())` --- lib/column.js | 6 ++++++ lib/dialect/postgres.js | 8 +++++++- lib/node/column.js | 1 + test/dialects/distinct-tests.js | 9 +++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/dialects/distinct-tests.js diff --git a/lib/column.js b/lib/column.js index 5f5a5425..93abecad 100644 --- a/lib/column.js +++ b/lib/column.js @@ -91,6 +91,12 @@ Column.prototype.count = function(alias) { return new ColumnNode(context); }; +Column.prototype.distinct = function() { + var context = contextify(this); + context.distinct = true; + return new ColumnNode(context); +}; + binaryMethod('equals', '='); binaryMethod('equal', '='); binaryMethod('notEqual', '<>'); diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 1af0b7b1..0a227eee 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -287,11 +287,17 @@ Postgres.prototype.visitColumn = function(columnNode) { var table = columnNode.table; var inSelectClause = !this._selectOrDeleteEndIndex; var txt = ""; + var closeParen = false; if(inSelectClause) { if (columnNode.asArray) { + closeParen = true; txt += this._arrayAggFunctionName+'('; } else if (columnNode.aggCount) { + closeParen = true; txt += 'COUNT('; + } else if (columnNode.distinct === true) { + closeParen = true; + txt += 'DISTINCT(' } } if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { @@ -311,7 +317,7 @@ Postgres.prototype.visitColumn = function(columnNode) { } else { txt += this.quote(columnNode.name); } - if(inSelectClause && (columnNode.asArray || columnNode.aggCount)) { + if(closeParen) { txt += ')'; } if(inSelectClause && columnNode.alias) { diff --git a/lib/node/column.js b/lib/node/column.js index 0bd0a21b..a7d19b34 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -14,6 +14,7 @@ module.exports = Node.define({ this.table = config.table; this.value = config.getValue(); this.dataType = config.dataType; + this.distinct = config.distinct; }, as: function(alias) { this.alias = alias; diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js new file mode 100644 index 00000000..58aaa6b7 --- /dev/null +++ b/test/dialects/distinct-tests.js @@ -0,0 +1,9 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); + +Harness.test({ + query : user.select(user.id.distinct()), + pg : 'SELECT DISTINCT("user"."id") FROM "user"' +}); From 01ff641ce4e3a592e60376ac3cdb77b91dd87649 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 6 May 2013 12:57:06 -0500 Subject: [PATCH 072/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb821052..f28e3bc3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.11.0", + "version": "0.12.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 275488d8fefad0c9b20df8d83ca8b4a9e9ac2d02 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Thu, 9 May 2013 09:57:29 -0500 Subject: [PATCH 073/507] Add count().distinct() to columns --- lib/dialect/postgres.js | 16 +++++++++------- test/dialects/distinct-tests.js | 5 +++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 0a227eee..4bffb67c 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -287,16 +287,16 @@ Postgres.prototype.visitColumn = function(columnNode) { var table = columnNode.table; var inSelectClause = !this._selectOrDeleteEndIndex; var txt = ""; - var closeParen = false; + var closeParen = 0; if(inSelectClause) { if (columnNode.asArray) { - closeParen = true; + closeParen++; txt += this._arrayAggFunctionName+'('; - } else if (columnNode.aggCount) { - closeParen = true; + } if (columnNode.aggCount) { + closeParen++; txt += 'COUNT('; - } else if (columnNode.distinct === true) { - closeParen = true; + } if (columnNode.distinct === true) { + closeParen++; txt += 'DISTINCT(' } } @@ -318,7 +318,9 @@ Postgres.prototype.visitColumn = function(columnNode) { txt += this.quote(columnNode.name); } if(closeParen) { - txt += ')'; + for(var i = 0; i < closeParen; i++) { + txt += ')'; + } } if(inSelectClause && columnNode.alias) { txt += ' AS ' + this.quote(columnNode.alias); diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js index 58aaa6b7..f803c0ad 100644 --- a/test/dialects/distinct-tests.js +++ b/test/dialects/distinct-tests.js @@ -7,3 +7,8 @@ Harness.test({ query : user.select(user.id.distinct()), pg : 'SELECT DISTINCT("user"."id") FROM "user"' }); + +Harness.test({ + query : user.select(user.id.count().distinct().as('count')), + pg : 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' +}); From 795607fb48300cb1c901a87101476c6d25228415 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Thu, 9 May 2013 09:57:59 -0500 Subject: [PATCH 074/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f28e3bc3..7e3c0f3f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.12.0", + "version": "0.13.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From f5b6961301f3e515b32f12be1b19f6b18d64286b Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Thu, 9 May 2013 10:28:23 -0500 Subject: [PATCH 075/507] Add 'NOT LIKE' support --- lib/column.js | 1 + test/binary-clause-tests.js | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/column.js b/lib/column.js index 93abecad..ef666613 100644 --- a/lib/column.js +++ b/lib/column.js @@ -108,6 +108,7 @@ binaryMethod('gte', '>='); binaryMethod('lt', '<'); binaryMethod('lte', '<='); binaryMethod('like', 'LIKE'); +binaryMethod('notLike', 'NOT LIKE'); binaryMethod('in', 'IN'); binaryMethod('notIn', 'NOT IN'); diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 9bf13a11..6d132bb8 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -13,6 +13,7 @@ test('operators', function() { assert.equal(Foo.baz.notEqual(1).operator, '<>'); assert.equal(Foo.baz.notEquals(1).operator, '<>'); assert.equal(Foo.baz.like('asdf').operator, 'LIKE'); + assert.equal(Foo.baz.notLike('asdf').operator, 'NOT LIKE'); assert.equal(Foo.baz.isNull().operator, 'IS NULL'); assert.equal(Foo.baz.isNotNull().operator, 'IS NOT NULL'); assert.equal(Foo.baz.gt(1).operator, '>'); From 3b1072f4013b1a25db4f12d9fa61696d83f5047f Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Thu, 9 May 2013 10:28:45 -0500 Subject: [PATCH 076/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7e3c0f3f..5e97e224 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.13.0", + "version": "0.14.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 951a55b76abdc88a53931bfc8e8e0ae4c2e866e6 Mon Sep 17 00:00:00 2001 From: bmc Date: Fri, 10 May 2013 10:21:36 -0500 Subject: [PATCH 077/507] Allow chainable selects --- lib/node/query.js | 10 ++++++++-- test/dialects/select-tests.js | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test/dialects/select-tests.js diff --git a/lib/node/query.js b/lib/node/query.js index 720efbbc..e08c5dfd 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -42,7 +42,13 @@ var Query = Node.define({ this.table = table; }, select: function() { - var select = new Select(); + var select; + if(this._select) { + select = this._select; + } else { + var select = this._select = new Select(); + this.add(select); + } var args = sliced(arguments); if(util.isArray(args[0])) { args = args[0]; @@ -60,7 +66,7 @@ var Query = Node.define({ } } } - return this.add(select); + return this; }, star: function() { assert( this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js new file mode 100644 index 00000000..fa12846e --- /dev/null +++ b/test/dialects/select-tests.js @@ -0,0 +1,11 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); + +Harness.test({ + query : post.select(post.id).select(post.content), + pg : 'SELECT "post"."id", "post"."content" FROM "post"', + sqlite: 'SELECT "post"."id", "post"."content" FROM "post"', + mysql : 'SELECT `post`.`id`, `post`.`content` FROM `post`' +}); From b4c9fa4435eec599b732264ff7cf125f06a2af0b Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 10 May 2013 13:36:05 -0500 Subject: [PATCH 078/507] remove redundant --- lib/node/query.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/query.js b/lib/node/query.js index e08c5dfd..8cdb6405 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -46,7 +46,7 @@ var Query = Node.define({ if(this._select) { select = this._select; } else { - var select = this._select = new Select(); + select = this._select = new Select(); this.add(select); } var args = sliced(arguments); From ef9aee41adad2f5113c6ddd32d0dc7498ed9df09 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Fri, 10 May 2013 20:41:47 +0200 Subject: [PATCH 079/507] added possibility to chain from statements --- lib/dialect/postgres.js | 9 ++++++++- test/dialects/from-clause-tests.js | 12 ++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 test/dialects/from-clause-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4bffb67c..b9bda626 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -162,7 +162,11 @@ Postgres.prototype.visitAlter = function(alter) { Postgres.prototype.visitFrom = function(from) { var result = []; - result.push('FROM'); + if (from.skipFromStatement) { + result.push(','); + } else { + result.push('FROM'); + } for(var i = 0; i < from.nodes.length; i++) { result = result.concat(this.visit(from.nodes[i])); } @@ -217,6 +221,7 @@ Postgres.prototype.visitQuery = function(queryNode) { //so select/insert/update/delete comes before from comes before where var sortedNodes = []; var missingFrom = true; + var hasFrom = false; var actions = []; var targets = []; var filters = []; @@ -236,6 +241,8 @@ Postgres.prototype.visitQuery = function(queryNode) { missingFrom = false; break; case "FROM": + node.skipFromStatement = hasFrom; + hasFrom = true; missingFrom = false; targets.push(node); break; diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js new file mode 100644 index 00000000..47ea598c --- /dev/null +++ b/test/dialects/from-clause-tests.js @@ -0,0 +1,12 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); +var post = Harness.definePostTable(); + +Harness.test({ + query : user.select(user.star()).from(user).from(post), + pg : 'SELECT "user".* FROM "user" , "post"', + sqlite: 'SELECT "user".* FROM "user" , "post"', + mysql : 'SELECT `user`.* FROM `user` , `post`' +}); From 09c9b89cd9e1aae5c8c48b5109bddbfcc5d2c1ab Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 10 May 2013 14:02:50 -0500 Subject: [PATCH 080/507] Add support for table.column.toQuery() Add tests to support the behavior. --- lib/column.js | 4 ++++ lib/dialect/postgres.js | 5 +++-- test/column-tests.js | 27 +++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/column-tests.js diff --git a/lib/column.js b/lib/column.js index ef666613..88c297f8 100644 --- a/lib/column.js +++ b/lib/column.js @@ -97,6 +97,10 @@ Column.prototype.distinct = function() { return new ColumnNode(context); }; +Column.prototype.toQuery = function() { + return this.toNode().toQuery(); +}; + binaryMethod('equals', '='); binaryMethod('equal', '='); binaryMethod('notEqual', '<>'); diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 4bffb67c..a44a04b9 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -3,6 +3,7 @@ var assert = require('assert'); var From = require(__dirname + '/../node/from'); var Select = require(__dirname + '/../node/select'); +var Table = require(__dirname + '/../table'); var Postgres = function() { this.output = []; this.params = []; @@ -14,7 +15,7 @@ Postgres.prototype._arrayAggFunctionName = 'array_agg'; Postgres.prototype.getQuery = function(queryNode) { //passed in a table, not a query - if(queryNode.name) { + if(queryNode instanceof Table) { queryNode = queryNode.select(queryNode.star()); } this.output = this.visit(queryNode); @@ -330,7 +331,7 @@ Postgres.prototype.visitColumn = function(columnNode) { ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); txt += ' ' + columnNode.dataType; } - return txt; + return [txt]; }; Postgres.prototype.visitParameter = function(parameter) { diff --git a/test/column-tests.js b/test/column-tests.js new file mode 100644 index 00000000..6b7970eb --- /dev/null +++ b/test/column-tests.js @@ -0,0 +1,27 @@ +var assert = require('assert'); +var sql = require(__dirname + '/../lib'); + +describe('column', function() { + var table = sql.define({ + name: 'user', + columns: ['id', 'created'] + }); + + it('can be accessed by property and array', function() { + assert.equal(table.created, table.columns[1], 'should be able to access created both by array and property'); + }); + + describe('toQuery()', function() { + it('works', function() { + assert.equal(table.id.toQuery().text, '"user"."id"'); + }); + + it('respects AS rename', function() { + assert.equal(table.id.as('userId').toQuery().text, '"user"."id" AS "userId"'); + }); + + it('respects count and distinct', function() { + assert.equal(table.id.count().distinct().as("userIdCount").toQuery().text, 'COUNT(DISTINCT("user"."id")) AS "userIdCount"'); + }); + }); +}); From 61ccd711d0db14afacddaae63172aa005ec825b0 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Fri, 10 May 2013 14:25:47 -0500 Subject: [PATCH 081/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5e97e224..41b2c74e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.14.0", + "version": "0.15.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From eda540a4a1265690668358c7b31c93b9b397a497 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Fri, 10 May 2013 22:03:44 +0200 Subject: [PATCH 082/507] allow dynamical definition of columns --- lib/table.js | 19 +++++++++++-------- test/table-tests.js | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/table.js b/lib/table.js index 9f1a0b8b..56a46137 100644 --- a/lib/table.js +++ b/lib/table.js @@ -1,4 +1,4 @@ -'use strict'; + 'use strict'; var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); @@ -16,22 +16,25 @@ var Table = function(config) { Table.define = function(config) { var table = new Table(config); for (var i = 0; i < config.columns.length; i++) { - var col = config.columns[i]; + table.addColumn(config.columns[i]); + } + return table; +}; + +Table.prototype.addColumn = function(col) { + if(!(col instanceof Column)) { if(typeof col === 'string') { col = { name: col }; } - col.table = table; + + col.table = this; col = new Column(col); - table.addColumn(col); } - return table; -}; -Table.prototype.addColumn = function(col) { - this.columns.push(col); if(this[col.name]) { throw new Error('Table ' + this._name + ' already has column or property by the name of ' + col.name); } + this.columns.push(col); this[col.name] = col; return this; }; diff --git a/test/table-tests.js b/test/table-tests.js index 11528a7d..deafdf05 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -18,7 +18,7 @@ suite('table', function() { }); test('can add column', function() { - + var col = new Column({ table: table, name: 'boom' @@ -82,3 +82,19 @@ test('table with fancier column definitions', function() { assert.equal(email.unique, true); assert.equal(email.anythingYouWant, 'awesome'); }); + +test('table with dynamic column definition', function() { + var table = Table.define({ name: 'foo', columns: [] }); + assert.equal(table.columns.length, 0); + + table.addColumn('foo'); + assert.equal(table.columns.length, 1); + + var error = null; + + assert.throws(function() { + table.addColumn('foo'); + }); + + assert.equal(table.columns.length, 1); +}); From da961d48ac42dd9b5e6fa241d466df0e93d0c009 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Fri, 10 May 2013 22:04:40 +0200 Subject: [PATCH 083/507] whoops --- lib/table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index 56a46137..e6c6dee4 100644 --- a/lib/table.js +++ b/lib/table.js @@ -1,4 +1,4 @@ - 'use strict'; +'use strict'; var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); From 669e1c433a0361bb36b126a09eab7a49f3aba1b7 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Fri, 10 May 2013 22:07:28 +0200 Subject: [PATCH 084/507] formatting --- test/table-tests.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/table-tests.js b/test/table-tests.js index deafdf05..575b9609 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -18,7 +18,6 @@ suite('table', function() { }); test('can add column', function() { - var col = new Column({ table: table, name: 'boom' From f3bc8d27903db0f218d89bda24aa49b70b63162d Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sat, 11 May 2013 13:32:14 +0200 Subject: [PATCH 085/507] - added createColumn that transforms input into a column - added hasColumn that checks if there is already a column with a certain name - use hasColumn everywhere --- lib/table.js | 30 +++++++++++++++++++++++++----- package.json | 2 +- test/table-tests.js | 21 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/table.js b/lib/table.js index e6c6dee4..4c25092d 100644 --- a/lib/table.js +++ b/lib/table.js @@ -21,7 +21,7 @@ Table.define = function(config) { return table; }; -Table.prototype.addColumn = function(col) { +Table.prototype.createColumn = function(col) { if(!(col instanceof Column)) { if(typeof col === 'string') { col = { name: col }; @@ -31,19 +31,39 @@ Table.prototype.addColumn = function(col) { col = new Column(col); } - if(this[col.name]) { + return col; +}; + +Table.prototype.addColumn = function(col) { + col = this.createColumn(col); + + if(this.hasColumn(col)) { throw new Error('Table ' + this._name + ' already has column or property by the name of ' + col.name); + } else if(!!this[col.name] && (process.env.NODE_ENV !== 'test')) { + 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); - this[col.name] = col; + this[col.name] = this[col.name] || col; return this; }; +Table.prototype.hasColumn = function(col) { + col = this.createColumn(col); + + var cols = this.columns.filter(function(column) { + return column.name === col.name; + }); + + return cols.length > 0; +}; + Table.prototype.getColumn = function(colName) { - var col = this[colName]; - if(!col) { + var col = this.createColumn(colName); + + if(!this.hasColumn(col)) { throw new Error('Table ' + this._name + ' does not have a column named ' + colName); } + return col; }; diff --git a/package.json b/package.json index 41b2c74e..f7fe7019 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "main": "lib/", "scripts": { - "test": "./node_modules/.bin/mocha" + "test": "NODE_ENV=test ./node_modules/.bin/mocha" }, "engines": { "node": "*" diff --git a/test/table-tests.js b/test/table-tests.js index 575b9609..e3f2ab56 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -97,3 +97,24 @@ test('table with dynamic column definition', function() { assert.equal(table.columns.length, 1); }); + + +test('hasColumn', function() { + var table = Table.define({ name: 'foo', columns: [] }); + + assert.equal(table.hasColumn('baz'), false); + table.addColumn('baz'); + assert.equal(table.hasColumn('baz'), true); +}); + +test('the column "from" does not overwrite the from method', function() { + var table = Table.define({ name: 'foo', columns: [] }); + table.addColumn('from'); + assert.equal(typeof table.from, 'function'); +}); + +test('getColumn returns the from column', function() { + var table = Table.define({ name: 'foo', columns: [] }); + table.addColumn('from'); + assert(table.getColumn('from') instanceof Column); +}); From d1d97deb7fbf5817ea13d782afb12b0c347b2573 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sat, 11 May 2013 13:38:36 +0200 Subject: [PATCH 086/507] added shorthand form of getColumn => get --- lib/table.js | 4 +++- test/table-tests.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index 4c25092d..5b022408 100644 --- a/lib/table.js +++ b/lib/table.js @@ -57,7 +57,9 @@ Table.prototype.hasColumn = function(col) { return cols.length > 0; }; -Table.prototype.getColumn = function(colName) { +Table.prototype.getColumn = +Table.prototype.get = +function(colName) { var col = this.createColumn(colName); if(!this.hasColumn(col)) { diff --git a/test/table-tests.js b/test/table-tests.js index e3f2ab56..b15d29f9 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -117,4 +117,5 @@ test('getColumn returns the from column', function() { var table = Table.define({ name: 'foo', columns: [] }); table.addColumn('from'); assert(table.getColumn('from') instanceof Column); + assert(table.get('from') instanceof Column); }); From e29c18e5f4845de0f321d2d73ae96ddaf50c6509 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sat, 11 May 2013 14:11:11 +0200 Subject: [PATCH 087/507] use new get method --- lib/node/query.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 8cdb6405..35c7c56c 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -122,7 +122,7 @@ var Query = Node.define({ //object literal if(arguments.length == 1 && !o.toNode && !o.forEach) { args = Object.keys(o).map(function(key) { - return self.table[key].value(o[key]); + return self.table.get(key).value(o[key]); }); } else if (o.forEach) { o.forEach(function (arg) { @@ -147,7 +147,7 @@ var Query = Node.define({ var update = new Update(); Object.keys(o).forEach(function(key) { var val = o[key]; - update.add(self.table[key].value(val && val.toNode ? val.toNode() : new ParameterNode(val))); + update.add(self.table.get(key).value(val && val.toNode ? val.toNode() : new ParameterNode(val))); }); return this.add(update); }, From eb7fd2ce7fbca8802711fd97fce1debe3fde788b Mon Sep 17 00:00:00 2001 From: Gorgi Kosev Date: Mon, 13 May 2013 20:08:59 +0200 Subject: [PATCH 088/507] fix multi-field object in where clause bug When a multi-field object is passed to a where clause, all fields except the first one were being ignored. This commit fixes the bug. --- lib/node/where.js | 2 +- test/dialects/table-tests.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/node/where.js b/lib/node/where.js index 67f7be2c..0a8b126b 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -17,7 +17,7 @@ var normalizeNode = function(table, node) { if (!result) result = query; else - result.and(query); + result = result.and(query); } } return result; diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 5e7a2b6d..21f40b39 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -166,6 +166,14 @@ Harness.test({ params: ['brian'] }); +Harness.test({ + query : user.select('name').from('user').where({name: 'brian', id: 1}), + pg : 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + sqlite: 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + mysql : 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + params: ['brian', 1] +}); + Harness.test({ query : user.select(user.name.as('quote"quote"tick`tick`')), pg : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', From d8d970c3a70291ccb19d51fadbb8fc50e1e84062 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 13 May 2013 20:20:47 +0200 Subject: [PATCH 089/507] added failing test for renameColumn --- test/dialects/alter-table-tests.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 2eed1d09..dc998b90 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -121,3 +121,21 @@ Harness.test({ mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', params: [] }); + +var UserWithSignature = Table.define({ + name: 'UserWithSignature', + columns: [{ + name: 'Signature', + dataType: "VARCHAR(255) NOT NULL DEFAULT 'Signature'" + }] +}) + +Harness.test({ + query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), + pg: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', + mysql: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig`VARCHAR(255) NOT NULL DEFAULT \'Signature\'', + sqlite: { + text : 'Sqlite cannot rename columns', + throws: true + } +}) From 3a78b26162106933bde4b3d09b61be6c7f0b929e Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 14 May 2013 09:04:23 -0500 Subject: [PATCH 090/507] Fix expected query statement in test --- test/dialects/alter-table-tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index dc998b90..612a89eb 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -133,7 +133,7 @@ var UserWithSignature = Table.define({ Harness.test({ query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), pg: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', - mysql: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig`VARCHAR(255) NOT NULL DEFAULT \'Signature\'', + mysql: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'', sqlite: { text : 'Sqlite cannot rename columns', throws: true From f2146843f4160bfb85ce050b038758d0a7f3b838 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 14 May 2013 09:04:44 -0500 Subject: [PATCH 091/507] Return actual column, not a copy, when calling get --- lib/table.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/table.js b/lib/table.js index 5b022408..da420441 100644 --- a/lib/table.js +++ b/lib/table.js @@ -60,13 +60,13 @@ Table.prototype.hasColumn = function(col) { Table.prototype.getColumn = Table.prototype.get = function(colName) { - var col = this.createColumn(colName); - - if(!this.hasColumn(col)) { - throw new Error('Table ' + this._name + ' does not have a column named ' + colName); + for(var i = 0; i < this.columns.length; i++) { + var col = this.columns[i]; + if(col.name == colName) { + return col; + } } - - return col; + throw new Error('Table ' + this._name + ' does not have a column named ' + colName); }; Table.prototype.getSchema = function() { From aa1c09887a75f18f839c1b5bf6c05a8704651072 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 15 May 2013 10:25:12 -0500 Subject: [PATCH 092/507] Allow hash of columns as well as an array allows table definition like this: var table = sql.define({ name: 'blah', columns: { id: { primaryKey: true, type: 'serial' }, email: { type: 'text' } } }); --- lib/table.js | 14 ++++++++++++++ test/table-tests.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/table.js b/lib/table.js index da420441..423b3a32 100644 --- a/lib/table.js +++ b/lib/table.js @@ -1,5 +1,7 @@ 'use strict'; +var util = require('util'); + var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); var TableNode = require(__dirname + '/node/table'); @@ -15,6 +17,18 @@ var Table = function(config) { Table.define = function(config) { var table = new Table(config); + + //allow hash of columns as well as array + if(config.columns && !util.isArray(config.columns)) { + var cols = [] + for(var key in config.columns) { + var col = config.columns[key]; + col.name = key; + cols.push(col); + } + config.columns = cols; + } + for (var i = 0; i < config.columns.length; i++) { table.addColumn(config.columns[i]); } diff --git a/test/table-tests.js b/test/table-tests.js index b15d29f9..46a231fa 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -82,6 +82,37 @@ test('table with fancier column definitions', function() { assert.equal(email.anythingYouWant, 'awesome'); }); +test('table with object structured column definitions', function() { + var table = Table.define({ + name: 'blah', + columns: { + id: { + type: 'serial', + notNull: true, + primaryKey: true + }, + email: { + type: 'text', + notNull: true, + unique: true, + anythingYouWant: 'awesome' + } + } + }); + var cols = table.columns; + assert.equal(cols.length, 2); + var id = cols[0]; + assert.equal(id.name, 'id'); + assert.equal(id.type, 'serial'); + assert.equal(id.notNull, true); + assert.equal(id.primaryKey, true); + var email = cols[1]; + assert.equal(email.name, 'email'); + assert.equal(email.type, 'text'); + assert.equal(email.notNull, true); + assert.equal(email.unique, true); + assert.equal(email.anythingYouWant, 'awesome'); +}); test('table with dynamic column definition', function() { var table = Table.define({ name: 'foo', columns: [] }); assert.equal(table.columns.length, 0); From 2b010dd7be28080264946ea8ae8ba43b8780e204 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 15 May 2013 15:50:58 -0500 Subject: [PATCH 093/507] Auto-join based on column information for usage please see test/dialects/join-to-tests.js --- lib/joiner.js | 39 ++++++++++++++++++++++++ lib/table.js | 6 ++++ test/dialects/join-to-tests.js | 54 ++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 lib/joiner.js create mode 100644 test/dialects/join-to-tests.js diff --git a/lib/joiner.js b/lib/joiner.js new file mode 100644 index 00000000..bd7a4e3c --- /dev/null +++ b/lib/joiner.js @@ -0,0 +1,39 @@ +var getPrimaryKeyColumn = function(table) { + for(var i = 0; i < table.columns.length; i++) { + var col = table.columns[i]; + if(col.primaryKey) { + return col; + } + } +}; + +var findReference = function(left, right) { + //find reference + for(var i = 0; i < right.columns.length; i++) { + var col = right.columns[i]; + if(col.references) { + var leftName = left.getName(); + if(col.references == leftName || col.references.table == leftName) { + var leftCol = left[col.references.column] || getPrimaryKeyColumn(left); + return { + left: leftCol, + right: col + }; + } + } + } +}; + +module.exports = { + //auto-join two tables based on column properties + //requires one column to have { references: {table: 'foreignTableName', column: 'foreignColumnName'}} + //or to have { references: 'foreignTableName'} -- in which case the foreign table's primary key is assumed + leftJoin: function(left, right) { + var leftCol, rightCol; + var ref = findReference(left, right); + if(!ref) { + ref = findReference(right, left); + } + return left.join(right).on(ref.left.equals(ref.right)); + } +} diff --git a/lib/table.js b/lib/table.js index 423b3a32..7286cfe9 100644 --- a/lib/table.js +++ b/lib/table.js @@ -6,6 +6,7 @@ var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); var TableNode = require(__dirname + '/node/table'); var JoinNode = require(__dirname + '/node/join'); +var Joiner = require(__dirname + '/joiner'); var Table = function(config) { this._schema = config.schema; @@ -170,6 +171,11 @@ Table.prototype.leftJoin = function(other) { return new JoinNode('LEFT', this.toNode(), other.toNode()); }; +//auto-join tables based on column intropsection +Table.prototype.joinTo = function(other) { + return Joiner.leftJoin(this, other); +}; + Table.prototype.as = function(alias) { //TODO could this be cleaner? var t = Table.define(this._initialConfig); diff --git a/test/dialects/join-to-tests.js b/test/dialects/join-to-tests.js new file mode 100644 index 00000000..93f64579 --- /dev/null +++ b/test/dialects/join-to-tests.js @@ -0,0 +1,54 @@ +'use strict'; +var sql = require(__dirname + '/../../lib'); + +var Harness = require('./support'); + +var user = sql.define({ + name: 'user', + columns: { + id: { primaryKey: true } + } +}); + +var photo = sql.define({ + name: 'photo', + columns: { + ownerId: { + references: 'user' + } + } +}); + +var post = sql.define({ + name: 'post', + columns: { + id: { primaryKey: true }, + ownerId: { + references: { + table: 'user', + column: 'id' + } + } + } +}); + +Harness.test({ + query : user.joinTo(post), + pg : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + sqlite: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + mysql : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' +}); + +Harness.test({ + query : post.joinTo(user), + pg : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + sqlite: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + mysql : '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' +}); + +Harness.test({ + query : user.joinTo(photo), + pg : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + sqlite: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + mysql : '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)' +}); From 85b3a96ab0835bbedfde57c83204e1ff8106b2d6 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 15 May 2013 15:58:10 -0500 Subject: [PATCH 094/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f7fe7019..0a0bec9f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.15.0", + "version": "0.16.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 0bd0ee7207fb0651b5583ac9a597f6936337d83d Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 19 May 2013 21:46:44 +0200 Subject: [PATCH 095/507] added methods for reading indexes --- lib/dialect/mysql.js | 6 ++++++ lib/dialect/postgres.js | 15 +++++++++++++++ lib/dialect/sqlite.js | 5 +++++ lib/node/indexes.js | 12 ++++++++++++ lib/node/query.js | 5 +++++ lib/table.js | 6 ++++++ test/dialects/indexes-tests.js | 11 +++++++++++ 7 files changed, 60 insertions(+) create mode 100644 lib/node/indexes.js create mode 100644 test/dialects/indexes-tests.js diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index a3b48f6e..6e9fdf3f 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -41,4 +41,10 @@ Mysql.prototype.visitInsert = function(insert) { return result; }; +Mysql.prototype.visitIndexes = function(node) { + var tableName = this.visit(this._queryNode.table.toNode()); + + return "SHOW INDEX FROM " + tableName; +}; + module.exports = Mysql; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 82ce0ea0..57e40c1b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -54,6 +54,7 @@ Postgres.prototype.visit = function(node) { case 'ADD COLUMN': return this.visitAddColumn(node); case 'DROP COLUMN': return this.visitDropColumn(node); case 'RENAME COLUMN': return this.visitRenameColumn(node); + case "INDEXES": return this.visitIndexes(node); case 'LIMIT': case 'OFFSET': return this.visitModifier(node); @@ -233,6 +234,7 @@ Postgres.prototype.visitQuery = function(queryNode) { case "DELETE": actions.push(node); break; + case "INDEXES": case "INSERT": case "UPDATE": case "CREATE": @@ -397,4 +399,17 @@ Postgres.prototype.visitModifier = function(node) { return [node.type, node.count.type ? this.visit(node.count) : node.count]; }; +Postgres.prototype.visitIndexes = function(node) { + var tableName = this.visit(this._queryNode.table.toNode()); + + return [ + "SELECT relname", + "FROM pg_class", + "WHERE oid IN (", + "SELECT indexrelid", + "FROM pg_index, pg_class WHERE pg_class.relname=" + tableName, + "AND pg_class.oid=pg_index.indrelid)" + ].join(' '); +}; + module.exports = Postgres; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 321f28bf..bef7e3ac 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -39,4 +39,9 @@ Sqlite.prototype.visitAddColumn = function(addColumn) { return result; }; +Sqlite.prototype.visitIndexes = function(node) { + var tableName = this.visit(this._queryNode.table.toNode()); + return "PRAGMA INDEX_LIST(" + tableName + ")"; +}; + module.exports = Sqlite; diff --git a/lib/node/indexes.js b/lib/node/indexes.js new file mode 100644 index 00000000..bf5c1137 --- /dev/null +++ b/lib/node/indexes.js @@ -0,0 +1,12 @@ +'use strict'; + +var Node = require(__dirname); +var IndexesNode = module.exports = Node.define({ + type: 'INDEXES', + constructor: function () { + Node.call(this); + this.names = []; + this.columns = []; + this.valueSets = []; + } +}); diff --git a/lib/node/query.js b/lib/node/query.js index 35c7c56c..730fdd9f 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -26,6 +26,7 @@ var Column = require(__dirname + '/../column'); var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); +var Indexes = require(__dirname + '/indexes'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -226,6 +227,10 @@ var Query = Node.define({ ifNotExists: function() { this.nodes[0].add(new IfNotExists()); return this; + }, + indexes: function() { + this.add(new Indexes()); + return this; } }); diff --git a/lib/table.js b/lib/table.js index 7286cfe9..c1e8130b 100644 --- a/lib/table.js +++ b/lib/table.js @@ -206,4 +206,10 @@ Table.prototype.or = function() { return query; }; +Table.prototype.indexes = function() { + var query = new Query(this); + query.indexes.apply(query, arguments); + return query; +} + module.exports = Table; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js new file mode 100644 index 00000000..07ba65a7 --- /dev/null +++ b/test/dialects/indexes-tests.js @@ -0,0 +1,11 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); + +Harness.test({ + query: post.indexes(), + pg: "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)", + mysql: "SHOW INDEX FROM `post`", + sqlite: "PRAGMA INDEX_LIST(\"post\")" +}); From d61bdaebed2f2ca14ea684bb03dde7eeda98504c Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 20 May 2013 14:00:46 +0200 Subject: [PATCH 096/507] create on indexes --- lib/node/indexes.js | 8 +++++--- lib/node/query.js | 3 ++- lib/table.js | 2 +- test/dialects/indexes-tests.js | 11 +++++++++++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/node/indexes.js b/lib/node/indexes.js index bf5c1137..513b5c0b 100644 --- a/lib/node/indexes.js +++ b/lib/node/indexes.js @@ -3,10 +3,12 @@ var Node = require(__dirname); var IndexesNode = module.exports = Node.define({ type: 'INDEXES', - constructor: function () { + + constructor: function(table) { Node.call(this); - this.names = []; - this.columns = []; + this.table = table; + this.names = []; + this.columns = []; this.valueSets = []; } }); diff --git a/lib/node/query.js b/lib/node/query.js index 730fdd9f..e66208f6 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -229,7 +229,8 @@ var Query = Node.define({ return this; }, indexes: function() { - this.add(new Indexes()); + var indexes = new Indexes({ table: this.table }); + this.add(indexes); return this; } }); diff --git a/lib/table.js b/lib/table.js index c1e8130b..6ee45f45 100644 --- a/lib/table.js +++ b/lib/table.js @@ -210,6 +210,6 @@ Table.prototype.indexes = function() { var query = new Query(this); query.indexes.apply(query, arguments); return query; -} +}; module.exports = Table; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 07ba65a7..e59ad239 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -9,3 +9,14 @@ Harness.test({ mysql: "SHOW INDEX FROM `post`", sqlite: "PRAGMA INDEX_LIST(\"post\")" }); + +Harness.test({ + query: post.indexes().create({ + type: 'unique', + algorithm: 'btree', + parser: 'foo', + name: 'bar', + columns: [post.id, post.userId] + }), + mysql: "CREATE UNIQUE INDEX `bar` USING BTREE ON `post` (`post`.`id`, `post`.`userId`) WITH PARSER foo" +}) From 60a52dc91e6b9a29c74368b85174348f238172ca Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 20 May 2013 21:00:22 +0200 Subject: [PATCH 097/507] creating indexes is now based on chaining --- lib/dialect/postgres.js | 36 ++++++++++++++++++++++++++++++++- lib/node/createIndex.js | 37 ++++++++++++++++++++++++++++++++++ lib/node/indexes.js | 1 + lib/node/query.js | 26 +++++++++++++++++++----- lib/table.js | 8 ++++---- test/dialects/indexes-tests.js | 13 ++++-------- 6 files changed, 102 insertions(+), 19 deletions(-) create mode 100644 lib/node/createIndex.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 57e40c1b..e3971f4d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -54,7 +54,8 @@ Postgres.prototype.visit = function(node) { case 'ADD COLUMN': return this.visitAddColumn(node); case 'DROP COLUMN': return this.visitDropColumn(node); case 'RENAME COLUMN': return this.visitRenameColumn(node); - case "INDEXES": return this.visitIndexes(node); + case 'INDEXES': return this.visitIndexes(node); + case 'CREATE INDEX': return this.visitCreateIndex(node); case 'LIMIT': case 'OFFSET': return this.visitModifier(node); @@ -412,4 +413,37 @@ Postgres.prototype.visitIndexes = function(node) { ].join(' '); }; +Postgres.prototype.visitCreateIndex = function(node) { + console.log(node.options) + var tableName = this.visit(node.table.toNode()); + var indexName = node.options.indexName || tableName; + var indexNode = Table.define({ name: indexName, columns: [] }).toNode(); + var result = [ 'CREATE' ]; + + if (node.options.type) { + result.push(node.options.type.toUpperCase()); + } + + result = result.concat([ 'INDEX', this.visit(indexNode) ]); + + if (node.options.algorithm) { + result.push("USING " + node.options.algorithm.toUpperCase()); + } + + result = result.concat([ + "ON", + tableName, + "(" + node.options.columns.reduce(function(result, col) { + return result.concat(this.visit(col.toNode())); + }.bind(this), []) + ")" + ]); + + if (node.options.parser) { + result.push("WITH PARSER"); + result.push(node.options.parser); + } + + return result; +}; + module.exports = Postgres; diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js new file mode 100644 index 00000000..5bc66652 --- /dev/null +++ b/lib/node/createIndex.js @@ -0,0 +1,37 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'CREATE INDEX', + + constructor: function(table, indexName) { + Node.call(this); + + this.table = table; + this.names = []; + this.columns = []; + this.valueSets = []; + this.options = { indexName: indexName }; + }, + + unique: function() { + this.options.type = 'unique'; + return this; + }, + + using: function(algorithm) { + this.options.algorithm = algorithm; + return this; + }, + + onColumns: function() { + this.options.columns = Array.prototype.slice.call(arguments); + return this; + }, + + withParser: function(parser) { + this.options.parser = parser; + return this; + } +}); diff --git a/lib/node/indexes.js b/lib/node/indexes.js index 513b5c0b..7777c8f7 100644 --- a/lib/node/indexes.js +++ b/lib/node/indexes.js @@ -6,6 +6,7 @@ var IndexesNode = module.exports = Node.define({ constructor: function(table) { Node.call(this); + this.table = table; this.names = []; this.columns = []; diff --git a/lib/node/query.js b/lib/node/query.js index e66208f6..88eba1b1 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -27,6 +27,7 @@ var ParameterNode = require(__dirname + '/parameter'); var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); var Indexes = require(__dirname + '/indexes'); +var CreateIndex = require(__dirname + '/createIndex'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -168,15 +169,25 @@ var Query = Node.define({ returning.addAll(args); return this.add(returning); }, - create: function() { - return this.add(new Create()); + + create: function(indexName) { + if (this.indexesCause) { + var createIndex = new CreateIndex(this.table, indexName); + this.add(createIndex); + return createIndex; + } else { + return this.add(new Create()); + } }, + drop: function() { return this.add(new Drop()); }, + alter: function() { return this.add(new Alter()); }, + rename: function(newName) { var renameClause = new Rename(); if (!newName.toNode) @@ -203,6 +214,7 @@ var Query = Node.define({ this.nodes[0].add(dropClause); return this; }, + renameColumn: function(oldColumn, newColumn) { var renameClause = new RenameColumn(); if (!oldColumn.toNode) @@ -214,24 +226,28 @@ var Query = Node.define({ this.nodes[0].add(renameClause); return this; }, + limit: function(count) { return this.add(new Modifier(this, 'LIMIT', count)); }, + offset: function(count) { return this.add(new Modifier(this, 'OFFSET', count)); }, + ifExists: function() { this.nodes[0].add(new IfExists()); return this; }, + ifNotExists: function() { this.nodes[0].add(new IfNotExists()); return this; }, + indexes: function() { - var indexes = new Indexes({ table: this.table }); - this.add(indexes); - return this; + this.indexesCause = new Indexes({ table: this.table }); + return this.add(this.indexesCause); } }); diff --git a/lib/table.js b/lib/table.js index 6ee45f45..d733e45f 100644 --- a/lib/table.js +++ b/lib/table.js @@ -21,12 +21,14 @@ Table.define = function(config) { //allow hash of columns as well as array if(config.columns && !util.isArray(config.columns)) { - var cols = [] + var cols = []; + for(var key in config.columns) { var col = config.columns[key]; col.name = key; cols.push(col); } + config.columns = cols; } @@ -207,9 +209,7 @@ Table.prototype.or = function() { }; Table.prototype.indexes = function() { - var query = new Query(this); - query.indexes.apply(query, arguments); - return query; + return new Query(this).indexes(); }; module.exports = Table; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index e59ad239..59d0aadd 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -11,12 +11,7 @@ Harness.test({ }); Harness.test({ - query: post.indexes().create({ - type: 'unique', - algorithm: 'btree', - parser: 'foo', - name: 'bar', - columns: [post.id, post.userId] - }), - mysql: "CREATE UNIQUE INDEX `bar` USING BTREE ON `post` (`post`.`id`, `post`.`userId`) WITH PARSER foo" -}) + query: post.indexes().create('index_name').unique().using('btree').onColumns(post.id, post.userId).withParser('foo'), + pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo", + my2sql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`post`.`id`,`post`.`userId`) WITH PARSER foo" +}); From 2d80c3941aa29b5fbbace24b0d1d3c3cd4784a36 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 20 May 2013 21:02:03 +0200 Subject: [PATCH 098/507] test for sqlite --- lib/dialect/postgres.js | 1 - test/dialects/indexes-tests.js | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index e3971f4d..07034ef0 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -414,7 +414,6 @@ Postgres.prototype.visitIndexes = function(node) { }; Postgres.prototype.visitCreateIndex = function(node) { - console.log(node.options) var tableName = this.visit(node.table.toNode()); var indexName = node.options.indexName || tableName; var indexNode = Table.define({ name: indexName, columns: [] }).toNode(); diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 59d0aadd..8b4596f2 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -11,7 +11,8 @@ Harness.test({ }); Harness.test({ - query: post.indexes().create('index_name').unique().using('btree').onColumns(post.id, post.userId).withParser('foo'), - pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo", - my2sql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`post`.`id`,`post`.`userId`) WITH PARSER foo" + query: post.indexes().create('index_name').unique().using('btree').onColumns(post.id, post.userId).withParser('foo'), + pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo", + mysql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`post`.`id`,`post`.`userId`) WITH PARSER foo", + sqlite: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo" }); From e652985af26ed12f69f5a682e24c61eabb765620 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 20 May 2013 21:29:50 +0200 Subject: [PATCH 099/507] added test for index creation without custom name --- lib/dialect/postgres.js | 3 +-- lib/node/createIndex.js | 16 +++++++++++++++- test/dialects/indexes-tests.js | 9 ++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 07034ef0..f46b32ba 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -415,8 +415,7 @@ Postgres.prototype.visitIndexes = function(node) { Postgres.prototype.visitCreateIndex = function(node) { var tableName = this.visit(node.table.toNode()); - var indexName = node.options.indexName || tableName; - var indexNode = Table.define({ name: indexName, columns: [] }).toNode(); + var indexNode = Table.define({ name: node.indexName(), columns: [] }).toNode(); var result = [ 'CREATE' ]; if (node.options.type) { diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index 5bc66652..7b34f1cc 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -25,7 +25,7 @@ module.exports = Node.define({ return this; }, - onColumns: function() { + on: function() { this.options.columns = Array.prototype.slice.call(arguments); return this; }, @@ -33,5 +33,19 @@ module.exports = Node.define({ withParser: function(parser) { this.options.parser = parser; return this; + }, + + indexName: function() { + var result = this.options.indexName; + + if (!result) { + result = [this.table._name]; + this.options.columns.forEach(function(col) { + result.push(col.name); + }); + result = result.join('_'); + } + + return result; } }); diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 8b4596f2..c758da5e 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -11,8 +11,15 @@ Harness.test({ }); Harness.test({ - query: post.indexes().create('index_name').unique().using('btree').onColumns(post.id, post.userId).withParser('foo'), + query: post.indexes().create('index_name').unique().using('btree').on(post.id, post.userId).withParser('foo'), pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo", mysql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`post`.`id`,`post`.`userId`) WITH PARSER foo", sqlite: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo" }); + +Harness.test({ + query: post.indexes().create().on(post.userId), + pg: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")", + mysql: "CREATE INDEX `post_userId` ON `post` (`post`.`userId`)", + sqlite: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")", +}); From 0093f98edba175bb1113904c9b7bb05045458d87 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 20 May 2013 21:41:50 +0200 Subject: [PATCH 100/507] throw an error if no columns have been passed to index creation --- lib/dialect/postgres.js | 4 ++++ test/dialects/indexes-tests.js | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index f46b32ba..f3fb86d1 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -414,6 +414,10 @@ Postgres.prototype.visitIndexes = function(node) { }; Postgres.prototype.visitCreateIndex = function(node) { + if (!node.options.columns) { + throw new Error('No columns defined!'); + } + var tableName = this.visit(node.table.toNode()); var indexNode = Table.define({ name: node.indexName(), columns: [] }).toNode(); var result = [ 'CREATE' ]; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index c758da5e..2d76232c 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -21,5 +21,12 @@ Harness.test({ query: post.indexes().create().on(post.userId), pg: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")", mysql: "CREATE INDEX `post_userId` ON `post` (`post`.`userId`)", - sqlite: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")", + sqlite: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")" +}); + +Harness.test({ + query: post.indexes().create(), + pg: { text: 'No columns defined!', throws: true }, + mysql: { text: 'No columns defined!', throws: true }, + sqlite: { text: 'No columns defined!', throws: true } }); From f09e93118ad7f470b8919a0392ab5accd7638b56 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 20 May 2013 22:21:12 +0200 Subject: [PATCH 101/507] make sure that the generated index name is correctly sorted --- lib/node/createIndex.js | 8 +++++--- test/dialects/indexes-tests.js | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index 7b34f1cc..b013af9e 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -39,10 +39,12 @@ module.exports = Node.define({ var result = this.options.indexName; if (!result) { + var columns = this.options.columns.map(function(col) { + return col.name; + }).sort(); + result = [this.table._name]; - this.options.columns.forEach(function(col) { - result.push(col.name); - }); + result = result.concat(columns); result = result.join('_'); } diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 2d76232c..aab99895 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -18,10 +18,10 @@ Harness.test({ }); Harness.test({ - query: post.indexes().create().on(post.userId), - pg: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")", - mysql: "CREATE INDEX `post_userId` ON `post` (`post`.`userId`)", - sqlite: "CREATE INDEX \"post_userId\" ON \"post\" (\"post\".\"userId\")" + query: post.indexes().create().on(post.userId, post.id), + pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")", + mysql: "CREATE INDEX `post_id_userId` ON `post` (`post`.`userId`,`post`.`id`)", + sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")" }); Harness.test({ From 0655f3ca75779c1a4e0283f4a21d8bc5faca9a8d Mon Sep 17 00:00:00 2001 From: tmont Date: Tue, 21 May 2013 02:11:28 -0700 Subject: [PATCH 102/507] added section on using sql in conjunection with the node-sql-generate command line tool --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index 443086bf..a26d2339 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,42 @@ var friendsWhoUseGmailQuery = userToFriends.where(friends.email.like('%@gmail.co There are a __lot__ more examples included in the `test/dialects` folder. +## from the command line +You can use the [sql-generate module](https://github.com/tmont/node-sql-generate) +to automatically generate definition files from a database instance. For example, +running `node-sql-generate --dsn "mysql://user:password@host/database"` will generate +something similar to: + +```javascript +// autogenerated by node-sql-generate v0.0.1 on Tue May 21 2013 01:04:12 GMT-0700 (PDT) +var sql = require('sql'); + +/** + * SQL definition for database.bar + */ +exports.bar = sql.define({ + name: 'bar', + columns: [ + 'id', + 'foo_id' + ] +}); + +/** + * SQL definition for database.foo + */ +exports.foo = sql.define({ + name: 'foo', + columns: [ + 'id', + 'field_1', + 'foo_bar_baz' + ] +}); +``` + +Read the module's documentation for more details. + ## contributing I __love__ contributions. If I could, I would write __love__ 500 times, but that would be readme bloat. From 39a3e86f30a7aef4e3fde4462d7321cd9a5d1969 Mon Sep 17 00:00:00 2001 From: Andrey Popp <8mayday@gmail.com> Date: Tue, 21 May 2013 18:03:16 +0400 Subject: [PATCH 103/507] Table::select() creates *-select by default Test case provided. --- lib/table.js | 6 +++++- test/table-tests.js | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index 7286cfe9..2f86dea3 100644 --- a/lib/table.js +++ b/lib/table.js @@ -105,7 +105,11 @@ Table.prototype.count = function(alias) { Table.prototype.select = function() { //create the query and pass it off var query = new Query(this); - query.select.apply(query, arguments); + if (arguments.length === 0) { + query.select.call(query, this.star()); + } else { + query.select.apply(query, arguments); + } return query; }; diff --git a/test/table-tests.js b/test/table-tests.js index 46a231fa..6b989177 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -36,6 +36,11 @@ suite('table', function() { assert.equal(sel.type, 'QUERY'); }); + test('creates *-query if no args is provided to select()', function() { + var sel = table.select(); + assert.ok(sel.nodes[0].nodes[0].star); + }); + test('can be defined', function() { var user = Table.define({ name: 'user', From b9942f77af199969bbe7968b5c626840ced32685 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Tue, 21 May 2013 18:43:51 +0200 Subject: [PATCH 104/507] support for fulltext and spatial indexes --- lib/node/createIndex.js | 10 ++++++++++ test/dialects/indexes-tests.js | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index b013af9e..f78e9cc2 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -20,6 +20,16 @@ module.exports = Node.define({ return this; }, + spatial: function() { + this.options.type = 'spatial'; + return this; + }, + + fulltext: function() { + this.options.type = 'fulltext'; + return this; + }, + using: function(algorithm) { this.options.algorithm = algorithm; return this; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index aab99895..8287e0d9 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -17,6 +17,20 @@ Harness.test({ sqlite: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo" }); +Harness.test({ + query: post.indexes().create().fulltext().on(post.id), + pg: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"post\".\"id\")", + mysql: "CREATE FULLTEXT INDEX `post_id` ON `post` (`post`.`id`)", + sqlite: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"post\".\"id\")" +}); + +Harness.test({ + query: post.indexes().create().spatial().on(post.id), + pg: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"post\".\"id\")", + mysql: "CREATE SPATIAL INDEX `post_id` ON `post` (`post`.`id`)", + sqlite: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"post\".\"id\")" +}); + Harness.test({ query: post.indexes().create().on(post.userId, post.id), pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")", @@ -30,3 +44,24 @@ Harness.test({ mysql: { text: 'No columns defined!', throws: true }, sqlite: { text: 'No columns defined!', throws: true } }); + +// Harness.test({ +// query: post.indexes().drop(), +// pg: { text: 'No index defined!', throws: true }, +// mysql: { text: 'No index defined!', throws: true }, +// sqlite: { text: 'No index defined!', throws: true } +// }); + +// Harness.test({ +// query: post.indexes().drop('index_name'), +// pg: "DROP INDEX \"index_name\"", +// mysql: "DROP INDEX `index_name`", +// sqlite: "DROP INDEX \"index_name\"" +// }); + +// Harness.test({ +// query: post.indexes().drop(post.userId, post.id), +// pg: "DROP INDEX \"post_id_userId\"", +// mysql: "DROP INDEX `post_id_userId`", +// sqlite: "DROP INDEX \"post_id_userId\"" +// }); From 7d4b4a7cec6f6b7831a90b89680bd5c0aa00cbc1 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Tue, 21 May 2013 19:34:56 +0200 Subject: [PATCH 105/507] added support for dropping indexes --- lib/dialect/postgres.js | 9 +++++++ lib/node/dropIndex.js | 44 ++++++++++++++++++++++++++++++++++ lib/node/query.js | 10 +++++++- test/dialects/indexes-tests.js | 31 ++++++++++-------------- 4 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 lib/node/dropIndex.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index f3fb86d1..e5df7af6 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -56,6 +56,7 @@ Postgres.prototype.visit = function(node) { case 'RENAME COLUMN': return this.visitRenameColumn(node); case 'INDEXES': return this.visitIndexes(node); case 'CREATE INDEX': return this.visitCreateIndex(node); + case 'DROP INDEX': return this.visitDropIndex(node); case 'LIMIT': case 'OFFSET': return this.visitModifier(node); @@ -448,4 +449,12 @@ Postgres.prototype.visitCreateIndex = function(node) { return result; }; +Postgres.prototype.visitDropIndex = function(node) { + var result = [ 'DROP INDEX' ]; + result.push(this.visit(Table.define({ name: node.options.indexName, columns: [] }).toNode())); + result.push("ON"); + result.push(this.visit(node.table.toNode())); + return result; +}; + module.exports = Postgres; diff --git a/lib/node/dropIndex.js b/lib/node/dropIndex.js new file mode 100644 index 00000000..3b09f517 --- /dev/null +++ b/lib/node/dropIndex.js @@ -0,0 +1,44 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'DROP INDEX', + + constructor: function(table, indexName) { + var args = Array.prototype.slice.call(arguments); + + if (!indexName) { + throw new Error('No index defined!'); + } else if (Array.isArray(indexName) && (typeof indexName[0] === 'string')) { + indexName = indexName[0]; + } else if (Array.isArray(indexName)) { + var columns = indexName.map(function(col) { return col.name; }).sort(); + indexName = [table._name].concat(columns).join('_'); + } + + Node.call(this); + + this.table = table; + this.names = []; + this.columns = []; + this.valueSets = []; + this.options = { indexName: indexName }; + }, + + indexName: function() { + var result = this.options.indexName; + + if (!result) { + var columns = this.options.columns.map(function(col) { + return col.name; + }).sort(); + + result = [this.table._name]; + result = result.concat(columns); + result = result.join('_'); + } + + return result; + } +}); diff --git a/lib/node/query.js b/lib/node/query.js index 88eba1b1..1ba5e2e3 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -28,6 +28,7 @@ var IfExists = require(__dirname + '/ifExists'); var IfNotExists = require(__dirname + '/ifNotExists'); var Indexes = require(__dirname + '/indexes'); var CreateIndex = require(__dirname + '/createIndex'); +var DropIndex = require(__dirname + '/dropIndex'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -181,7 +182,14 @@ var Query = Node.define({ }, drop: function() { - return this.add(new Drop()); + if (this.indexesCause) { + var args = Array.prototype.slice.call(arguments); + var dropIndex = new DropIndex(this.table, args); + this.add(dropIndex); + return dropIndex; + } else { + return this.add(new Drop()); + } }, alter: function() { diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 8287e0d9..f4593907 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -45,23 +45,16 @@ Harness.test({ sqlite: { text: 'No columns defined!', throws: true } }); -// Harness.test({ -// query: post.indexes().drop(), -// pg: { text: 'No index defined!', throws: true }, -// mysql: { text: 'No index defined!', throws: true }, -// sqlite: { text: 'No index defined!', throws: true } -// }); - -// Harness.test({ -// query: post.indexes().drop('index_name'), -// pg: "DROP INDEX \"index_name\"", -// mysql: "DROP INDEX `index_name`", -// sqlite: "DROP INDEX \"index_name\"" -// }); +Harness.test({ + query: post.indexes().drop('index_name'), + pg: "DROP INDEX \"index_name\" ON \"post\"", + mysql: "DROP INDEX `index_name` ON `post`", + sqlite: "DROP INDEX \"index_name\" ON \"post\"" +}); -// Harness.test({ -// query: post.indexes().drop(post.userId, post.id), -// pg: "DROP INDEX \"post_id_userId\"", -// mysql: "DROP INDEX `post_id_userId`", -// sqlite: "DROP INDEX \"post_id_userId\"" -// }); +Harness.test({ + query: post.indexes().drop(post.userId, post.id), + pg: "DROP INDEX \"post_id_userId\" ON \"post\"", + mysql: "DROP INDEX `post_id_userId` ON `post`", + sqlite: "DROP INDEX \"post_id_userId\" ON \"post\"" +}); From f894d445bd6540976a8f11f5786680da7eff2cc5 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Tue, 21 May 2013 20:43:33 +0200 Subject: [PATCH 106/507] allow multiple calls of on for index creation --- lib/dialect/postgres.js | 2 +- lib/node/createIndex.js | 5 +++-- test/dialects/indexes-tests.js | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index e5df7af6..a7886e8f 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -415,7 +415,7 @@ Postgres.prototype.visitIndexes = function(node) { }; Postgres.prototype.visitCreateIndex = function(node) { - if (!node.options.columns) { + if (!node.options.columns || (node.options.columns.length === 0)) { throw new Error('No columns defined!'); } diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index f78e9cc2..b4ca484d 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -12,7 +12,7 @@ module.exports = Node.define({ this.names = []; this.columns = []; this.valueSets = []; - this.options = { indexName: indexName }; + this.options = { indexName: indexName, columns: [] }; }, unique: function() { @@ -36,7 +36,8 @@ module.exports = Node.define({ }, on: function() { - this.options.columns = Array.prototype.slice.call(arguments); + var args = Array.prototype.slice.call(arguments); + this.options.columns = this.options.columns.concat(args); return this; }, diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index f4593907..e0f94f2f 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -38,6 +38,13 @@ Harness.test({ sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")" }); +Harness.test({ + query: post.indexes().create().on(post.userId).on(post.id), + pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")", + mysql: "CREATE INDEX `post_id_userId` ON `post` (`post`.`userId`,`post`.`id`)", + sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")" +}); + Harness.test({ query: post.indexes().create(), pg: { text: 'No columns defined!', throws: true }, From eb8afaf88cae719a4d0d3ada7c63ae11931c46f9 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Tue, 21 May 2013 21:31:42 +0200 Subject: [PATCH 107/507] fixed syntax of index creation --- lib/dialect/postgres.js | 9 +++++---- test/dialects/indexes-tests.js | 30 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a7886e8f..b34e5f6b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -420,14 +420,13 @@ Postgres.prototype.visitCreateIndex = function(node) { } var tableName = this.visit(node.table.toNode()); - var indexNode = Table.define({ name: node.indexName(), columns: [] }).toNode(); var result = [ 'CREATE' ]; if (node.options.type) { result.push(node.options.type.toUpperCase()); } - result = result.concat([ 'INDEX', this.visit(indexNode) ]); + result = result.concat([ 'INDEX', this.quote(node.indexName()) ]); if (node.options.algorithm) { result.push("USING " + node.options.algorithm.toUpperCase()); @@ -437,7 +436,7 @@ Postgres.prototype.visitCreateIndex = function(node) { "ON", tableName, "(" + node.options.columns.reduce(function(result, col) { - return result.concat(this.visit(col.toNode())); + return result.concat(this.quote(col.name)); }.bind(this), []) + ")" ]); @@ -451,9 +450,11 @@ Postgres.prototype.visitCreateIndex = function(node) { Postgres.prototype.visitDropIndex = function(node) { var result = [ 'DROP INDEX' ]; - result.push(this.visit(Table.define({ name: node.options.indexName, columns: [] }).toNode())); + + result.push(this.quote(node.options.indexName)); result.push("ON"); result.push(this.visit(node.table.toNode())); + return result; }; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index e0f94f2f..838b2cf5 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -12,37 +12,37 @@ Harness.test({ Harness.test({ query: post.indexes().create('index_name').unique().using('btree').on(post.id, post.userId).withParser('foo'), - pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo", - mysql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`post`.`id`,`post`.`userId`) WITH PARSER foo", - sqlite: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"post\".\"id\",\"post\".\"userId\") WITH PARSER foo" + pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"id\",\"userId\") WITH PARSER foo", + mysql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo", + sqlite: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"id\",\"userId\") WITH PARSER foo" }); Harness.test({ query: post.indexes().create().fulltext().on(post.id), - pg: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"post\".\"id\")", - mysql: "CREATE FULLTEXT INDEX `post_id` ON `post` (`post`.`id`)", - sqlite: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"post\".\"id\")" + pg: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"id\")", + mysql: "CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)", + sqlite: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"id\")" }); Harness.test({ query: post.indexes().create().spatial().on(post.id), - pg: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"post\".\"id\")", - mysql: "CREATE SPATIAL INDEX `post_id` ON `post` (`post`.`id`)", - sqlite: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"post\".\"id\")" + pg: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"id\")", + mysql: "CREATE SPATIAL INDEX `post_id` ON `post` (`id`)", + sqlite: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"id\")" }); Harness.test({ query: post.indexes().create().on(post.userId, post.id), - pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")", - mysql: "CREATE INDEX `post_id_userId` ON `post` (`post`.`userId`,`post`.`id`)", - sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")" + pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")", + mysql: "CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)", + sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")" }); Harness.test({ query: post.indexes().create().on(post.userId).on(post.id), - pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")", - mysql: "CREATE INDEX `post_id_userId` ON `post` (`post`.`userId`,`post`.`id`)", - sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"post\".\"userId\",\"post\".\"id\")" + pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")", + mysql: "CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)", + sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")" }); Harness.test({ From f71207edb98c165c34cbe26a5c478a1bc2cb088c Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Tue, 21 May 2013 22:23:33 +0200 Subject: [PATCH 108/507] support ifExists and ifNotExists for index#create / index#drop --- lib/dialect/postgres.js | 12 +++++++++++- lib/node/createIndex.js | 5 +++++ lib/node/dropIndex.js | 5 +++++ test/dialects/indexes-tests.js | 14 ++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index b34e5f6b..bbe52686 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -426,7 +426,13 @@ Postgres.prototype.visitCreateIndex = function(node) { result.push(node.options.type.toUpperCase()); } - result = result.concat([ 'INDEX', this.quote(node.indexName()) ]); + result.push('INDEX'); + + if (node.options.ifNotExists) { + result.push('IF NOT EXISTS'); + } + + result.push(this.quote(node.indexName())); if (node.options.algorithm) { result.push("USING " + node.options.algorithm.toUpperCase()); @@ -451,6 +457,10 @@ Postgres.prototype.visitCreateIndex = function(node) { Postgres.prototype.visitDropIndex = function(node) { var result = [ 'DROP INDEX' ]; + if (node.options.ifExists) { + result.push('IF EXISTS'); + } + result.push(this.quote(node.options.indexName)); result.push("ON"); result.push(this.visit(node.table.toNode())); diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index b4ca484d..479e7559 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -60,5 +60,10 @@ module.exports = Node.define({ } return result; + }, + + ifNotExists: function() { + this.options.ifNotExists = true; + return this; } }); diff --git a/lib/node/dropIndex.js b/lib/node/dropIndex.js index 3b09f517..3a59c385 100644 --- a/lib/node/dropIndex.js +++ b/lib/node/dropIndex.js @@ -40,5 +40,10 @@ module.exports = Node.define({ } return result; + }, + + ifExists: function() { + this.options.ifExists = true; + return this; } }); diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 838b2cf5..b17b0cc0 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -31,6 +31,13 @@ Harness.test({ sqlite: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"id\")" }); +Harness.test({ + query: post.indexes().create().ifNotExists().on(post.id), + pg: "CREATE INDEX IF NOT EXISTS \"post_id\" ON \"post\" (\"id\")", + mysql: "CREATE INDEX IF NOT EXISTS `post_id` ON `post` (`id`)", + sqlite: "CREATE INDEX IF NOT EXISTS \"post_id\" ON \"post\" (\"id\")" +}); + Harness.test({ query: post.indexes().create().on(post.userId, post.id), pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")", @@ -59,6 +66,13 @@ Harness.test({ sqlite: "DROP INDEX \"index_name\" ON \"post\"" }); +Harness.test({ + query: post.indexes().drop('index_name').ifExists(), + pg: "DROP INDEX IF EXISTS \"index_name\" ON \"post\"", + mysql: "DROP INDEX IF EXISTS `index_name` ON `post`", + sqlite: "DROP INDEX IF EXISTS \"index_name\" ON \"post\"" +}); + Harness.test({ query: post.indexes().drop(post.userId, post.id), pg: "DROP INDEX \"post_id_userId\" ON \"post\"", From 8646cd907146cc658b32a0b327072c015bbb3cc7 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Tue, 21 May 2013 22:39:54 +0200 Subject: [PATCH 109/507] Revert "support ifExists and ifNotExists for index#create / index#drop" This reverts commit f71207edb98c165c34cbe26a5c478a1bc2cb088c. --- lib/dialect/postgres.js | 12 +----------- lib/node/createIndex.js | 5 ----- lib/node/dropIndex.js | 5 ----- test/dialects/indexes-tests.js | 14 -------------- 4 files changed, 1 insertion(+), 35 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index bbe52686..b34e5f6b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -426,13 +426,7 @@ Postgres.prototype.visitCreateIndex = function(node) { result.push(node.options.type.toUpperCase()); } - result.push('INDEX'); - - if (node.options.ifNotExists) { - result.push('IF NOT EXISTS'); - } - - result.push(this.quote(node.indexName())); + result = result.concat([ 'INDEX', this.quote(node.indexName()) ]); if (node.options.algorithm) { result.push("USING " + node.options.algorithm.toUpperCase()); @@ -457,10 +451,6 @@ Postgres.prototype.visitCreateIndex = function(node) { Postgres.prototype.visitDropIndex = function(node) { var result = [ 'DROP INDEX' ]; - if (node.options.ifExists) { - result.push('IF EXISTS'); - } - result.push(this.quote(node.options.indexName)); result.push("ON"); result.push(this.visit(node.table.toNode())); diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index 479e7559..b4ca484d 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -60,10 +60,5 @@ module.exports = Node.define({ } return result; - }, - - ifNotExists: function() { - this.options.ifNotExists = true; - return this; } }); diff --git a/lib/node/dropIndex.js b/lib/node/dropIndex.js index 3a59c385..3b09f517 100644 --- a/lib/node/dropIndex.js +++ b/lib/node/dropIndex.js @@ -40,10 +40,5 @@ module.exports = Node.define({ } return result; - }, - - ifExists: function() { - this.options.ifExists = true; - return this; } }); diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index b17b0cc0..838b2cf5 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -31,13 +31,6 @@ Harness.test({ sqlite: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"id\")" }); -Harness.test({ - query: post.indexes().create().ifNotExists().on(post.id), - pg: "CREATE INDEX IF NOT EXISTS \"post_id\" ON \"post\" (\"id\")", - mysql: "CREATE INDEX IF NOT EXISTS `post_id` ON `post` (`id`)", - sqlite: "CREATE INDEX IF NOT EXISTS \"post_id\" ON \"post\" (\"id\")" -}); - Harness.test({ query: post.indexes().create().on(post.userId, post.id), pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")", @@ -66,13 +59,6 @@ Harness.test({ sqlite: "DROP INDEX \"index_name\" ON \"post\"" }); -Harness.test({ - query: post.indexes().drop('index_name').ifExists(), - pg: "DROP INDEX IF EXISTS \"index_name\" ON \"post\"", - mysql: "DROP INDEX IF EXISTS `index_name` ON `post`", - sqlite: "DROP INDEX IF EXISTS \"index_name\" ON \"post\"" -}); - Harness.test({ query: post.indexes().drop(post.userId, post.id), pg: "DROP INDEX \"post_id_userId\" ON \"post\"", From c0d813ee723fcb92f77b04c2446e6319e17d24f1 Mon Sep 17 00:00:00 2001 From: bmc Date: Thu, 23 May 2013 10:13:44 -0500 Subject: [PATCH 110/507] Update readme example to be valid --- README.md | 8 ++++---- test/readme-examples.js | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 test/readme-examples.js diff --git a/README.md b/README.md index a26d2339..4a28e914 100644 --- a/README.md +++ b/README.md @@ -61,17 +61,17 @@ var friendship = sql.define({ var friends = user.as('friends'); var userToFriends = user - .leftJoin(friendship.on(user.id.equals(friendship.userId))) - .leftJoin(friends.on(friendship.friendId.equals(friends.id))); + .leftJoin(friendship).on(user.id.equals(friendship.userId)) + .leftJoin(friends).on(friendship.friendId.equals(friends.id)); //and now...compose... -var friendsWhoHaveLoggedInQuery = userToFriends.where(friends.lastLogin.notNull()); +var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.notNull()); //SELECT * FROM "user" //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") //WHERE "friends"."lastLogin" IS NOT NULL -var friendsWhoUseGmailQuery = userToFriends.where(friends.email.like('%@gmail.com')); +var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); //SELECT * FROM "user" //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") diff --git a/test/readme-examples.js b/test/readme-examples.js new file mode 100644 index 00000000..9131377e --- /dev/null +++ b/test/readme-examples.js @@ -0,0 +1,32 @@ +var sql = require('../lib'); +var user = sql.define({ + name: 'user', + columns: ['id', 'lastLogin', 'email'] +}); + +//this also makes parts of your queries composable, which is handy + +var friendship = sql.define({ + name: 'friendship', + columns: ['userId', 'friendId'] +}); + +var friends = user.as('friends'); +var userToFriends = user + .leftJoin(friendship).on(user.id.equals(friendship.userId)) + .leftJoin(friends).on(friendship.friendId.equals(friends.id)); + +//and now...compose... +var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); +console.log(friendsWhoHaveLoggedInQuery.toQuery().text); +//SELECT * FROM "user" +//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +//LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") +//WHERE "friends"."lastLogin" IS NOT NULL + +var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); +console.log(friendsWhoUseGmailQuery.toQuery().text); +//SELECT * FROM "user" +//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +//LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") +//WHERE "friends"."email" LIKE %1 From c29ca3a0c6e99e68a51b50ddeabf830d6fe13f4c Mon Sep 17 00:00:00 2001 From: bmc Date: Thu, 23 May 2013 10:16:23 -0500 Subject: [PATCH 111/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a0bec9f..2818cf3a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.16.0", + "version": "0.17.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From c1a1532b65d27cdca8bab8baf5212fe6ad8e867d Mon Sep 17 00:00:00 2001 From: tmont Date: Thu, 23 May 2013 14:55:14 -0700 Subject: [PATCH 112/507] ignore .idea directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c2658d7d..9cf6fffa 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +.idea From 8fb83185c226315a5035bf78d96eb62f8a5493a6 Mon Sep 17 00:00:00 2001 From: tmont Date: Thu, 23 May 2013 15:10:33 -0700 Subject: [PATCH 113/507] added special 'property' field to columns When defining a column, you can specify a "property" field that will allow a more programmer-friendly name to be used when selecting fields. e.g. var user = sql.define({ name: 'user', columns: [{ state: 'state_or_province', property: 'state' }] }); user.select(user.state); --- README.md | 17 +++++++++++++++++ lib/table.js | 3 ++- test/table-tests.js | 21 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a28e914..fcb159a1 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,24 @@ var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like( //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") //WHERE "friends"."email" LIKE %1 +``` + +## Using different property names for columns +```javascript +var user = sql.define({ + name: 'user', + columns: [{ + name: 'id' + }, { + name: 'state_or_province', + property: 'state' + } + ] +}); +//now, instead of user.state_or_province, you can just use user.state +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. diff --git a/lib/table.js b/lib/table.js index 0d67b55a..667ab377 100644 --- a/lib/table.js +++ b/lib/table.js @@ -60,7 +60,8 @@ Table.prototype.addColumn = function(col) { 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); - this[col.name] = this[col.name] || col; + var property = col.property || col.name; + this[property] = this[property] || col; return this; }; diff --git a/test/table-tests.js b/test/table-tests.js index 6b989177..c16efb5e 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -56,6 +56,27 @@ suite('table', function() { }); }); +test('table with user-defined column property names', function () { + var table = Table.define({ + name: 'blah', + columns: [{ + name: 'id', + property: 'theId' + }, { + name: 'email', + property: 'uniqueEmail' + }] + }); + var cols = table.columns; + assert.equal(cols.length, 2); + assert.equal(cols[0].name, 'id'); + assert(cols[0] === table.theId, 'Expected table.theId to be the first column'); + assert(table.id === undefined, 'Expected table.id to not exist'); + assert.equal(cols[1].name, 'email'); + assert(cols[1] === table.uniqueEmail, 'Expected table.uniqueEmail to be the second column'); + assert(table.email === undefined, 'Expected table.email to not exist'); +}); + test('table with fancier column definitions', function() { var table = Table.define({ name: 'blah', From 402b759f58afcb79c83567dbc512198eafd78a88 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 26 May 2013 11:13:28 +0200 Subject: [PATCH 114/507] added support for min and max queries --- lib/column.js | 18 ++++++++++-- lib/dialect/postgres.js | 12 +++++--- lib/node/column.js | 2 +- test/dialects/aggregate-tests.js | 48 ++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 8 deletions(-) diff --git a/lib/column.js b/lib/column.js index 88c297f8..0fce18ac 100644 --- a/lib/column.js +++ b/lib/column.js @@ -84,13 +84,25 @@ Column.prototype.arrayAgg = function(alias) { return new ColumnNode(context); }; -Column.prototype.count = function(alias) { +Column.prototype.aggregate = function(alias, aggregator) { var context = contextify(this); - context.aggCount = true; - context.alias = alias || context.name + '_count'; + context.aggregator = aggregator.toUpperCase(); + context.alias = alias || context.name + '_' + context.aggregator.toLowerCase(); return new ColumnNode(context); }; +Column.prototype.count = function(alias) { + return this.aggregate(alias, 'count'); +}; + +Column.prototype.min = function(alias) { + return this.aggregate(alias, 'min'); +}; + +Column.prototype.max = function(alias) { + return this.aggregate(alias, 'max'); +}; + Column.prototype.distinct = function() { var context = contextify(this); context.distinct = true; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index b34e5f6b..b847d583 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -304,12 +304,16 @@ Postgres.prototype.visitColumn = function(columnNode) { if (columnNode.asArray) { closeParen++; txt += this._arrayAggFunctionName+'('; - } if (columnNode.aggCount) { + } + + if (!!columnNode.aggregator) { closeParen++; - txt += 'COUNT('; - } if (columnNode.distinct === true) { + txt += columnNode.aggregator + '('; + } + + if (columnNode.distinct === true) { closeParen++; - txt += 'DISTINCT(' + txt += 'DISTINCT('; } } if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { diff --git a/lib/node/column.js b/lib/node/column.js index a7d19b34..9216d1bc 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -10,7 +10,7 @@ module.exports = Node.define({ this.alias = config.alias; this.star = config.star; this.asArray = config.asArray; - this.aggCount = config.aggCount; + this.aggregator = config.aggregator; this.table = config.table; this.value = config.getValue(); this.dataType = config.dataType; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index fb89b258..f6c4c00a 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -50,3 +50,51 @@ Harness.test({ mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', params: [] }); + +Harness.test({ + query : post.select(post.id.min()), + pg : 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + sqlite: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + mysql : 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', + params: [] +}); + +Harness.test({ + query : post.select(post.id.min().as('min_id')), + pg : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + sqlite: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + mysql : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + params: [] +}); + +Harness.test({ + query : post.select(post.id.min('min_id')), + pg : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + sqlite: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + mysql : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + params: [] +}); + +Harness.test({ + query : post.select(post.id.max()), + pg : 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + sqlite: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + mysql : 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', + params: [] +}); + +Harness.test({ + query : post.select(post.id.max().as('max_id')), + pg : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + sqlite: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + mysql : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + params: [] +}); + +Harness.test({ + query : post.select(post.id.max('max_id')), + pg : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + sqlite: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + mysql : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + params: [] +}); From 6fb2e94b1406f89292e07ac40a1110078218e9d8 Mon Sep 17 00:00:00 2001 From: bmc Date: Sun, 26 May 2013 08:59:55 -0500 Subject: [PATCH 115/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2818cf3a..96ad4436 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.17.0", + "version": "0.18.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From c60b296ab17f3fd8146c681f35f196768db0ede1 Mon Sep 17 00:00:00 2001 From: Brian C Date: Sun, 26 May 2013 09:04:12 -0500 Subject: [PATCH 116/507] Update README closes #70 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fcb159a1..cda39a47 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ var sql = require('sql'); //first we define our tables var user = sql.define({ name: 'user', - columns: ['id', 'email', 'lastLogin'] + columns: ['id', 'name', 'email', 'lastLogin'] }); var post = sql.define({ @@ -47,10 +47,10 @@ console.log(query.values); //['boom', 1, 'bang', 2] //how about a join? -var query = user.select(user.name, post.content) +var query = user.select(user.name, post.body) .from(user.join(post).on(user.id.equals(post.userId))).toQuery(); -console.log(query.text); //'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' +console.log(query.text); //'SELECT "user"."name", "post"."body" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' //this also makes parts of your queries composable, which is handy @@ -65,7 +65,7 @@ var userToFriends = user .leftJoin(friends).on(friendship.friendId.equals(friends.id)); //and now...compose... -var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.notNull()); +var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); //SELECT * FROM "user" //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") From b81992d66de907f6e68f6f3ede703bce492b42d9 Mon Sep 17 00:00:00 2001 From: Brian C Date: Sun, 26 May 2013 09:05:44 -0500 Subject: [PATCH 117/507] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cda39a47..a6d38713 100644 --- a/README.md +++ b/README.md @@ -76,10 +76,9 @@ var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like( //LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") //WHERE "friends"."email" LIKE %1 -``` -## Using different property names for columns -```javascript +//Using different property names for columns +//helpful if your column name is long or not camelCase var user = sql.define({ name: 'user', columns: [{ From 9b1f54233b5ecf4dd4b4fe6fe79801598a0dd5b8 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 26 May 2013 17:20:40 +0200 Subject: [PATCH 118/507] allow silent add column --- lib/table.js | 14 +++++++++++--- package.json | 3 ++- test/table-tests.js | 8 ++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/table.js b/lib/table.js index 667ab377..fd5d3e78 100644 --- a/lib/table.js +++ b/lib/table.js @@ -1,6 +1,7 @@ 'use strict'; var util = require('util'); +var lodash = require('lodash'); var Query = require(__dirname + '/node/query'); var Column = require(__dirname + '/column'); @@ -51,11 +52,18 @@ Table.prototype.createColumn = function(col) { return col; }; -Table.prototype.addColumn = function(col) { - col = this.createColumn(col); +Table.prototype.addColumn = function(col, options) { + col = this.createColumn(col); + options = lodash.extend({ + noisy: true + }, options || {}); if(this.hasColumn(col)) { - throw new Error('Table ' + this._name + ' already has column or property by the name of ' + col.name); + if (options.noisy) { + throw new Error('Table ' + this._name + ' already has column or property by the name of ' + col.name); + } else { + return this; + } } else if(!!this[col.name] && (process.env.NODE_ENV !== 'test')) { 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 + '\');"!'); } diff --git a/package.json b/package.json index 96ad4436..0f6ce6e9 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "node": "*" }, "dependencies": { - "sliced": "0.0.5" + "sliced": "0.0.5", + "lodash": "~1.2.1" }, "devDependencies": { "mocha": "*" diff --git a/test/table-tests.js b/test/table-tests.js index c16efb5e..6fc32217 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -116,7 +116,7 @@ test('table with object structured column definitions', function() { type: 'serial', notNull: true, primaryKey: true - }, + }, email: { type: 'text', notNull: true, @@ -139,6 +139,7 @@ test('table with object structured column definitions', function() { assert.equal(email.unique, true); assert.equal(email.anythingYouWant, 'awesome'); }); + test('table with dynamic column definition', function() { var table = Table.define({ name: 'foo', columns: [] }); assert.equal(table.columns.length, 0); @@ -152,10 +153,13 @@ test('table with dynamic column definition', function() { table.addColumn('foo'); }); + assert.doesNotThrow(function() { + table.addColumn('foo', { noisy: false }); + }); + assert.equal(table.columns.length, 1); }); - test('hasColumn', function() { var table = Table.define({ name: 'foo', columns: [] }); From 17529c4ac698bad97cf49413e4f0cb3d47701328 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 26 May 2013 17:22:55 +0200 Subject: [PATCH 119/507] documentation --- README.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a6d38713..7b61251a 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ console.log(query.values); //['boom', 1, 'bang', 2] //how about a join? var query = user.select(user.name, post.body) .from(user.join(post).on(user.id.equals(post.userId))).toQuery(); - + console.log(query.text); //'SELECT "user"."name", "post"."body" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' //this also makes parts of your queries composable, which is handy @@ -63,17 +63,17 @@ var friends = user.as('friends'); var userToFriends = user .leftJoin(friendship).on(user.id.equals(friendship.userId)) .leftJoin(friends).on(friendship.friendId.equals(friends.id)); - + //and now...compose... var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); -//SELECT * FROM "user" -//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +//SELECT * FROM "user" +//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") //WHERE "friends"."lastLogin" IS NOT NULL var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); -//SELECT * FROM "user" -//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +//SELECT * FROM "user" +//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") //LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") //WHERE "friends"."email" LIKE %1 @@ -129,6 +129,16 @@ exports.foo = sql.define({ 'foo_bar_baz' ] }); + +/** + * Adding a column to an existing table: + */ +var model = sql.define({ name: 'foo', columns: [] }); +model.addColumn('id'); + +// If you try to add another column "id", node-sql will throw an error. +// You can suppress that error via: +model.addColumn('id', { noisy: false }); ``` Read the module's documentation for more details. From 155eb2bafbf137d9b1d04135e78f620a7368914e Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 26 May 2013 20:50:42 +0200 Subject: [PATCH 120/507] allow definition of mysql engine --- lib/dialect/mysql.js | 11 +++++++++++ test/dialects/create-table-tests.js | 9 ++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 6e9fdf3f..5c6d83c4 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -23,6 +23,17 @@ Mysql.prototype.visitParameter = function(parameter) { return "?"; }; +Mysql.prototype.visitCreate = function(create) { + var result = Mysql.super_.prototype.visitCreate.call(this, create); + var engine = this._queryNode.table._initialConfig.engine; + + if (!!engine) { + result.push('ENGINE=' + engine); + } + + return result; +}; + /*jshint unused: false */ Mysql.prototype.visitDefault = function(parameter) { return "DEFAULT"; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 0d17b05c..5e372377 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -28,4 +28,11 @@ Harness.test({ sqlite: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', mysql : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', params: [] -}); \ No newline at end of file +}); + +Harness.test({ + query : Table.define({ name: 'user', columns: [{ name: 'id', dataType: 'varchar(100)' }], engine: 'InnoDB' }).create(), + pg : 'CREATE TABLE "user" ("id" varchar(100))', + sqlite: 'CREATE TABLE "user" ("id" varchar(100))', + mysql : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' +}); From 79a3cc25041a6f77e7a8a3ec7c7b01d8975d62c7 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 26 May 2013 20:56:15 +0200 Subject: [PATCH 121/507] charset support --- lib/dialect/mysql.js | 9 +++++++-- test/dialects/create-table-tests.js | 7 +++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 5c6d83c4..c02ab1ad 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -24,13 +24,18 @@ Mysql.prototype.visitParameter = function(parameter) { }; Mysql.prototype.visitCreate = function(create) { - var result = Mysql.super_.prototype.visitCreate.call(this, create); - var engine = this._queryNode.table._initialConfig.engine; + 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; }; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 5e372377..4355bc92 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -36,3 +36,10 @@ Harness.test({ sqlite: 'CREATE TABLE "user" ("id" varchar(100))', mysql : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' }); + +Harness.test({ + query : Table.define({ name: 'user', columns: [{ name: 'id', dataType: 'varchar(100)' }], charset: 'latin1' }).create(), + pg : 'CREATE TABLE "user" ("id" varchar(100))', + sqlite: 'CREATE TABLE "user" ("id" varchar(100))', + mysql : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' +}); From 2da1b22cc8a09d0e63f1c174b6058ff709307026 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Sun, 26 May 2013 20:57:55 +0200 Subject: [PATCH 122/507] another test for charset and engine --- test/dialects/create-table-tests.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index 4355bc92..73eb1ebd 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -43,3 +43,10 @@ Harness.test({ sqlite: 'CREATE TABLE "user" ("id" varchar(100))', mysql : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' }); + +Harness.test({ + query : Table.define({ name: 'user', columns: [{ name: 'id', dataType: 'varchar(100)' }], engine: 'MyISAM', charset: 'latin1' }).create(), + pg : 'CREATE TABLE "user" ("id" varchar(100))', + sqlite: 'CREATE TABLE "user" ("id" varchar(100))', + mysql : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' +}); From f5467bedf8c0bc75d4e9310e773278e8310c7986 Mon Sep 17 00:00:00 2001 From: thadclay Date: Mon, 3 Jun 2013 12:22:07 -0400 Subject: [PATCH 123/507] Add support for SUM and AVG aggregate functions --- lib/column.js | 8 ++++++ test/dialects/aggregate-tests.js | 43 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/lib/column.js b/lib/column.js index 0fce18ac..e3007f0b 100644 --- a/lib/column.js +++ b/lib/column.js @@ -103,6 +103,14 @@ Column.prototype.max = function(alias) { return this.aggregate(alias, 'max'); }; +Column.prototype.sum = function(alias) { + return this.aggregate(alias, 'sum'); +}; + +Column.prototype.avg = function(alias) { + return this.aggregate(alias, 'avg'); +}; + Column.prototype.distinct = function() { var context = contextify(this); context.distinct = true; diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index f6c4c00a..c0a46506 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -98,3 +98,46 @@ Harness.test({ mysql : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', params: [] }); + +Harness.test({ + query : post.select(post.id.sum()), + pg : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + sqllite : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + mysql : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', +}); + +Harness.test({ + query : post.select(post.id.sum().as('sum_id')), + pg : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + sqllite : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + mysql : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', +}); + +Harness.test({ + query : post.select(post.id.sum('sum_id')), + pg : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + sqllite : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + mysql : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', +}); + +Harness.test({ + query : post.select(post.id.avg()), + pg : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + sqllite : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + mysql : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', +}); + +Harness.test({ + query : post.select(post.id.avg().as('avg_id')), + pg : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + sqllite : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + mysql : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', +}); + +Harness.test({ + query : post.select(post.id.avg('avg_id')), + pg : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + sqllite : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + mysql : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', +}); + From 6e5f6778e9fd4a3e7cb3b4866a02945d095767ad Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 3 Jun 2013 13:28:00 -0500 Subject: [PATCH 124/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f6ce6e9..f1f4d791 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.18.0", + "version": "0.19.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From fcd21053b8eefcaa89a984003d10d60e6245480e Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 4 Jun 2013 11:40:08 -0500 Subject: [PATCH 125/507] Fix toQuery() on subquery column --- lib/dialect/postgres.js | 2 +- test/column-tests.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index b847d583..cd257073 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -300,7 +300,7 @@ Postgres.prototype.visitColumn = function(columnNode) { var inSelectClause = !this._selectOrDeleteEndIndex; var txt = ""; var closeParen = 0; - if(inSelectClause) { + if(inSelectClause && !table.alias) { if (columnNode.asArray) { closeParen++; txt += this._arrayAggFunctionName+'('; diff --git a/test/column-tests.js b/test/column-tests.js index 6b7970eb..ae10b7e0 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -23,5 +23,12 @@ describe('column', function() { it('respects count and distinct', function() { assert.equal(table.id.count().distinct().as("userIdCount").toQuery().text, 'COUNT(DISTINCT("user"."id")) AS "userIdCount"'); }); + + describe('in subquery with min', function() { + var subquery = table.subQuery('subTable').select(table.id.min().as('subId')); + var col = subquery.subId.toQuery().text + console.log(col) + assert.equal(col, '"subTable"."subId"'); + }); }); }); From c7559da6083ae4718c51910021377d3cbe0e99cc Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 4 Jun 2013 11:40:28 -0500 Subject: [PATCH 126/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f1f4d791..05a68bf3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.19.0", + "version": "0.20.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 0dea29827b400fdeafda095e180b2b2627e3c84f Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 14:55:27 -0700 Subject: [PATCH 127/507] address all jshint issues --- lib/joiner.js | 6 +++--- lib/node/unary.js | 2 +- test/binary-clause-tests.js | 2 ++ test/clause-definition.js | 2 ++ test/column-tests.js | 5 ++--- test/dialects/alter-table-tests.js | 4 ++-- test/dialects/support.js | 1 + test/index-tests.js | 1 + test/select-tests.js | 1 + test/table-tests.js | 3 ++- 10 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/joiner.js b/lib/joiner.js index bd7a4e3c..69bfd552 100644 --- a/lib/joiner.js +++ b/lib/joiner.js @@ -3,7 +3,7 @@ var getPrimaryKeyColumn = function(table) { var col = table.columns[i]; if(col.primaryKey) { return col; - } + } } }; @@ -16,7 +16,7 @@ var findReference = function(left, right) { if(col.references == leftName || col.references.table == leftName) { var leftCol = left[col.references.column] || getPrimaryKeyColumn(left); return { - left: leftCol, + left: leftCol, right: col }; } @@ -36,4 +36,4 @@ module.exports = { } return left.join(right).on(ref.left.equals(ref.right)); } -} +}; diff --git a/lib/node/unary.js b/lib/node/unary.js index 11d6b80a..5526c3e6 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -5,7 +5,7 @@ module.exports = Node.define({ type: 'UNARY', constructor: function(config) { Node.call(this); - this.left = config.left, + this.left = config.left; this.operator = config.operator; } }); diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 6d132bb8..1214e405 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -1,4 +1,6 @@ +/* global test */ 'use strict'; + var assert = require('assert'); var Table = require(__dirname + '/../lib/table'); diff --git a/test/clause-definition.js b/test/clause-definition.js index 56afbade..6f918dad 100644 --- a/test/clause-definition.js +++ b/test/clause-definition.js @@ -1,4 +1,6 @@ +/* global test */ 'use strict'; + var assert = require('assert'); var Node = require(__dirname + '/../lib/node/'); diff --git a/test/column-tests.js b/test/column-tests.js index ae10b7e0..0db0bca3 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -6,7 +6,7 @@ describe('column', function() { name: 'user', columns: ['id', 'created'] }); - + it('can be accessed by property and array', function() { assert.equal(table.created, table.columns[1], 'should be able to access created both by array and property'); }); @@ -26,8 +26,7 @@ describe('column', function() { describe('in subquery with min', function() { var subquery = table.subQuery('subTable').select(table.id.min().as('subId')); - var col = subquery.subId.toQuery().text - console.log(col) + var col = subquery.subId.toQuery().text; assert.equal(col, '"subTable"."subId"'); }); }); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 612a89eb..9cb7f4a8 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -128,7 +128,7 @@ var UserWithSignature = Table.define({ name: 'Signature', dataType: "VARCHAR(255) NOT NULL DEFAULT 'Signature'" }] -}) +}); Harness.test({ query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), @@ -138,4 +138,4 @@ Harness.test({ text : 'Sqlite cannot rename columns', throws: true } -}) +}); diff --git a/test/dialects/support.js b/test/dialects/support.js index 04786055..ce05b7fd 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -1,3 +1,4 @@ +/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/index-tests.js b/test/index-tests.js index 0ba1d463..9f99873f 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -1,3 +1,4 @@ +/* global suite, test */ 'use strict'; var assert = require('assert'); diff --git a/test/select-tests.js b/test/select-tests.js index b771a831..836098eb 100644 --- a/test/select-tests.js +++ b/test/select-tests.js @@ -1,3 +1,4 @@ +/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/table-tests.js b/test/table-tests.js index 6fc32217..53401fb2 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -1,3 +1,4 @@ +/* global suite, test */ 'use strict'; var assert = require('assert'); @@ -29,7 +30,7 @@ suite('table', function() { table.addColumn(col); assert.equal(table.columns.length, 1); assert.equal(table.boom, col); - }) + }); test('creates query node', function() { var sel = table.select(table.boom); From e6ea2016fe640081fb16f23c46c5b3c260bffdd2 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 15:03:58 -0700 Subject: [PATCH 128/507] fix spacing in comments --- lib/column.js | 6 +++--- lib/dialect/postgres.js | 24 ++++++++++++------------ lib/joiner.js | 8 ++++---- lib/node/index.js | 4 ++-- lib/node/query.js | 6 +++--- lib/node/where.js | 2 +- lib/table.js | 15 ++++++++------- test/dialects/clause-ordering-tests.js | 8 ++++---- test/dialects/insert-tests.js | 8 +++----- test/dialects/namespace-tests.js | 1 - test/dialects/shortcut-tests.js | 4 ++-- test/dialects/table-tests.js | 1 - test/readme-examples.js | 21 ++++++++++----------- 13 files changed, 52 insertions(+), 56 deletions(-) diff --git a/lib/column.js b/lib/column.js index e3007f0b..e5f6e1c8 100644 --- a/lib/column.js +++ b/lib/column.js @@ -67,7 +67,7 @@ Column.prototype.getValue = function() { }; Column.prototype.toNode = function() { - //creates a query node from this column + // creates a query node from this column return new ColumnNode(contextify(this)); }; @@ -103,11 +103,11 @@ Column.prototype.max = function(alias) { return this.aggregate(alias, 'max'); }; -Column.prototype.sum = function(alias) { +Column.prototype.sum = function(alias) { return this.aggregate(alias, 'sum'); }; -Column.prototype.avg = function(alias) { +Column.prototype.avg = function(alias) { return this.aggregate(alias, 'avg'); }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index cd257073..21c850f6 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -14,7 +14,7 @@ Postgres.prototype._myClass = Postgres; Postgres.prototype._arrayAggFunctionName = 'array_agg'; Postgres.prototype.getQuery = function(queryNode) { - //passed in a table, not a query + // passed in a table, not a query if(queryNode instanceof Table) { queryNode = queryNode.select(queryNode.star()); } @@ -78,7 +78,7 @@ Postgres.prototype.visitSelect = function(select) { Postgres.prototype.visitInsert = function(insert) { var self = this; - //don't use table.column for inserts + // don't use table.column for inserts this._visitedInsert = true; var paramNodes = insert.getParameters() @@ -104,9 +104,9 @@ Postgres.prototype.visitInsert = function(insert) { }; Postgres.prototype.visitUpdate = function(update) { - //don't auto-generate from clause + // don't auto-generate from clause var params = []; - /*jshint boss: true */ + /* jshint boss: true */ for(var i = 0, node; node = update.nodes[i]; i++) { this._visitingUpdateTargetColumn = true; var target_col = this.visit(node); @@ -129,7 +129,7 @@ Postgres.prototype.visitDelete = function() { Postgres.prototype.visitCreate = function(create) { this._visitingCreate = true; - //don't auto-generate from clause + // don't auto-generate from clause var table = this._queryNode.table; var col_nodes = table.columns.map(function(col) { return col.toNode(); }); @@ -142,7 +142,7 @@ Postgres.prototype.visitCreate = function(create) { }; Postgres.prototype.visitDrop = function(drop) { - //don't auto-generate from clause + // don't auto-generate from clause var result = ['DROP TABLE']; result = result.concat(drop.nodes.map(this.visit.bind(this))); result.push(this.visit(this._queryNode.table.toNode())); @@ -151,7 +151,7 @@ Postgres.prototype.visitDrop = function(drop) { Postgres.prototype.visitAlter = function(alter) { this._visitingAlter = true; - //don't auto-generate from clause + // don't auto-generate from clause var table = this._queryNode.table; // TODO: col_nodes is unused? var col_nodes = table.columns.map(function(col) { return col.toNode(); }); @@ -221,8 +221,8 @@ Postgres.prototype.visitUnary = function(unary) { 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 + // 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; @@ -257,19 +257,19 @@ Postgres.prototype.visitQuery = function(queryNode) { } } if(!actions.length) { - //if no actions are given, guess it's a select + // if no actions are given, guess it's a select actions.push(new Select().add('*')); } if(missingFrom) { targets.push(new From().add(queryNode.table)); } - //lazy-man sorting + // 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' + // implicit 'from' return this.output; }; diff --git a/lib/joiner.js b/lib/joiner.js index bd7a4e3c..b1eacb39 100644 --- a/lib/joiner.js +++ b/lib/joiner.js @@ -8,7 +8,7 @@ var getPrimaryKeyColumn = function(table) { }; var findReference = function(left, right) { - //find reference + // find reference for(var i = 0; i < right.columns.length; i++) { var col = right.columns[i]; if(col.references) { @@ -25,9 +25,9 @@ var findReference = function(left, right) { }; module.exports = { - //auto-join two tables based on column properties - //requires one column to have { references: {table: 'foreignTableName', column: 'foreignColumnName'}} - //or to have { references: 'foreignTableName'} -- in which case the foreign table's primary key is assumed + // auto-join two tables based on column properties + // requires one column to have { references: {table: 'foreignTableName', column: 'foreignColumnName'}} + // or to have { references: 'foreignTableName'} -- in which case the foreign table's primary key is assumed leftJoin: function(left, right) { var leftCol, rightCol; var ref = findReference(left, right); diff --git a/lib/node/index.js b/lib/node/index.js index 69fb287d..10fe5629 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -3,7 +3,7 @@ var util = require('util'); var assert = require('assert'); -/*jshint unused: false */ +/* jshint unused: false */ var Node = function(type) { this.nodes = []; }; @@ -34,7 +34,7 @@ Node.define = function(def) { var c = function() { Node.call(this); }; - //allow custom sub-class constructor + // allow custom sub-class constructor if(def.constructor && def.constructor != {}.constructor) { c = def.constructor; } diff --git a/lib/node/query.js b/lib/node/query.js index 1ba5e2e3..46968180 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -81,14 +81,14 @@ var Query = Node.define({ }, where: function(node) { if(arguments.length > 1) { - //allow multiple where clause arguments + // allow multiple where clause arguments var args = sliced(arguments); for(var i = 0; i < args.length; i++) { this.where(args[i]); } return this; } - //calling #where twice functions like calling #where & then #and + // calling #where twice functions like calling #where & then #and if(this.whereClause) return this.and(node); this.whereClause = new Where(this.table); this.whereClause.add(node); @@ -122,7 +122,7 @@ var Query = Node.define({ var self = this; var args = sliced(arguments); - //object literal + // object literal if(arguments.length == 1 && !o.toNode && !o.forEach) { args = Object.keys(o).map(function(key) { return self.table.get(key).value(o[key]); diff --git a/lib/node/where.js b/lib/node/where.js index 0a8b126b..3b22ae9d 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -35,7 +35,7 @@ module.exports = Node.define({ }, or: function(other) { var right = normalizeNode(this.table, other); - //calling 'or' without an initial 'where' + // calling 'or' without an initial 'where' if(!this.nodes.length) { return this.add(other); } diff --git a/lib/table.js b/lib/table.js index fd5d3e78..5c6a0991 100644 --- a/lib/table.js +++ b/lib/table.js @@ -20,7 +20,7 @@ var Table = function(config) { Table.define = function(config) { var table = new Table(config); - //allow hash of columns as well as array + // allow hash of columns as well as array if(config.columns && !util.isArray(config.columns)) { var cols = []; @@ -110,11 +110,12 @@ Table.prototype.star = function() { Table.prototype.count = function(alias) { var name = this.alias || this._name, col = new Column({table: this, star: true}); - return col.count(alias || name + '_count'); //ColumnNode + // ColumnNode + return col.count(alias || name + '_count'); }; Table.prototype.select = function() { - //create the query and pass it off + // create the query and pass it off var query = new Query(this); if (arguments.length === 0) { query.select.call(query, this.star()); @@ -131,7 +132,7 @@ Table.prototype.from = function() { }; Table.prototype.subQuery = function(alias) { - //create the query and pass it off + // create the query and pass it off var query = new Query(this); query.type = 'SUBQUERY'; query.alias = alias; @@ -186,19 +187,19 @@ Table.prototype.leftJoin = function(other) { return new JoinNode('LEFT', this.toNode(), other.toNode()); }; -//auto-join tables based on column intropsection +// auto-join tables based on column intropsection Table.prototype.joinTo = function(other) { return Joiner.leftJoin(this, other); }; Table.prototype.as = function(alias) { - //TODO could this be cleaner? + // TODO could this be cleaner? var t = Table.define(this._initialConfig); t.alias = alias; return t; }; -//called in shorthand when not calling select +// called in shorthand when not calling select Table.prototype.__defineGetter__("nodes", function() { return this.select(this.star()).nodes; }); diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index 4038f299..c7ca3a79 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -4,7 +4,7 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); -//FROM - SELECT +// FROM - SELECT Harness.test({ query : user.from(user.join(post).on(user.id.equals(post.userId))).select(user.name, post.content), pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', @@ -12,7 +12,7 @@ Harness.test({ mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }); -//WHERE - FROM - SELECT +// WHERE - FROM - SELECT Harness.test({ query : user.where({name: ''}).from(user).select(user.id), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', @@ -21,7 +21,7 @@ Harness.test({ params: [''] }); -//SELECT - FROM - WHERE +// SELECT - FROM - WHERE Harness.test({ query : user .select(user.name, post.content) @@ -33,7 +33,7 @@ Harness.test({ params: [''] }); -//SELECT - FROM - WHERE +// SELECT - FROM - WHERE Harness.test({ query : user.select(user.id).from(user).where({name: ''}), pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index a131b274..d02fa695 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -28,7 +28,7 @@ Harness.test({ params: ['test', 2] }); -//allow bulk insert +// allow bulk insert Harness.test({ query : post.insert([{content: 'whoah'}, {content: 'hey'}]), pg : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', @@ -45,8 +45,7 @@ Harness.test({ params: ['whoah', 1, 'hey', 2] }); - -//consistent order +// consistent order Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {userId: 2, content: 'hey' }]), pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', @@ -55,8 +54,7 @@ Harness.test({ params: ['whoah', 1, 'hey', 2] }); - -//handle missing columns +// handle missing columns Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey'}]), pg : { diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 85a81ee1..077d1eb0 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -36,7 +36,6 @@ Harness.test({ mysql : '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))' }); - // the quote property isn't implemented for columns, so all columns are quoted in generated queries var comment = Table.define({ name: 'comment', diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 98952ed1..188326e6 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -4,7 +4,7 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); -//shortcut: 'select * from
' +// shortcut: 'select * from
' Harness.test({ query : user, pg : 'SELECT "user".* FROM "user"', @@ -28,7 +28,7 @@ Harness.test({ params: [3,1] }); -//shortcut: no 'from' +// shortcut: no 'from' Harness.test({ query : post.select(post.content), pg : 'SELECT "post"."content" FROM "post"', diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 21f40b39..c2ec86a0 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -118,7 +118,6 @@ Harness.test({ params: ['brian'] }); -//Fix #10: prevent column state mutation Harness.test({ query : user.select(user.name).from(user).where(user.name.equals('brian')), pg : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', diff --git a/test/readme-examples.js b/test/readme-examples.js index 9131377e..33fa47e9 100644 --- a/test/readme-examples.js +++ b/test/readme-examples.js @@ -4,8 +4,7 @@ var user = sql.define({ columns: ['id', 'lastLogin', 'email'] }); -//this also makes parts of your queries composable, which is handy - +// this also makes parts of your queries composable, which is handy var friendship = sql.define({ name: 'friendship', columns: ['userId', 'friendId'] @@ -15,18 +14,18 @@ var friends = user.as('friends'); var userToFriends = user .leftJoin(friendship).on(user.id.equals(friendship.userId)) .leftJoin(friends).on(friendship.friendId.equals(friends.id)); - + //and now...compose... var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); console.log(friendsWhoHaveLoggedInQuery.toQuery().text); -//SELECT * FROM "user" -//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") -//LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") -//WHERE "friends"."lastLogin" IS NOT NULL +// SELECT * FROM "user" +// LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +// LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") +// WHERE "friends"."lastLogin" IS NOT NULL var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); console.log(friendsWhoUseGmailQuery.toQuery().text); -//SELECT * FROM "user" -//LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") -//LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") -//WHERE "friends"."email" LIKE %1 +// SELECT * FROM "user" +// LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") +// LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") +// WHERE "friends"."email" LIKE %1 From 758c7392c2af665b86231d7b1d4d0f30ad1be948 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 15:12:00 -0700 Subject: [PATCH 129/507] Add jshint to the devDependencies, update makefile to use local jshint --- Makefile | 2 +- package.json | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 3013fff4..6cde1304 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: jshint test jshint: - jshint lib test + ./node_modules/.bin/jshint lib test test: npm test diff --git a/package.json b/package.json index 05a68bf3..3e5c6fbf 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,11 @@ "node": "*" }, "dependencies": { - "sliced": "0.0.5", - "lodash": "~1.2.1" + "sliced" : "0.0.5", + "lodash" : "~1.2.1" }, "devDependencies": { - "mocha": "*" + "jshint" : "*", + "mocha" : "*" } } From 9281093a5ee80b1bf1bf79eb0c8185e0953338ee Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 19:50:54 -0700 Subject: [PATCH 130/507] moving readme-examples.js file --- test/readme-examples.js => readme-examples.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/readme-examples.js => readme-examples.js (97%) diff --git a/test/readme-examples.js b/readme-examples.js similarity index 97% rename from test/readme-examples.js rename to readme-examples.js index 33fa47e9..d59ddfbc 100644 --- a/test/readme-examples.js +++ b/readme-examples.js @@ -1,4 +1,4 @@ -var sql = require('../lib'); +var sql = require('./lib'); var user = sql.define({ name: 'user', columns: ['id', 'lastLogin', 'email'] From 392738edd6bb2248c4a04187903ae5952516157d Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 19:56:30 -0700 Subject: [PATCH 131/507] update travis to run against node 0.10 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2a9b9e68..d523c5f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,4 @@ node_js: - 0.4 - 0.6 - 0.8 + - 0.10 From 45b50d998becfa62bd95d4a5a94775e1b734e514 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Wed, 5 Jun 2013 08:58:34 -0500 Subject: [PATCH 132/507] remove unneeded file --- readme-examples.js | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 readme-examples.js diff --git a/readme-examples.js b/readme-examples.js deleted file mode 100644 index d59ddfbc..00000000 --- a/readme-examples.js +++ /dev/null @@ -1,31 +0,0 @@ -var sql = require('./lib'); -var user = sql.define({ - name: 'user', - columns: ['id', 'lastLogin', 'email'] -}); - -// this also makes parts of your queries composable, which is handy -var friendship = sql.define({ - name: 'friendship', - columns: ['userId', 'friendId'] -}); - -var friends = user.as('friends'); -var userToFriends = user - .leftJoin(friendship).on(user.id.equals(friendship.userId)) - .leftJoin(friends).on(friendship.friendId.equals(friends.id)); - -//and now...compose... -var friendsWhoHaveLoggedInQuery = user.from(userToFriends).where(friends.lastLogin.isNotNull()); -console.log(friendsWhoHaveLoggedInQuery.toQuery().text); -// SELECT * FROM "user" -// LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") -// LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") -// WHERE "friends"."lastLogin" IS NOT NULL - -var friendsWhoUseGmailQuery = user.from(userToFriends).where(friends.email.like('%@gmail.com')); -console.log(friendsWhoUseGmailQuery.toQuery().text); -// SELECT * FROM "user" -// LEFT JOIN "friendship" ON ("user"."id" = "friendship"."userId") -// LEFT JOIN "user" AS "friends" ON ("friendship"."friendId" = "friends"."id") -// WHERE "friends"."email" LIKE %1 From 55b9c0c664fbb61ed2bc0e295bea1a6110e4df75 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Mon, 3 Jun 2013 11:28:26 -0700 Subject: [PATCH 133/507] Add SQL arithmetic operators as binaryMethods --- lib/column.js | 6 ++++++ test/binary-clause-tests.js | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/lib/column.js b/lib/column.js index e5f6e1c8..0f726321 100644 --- a/lib/column.js +++ b/lib/column.js @@ -136,4 +136,10 @@ binaryMethod('notLike', 'NOT LIKE'); binaryMethod('in', 'IN'); binaryMethod('notIn', 'NOT IN'); +binaryMethod('add', '+'); +binaryMethod('subtract', '-'); +binaryMethod('multiply', '*'); +binaryMethod('divide', '/'); +binaryMethod('modulo', '%'); + module.exports = Column; diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 1214e405..0b218bd0 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -22,4 +22,9 @@ test('operators', function() { assert.equal(Foo.baz.gte(1).operator, '>='); assert.equal(Foo.baz.lt(1).operator, '<'); assert.equal(Foo.baz.lte(1).operator, '<='); + assert.equal(Foo.baz.add(1).operator, '+'); + assert.equal(Foo.baz.subtract(1).operator, '-'); + assert.equal(Foo.baz.multiply(1).operator, '*'); + assert.equal(Foo.baz.divide(1).operator, '/'); + assert.equal(Foo.baz.modulo(1).operator, '%'); }); From ab6655d6793c0f008f16be0aa56f690cad327d69 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Tue, 4 Jun 2013 14:12:37 -0700 Subject: [PATCH 134/507] Let binary expressions (e.g. boolean AND, OR, =, or arithmetic +, -, ...) be composable --- lib/column.js | 41 ++----------------- lib/node/binary.js | 72 +++++++++++++++++++++++++-------- lib/node/where.js | 2 +- test/dialects/shortcut-tests.js | 9 +++++ test/dialects/support.js | 7 ++++ 5 files changed, 76 insertions(+), 55 deletions(-) diff --git a/lib/column.js b/lib/column.js index 0f726321..7f4cb26f 100644 --- a/lib/column.js +++ b/lib/column.js @@ -1,8 +1,9 @@ 'use strict'; +var _ = require('lodash'); var ColumnNode = require(__dirname + '/node/column'); var ParameterNode = require(__dirname + '/node/parameter'); -var BinaryNode = require(__dirname + '/node/binary'); +var valueExpressionMixin = require(__dirname + '/node/binary').valueExpressionMixin; var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); @@ -21,24 +22,6 @@ var Column = function(config) { this.dataType = config.dataType; }; -var binaryMethod = function(name, operator) { - Column.prototype[name] = function(val) { - var node = new BinaryNode({ - left: this.toNode(), - operator: operator - }); - if (Array.isArray(val)) { - node.right = val.map(function (v) { - return v.toNode ? v.toNode() : new ParameterNode(v); - }); - } - else { - node.right = val.toNode ? val.toNode() : new ParameterNode(val); - } - return node; - }; -}; - var unaryMethod = function(name, operator) { /*jshint unused: false */ Column.prototype[name] = function(val) { @@ -121,25 +104,9 @@ Column.prototype.toQuery = function() { return this.toNode().toQuery(); }; -binaryMethod('equals', '='); -binaryMethod('equal', '='); -binaryMethod('notEqual', '<>'); -binaryMethod('notEquals', '<>'); +Column.prototype = _.extend(Column.prototype, valueExpressionMixin); + unaryMethod('isNull', 'IS NULL'); unaryMethod('isNotNull', 'IS NOT NULL'); -binaryMethod('gt', '>'); -binaryMethod('gte', '>='); -binaryMethod('lt', '<'); -binaryMethod('lte', '<='); -binaryMethod('like', 'LIKE'); -binaryMethod('notLike', 'NOT LIKE'); -binaryMethod('in', 'IN'); -binaryMethod('notIn', 'NOT IN'); - -binaryMethod('add', '+'); -binaryMethod('subtract', '-'); -binaryMethod('multiply', '*'); -binaryMethod('divide', '/'); -binaryMethod('modulo', '%'); module.exports = Column; diff --git a/lib/node/binary.js b/lib/node/binary.js index 5f666995..4d4fdb33 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -1,6 +1,53 @@ 'use strict'; -var Node = require(__dirname); -var BinaryNode = module.exports = Node.define({ + +var _ = require('lodash'); +var Node = require(__dirname); +var ParameterNode = require(__dirname + '/parameter'); + +var binaryMethod = function(operator) { + return function(val) { + var node = new BinaryNode({ + left: this.toNode(), + operator: operator + }); + if (Array.isArray(val)) { + node.right = val.map(function (v) { + return v.toNode ? v.toNode() : new ParameterNode(v); + }); + } + else { + node.right = val.toNode ? val.toNode() : new ParameterNode(val); + } + return node; + }; +} ; + +// Value expressions can be composed to form new binary expressions. +// valueExpressionMixin is in this file because it depends upon +// BinaryNode, while BinaryNode depends upon valueExpressionMixin. +var valueExpressionMixin = { + or : binaryMethod('OR'), + and : binaryMethod('AND'), + equals : binaryMethod('='), + equal : binaryMethod('='), + notEquals: binaryMethod('<>'), + notEqual : binaryMethod('<>'), + gt : binaryMethod('>'), + gte : binaryMethod('>='), + lt : binaryMethod('<'), + lte : binaryMethod('<='), + add : binaryMethod('+'), + subtract : binaryMethod('-'), + multiply : binaryMethod('*'), + divide : binaryMethod('/'), + modulo : binaryMethod('%'), + like : binaryMethod('LIKE'), + notLike : binaryMethod('NOT LIKE'), + in : binaryMethod('IN'), + notIn : binaryMethod('NOT IN') +}; + +var BinaryNode = Node.define(_.extend({ type: 'BINARY', constructor: function(config) { Node.call(this); @@ -8,18 +55,9 @@ var BinaryNode = module.exports = Node.define({ this.operator = config.operator; this.right = config.right; }, - or: function(node) { - return new BinaryNode({ - left: this, - operator: 'OR', - right: node - }); - }, - and: function(node) { - return new BinaryNode({ - left: this, - operator: 'AND', - right: node - }); - } -}); +}, valueExpressionMixin)); + +module.exports = { + BinaryNode : BinaryNode, + valueExpressionMixin: valueExpressionMixin +} diff --git a/lib/node/where.js b/lib/node/where.js index 3b22ae9d..8a9976cb 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,7 +1,7 @@ 'use strict'; var Node = require(__dirname); -var BinaryNode = require(__dirname + '/binary'); +var BinaryNode = require(__dirname + '/binary').BinaryNode; var TextNode = require(__dirname + '/text'); var normalizeNode = function(table, node) { diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 188326e6..8c4c8abc 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -3,6 +3,7 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); +var customer = Harness.defineCustomerTable(); // shortcut: 'select * from
' Harness.test({ @@ -51,3 +52,11 @@ Harness.test({ mysql : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', params: ['', 1] }); + +Harness.test({ + query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.add(5).multiply(customer.age.subtract(2)).equals(10)), + pg : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + sqlite: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + mysql : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', + params: [100, 5, 2, 10] +}); diff --git a/test/dialects/support.js b/test/dialects/support.js index ce05b7fd..a19d26a0 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -77,5 +77,12 @@ module.exports = { name: 'comment', columns: ['postId', 'text'] }); + }, + + defineCustomerTable: function () { + return Table.define({ + name: 'customer', + columns: ['id', 'name', 'age', 'income'] + }); } }; From e668e4e8dead497c9f9429b5122d897bf21d7eba Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Tue, 4 Jun 2013 14:44:06 -0700 Subject: [PATCH 135/507] Fix nits; capitalization and spaces. --- lib/column.js | 4 ++-- lib/node/binary.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/column.js b/lib/column.js index 7f4cb26f..dfc47584 100644 --- a/lib/column.js +++ b/lib/column.js @@ -3,7 +3,7 @@ var _ = require('lodash'); var ColumnNode = require(__dirname + '/node/column'); var ParameterNode = require(__dirname + '/node/parameter'); -var valueExpressionMixin = require(__dirname + '/node/binary').valueExpressionMixin; +var ValueExpressionMixin = require(__dirname + '/node/binary').ValueExpressionMixin; var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); @@ -104,7 +104,7 @@ Column.prototype.toQuery = function() { return this.toNode().toQuery(); }; -Column.prototype = _.extend(Column.prototype, valueExpressionMixin); +Column.prototype = _.extend(Column.prototype, ValueExpressionMixin); unaryMethod('isNull', 'IS NULL'); unaryMethod('isNotNull', 'IS NOT NULL'); diff --git a/lib/node/binary.js b/lib/node/binary.js index 4d4fdb33..553f98ed 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -20,12 +20,12 @@ var binaryMethod = function(operator) { } return node; }; -} ; +}; // Value expressions can be composed to form new binary expressions. // valueExpressionMixin is in this file because it depends upon // BinaryNode, while BinaryNode depends upon valueExpressionMixin. -var valueExpressionMixin = { +var ValueExpressionMixin = { or : binaryMethod('OR'), and : binaryMethod('AND'), equals : binaryMethod('='), @@ -59,5 +59,5 @@ var BinaryNode = Node.define(_.extend({ module.exports = { BinaryNode : BinaryNode, - valueExpressionMixin: valueExpressionMixin + ValueExpressionMixin: ValueExpressionMixin } From 55810ac805197ca63477ab5875e071480ddfcc1a Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 15:20:49 -0700 Subject: [PATCH 136/507] Fix up errors caught by jshint --- lib/node/binary.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node/binary.js b/lib/node/binary.js index 553f98ed..041472bd 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -23,8 +23,8 @@ var binaryMethod = function(operator) { }; // Value expressions can be composed to form new binary expressions. -// valueExpressionMixin is in this file because it depends upon -// BinaryNode, while BinaryNode depends upon valueExpressionMixin. +// ValueExpressionMixin is in this file because it depends upon +// BinaryNode, while BinaryNode depends upon ValueExpressionMixin. var ValueExpressionMixin = { or : binaryMethod('OR'), and : binaryMethod('AND'), @@ -55,9 +55,9 @@ var BinaryNode = Node.define(_.extend({ this.operator = config.operator; this.right = config.right; }, -}, valueExpressionMixin)); +}, ValueExpressionMixin)); module.exports = { BinaryNode : BinaryNode, ValueExpressionMixin: ValueExpressionMixin -} +}; From f435fe8e4f1524284afc2682d621fe88648b4ed3 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 16:09:49 -0700 Subject: [PATCH 137/507] binary clause dialect test --- test/dialects/binary-clause-tests.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/dialects/binary-clause-tests.js diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js new file mode 100644 index 00000000..23a08c39 --- /dev/null +++ b/test/dialects/binary-clause-tests.js @@ -0,0 +1,22 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var post = Harness.definePostTable(); +var Table = require(__dirname + '/../../lib/table'); + +Harness.test({ + query : customer.select(customer.name.add(customer.age)), + pg : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + sqlite: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + mysql : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', + params: [] +}); + +Harness.test({ + query : post.select(post.content.add('!')).where(post.userId.in(customer.subQuery().select(customer.id))), + pg : 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', + sqlite: 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', + mysql : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', + params: ['!'] +}); From 48a81ce1630ae9262fef6660be5a0dee5418a034 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Tue, 4 Jun 2013 22:12:11 -0700 Subject: [PATCH 138/507] Break out ValueExpressionMixin into its own file, and mix it into the value expressions BinaryNode, UnaryNode, and Column. Will make composing such value expression nodes easier in the future. --- lib/column.js | 25 +++++--------- lib/node/binary.js | 59 ++++++--------------------------- lib/node/unary.js | 9 +++++ lib/node/valueExpression.js | 66 +++++++++++++++++++++++++++++++++++++ lib/node/where.js | 2 +- 5 files changed, 94 insertions(+), 67 deletions(-) create mode 100644 lib/node/valueExpression.js diff --git a/lib/column.js b/lib/column.js index dfc47584..5e819a38 100644 --- a/lib/column.js +++ b/lib/column.js @@ -2,12 +2,12 @@ var _ = require('lodash'); var ColumnNode = require(__dirname + '/node/column'); -var ParameterNode = require(__dirname + '/node/parameter'); -var ValueExpressionMixin = require(__dirname + '/node/binary').ValueExpressionMixin; +var ValueExpressionMixin = require(__dirname + '/node/valueExpression'); var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); +var valueExpressionMixed = false; var Column = function(config) { this.table = config.table; for(var name in config) { @@ -20,16 +20,12 @@ var Column = function(config) { direction: new TextNode('DESC') }); this.dataType = config.dataType; -}; - -var unaryMethod = function(name, operator) { - /*jshint unused: false */ - Column.prototype[name] = function(val) { - return new UnaryNode({ - left: this.toNode(), - operator: operator - }); - }; + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. This is to avoid circular dependency in + // CommonJS. + if (!valueExpressionMixed) { + _.extend(Column.prototype, ValueExpressionMixin()); + } }; var contextify = function(base) { @@ -104,9 +100,4 @@ Column.prototype.toQuery = function() { return this.toNode().toQuery(); }; -Column.prototype = _.extend(Column.prototype, ValueExpressionMixin); - -unaryMethod('isNull', 'IS NULL'); -unaryMethod('isNotNull', 'IS NOT NULL'); - module.exports = Column; diff --git a/lib/node/binary.js b/lib/node/binary.js index 041472bd..08e3ec1c 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -2,51 +2,9 @@ var _ = require('lodash'); var Node = require(__dirname); -var ParameterNode = require(__dirname + '/parameter'); - -var binaryMethod = function(operator) { - return function(val) { - var node = new BinaryNode({ - left: this.toNode(), - operator: operator - }); - if (Array.isArray(val)) { - node.right = val.map(function (v) { - return v.toNode ? v.toNode() : new ParameterNode(v); - }); - } - else { - node.right = val.toNode ? val.toNode() : new ParameterNode(val); - } - return node; - }; -}; - -// Value expressions can be composed to form new binary expressions. -// ValueExpressionMixin is in this file because it depends upon -// BinaryNode, while BinaryNode depends upon ValueExpressionMixin. -var ValueExpressionMixin = { - or : binaryMethod('OR'), - and : binaryMethod('AND'), - equals : binaryMethod('='), - equal : binaryMethod('='), - notEquals: binaryMethod('<>'), - notEqual : binaryMethod('<>'), - gt : binaryMethod('>'), - gte : binaryMethod('>='), - lt : binaryMethod('<'), - lte : binaryMethod('<='), - add : binaryMethod('+'), - subtract : binaryMethod('-'), - multiply : binaryMethod('*'), - divide : binaryMethod('/'), - modulo : binaryMethod('%'), - like : binaryMethod('LIKE'), - notLike : binaryMethod('NOT LIKE'), - in : binaryMethod('IN'), - notIn : binaryMethod('NOT IN') -}; +var ValueExpressionMixin = require(__dirname + '/valueExpression'); +var valueExpressionMixed = false; var BinaryNode = Node.define(_.extend({ type: 'BINARY', constructor: function(config) { @@ -54,10 +12,13 @@ var BinaryNode = Node.define(_.extend({ this.left = config.left; this.operator = config.operator; this.right = config.right; + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. This is to avoid circular dependency in + // CommonJS. + if (!valueExpressionMixed) { + _.extend(BinaryNode.prototype, ValueExpressionMixin()); + } }, -}, ValueExpressionMixin)); +})); -module.exports = { - BinaryNode : BinaryNode, - ValueExpressionMixin: ValueExpressionMixin -}; +module.exports = BinaryNode; diff --git a/lib/node/unary.js b/lib/node/unary.js index 5526c3e6..8b7d3ec5 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -1,11 +1,20 @@ 'use strict'; var Node = require(__dirname); +var ValueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; module.exports = Node.define({ type: 'UNARY', constructor: function(config) { Node.call(this); this.left = config.left; this.operator = config.operator; + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. This is to avoid circular dependency in + // CommonJS. + if (!valueExpressionMixed) { + _.extend(UnaryNode.prototype, ValueExpressionMixin()); + } } }); diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js new file mode 100644 index 00000000..dbea85c9 --- /dev/null +++ b/lib/node/valueExpression.js @@ -0,0 +1,66 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var ParameterNode = require(__dirname + '/parameter'); + +// Process values, wrapping them in ParameterNode if necessary. +var processParams = function(val) { + var helper = function(v) { + return v.toNode ? v.toNode() : new ParameterNode(v); + } + return Array.isArray(val) ? val.map(helper) : helper(val) +} + +// Value expressions can be composed to form new value expressions. +// Value expressions include binary expressions and unary expressions +// so far. ValueExpressionMixin is evaluated at runtime, hence the +// "thunk" around it. +var ValueExpressionMixin = module.exports = function() { + var BinaryNode = require(__dirname + '/binary'); + var UnaryNode = require(__dirname + '/unary'); + + var binaryMethod = function(operator) { + return function(val) { + return new BinaryNode({ + left: this.toNode(), + operator: operator, + right: processParams(val) + }); + }; + }; + + var unaryMethod = function(operator) { + /*jshint unused: false */ + return function(val) { + return new UnaryNode({ + left: this.toNode(), + operator: operator + }); + }; + }; + + return { + or : binaryMethod('OR'), + and : binaryMethod('AND'), + equals : binaryMethod('='), + equal : binaryMethod('='), + notEquals: binaryMethod('<>'), + notEqual : binaryMethod('<>'), + gt : binaryMethod('>'), + gte : binaryMethod('>='), + lt : binaryMethod('<'), + lte : binaryMethod('<='), + add : binaryMethod('+'), + subtract : binaryMethod('-'), + multiply : binaryMethod('*'), + divide : binaryMethod('/'), + modulo : binaryMethod('%'), + like : binaryMethod('LIKE'), + notLike : binaryMethod('NOT LIKE'), + in : binaryMethod('IN'), + notIn : binaryMethod('NOT IN'), + isNull : unaryMethod('IS NULL'), + isNotNull: unaryMethod('IS NOT NULL') + } +}; diff --git a/lib/node/where.js b/lib/node/where.js index 8a9976cb..3b22ae9d 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -1,7 +1,7 @@ 'use strict'; var Node = require(__dirname); -var BinaryNode = require(__dirname + '/binary').BinaryNode; +var BinaryNode = require(__dirname + '/binary'); var TextNode = require(__dirname + '/text'); var normalizeNode = function(table, node) { From 4fcb84874b6f13b83b3233e6d84f8b06482fc738 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Tue, 4 Jun 2013 22:26:09 -0700 Subject: [PATCH 139/507] whoops, accidentally pushed when not ready. fixed some bugs in previous commit --- lib/node/unary.js | 3 ++- test/dialects/shortcut-tests.js | 9 --------- test/dialects/value-expression-tests.js | 12 ++++++++++++ 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 test/dialects/value-expression-tests.js diff --git a/lib/node/unary.js b/lib/node/unary.js index 8b7d3ec5..e22cfda3 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -1,10 +1,11 @@ 'use strict'; +var _ = require('lodash'); var Node = require(__dirname); var ValueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; -module.exports = Node.define({ +var UnaryNode = module.exports = Node.define({ type: 'UNARY', constructor: function(config) { Node.call(this); diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 8c4c8abc..188326e6 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -3,7 +3,6 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); -var customer = Harness.defineCustomerTable(); // shortcut: 'select * from
' Harness.test({ @@ -52,11 +51,3 @@ Harness.test({ mysql : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', params: ['', 1] }); - -Harness.test({ - query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.add(5).multiply(customer.age.subtract(2)).equals(10)), - pg : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', - sqlite: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', - mysql : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', - params: [100, 5, 2, 10] -}); diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js new file mode 100644 index 00000000..7fcfa1eb --- /dev/null +++ b/test/dialects/value-expression-tests.js @@ -0,0 +1,12 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); + +Harness.test({ + query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.add(5).multiply(customer.age.subtract(2)).equals(10)), + pg : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + sqlite: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + mysql : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', + params: [100, 5, 2, 10] +}); From ef951a9b96cb2a4d34ed5827468ace5dae970b80 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Wed, 5 Jun 2013 11:31:59 -0700 Subject: [PATCH 140/507] Mixin only once. Set flag to true once mixed --- lib/column.js | 1 + lib/node/binary.js | 1 + lib/node/unary.js | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/column.js b/lib/column.js index 5e819a38..5d6b09ef 100644 --- a/lib/column.js +++ b/lib/column.js @@ -24,6 +24,7 @@ var Column = function(config) { // mixin only once. This is to avoid circular dependency in // CommonJS. if (!valueExpressionMixed) { + valueExpressionMixed = true; _.extend(Column.prototype, ValueExpressionMixin()); } }; diff --git a/lib/node/binary.js b/lib/node/binary.js index 08e3ec1c..c10cf6aa 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -16,6 +16,7 @@ var BinaryNode = Node.define(_.extend({ // mixin only once. This is to avoid circular dependency in // CommonJS. if (!valueExpressionMixed) { + valueExpressionMixed = true; _.extend(BinaryNode.prototype, ValueExpressionMixin()); } }, diff --git a/lib/node/unary.js b/lib/node/unary.js index e22cfda3..b2ae65f9 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -15,6 +15,7 @@ var UnaryNode = module.exports = Node.define({ // mixin only once. This is to avoid circular dependency in // CommonJS. if (!valueExpressionMixed) { + valueExpressionMixed = true; _.extend(UnaryNode.prototype, ValueExpressionMixin()); } } From 45a9a7ed6183272b9baab19542953571005835c3 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Wed, 5 Jun 2013 15:50:06 -0700 Subject: [PATCH 141/507] Add tests implementing simple formulas to test composing binary expressions. --- test/dialects/support.js | 8 +++++++ test/dialects/value-expression-tests.js | 30 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/test/dialects/support.js b/test/dialects/support.js index a19d26a0..346bee70 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -84,5 +84,13 @@ module.exports = { name: 'customer', columns: ['id', 'name', 'age', 'income'] }); + }, + + // This table contains column names that correspond to popularly used variables in formulas. + defineVariableTable: function() { + return Table.define({ + name: 'variable', + columns: ['a', 'b', 'c', 'd', 't', 'u', 'v', 'x', 'y', 'z'] + }); } }; diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 7fcfa1eb..8dd14e72 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -2,7 +2,9 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); +var v = Harness.defineVariableTable(); +// Test composition of binary methods +, *, -, =. Harness.test({ query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.add(5).multiply(customer.age.subtract(2)).equals(10)), pg : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', @@ -10,3 +12,31 @@ Harness.test({ mysql : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', params: [100, 5, 2, 10] }); + +// Test composition of binary (e.g. +) and unary (e.g. like) methods. +Harness.test({ + query : customer.select(customer.name).where(customer.name.like(customer.id.add('hello'))), + pg : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', + sqlite: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', + mysql : 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', + params: ['hello'] +}); + +// Test implementing simple formulas. +// Acceleration formula. (a * t^2 / 2) + (v * t) = d +Harness.test({ + query : v.select(v.a.multiply(v.a).divide(2).add(v.v.multiply(v.t)).equals(v.d)), + pg : 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', + sqlite: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', + mysql : 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', + params: [2] +}); + +// Pythagorean theorem. a^2 + b^2 = c^2. +Harness.test({ + query : v.select(v.a.multiply(v.a).add(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), + pg : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + sqlite: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + mysql : 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', + params: [] +}); From f840af4f35045e898f867ccaf0f35ec89369232a Mon Sep 17 00:00:00 2001 From: Di Wu Date: Wed, 5 Jun 2013 21:59:54 -0700 Subject: [PATCH 142/507] Cleanup for jshint --- lib/column.js | 4 ++-- lib/node/binary.js | 4 ++-- lib/node/unary.js | 4 ++-- lib/node/valueExpression.js | 10 +++++----- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/column.js b/lib/column.js index 5d6b09ef..888b3ef9 100644 --- a/lib/column.js +++ b/lib/column.js @@ -2,7 +2,7 @@ var _ = require('lodash'); var ColumnNode = require(__dirname + '/node/column'); -var ValueExpressionMixin = require(__dirname + '/node/valueExpression'); +var valueExpressionMixin = require(__dirname + '/node/valueExpression'); var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); @@ -25,7 +25,7 @@ var Column = function(config) { // CommonJS. if (!valueExpressionMixed) { valueExpressionMixed = true; - _.extend(Column.prototype, ValueExpressionMixin()); + _.extend(Column.prototype, valueExpressionMixin()); } }; diff --git a/lib/node/binary.js b/lib/node/binary.js index c10cf6aa..765f4c6e 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -2,7 +2,7 @@ var _ = require('lodash'); var Node = require(__dirname); -var ValueExpressionMixin = require(__dirname + '/valueExpression'); +var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; var BinaryNode = Node.define(_.extend({ @@ -17,7 +17,7 @@ var BinaryNode = Node.define(_.extend({ // CommonJS. if (!valueExpressionMixed) { valueExpressionMixed = true; - _.extend(BinaryNode.prototype, ValueExpressionMixin()); + _.extend(BinaryNode.prototype, valueExpressionMixin()); } }, })); diff --git a/lib/node/unary.js b/lib/node/unary.js index b2ae65f9..c6f5e441 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -2,7 +2,7 @@ var _ = require('lodash'); var Node = require(__dirname); -var ValueExpressionMixin = require(__dirname + '/valueExpression'); +var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; var UnaryNode = module.exports = Node.define({ @@ -16,7 +16,7 @@ var UnaryNode = module.exports = Node.define({ // CommonJS. if (!valueExpressionMixed) { valueExpressionMixed = true; - _.extend(UnaryNode.prototype, ValueExpressionMixin()); + _.extend(UnaryNode.prototype, valueExpressionMixin()); } } }); diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index dbea85c9..17e1fbb2 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -8,9 +8,9 @@ var ParameterNode = require(__dirname + '/parameter'); var processParams = function(val) { var helper = function(v) { return v.toNode ? v.toNode() : new ParameterNode(v); - } - return Array.isArray(val) ? val.map(helper) : helper(val) -} + }; + return Array.isArray(val) ? val.map(helper) : helper(val); +}; // Value expressions can be composed to form new value expressions. // Value expressions include binary expressions and unary expressions @@ -25,7 +25,7 @@ var ValueExpressionMixin = module.exports = function() { return new BinaryNode({ left: this.toNode(), operator: operator, - right: processParams(val) + right: processParams(val) }); }; }; @@ -62,5 +62,5 @@ var ValueExpressionMixin = module.exports = function() { notIn : binaryMethod('NOT IN'), isNull : unaryMethod('IS NULL'), isNotNull: unaryMethod('IS NOT NULL') - } + }; }; From 03287e45d544ecbdb45358f1f271095a18665188 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Thu, 6 Jun 2013 16:58:01 -0700 Subject: [PATCH 143/507] binary and unary clause tests --- lib/node/binary.js | 5 +++-- lib/node/unary.js | 5 +++-- test/dialects/binary-clause-tests.js | 8 ++++++++ test/dialects/unary-clause-tests.js | 22 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 test/dialects/unary-clause-tests.js diff --git a/lib/node/binary.js b/lib/node/binary.js index 765f4c6e..c15c2967 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -13,8 +13,9 @@ var BinaryNode = Node.define(_.extend({ this.operator = config.operator; this.right = config.right; // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. This is to avoid circular dependency in - // CommonJS. + // mixin only once. + // There is circular dependency between unary, binary and value + // expression mixin, thus this must be delayed to runtime. if (!valueExpressionMixed) { valueExpressionMixed = true; _.extend(BinaryNode.prototype, valueExpressionMixin()); diff --git a/lib/node/unary.js b/lib/node/unary.js index c6f5e441..2e3e7673 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -12,8 +12,9 @@ var UnaryNode = module.exports = Node.define({ this.left = config.left; this.operator = config.operator; // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. This is to avoid circular dependency in - // CommonJS. + // mixin only once. + // There is circular dependency between unary, binary and value + // expression mixin, thus this must be delayed to runtime. if (!valueExpressionMixed) { valueExpressionMixed = true; _.extend(UnaryNode.prototype, valueExpressionMixin()); diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 23a08c39..eac93f0a 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -20,3 +20,11 @@ Harness.test({ mysql : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', params: ['!'] }); + +Harness.test({ + query : post.select(post.id.add(': ').add(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), + pg : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', + sqlite : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', + mysql : 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', + params : [': '] +}); diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js new file mode 100644 index 00000000..34a18f86 --- /dev/null +++ b/test/dialects/unary-clause-tests.js @@ -0,0 +1,22 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var post = Harness.definePostTable(); +var Table = require(__dirname + '/../../lib/table'); + +Harness.test({ + query : customer.select().where(customer.age.isNotNull()), + pg : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + sqlite: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + mysql : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', + params: [] +}); + +Harness.test({ + query : post.select().where(post.userId.in(customer.subQuery().select(customer.id).where(customer.age.isNull()))), + pg : 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + sqlite: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + mysql : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', + params: [] +}); From aa8422e1b547f9ebfe8a39db797b8558cc695660 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Thu, 6 Jun 2013 18:33:03 -0700 Subject: [PATCH 144/507] Ternary between and tests --- lib/dialect/postgres.js | 26 ++++++++++++++++++++++++++ lib/node/binary.js | 9 ++++----- lib/node/ternary.js | 27 +++++++++++++++++++++++++++ lib/node/unary.js | 4 ++-- lib/node/valueExpression.js | 16 +++++++++++++++- test/dialects/ternary-clause-tests.js | 22 ++++++++++++++++++++++ test/ternary-clause-tests.js | 15 +++++++++++++++ test/unary-clause-tests.js | 15 +++++++++++++++ 8 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 lib/node/ternary.js create mode 100644 test/dialects/ternary-clause-tests.js create mode 100644 test/ternary-clause-tests.js create mode 100644 test/unary-clause-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 21c850f6..5eaf4401 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -45,6 +45,7 @@ Postgres.prototype.visit = function(node) { case 'COLUMN': return this.visitColumn(node); case 'JOIN': return this.visitJoin(node); case 'TEXT': return node.text; + case 'TERNARY': return this.visitTernary(node); case 'UNARY': return this.visitUnary(node); case 'PARAMETER': return this.visitParameter(node); case 'DEFAULT': return this.visitDefault(node); @@ -215,6 +216,31 @@ Postgres.prototype.visitBinary = function(binary) { return result; }; +Postgres.prototype.visitTernary = function(ternary) { + var self = this; + var result = '(' + this.visit(ternary.left) + ' ' + ternary.operator + ' '; + + var visitPart = function(value) { + var text = ''; + if (Array.isArray(value)) { + text += '(' + value.map(function (node) { + return self.visit(node); + }).join(', ') + ')'; + } + else { + text += self.visit(value); + } + return text; + }; + + result += visitPart(ternary.middle); + result += ' ' + ternary.separator + ' '; + result += visitPart(ternary.right); + + result += ')'; + return result; +}; + Postgres.prototype.visitUnary = function(unary) { return '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; }; diff --git a/lib/node/binary.js b/lib/node/binary.js index c15c2967..341b8037 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -1,7 +1,7 @@ 'use strict'; -var _ = require('lodash'); -var Node = require(__dirname); +var _ = require('lodash'); +var Node = require(__dirname); var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; @@ -12,10 +12,9 @@ var BinaryNode = Node.define(_.extend({ this.left = config.left; this.operator = config.operator; this.right = config.right; + // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. - // There is circular dependency between unary, binary and value - // expression mixin, thus this must be delayed to runtime. + // mixin only once. ValueExpressionMixin has circular dependencies. if (!valueExpressionMixed) { valueExpressionMixed = true; _.extend(BinaryNode.prototype, valueExpressionMixin()); diff --git a/lib/node/ternary.js b/lib/node/ternary.js new file mode 100644 index 00000000..2a93c23c --- /dev/null +++ b/lib/node/ternary.js @@ -0,0 +1,27 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var TernaryNode = Node.define(_.extend({ + type: 'TERNARY', + constructor: function(config) { + Node.call(this); + this.left = config.left; + this.middle = config.middle; + this.operator = config.operator; + this.right = config.right; + this.separator = config.separator; + + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(TernaryNode.prototype, valueExpressionMixin()); + } + }, +})); + +module.exports = TernaryNode; diff --git a/lib/node/unary.js b/lib/node/unary.js index 2e3e7673..8b2ff9f0 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -1,7 +1,7 @@ 'use strict'; -var _ = require('lodash'); -var Node = require(__dirname); +var _ = require('lodash'); +var Node = require(__dirname); var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 17e1fbb2..d2c47c17 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -18,6 +18,7 @@ var processParams = function(val) { // "thunk" around it. var ValueExpressionMixin = module.exports = function() { var BinaryNode = require(__dirname + '/binary'); + var TernaryNode = require(__dirname + '/ternary'); var UnaryNode = require(__dirname + '/unary'); var binaryMethod = function(operator) { @@ -30,6 +31,18 @@ var ValueExpressionMixin = module.exports = function() { }; }; + var ternaryMethod = function(operator, separator) { + return function(middle, right) { + return new TernaryNode({ + left: this.toNode(), + middle: processParams(middle), + operator: operator, + right: processParams(right), + separator: separator + }); + }; + }; + var unaryMethod = function(operator) { /*jshint unused: false */ return function(val) { @@ -61,6 +74,7 @@ var ValueExpressionMixin = module.exports = function() { in : binaryMethod('IN'), notIn : binaryMethod('NOT IN'), isNull : unaryMethod('IS NULL'), - isNotNull: unaryMethod('IS NOT NULL') + isNotNull: unaryMethod('IS NOT NULL'), + between : ternaryMethod('BETWEEN', 'AND') }; }; diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js new file mode 100644 index 00000000..887c7fad --- /dev/null +++ b/test/dialects/ternary-clause-tests.js @@ -0,0 +1,22 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var post = Harness.definePostTable(); +var Table = require(__dirname + '/../../lib/table'); + +Harness.test({ + query : customer.select().where(customer.age.between(18, 25)), + pg : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + sqlite: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + mysql : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', + params: [18, 25] +}); + +Harness.test({ + query : post.select().where(post.userId.between(customer.subQuery().select(customer.id.min()), customer.subQuery().select(customer.id.max()))), + pg : '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"))', + sqlite: '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"))', + mysql : '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: [] +}); diff --git a/test/ternary-clause-tests.js b/test/ternary-clause-tests.js new file mode 100644 index 00000000..71d897c3 --- /dev/null +++ b/test/ternary-clause-tests.js @@ -0,0 +1,15 @@ +/* global test */ +'use strict'; + +var assert = require('assert'); +var Table = require(__dirname + '/../lib/table'); + +var Foo = Table.define({ + name: 'foo', + columns: ['baz','bar'] +}); + +test('operators', function() { + assert.equal(Foo.bar.between(1, 2).operator, 'BETWEEN'); + assert.equal(Foo.baz.between(1, 2).separator, 'AND'); +}); diff --git a/test/unary-clause-tests.js b/test/unary-clause-tests.js new file mode 100644 index 00000000..745eb20f --- /dev/null +++ b/test/unary-clause-tests.js @@ -0,0 +1,15 @@ +/* global test */ +'use strict'; + +var assert = require('assert'); +var Table = require(__dirname + '/../lib/table'); + +var Foo = Table.define({ + name: 'foo', + columns: ['baz','bar'] +}); + +test('operators', function() { + assert.equal(Foo.bar.isNull().operator, 'IS NULL'); + assert.equal(Foo.baz.isNotNull().operator, 'IS NOT NULL'); +}); From 6b2ab16b1a4df20bd68b2afb3f1ec8efd5012b4c Mon Sep 17 00:00:00 2001 From: Di Wu Date: Thu, 6 Jun 2013 18:37:08 -0700 Subject: [PATCH 145/507] Re-ordering unary, binary, ternary in valueExpression --- lib/node/valueExpression.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index d2c47c17..8a76a55e 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -31,6 +31,16 @@ var ValueExpressionMixin = module.exports = function() { }; }; + var unaryMethod = function(operator) { + /*jshint unused: false */ + return function(val) { + return new UnaryNode({ + left: this.toNode(), + operator: operator + }); + }; + }; + var ternaryMethod = function(operator, separator) { return function(middle, right) { return new TernaryNode({ @@ -43,17 +53,9 @@ var ValueExpressionMixin = module.exports = function() { }; }; - var unaryMethod = function(operator) { - /*jshint unused: false */ - return function(val) { - return new UnaryNode({ - left: this.toNode(), - operator: operator - }); - }; - }; - return { + isNull : unaryMethod('IS NULL'), + isNotNull: unaryMethod('IS NOT NULL'), or : binaryMethod('OR'), and : binaryMethod('AND'), equals : binaryMethod('='), @@ -73,8 +75,6 @@ var ValueExpressionMixin = module.exports = function() { notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), notIn : binaryMethod('NOT IN'), - isNull : unaryMethod('IS NULL'), - isNotNull: unaryMethod('IS NOT NULL'), between : ternaryMethod('BETWEEN', 'AND') }; }; From 1fff1b66c17d6595118580a6799c1aabe4c76ce8 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 7 Jun 2013 00:20:06 -0700 Subject: [PATCH 146/507] dialect refactor to have unary,binary,ternary return array of string --- lib/dialect/postgres.js | 112 +++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 5eaf4401..75c426b9 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -25,43 +25,46 @@ Postgres.prototype.getQuery = function(queryNode) { Postgres.prototype.visit = function(node) { switch(node.type) { - case 'QUERY': return this.visitQuery(node); - case 'SUBQUERY': return this.visitSubquery(node); - case 'SELECT': return this.visitSelect(node); - case 'INSERT': return this.visitInsert(node); - case 'UPDATE': return this.visitUpdate(node); - case 'DELETE': return this.visitDelete(); - case 'CREATE': return this.visitCreate(node); - case 'DROP': return this.visitDrop(node); - case 'ALTER': return this.visitAlter(node); - case 'FROM': return this.visitFrom(node); - case 'WHERE': return this.visitWhere(node); - case 'ORDER BY': return this.visitOrderBy(node); - case 'ORDER BY COLUMN': return this.visitOrderByColumn(node); - case 'GROUP BY': return this.visitGroupBy(node); - case 'RETURNING': return this.visitReturning(node); - case 'BINARY': return this.visitBinary(node); - case 'TABLE': return this.visitTable(node); - case 'COLUMN': return this.visitColumn(node); - case 'JOIN': return this.visitJoin(node); - case 'TEXT': return node.text; - case 'TERNARY': return this.visitTernary(node); - case 'UNARY': return this.visitUnary(node); - case 'PARAMETER': return this.visitParameter(node); - case 'DEFAULT': return this.visitDefault(node); - case 'IF EXISTS': return this.visitIfExists(); - case 'IF NOT EXISTS': return this.visitIfNotExists(); - case 'RENAME': return this.visitRename(node); - case 'ADD COLUMN': return this.visitAddColumn(node); - case 'DROP COLUMN': return this.visitDropColumn(node); - case 'RENAME COLUMN': return this.visitRenameColumn(node); - case 'INDEXES': return this.visitIndexes(node); - case 'CREATE INDEX': return this.visitCreateIndex(node); - case 'DROP INDEX': return this.visitDropIndex(node); - case 'LIMIT': + case 'QUERY' : return this.visitQuery(node); + case 'SUBQUERY' : return this.visitSubquery(node); + case 'SELECT' : return this.visitSelect(node); + case 'INSERT' : return this.visitInsert(node); + case 'UPDATE' : return this.visitUpdate(node); + case 'DELETE' : return this.visitDelete(); + case 'CREATE' : return this.visitCreate(node); + case 'DROP' : return this.visitDrop(node); + case 'ALTER' : return this.visitAlter(node); + case 'FROM' : return this.visitFrom(node); + case 'WHERE' : return this.visitWhere(node); + case 'ORDER BY' : return this.visitOrderBy(node); + case 'ORDER BY COLUMN' : return this.visitOrderByColumn(node); + case 'GROUP BY' : return this.visitGroupBy(node); + case 'RETURNING' : return this.visitReturning(node); + case 'TABLE' : return this.visitTable(node); + case 'COLUMN' : return this.visitColumn(node); + case 'JOIN' : return this.visitJoin(node); + case 'TEXT' : return node.text; + case 'PARAMETER' : return this.visitParameter(node); + case 'DEFAULT' : return this.visitDefault(node); + case 'IF EXISTS' : return this.visitIfExists(); + case 'IF NOT EXISTS' : return this.visitIfNotExists(); + case 'RENAME' : return this.visitRename(node); + case 'ADD COLUMN' : return this.visitAddColumn(node); + case 'DROP COLUMN' : return this.visitDropColumn(node); + case 'RENAME COLUMN' : return this.visitRenameColumn(node); + case 'INDEXES' : return this.visitIndexes(node); + case 'CREATE INDEX' : return this.visitCreateIndex(node); + case 'DROP INDEX' : return this.visitDropIndex(node); + + case 'UNARY' : return this.visitUnary(node); + case 'BINARY' : return this.visitBinary(node); + case 'TERNARY' : return this.visitTernary(node); + + case 'LIMIT' : case 'OFFSET': return this.visitModifier(node); - default: throw new Error("Unrecognized node type " + node.type); + default: + throw new Error("Unrecognized node type " + node.type); } }; @@ -189,11 +192,11 @@ Postgres.prototype.visitOrderBy = function(orderBy) { }; Postgres.prototype.visitOrderByColumn = function(column) { - if(column.direction) { - return this.visit(column.column) + ' ' + this.visit(column.direction); - } else { - return this.visit(column.column); + var text = this.visit(column.column); + if (column.direction) { + text += ' ' + this.visit(column.direction); } + return [text]; }; Postgres.prototype.visitGroupBy = function(groupBy) { @@ -201,24 +204,29 @@ Postgres.prototype.visitGroupBy = function(groupBy) { return result; }; +Postgres.prototype.visitUnary = function(unary) { + var text = '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; + return [text]; +}; + Postgres.prototype.visitBinary = function(binary) { var self = this; - var result = '(' + this.visit(binary.left) + ' ' + binary.operator + ' '; + var text = '(' + this.visit(binary.left) + ' ' + binary.operator + ' '; if (Array.isArray(binary.right)) { - result += '(' + binary.right.map(function (node) { + text += '(' + binary.right.map(function (node) { return self.visit(node); }).join(', ') + ')'; } else { - result += this.visit(binary.right); + text += this.visit(binary.right); } - result += ')'; - return result; + text += ')'; + return [text]; }; Postgres.prototype.visitTernary = function(ternary) { var self = this; - var result = '(' + this.visit(ternary.left) + ' ' + ternary.operator + ' '; + var text = '(' + this.visit(ternary.left) + ' ' + ternary.operator + ' '; var visitPart = function(value) { var text = ''; @@ -233,16 +241,12 @@ Postgres.prototype.visitTernary = function(ternary) { return text; }; - result += visitPart(ternary.middle); - result += ' ' + ternary.separator + ' '; - result += visitPart(ternary.right); + text += visitPart(ternary.middle); + text += ' ' + ternary.separator + ' '; + text += visitPart(ternary.right); - result += ')'; - return result; -}; - -Postgres.prototype.visitUnary = function(unary) { - return '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; + text += ')'; + return [text]; }; Postgres.prototype.visitQuery = function(queryNode) { From ab0fa41663f61edee68bb56090e5f9296bac4c05 Mon Sep 17 00:00:00 2001 From: Gorgi Kosev Date: Fri, 7 Jun 2013 15:42:38 +0200 Subject: [PATCH 147/507] failing tests for multi-dialect create --- lib/index.js | 56 +++++++++++++++++++++++++-------------------- test/index-tests.js | 10 ++++++++ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/index.js b/lib/index.js index 7e011337..c08e7883 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,31 +2,37 @@ var Table = require(__dirname + '/table'); -var sql = { - Table: Table, - define: Table.define, - select: function() { - var Query = require(__dirname + '/node/query'); - var query = new Query(); - query.select.apply(query, arguments); - return query; - }, - setDialect: function(dialect) { - switch(dialect.toLowerCase()) { - case 'postgres': - this.dialect = require(__dirname + '/dialect/postgres'); +function create(dialect) { + var sql = { + Table: Table, + define: Table.define, + select: function() { + var Query = require(__dirname + '/node/query'); + var query = new Query(); + query.select.apply(query, arguments); + return query; + }, + setDialect: function(dialect) { + switch(dialect.toLowerCase()) { + case 'postgres': + this.dialect = require(__dirname + '/dialect/postgres'); + break; + case 'mysql': + this.dialect = require(__dirname + '/dialect/mysql'); break; - case 'mysql': - this.dialect = require(__dirname + '/dialect/mysql'); - break; - case 'sqlite': - this.dialect = require(__dirname + '/dialect/sqlite'); - break; - default: - throw new Error(dialect + ' is unsupported'); + case 'sqlite': + this.dialect = require(__dirname + '/dialect/sqlite'); + break; + default: + throw new Error(dialect + ' is unsupported'); + } + return this; } - return this; - } -}; + }; + if (dialect) sql.setDialect(dialect); + return sql; +} + -module.exports = sql.setDialect('postgres'); +module.exports = create('postgres'); +module.exports.create = create; diff --git a/test/index-tests.js b/test/index-tests.js index 9f99873f..ffed77f1 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -29,4 +29,14 @@ suite('index', function() { assert.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); }); + + + 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'); + + }); + }); From dac9724025785dfc9e84127523d882b5fd35fad8 Mon Sep 17 00:00:00 2001 From: Gorgi Kosev Date: Fri, 7 Jun 2013 17:15:52 +0200 Subject: [PATCH 148/507] fixed everything necessary to make sql.create work --- lib/index.js | 6 ++++-- lib/node/index.js | 7 ++++++- lib/node/query.js | 1 + lib/node/select.js | 8 +++++++- lib/table.js | 3 ++- test/npm-debug.log | 21 +++++++++++++++++++++ test/select-tests.js | 3 ++- 7 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 test/npm-debug.log diff --git a/lib/index.js b/lib/index.js index c08e7883..40cf4d2e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,10 +5,12 @@ var Table = require(__dirname + '/table'); function create(dialect) { var sql = { Table: Table, - define: Table.define, + define: function(def) { + return Table.define(def, this); + }, select: function() { var Query = require(__dirname + '/node/query'); - var query = new Query(); + var query = new Query({sql: this}); query.select.apply(query, arguments); return query; }, diff --git a/lib/node/index.js b/lib/node/index.js index 10fe5629..e2f0420e 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -19,7 +19,12 @@ Node.prototype.add = function(node) { }; Node.prototype.toQuery = function() { - var Dialect = require(__dirname + '/../').dialect; + var sql = this.sql || (this.table && this.table.sql); + if (sql && sql.dialect) + var Dialect = sql.dialect; + else { + throw new Error("sql dialect not set properly"); + } return new Dialect().getQuery(this); }; diff --git a/lib/node/query.js b/lib/node/query.js index 46968180..6b1964e3 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -43,6 +43,7 @@ var Query = Node.define({ constructor: function(table) { Node.call(this); this.table = table; + if (table) this.sql = table.sql; }, select: function() { var select; diff --git a/lib/node/select.js b/lib/node/select.js index 847e1a74..db3f3230 100644 --- a/lib/node/select.js +++ b/lib/node/select.js @@ -3,5 +3,11 @@ var Node = require(__dirname); module.exports = Node.define({ - type: 'SELECT' + type: 'SELECT', + constructor: function(arg) { + Node.call(this); + if (arg && arg.sql) { + this.sql = arg.sql; + } + } }); diff --git a/lib/table.js b/lib/table.js index 5c6a0991..bbc85df3 100644 --- a/lib/table.js +++ b/lib/table.js @@ -15,11 +15,12 @@ var Table = function(config) { this._initialConfig = config; this.columns = []; this.table = this; + if (!config.sql) config.sql = require('./index') + this.sql = config.sql; }; Table.define = function(config) { var table = new Table(config); - // allow hash of columns as well as array if(config.columns && !util.isArray(config.columns)) { var cols = []; diff --git a/test/npm-debug.log b/test/npm-debug.log new file mode 100644 index 00000000..63c88f85 --- /dev/null +++ b/test/npm-debug.log @@ -0,0 +1,21 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/home/spion/.nvm/v0.10.10/bin/node', +1 verbose cli '/home/spion/.nvm/v0.10.10/bin/npm', +1 verbose cli 'test' ] +2 info using npm@1.2.25 +3 info using node@v0.10.10 +4 verbose read json /home/spion/Documents/node-sql/test/package.json +5 error Error: ENOENT, open '/home/spion/Documents/node-sql/test/package.json' +6 error If you need help, you may report this log at: +6 error +6 error or email it to: +6 error +7 error System Linux 3.8.0-22-generic +8 error command "/home/spion/.nvm/v0.10.10/bin/node" "/home/spion/.nvm/v0.10.10/bin/npm" "test" +9 error cwd /home/spion/Documents/node-sql/test +10 error node -v v0.10.10 +11 error npm -v 1.2.25 +12 error path /home/spion/Documents/node-sql/test/package.json +13 error code ENOENT +14 error errno 34 +15 verbose exit [ 34, true ] diff --git a/test/select-tests.js b/test/select-tests.js index 836098eb..af8db6d2 100644 --- a/test/select-tests.js +++ b/test/select-tests.js @@ -4,7 +4,8 @@ var assert = require('assert'); var Select = require(__dirname + '/../lib/node/select'); -var select = new Select(); +var select = new Select({sql: require('../lib/index')}); + test('has SELECT type', function() { assert.equal(select.type, 'SELECT'); }); From bf83963dd0c2cee467778602fd24d9d99fec409b Mon Sep 17 00:00:00 2001 From: Gorgi Kosev Date: Sat, 8 Jun 2013 13:18:39 +0200 Subject: [PATCH 149/507] fix Table.define, add test, remove npm-debug.log --- lib/index.js | 1 + test/index-tests.js | 13 +++++++++++++ test/npm-debug.log | 21 --------------------- 3 files changed, 14 insertions(+), 21 deletions(-) delete mode 100644 test/npm-debug.log diff --git a/lib/index.js b/lib/index.js index 40cf4d2e..5d61b6e2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -6,6 +6,7 @@ function create(dialect) { var sql = { Table: Table, define: function(def) { + if (!def.sql) def.sql = this; return Table.define(def, this); }, select: function() { diff --git a/test/index-tests.js b/test/index-tests.js index ffed77f1..3a595789 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -39,4 +39,17 @@ suite('index', function() { }); + test('sql.define for parallel dialects work independently', function() { + var mysql = sql.create('mysql'); + var postgres = sql.create('postgres'); + + var mysqlTable = mysql.define({name: 'table', columns: ['column']}); + var postgresTable = postgres.define({name: 'table', columns: ['column']}); + + assert.equal(mysqlTable.sql, mysql); + assert.equal(postgresTable.sql, postgres); + }); + + + }); diff --git a/test/npm-debug.log b/test/npm-debug.log deleted file mode 100644 index 63c88f85..00000000 --- a/test/npm-debug.log +++ /dev/null @@ -1,21 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/home/spion/.nvm/v0.10.10/bin/node', -1 verbose cli '/home/spion/.nvm/v0.10.10/bin/npm', -1 verbose cli 'test' ] -2 info using npm@1.2.25 -3 info using node@v0.10.10 -4 verbose read json /home/spion/Documents/node-sql/test/package.json -5 error Error: ENOENT, open '/home/spion/Documents/node-sql/test/package.json' -6 error If you need help, you may report this log at: -6 error -6 error or email it to: -6 error -7 error System Linux 3.8.0-22-generic -8 error command "/home/spion/.nvm/v0.10.10/bin/node" "/home/spion/.nvm/v0.10.10/bin/npm" "test" -9 error cwd /home/spion/Documents/node-sql/test -10 error node -v v0.10.10 -11 error npm -v 1.2.25 -12 error path /home/spion/Documents/node-sql/test/package.json -13 error code ENOENT -14 error errno 34 -15 verbose exit [ 34, true ] From 7cdab7c779d1bcc5c9ec5eb21aae3db2e238339b Mon Sep 17 00:00:00 2001 From: bmc Date: Sat, 8 Jun 2013 12:07:34 -0500 Subject: [PATCH 150/507] Bump version --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 3e5c6fbf..0f205daa 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.20.0", + "version": "0.21.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", @@ -16,11 +16,11 @@ "node": "*" }, "dependencies": { - "sliced" : "0.0.5", - "lodash" : "~1.2.1" + "sliced": "0.0.5", + "lodash": "~1.2.1" }, "devDependencies": { - "jshint" : "*", - "mocha" : "*" + "jshint": "*", + "mocha": "*" } } From 163180f45832adbfc80c01809f82cc64160cbde0 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 9 Jun 2013 15:34:53 -0700 Subject: [PATCH 151/507] Refactor Sql into a class, same api as before --- lib/index.js | 86 ++++++++++++++++++++++++++------------------- lib/node/index.js | 3 +- lib/table.js | 2 +- test/index-tests.js | 16 +++++++-- 4 files changed, 66 insertions(+), 41 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5d61b6e2..30f6d164 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,41 +1,55 @@ 'use strict'; +var _ = require('lodash'); +var Query = require(__dirname + '/node/query'); var Table = require(__dirname + '/table'); -function create(dialect) { - var sql = { - Table: Table, - define: function(def) { - if (!def.sql) def.sql = this; - return Table.define(def, this); - }, - select: function() { - var Query = require(__dirname + '/node/query'); - var query = new Query({sql: this}); - query.select.apply(query, arguments); - return query; - }, - setDialect: function(dialect) { - switch(dialect.toLowerCase()) { - case 'postgres': - this.dialect = require(__dirname + '/dialect/postgres'); - break; - case 'mysql': - this.dialect = require(__dirname + '/dialect/mysql'); - break; - case 'sqlite': - this.dialect = require(__dirname + '/dialect/sqlite'); - break; - default: - throw new Error(dialect + ' is unsupported'); - } - return this; - } - }; - if (dialect) sql.setDialect(dialect); - return sql; -} - - -module.exports = create('postgres'); +// default dialect is postgres +var DEFAULT_DIALECT = 'postgres'; + +var Sql = function(dialect) { + dialect = dialect || DEFAULT_DIALECT; + + this.setDialect(dialect); +}; + +Sql.prototype.define = function(def) { + def = _.defaults(def || {}, { + sql: this + }); + + return Table.define(def); +}; + +Sql.prototype.select = function() { + var query = new Query({sql: this}); + query.select.apply(query, arguments); + return query; +}; + +Sql.prototype.setDialect = function(dialect) { + switch(dialect.toLowerCase()) { + case 'postgres': + this.dialect = require(__dirname + '/dialect/postgres'); + break; + case 'mysql': + this.dialect = require(__dirname + '/dialect/mysql'); + break; + case 'sqlite': + this.dialect = require(__dirname + '/dialect/sqlite'); + break; + default: + throw new Error(dialect + ' is unsupported'); + } + return this; +}; + +// back compat shim for the Sql class constructor +var create = function(dialect) { + return new Sql(dialect); +}; + +module.exports = new Sql('postgres'); 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 e2f0420e..50b8b79d 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -20,8 +20,9 @@ Node.prototype.add = function(node) { Node.prototype.toQuery = function() { var sql = this.sql || (this.table && this.table.sql); + var Dialect; if (sql && sql.dialect) - var Dialect = sql.dialect; + Dialect = sql.dialect; else { throw new Error("sql dialect not set properly"); } diff --git a/lib/table.js b/lib/table.js index bbc85df3..9bf84ab7 100644 --- a/lib/table.js +++ b/lib/table.js @@ -15,7 +15,7 @@ var Table = function(config) { this._initialConfig = config; this.columns = []; this.table = this; - if (!config.sql) config.sql = require('./index') + if (!config.sql) config.sql = require('./index'); this.sql = config.sql; }; diff --git a/test/index-tests.js b/test/index-tests.js index 3a595789..175031ee 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -16,7 +16,6 @@ suite('index', function() { }); }); - test('throws before dialect is set', function() { assert.throws(function() { var query = sql.select(user.id).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); @@ -30,10 +29,9 @@ suite('index', function() { assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); }); - 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(); + 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'); @@ -42,14 +40,26 @@ suite('index', function() { test('sql.define for parallel dialects work independently', function() { var mysql = sql.create('mysql'); var postgres = sql.create('postgres'); + var sqlite = sql.create('sqlite'); var mysqlTable = mysql.define({name: 'table', columns: ['column']}); var postgresTable = postgres.define({name: 'table', columns: ['column']}); + var sqliteTable = sqlite.define({name: 'table', columns: ['column']}); assert.equal(mysqlTable.sql, mysql); assert.equal(postgresTable.sql, postgres); + assert.equal(sqliteTable.sql, sqlite); }); + test('using Sql as a class', function() { + var Sql = sql.Sql; + var mysql = new Sql('mysql'); + var postgres = new Sql('postgres'); + var sqlite = new Sql('sqlite'); + 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')); + }); }); From 8cba3ac7bc22ba94c22a6c8b3c15ccd66000e341 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 10 Jun 2013 14:08:09 -0700 Subject: [PATCH 152/507] fix up comment in unary, fix up delete-tests --- lib/node/unary.js | 5 ++--- test/dialects/delete-tests.js | 8 ++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/node/unary.js b/lib/node/unary.js index 8b2ff9f0..0be3fbd6 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -11,10 +11,9 @@ var UnaryNode = module.exports = Node.define({ Node.call(this); this.left = config.left; this.operator = config.operator; + // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. - // There is circular dependency between unary, binary and value - // expression mixin, thus this must be delayed to runtime. + // mixin only once. ValueExpressionMixin has circular dependencies. if (!valueExpressionMixed) { valueExpressionMixed = true; _.extend(UnaryNode.prototype, valueExpressionMixin()); diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 663cd8cc..42653d77 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -4,7 +4,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post['delete']().where(post.content.equals('')), + query : post.delete().where(post.content.equals('')), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', @@ -12,7 +12,7 @@ Harness.test({ }); Harness.test({ - query : post['delete']().where({content: ''}), + query : post.delete().where({content: ''}), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', @@ -20,7 +20,7 @@ Harness.test({ }); Harness.test({ - query : post['delete']({content: ''}), + query : post.delete({content: ''}), pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', @@ -28,7 +28,7 @@ Harness.test({ }); Harness.test({ - query : post['delete']({content: ''}).or(post.content.isNull()), + query : post.delete({content: ''}).or(post.content.isNull()), pg : 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', sqlite: 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', mysql : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', From 70053bcd0f81d12edf23d6dd3908c62105bde66d Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 10 Jun 2013 14:07:52 -0700 Subject: [PATCH 153/507] Adding having clause and tests --- lib/dialect/postgres.js | 6 ++++ lib/node/having.js | 7 +++++ lib/node/query.js | 57 ++++++++++++++++++++--------------- test/dialects/having-tests.js | 28 +++++++++++++++++ 4 files changed, 74 insertions(+), 24 deletions(-) create mode 100644 lib/node/having.js create mode 100644 test/dialects/having-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 75c426b9..abe7c573 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -39,6 +39,7 @@ Postgres.prototype.visit = function(node) { case 'ORDER BY' : return this.visitOrderBy(node); case 'ORDER BY COLUMN' : return this.visitOrderByColumn(node); case 'GROUP BY' : return this.visitGroupBy(node); + case 'HAVING' : return this.visitHaving(node); case 'RETURNING' : return this.visitReturning(node); case 'TABLE' : return this.visitTable(node); case 'COLUMN' : return this.visitColumn(node); @@ -204,6 +205,11 @@ Postgres.prototype.visitGroupBy = function(groupBy) { return result; }; +Postgres.prototype.visitHaving = function(having) { + var result = ['HAVING', having.nodes.map(this.visit.bind(this)).join(' AND ')]; + return result; +}; + Postgres.prototype.visitUnary = function(unary) { var text = '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; return [text]; diff --git a/lib/node/having.js b/lib/node/having.js new file mode 100644 index 00000000..7dcf3434 --- /dev/null +++ b/lib/node/having.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'HAVING' +}); diff --git a/lib/node/query.js b/lib/node/query.js index 6b1964e3..43d9ac22 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -5,30 +5,31 @@ var util = require('util'); var sliced = require('sliced'); -var Node = require(__dirname); -var Select = require(__dirname + '/select'); -var From = require(__dirname + '/from'); -var Where = require(__dirname + '/where'); -var OrderBy = require(__dirname + '/orderBy'); -var GroupBy = require(__dirname + '/groupBy'); -var Insert = require(__dirname + '/insert'); -var Update = require(__dirname + '/update'); -var Delete = require(__dirname + '/delete'); -var Returning = require(__dirname + '/returning'); -var Create = require(__dirname + '/create'); -var Drop = require(__dirname + '/drop'); -var Alter = require(__dirname + '/alter'); -var AddColumn = require(__dirname + '/addColumn'); -var DropColumn = require(__dirname + '/dropColumn'); -var RenameColumn = require(__dirname + '/renameColumn'); -var Rename = require(__dirname + '/rename'); -var Column = require(__dirname + '/../column'); +var Node = require(__dirname); +var Select = require(__dirname + '/select'); +var From = require(__dirname + '/from'); +var Where = require(__dirname + '/where'); +var OrderBy = require(__dirname + '/orderBy'); +var GroupBy = require(__dirname + '/groupBy'); +var Having = require(__dirname + '/having'); +var Insert = require(__dirname + '/insert'); +var Update = require(__dirname + '/update'); +var Delete = require(__dirname + '/delete'); +var Returning = require(__dirname + '/returning'); +var Create = require(__dirname + '/create'); +var Drop = require(__dirname + '/drop'); +var Alter = require(__dirname + '/alter'); +var AddColumn = require(__dirname + '/addColumn'); +var DropColumn = require(__dirname + '/dropColumn'); +var RenameColumn = require(__dirname + '/renameColumn'); +var Rename = require(__dirname + '/rename'); +var Column = require(__dirname + '/../column'); var ParameterNode = require(__dirname + '/parameter'); -var IfExists = require(__dirname + '/ifExists'); -var IfNotExists = require(__dirname + '/ifNotExists'); -var Indexes = require(__dirname + '/indexes'); -var CreateIndex = require(__dirname + '/createIndex'); -var DropIndex = require(__dirname + '/dropIndex'); +var IfExists = require(__dirname + '/ifExists'); +var IfNotExists = require(__dirname + '/ifNotExists'); +var Indexes = require(__dirname + '/indexes'); +var CreateIndex = require(__dirname + '/createIndex'); +var DropIndex = require(__dirname + '/dropIndex'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -119,6 +120,14 @@ var Query = Node.define({ var groupBy = new GroupBy().addAll(args); return this.add(groupBy); }, + having: function() { + var args = sliced(arguments); + if (util.isArray(args[0])) { + args = args[0]; + } + var having = new Having().addAll(args); + return this.add(having); + }, insert: function(o) { var self = this; @@ -155,7 +164,7 @@ var Query = Node.define({ }); return this.add(update); }, - 'delete': function(params) { + delete: function(params) { var result = this.add(new Delete()); if(params) { result = this.where(params); diff --git a/test/dialects/having-tests.js b/test/dialects/having-tests.js new file mode 100644 index 00000000..5d5ab1b7 --- /dev/null +++ b/test/dialects/having-tests.js @@ -0,0 +1,28 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); + +Harness.test({ + query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10)), + pg : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', + sqlite: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', + mysql : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?)', + params: [10] +}); + +Harness.test({ + query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10), post.userId.lt(100)), + pg : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + sqlite: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + mysql : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', + params: [10, 100] +}); + +Harness.test({ + query : post.select(post.userId, post.content.count()).group(post.userId).having([post.userId.gt(10), post.userId.lt(100)]), + pg : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + sqlite: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + mysql : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', + params: [10, 100] +}); From e7223f26d5b07a6e1f4c7a105a37da383b27eb0b Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Tue, 4 Jun 2013 18:05:11 -0700 Subject: [PATCH 154/507] Add sql.functionCall. Example: sql.select(sql.functionCall('concat', 'hello', 'world')) --- lib/dialect/postgres.js | 8 ++++++- lib/functions.js | 51 ++++++++++++++++++++++++++++++++++++++++ lib/index.js | 15 ++++++++++++ lib/node/functionCall.js | 15 ++++++++++++ test/index-tests.js | 18 ++++++++++++++ 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 lib/functions.js create mode 100644 lib/node/functionCall.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index abe7c573..670adab7 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -15,7 +15,7 @@ Postgres.prototype._arrayAggFunctionName = 'array_agg'; Postgres.prototype.getQuery = function(queryNode) { // passed in a table, not a query - if(queryNode instanceof Table) { + if (queryNode instanceof Table) { queryNode = queryNode.select(queryNode.star()); } this.output = this.visit(queryNode); @@ -56,6 +56,7 @@ Postgres.prototype.visit = function(node) { case 'INDEXES' : return this.visitIndexes(node); case 'CREATE INDEX' : return this.visitCreateIndex(node); case 'DROP INDEX' : return this.visitDropIndex(node); + case 'FUNCTION CALL' : return this.visitFunctionCall(node); case 'UNARY' : return this.visitUnary(node); case 'BINARY' : return this.visitBinary(node); @@ -385,6 +386,11 @@ Postgres.prototype.visitColumn = function(columnNode) { return [txt]; }; +Postgres.prototype.visitFunctionCall = function(functionCall) { + var txt = functionCall.name + '(' + functionCall.nodes.map(this.visit.bind(this)).join(', ') + ')'; + return [txt]; +}; + Postgres.prototype.visitParameter = function(parameter) { this.params.push(parameter.value()); return "$"+this.params.length; diff --git a/lib/functions.js b/lib/functions.js new file mode 100644 index 00000000..974ba157 --- /dev/null +++ b/lib/functions.js @@ -0,0 +1,51 @@ +'use strict'; +var _ = require('lodash'); +var FunctionCall = require(__dirname + '/node/functionCall'); + +// aggregate functions available to all databases +var aggregateFunctions = [ + 'AVG', + 'COUNT', + 'MAX', + 'MIN', + 'SUM' +]; + +// common scalar functions available to most databases +var scalarFunctions = [ + 'ABS', + 'COALESC', + 'LENGTH', + 'LOWER', + 'LTRIM', + 'RANDOM', + 'ROUND', + 'RTRIM', + 'SUBSTR', + 'TRIM', + 'UPPER' +]; + +var functionNames = aggregateFunctions.concat(scalarFunctions); + +// create a function that creates a function call of the specific name, using the specified sql instance +var createFunctionCall = function(name, sql) { + return function() { + // turn array-like arguments object into a true array + var args = Array.prototype.slice.call(arguments, 0); + var functionCall = new FunctionCall(name, args); + functionCall.sql = sql; + return functionCall; + }; +}; + +// creates a hash of the standard functions for a sql instance +var getFunctions = function(sql) { + var functions = _.reduce(functionNames, function(reducer, name) { + reducer[name] = createFunctionCall(name, sql); + return reducer; + }, {}); + return functions; +}; + +module.exports.getFunctions = getFunctions; diff --git a/lib/index.js b/lib/index.js index 30f6d164..f0f62a44 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,8 @@ 'use strict'; var _ = require('lodash'); +var FunctionCall = require(__dirname + '/node/functionCall'); +var functions = require(__dirname + '/functions'); var Query = require(__dirname + '/node/query'); var Table = require(__dirname + '/table'); @@ -11,8 +13,12 @@ var Sql = function(dialect) { dialect = dialect || DEFAULT_DIALECT; this.setDialect(dialect); + + // attach the standard functions to this instance + this.functions = functions.getFunctions(this); }; +// Define a table Sql.prototype.define = function(def) { def = _.defaults(def || {}, { sql: this @@ -21,12 +27,21 @@ Sql.prototype.define = function(def) { return Table.define(def); }; +// Define a function call +Sql.prototype.functionCall = function() { + var functionCall = new FunctionCall(_.head(arguments), _.rest(arguments)); + functionCall.sql = this; + return functionCall; +}; + +// Define a select statement Sql.prototype.select = function() { var query = new Query({sql: this}); query.select.apply(query, arguments); return query; }; +// Set the dialect Sql.prototype.setDialect = function(dialect) { switch(dialect.toLowerCase()) { case 'postgres': diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js new file mode 100644 index 00000000..06d3e974 --- /dev/null +++ b/lib/node/functionCall.js @@ -0,0 +1,15 @@ +'use strict'; + +var Node = require(__dirname); +var ParameterNode = require(__dirname + '/parameter'); + +module.exports = Node.define({ + type: 'FUNCTION CALL', + constructor: function(name, args) { + Node.call(this); + this.name = name; + this.addAll(args.map(function (v) { + return v.toNode ? v.toNode() : new ParameterNode(v); + })); + }, +}); diff --git a/test/index-tests.js b/test/index-tests.js index 175031ee..65700f62 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -62,4 +62,22 @@ suite('index', function() { assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); }); + test('creating function call works', function() { + var functionCall = sql.functionCall('CONCAT', 'hello', 'world').toQuery(); + assert.equal(functionCall.text, 'CONCAT($1, $2)'); + assert.equal(functionCall.values[0], 'hello'); + assert.equal(functionCall.values[1], 'world'); + }); + + test('creating function call on columns works', function() { + var functionCall = sql.functionCall('CONCAT', user.id, user.email).toQuery(); + assert.equal(functionCall.text, 'CONCAT("user"."id", "user"."email")'); + assert.equal(functionCall.values.length, 0); + }); + + test('function call inside select works', function() { + var functionCall = sql.select(sql.functionCall('CONCAT', user.id, user.email)).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); + assert.equal(functionCall.text, 'SELECT CONCAT("user"."id", "user"."email") FROM "user" WHERE ("user"."email" = $1)'); + assert.equal(functionCall.values[0], 'brian.m.carlson@gmail.com'); + }); }); From ebf53a16daa76416c2e3b2e81946ce4c5a6d9f53 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 4 Jun 2013 19:49:43 -0700 Subject: [PATCH 155/507] Adding in shortcut for standard functions, next step is to figure out how to load dialect specific functions --- lib/functions.js | 46 +++++++++-------- lib/index.js | 20 +++++--- lib/node/functionCall.js | 13 +++-- lib/node/valueExpression.js | 7 ++- test/binary-clause-tests.js | 4 +- test/dialects/binary-clause-tests.js | 6 +-- test/dialects/value-expression-tests.js | 8 +-- test/function-tests.js | 68 +++++++++++++++++++++++++ test/index-tests.js | 19 ------- test/value-expression-tests.js | 17 +++++++ 10 files changed, 145 insertions(+), 63 deletions(-) create mode 100644 test/function-tests.js create mode 100644 test/value-expression-tests.js diff --git a/lib/functions.js b/lib/functions.js index 974ba157..503980df 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -1,11 +1,32 @@ 'use strict'; var _ = require('lodash'); +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) { + return function() { + // turn array-like arguments object into a true array + var functionCall = new FunctionCall(name, sliced(arguments)); + functionCall.sql = sql; + return functionCall; + }; +}; + +// creates a hash of functions for a sql instance +var getFunctions = function(functionNames, sql) { + var functions = _.reduce(functionNames, function(reducer, name) { + reducer[name] = getFunctionCallCreator(name, sql); + return reducer; + }, {}); + return functions; +}; + // aggregate functions available to all databases var aggregateFunctions = [ 'AVG', 'COUNT', + 'DISTINCT', 'MAX', 'MIN', 'SUM' @@ -26,26 +47,11 @@ var scalarFunctions = [ 'UPPER' ]; -var functionNames = aggregateFunctions.concat(scalarFunctions); +var standardFunctionNames = aggregateFunctions.concat(scalarFunctions); -// create a function that creates a function call of the specific name, using the specified sql instance -var createFunctionCall = function(name, sql) { - return function() { - // turn array-like arguments object into a true array - var args = Array.prototype.slice.call(arguments, 0); - var functionCall = new FunctionCall(name, args); - functionCall.sql = sql; - return functionCall; - }; -}; - -// creates a hash of the standard functions for a sql instance -var getFunctions = function(sql) { - var functions = _.reduce(functionNames, function(reducer, name) { - reducer[name] = createFunctionCall(name, sql); - return reducer; - }, {}); - return functions; +// creates a hash of standard functions for a sql instance +var getStandardFunctions = function(sql) { + return getFunctions(standardFunctionNames, sql); }; -module.exports.getFunctions = getFunctions; +module.exports.getStandardFunctions = getStandardFunctions; diff --git a/lib/index.js b/lib/index.js index f0f62a44..6fac17f6 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,7 @@ 'use strict'; var _ = require('lodash'); +var sliced = require('sliced'); var FunctionCall = require(__dirname + '/node/functionCall'); var functions = require(__dirname + '/functions'); var Query = require(__dirname + '/node/query'); @@ -14,8 +15,8 @@ var Sql = function(dialect) { this.setDialect(dialect); - // attach the standard functions to this instance - this.functions = functions.getFunctions(this); + // attach the standard SQL functions to this instance + this.functions = functions.getStandardFunctions(this); }; // Define a table @@ -27,14 +28,17 @@ Sql.prototype.define = function(def) { return Table.define(def); }; -// Define a function call -Sql.prototype.functionCall = function() { - var functionCall = new FunctionCall(_.head(arguments), _.rest(arguments)); - functionCall.sql = this; - return functionCall; +// 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; + }; }; -// Define a select statement +// Returns a select statement Sql.prototype.select = function() { var query = new Query({sql: this}); query.select.apply(query, arguments); diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js index 06d3e974..24e3293a 100644 --- a/lib/node/functionCall.js +++ b/lib/node/functionCall.js @@ -1,15 +1,22 @@ 'use strict'; +var _ = require('lodash'); var Node = require(__dirname); var ParameterNode = require(__dirname + '/parameter'); +var valueExpressionMixin = require(__dirname + '/valueExpression'); -module.exports = Node.define({ +var FunctionCallNode = Node.define({ type: 'FUNCTION CALL', constructor: function(name, args) { Node.call(this); this.name = name; this.addAll(args.map(function (v) { - return v.toNode ? v.toNode() : new ParameterNode(v); + return v.toNode ? v.toNode() : new ParameterNode(v); })); - }, + } }); + +// mix in value expression +_.extend(FunctionCallNode.prototype, valueExpressionMixin()); + +module.exports = FunctionCallNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 8a76a55e..ba44e35c 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -13,8 +13,7 @@ var processParams = function(val) { }; // Value expressions can be composed to form new value expressions. -// Value expressions include binary expressions and unary expressions -// so far. ValueExpressionMixin is evaluated at runtime, hence the +// ValueExpressionMixin is evaluated at runtime, hence the // "thunk" around it. var ValueExpressionMixin = module.exports = function() { var BinaryNode = require(__dirname + '/binary'); @@ -66,8 +65,8 @@ var ValueExpressionMixin = module.exports = function() { gte : binaryMethod('>='), lt : binaryMethod('<'), lte : binaryMethod('<='), - add : binaryMethod('+'), - subtract : binaryMethod('-'), + plus : binaryMethod('+'), + minus : binaryMethod('-'), multiply : binaryMethod('*'), divide : binaryMethod('/'), modulo : binaryMethod('%'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 0b218bd0..3174b214 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -22,8 +22,8 @@ test('operators', function() { assert.equal(Foo.baz.gte(1).operator, '>='); assert.equal(Foo.baz.lt(1).operator, '<'); assert.equal(Foo.baz.lte(1).operator, '<='); - assert.equal(Foo.baz.add(1).operator, '+'); - assert.equal(Foo.baz.subtract(1).operator, '-'); + assert.equal(Foo.baz.plus(1).operator, '+'); + assert.equal(Foo.baz.minus(1).operator, '-'); assert.equal(Foo.baz.multiply(1).operator, '*'); assert.equal(Foo.baz.divide(1).operator, '/'); assert.equal(Foo.baz.modulo(1).operator, '%'); diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index eac93f0a..4b59721f 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -6,7 +6,7 @@ var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); Harness.test({ - query : customer.select(customer.name.add(customer.age)), + query : customer.select(customer.name.plus(customer.age)), pg : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', sqlite: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', mysql : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', @@ -14,7 +14,7 @@ Harness.test({ }); Harness.test({ - query : post.select(post.content.add('!')).where(post.userId.in(customer.subQuery().select(customer.id))), + query : post.select(post.content.plus('!')).where(post.userId.in(customer.subQuery().select(customer.id))), pg : 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', sqlite: 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', mysql : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', @@ -22,7 +22,7 @@ Harness.test({ }); Harness.test({ - query : post.select(post.id.add(': ').add(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), + query : post.select(post.id.plus(': ').plus(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), pg : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', sqlite : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', mysql : 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 8dd14e72..8db4504a 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -6,7 +6,7 @@ var v = Harness.defineVariableTable(); // Test composition of binary methods +, *, -, =. Harness.test({ - query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.add(5).multiply(customer.age.subtract(2)).equals(10)), + query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.plus(5).multiply(customer.age.minus(2)).equals(10)), pg : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', sqlite: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', mysql : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', @@ -15,7 +15,7 @@ Harness.test({ // Test composition of binary (e.g. +) and unary (e.g. like) methods. Harness.test({ - query : customer.select(customer.name).where(customer.name.like(customer.id.add('hello'))), + query : customer.select(customer.name).where(customer.name.like(customer.id.plus('hello'))), pg : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', sqlite: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', mysql : 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', @@ -25,7 +25,7 @@ Harness.test({ // Test implementing simple formulas. // Acceleration formula. (a * t^2 / 2) + (v * t) = d Harness.test({ - query : v.select(v.a.multiply(v.a).divide(2).add(v.v.multiply(v.t)).equals(v.d)), + query : v.select(v.a.multiply(v.a).divide(2).plus(v.v.multiply(v.t)).equals(v.d)), pg : 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', sqlite: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', mysql : 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', @@ -34,7 +34,7 @@ Harness.test({ // Pythagorean theorem. a^2 + b^2 = c^2. Harness.test({ - query : v.select(v.a.multiply(v.a).add(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), + query : v.select(v.a.multiply(v.a).plus(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), pg : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', sqlite: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', mysql : 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', diff --git a/test/function-tests.js b/test/function-tests.js new file mode 100644 index 00000000..d9805770 --- /dev/null +++ b/test/function-tests.js @@ -0,0 +1,68 @@ +/* global suite, test */ +'use strict'; +var assert = require('assert'); + +var sql = require(__dirname + '/../lib').setDialect('postgres'); + +var user = sql.define({ + name: 'user', + columns: ['id', 'email', 'name'] +}); + +suite('function', function() { + test('creating function call works', function() { + var upper = sql.functionCallCreator('UPPER'); + var functionCall = upper('hello', 'world').toQuery(); + + assert.equal(functionCall.text, 'UPPER($1, $2)'); + assert.equal(functionCall.values[0], 'hello'); + assert.equal(functionCall.values[1], 'world'); + }); + + test('creating function call on columns works', function() { + var upper = sql.functionCallCreator('UPPER'); + var functionCall = upper(user.id, user.email).toQuery(); + + assert.equal(functionCall.text, 'UPPER("user"."id", "user"."email")'); + assert.equal(functionCall.values.length, 0); + }); + + test('function call inside select works', function() { + var upper = sql.functionCallCreator('UPPER'); + var query = sql.select(upper(user.id, user.email)).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); + + assert.equal(query.text, 'SELECT UPPER("user"."id", "user"."email") FROM "user" WHERE ("user"."email" = $1)'); + assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); + }); + + test('standard aggregate functions with having clause', function() { + var count = sql.functions.COUNT; + var distinct = sql.functions.DISTINCT; + var distinctEmailCount = count(distinct(user.email)); + + var query = user.select(user.id, distinctEmailCount).group(user.id).having(distinctEmailCount.gt(100)).toQuery(); + + assert.equal(query.text, 'SELECT "user"."id", COUNT(DISTINCT("user"."email")) FROM "user" GROUP BY "user"."id" HAVING (COUNT(DISTINCT("user"."email")) > $1)'); + assert.equal(query.values[0], 100); + }); + + test('custom and standard functions behave the same', function() { + var standardUpper = sql.functions.UPPER; + var customUpper = sql.functionCallCreator('UPPER'); + + var standardQuery = user.select(standardUpper(user.name)).toQuery(); + var customQuery = user.select(customUpper(user.name)).toQuery(); + + var expectedQuery = 'SELECT UPPER("user"."name") FROM "user"'; + assert.equal(standardQuery.text, expectedQuery); + assert.equal(customQuery.text, expectedQuery); + }); + + test('combine function with operations', function() { + var f = sql.functions; + var query = user.select(f.AVG(f.DISTINCT(f.COUNT(user.id).plus(f.MAX(user.id))).minus(f.MIN(user.id))).multiply(100)).toQuery(); + + 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); + }); +}); diff --git a/test/index-tests.js b/test/index-tests.js index 65700f62..aa0237bd 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -61,23 +61,4 @@ suite('index', function() { assert.equal(postgres.dialect, require(__dirname + '/../lib/dialect/postgres')); assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); }); - - test('creating function call works', function() { - var functionCall = sql.functionCall('CONCAT', 'hello', 'world').toQuery(); - assert.equal(functionCall.text, 'CONCAT($1, $2)'); - assert.equal(functionCall.values[0], 'hello'); - assert.equal(functionCall.values[1], 'world'); - }); - - test('creating function call on columns works', function() { - var functionCall = sql.functionCall('CONCAT', user.id, user.email).toQuery(); - assert.equal(functionCall.text, 'CONCAT("user"."id", "user"."email")'); - assert.equal(functionCall.values.length, 0); - }); - - test('function call inside select works', function() { - var functionCall = sql.select(sql.functionCall('CONCAT', user.id, user.email)).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - assert.equal(functionCall.text, 'SELECT CONCAT("user"."id", "user"."email") FROM "user" WHERE ("user"."email" = $1)'); - assert.equal(functionCall.values[0], 'brian.m.carlson@gmail.com'); - }); }); diff --git a/test/value-expression-tests.js b/test/value-expression-tests.js new file mode 100644 index 00000000..4ef2b7e0 --- /dev/null +++ b/test/value-expression-tests.js @@ -0,0 +1,17 @@ +/* global suite, test */ +'use strict'; + +var assert = require('assert'); +var valueExpressionMixin = require(__dirname + './../lib/node/valueExpression'); +var Node = require(__dirname + './../lib/node'); + +suite('value-expression', function() { + test("value expression mixin should not overwrite Node prototype properties", function() { + var mixin = valueExpressionMixin(); + + // make sure that the node class doesn't have any conflicting properties + for (var key in mixin) { + assert.equal(Node.prototype[key], undefined); + } + }); +}); From 1746dc47e730a600fdb4ebdfc8f19b011b26d54a Mon Sep 17 00:00:00 2001 From: bmc Date: Mon, 10 Jun 2013 23:21:04 -0500 Subject: [PATCH 156/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f205daa..a7dc5519 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.21.0", + "version": "0.22.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From b688d030d867a17f598509804cf292a38caad9a2 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 10 Jun 2013 19:43:53 -0700 Subject: [PATCH 157/507] Alias Node, add alias behavior to unary, binary, ternary and function calls, with tests --- lib/dialect/postgres.js | 6 ++++++ lib/node/alias.js | 29 +++++++++++++++++++++++++++++ lib/node/binary.js | 4 ++++ lib/node/functionCall.js | 4 ++++ lib/node/ternary.js | 4 ++++ lib/node/unary.js | 8 +++++++- lib/node/valueExpression.js | 4 ++-- test/dialects/alias-tests.js | 30 ++++++++++++++++++++++++++++++ test/function-tests.js | 7 +++++++ 9 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 lib/node/alias.js create mode 100644 test/dialects/alias-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 670adab7..bff3e032 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -33,6 +33,7 @@ Postgres.prototype.visit = function(node) { case 'DELETE' : return this.visitDelete(); case 'CREATE' : return this.visitCreate(node); case 'DROP' : return this.visitDrop(node); + case 'ALIAS' : return this.visitAlias(node); case 'ALTER' : return this.visitAlter(node); case 'FROM' : return this.visitFrom(node); case 'WHERE' : return this.visitWhere(node); @@ -155,6 +156,11 @@ Postgres.prototype.visitDrop = function(drop) { return result; }; +Postgres.prototype.visitAlias = function(alias) { + var result = [this.visit(alias.value) + ' AS ' + this.quote(alias.alias)]; + return result; +}; + Postgres.prototype.visitAlter = function(alter) { this._visitingAlter = true; // don't auto-generate from clause diff --git a/lib/node/alias.js b/lib/node/alias.js new file mode 100644 index 00000000..78f01323 --- /dev/null +++ b/lib/node/alias.js @@ -0,0 +1,29 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); + +var AliasNode = Node.define({ + type: 'ALIAS', + constructor: function(value, alias) { + Node.call(this); + + this.value = value; + this.alias = alias; + } +}); + +var AliasMixin = { + as: function(alias) { + // create an alias node + var aliasNode = new AliasNode(this, alias); + + // defaults the properties of the aliased node + _.defaults(aliasNode, this); + + return aliasNode; + } +}; + +module.exports = AliasNode; +module.exports.AliasMixin = AliasMixin; diff --git a/lib/node/binary.js b/lib/node/binary.js index 341b8037..7b721650 100644 --- a/lib/node/binary.js +++ b/lib/node/binary.js @@ -22,4 +22,8 @@ var BinaryNode = Node.define(_.extend({ }, })); +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(BinaryNode.prototype, AliasNode.AliasMixin); + module.exports = BinaryNode; diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js index 24e3293a..3014d931 100644 --- a/lib/node/functionCall.js +++ b/lib/node/functionCall.js @@ -19,4 +19,8 @@ var FunctionCallNode = Node.define({ // mix in value expression _.extend(FunctionCallNode.prototype, valueExpressionMixin()); +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(FunctionCallNode.prototype, AliasNode.AliasMixin); + module.exports = FunctionCallNode; diff --git a/lib/node/ternary.js b/lib/node/ternary.js index 2a93c23c..1ef5ce7b 100644 --- a/lib/node/ternary.js +++ b/lib/node/ternary.js @@ -24,4 +24,8 @@ var TernaryNode = Node.define(_.extend({ }, })); +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(TernaryNode.prototype, AliasNode.AliasMixin); + module.exports = TernaryNode; diff --git a/lib/node/unary.js b/lib/node/unary.js index 0be3fbd6..de503795 100644 --- a/lib/node/unary.js +++ b/lib/node/unary.js @@ -5,7 +5,7 @@ var Node = require(__dirname); var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; -var UnaryNode = module.exports = Node.define({ +var UnaryNode = Node.define({ type: 'UNARY', constructor: function(config) { Node.call(this); @@ -20,3 +20,9 @@ var UnaryNode = module.exports = Node.define({ } } }); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(UnaryNode.prototype, AliasNode.AliasMixin); + +module.exports = UnaryNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index ba44e35c..86b4bc9f 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -1,7 +1,7 @@ 'use strict'; -var _ = require('lodash'); -var Node = require(__dirname); +var _ = require('lodash'); +var Node = require(__dirname); var ParameterNode = require(__dirname + '/parameter'); // Process values, wrapping them in ParameterNode if necessary. diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js new file mode 100644 index 00000000..8b89c6b2 --- /dev/null +++ b/test/dialects/alias-tests.js @@ -0,0 +1,30 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var post = Harness.definePostTable(); +var Table = require(__dirname + '/../../lib/table'); + +Harness.test({ + query : customer.select(customer.name.isNull().as('nameIsNull')), + pg : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + sqlite : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + mysql : 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', + params : [] +}); + +Harness.test({ + query : customer.select(customer.name.plus(customer.age).as('nameAndAge')).where(customer.age.gt(10).and(customer.age.lt(20))), + pg : 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', + sqlite : 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', + mysql : 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > ?) AND (`customer`.`age` < ?))', + params : [10, 20] +}); + +Harness.test({ + query : customer.select(customer.age.between(10, 20).as('ageBetween')), + pg : 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', + sqlite : 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', + mysql : 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', + params : [10, 20] +}); diff --git a/test/function-tests.js b/test/function-tests.js index d9805770..3cac3a9b 100644 --- a/test/function-tests.js +++ b/test/function-tests.js @@ -10,6 +10,13 @@ var user = sql.define({ }); suite('function', function() { + test('alias function call', function() { + var upper = sql.functions.UPPER; + var aliasedUpper = upper(user.email).as('upperAlias').toQuery(); + + assert.equal(aliasedUpper.text, 'UPPER("user"."email") AS "upperAlias"'); + }); + test('creating function call works', function() { var upper = sql.functionCallCreator('UPPER'); var functionCall = upper('hello', 'world').toQuery(); From d31c6b3a97d72ddcfab705b52db07f9b20da87f2 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Wed, 12 Jun 2013 22:28:10 -0700 Subject: [PATCH 158/507] Column doesn't need to use delayed runtime valueExpressionMixin --- lib/column.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/column.js b/lib/column.js index 888b3ef9..d3403a50 100644 --- a/lib/column.js +++ b/lib/column.js @@ -7,7 +7,6 @@ var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); var UnaryNode = require(__dirname + '/node/unary'); var TextNode = require(__dirname + '/node/text'); -var valueExpressionMixed = false; var Column = function(config) { this.table = config.table; for(var name in config) { @@ -20,15 +19,11 @@ var Column = function(config) { direction: new TextNode('DESC') }); this.dataType = config.dataType; - // Delay mixin to runtime, when all nodes have been defined, and - // mixin only once. This is to avoid circular dependency in - // CommonJS. - if (!valueExpressionMixed) { - valueExpressionMixed = true; - _.extend(Column.prototype, valueExpressionMixin()); - } }; +// mix in value expression +_.extend(Column.prototype, valueExpressionMixin()); + var contextify = function(base) { var context = Object.create(Column.prototype); Object.keys(base).forEach(function (key) { From b8c67d504c29a2850a596cd52a2b19b63592a3e8 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Thu, 13 Jun 2013 16:38:46 -0500 Subject: [PATCH 159/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a7dc5519..b7d5c808 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.22.0", + "version": "0.23.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From d2dd4d929119bfea30fcc91341b8953ee45f0fa2 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Thu, 13 Jun 2013 15:13:05 -0700 Subject: [PATCH 160/507] add shift, unshift operations --- lib/dialect/postgres.js | 8 ++--- lib/node/functionCall.js | 6 ++-- lib/node/valueExpression.js | 72 +++++++++++++++++++------------------ 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index bff3e032..6aaf1015 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1,9 +1,9 @@ 'use strict'; -var assert = require('assert'); -var From = require(__dirname + '/../node/from'); -var Select = require(__dirname + '/../node/select'); -var Table = require(__dirname + '/../table'); +var assert = require('assert'); +var From = require(__dirname + '/../node/from'); +var Select = require(__dirname + '/../node/select'); +var Table = require(__dirname + '/../table'); var Postgres = function() { this.output = []; this.params = []; diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js index 3014d931..da8d8767 100644 --- a/lib/node/functionCall.js +++ b/lib/node/functionCall.js @@ -1,8 +1,8 @@ 'use strict'; -var _ = require('lodash'); -var Node = require(__dirname); -var ParameterNode = require(__dirname + '/parameter'); +var _ = require('lodash'); +var Node = require(__dirname); +var ParameterNode = require(__dirname + '/parameter'); var valueExpressionMixin = require(__dirname + '/valueExpression'); var FunctionCallNode = Node.define({ diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 86b4bc9f..10c479be 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -16,26 +16,26 @@ var processParams = function(val) { // ValueExpressionMixin is evaluated at runtime, hence the // "thunk" around it. var ValueExpressionMixin = module.exports = function() { - var BinaryNode = require(__dirname + '/binary'); + var UnaryNode = require(__dirname + '/unary'); + var BinaryNode = require(__dirname + '/binary'); var TernaryNode = require(__dirname + '/ternary'); - var UnaryNode = require(__dirname + '/unary'); - var binaryMethod = function(operator) { + var unaryMethod = function(operator) { + /*jshint unused: false */ return function(val) { - return new BinaryNode({ + return new UnaryNode({ left: this.toNode(), - operator: operator, - right: processParams(val) + operator: operator }); }; }; - var unaryMethod = function(operator) { - /*jshint unused: false */ + var binaryMethod = function(operator) { return function(val) { - return new UnaryNode({ + return new BinaryNode({ left: this.toNode(), - operator: operator + operator: operator, + right: processParams(val) }); }; }; @@ -44,36 +44,38 @@ var ValueExpressionMixin = module.exports = function() { return function(middle, right) { return new TernaryNode({ left: this.toNode(), - middle: processParams(middle), operator: operator, - right: processParams(right), - separator: separator + middle: processParams(middle), + separator: separator, + right: processParams(right) }); }; }; return { - isNull : unaryMethod('IS NULL'), - isNotNull: unaryMethod('IS NOT NULL'), - or : binaryMethod('OR'), - and : binaryMethod('AND'), - equals : binaryMethod('='), - equal : binaryMethod('='), - notEquals: binaryMethod('<>'), - notEqual : binaryMethod('<>'), - gt : binaryMethod('>'), - gte : binaryMethod('>='), - lt : binaryMethod('<'), - lte : binaryMethod('<='), - plus : binaryMethod('+'), - minus : binaryMethod('-'), - multiply : binaryMethod('*'), - divide : binaryMethod('/'), - modulo : binaryMethod('%'), - like : binaryMethod('LIKE'), - notLike : binaryMethod('NOT LIKE'), - in : binaryMethod('IN'), - notIn : binaryMethod('NOT IN'), - between : ternaryMethod('BETWEEN', 'AND') + isNull : unaryMethod('IS NULL'), + isNotNull : unaryMethod('IS NOT NULL'), + or : binaryMethod('OR'), + and : binaryMethod('AND'), + equals : binaryMethod('='), + equal : binaryMethod('='), + notEquals : binaryMethod('<>'), + notEqual : binaryMethod('<>'), + gt : binaryMethod('>'), + gte : binaryMethod('>='), + lt : binaryMethod('<'), + lte : binaryMethod('<='), + plus : binaryMethod('+'), + minus : binaryMethod('-'), + multiply : binaryMethod('*'), + divide : binaryMethod('/'), + modulo : binaryMethod('%'), + leftShift : binaryMethod('<<') + rightShift : binaryMethod('>>') + like : binaryMethod('LIKE'), + notLike : binaryMethod('NOT LIKE'), + in : binaryMethod('IN'), + notIn : binaryMethod('NOT IN'), + between : ternaryMethod('BETWEEN', 'AND') }; }; From c69b4852728ef39598c6398d5fec15d2c3ab75ef Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Fri, 14 Jun 2013 19:37:29 -0700 Subject: [PATCH 161/507] simple tests for left shift, right shift --- 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 3174b214..30607bcf 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -25,6 +25,8 @@ test('operators', function() { assert.equal(Foo.baz.plus(1).operator, '+'); assert.equal(Foo.baz.minus(1).operator, '-'); assert.equal(Foo.baz.multiply(1).operator, '*'); + assert.equal(Foo.baz.leftShift(1).operator, '<<'); + assert.equal(Foo.baz.rightShift(1).operator, '>>'); assert.equal(Foo.baz.divide(1).operator, '/'); assert.equal(Foo.baz.modulo(1).operator, '%'); }); From b7f0fd0fb9141ec813e0bc6fb43df86a1ee674d7 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Fri, 14 Jun 2013 19:39:31 -0700 Subject: [PATCH 162/507] commas for javascript --- lib/node/valueExpression.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 10c479be..66de6fea 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -70,8 +70,8 @@ var ValueExpressionMixin = module.exports = function() { multiply : binaryMethod('*'), divide : binaryMethod('/'), modulo : binaryMethod('%'), - leftShift : binaryMethod('<<') - rightShift : binaryMethod('>>') + leftShift : binaryMethod('<<'), + rightShift : binaryMethod('>>'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), From b55d30ecf764899c9f59a689d3cf340d65a9084e Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 14 Jun 2013 22:11:33 -0700 Subject: [PATCH 163/507] toQuery with dialect argument --- lib/dialect/index.js | 15 +++++++++++++++ lib/index.js | 29 +++++++++-------------------- lib/node/index.js | 23 +++++++++++++++++------ test/index-tests.js | 38 +++++++++++++++++++++++++++++++++----- 4 files changed, 74 insertions(+), 31 deletions(-) create mode 100644 lib/dialect/index.js diff --git a/lib/dialect/index.js b/lib/dialect/index.js new file mode 100644 index 00000000..e04a1b4e --- /dev/null +++ b/lib/dialect/index.js @@ -0,0 +1,15 @@ +// given a dialect name, return the class +var getDialect = function(dialect) { + switch (dialect.toLowerCase()) { + case 'postgres': + return require('./postgres'); + case 'mysql': + return require('./mysql'); + case 'sqlite': + return require('./sqlite'); + default: + throw new Error(dialect + ' is unsupported'); + } +}; + +module.exports = getDialect; diff --git a/lib/index.js b/lib/index.js index 6fac17f6..4ab93b01 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,12 @@ 'use strict'; -var _ = require('lodash'); -var sliced = require('sliced'); -var FunctionCall = require(__dirname + '/node/functionCall'); -var functions = require(__dirname + '/functions'); -var Query = require(__dirname + '/node/query'); -var Table = require(__dirname + '/table'); +var _ = require('lodash'); +var FunctionCall = require('./node/functionCall'); +var functions = require('./functions'); +var getDialect = require('./dialect'); +var Query = require('./node/query'); +var sliced = require('sliced'); +var Table = require('./table'); // default dialect is postgres var DEFAULT_DIALECT = 'postgres'; @@ -47,19 +48,7 @@ Sql.prototype.select = function() { // Set the dialect Sql.prototype.setDialect = function(dialect) { - switch(dialect.toLowerCase()) { - case 'postgres': - this.dialect = require(__dirname + '/dialect/postgres'); - break; - case 'mysql': - this.dialect = require(__dirname + '/dialect/mysql'); - break; - case 'sqlite': - this.dialect = require(__dirname + '/dialect/sqlite'); - break; - default: - throw new Error(dialect + ' is unsupported'); - } + this.dialect = getDialect(dialect); return this; }; @@ -68,7 +57,7 @@ var create = function(dialect) { return new Sql(dialect); }; -module.exports = new Sql('postgres'); +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 50b8b79d..b1f0d727 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,7 +1,9 @@ 'use strict'; -var util = require('util'); -var assert = require('assert'); +var _ = require('lodash'); +var assert = require('assert'); +var getDialect = require('../dialect'); +var util = require('util'); /* jshint unused: false */ var Node = function(type) { @@ -18,13 +20,22 @@ Node.prototype.add = function(node) { return this; }; -Node.prototype.toQuery = function() { +// Before the change that introduced parallel dialects, every node could be turned +// into a query. The parallel dialects change made it impossible to change some nodes +// into a query because not all nodes are constructed with the sql instance. +Node.prototype.toQuery = function(dialect) { var sql = this.sql || (this.table && this.table.sql); var Dialect; - if (sql && sql.dialect) + + if (dialect) { + // dialect is specified + Dialect = getDialect(dialect); + } else if (sql && sql.dialect) { + // dialect is not specified, use the dialect from the sql instance Dialect = sql.dialect; - else { - throw new Error("sql dialect not set properly"); + } else { + // dialect is not specified, use the default dialect + Dialect = require(__dirname + '/../').dialect; } return new Dialect().getQuery(this); }; diff --git a/test/index-tests.js b/test/index-tests.js index aa0237bd..614aee95 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -2,7 +2,7 @@ 'use strict'; var assert = require('assert'); -var sql = require(__dirname + '/../lib'); +var sql = require('../lib'); var user = sql.define({ name: 'user', @@ -16,10 +16,10 @@ suite('index', function() { }); }); - test('throws before dialect is set', function() { - assert.throws(function() { - var query = sql.select(user.id).where(user.email.equals('brian.m.carlson@gmail.com')).toQuery(); - }); + 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)'); + assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); }); test('setting dialect to postgres works', function() { @@ -61,4 +61,32 @@ suite('index', function() { assert.equal(postgres.dialect, require(__dirname + '/../lib/dialect/postgres')); assert.equal(sqlite.dialect, require(__dirname + '/../lib/dialect/sqlite')); }); + + test('override dialect for toQuery using dialect name', function() { + var Sql = sql.Sql; + var mysql = new Sql('mysql'); + var postgres = new Sql('postgres'); + var sqlite = new Sql('sqlite'); + + 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 values = ['brian.m.carlson@gmail.com']; + assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + assert.deepEqual(sqliteQuery.values, values); + + assert.equal(postgresQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + assert.deepEqual(postgresQuery.values, values); + + assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); + assert.deepEqual(mysqlQuery.values, values); + }); + + test('override dialect for toQuery using invalid dialect name', function() { + var query = sql.select(user.id).from(user); + assert.throws(function() { + query.toQuery('invalid'); + }); + }); }); From 07371561e3257836387ebc5cda545bf1ecf16695 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 15 Jun 2013 00:36:14 -0700 Subject: [PATCH 164/507] dialect getString --- lib/dialect/mysql.js | 21 +++---- lib/dialect/postgres.js | 97 ++++++++++++++++++++++++++++---- lib/node/index.js | 16 +++++- test/dialects/aggregate-tests.js | 14 +++-- test/dialects/insert-tests.js | 8 +-- test/dialects/support.js | 38 ++++++------- 6 files changed, 137 insertions(+), 57 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index c02ab1ad..4765fa91 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -18,37 +18,32 @@ Mysql.prototype._quoteCharacter = '`'; Mysql.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; -Mysql.prototype.visitParameter = function(parameter) { - this.params.push(parameter.value()); - return "?"; +/* jshint unused: false */ +Mysql.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 result = Mysql.super_.prototype.visitCreate.call(this, create); + var engine = this._queryNode.table._initialConfig.engine; var charset = this._queryNode.table._initialConfig.charset; - if (!!engine) { + if ( !! engine) { result.push('ENGINE=' + engine); } - if (!!charset) { + if ( !! charset) { result.push('DEFAULT CHARSET=' + charset); } return result; }; -/*jshint unused: false */ -Mysql.prototype.visitDefault = function(parameter) { - return "DEFAULT"; -}; - 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]; + return ['CHANGE COLUMN ' + this.visit(renameColumn.nodes[0]) + ' ' + this.visit(renameColumn.nodes[1]) + ' ' + dataType]; }; Mysql.prototype.visitInsert = function(insert) { diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 6aaf1015..116032aa 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -1,9 +1,11 @@ 'use strict'; -var assert = require('assert'); -var From = require(__dirname + '/../node/from'); -var Select = require(__dirname + '/../node/select'); -var Table = require(__dirname + '/../table'); +var _ = require('lodash'); +var assert = require('assert'); +var From = require('../node/from'); +var Select = require('../node/select'); +var Table = require('../table'); + var Postgres = function() { this.output = []; this.params = []; @@ -13,15 +15,79 @@ Postgres.prototype._myClass = Postgres; Postgres.prototype._arrayAggFunctionName = 'array_agg'; +Postgres.prototype._getParameterText = function(index, value) { + if (this._disableParameterPlaceholders) { + // do not use placeholder + return this._getParameterValue(value); + } else { + // use placeholder + return this._getParameterPlaceholder(index, value); + } +}; + +Postgres.prototype._getParameterValue = function(value) { + // handle primitives + if (null === value) { + value = 'NULL'; + } else if ('boolean' === typeof value) { + value = value ? 'TRUE' : 'FALSE'; + } else if ('number' === typeof value) { + // number is just number + value = value; + } else if ('string' === typeof value) { + // string uses single quote + 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(', ') + ')'; + } else { + // rich object represent with string + value = this._getParameterValue(value.toString()); + } + } else { + throw new Error('Unable to use ' + value + ' in query'); + } + + // value has been converted at this point + return value; +}; + +Postgres.prototype._getParameterPlaceholder = function(index, value) { + return '$' + index; +}; + Postgres.prototype.getQuery = function(queryNode) { // passed in a table, not a query if (queryNode instanceof Table) { queryNode = queryNode.select(queryNode.star()); } this.output = this.visit(queryNode); - return { text: this.output.join(' '), values: this.params }; + + // create the query object + var query = { text: this.output.join(' '), values: this.params }; + + // reset the internal state of this builder + this.output = []; + this.params = []; + + return query; }; +Postgres.prototype.getString = function(queryNode) { + // switch off parameter placeholders + this._disableParameterPlaceholders = true; + var query; + try { + // use the same code path for query building + query = this.getQuery(queryNode); + } finally { + // always toggle parameter placeholders on afterwards + this._disableParameterPlaceholders = false; + } + return query.text; +}; Postgres.prototype.visit = function(node) { switch(node.type) { @@ -72,8 +138,15 @@ Postgres.prototype.visit = function(node) { }; Postgres.prototype._quoteCharacter = '"'; -Postgres.prototype.quote = function(word) { - var q = this._quoteCharacter; +Postgres.prototype.quote = function(word, quoteCharacter) { + var q; + if (quoteCharacter) { + // use the specified quote character if given + q = quoteCharacter; + } else { + q = this._quoteCharacter; + } + return q + word.replace(new RegExp(q,'g'),q+q) + q; }; @@ -398,14 +471,14 @@ Postgres.prototype.visitFunctionCall = function(functionCall) { }; Postgres.prototype.visitParameter = function(parameter) { - this.params.push(parameter.value()); - return "$"+this.params.length; + // save the value into the parameters array + var value = parameter.value(); + this.params.push(value); + return [this._getParameterText(this.params.length, value)]; }; Postgres.prototype.visitDefault = function(parameter) { - var params = this.params; - this.params.push('DEFAULT'); - return "$"+params.length; + return ['DEFAULT']; }; Postgres.prototype.visitAddColumn = function(addColumn) { diff --git a/lib/node/index.js b/lib/node/index.js index b1f0d727..7112d9be 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -23,8 +23,8 @@ Node.prototype.add = function(node) { // Before the change that introduced parallel dialects, every node could be turned // into a query. The parallel dialects change made it impossible to change some nodes // into a query because not all nodes are constructed with the sql instance. -Node.prototype.toQuery = function(dialect) { - var sql = this.sql || (this.table && this.table.sql); +var determineDialect = function(query, dialect) { + var sql = query.sql || (query.table && query.table.sql); var Dialect; if (dialect) { @@ -35,11 +35,21 @@ Node.prototype.toQuery = function(dialect) { Dialect = sql.dialect; } else { // dialect is not specified, use the default dialect - Dialect = require(__dirname + '/../').dialect; + Dialect = require('../').dialect; } + return Dialect; +}; + +Node.prototype.toQuery = function(dialect) { + var Dialect = determineDialect(this, dialect); return new Dialect().getQuery(this); }; +Node.prototype.toString = function(dialect) { + var Dialect = determineDialect(this, dialect); + return new Dialect().getString(this); +}; + Node.prototype.addAll = function(nodes) { for(var i = 0, len = nodes.length; i < len; i++) { this.add(nodes[i]); diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index c0a46506..6eca5824 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -1,5 +1,7 @@ +/* global test */ 'use strict'; +var assert = require('assert'); var Harness = require('./support'); var post = Harness.definePostTable(); @@ -99,42 +101,42 @@ Harness.test({ params: [] }); -Harness.test({ +Harness.test({ query : post.select(post.id.sum()), pg : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', sqllite : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', mysql : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', }); -Harness.test({ +Harness.test({ query : post.select(post.id.sum().as('sum_id')), pg : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', sqllite : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', mysql : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', }); -Harness.test({ +Harness.test({ query : post.select(post.id.sum('sum_id')), pg : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', sqllite : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', mysql : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', }); -Harness.test({ +Harness.test({ query : post.select(post.id.avg()), pg : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', sqllite : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', mysql : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', }); -Harness.test({ +Harness.test({ query : post.select(post.id.avg().as('avg_id')), pg : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', sqllite : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', mysql : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', }); -Harness.test({ +Harness.test({ query : post.select(post.id.avg('avg_id')), pg : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', sqllite : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index d02fa695..b79e1acf 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -58,8 +58,8 @@ Harness.test({ Harness.test({ query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey'}]), pg : { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - params: ['whoah', 1, 'hey', 'DEFAULT'] + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, DEFAULT)', + params: ['whoah', 1, 'hey'] }, sqlite: { text: 'Sqlite requires the same number of columns in each insert row', @@ -74,8 +74,8 @@ Harness.test({ Harness.test({ query : post.insert([{userId: 1}, {content: 'hey', userId: 2}]), pg : { - text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, $2), ($3, $4)', - params: [1, 'DEFAULT', 2, 'hey'] + text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, DEFAULT), ($2, $3)', + params: [1, 2, 'hey'] }, sqlite: { text: 'Sqlite requires the same number of columns in each insert row', diff --git a/test/dialects/support.js b/test/dialects/support.js index 346bee70..ed96d73b 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -2,29 +2,29 @@ 'use strict'; var assert = require('assert'); -var Table = require(__dirname + '/../../lib/table'); +var Table = require('../../lib/table'); // specify dialect classes var dialects = { - pg : require('../../lib/dialect/postgres'), - sqlite: require('../../lib/dialect/sqlite'), - mysql : require('../../lib/dialect/mysql') + pg : require('../../lib/dialect/postgres'), + sqlite : require('../../lib/dialect/sqlite'), + mysql : require('../../lib/dialect/mysql') }; module.exports = { - test: function(expected) { + test: function(expected) { // for each dialect Object.keys(dialects).forEach(function(dialect) { - if(expected[dialect]) { + if (undefined !== expected[dialect]) { var DialectClass = dialects[dialect]; - var title = dialect+': '+(expected.title || expected[dialect].text || expected[dialect]); + var title = dialect + ': ' + (expected.title || expected[dialect].text || expected[dialect]); test(title, function() { // check if this query is expected to throw - if(expected[dialect].throws) { + if (expected[dialect].throws) { assert.throws(function() { new DialectClass().getQuery(expected.query); @@ -37,14 +37,14 @@ module.exports = { // test result is correct var expectedText = expected[dialect].text || expected[dialect]; - assert.equal(compiledQuery.text, expectedText,'query result'); + assert.equal(compiledQuery.text, expectedText, 'query result'); // if params are specified then test these are correct var expectedParams = expected[dialect].params || expected.params; - if(expectedParams) { + if (expectedParams) { assert.equal(expectedParams.length, compiledQuery.values.length, 'params length'); - for(var i = 0; i < expectedParams.length; i++) { - assert.equal(expectedParams[i], compiledQuery.values[i], 'param '+(i+1)); + for (var i = 0; i < expectedParams.length; i++) { + assert.equal(expectedParams[i], compiledQuery.values[i], 'param ' + (i + 1)); } } @@ -57,29 +57,29 @@ module.exports = { }, - defineUserTable: function () { + defineUserTable: function() { return Table.define({ name: 'user', quote: true, - columns: ['id','name'] + columns: ['id', 'name'] }); }, - definePostTable: function () { + definePostTable: function() { return Table.define({ name: 'post', columns: ['id', 'userId', 'content'] }); }, - defineCommentTable: function () { + defineCommentTable: function() { return Table.define({ name: 'comment', columns: ['postId', 'text'] }); }, - defineCustomerTable: function () { + defineCustomerTable: function() { return Table.define({ name: 'customer', columns: ['id', 'name', 'age', 'income'] @@ -89,8 +89,8 @@ module.exports = { // This table contains column names that correspond to popularly used variables in formulas. defineVariableTable: function() { return Table.define({ - name: 'variable', - columns: ['a', 'b', 'c', 'd', 't', 'u', 'v', 'x', 'y', 'z'] + name: 'variable', + columns: ['a', 'b', 'c', 'd', 't', 'u', 'v', 'x', 'y', 'z'] }); } }; From 9ad593cc2f6762358e534f7c0592a9080551d4f8 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 15 Jun 2013 17:17:16 -0700 Subject: [PATCH 165/507] test updates --- test/dialects/aggregate-tests.js | 307 +++++++++++++++++++------ test/dialects/alias-tests.js | 57 +++-- test/dialects/alter-table-tests.js | 179 +++++++++----- test/dialects/binary-clause-tests.js | 53 +++-- test/dialects/clause-ordering-tests.js | 80 +++++-- test/dialects/create-table-tests.js | 123 +++++++--- test/dialects/delete-tests.js | 76 ++++-- test/dialects/distinct-tests.js | 32 ++- test/dialects/drop-table-tests.js | 36 ++- test/dialects/from-clause-tests.js | 17 +- test/dialects/group-by-tests.js | 85 +++++-- test/dialects/having-tests.js | 45 +++- test/dialects/indexes-tests.js | 161 ++++++++++--- test/dialects/insert-tests.js | 288 +++++++++++++++++------ test/dialects/support.js | 27 ++- 15 files changed, 1190 insertions(+), 376 deletions(-) diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 6eca5824..fb80f353 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -6,140 +6,301 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.select(post.count()), - pg : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - sqlite: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - mysql : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', + query: post.select(post.count()), + pg: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + 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`' + }, params: [] }); Harness.test({ - query : post.select(post.count('post_count')), - pg : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - sqlite: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', - msyql : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', + query: post.select(post.count('post_count')), + pg: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + 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`' + }, params: [] }); Harness.test({ - query : post.select(post.count().as('post_amount')), - pg : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', - sqlite: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', - mysql : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', + query: post.select(post.count().as('post_amount')), + pg: { + text: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + 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`' + }, params: [] }); Harness.test({ - query : post.select(post.content.count()), - pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - sqlite: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + query: post.select(post.content.count()), + pg: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.content.count('content_count')), - pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - sqlite: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + query: post.select(post.content.count('content_count')), + pg: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.content.count().as('content_count')), - pg : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - sqlite: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', - mysql : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + query: post.select(post.content.count().as('content_count')), + pg: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + sqlite: { + text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' + }, + mysql: { + text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.min()), - pg : 'SELECT MIN("post"."id") AS "id_min" FROM "post"', - sqlite: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', - mysql : 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', + query: post.select(post.id.min()), + pg: { + text: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' + }, + sqlite: { + text: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' + }, + mysql: { + text: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', + string: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.min().as('min_id')), - pg : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - sqlite: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - mysql : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + query: post.select(post.id.min().as('min_id')), + pg: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + mysql: { + text: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.min('min_id')), - pg : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - sqlite: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', - mysql : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + query: post.select(post.id.min('min_id')), + pg: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' + }, + mysql: { + text: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.max()), - pg : 'SELECT MAX("post"."id") AS "id_max" FROM "post"', - sqlite: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', - mysql : 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', + query: post.select(post.id.max()), + pg: { + text: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' + }, + sqlite: { + text: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' + }, + mysql: { + text: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', + string: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.max().as('max_id')), - pg : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - sqlite: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - mysql : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + query: post.select(post.id.max().as('max_id')), + pg: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + mysql: { + text: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.max('max_id')), - pg : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - sqlite: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', - mysql : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + query: post.select(post.id.max('max_id')), + pg: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + sqlite: { + text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' + }, + mysql: { + text: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' + }, params: [] }); Harness.test({ - query : post.select(post.id.sum()), - pg : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', - sqllite : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', - mysql : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', + query: post.select(post.id.sum()), + pg: { + text: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', + string: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`' + }, }); Harness.test({ - query : post.select(post.id.sum().as('sum_id')), - pg : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - sqllite : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - mysql : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + query: post.select(post.id.sum().as('sum_id')), + pg: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' + }, }); Harness.test({ - query : post.select(post.id.sum('sum_id')), - pg : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - sqllite : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', - mysql : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + query: post.select(post.id.sum('sum_id')), + pg: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + sqlite: { + text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' + }, + mysql: { + text: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' + }, }); Harness.test({ - query : post.select(post.id.avg()), - pg : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', - sqllite : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', - mysql : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', + query: post.select(post.id.avg()), + pg: { + text: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' + }, + sqlite: { + text: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' + }, + mysql: { + text: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', + string: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`' + }, }); Harness.test({ - query : post.select(post.id.avg().as('avg_id')), - pg : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - sqllite : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - mysql : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + query: post.select(post.id.avg().as('avg_id')), + pg: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + sqlite: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + mysql: { + text: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' + }, }); Harness.test({ - query : post.select(post.id.avg('avg_id')), - pg : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - sqllite : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', - mysql : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + query: post.select(post.id.avg('avg_id')), + pg: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + sqlite: { + text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' + }, + mysql: { + 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 8b89c6b2..6b41f5ff 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -6,25 +6,52 @@ var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); Harness.test({ - query : customer.select(customer.name.isNull().as('nameIsNull')), - pg : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', - sqlite : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', - mysql : 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', - params : [] + query: customer.select(customer.name.isNull().as('nameIsNull')), + pg: { + text: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' + }, + mysql: { + text: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', + string: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`' + }, + params: [] }); Harness.test({ - query : customer.select(customer.name.plus(customer.age).as('nameAndAge')).where(customer.age.gt(10).and(customer.age.lt(20))), - pg : 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', - sqlite : 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', - mysql : 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > ?) AND (`customer`.`age` < ?))', - params : [10, 20] + query: customer.select(customer.name.plus(customer.age).as('nameAndAge')).where(customer.age.gt(10).and(customer.age.lt(20))), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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] }); Harness.test({ - query : customer.select(customer.age.between(10, 20).as('ageBetween')), - pg : 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', - sqlite : 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', - mysql : 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', - params : [10, 20] + query: customer.select(customer.age.between(10, 20).as('ageBetween')), + pg: { + text: 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', + string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) AS "ageBetween" FROM "customer"' + }, + sqlite: { + text: 'SELECT ("customer"."age" BETWEEN $1 AND $2) AS "ageBetween" FROM "customer"', + string: 'SELECT ("customer"."age" BETWEEN 10 AND 20) AS "ageBetween" FROM "customer"' + }, + mysql: { + 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] }); diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 9cb7f4a8..06befddc 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -5,137 +5,208 @@ var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); Harness.test({ - query : post.alter().dropColumn(post.content), - pg : 'ALTER TABLE "post" DROP COLUMN "content"', + query: post.alter().dropColumn(post.content), + pg: { + text: 'ALTER TABLE "post" DROP COLUMN "content"', + string: 'ALTER TABLE "post" DROP COLUMN "content"' + }, sqlite: { - text : 'Sqlite cannot drop columns', + text: 'Sqlite cannot drop columns', throws: true }, - mysql : 'ALTER TABLE `post` DROP COLUMN `content`', + mysql: { + text: 'ALTER TABLE `post` DROP COLUMN `content`', + string: 'ALTER TABLE `post` DROP COLUMN `content`' + }, params: [] }); Harness.test({ - query : post.alter().dropColumn(post.content).dropColumn(post.userId), - pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + query: post.alter().dropColumn(post.content).dropColumn(post.userId), + pg: { + text: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' + }, sqlite: { - text : 'Sqlite cannot drop columns', + text: 'Sqlite cannot drop columns', throws: true }, - mysql : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + mysql: { + text: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' + }, params: [] }); Harness.test({ - query : post.alter().dropColumn('content').dropColumn('userId'), - pg : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + query: post.alter().dropColumn('content').dropColumn('userId'), + pg: { + text: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' + }, sqlite: { - text : 'Sqlite cannot drop columns', + text: 'Sqlite cannot drop columns', throws: true }, - mysql : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + mysql: { + text: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' + }, params: [] }); Harness.test({ - query : post.alter().rename('posts'), - pg : 'ALTER TABLE "post" RENAME TO "posts"', - sqlite: 'ALTER TABLE "post" RENAME TO "posts"', - mysql : 'ALTER TABLE `post` RENAME TO `posts`', + query: post.alter().rename('posts'), + pg: { + text: 'ALTER TABLE "post" RENAME TO "posts"', + string: 'ALTER TABLE "post" RENAME TO "posts"' + }, + sqlite: { + text: 'ALTER TABLE "post" RENAME TO "posts"', + string: 'ALTER TABLE "post" RENAME TO "posts"' + }, + mysql: { + text: 'ALTER TABLE `post` RENAME TO `posts`', + string: 'ALTER TABLE `post` RENAME TO `posts`' + }, params: [] }); var group = Table.define({ name: 'group', columns: [{ - name: 'id', - dataType: 'varchar(100)' - }, { - name: 'userId', - dataType: 'varchar(100)' - }] + name: 'id', + dataType: 'varchar(100)' + }, { + name: 'userId', + dataType: 'varchar(100)' + } + ] }); Harness.test({ - query : group.alter().addColumn(group.id), - pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', - sqlite: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', - mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', + query: group.alter().addColumn(group.id), + pg: { + text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' + }, + sqlite: { + text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' + }, + mysql: { + text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', + string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)' + }, params: [] }); Harness.test({ - query : group.alter().addColumn(group.id).addColumn(group.userId), - pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + query: group.alter().addColumn(group.id).addColumn(group.userId), + pg: { + 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)' + }, sqlite: { - text : 'Sqlite cannot add more than one column at a time', + text: 'Sqlite cannot add more than one column at a time', throws: true }, - mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', + mysql: { + 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)' + }, params: [] }); Harness.test({ - query : group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), - pg : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + query: group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), + pg: { + 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)' + }, sqlite: { - text : 'Sqlite cannot add more than one column at a time', + text: 'Sqlite cannot add more than one column at a time', throws: true }, - mysql : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', + mysql: { + 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)' + }, params: [] }); Harness.test({ - query : group.alter().renameColumn('userId', 'newUserId'), - pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', - mysql : { + query: group.alter().renameColumn('userId', 'newUserId'), + pg: { + text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' + }, + mysql: { text: 'Mysql requires data type for renaming a column', throws: true }, sqlite: { - text : 'Sqlite cannot rename columns', + text: 'Sqlite cannot rename columns', throws: true }, params: [] }); Harness.test({ - query : group.alter().renameColumn(group.userId, 'newUserId'), - pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + query: group.alter().renameColumn(group.userId, 'newUserId'), + pg: { + text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' + }, sqlite: { - text : 'Sqlite cannot rename columns', + text: 'Sqlite cannot rename columns', throws: true }, - mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', + mysql: { + text: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', + string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)' + }, params: [] }); Harness.test({ - query : group.alter().renameColumn('userId', group.id), - pg : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + query: group.alter().renameColumn('userId', group.id), + pg: { + text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"' + }, sqlite: { - text : 'Sqlite cannot rename columns', + text: 'Sqlite cannot rename columns', throws: true }, - mysql : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', + mysql: { + text: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', + string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)' + }, params: [] }); var UserWithSignature = Table.define({ - name: 'UserWithSignature', + name: 'UserWithSignature', columns: [{ - name: 'Signature', - dataType: "VARCHAR(255) NOT NULL DEFAULT 'Signature'" - }] + name: 'Signature', + dataType: "VARCHAR(255) NOT NULL DEFAULT 'Signature'" + } + ] }); Harness.test({ - query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), - pg: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', - mysql: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'', + query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), + pg: { + text: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', + string: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"' + }, + mysql: { + text: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'', + string: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'' + }, sqlite: { - text : 'Sqlite cannot rename columns', + text: 'Sqlite cannot rename columns', throws: true } }); diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 4b59721f..3a2d49b2 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -6,25 +6,52 @@ var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); Harness.test({ - query : customer.select(customer.name.plus(customer.age)), - pg : 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - sqlite: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', - mysql : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', + query: customer.select(customer.name.plus(customer.age)), + 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`' + }, params: [] }); Harness.test({ - query : post.select(post.content.plus('!')).where(post.userId.in(customer.subQuery().select(customer.id))), - pg : 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', - sqlite: 'SELECT ("post"."content" + $1) FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer"))', - mysql : 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', + query: post.select(post.content.plus('!')).where(post.userId. in (customer.subQuery().select(customer.id))), + pg: { + 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"))' + }, + sqlite: { + 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"))' + }, + mysql: { + 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: ['!'] }); Harness.test({ - query : post.select(post.id.plus(': ').plus(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), - pg : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', - sqlite : 'SELECT (("post"."id" + $1) + "post"."content") FROM "post" WHERE ("post"."userId" NOT IN (SELECT "customer"."id" FROM "customer"))', - mysql : 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', - params : [': '] + query: post.select(post.id.plus(': ').plus(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), + pg: { + 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"))' + }, + sqlite: { + 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"))' + }, + mysql: { + 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: [': '] }); diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index c7ca3a79..b211985a 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -6,38 +6,80 @@ var post = Harness.definePostTable(); // FROM - SELECT Harness.test({ - query : user.from(user.join(post).on(user.id.equals(post.userId))).select(user.name, post.content), - pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + 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")', + }, + sqlite: { + 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")' + }, + mysql: { + 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`)' + }, }); // WHERE - FROM - SELECT Harness.test({ - query : user.where({name: ''}).from(user).select(user.id), - pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + query: user.where({ + name: '' + }).from(user).select(user.id), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' + }, params: [''] }); // SELECT - FROM - WHERE Harness.test({ - query : user - .select(user.name, post.content) - .from(user.join(post).on(user.id.equals(post.userId))) - .where({ name: '' }), - pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = ?)', + query: user + .select(user.name, post.content) + .from(user.join(post).on(user.id.equals(post.userId))) + .where({ + name: '' + }), + pg: { + 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" = \'\')' + }, + sqlite: { + 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" = \'\')' + }, + mysql: { + 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: [''] }); // SELECT - FROM - WHERE Harness.test({ - query : user.select(user.id).from(user).where({name: ''}), - pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + query: user.select(user.id).from(user).where({ + name: '' + }), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + 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 73eb1ebd..3d91238f 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -6,47 +6,118 @@ var Harness = require('./support'); var group = Table.define({ name: 'group', columns: [{ - name: 'id', - dataType: 'varchar(100)' - }, { - name: 'user_id', - dataType: 'varchar(100)' - }] + name: 'id', + dataType: 'varchar(100)' + }, { + name: 'user_id', + dataType: 'varchar(100)' + } + ] }); Harness.test({ - query : group.create(), - pg : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', - sqlite: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', - mysql : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', + query: group.create(), + pg: { + text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', + string: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))' + }, params: [] }); Harness.test({ - query : group.create().ifNotExists(), - pg : 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', - sqlite: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', - mysql : 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', + query: group.create().ifNotExists(), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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))' + }, params: [] }); Harness.test({ - query : Table.define({ name: 'user', columns: [{ name: 'id', dataType: 'varchar(100)' }], engine: 'InnoDB' }).create(), - pg : 'CREATE TABLE "user" ("id" varchar(100))', - sqlite: 'CREATE TABLE "user" ("id" varchar(100))', - mysql : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'varchar(100)' + } + ], + engine: 'InnoDB' + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', + string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' + } }); Harness.test({ - query : Table.define({ name: 'user', columns: [{ name: 'id', dataType: 'varchar(100)' }], charset: 'latin1' }).create(), - pg : 'CREATE TABLE "user" ("id" varchar(100))', - sqlite: 'CREATE TABLE "user" ("id" varchar(100))', - mysql : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'varchar(100)' + } + ], + charset: 'latin1' + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + mysql: { + text: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', + string: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' + } }); Harness.test({ - query : Table.define({ name: 'user', columns: [{ name: 'id', dataType: 'varchar(100)' }], engine: 'MyISAM', charset: 'latin1' }).create(), - pg : 'CREATE TABLE "user" ("id" varchar(100))', - sqlite: 'CREATE TABLE "user" ("id" varchar(100))', - mysql : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'varchar(100)' + } + ], + engine: 'MyISAM', + charset: 'latin1' + }).create(), + pg: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + sqlite: { + text: 'CREATE TABLE "user" ("id" varchar(100))', + string: 'CREATE TABLE "user" ("id" varchar(100))' + }, + 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' + } }); diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 42653d77..f1bf6188 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -4,33 +4,75 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.delete().where(post.content.equals('')), - pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', - mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', - params: [''] + query: post.delete().where(post.content.equals("hello's world")), + pg: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' + }, + mysql: { + text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + string: 'DELETE FROM `post` WHERE (`post`.`content` = \'hello\'\'s world\')' + }, + params: ["hello's world"] }); Harness.test({ - query : post.delete().where({content: ''}), - pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', - mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + query: post.delete().where({ + content: '' + }), + pg: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + mysql: { + text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' + }, params: [''] }); Harness.test({ - query : post.delete({content: ''}), - pg : 'DELETE FROM "post" WHERE ("post"."content" = $1)', - sqlite: 'DELETE FROM "post" WHERE ("post"."content" = $1)', - mysql : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + query: post.delete({ + content: '' + }), + pg: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + sqlite: { + text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' + }, + mysql: { + text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' + }, params: [''] }); Harness.test({ - query : post.delete({content: ''}).or(post.content.isNull()), - pg : 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', - sqlite: 'DELETE FROM "post" WHERE (("post"."content" = $1) OR ("post"."content" IS NULL))', - mysql : 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', + query: post.delete({ + content: '' + }).or(post.content.isNull()), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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: [''] }); diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js index f803c0ad..c584745f 100644 --- a/test/dialects/distinct-tests.js +++ b/test/dialects/distinct-tests.js @@ -4,11 +4,35 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); Harness.test({ - query : user.select(user.id.distinct()), - pg : 'SELECT DISTINCT("user"."id") FROM "user"' + query: user.select(user.id.distinct()), + pg: { + text: 'SELECT DISTINCT("user"."id") FROM "user"', + string: 'SELECT DISTINCT("user"."id") FROM "user"' + }, + sqlite: { + text: 'SELECT DISTINCT("user"."id") FROM "user"', + string: 'SELECT DISTINCT("user"."id") FROM "user"' + }, + mysql: { + text: 'SELECT DISTINCT(`user`.`id`) FROM `user`', + string: 'SELECT DISTINCT(`user`.`id`) FROM `user`' + }, + params: [] }); Harness.test({ - query : user.select(user.id.count().distinct().as('count')), - pg : 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' + query: user.select(user.id.count().distinct().as('count')), + pg: { + text: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', + string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' + }, + sqlite: { + text: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', + string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' + }, + mysql: { + text: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', + string: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`' + }, + params: [] }); diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index eb07196d..eb5f78f9 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -4,17 +4,35 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.drop(), - pg : 'DROP TABLE "post"', - sqlite: 'DROP TABLE "post"', - mysql : 'DROP TABLE `post`', + query: post.drop(), + pg: { + text: 'DROP TABLE "post"', + string: 'DROP TABLE "post"' + }, + sqlite: { + text: 'DROP TABLE "post"', + string: 'DROP TABLE "post"' + }, + mysql: { + text: 'DROP TABLE `post`', + string: 'DROP TABLE `post`' + }, params: [] }); Harness.test({ - query : post.drop().ifExists(), - pg : 'DROP TABLE IF EXISTS "post"', - sqlite: 'DROP TABLE IF EXISTS "post"', - mysql : 'DROP TABLE IF EXISTS `post`', + query: post.drop().ifExists(), + pg: { + text: 'DROP TABLE IF EXISTS "post"', + string: 'DROP TABLE IF EXISTS "post"' + }, + sqlite: { + text: 'DROP TABLE IF EXISTS "post"', + string: 'DROP TABLE IF EXISTS "post"' + }, + mysql: { + text: 'DROP TABLE IF EXISTS `post`', + string: 'DROP TABLE IF EXISTS `post`' + }, params: [] -}); \ No newline at end of file +}); diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js index 47ea598c..318fa379 100644 --- a/test/dialects/from-clause-tests.js +++ b/test/dialects/from-clause-tests.js @@ -5,8 +5,17 @@ var user = Harness.defineUserTable(); var post = Harness.definePostTable(); Harness.test({ - query : user.select(user.star()).from(user).from(post), - pg : 'SELECT "user".* FROM "user" , "post"', - sqlite: 'SELECT "user".* FROM "user" , "post"', - mysql : 'SELECT `user`.* FROM `user` , `post`' + query: user.select(user.star()).from(user).from(post), + pg: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" , "post"', + string: 'SELECT "user".* FROM "user" , "post"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` , `post`', + string: 'SELECT `user`.* FROM `user` , `post`' + } }); diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index 3d5dd756..33e6afd1 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -4,41 +4,86 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.select(post.content).group(post.userId), - pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', - sqlite: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', - mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', + query: post.select(post.content).group(post.userId), + pg: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', + string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`' + }, params: [] }); Harness.test({ - query : post.select(post.content).group(post.userId, post.id), - pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - sqlite: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + query: post.select(post.content).group(post.userId, post.id), + pg: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + mysql: { + 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: [] }); Harness.test({ - query : post.select(post.content.arrayAgg()).group(post.userId), - pg : 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', - sqlite: 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', - mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', + query: post.select(post.content.arrayAgg()).group(post.userId), + pg: { + text: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"' + }, + sqlite: { + 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"' + }, + mysql: { + 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`' + }, params: [] }); Harness.test({ - query : post.select(post.content.arrayAgg('post contents')).group(post.userId), - pg : 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', - sqlite: 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', - mysql : 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', + query: post.select(post.content.arrayAgg('post contents')).group(post.userId), + pg: { + text: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + string: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"' + }, + sqlite: { + 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"' + }, + mysql: { + 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`' + }, params: [] }); Harness.test({ - query : post.select(post.content).group([post.userId, post.id]), - pg : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - sqlite: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', - mysql : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + query: post.select(post.content).group([post.userId, post.id]), + pg: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' + }, + mysql: { + 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 5d5ab1b7..dff7144a 100644 --- a/test/dialects/having-tests.js +++ b/test/dialects/having-tests.js @@ -5,24 +5,51 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10)), - pg : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', - sqlite: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', - mysql : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?)', + pg : { + 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)' + }, + sqlite: { + 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)' + }, + mysql : { + 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] }); Harness.test({ query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10), post.userId.lt(100)), - pg : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - sqlite: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - mysql : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', + pg : { + 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)' + }, + sqlite: { + 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)' + }, + mysql : { + 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] }); Harness.test({ query : post.select(post.userId, post.content.count()).group(post.userId).having([post.userId.gt(10), post.userId.lt(100)]), - pg : 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - sqlite: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', - mysql : 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > ?) AND (`post`.`userId` < ?)', + pg : { + 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)' + }, + sqlite: { + 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)' + }, + mysql : { + 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] }); diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 838b2cf5..44a12a96 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -4,64 +4,153 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query: post.indexes(), - pg: "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)", - mysql: "SHOW INDEX FROM `post`", - sqlite: "PRAGMA INDEX_LIST(\"post\")" + 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)' + }, + mysql: { + text: 'SHOW INDEX FROM `post`', + string: 'SHOW INDEX FROM `post`' + }, + sqlite: { + text: 'PRAGMA INDEX_LIST("post")', + string: 'PRAGMA INDEX_LIST("post")' + }, + params: [] }); Harness.test({ - query: post.indexes().create('index_name').unique().using('btree').on(post.id, post.userId).withParser('foo'), - pg: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"id\",\"userId\") WITH PARSER foo", - mysql: "CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo", - sqlite: "CREATE UNIQUE INDEX \"index_name\" USING BTREE ON \"post\" (\"id\",\"userId\") WITH PARSER foo" + query: post.indexes().create('index_name').unique().using('btree').on(post.id, post.userId).withParser('foo'), + pg: { + 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' + }, + mysql: { + 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' + }, + sqlite: { + 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: [] }); Harness.test({ - query: post.indexes().create().fulltext().on(post.id), - pg: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"id\")", - mysql: "CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)", - sqlite: "CREATE FULLTEXT INDEX \"post_id\" ON \"post\" (\"id\")" + query: post.indexes().create().fulltext().on(post.id), + pg: { + text: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', + string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' + }, + mysql: { + text: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)', + string: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)' + }, + sqlite: { + text: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', + string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' + }, + params: [] }); Harness.test({ - query: post.indexes().create().spatial().on(post.id), - pg: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"id\")", - mysql: "CREATE SPATIAL INDEX `post_id` ON `post` (`id`)", - sqlite: "CREATE SPATIAL INDEX \"post_id\" ON \"post\" (\"id\")" + query: post.indexes().create().spatial().on(post.id), + pg: { + text: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', + string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' + }, + mysql: { + text: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)', + string: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)' + }, + sqlite: { + text: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', + string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' + }, + params: [] }); Harness.test({ - query: post.indexes().create().on(post.userId, post.id), - pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")", - mysql: "CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)", - sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")" + query: post.indexes().create().on(post.userId, post.id), + pg: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + mysql: { + text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' + }, + sqlite: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + params: [] }); Harness.test({ - query: post.indexes().create().on(post.userId).on(post.id), - pg: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")", - mysql: "CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)", - sqlite: "CREATE INDEX \"post_id_userId\" ON \"post\" (\"userId\",\"id\")" + query: post.indexes().create().on(post.userId).on(post.id), + pg: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + mysql: { + text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', + string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' + }, + sqlite: { + text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' + }, + params: [] }); Harness.test({ - query: post.indexes().create(), - pg: { text: 'No columns defined!', throws: true }, - mysql: { text: 'No columns defined!', throws: true }, - sqlite: { text: 'No columns defined!', throws: true } + query: post.indexes().create(), + pg: { + text: 'No columns defined!', + throws: true + }, + mysql: { + text: 'No columns defined!', + throws: true + }, + sqlite: { + text: 'No columns defined!', + throws: true + } }); Harness.test({ - query: post.indexes().drop('index_name'), - pg: "DROP INDEX \"index_name\" ON \"post\"", - mysql: "DROP INDEX `index_name` ON `post`", - sqlite: "DROP INDEX \"index_name\" ON \"post\"" + query: post.indexes().drop('index_name'), + pg: { + text: 'DROP INDEX "index_name" ON "post"', + string: 'DROP INDEX "index_name" ON "post"' + }, + mysql: { + text: 'DROP INDEX `index_name` ON `post`', + string: 'DROP INDEX `index_name` ON `post`' + }, + sqlite: { + text: 'DROP INDEX "index_name" ON "post"', + string: 'DROP INDEX "index_name" ON "post"' + }, + params: [] }); Harness.test({ - query: post.indexes().drop(post.userId, post.id), - pg: "DROP INDEX \"post_id_userId\" ON \"post\"", - mysql: "DROP INDEX `post_id_userId` ON `post`", - sqlite: "DROP INDEX \"post_id_userId\" ON \"post\"" + 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"' + }, + mysql: { + text: 'DROP INDEX `post_id_userId` ON `post`', + string: 'DROP INDEX `post_id_userId` ON `post`' + }, + sqlite: { + text: 'DROP INDEX "post_id_userId" ON "post"', + string: 'DROP INDEX "post_id_userId" ON "post"' + }, + params: [] }); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index b79e1acf..32cea8f6 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -4,133 +4,279 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.insert(post.content.value('test'), post.userId.value(1)), - pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + query: post.insert(post.content.value('test'), post.userId.value(1)), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 1)' + }, params: ['test', 1] }); Harness.test({ - query : post.insert(post.content.value('whoah')), - pg : 'INSERT INTO "post" ("content") VALUES ($1)', - sqlite: 'INSERT INTO "post" ("content") VALUES ($1)', - mysql : 'INSERT INTO `post` (`content`) VALUES (?)', + query: post.insert(post.content.value('whoah')), + pg: { + text: 'INSERT INTO "post" ("content") VALUES ($1)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("content") VALUES ($1)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' + }, + mysql: { + text: 'INSERT INTO `post` (`content`) VALUES (?)', + string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\')' + }, params: ['whoah'] }); Harness.test({ - query : post.insert({content: 'test', userId: 2}), - pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + query: post.insert({ + content: 'test', + userId: 2 + }), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 2)' + }, params: ['test', 2] }); // allow bulk insert Harness.test({ - query : post.insert([{content: 'whoah'}, {content: 'hey'}]), - pg : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - sqlite: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - mysql : 'INSERT INTO `post` (`content`) VALUES (?), (?)', + query: post.insert([{ + content: 'whoah' + }, { + content: 'hey' + } + ]), + pg: { + text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + sqlite: { + text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' + }, + mysql: { + text: 'INSERT INTO `post` (`content`) VALUES (?), (?)', + string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\'), (\'hey\')' + }, params: ['whoah', 'hey'] }); Harness.test({ - query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey', userId: 2}]), - pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + query: post.insert([{ + content: 'whoah', + userId: 1 + }, { + content: 'hey', + userId: 2 + } + ]), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' + }, params: ['whoah', 1, 'hey', 2] }); // consistent order Harness.test({ - query : post.insert([{content: 'whoah', userId: 1}, {userId: 2, content: 'hey' }]), - pg : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - sqlite: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', - mysql : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + query: post.insert([{ + content: 'whoah', + userId: 1 + }, { + userId: 2, + content: 'hey' + } + ]), + pg: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + sqlite: { + text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' + }, params: ['whoah', 1, 'hey', 2] }); -// handle missing columns Harness.test({ - query : post.insert([{content: 'whoah', userId: 1}, {content: 'hey'}]), - pg : { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, DEFAULT)', - params: ['whoah', 1, 'hey'] + query: post.insert({}), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES', + string: 'INSERT INTO "post" DEFAULT VALUES' }, sqlite: { - text: 'Sqlite requires the same number of columns in each insert row', - throws: true + text: 'INSERT INTO "post" DEFAULT VALUES', + string: 'INSERT INTO "post" DEFAULT VALUES' }, - mysql : { - text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', - params: ['whoah', 1, 'hey'] - } + mysql: { + text: 'INSERT INTO `post` () VALUES ()', + string: 'INSERT INTO `post` () VALUES ()' + }, + params: [] }); Harness.test({ - query : post.insert([{userId: 1}, {content: 'hey', userId: 2}]), - pg : { - text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, DEFAULT), ($2, $3)', - params: [1, 2, 'hey'] + query: post.insert({}).returning('*'), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, sqlite: { - text: 'Sqlite requires the same number of columns in each insert row', - throws: true + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, - mysql : { - text: 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', - params: [1, 2, 'hey'] - } + mysql: { + text: 'INSERT INTO `post` () VALUES () RETURNING *', + string: 'INSERT INTO `post` () VALUES () RETURNING *' + }, + params: [] }); Harness.test({ - query : post.insert({}), - pg : 'INSERT INTO "post" DEFAULT VALUES', - sqlite: 'INSERT INTO "post" DEFAULT VALUES', - mysql : 'INSERT INTO `post` () VALUES ()', + query: post.insert({}).returning(post.star()), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' + }, + sqlite: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' + }, + mysql: { + text: 'INSERT INTO `post` () VALUES () RETURNING *', + string: 'INSERT INTO `post` () VALUES () RETURNING *' + }, params: [] }); Harness.test({ - query : post.insert({}).returning('*'), - pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - mysql : 'INSERT INTO `post` () VALUES () RETURNING *', + query: post.insert({}).returning(post.id), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' + }, + sqlite: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' + }, + mysql: { + text: 'INSERT INTO `post` () VALUES () RETURNING `id`', + string: 'INSERT INTO `post` () VALUES () RETURNING `id`' + }, params: [] }); Harness.test({ - query : post.insert({}).returning(post.star()), - pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - mysql : 'INSERT INTO `post` () VALUES () RETURNING *', + query: post.insert({}).returning(post.id, post.content), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + }, + sqlite: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + }, + mysql: { + text: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', + string: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`' + }, params: [] }); Harness.test({ - query : post.insert({}).returning(post.id), - pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', - sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', - mysql : 'INSERT INTO `post` () VALUES () RETURNING `id`', + query: post.insert({}).returning([post.id, post.content]), + pg: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + }, + sqlite: { + text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + }, + mysql: { + text: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', + string: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`' + }, params: [] }); +// handle missing columns Harness.test({ - query : post.insert({}).returning(post.id, post.content), - pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - mysql : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', - params: [] + query: post.insert([{ + content: 'whoah', + userId: 1 + }, { + content: 'hey' + } + ]), + pg: { + 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'] + }, + sqlite: { + text: 'Sqlite requires the same number of columns in each insert row', + throws: true + }, + mysql: { + text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', + params: ['whoah', 1, 'hey'] + } }); Harness.test({ - query : post.insert({}).returning([post.id, post.content]), - pg : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - sqlite: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - mysql : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', - params: [] + query: post.insert([{ + userId: 1 + }, { + content: 'hey', + userId: 2 + } + ]), + pg: { + 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'] + }, + sqlite: { + text: 'Sqlite requires the same number of columns in each insert row', + throws: true + }, + mysql: { + text: 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', + string: 'INSERT INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, \'hey\')', + params: [1, 2, 'hey'] + } }); diff --git a/test/dialects/support.js b/test/dialects/support.js index ed96d73b..86e30f7a 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -16,15 +16,16 @@ module.exports = { // for each dialect Object.keys(dialects).forEach(function(dialect) { - if (undefined !== expected[dialect]) { + var expectedObject = expected[dialect]; + if (undefined !== expectedObject) { var DialectClass = dialects[dialect]; - var title = dialect + ': ' + (expected.title || expected[dialect].text || expected[dialect]); + var title = dialect + ': ' + (expected.title || expectedObject.text || expectedObject); test(title, function() { // check if this query is expected to throw - if (expected[dialect].throws) { + if (expectedObject.throws) { assert.throws(function() { new DialectClass().getQuery(expected.query); @@ -36,11 +37,11 @@ module.exports = { var compiledQuery = new DialectClass().getQuery(expected.query); // test result is correct - var expectedText = expected[dialect].text || expected[dialect]; + var expectedText = expectedObject.text || expectedObject; assert.equal(compiledQuery.text, expectedText, 'query result'); // if params are specified then test these are correct - var expectedParams = expected[dialect].params || expected.params; + var expectedParams = expectedObject.params || expected.params; if (expectedParams) { assert.equal(expectedParams.length, compiledQuery.values.length, 'params length'); for (var i = 0; i < expectedParams.length; i++) { @@ -49,8 +50,22 @@ module.exports = { } } - }); + if (undefined !== expectedObject.string) { + // test the toString + if (expectedObject.throws) { + assert.throws(function() { + new DialectClass().getString(expected.query); + }); + } else { + var compiledString = new DialectClass().getString(expected.query); + + // test result is correct + assert.equal(compiledString, expectedObject.string); + } + } + + }); } // if }); // forEach From bfa041bc35268b41d84136ce74538e3eaba1e772 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 15 Jun 2013 19:40:24 -0700 Subject: [PATCH 166/507] pass string flag to subquery --- lib/dialect/postgres.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 116032aa..56f92a8b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -77,14 +77,15 @@ Postgres.prototype.getQuery = function(queryNode) { Postgres.prototype.getString = function(queryNode) { // switch off parameter placeholders + var previousFlagStatus = this._disableParameterPlaceholders; this._disableParameterPlaceholders = true; var query; try { // use the same code path for query building query = this.getQuery(queryNode); } finally { - // always toggle parameter placeholders on afterwards - this._disableParameterPlaceholders = false; + // always restore the flag afterwards + this._disableParameterPlaceholders = previousFlagStatus; } return query.text; }; @@ -390,9 +391,22 @@ Postgres.prototype.visitQuery = function(queryNode) { }; Postgres.prototype.visitSubquery = function(queryNode) { + // create another query builder of the current class to build the subquery var subQuery = new this._myClass(); + + // let the subquery modify this instance's params array subQuery.params = this.params; - subQuery.visitQuery(queryNode); + + // pass on the disable parameter placeholder flag + var previousFlagStatus = subQuery._disableParameterPlaceholders; + subQuery._disableParameterPlaceholders = this._disableParameterPlaceholders; + try { + subQuery.visitQuery(queryNode); + } finally { + // restore the flag + subQuery._disableParameterPlaceholders = previousFlagStatus; + } + var alias = queryNode.alias; return '(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + alias : ''); }; From 4803d7afd6df670c93f6e511f6dc8daf4079edfe Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 15 Jun 2013 20:06:05 -0700 Subject: [PATCH 167/507] update the rest of the tests --- test/dialects/join-tests.js | 140 +++++--- test/dialects/join-to-tests.js | 62 +++- test/dialects/limit-and-offset-tests.js | 75 ++++- test/dialects/namespace-tests.js | 106 ++++-- test/dialects/order-tests.js | 72 ++++- test/dialects/schema-tests.js | 92 ++++-- test/dialects/select-tests.js | 18 +- test/dialects/shortcut-tests.js | 112 +++++-- test/dialects/support.js | 10 +- test/dialects/table-tests.js | 413 ++++++++++++++++++------ test/dialects/ternary-clause-tests.js | 34 +- test/dialects/unary-clause-tests.js | 34 +- test/dialects/update-tests.js | 117 +++++-- test/dialects/value-expression-tests.js | 68 +++- test/dialects/where-clause-tests.js | 36 ++- 15 files changed, 1049 insertions(+), 340 deletions(-) diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index ba281781..67c2d74e 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -6,71 +6,123 @@ var post = Harness.definePostTable(); var comment = Harness.defineCommentTable(); Harness.test({ - query : user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), - pg : 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - sqlite: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + query: user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); Harness.test({ - query : user.join(post).on(user.id.equals(post.userId)), - pg : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - sqlite: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', - mysql : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + query: user.join(post).on(user.id.equals(post.userId)), + pg: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + sqlite: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' + }, + mysql: { + text: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' + }, + params: [] }); Harness.test({ - query : user - .select(user.name, post.content, comment.text) - .from( - user - .join(post).on(user.id.equals(post.userId)) - .join(comment).on(post.id.equals(comment.postId)) - ), - pg : '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")', - sqlite: '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")', - mysql : '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`)' + query: user + .select(user.name, post.content, comment.text) + .from( + user + .join(post).on(user.id.equals(post.userId)) + .join(comment).on(post.id.equals(comment.postId))), + pg: { + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); Harness.test({ - query : user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), - pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', - sqlite: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', - mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' + query: user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), + pg: { + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); Harness.test({ - query : user - .select(user.name, post.content) - .from( - user - .leftJoin(post).on(user.id.equals(post.userId)) - .leftJoin(comment).on(post.id.equals(comment.postId)) - ), - pg : 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + - ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', - sqlite: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")' + - ' LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', - mysql : 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)' + - ' LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)' + query: user + .select(user.name, post.content) + .from( + user + .leftJoin(post).on(user.id.equals(post.userId)) + .leftJoin(comment).on(post.id.equals(comment.postId))), + pg: { + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); var subposts = post .subQuery('subposts') .select( - post.content, - post.userId.as('subpostUserId')) + post.content, + post.userId.as('subpostUserId')) .from(post); Harness.test({ - query : user + query: user .select(user.name, subposts.content) .from(user.join(subposts) .on(user.id.equals(subposts.subpostUserId))), - pg : '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: '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 : 'SELECT `user`.`name`, `subposts`.`content` FROM `user` INNER JOIN (SELECT `post`.`content`, `post`.`userId` AS `subpostUserId` FROM `post`) subposts ON (`user`.`id` = `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")' + }, + 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")' + }, + 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`)' + }, + params: [] }); diff --git a/test/dialects/join-to-tests.js b/test/dialects/join-to-tests.js index 93f64579..b421eb38 100644 --- a/test/dialects/join-to-tests.js +++ b/test/dialects/join-to-tests.js @@ -6,7 +6,9 @@ var Harness = require('./support'); var user = sql.define({ name: 'user', columns: { - id: { primaryKey: true } + id: { + primaryKey: true + } } }); @@ -22,7 +24,9 @@ var photo = sql.define({ var post = sql.define({ name: 'post', columns: { - id: { primaryKey: true }, + id: { + primaryKey: true + }, ownerId: { references: { table: 'user', @@ -33,22 +37,52 @@ var post = sql.define({ }); Harness.test({ - query : user.joinTo(post), - pg : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', - sqlite: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', - mysql : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' + query: user.joinTo(post), + pg: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' + }, + sqlite: { + text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' + }, + mysql: { + text: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', + string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' + }, + params: [] }); Harness.test({ - query : post.joinTo(user), - pg : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', - sqlite: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', - mysql : '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' + query: post.joinTo(user), + pg: { + text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' + }, + sqlite: { + text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' + }, + mysql: { + text: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', + string: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' + }, + params: [] }); Harness.test({ - query : user.joinTo(photo), - pg : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', - sqlite: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', - mysql : '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)' + query: user.joinTo(photo), + pg: { + text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' + }, + sqlite: { + text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' + }, + mysql: { + 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 294d7315..55afafdb 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -7,30 +7,73 @@ var user = Harness.defineUserTable(); // http://dev.mysql.com/doc/refman/5.0/en/select.html Harness.test({ - query : user.select(user.star()).from(user).order(user.name.asc).limit(1), - pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', - sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', - mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' + query: user.select(user.star()).from(user).order(user.name.asc).limit(1), + pg: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1', + string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' + }, + params: [] }); Harness.test({ - query : user.select(user.star()).from(user).order(user.name.asc).limit(3).offset(6), - pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', - sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', - mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6' + query: user.select(user.star()).from(user).order(user.name.asc).limit(3).offset(6), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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' + }, + params: [] }); Harness.test({ - query : user.select(user.star()).from(user).order(user.name.asc).offset(10), - pg : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', - sqlite: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', - mysql : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' + query: user.select(user.star()).from(user).order(user.name.asc).offset(10), + pg: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', + string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' + }, + mysql: { + text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', + string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' + }, + params: [] }); Harness.test({ - query : user.select(user.star()).where({name: 'John'}).offset(user.subQuery().select('FLOOR(RANDOM() * COUNT(*))').where({name: 'John'})).limit(1), - pg : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', - sqlite: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', - mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT 1', + query: user.select(user.star()).where({ + name: 'John' + }).offset(user.subQuery().select('FLOOR(RANDOM() * COUNT(*))').where({ + name: 'John' + })).limit(1), + pg: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', + string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' + }, + sqlite: { + text: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', + string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' + }, + mysql: { + 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' + }, values: ['John', 'John'] }); diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 077d1eb0..9785b517 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -1,56 +1,106 @@ 'use strict'; var Harness = require('./support'); -var Table = require(__dirname + '/../../lib/table'); +var Table = require('../../lib/table'); var user = Harness.defineUserTable(); var post = Harness.definePostTable(); var u = user.as('u'); Harness.test({ - query : u.select(u.name).from(u), - pg :'SELECT "u"."name" FROM "user" AS "u"', - sqlite:'SELECT "u"."name" FROM "user" AS "u"', - mysql :'SELECT `u`.`name` FROM `user` AS `u`' + query: u.select(u.name).from(u), + pg: { + text: 'SELECT "u"."name" FROM "user" AS "u"', + string: 'SELECT "u"."name" FROM "user" AS "u"' + }, + sqlite: { + text: 'SELECT "u"."name" FROM "user" AS "u"', + string: 'SELECT "u"."name" FROM "user" AS "u"' + }, + mysql: { + text: 'SELECT `u`.`name` FROM `user` AS `u`', + string: 'SELECT `u`.`name` FROM `user` AS `u`' + }, + params: [] }); Harness.test({ - query : u.select(u.star()).from(u), - pg : 'SELECT "u".* FROM "user" AS "u"', - sqlite: 'SELECT "u".* FROM "user" AS "u"', - mysql : 'SELECT `u`.* FROM `user` AS `u`' + query: u.select(u.star()).from(u), + pg: { + text: 'SELECT "u".* FROM "user" AS "u"', + string: 'SELECT "u".* FROM "user" AS "u"' + }, + sqlite: { + text: 'SELECT "u".* FROM "user" AS "u"', + string: 'SELECT "u".* FROM "user" AS "u"' + }, + mysql: { + text: 'SELECT `u`.* FROM `user` AS `u`', + string: 'SELECT `u`.* FROM `user` AS `u`' + }, + params: [] }); var p = post.as('p'); Harness.test({ - query : u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), - pg : 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', - sqlite: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', - mysql : 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = ?))', - params : [3] + query: u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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] }); Harness.test({ - query : u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), - pg : '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))', - sqlite: '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))', - mysql : '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))' + query: u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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: [] }); // the quote property isn't implemented for columns, so all columns are quoted in generated queries var comment = Table.define({ name: 'comment', columns: [{ - name: 'text', - quote: true - }, { - name: 'userId', - quote: false - }] + name: 'text', + quote: true + }, { + name: 'userId', + quote: false + } + ] }); Harness.test({ - query : comment.select(comment.text, comment.userId), - pg : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', - sqlite: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', - mysql : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' + query: comment.select(comment.text, comment.userId), + pg: { + text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + }, + sqlite: { + text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' + }, + mysql: { + text: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', + string: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' + }, + params: [] }); diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index fea76528..2a8a3fe1 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -4,29 +4,69 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.select(post.content).order(post.content), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', - mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' + query: post.select(post.content).order(post.content), + pg: { + text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' + }, + 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`' + }, + params: [] }); Harness.test({ - query : post.select(post.content).order(post.content, post.userId.descending), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + query: post.select(post.content).order(post.content, post.userId.descending), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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: [] }); Harness.test({ - query : post.select(post.content).order(post.content.asc, post.userId.desc), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + query: post.select(post.content).order(post.content.asc, post.userId.desc), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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: [] }); Harness.test({ - query : post.select(post.content).order([post.content, post.userId.descending]), - pg : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - sqlite: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', - mysql : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC' + query: post.select(post.content).order([post.content, post.userId.descending]), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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: [] }); diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index 347cea7b..157478eb 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -7,29 +7,59 @@ var userWithSchema = Table.define({ schema: 'staging', name: 'user', quote: true, - columns: ['id','name'] + columns: ['id', 'name'] }); Harness.test({ - query : userWithSchema.select(userWithSchema.id).from(userWithSchema), - pg : 'SELECT "staging"."user"."id" FROM "staging"."user"', - sqlite: 'SELECT "staging"."user"."id" FROM "staging"."user"', - mysql : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' + query: userWithSchema.select(userWithSchema.id).from(userWithSchema), + pg: { + text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id" FROM "staging"."user"' + }, + sqlite: { + text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id" FROM "staging"."user"' + }, + mysql: { + text: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', + string: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' + }, + params: [] }); Harness.test({ - query : userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), - pg : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', - sqlite: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', - mysql : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' + query: userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), + pg: { + text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + }, + sqlite: { + text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' + }, + mysql: { + text: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', + string: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' + }, + params: [] }); var uws = userWithSchema.as('uws'); Harness.test({ - query : uws.select(uws.name).from(uws), - pg :'SELECT "uws"."name" FROM "staging"."user" AS "uws"', - sqlite:'SELECT "uws"."name" FROM "staging"."user" AS "uws"', - mysql :'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' + query: uws.select(uws.name).from(uws), + pg: { + text: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' + }, + sqlite: { + text: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' + }, + mysql: { + text: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', + string: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' + }, + params: [] }); var postWithSchema = Table.define({ @@ -39,15 +69,35 @@ var postWithSchema = Table.define({ }); Harness.test({ - query : userWithSchema.select(userWithSchema.name, postWithSchema.content).from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), - pg : 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', - sqlite: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', - mysql : 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)' + query: userWithSchema.select(userWithSchema.name, postWithSchema.content).from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), + pg: { + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); Harness.test({ - query : uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), - pg : 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', - sqlite: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', - mysql : 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)' + query: uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), + pg: { + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index fa12846e..4dbc3a82 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -4,8 +4,18 @@ var Harness = require('./support'); var post = Harness.definePostTable(); Harness.test({ - query : post.select(post.id).select(post.content), - pg : 'SELECT "post"."id", "post"."content" FROM "post"', - sqlite: 'SELECT "post"."id", "post"."content" FROM "post"', - mysql : 'SELECT `post`.`id`, `post`.`content` FROM `post`' + query: post.select(post.id).select(post.content), + pg: { + text: 'SELECT "post"."id", "post"."content" FROM "post"', + string: 'SELECT "post"."id", "post"."content" FROM "post"' + }, + sqlite: { + text: 'SELECT "post"."id", "post"."content" FROM "post"', + string: 'SELECT "post"."id", "post"."content" FROM "post"' + }, + mysql: { + text: 'SELECT `post`.`id`, `post`.`content` FROM `post`', + string: 'SELECT `post`.`id`, `post`.`content` FROM `post`' + }, + params: [] }); diff --git a/test/dialects/shortcut-tests.js b/test/dialects/shortcut-tests.js index 188326e6..f172a244 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -6,48 +6,108 @@ var post = Harness.definePostTable(); // shortcut: 'select * from
' Harness.test({ - query : user, - pg : 'SELECT "user".* FROM "user"', - sqlite: 'SELECT "user".* FROM "user"', - mysql : 'SELECT `user`.* FROM `user`' + query: user, + pg: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user`', + string: 'SELECT `user`.* FROM `user`' + }, + params: [] }); Harness.test({ - query : user.where(user.name.equals(3)), - pg : 'SELECT * FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', - params : [3] + query: user.where(user.name.equals(3)), + pg: { + text: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' + }, + mysql: { + text: 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', + string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' + }, + params: [3] }); Harness.test({ - query : user.where(user.name.equals(3)).where(user.id.equals(1)), - pg : 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - sqlite: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - mysql : 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', - params: [3,1] + query: user.where(user.name.equals(3)).where(user.id.equals(1)), + pg: { + text: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' + }, + sqlite: { + text: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' + }, + mysql: { + 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] }); // shortcut: no 'from' Harness.test({ - query : post.select(post.content), - pg : 'SELECT "post"."content" FROM "post"', - sqlite: 'SELECT "post"."content" FROM "post"', - mysql : 'SELECT `post`.`content` FROM `post`' + query: post.select(post.content), + 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`' + }, + params: [] }); Harness.test({ - query : post.select(post.content).where(post.userId.equals(1)), - pg : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', - sqlite: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', - mysql : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', + query: post.select(post.content).where(post.userId.equals(1)), + pg: { + text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' + }, + sqlite: { + text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' + }, + mysql: { + text: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', + string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' + }, params: [1] }); Harness.test({ - query : post.where(post.content.isNull()).or({content: ''}).and({userId: 1}), - pg : 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', - sqlite: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', - mysql : 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = ?)) AND (`post`.`userId` = ?))', + query: post.where(post.content.isNull()).or({ + content: '' + }).and({ + userId: 1 + }), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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] }); diff --git a/test/dialects/support.js b/test/dialects/support.js index 86e30f7a..6c3e6baf 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -13,7 +13,6 @@ var dialects = { module.exports = { test: function(expected) { - // for each dialect Object.keys(dialects).forEach(function(dialect) { var expectedObject = expected[dialect]; @@ -26,13 +25,10 @@ module.exports = { // check if this query is expected to throw if (expectedObject.throws) { - assert.throws(function() { new DialectClass().getQuery(expected.query); }); - } else { - // build query for dialect var compiledQuery = new DialectClass().getQuery(expected.query); @@ -42,13 +38,12 @@ module.exports = { // if params are specified then test these are correct var expectedParams = expectedObject.params || expected.params; - if (expectedParams) { + if (undefined !== expectedParams) { assert.equal(expectedParams.length, compiledQuery.values.length, 'params length'); for (var i = 0; i < expectedParams.length; i++) { assert.equal(expectedParams[i], compiledQuery.values[i], 'param ' + (i + 1)); } } - } if (undefined !== expectedObject.string) { @@ -64,12 +59,9 @@ module.exports = { assert.equal(compiledString, expectedObject.string); } } - }); - } // if }); // forEach - }, defineUserTable: function() { diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index c2ec86a0..ab40862f 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -4,187 +4,404 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); Harness.test({ - query : user.select(user.id).from(user), - pg : 'SELECT "user"."id" FROM "user"', - sqlite: 'SELECT "user"."id" FROM "user"', - mysql : 'SELECT `user`.`id` FROM `user`' + query: user.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`' + }, + params: [] }); Harness.test({ - query : user.select(user.id, user.name).from(user), - pg : 'SELECT "user"."id", "user"."name" FROM "user"', - sqlite: 'SELECT "user"."id", "user"."name" FROM "user"', - mysql : 'SELECT `user`.`id`, `user`.`name` FROM `user`' + query: user.select(user.id, user.name).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + params: [] }); Harness.test({ - query : user.select(user.star()).from(user), - pg : 'SELECT "user".* FROM "user"', - sqlite: 'SELECT "user".* FROM "user"', - mysql : 'SELECT `user`.* FROM `user`' + query: user.select(user.star()).from(user), + pg: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + sqlite: { + text: 'SELECT "user".* FROM "user"', + string: 'SELECT "user".* FROM "user"' + }, + mysql: { + text: 'SELECT `user`.* FROM `user`', + string: 'SELECT `user`.* FROM `user`' + }, + params: [] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.equals('foo')), - pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + query: user.select(user.id).from(user).where(user.name.equals('foo')), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' + }, + mysql: { + text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'foo\')' + }, params: ['foo'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.equals('foo').or(user.name.equals('bar'))), - pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', + query: user.select(user.id).from(user).where(user.name.equals('foo').or(user.name.equals('bar'))), + pg: { + 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\'))' + }, + sqlite: { + 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\'))' + }, + mysql: { + 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'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.equals('foo').and(user.name.equals('bar'))), - pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', + query: user.select(user.id).from(user).where(user.name.equals('foo').and(user.name.equals('bar'))), + pg: { + 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\'))' + }, + sqlite: { + 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\'))' + }, + mysql: { + 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'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('bar')), - pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))' + query: user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('bar')), + pg: { + 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\'))' + }, + sqlite: { + 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\'))' + }, + mysql: { + 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'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('baz')).and(user.name.equals('bar')), - pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))' + query: user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('baz')).and(user.name.equals('bar')), + pg: { + 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\'))' + }, + sqlite: { + 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\'))' + }, + mysql: { + 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'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar'])), - pg : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', + query: user.select(user.id).from(user).where(user.name.in(['foo', 'bar'])), + pg: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' + }, + sqlite: { + text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' + }, + mysql: { + 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'] }); Harness.test({ - query : user.select(user.id).from(user).where(user.name['in'](['foo', 'bar']).and(user.id.equals(1))), - pg : 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', + query: user.select(user.id).from(user).where(user.name.in(['foo', 'bar']).and(user.id.equals(1))), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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] }); Harness.test({ - query : user.select(user.columns), - pg : 'SELECT "user"."id", "user"."name" FROM "user"', - sqlite: 'SELECT "user"."id", "user"."name" FROM "user"', - mysql : 'SELECT `user`.`id`, `user`.`name` FROM `user`', + query: user.select(user.columns), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, params: [] }); Harness.test({ - query : user + query: user .select(user.id) .from(user) .where( - user.name.equals('boom') - .and(user.id.equals(1)) - ).or( - user.name.equals('bang').and(user.id.equals(2)) - ), - pg : 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', - sqlite: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', - mysql : 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) AND (`user`.`id` = ?)) OR ((`user`.`name` = ?) AND (`user`.`id` = ?)))', - params: ['boom', 1, 'bang', 2] + user.name.equals('boom') + .and(user.id.equals(1))).or( + user.name.equals('bang').and(user.id.equals(2))), + pg: { + 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)))' + }, + sqlite: { + 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)))' + }, + mysql: { + 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] }); Harness.test({ - query : user.select(user.name.as('user name'), user.id.as('user id')).from(user), - pg : 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', - sqlite: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', - mysql : 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`' + query: user.select(user.name.as('user name'), user.id.as('user id')).from(user), + pg: { + 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"' + }, + sqlite: { + 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"' + }, + mysql: { + 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: [] }); Harness.test({ - query : user.select(user.name.as('user name')).from(user).where(user.name.equals('brian')), - pg : 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', + query: user.select(user.name.as('user name')).from(user).where(user.name.equals('brian')), + pg: { + 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\')' + }, + sqlite: { + 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\')' + }, + mysql: { + 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'] }); Harness.test({ - query : user.select(user.name).from(user).where(user.name.equals('brian')), - pg : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', - sqlite: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', - mysql : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)' + query: user.select(user.name).from(user).where(user.name.equals('brian')), + pg: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + sqlite: { + text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' + }, + mysql: { + text: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', + string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = \'brian\')' + }, + params: ['brian'] }); Harness.test({ - query : user.select('name').from('user').where('name <> NULL'), - pg : 'SELECT name FROM user WHERE (name <> NULL)', - sqlite: 'SELECT name FROM user WHERE (name <> NULL)', - mysql : 'SELECT name FROM user WHERE (name <> NULL)', + query: user.select('name').from('user').where('name <> NULL'), + pg: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + sqlite: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, + mysql: { + text: 'SELECT name FROM user WHERE (name <> NULL)', + string: 'SELECT name FROM user WHERE (name <> NULL)' + }, params: [] }); Harness.test({ - query : user.select('name,id').from('user').where('name <> NULL'), - pg : 'SELECT name,id FROM user WHERE (name <> NULL)', - sqlite: 'SELECT name,id FROM user WHERE (name <> NULL)', - mysql : 'SELECT name,id FROM user WHERE (name <> NULL)', + query: user.select('name,id').from('user').where('name <> NULL'), + pg: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + sqlite: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, + mysql: { + text: 'SELECT name,id FROM user WHERE (name <> NULL)', + string: 'SELECT name,id FROM user WHERE (name <> NULL)' + }, params: [] }); Harness.test({ - query : user.select('name','id').from('user').where('name <> NULL'), - pg : 'SELECT name, id FROM user WHERE (name <> NULL)', - sqlite: 'SELECT name, id FROM user WHERE (name <> NULL)', - mysql : 'SELECT name, id FROM user WHERE (name <> NULL)', + query: user.select('name', 'id').from('user').where('name <> NULL'), + pg: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + sqlite: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, + mysql: { + text: 'SELECT name, id FROM user WHERE (name <> NULL)', + string: 'SELECT name, id FROM user WHERE (name <> NULL)' + }, params: [] }); Harness.test({ - query : user.select('name','id').from('user').where('name <> NULL').and('id <> NULL'), - pg : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - sqlite: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', - mysql : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + query: user.select('name', 'id').from('user').where('name <> NULL').and('id <> NULL'), + pg: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + sqlite: { + text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' + }, + mysql: { + 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: [] }); Harness.test({ - query : user.select('name').from('user').where({name: 'brian'}), - pg : 'SELECT name FROM user WHERE ("user"."name" = $1)', - sqlite: 'SELECT name FROM user WHERE ("user"."name" = $1)', - mysql : 'SELECT name FROM user WHERE (`user`.`name` = ?)', + query: user.select('name').from('user').where({ + name: 'brian' + }), + pg: { + text: 'SELECT name FROM user WHERE ("user"."name" = $1)', + string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' + }, + sqlite: { + text: 'SELECT name FROM user WHERE ("user"."name" = $1)', + string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' + }, + mysql: { + text: 'SELECT name FROM user WHERE (`user`.`name` = ?)', + string: 'SELECT name FROM user WHERE (`user`.`name` = \'brian\')' + }, params: ['brian'] }); Harness.test({ - query : user.select('name').from('user').where({name: 'brian', id: 1}), - pg : 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - sqlite: 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', - mysql : 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + query: user.select('name').from('user').where({ + name: 'brian', + id: 1 + }), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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] }); Harness.test({ - query : user.select(user.name.as('quote"quote"tick`tick`')), - pg : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', - sqlite: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', - mysql : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', + query: user.select(user.name.as('quote"quote"tick`tick`')), + pg: { + text: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', + string: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`' + }, params: [] }); Harness.test({ - query : user.select(user.star()).where(user.id['in'](user.subQuery().select(user.id))), - pg : 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', - sqlite: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', - mysql : 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', + query: user.select(user.star()).where(user.id.in(user.subQuery().select(user.id))), + pg: { + 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"))' + }, + sqlite: { + 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"))' + }, + mysql: { + 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 887c7fad..ce1f539e 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -6,17 +6,35 @@ var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); Harness.test({ - query : customer.select().where(customer.age.between(18, 25)), - pg : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', - sqlite: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', - mysql : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', + query: customer.select().where(customer.age.between(18, 25)), + pg: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' + }, + sqlite: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' + }, + mysql: { + 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] }); Harness.test({ - query : post.select().where(post.userId.between(customer.subQuery().select(customer.id.min()), customer.subQuery().select(customer.id.max()))), - pg : '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"))', - sqlite: '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"))', - mysql : '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`))', + query: post.select().where(post.userId.between(customer.subQuery().select(customer.id.min()), customer.subQuery().select(customer.id.max()))), + pg: { + 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"))' + }, + sqlite: { + 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"))' + }, + mysql: { + 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: [] }); diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js index 34a18f86..5654df58 100644 --- a/test/dialects/unary-clause-tests.js +++ b/test/dialects/unary-clause-tests.js @@ -6,17 +6,35 @@ var post = Harness.definePostTable(); var Table = require(__dirname + '/../../lib/table'); Harness.test({ - query : customer.select().where(customer.age.isNotNull()), - pg : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', - sqlite: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', - mysql : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', + query: customer.select().where(customer.age.isNotNull()), + pg: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' + }, + sqlite: { + text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' + }, + mysql: { + text: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', + string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)' + }, params: [] }); Harness.test({ - query : post.select().where(post.userId.in(customer.subQuery().select(customer.id).where(customer.age.isNull()))), - pg : 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', - sqlite: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', - mysql : 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', + query: post.select().where(post.userId. in (customer.subQuery().select(customer.id).where(customer.age.isNull()))), + pg: { + 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)))' + }, + sqlite: { + 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)))' + }, + mysql: { + 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 1e649fd7..c97d9c95 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -5,50 +5,119 @@ var post = Harness.definePostTable(); var user = Harness.defineUserTable(); Harness.test({ - query : post.update({content: 'test'}), - pg : 'UPDATE "post" SET "content" = $1', - sqlite: 'UPDATE "post" SET "content" = $1', - mysql : 'UPDATE `post` SET `content` = ?', + query: post.update({ + content: 'test' + }), + pg: { + text: 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = \'test\'' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = \'test\'' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?', + string: 'UPDATE `post` SET `content` = \'test\'' + }, params: ['test'] }); Harness.test({ - query : post.update({content: 'test', userId: 3}), - pg : 'UPDATE "post" SET "content" = $1, "userId" = $2', - sqlite: 'UPDATE "post" SET "content" = $1, "userId" = $2', - mysql : 'UPDATE `post` SET `content` = ?, `userId` = ?', + query: post.update({ + content: 'test', + userId: 3 + }), + pg: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?, `userId` = ?', + string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3' + }, params: ['test', 3] }); Harness.test({ - query : post.update({content: null, userId: 3}), - pg : 'UPDATE "post" SET "content" = $1, "userId" = $2', - sqlite: 'UPDATE "post" SET "content" = $1, "userId" = $2', - mysql : 'UPDATE `post` SET `content` = ?, `userId` = ?', + query: post.update({ + content: null, + userId: 3 + }), + pg: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' + }, + mysql: { + text: 'UPDATE `post` SET `content` = ?, `userId` = ?', + string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' + }, params: [null, 3] }); Harness.test({ - query : post.update({content: 'test', userId: 3}).where(post.content.equals('no')), - pg : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', - sqlite: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', - mysql : 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', + query: post.update({ + content: 'test', + userId: 3 + }).where(post.content.equals('no')), + pg: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' + }, + sqlite: { + text: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' + }, + mysql: { + 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'] }); Harness.test({ - query : post.update({content: user.name}).from(user).where(post.userId.equals(user.id)), - sqlite: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', - pg : 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', - mysql : 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', + query: post.update({ + content: user.name + }).from(user).where(post.userId.equals(user.id)), + sqlite: { + 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")' + }, + pg: { + 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")' + }, + mysql: { + 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: [] }); // update() needs to prefix ambiguous source columns; prefixing target columns is not allowed Harness.test({ - query : post.update({userId: user.id}).from(user).where(post.userId.equals(user.id)), - pg : 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', - sqlite: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', - mysql : 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', + query: post.update({ + userId: user.id + }).from(user).where(post.userId.equals(user.id)), + pg: { + 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")' + }, + sqlite: { + 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")' + }, + mysql: { + 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: [] }); diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 8db4504a..6c694954 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -6,37 +6,73 @@ var v = Harness.defineVariableTable(); // Test composition of binary methods +, *, -, =. Harness.test({ - query : customer.select(customer.name, customer.income.modulo(100)).where(customer.age.plus(5).multiply(customer.age.minus(2)).equals(10)), - pg : 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', - sqlite: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', - mysql : 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', + query: customer.select(customer.name, customer.income.modulo(100)).where(customer.age.plus(5).multiply(customer.age.minus(2)).equals(10)), + pg: { + 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)' + }, + sqlite: { + 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)' + }, + mysql: { + 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] }); // Test composition of binary (e.g. +) and unary (e.g. like) methods. Harness.test({ - query : customer.select(customer.name).where(customer.name.like(customer.id.plus('hello'))), - pg : 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', - sqlite: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', - mysql : 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', + query: customer.select(customer.name).where(customer.name.like(customer.id.plus('hello'))), + pg: { + 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\'))' + }, + sqlite: { + 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\'))' + }, + mysql: { + 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'] }); // Test implementing simple formulas. // Acceleration formula. (a * t^2 / 2) + (v * t) = d Harness.test({ - query : v.select(v.a.multiply(v.a).divide(2).plus(v.v.multiply(v.t)).equals(v.d)), - pg : 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', - sqlite: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("variable"."v" * "variable"."t")) = "variable"."d") FROM "variable"', - mysql : 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', + query: v.select(v.a.multiply(v.a).divide(2).plus(v.v.multiply(v.t)).equals(v.d)), + pg: { + 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"' + }, + sqlite: { + 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"' + }, + mysql: { + 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] }); // Pythagorean theorem. a^2 + b^2 = c^2. Harness.test({ - query : v.select(v.a.multiply(v.a).plus(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), - pg : 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', - sqlite: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', - mysql : 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', + query: v.select(v.a.multiply(v.a).plus(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), + pg: { + 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"' + }, + sqlite: { + 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"' + }, + mysql: { + 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: [] }); diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index e9bcc7f4..01f12417 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -4,15 +4,35 @@ var Harness = require('./support'); var user = Harness.defineUserTable(); Harness.test({ - query : user.where(user.id.isNotNull(), user.name.isNotNull()), - pg : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - mysql : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', - sqlite: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + 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: [] }); Harness.test({ - query : user.and(user.id.isNotNull(), user.name.isNotNull()), - pg : 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', - mysql : 'SELECT * FROM `user` WHERE ((`user`.`id` IS NOT NULL) AND (`user`.`name` IS NOT NULL))', - sqlite: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))' + query: user.and(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: [] }); From 8161d65b3fe2708c26a80f00aa53ad32f44a7a57 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 15 Jun 2013 20:29:03 -0700 Subject: [PATCH 168/507] optional travis build for node v0.11 --- .travis.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d523c5f5..b02f3658 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,11 @@ language: node_js node_js: - - 0.4 - - 0.6 - - 0.8 - - 0.10 + - "0.4" + - "0.6" + - "0.8" + - "0.10" + - "0.11" + +matrix: + allow_failures: + - node_js: "0.11" From 2b97a4b74ee35de4706a181503ac97518894a013 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 15 Jun 2013 22:54:34 -0700 Subject: [PATCH 169/507] dialect test alignment change for readability --- test/dialects/aggregate-tests.js | 108 +++++++++---------- test/dialects/alias-tests.js | 18 ++-- test/dialects/alter-table-tests.js | 66 ++++++------ test/dialects/binary-clause-tests.js | 18 ++-- test/dialects/clause-ordering-tests.js | 24 ++--- test/dialects/create-table-tests.js | 30 +++--- test/dialects/delete-tests.js | 24 ++--- test/dialects/distinct-tests.js | 12 +-- test/dialects/drop-table-tests.js | 12 +-- test/dialects/from-clause-tests.js | 6 +- test/dialects/group-by-tests.js | 30 +++--- test/dialects/having-tests.js | 18 ++-- test/dialects/indexes-tests.js | 54 +++++----- test/dialects/insert-tests.js | 84 +++++++-------- test/dialects/join-tests.js | 36 +++---- test/dialects/join-to-tests.js | 18 ++-- test/dialects/limit-and-offset-tests.js | 24 ++--- test/dialects/namespace-tests.js | 30 +++--- test/dialects/order-tests.js | 24 ++--- test/dialects/schema-tests.js | 30 +++--- test/dialects/select-tests.js | 6 +- test/dialects/shortcut-tests.js | 36 +++---- test/dialects/table-tests.js | 138 ++++++++++++------------ test/dialects/ternary-clause-tests.js | 12 +-- test/dialects/unary-clause-tests.js | 12 +-- test/dialects/update-tests.js | 36 +++---- test/dialects/value-expression-tests.js | 24 ++--- test/dialects/where-clause-tests.js | 12 +-- 28 files changed, 471 insertions(+), 471 deletions(-) diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index fb80f353..84c38873 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -8,15 +8,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.select(post.count()), pg: { - text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' }, sqlite: { - text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' }, mysql: { - text: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', + text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' }, params: [] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: post.select(post.count('post_count')), pg: { - text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' }, sqlite: { - text: 'SELECT COUNT("post".*) AS "post_count" FROM "post"', + text : 'SELECT COUNT("post".*) AS "post_count" FROM "post"', string: 'SELECT COUNT("post".*) AS "post_count" FROM "post"' }, msyql: { - text: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', + text : 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_count` FROM `post`' }, params: [] @@ -42,15 +42,15 @@ Harness.test({ Harness.test({ query: post.select(post.count().as('post_amount')), pg: { - text: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + text : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' }, sqlite: { - text: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', + text : 'SELECT COUNT("post".*) AS "post_amount" FROM "post"', string: 'SELECT COUNT("post".*) AS "post_amount" FROM "post"' }, mysql: { - text: 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', + text : 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`', string: 'SELECT COUNT(`post`.*) AS `post_amount` FROM `post`' }, params: [] @@ -59,15 +59,15 @@ Harness.test({ Harness.test({ query: post.select(post.content.count()), pg: { - text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' }, sqlite: { - text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' }, mysql: { - text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, params: [] @@ -76,15 +76,15 @@ Harness.test({ Harness.test({ query: post.select(post.content.count('content_count')), pg: { - text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' }, sqlite: { - text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' }, mysql: { - text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, params: [] @@ -93,15 +93,15 @@ Harness.test({ Harness.test({ query: post.select(post.content.count().as('content_count')), pg: { - text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' }, sqlite: { - text: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', + text : 'SELECT COUNT("post"."content") AS "content_count" FROM "post"', string: 'SELECT COUNT("post"."content") AS "content_count" FROM "post"' }, mysql: { - text: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', + text : 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`', string: 'SELECT COUNT(`post`.`content`) AS `content_count` FROM `post`' }, params: [] @@ -110,15 +110,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.min()), pg: { - text: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + text : 'SELECT MIN("post"."id") AS "id_min" FROM "post"', string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' }, sqlite: { - text: 'SELECT MIN("post"."id") AS "id_min" FROM "post"', + text : 'SELECT MIN("post"."id") AS "id_min" FROM "post"', string: 'SELECT MIN("post"."id") AS "id_min" FROM "post"' }, mysql: { - text: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', + text : 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `id_min` FROM `post`' }, params: [] @@ -127,15 +127,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.min().as('min_id')), pg: { - text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' }, sqlite: { - text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' }, mysql: { - text: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' }, params: [] @@ -144,15 +144,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.min('min_id')), pg: { - text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' }, sqlite: { - text: 'SELECT MIN("post"."id") AS "min_id" FROM "post"', + text : 'SELECT MIN("post"."id") AS "min_id" FROM "post"', string: 'SELECT MIN("post"."id") AS "min_id" FROM "post"' }, mysql: { - text: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', + text : 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`', string: 'SELECT MIN(`post`.`id`) AS `min_id` FROM `post`' }, params: [] @@ -161,15 +161,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.max()), pg: { - text: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + text : 'SELECT MAX("post"."id") AS "id_max" FROM "post"', string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' }, sqlite: { - text: 'SELECT MAX("post"."id") AS "id_max" FROM "post"', + text : 'SELECT MAX("post"."id") AS "id_max" FROM "post"', string: 'SELECT MAX("post"."id") AS "id_max" FROM "post"' }, mysql: { - text: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', + text : 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `id_max` FROM `post`' }, params: [] @@ -178,15 +178,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.max().as('max_id')), pg: { - text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' }, sqlite: { - text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' }, mysql: { - text: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' }, params: [] @@ -195,15 +195,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.max('max_id')), pg: { - text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' }, sqlite: { - text: 'SELECT MAX("post"."id") AS "max_id" FROM "post"', + text : 'SELECT MAX("post"."id") AS "max_id" FROM "post"', string: 'SELECT MAX("post"."id") AS "max_id" FROM "post"' }, mysql: { - text: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', + text : 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`', string: 'SELECT MAX(`post`.`id`) AS `max_id` FROM `post`' }, params: [] @@ -212,15 +212,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.sum()), pg: { - text: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + text : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' }, sqlite: { - text: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', + text : 'SELECT SUM("post"."id") AS "id_sum" FROM "post"', string: 'SELECT SUM("post"."id") AS "id_sum" FROM "post"' }, mysql: { - text: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', + text : 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `id_sum` FROM `post`' }, }); @@ -228,15 +228,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.sum().as('sum_id')), pg: { - text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' }, sqlite: { - text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' }, mysql: { - text: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' }, }); @@ -244,15 +244,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.sum('sum_id')), pg: { - text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' }, sqlite: { - text: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', + text : 'SELECT SUM("post"."id") AS "sum_id" FROM "post"', string: 'SELECT SUM("post"."id") AS "sum_id" FROM "post"' }, mysql: { - text: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', + text : 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`', string: 'SELECT SUM(`post`.`id`) AS `sum_id` FROM `post`' }, }); @@ -260,15 +260,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.avg()), pg: { - text: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + text : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' }, sqlite: { - text: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', + text : 'SELECT AVG("post"."id") AS "id_avg" FROM "post"', string: 'SELECT AVG("post"."id") AS "id_avg" FROM "post"' }, mysql: { - text: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', + text : 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `id_avg` FROM `post`' }, }); @@ -276,15 +276,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.avg().as('avg_id')), pg: { - text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' }, sqlite: { - text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' }, mysql: { - text: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + text : 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', string: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`' }, }); @@ -292,15 +292,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.avg('avg_id')), pg: { - text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' }, sqlite: { - text: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', + text : 'SELECT AVG("post"."id") AS "avg_id" FROM "post"', string: 'SELECT AVG("post"."id") AS "avg_id" FROM "post"' }, mysql: { - text: 'SELECT AVG(`post`.`id`) AS `avg_id` FROM `post`', + 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 6b41f5ff..e0fc8709 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -8,15 +8,15 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select(customer.name.isNull().as('nameIsNull')), pg: { - text: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + text : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' }, sqlite: { - text: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', + text : 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"', string: 'SELECT ("customer"."name" IS NULL) AS "nameIsNull" FROM "customer"' }, mysql: { - text: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', + text : 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`', string: 'SELECT (`customer`.`name` IS NULL) AS `nameIsNull` FROM `customer`' }, params: [] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: customer.select(customer.name.plus(customer.age).as('nameAndAge')).where(customer.age.gt(10).and(customer.age.lt(20))), pg: { - text: 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', + 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))' }, sqlite: { - text: 'SELECT ("customer"."name" + "customer"."age") AS "nameAndAge" FROM "customer" WHERE (("customer"."age" > $1) AND ("customer"."age" < $2))', + 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))' }, mysql: { - 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` > ?) AND (`customer`.`age` < ?))', string: 'SELECT (`customer`.`name` + `customer`.`age`) AS `nameAndAge` FROM `customer` WHERE ((`customer`.`age` > 10) AND (`customer`.`age` < 20))' }, params: [10, 20] @@ -42,15 +42,15 @@ Harness.test({ Harness.test({ query: customer.select(customer.age.between(10, 20).as('ageBetween')), pg: { - text: 'SELECT ("customer"."age" BETWEEN $1 AND $2) 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"' }, sqlite: { - text: 'SELECT ("customer"."age" BETWEEN $1 AND $2) 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"' }, mysql: { - text: 'SELECT (`customer`.`age` BETWEEN ? AND ?) AS `ageBetween` FROM `customer`', + 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] diff --git a/test/dialects/alter-table-tests.js b/test/dialects/alter-table-tests.js index 06befddc..71a5c396 100644 --- a/test/dialects/alter-table-tests.js +++ b/test/dialects/alter-table-tests.js @@ -7,15 +7,15 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: post.alter().dropColumn(post.content), pg: { - text: 'ALTER TABLE "post" DROP COLUMN "content"', + text : 'ALTER TABLE "post" DROP COLUMN "content"', string: 'ALTER TABLE "post" DROP COLUMN "content"' }, sqlite: { - text: 'Sqlite cannot drop columns', + text : 'Sqlite cannot drop columns', throws: true }, mysql: { - text: 'ALTER TABLE `post` DROP COLUMN `content`', + text : 'ALTER TABLE `post` DROP COLUMN `content`', string: 'ALTER TABLE `post` DROP COLUMN `content`' }, params: [] @@ -24,15 +24,15 @@ Harness.test({ Harness.test({ query: post.alter().dropColumn(post.content).dropColumn(post.userId), pg: { - text: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + text : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' }, sqlite: { - text: 'Sqlite cannot drop columns', + text : 'Sqlite cannot drop columns', throws: true }, mysql: { - text: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + text : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' }, params: [] @@ -41,15 +41,15 @@ Harness.test({ Harness.test({ query: post.alter().dropColumn('content').dropColumn('userId'), pg: { - text: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', + text : 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"', string: 'ALTER TABLE "post" DROP COLUMN "content", DROP COLUMN "userId"' }, sqlite: { - text: 'Sqlite cannot drop columns', + text : 'Sqlite cannot drop columns', throws: true }, mysql: { - text: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', + text : 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`', string: 'ALTER TABLE `post` DROP COLUMN `content`, DROP COLUMN `userId`' }, params: [] @@ -58,15 +58,15 @@ Harness.test({ Harness.test({ query: post.alter().rename('posts'), pg: { - text: 'ALTER TABLE "post" RENAME TO "posts"', + text : 'ALTER TABLE "post" RENAME TO "posts"', string: 'ALTER TABLE "post" RENAME TO "posts"' }, sqlite: { - text: 'ALTER TABLE "post" RENAME TO "posts"', + text : 'ALTER TABLE "post" RENAME TO "posts"', string: 'ALTER TABLE "post" RENAME TO "posts"' }, mysql: { - text: 'ALTER TABLE `post` RENAME TO `posts`', + text : 'ALTER TABLE `post` RENAME TO `posts`', string: 'ALTER TABLE `post` RENAME TO `posts`' }, params: [] @@ -87,15 +87,15 @@ var group = Table.define({ Harness.test({ query: group.alter().addColumn(group.id), pg: { - text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + text : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' }, sqlite: { - text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', + text : 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)', string: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100)' }, mysql: { - text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', + text : 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)', string: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100)' }, params: [] @@ -104,15 +104,15 @@ Harness.test({ Harness.test({ query: group.alter().addColumn(group.id).addColumn(group.userId), pg: { - text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + 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)' }, sqlite: { - text: 'Sqlite cannot add more than one column at a time', + text : 'Sqlite cannot add more than one column at a time', throws: true }, mysql: { - text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', + 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)' }, params: [] @@ -121,15 +121,15 @@ Harness.test({ Harness.test({ query: group.alter().addColumn('id', 'varchar(100)').addColumn('userId', 'varchar(100)'), pg: { - text: 'ALTER TABLE "group" ADD COLUMN "id" varchar(100), ADD COLUMN "userId" varchar(100)', + 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)' }, sqlite: { - text: 'Sqlite cannot add more than one column at a time', + text : 'Sqlite cannot add more than one column at a time', throws: true }, mysql: { - text: 'ALTER TABLE `group` ADD COLUMN `id` varchar(100), ADD COLUMN `userId` varchar(100)', + 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)' }, params: [] @@ -138,15 +138,15 @@ Harness.test({ Harness.test({ query: group.alter().renameColumn('userId', 'newUserId'), pg: { - text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + text : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' }, mysql: { - text: 'Mysql requires data type for renaming a column', + text : 'Mysql requires data type for renaming a column', throws: true }, sqlite: { - text: 'Sqlite cannot rename columns', + text : 'Sqlite cannot rename columns', throws: true }, params: [] @@ -155,15 +155,15 @@ Harness.test({ Harness.test({ query: group.alter().renameColumn(group.userId, 'newUserId'), pg: { - text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', + text : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"', string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "newUserId"' }, sqlite: { - text: 'Sqlite cannot rename columns', + text : 'Sqlite cannot rename columns', throws: true }, mysql: { - text: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', + text : 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)', string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `newUserId` varchar(100)' }, params: [] @@ -172,15 +172,15 @@ Harness.test({ Harness.test({ query: group.alter().renameColumn('userId', group.id), pg: { - text: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', + text : 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"', string: 'ALTER TABLE "group" RENAME COLUMN "userId" TO "id"' }, sqlite: { - text: 'Sqlite cannot rename columns', + text : 'Sqlite cannot rename columns', throws: true }, mysql: { - text: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', + text : 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)', string: 'ALTER TABLE `group` CHANGE COLUMN `userId` `id` varchar(100)' }, params: [] @@ -198,15 +198,15 @@ var UserWithSignature = Table.define({ Harness.test({ query: UserWithSignature.alter().renameColumn(UserWithSignature.get('Signature'), 'sig'), pg: { - text: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', + text : 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"', string: 'ALTER TABLE "UserWithSignature" RENAME COLUMN "Signature" TO "sig"' }, mysql: { - text: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'', + text : 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'', string: 'ALTER TABLE `UserWithSignature` CHANGE COLUMN `Signature` `sig` VARCHAR(255) NOT NULL DEFAULT \'Signature\'' }, sqlite: { - text: 'Sqlite cannot rename columns', + text : 'Sqlite cannot rename columns', throws: true } }); diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index 3a2d49b2..a2002225 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -8,15 +8,15 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select(customer.name.plus(customer.age)), pg: { - text: 'SELECT ("customer"."name" + "customer"."age") FROM "customer"', + 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"', + 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`', + text : 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`', string: 'SELECT (`customer`.`name` + `customer`.`age`) FROM `customer`' }, params: [] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: post.select(post.content.plus('!')).where(post.userId. in (customer.subQuery().select(customer.id))), pg: { - text: 'SELECT ("post"."content" + $1) 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"))' }, sqlite: { - text: 'SELECT ("post"."content" + $1) 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"))' }, mysql: { - text: 'SELECT (`post`.`content` + ?) FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer`))', + 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: ['!'] @@ -42,15 +42,15 @@ Harness.test({ Harness.test({ query: post.select(post.id.plus(': ').plus(post.content)).where(post.userId.notIn(customer.subQuery().select(customer.id))), pg: { - text: 'SELECT (("post"."id" + $1) + "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"))' }, sqlite: { - text: 'SELECT (("post"."id" + $1) + "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"))' }, mysql: { - text: 'SELECT ((`post`.`id` + ?) + `post`.`content`) FROM `post` WHERE (`post`.`userId` NOT IN (SELECT `customer`.`id` FROM `customer`))', + 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: [': '] diff --git a/test/dialects/clause-ordering-tests.js b/test/dialects/clause-ordering-tests.js index b211985a..8d957471 100644 --- a/test/dialects/clause-ordering-tests.js +++ b/test/dialects/clause-ordering-tests.js @@ -8,15 +8,15 @@ var post = Harness.definePostTable(); 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")', + 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")', }, sqlite: { - text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + 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")' }, mysql: { - text: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + 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`)' }, }); @@ -27,15 +27,15 @@ Harness.test({ name: '' }).from(user).select(user.id), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'\')' }, params: [''] @@ -50,15 +50,15 @@ Harness.test({ name: '' }), pg: { - text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', + 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" = \'\')' }, sqlite: { - text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId") WHERE ("user"."name" = $1)', + 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" = \'\')' }, mysql: { - 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` = ?)', string: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`) WHERE (`user`.`name` = \'\')' }, params: [''] @@ -70,15 +70,15 @@ Harness.test({ name: '' }), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'\')' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', 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 3d91238f..df2e1a27 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -18,15 +18,15 @@ var group = Table.define({ Harness.test({ query: group.create(), pg: { - text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + text : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' }, sqlite: { - text: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', + text : 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))', string: 'CREATE TABLE "group" ("id" varchar(100), "user_id" varchar(100))' }, mysql: { - text: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', + text : 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))', string: 'CREATE TABLE `group` (`id` varchar(100), `user_id` varchar(100))' }, params: [] @@ -35,15 +35,15 @@ Harness.test({ Harness.test({ query: group.create().ifNotExists(), pg: { - text: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', + 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))' }, sqlite: { - text: 'CREATE TABLE IF NOT EXISTS "group" ("id" varchar(100), "user_id" varchar(100))', + 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))' }, mysql: { - text: 'CREATE TABLE IF NOT EXISTS `group` (`id` varchar(100), `user_id` varchar(100))', + 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))' }, params: [] @@ -60,15 +60,15 @@ Harness.test({ engine: 'InnoDB' }).create(), pg: { - text: 'CREATE TABLE "user" ("id" varchar(100))', + text : 'CREATE TABLE "user" ("id" varchar(100))', string: 'CREATE TABLE "user" ("id" varchar(100))' }, sqlite: { - text: 'CREATE TABLE "user" ("id" varchar(100))', + text : 'CREATE TABLE "user" ("id" varchar(100))', string: 'CREATE TABLE "user" ("id" varchar(100))' }, mysql: { - text: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', + text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB', string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=InnoDB' } }); @@ -84,15 +84,15 @@ Harness.test({ charset: 'latin1' }).create(), pg: { - text: 'CREATE TABLE "user" ("id" varchar(100))', + text : 'CREATE TABLE "user" ("id" varchar(100))', string: 'CREATE TABLE "user" ("id" varchar(100))' }, sqlite: { - text: 'CREATE TABLE "user" ("id" varchar(100))', + text : 'CREATE TABLE "user" ("id" varchar(100))', string: 'CREATE TABLE "user" ("id" varchar(100))' }, mysql: { - text: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', + text : 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1', string: 'CREATE TABLE `user` (`id` varchar(100)) DEFAULT CHARSET=latin1' } }); @@ -109,15 +109,15 @@ Harness.test({ charset: 'latin1' }).create(), pg: { - text: 'CREATE TABLE "user" ("id" varchar(100))', + text : 'CREATE TABLE "user" ("id" varchar(100))', string: 'CREATE TABLE "user" ("id" varchar(100))' }, sqlite: { - text: 'CREATE TABLE "user" ("id" varchar(100))', + text : 'CREATE TABLE "user" ("id" varchar(100))', string: 'CREATE TABLE "user" ("id" varchar(100))' }, mysql: { - text: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1', + text : 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1', string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' } }); diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index f1bf6188..71c27d95 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.delete().where(post.content.equals("hello's world")), pg: { - text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' }, sqlite: { - text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', string: 'DELETE FROM "post" WHERE ("post"."content" = \'hello\'\'s world\')' }, mysql: { - text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'hello\'\'s world\')' }, params: ["hello's world"] @@ -25,15 +25,15 @@ Harness.test({ content: '' }), pg: { - text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' }, sqlite: { - text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' }, mysql: { - text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, params: [''] @@ -44,15 +44,15 @@ Harness.test({ content: '' }), pg: { - text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' }, sqlite: { - text: 'DELETE FROM "post" WHERE ("post"."content" = $1)', + text : 'DELETE FROM "post" WHERE ("post"."content" = $1)', string: 'DELETE FROM "post" WHERE ("post"."content" = \'\')' }, mysql: { - text: 'DELETE FROM `post` WHERE (`post`.`content` = ?)', + text : 'DELETE FROM `post` WHERE (`post`.`content` = ?)', string: 'DELETE FROM `post` WHERE (`post`.`content` = \'\')' }, params: [''] @@ -63,15 +63,15 @@ Harness.test({ content: '' }).or(post.content.isNull()), pg: { - text: 'DELETE FROM "post" WHERE (("post"."content" = $1) 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))' }, sqlite: { - text: 'DELETE FROM "post" WHERE (("post"."content" = $1) 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))' }, mysql: { - text: 'DELETE FROM `post` WHERE ((`post`.`content` = ?) OR (`post`.`content` IS NULL))', + 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: [''] diff --git a/test/dialects/distinct-tests.js b/test/dialects/distinct-tests.js index c584745f..5a767183 100644 --- a/test/dialects/distinct-tests.js +++ b/test/dialects/distinct-tests.js @@ -6,15 +6,15 @@ var user = Harness.defineUserTable(); Harness.test({ query: user.select(user.id.distinct()), pg: { - text: 'SELECT DISTINCT("user"."id") FROM "user"', + text : 'SELECT DISTINCT("user"."id") FROM "user"', string: 'SELECT DISTINCT("user"."id") FROM "user"' }, sqlite: { - text: 'SELECT DISTINCT("user"."id") FROM "user"', + text : 'SELECT DISTINCT("user"."id") FROM "user"', string: 'SELECT DISTINCT("user"."id") FROM "user"' }, mysql: { - text: 'SELECT DISTINCT(`user`.`id`) FROM `user`', + text : 'SELECT DISTINCT(`user`.`id`) FROM `user`', string: 'SELECT DISTINCT(`user`.`id`) FROM `user`' }, params: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: user.select(user.id.count().distinct().as('count')), pg: { - text: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', + text : 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' }, sqlite: { - text: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', + text : 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"', string: 'SELECT COUNT(DISTINCT("user"."id")) AS "count" FROM "user"' }, mysql: { - text: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', + text : 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`', string: 'SELECT COUNT(DISTINCT(`user`.`id`)) AS `count` FROM `user`' }, params: [] diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index eb5f78f9..6e8943b5 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.drop(), pg: { - text: 'DROP TABLE "post"', + text : 'DROP TABLE "post"', string: 'DROP TABLE "post"' }, sqlite: { - text: 'DROP TABLE "post"', + text : 'DROP TABLE "post"', string: 'DROP TABLE "post"' }, mysql: { - text: 'DROP TABLE `post`', + text : 'DROP TABLE `post`', string: 'DROP TABLE `post`' }, params: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: post.drop().ifExists(), pg: { - text: 'DROP TABLE IF EXISTS "post"', + text : 'DROP TABLE IF EXISTS "post"', string: 'DROP TABLE IF EXISTS "post"' }, sqlite: { - text: 'DROP TABLE IF EXISTS "post"', + text : 'DROP TABLE IF EXISTS "post"', string: 'DROP TABLE IF EXISTS "post"' }, mysql: { - text: 'DROP TABLE IF EXISTS `post`', + text : 'DROP TABLE IF EXISTS `post`', string: 'DROP TABLE IF EXISTS `post`' }, params: [] diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js index 318fa379..6e2534d7 100644 --- a/test/dialects/from-clause-tests.js +++ b/test/dialects/from-clause-tests.js @@ -7,15 +7,15 @@ var post = Harness.definePostTable(); Harness.test({ query: user.select(user.star()).from(user).from(post), pg: { - text: 'SELECT "user".* FROM "user" , "post"', + text : 'SELECT "user".* FROM "user" , "post"', string: 'SELECT "user".* FROM "user" , "post"' }, sqlite: { - text: 'SELECT "user".* FROM "user" , "post"', + text : 'SELECT "user".* FROM "user" , "post"', string: 'SELECT "user".* FROM "user" , "post"' }, mysql: { - text: 'SELECT `user`.* FROM `user` , `post`', + text : 'SELECT `user`.* FROM `user` , `post`', string: 'SELECT `user`.* FROM `user` , `post`' } }); diff --git a/test/dialects/group-by-tests.js b/test/dialects/group-by-tests.js index 33e6afd1..c9db48ed 100644 --- a/test/dialects/group-by-tests.js +++ b/test/dialects/group-by-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.select(post.content).group(post.userId), pg: { - text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"', string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId"' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', + text : 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`', string: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`' }, params: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: post.select(post.content).group(post.userId, post.id), pg: { - text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + 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: [] @@ -40,15 +40,15 @@ Harness.test({ Harness.test({ query: post.select(post.content.arrayAgg()).group(post.userId), pg: { - text: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + text : 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', string: 'SELECT array_agg("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"' }, sqlite: { - text: 'SELECT GROUP_CONCAT("post"."content") AS "contents" FROM "post" GROUP BY "post"."userId"', + 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"' }, mysql: { - text: 'SELECT GROUP_CONCAT(`post`.`content`) AS `contents` FROM `post` GROUP BY `post`.`userId`', + 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`' }, params: [] @@ -57,15 +57,15 @@ Harness.test({ Harness.test({ query: post.select(post.content.arrayAgg('post contents')).group(post.userId), pg: { - text: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + text : 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', string: 'SELECT array_agg("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"' }, sqlite: { - text: 'SELECT GROUP_CONCAT("post"."content") AS "post contents" FROM "post" GROUP BY "post"."userId"', + 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"' }, mysql: { - text: 'SELECT GROUP_CONCAT(`post`.`content`) AS `post contents` FROM `post` GROUP BY `post`.`userId`', + 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`' }, params: [] @@ -74,15 +74,15 @@ Harness.test({ Harness.test({ query: post.select(post.content).group([post.userId, post.id]), pg: { - text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', + text : 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"', string: 'SELECT "post"."content" FROM "post" GROUP BY "post"."userId", "post"."id"' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` GROUP BY `post`.`userId`, `post`.`id`', + 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 dff7144a..b06190e3 100644 --- a/test/dialects/having-tests.js +++ b/test/dialects/having-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10)), pg : { - text: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', + 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)' }, sqlite: { - text: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1)', + 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)' }, mysql : { - 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` > ?)', string: 'SELECT `post`.`userId`, COUNT(`post`.`content`) AS `content_count` FROM `post` GROUP BY `post`.`userId` HAVING (`post`.`userId` > 10)' }, params: [10] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query : post.select(post.userId, post.content.count()).group(post.userId).having(post.userId.gt(10), post.userId.lt(100)), pg : { - text: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + 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)' }, sqlite: { - text: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + 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)' }, mysql : { - 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` > ?) 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] @@ -40,15 +40,15 @@ Harness.test({ Harness.test({ query : post.select(post.userId, post.content.count()).group(post.userId).having([post.userId.gt(10), post.userId.lt(100)]), pg : { - text: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + 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)' }, sqlite: { - text: 'SELECT "post"."userId", COUNT("post"."content") AS "content_count" FROM "post" GROUP BY "post"."userId" HAVING ("post"."userId" > $1) AND ("post"."userId" < $2)', + 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)' }, mysql : { - 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` > ?) 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] diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 44a12a96..916b4eef 100644 --- a/test/dialects/indexes-tests.js +++ b/test/dialects/indexes-tests.js @@ -6,15 +6,15 @@ 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)', + 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)' }, mysql: { - text: 'SHOW INDEX FROM `post`', + text : 'SHOW INDEX FROM `post`', string: 'SHOW INDEX FROM `post`' }, sqlite: { - text: 'PRAGMA INDEX_LIST("post")', + text : 'PRAGMA INDEX_LIST("post")', string: 'PRAGMA INDEX_LIST("post")' }, params: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: post.indexes().create('index_name').unique().using('btree').on(post.id, post.userId).withParser('foo'), pg: { - text: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', + 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' }, mysql: { - text: 'CREATE UNIQUE INDEX `index_name` USING BTREE ON `post` (`id`,`userId`) WITH PARSER foo', + 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' }, sqlite: { - text: 'CREATE UNIQUE INDEX "index_name" USING BTREE ON "post" ("id","userId") WITH PARSER foo', + 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: [] @@ -40,15 +40,15 @@ Harness.test({ Harness.test({ query: post.indexes().create().fulltext().on(post.id), pg: { - text: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', + text : 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' }, mysql: { - text: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)', + text : 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)', string: 'CREATE FULLTEXT INDEX `post_id` ON `post` (`id`)' }, sqlite: { - text: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', + text : 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")', string: 'CREATE FULLTEXT INDEX "post_id" ON "post" ("id")' }, params: [] @@ -57,15 +57,15 @@ Harness.test({ Harness.test({ query: post.indexes().create().spatial().on(post.id), pg: { - text: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', + text : 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' }, mysql: { - text: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)', + text : 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)', string: 'CREATE SPATIAL INDEX `post_id` ON `post` (`id`)' }, sqlite: { - text: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', + text : 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")', string: 'CREATE SPATIAL INDEX "post_id" ON "post" ("id")' }, params: [] @@ -74,15 +74,15 @@ Harness.test({ Harness.test({ query: post.indexes().create().on(post.userId, post.id), pg: { - text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' }, mysql: { - text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', + text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' }, sqlite: { - text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' }, params: [] @@ -91,15 +91,15 @@ Harness.test({ Harness.test({ query: post.indexes().create().on(post.userId).on(post.id), pg: { - text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' }, mysql: { - text: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', + text : 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)', string: 'CREATE INDEX `post_id_userId` ON `post` (`userId`,`id`)' }, sqlite: { - text: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', + text : 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")', string: 'CREATE INDEX "post_id_userId" ON "post" ("userId","id")' }, params: [] @@ -108,15 +108,15 @@ Harness.test({ Harness.test({ query: post.indexes().create(), pg: { - text: 'No columns defined!', + text : 'No columns defined!', throws: true }, mysql: { - text: 'No columns defined!', + text : 'No columns defined!', throws: true }, sqlite: { - text: 'No columns defined!', + text : 'No columns defined!', throws: true } }); @@ -124,15 +124,15 @@ Harness.test({ Harness.test({ query: post.indexes().drop('index_name'), pg: { - text: 'DROP INDEX "index_name" ON "post"', + text : 'DROP INDEX "index_name" ON "post"', string: 'DROP INDEX "index_name" ON "post"' }, mysql: { - text: 'DROP INDEX `index_name` ON `post`', + text : 'DROP INDEX `index_name` ON `post`', string: 'DROP INDEX `index_name` ON `post`' }, sqlite: { - text: 'DROP INDEX "index_name" ON "post"', + text : 'DROP INDEX "index_name" ON "post"', string: 'DROP INDEX "index_name" ON "post"' }, params: [] @@ -141,15 +141,15 @@ Harness.test({ Harness.test({ query: post.indexes().drop(post.userId, post.id), pg: { - text: 'DROP INDEX "post_id_userId" ON "post"', + text : 'DROP INDEX "post_id_userId" ON "post"', string: 'DROP INDEX "post_id_userId" ON "post"' }, mysql: { - text: 'DROP INDEX `post_id_userId` ON `post`', + text : 'DROP INDEX `post_id_userId` ON `post`', string: 'DROP INDEX `post_id_userId` ON `post`' }, sqlite: { - text: 'DROP INDEX "post_id_userId" ON "post"', + text : 'DROP INDEX "post_id_userId" ON "post"', string: 'DROP INDEX "post_id_userId" ON "post"' }, params: [] diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 32cea8f6..8340faf4 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.insert(post.content.value('test'), post.userId.value(1)), pg: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' }, sqlite: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 1)' }, mysql: { - text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 1)' }, params: ['test', 1] @@ -24,15 +24,15 @@ Harness.test({ Harness.test({ query: post.insert(post.content.value('whoah')), pg: { - text: 'INSERT INTO "post" ("content") VALUES ($1)', + text : 'INSERT INTO "post" ("content") VALUES ($1)', string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' }, sqlite: { - text: 'INSERT INTO "post" ("content") VALUES ($1)', + text : 'INSERT INTO "post" ("content") VALUES ($1)', string: 'INSERT INTO "post" ("content") VALUES (\'whoah\')' }, mysql: { - text: 'INSERT INTO `post` (`content`) VALUES (?)', + text : 'INSERT INTO `post` (`content`) VALUES (?)', string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\')' }, params: ['whoah'] @@ -44,15 +44,15 @@ Harness.test({ userId: 2 }), pg: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' }, sqlite: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'test\', 2)' }, mysql: { - text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'test\', 2)' }, params: ['test', 2] @@ -67,15 +67,15 @@ Harness.test({ } ]), pg: { - text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' }, sqlite: { - text: 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', string: 'INSERT INTO "post" ("content") VALUES (\'whoah\'), (\'hey\')' }, mysql: { - text: 'INSERT INTO `post` (`content`) VALUES (?), (?)', + text : 'INSERT INTO `post` (`content`) VALUES (?), (?)', string: 'INSERT INTO `post` (`content`) VALUES (\'whoah\'), (\'hey\')' }, params: ['whoah', 'hey'] @@ -91,15 +91,15 @@ Harness.test({ } ]), pg: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' }, sqlite: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' }, mysql: { - text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' }, params: ['whoah', 1, 'hey', 2] @@ -116,15 +116,15 @@ Harness.test({ } ]), pg: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' }, sqlite: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, $4)', string: 'INSERT INTO "post" ("content", "userId") VALUES (\'whoah\', 1), (\'hey\', 2)' }, mysql: { - text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, ?)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', 2)' }, params: ['whoah', 1, 'hey', 2] @@ -133,15 +133,15 @@ Harness.test({ Harness.test({ query: post.insert({}), pg: { - text: 'INSERT INTO "post" DEFAULT VALUES', + text : 'INSERT INTO "post" DEFAULT VALUES', string: 'INSERT INTO "post" DEFAULT VALUES' }, sqlite: { - text: 'INSERT INTO "post" DEFAULT VALUES', + text : 'INSERT INTO "post" DEFAULT VALUES', string: 'INSERT INTO "post" DEFAULT VALUES' }, mysql: { - text: 'INSERT INTO `post` () VALUES ()', + text : 'INSERT INTO `post` () VALUES ()', string: 'INSERT INTO `post` () VALUES ()' }, params: [] @@ -150,15 +150,15 @@ Harness.test({ Harness.test({ query: post.insert({}).returning('*'), pg: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, sqlite: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, mysql: { - text: 'INSERT INTO `post` () VALUES () RETURNING *', + text : 'INSERT INTO `post` () VALUES () RETURNING *', string: 'INSERT INTO `post` () VALUES () RETURNING *' }, params: [] @@ -167,15 +167,15 @@ Harness.test({ Harness.test({ query: post.insert({}).returning(post.star()), pg: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, sqlite: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING *', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, mysql: { - text: 'INSERT INTO `post` () VALUES () RETURNING *', + text : 'INSERT INTO `post` () VALUES () RETURNING *', string: 'INSERT INTO `post` () VALUES () RETURNING *' }, params: [] @@ -184,15 +184,15 @@ Harness.test({ Harness.test({ query: post.insert({}).returning(post.id), pg: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' }, sqlite: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' }, mysql: { - text: 'INSERT INTO `post` () VALUES () RETURNING `id`', + text : 'INSERT INTO `post` () VALUES () RETURNING `id`', string: 'INSERT INTO `post` () VALUES () RETURNING `id`' }, params: [] @@ -201,15 +201,15 @@ Harness.test({ Harness.test({ query: post.insert({}).returning(post.id, post.content), pg: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' }, sqlite: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' }, mysql: { - text: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', + text : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', string: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`' }, params: [] @@ -218,15 +218,15 @@ Harness.test({ Harness.test({ query: post.insert({}).returning([post.id, post.content]), pg: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' }, sqlite: { - text: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', + text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' }, mysql: { - text: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', + text : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', string: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`' }, params: [] @@ -242,16 +242,16 @@ Harness.test({ } ]), pg: { - text: 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2), ($3, DEFAULT)', + 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'] }, sqlite: { - text: 'Sqlite requires the same number of columns in each insert row', + text : 'Sqlite requires the same number of columns in each insert row', throws: true }, mysql: { - text: 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?), (?, DEFAULT)', string: 'INSERT INTO `post` (`content`, `userId`) VALUES (\'whoah\', 1), (\'hey\', DEFAULT)', params: ['whoah', 1, 'hey'] } @@ -266,16 +266,16 @@ Harness.test({ } ]), pg: { - text: 'INSERT INTO "post" ("userId", "content") VALUES ($1, DEFAULT), ($2, $3)', + 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'] }, sqlite: { - text: 'Sqlite requires the same number of columns in each insert row', + text : 'Sqlite requires the same number of columns in each insert row', throws: true }, mysql: { - text: 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', + text : 'INSERT INTO `post` (`userId`, `content`) VALUES (?, DEFAULT), (?, ?)', string: 'INSERT INTO `post` (`userId`, `content`) VALUES (1, DEFAULT), (2, \'hey\')', params: [1, 2, 'hey'] } diff --git a/test/dialects/join-tests.js b/test/dialects/join-tests.js index 67c2d74e..d4e242af 100644 --- a/test/dialects/join-tests.js +++ b/test/dialects/join-tests.js @@ -8,15 +8,15 @@ var comment = Harness.defineCommentTable(); Harness.test({ query: user.select(user.name, post.content).from(user.join(post).on(user.id.equals(post.userId))), pg: { - text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + 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")' }, sqlite: { - text: 'SELECT "user"."name", "post"."content" FROM "user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + 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")' }, mysql: { - text: 'SELECT `user`.`name`, `post`.`content` FROM `user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + 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: [] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: user.join(post).on(user.id.equals(post.userId)), pg: { - text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' }, sqlite: { - text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', + text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")', string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."userId")' }, mysql: { - text: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', + text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)', string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`userId`)' }, params: [] @@ -47,15 +47,15 @@ Harness.test({ .join(post).on(user.id.equals(post.userId)) .join(comment).on(post.id.equals(comment.postId))), pg: { - 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")', + 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")' }, sqlite: { - 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")', + 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")' }, mysql: { - 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`)', + 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: [] @@ -64,15 +64,15 @@ Harness.test({ Harness.test({ query: user.select(user.name, post.content).from(user.leftJoin(post).on(user.id.equals(post.userId))), pg: { - text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + 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")' }, sqlite: { - text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId")', + 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")' }, mysql: { - text: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`)', + 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: [] @@ -86,15 +86,15 @@ Harness.test({ .leftJoin(post).on(user.id.equals(post.userId)) .leftJoin(comment).on(post.id.equals(comment.postId))), pg: { - text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + 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")' }, sqlite: { - text: 'SELECT "user"."name", "post"."content" FROM "user" LEFT JOIN "post" ON ("user"."id" = "post"."userId") LEFT JOIN "comment" ON ("post"."id" = "comment"."postId")', + 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")' }, mysql: { - text: 'SELECT `user`.`name`, `post`.`content` FROM `user` LEFT JOIN `post` ON (`user`.`id` = `post`.`userId`) LEFT JOIN `comment` ON (`post`.`id` = `comment`.`postId`)', + 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: [] @@ -113,15 +113,15 @@ 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")', + 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")', + 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`)', + 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/join-to-tests.js b/test/dialects/join-to-tests.js index b421eb38..5aca7e39 100644 --- a/test/dialects/join-to-tests.js +++ b/test/dialects/join-to-tests.js @@ -39,15 +39,15 @@ var post = sql.define({ Harness.test({ query: user.joinTo(post), pg: { - text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' }, sqlite: { - text: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', + text : '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")', string: '"user" INNER JOIN "post" ON ("user"."id" = "post"."ownerId")' }, mysql: { - text: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', + text : '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)', string: '`user` INNER JOIN `post` ON (`user`.`id` = `post`.`ownerId`)' }, params: [] @@ -56,15 +56,15 @@ Harness.test({ Harness.test({ query: post.joinTo(user), pg: { - text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + text : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' }, sqlite: { - text: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', + text : '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")', string: '"post" INNER JOIN "user" ON ("user"."id" = "post"."ownerId")' }, mysql: { - text: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', + text : '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)', string: '`post` INNER JOIN `user` ON (`user`.`id` = `post`.`ownerId`)' }, params: [] @@ -73,15 +73,15 @@ Harness.test({ Harness.test({ query: user.joinTo(photo), pg: { - text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + text : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' }, sqlite: { - text: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', + text : '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")', string: '"user" INNER JOIN "photo" ON ("user"."id" = "photo"."ownerId")' }, mysql: { - text: '`user` INNER JOIN `photo` ON (`user`.`id` = `photo`.`ownerId`)', + 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 55afafdb..aa83033c 100644 --- a/test/dialects/limit-and-offset-tests.js +++ b/test/dialects/limit-and-offset-tests.js @@ -9,15 +9,15 @@ var user = Harness.defineUserTable(); Harness.test({ query: user.select(user.star()).from(user).order(user.name.asc).limit(1), pg: { - text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', + text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' }, sqlite: { - text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', + text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1', string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 1' }, mysql: { - text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1', + text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 1' }, params: [] @@ -26,15 +26,15 @@ Harness.test({ Harness.test({ query: user.select(user.star()).from(user).order(user.name.asc).limit(3).offset(6), pg: { - text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', + 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' }, sqlite: { - text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" LIMIT 3 OFFSET 6', + 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' }, mysql: { - text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` LIMIT 3 OFFSET 6', + 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' }, params: [] @@ -43,15 +43,15 @@ Harness.test({ Harness.test({ query: user.select(user.star()).from(user).order(user.name.asc).offset(10), pg: { - text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', + text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' }, sqlite: { - text: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', + text : 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10', string: 'SELECT "user".* FROM "user" ORDER BY "user"."name" OFFSET 10' }, mysql: { - text: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', + text : 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10', string: 'SELECT `user`.* FROM `user` ORDER BY `user`.`name` OFFSET 10' }, params: [] @@ -64,15 +64,15 @@ Harness.test({ name: 'John' })).limit(1), pg: { - text: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', + text : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' }, sqlite: { - text: 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', + text : 'SELECT "user".* FROM "user" WHERE ("user"."name" = $1) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = $2)) LIMIT 1', string: 'SELECT "user".* FROM "user" WHERE ("user"."name" = \'John\') OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM "user" WHERE ("user"."name" = \'John\')) LIMIT 1' }, mysql: { - text: 'SELECT `user`.* FROM `user` WHERE (`user`.`name` = ?) OFFSET (SELECT FLOOR(RANDOM() * COUNT(*)) FROM `user` WHERE (`user`.`name` = ?)) LIMIT 1', + 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' }, values: ['John', 'John'] diff --git a/test/dialects/namespace-tests.js b/test/dialects/namespace-tests.js index 9785b517..2ebeb086 100644 --- a/test/dialects/namespace-tests.js +++ b/test/dialects/namespace-tests.js @@ -9,15 +9,15 @@ var u = user.as('u'); Harness.test({ query: u.select(u.name).from(u), pg: { - text: 'SELECT "u"."name" FROM "user" AS "u"', + text : 'SELECT "u"."name" FROM "user" AS "u"', string: 'SELECT "u"."name" FROM "user" AS "u"' }, sqlite: { - text: 'SELECT "u"."name" FROM "user" AS "u"', + text : 'SELECT "u"."name" FROM "user" AS "u"', string: 'SELECT "u"."name" FROM "user" AS "u"' }, mysql: { - text: 'SELECT `u`.`name` FROM `user` AS `u`', + text : 'SELECT `u`.`name` FROM `user` AS `u`', string: 'SELECT `u`.`name` FROM `user` AS `u`' }, params: [] @@ -26,15 +26,15 @@ Harness.test({ Harness.test({ query: u.select(u.star()).from(u), pg: { - text: 'SELECT "u".* FROM "user" AS "u"', + text : 'SELECT "u".* FROM "user" AS "u"', string: 'SELECT "u".* FROM "user" AS "u"' }, sqlite: { - text: 'SELECT "u".* FROM "user" AS "u"', + text : 'SELECT "u".* FROM "user" AS "u"', string: 'SELECT "u".* FROM "user" AS "u"' }, mysql: { - text: 'SELECT `u`.* FROM `user` AS `u`', + text : 'SELECT `u`.* FROM `user` AS `u`', string: 'SELECT `u`.* FROM `user` AS `u`' }, params: [] @@ -44,15 +44,15 @@ var p = post.as('p'); Harness.test({ query: u.select(u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.id.equals(3)))), pg: { - text: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', + 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))' }, sqlite: { - text: 'SELECT "u"."name" FROM "user" AS "u" INNER JOIN "post" AS "p" ON (("u"."id" = "p"."userId") AND ("p"."id" = $1))', + 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))' }, mysql: { - 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` = ?))', string: 'SELECT `u`.`name` FROM `user` AS `u` INNER JOIN `post` AS `p` ON ((`u`.`id` = `p`.`userId`) AND (`p`.`id` = 3))' }, params: [3] @@ -61,15 +61,15 @@ Harness.test({ Harness.test({ query: u.select(p.content, u.name).from(u.join(p).on(u.id.equals(p.userId).and(p.content.isNotNull()))), pg: { - 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))', + 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))' }, sqlite: { - 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))', + 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))' }, mysql: { - 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))', + 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: [] @@ -91,15 +91,15 @@ var comment = Table.define({ Harness.test({ query: comment.select(comment.text, comment.userId), pg: { - text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + text : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' }, sqlite: { - text: 'SELECT "comment"."text", "comment"."userId" FROM "comment"', + text : 'SELECT "comment"."text", "comment"."userId" FROM "comment"', string: 'SELECT "comment"."text", "comment"."userId" FROM "comment"' }, mysql: { - text: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', + text : 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`', string: 'SELECT `comment`.`text`, `comment`.`userId` FROM `comment`' }, params: [] diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 2a8a3fe1..1e0b3642 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.select(post.content).order(post.content), pg: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + text : 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', string: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content"', + 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`', + text : 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`', string: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`' }, params: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: post.select(post.content).order(post.content, post.userId.descending), pg: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + 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' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + 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' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + 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: [] @@ -40,15 +40,15 @@ Harness.test({ Harness.test({ query: post.select(post.content).order(post.content.asc, post.userId.desc), pg: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + 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' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + 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' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + 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: [] @@ -57,15 +57,15 @@ Harness.test({ Harness.test({ query: post.select(post.content).order([post.content, post.userId.descending]), pg: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + 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' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" ORDER BY "post"."content", "post"."userId" DESC', + 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' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` ORDER BY `post`.`content`, `post`.`userId` DESC', + 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: [] diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index 157478eb..1068a1ce 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -13,15 +13,15 @@ var userWithSchema = Table.define({ Harness.test({ query: userWithSchema.select(userWithSchema.id).from(userWithSchema), pg: { - text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + text : 'SELECT "staging"."user"."id" FROM "staging"."user"', string: 'SELECT "staging"."user"."id" FROM "staging"."user"' }, sqlite: { - text: 'SELECT "staging"."user"."id" FROM "staging"."user"', + text : 'SELECT "staging"."user"."id" FROM "staging"."user"', string: 'SELECT "staging"."user"."id" FROM "staging"."user"' }, mysql: { - text: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', + text : 'SELECT `staging`.`user`.`id` FROM `staging`.`user`', string: 'SELECT `staging`.`user`.`id` FROM `staging`.`user`' }, params: [] @@ -30,15 +30,15 @@ Harness.test({ Harness.test({ query: userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), pg: { - text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + text : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' }, sqlite: { - text: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', + text : 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"', string: 'SELECT "staging"."user"."id", "staging"."user"."name" FROM "staging"."user"' }, mysql: { - text: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', + text : 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`', string: 'SELECT `staging`.`user`.`id`, `staging`.`user`.`name` FROM `staging`.`user`' }, params: [] @@ -48,15 +48,15 @@ var uws = userWithSchema.as('uws'); Harness.test({ query: uws.select(uws.name).from(uws), pg: { - text: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + text : 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' }, sqlite: { - text: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', + text : 'SELECT "uws"."name" FROM "staging"."user" AS "uws"', string: 'SELECT "uws"."name" FROM "staging"."user" AS "uws"' }, mysql: { - text: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', + text : 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`', string: 'SELECT `uws`.`name` FROM `staging`.`user` AS `uws`' }, params: [] @@ -71,15 +71,15 @@ var postWithSchema = Table.define({ Harness.test({ query: userWithSchema.select(userWithSchema.name, postWithSchema.content).from(userWithSchema.join(postWithSchema).on(userWithSchema.id.equals(postWithSchema.userId))), pg: { - text: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + 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")' }, sqlite: { - text: 'SELECT "staging"."user"."name", "dev"."post"."content" FROM "staging"."user" INNER JOIN "dev"."post" ON ("staging"."user"."id" = "dev"."post"."userId")', + 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")' }, mysql: { - text: 'SELECT `staging`.`user`.`name`, `dev`.`post`.`content` FROM `staging`.`user` INNER JOIN `dev`.`post` ON (`staging`.`user`.`id` = `dev`.`post`.`userId`)', + 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: [] @@ -88,15 +88,15 @@ Harness.test({ Harness.test({ query: uws.select(uws.name, postWithSchema.content).from(uws.join(postWithSchema).on(uws.id.equals(postWithSchema.userId))), pg: { - text: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + 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")' }, sqlite: { - text: 'SELECT "uws"."name", "dev"."post"."content" FROM "staging"."user" AS "uws" INNER JOIN "dev"."post" ON ("uws"."id" = "dev"."post"."userId")', + 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")' }, mysql: { - text: 'SELECT `uws`.`name`, `dev`.`post`.`content` FROM `staging`.`user` AS `uws` INNER JOIN `dev`.`post` ON (`uws`.`id` = `dev`.`post`.`userId`)', + 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: [] diff --git a/test/dialects/select-tests.js b/test/dialects/select-tests.js index 4dbc3a82..0809574c 100644 --- a/test/dialects/select-tests.js +++ b/test/dialects/select-tests.js @@ -6,15 +6,15 @@ var post = Harness.definePostTable(); Harness.test({ query: post.select(post.id).select(post.content), pg: { - text: 'SELECT "post"."id", "post"."content" FROM "post"', + text : 'SELECT "post"."id", "post"."content" FROM "post"', string: 'SELECT "post"."id", "post"."content" FROM "post"' }, sqlite: { - text: 'SELECT "post"."id", "post"."content" FROM "post"', + text : 'SELECT "post"."id", "post"."content" FROM "post"', string: 'SELECT "post"."id", "post"."content" FROM "post"' }, mysql: { - text: '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/shortcut-tests.js b/test/dialects/shortcut-tests.js index f172a244..62e27574 100644 --- a/test/dialects/shortcut-tests.js +++ b/test/dialects/shortcut-tests.js @@ -8,15 +8,15 @@ var post = Harness.definePostTable(); Harness.test({ query: user, pg: { - text: 'SELECT "user".* FROM "user"', + text : 'SELECT "user".* FROM "user"', string: 'SELECT "user".* FROM "user"' }, sqlite: { - text: 'SELECT "user".* FROM "user"', + text : 'SELECT "user".* FROM "user"', string: 'SELECT "user".* FROM "user"' }, mysql: { - text: 'SELECT `user`.* FROM `user`', + text : 'SELECT `user`.* FROM `user`', string: 'SELECT `user`.* FROM `user`' }, params: [] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: user.where(user.name.equals(3)), pg: { - text: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT * FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' }, sqlite: { - text: 'SELECT * FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT * FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT * FROM "user" WHERE ("user"."name" = 3)' }, mysql: { - text: 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', + text : 'SELECT * FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT * FROM `user` WHERE (`user`.`name` = 3)' }, params: [3] @@ -42,15 +42,15 @@ Harness.test({ Harness.test({ query: user.where(user.name.equals(3)).where(user.id.equals(1)), pg: { - text: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + text : 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' }, sqlite: { - text: 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + text : 'SELECT * FROM "user" WHERE (("user"."name" = $1) AND ("user"."id" = $2))', string: 'SELECT * FROM "user" WHERE (("user"."name" = 3) AND ("user"."id" = 1))' }, mysql: { - text: 'SELECT * FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + 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] @@ -60,15 +60,15 @@ Harness.test({ Harness.test({ query: post.select(post.content), pg: { - text: 'SELECT "post"."content" FROM "post"', + text : 'SELECT "post"."content" FROM "post"', string: 'SELECT "post"."content" FROM "post"' }, sqlite: { - text: 'SELECT "post"."content" FROM "post"', + text : 'SELECT "post"."content" FROM "post"', string: 'SELECT "post"."content" FROM "post"' }, mysql: { - text: 'SELECT `post`.`content` FROM `post`', + text : 'SELECT `post`.`content` FROM `post`', string: 'SELECT `post`.`content` FROM `post`' }, params: [] @@ -77,15 +77,15 @@ Harness.test({ Harness.test({ query: post.select(post.content).where(post.userId.equals(1)), pg: { - text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + text : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' }, sqlite: { - text: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', + text : 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = $1)', string: 'SELECT "post"."content" FROM "post" WHERE ("post"."userId" = 1)' }, mysql: { - text: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', + text : 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = ?)', string: 'SELECT `post`.`content` FROM `post` WHERE (`post`.`userId` = 1)' }, params: [1] @@ -98,15 +98,15 @@ Harness.test({ userId: 1 }), pg: { - text: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + 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))' }, sqlite: { - text: 'SELECT * FROM "post" WHERE ((("post"."content" IS NULL) OR ("post"."content" = $1)) AND ("post"."userId" = $2))', + 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))' }, mysql: { - 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` = ?)) AND (`post`.`userId` = ?))', string: 'SELECT * FROM `post` WHERE (((`post`.`content` IS NULL) OR (`post`.`content` = \'\')) AND (`post`.`userId` = 1))' }, params: ['', 1] diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index ab40862f..01c2c1aa 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -6,15 +6,15 @@ var user = Harness.defineUserTable(); Harness.test({ query: user.select(user.id).from(user), pg: { - text: 'SELECT "user"."id" FROM "user"', + text : 'SELECT "user"."id" FROM "user"', string: 'SELECT "user"."id" FROM "user"' }, sqlite: { - text: 'SELECT "user"."id" FROM "user"', + text : 'SELECT "user"."id" FROM "user"', string: 'SELECT "user"."id" FROM "user"' }, mysql: { - text: 'SELECT `user`.`id` FROM `user`', + text : 'SELECT `user`.`id` FROM `user`', string: 'SELECT `user`.`id` FROM `user`' }, params: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: user.select(user.id, user.name).from(user), pg: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', + text : 'SELECT "user"."id", "user"."name" FROM "user"', string: 'SELECT "user"."id", "user"."name" FROM "user"' }, sqlite: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', + text : 'SELECT "user"."id", "user"."name" FROM "user"', string: 'SELECT "user"."id", "user"."name" FROM "user"' }, mysql: { - text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, params: [] @@ -40,15 +40,15 @@ Harness.test({ Harness.test({ query: user.select(user.star()).from(user), pg: { - text: 'SELECT "user".* FROM "user"', + text : 'SELECT "user".* FROM "user"', string: 'SELECT "user".* FROM "user"' }, sqlite: { - text: 'SELECT "user".* FROM "user"', + text : 'SELECT "user".* FROM "user"', string: 'SELECT "user".* FROM "user"' }, mysql: { - text: 'SELECT `user`.* FROM `user`', + text : 'SELECT `user`.* FROM `user`', string: 'SELECT `user`.* FROM `user`' }, params: [] @@ -57,15 +57,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.equals('foo')), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" = \'foo\')' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', + text : 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` = \'foo\')' }, params: ['foo'] @@ -74,15 +74,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.equals('foo').or(user.name.equals('bar'))), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + 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\'))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + 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\'))' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', + 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'] @@ -91,15 +91,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.equals('foo').and(user.name.equals('bar'))), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', + 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\'))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) AND ("user"."name" = $2))', + 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\'))' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) AND (`user`.`name` = ?))', + 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'] @@ -108,15 +108,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('bar')), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + 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\'))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" = $1) OR ("user"."name" = $2))', + 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\'))' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` = ?) OR (`user`.`name` = ?))', + 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'] @@ -125,15 +125,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.equals('foo')).or(user.name.equals('baz')).and(user.name.equals('bar')), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', + 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\'))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) OR ("user"."name" = $2)) AND ("user"."name" = $3))', + 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\'))' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE (((`user`.`name` = ?) OR (`user`.`name` = ?)) AND (`user`.`name` = ?))', + 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'] @@ -142,15 +142,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.in(['foo', 'bar'])), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', + text : 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN ($1, $2))', string: 'SELECT "user"."id" FROM "user" WHERE ("user"."name" IN (\'foo\', \'bar\'))' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE (`user`.`name` IN (?, ?))', + 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'] @@ -159,15 +159,15 @@ Harness.test({ Harness.test({ query: user.select(user.id).from(user).where(user.name.in(['foo', 'bar']).and(user.id.equals(1))), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', + 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))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE (("user"."name" IN ($1, $2)) AND ("user"."id" = $3))', + 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))' }, mysql: { - text: 'SELECT `user`.`id` FROM `user` WHERE ((`user`.`name` IN (?, ?)) AND (`user`.`id` = ?))', + 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] @@ -176,15 +176,15 @@ Harness.test({ Harness.test({ query: user.select(user.columns), pg: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', + text : 'SELECT "user"."id", "user"."name" FROM "user"', string: 'SELECT "user"."id", "user"."name" FROM "user"' }, sqlite: { - text: 'SELECT "user"."id", "user"."name" FROM "user"', + text : 'SELECT "user"."id", "user"."name" FROM "user"', string: 'SELECT "user"."id", "user"."name" FROM "user"' }, mysql: { - text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + text : 'SELECT `user`.`id`, `user`.`name` FROM `user`', string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' }, params: [] @@ -200,15 +200,15 @@ Harness.test({ .and(user.id.equals(1))).or( user.name.equals('bang').and(user.id.equals(2))), pg: { - text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', + 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)))' }, sqlite: { - text: 'SELECT "user"."id" FROM "user" WHERE ((("user"."name" = $1) AND ("user"."id" = $2)) OR (("user"."name" = $3) AND ("user"."id" = $4)))', + 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)))' }, mysql: { - 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` = ?) 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] @@ -217,15 +217,15 @@ Harness.test({ Harness.test({ query: user.select(user.name.as('user name'), user.id.as('user id')).from(user), pg: { - text: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', + 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"' }, sqlite: { - text: 'SELECT "user"."name" AS "user name", "user"."id" AS "user id" FROM "user"', + 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"' }, mysql: { - text: 'SELECT `user`.`name` AS `user name`, `user`.`id` AS `user id` FROM `user`', + 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: [] @@ -234,15 +234,15 @@ Harness.test({ Harness.test({ query: user.select(user.name.as('user name')).from(user).where(user.name.equals('brian')), pg: { - text: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', + 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\')' }, sqlite: { - text: 'SELECT "user"."name" AS "user name" FROM "user" WHERE ("user"."name" = $1)', + 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\')' }, mysql: { - text: 'SELECT `user`.`name` AS `user name` FROM `user` WHERE (`user`.`name` = ?)', + 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'] @@ -251,15 +251,15 @@ Harness.test({ Harness.test({ query: user.select(user.name).from(user).where(user.name.equals('brian')), pg: { - text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' }, sqlite: { - text: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', + text : 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = $1)', string: 'SELECT "user"."name" FROM "user" WHERE ("user"."name" = \'brian\')' }, mysql: { - text: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', + text : 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = ?)', string: 'SELECT `user`.`name` FROM `user` WHERE (`user`.`name` = \'brian\')' }, params: ['brian'] @@ -268,15 +268,15 @@ Harness.test({ Harness.test({ query: user.select('name').from('user').where('name <> NULL'), pg: { - text: 'SELECT name FROM user WHERE (name <> NULL)', + text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, sqlite: { - text: 'SELECT name FROM user WHERE (name <> NULL)', + text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, mysql: { - text: 'SELECT name FROM user WHERE (name <> NULL)', + text : 'SELECT name FROM user WHERE (name <> NULL)', string: 'SELECT name FROM user WHERE (name <> NULL)' }, params: [] @@ -285,15 +285,15 @@ Harness.test({ Harness.test({ query: user.select('name,id').from('user').where('name <> NULL'), pg: { - text: 'SELECT name,id FROM user WHERE (name <> NULL)', + text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, sqlite: { - text: 'SELECT name,id FROM user WHERE (name <> NULL)', + text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, mysql: { - text: 'SELECT name,id FROM user WHERE (name <> NULL)', + text : 'SELECT name,id FROM user WHERE (name <> NULL)', string: 'SELECT name,id FROM user WHERE (name <> NULL)' }, params: [] @@ -302,15 +302,15 @@ Harness.test({ Harness.test({ query: user.select('name', 'id').from('user').where('name <> NULL'), pg: { - text: 'SELECT name, id FROM user WHERE (name <> NULL)', + text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, sqlite: { - text: 'SELECT name, id FROM user WHERE (name <> NULL)', + text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, mysql: { - text: 'SELECT name, id FROM user WHERE (name <> NULL)', + text : 'SELECT name, id FROM user WHERE (name <> NULL)', string: 'SELECT name, id FROM user WHERE (name <> NULL)' }, params: [] @@ -319,15 +319,15 @@ Harness.test({ Harness.test({ query: user.select('name', 'id').from('user').where('name <> NULL').and('id <> NULL'), pg: { - text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' }, sqlite: { - text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + text : 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', string: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))' }, mysql: { - text: 'SELECT name, id FROM user WHERE ((name <> NULL) AND (id <> NULL))', + 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: [] @@ -338,15 +338,15 @@ Harness.test({ name: 'brian' }), pg: { - text: 'SELECT name FROM user WHERE ("user"."name" = $1)', + text : 'SELECT name FROM user WHERE ("user"."name" = $1)', string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' }, sqlite: { - text: 'SELECT name FROM user WHERE ("user"."name" = $1)', + text : 'SELECT name FROM user WHERE ("user"."name" = $1)', string: 'SELECT name FROM user WHERE ("user"."name" = \'brian\')' }, mysql: { - text: 'SELECT name FROM user WHERE (`user`.`name` = ?)', + text : 'SELECT name FROM user WHERE (`user`.`name` = ?)', string: 'SELECT name FROM user WHERE (`user`.`name` = \'brian\')' }, params: ['brian'] @@ -358,15 +358,15 @@ Harness.test({ id: 1 }), pg: { - text: 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + 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))' }, sqlite: { - text: 'SELECT name FROM user WHERE (("user"."name" = $1) AND ("user"."id" = $2))', + 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))' }, mysql: { - text: 'SELECT name FROM user WHERE ((`user`.`name` = ?) AND (`user`.`id` = ?))', + 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] @@ -375,15 +375,15 @@ Harness.test({ Harness.test({ query: user.select(user.name.as('quote"quote"tick`tick`')), pg: { - text: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + text : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' }, sqlite: { - text: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', + text : 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"', string: 'SELECT "user"."name" AS "quote""quote""tick`tick`" FROM "user"' }, mysql: { - text: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', + text : 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`', string: 'SELECT `user`.`name` AS `quote"quote"tick``tick``` FROM `user`' }, params: [] @@ -392,15 +392,15 @@ Harness.test({ Harness.test({ query: user.select(user.star()).where(user.id.in(user.subQuery().select(user.id))), pg: { - text: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + 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"))' }, sqlite: { - text: 'SELECT "user".* FROM "user" WHERE ("user"."id" IN (SELECT "user"."id" FROM "user"))', + 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"))' }, mysql: { - text: 'SELECT `user`.* FROM `user` WHERE (`user`.`id` IN (SELECT `user`.`id` FROM `user`))', + 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 ce1f539e..37ff8a3b 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -8,15 +8,15 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select().where(customer.age.between(18, 25)), pg: { - text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' }, sqlite: { - text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', + text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN $1 AND $2)', string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" BETWEEN 18 AND 25)' }, mysql: { - text: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` BETWEEN ? AND ?)', + 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] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: post.select().where(post.userId.between(customer.subQuery().select(customer.id.min()), customer.subQuery().select(customer.id.max()))), pg: { - 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"))', + 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"))' }, sqlite: { - 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"))', + 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"))' }, mysql: { - 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`))', + 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: [] diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js index 5654df58..8c26c624 100644 --- a/test/dialects/unary-clause-tests.js +++ b/test/dialects/unary-clause-tests.js @@ -8,15 +8,15 @@ var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select().where(customer.age.isNotNull()), pg: { - text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' }, sqlite: { - text: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', + text : 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)', string: 'SELECT "customer".* FROM "customer" WHERE ("customer"."age" IS NOT NULL)' }, mysql: { - text: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', + text : 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)', string: 'SELECT `customer`.* FROM `customer` WHERE (`customer`.`age` IS NOT NULL)' }, params: [] @@ -25,15 +25,15 @@ Harness.test({ Harness.test({ query: post.select().where(post.userId. in (customer.subQuery().select(customer.id).where(customer.age.isNull()))), pg: { - text: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + 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)))' }, sqlite: { - text: 'SELECT "post".* FROM "post" WHERE ("post"."userId" IN (SELECT "customer"."id" FROM "customer" WHERE ("customer"."age" IS NULL)))', + 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)))' }, mysql: { - text: 'SELECT `post`.* FROM `post` WHERE (`post`.`userId` IN (SELECT `customer`.`id` FROM `customer` WHERE (`customer`.`age` IS NULL)))', + 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 c97d9c95..bd4f6e46 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -9,15 +9,15 @@ Harness.test({ content: 'test' }), pg: { - text: 'UPDATE "post" SET "content" = $1', + text : 'UPDATE "post" SET "content" = $1', string: 'UPDATE "post" SET "content" = \'test\'' }, sqlite: { - text: 'UPDATE "post" SET "content" = $1', + text : 'UPDATE "post" SET "content" = $1', string: 'UPDATE "post" SET "content" = \'test\'' }, mysql: { - text: 'UPDATE `post` SET `content` = ?', + text : 'UPDATE `post` SET `content` = ?', string: 'UPDATE `post` SET `content` = \'test\'' }, params: ['test'] @@ -29,15 +29,15 @@ Harness.test({ userId: 3 }), pg: { - text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + text : 'UPDATE "post" SET "content" = $1, "userId" = $2', string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' }, sqlite: { - text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + text : 'UPDATE "post" SET "content" = $1, "userId" = $2', string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3' }, mysql: { - text: 'UPDATE `post` SET `content` = ?, `userId` = ?', + text : 'UPDATE `post` SET `content` = ?, `userId` = ?', string: 'UPDATE `post` SET `content` = \'test\', `userId` = 3' }, params: ['test', 3] @@ -49,15 +49,15 @@ Harness.test({ userId: 3 }), pg: { - text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + text : 'UPDATE "post" SET "content" = $1, "userId" = $2', string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' }, sqlite: { - text: 'UPDATE "post" SET "content" = $1, "userId" = $2', + text : 'UPDATE "post" SET "content" = $1, "userId" = $2', string: 'UPDATE "post" SET "content" = NULL, "userId" = 3' }, mysql: { - text: 'UPDATE `post` SET `content` = ?, `userId` = ?', + text : 'UPDATE `post` SET `content` = ?, `userId` = ?', string: 'UPDATE `post` SET `content` = NULL, `userId` = 3' }, params: [null, 3] @@ -69,15 +69,15 @@ Harness.test({ userId: 3 }).where(post.content.equals('no')), pg: { - text: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + text : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' }, sqlite: { - text: 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', + text : 'UPDATE "post" SET "content" = $1, "userId" = $2 WHERE ("post"."content" = $3)', string: 'UPDATE "post" SET "content" = \'test\', "userId" = 3 WHERE ("post"."content" = \'no\')' }, mysql: { - text: 'UPDATE `post` SET `content` = ?, `userId` = ? WHERE (`post`.`content` = ?)', + 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'] @@ -88,15 +88,15 @@ Harness.test({ content: user.name }).from(user).where(post.userId.equals(user.id)), sqlite: { - text: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + 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")' }, pg: { - text: 'UPDATE "post" SET "content" = "user"."name" FROM "user" WHERE ("post"."userId" = "user"."id")', + 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")' }, mysql: { - text: 'UPDATE `post` SET `content` = `user`.`name` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', + 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: [] @@ -108,15 +108,15 @@ Harness.test({ userId: user.id }).from(user).where(post.userId.equals(user.id)), pg: { - text: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + 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")' }, sqlite: { - text: 'UPDATE "post" SET "userId" = "user"."id" FROM "user" WHERE ("post"."userId" = "user"."id")', + 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")' }, mysql: { - text: 'UPDATE `post` SET `userId` = `user`.`id` FROM `user` WHERE (`post`.`userId` = `user`.`id`)', + 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: [] diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 6c694954..b9e335f6 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -8,15 +8,15 @@ var v = Harness.defineVariableTable(); Harness.test({ query: customer.select(customer.name, customer.income.modulo(100)).where(customer.age.plus(5).multiply(customer.age.minus(2)).equals(10)), pg: { - text: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + 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)' }, sqlite: { - text: 'SELECT "customer"."name", ("customer"."income" % $1) FROM "customer" WHERE ((("customer"."age" + $2) * ("customer"."age" - $3)) = $4)', + 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)' }, mysql: { - text: 'SELECT `customer`.`name`, (`customer`.`income` % ?) FROM `customer` WHERE (((`customer`.`age` + ?) * (`customer`.`age` - ?)) = ?)', + 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] @@ -26,15 +26,15 @@ Harness.test({ Harness.test({ query: customer.select(customer.name).where(customer.name.like(customer.id.plus('hello'))), pg: { - text: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', + 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\'))' }, sqlite: { - text: 'SELECT "customer"."name" FROM "customer" WHERE ("customer"."name" LIKE ("customer"."id" + $1))', + 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\'))' }, mysql: { - text: 'SELECT `customer`.`name` FROM `customer` WHERE (`customer`.`name` LIKE (`customer`.`id` + ?))', + 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'] @@ -45,15 +45,15 @@ Harness.test({ Harness.test({ query: v.select(v.a.multiply(v.a).divide(2).plus(v.v.multiply(v.t)).equals(v.d)), pg: { - text: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("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"' }, sqlite: { - text: 'SELECT (((("variable"."a" * "variable"."a") / $1) + ("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"' }, mysql: { - text: 'SELECT ((((`variable`.`a` * `variable`.`a`) / ?) + (`variable`.`v` * `variable`.`t`)) = `variable`.`d`) FROM `variable`', + 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] @@ -63,15 +63,15 @@ Harness.test({ Harness.test({ query: v.select(v.a.multiply(v.a).plus(v.b.multiply(v.b)).equals(v.c.multiply(v.c))), pg: { - text: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + 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"' }, sqlite: { - text: 'SELECT ((("variable"."a" * "variable"."a") + ("variable"."b" * "variable"."b")) = ("variable"."c" * "variable"."c")) FROM "variable"', + 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"' }, mysql: { - text: 'SELECT (((`variable`.`a` * `variable`.`a`) + (`variable`.`b` * `variable`.`b`)) = (`variable`.`c` * `variable`.`c`)) FROM `variable`', + 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: [] diff --git a/test/dialects/where-clause-tests.js b/test/dialects/where-clause-tests.js index 01f12417..7fef43f2 100644 --- a/test/dialects/where-clause-tests.js +++ b/test/dialects/where-clause-tests.js @@ -6,15 +6,15 @@ var user = Harness.defineUserTable(); 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))', + 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))', + 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))', + 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: [] @@ -23,15 +23,15 @@ Harness.test({ Harness.test({ query: user.and(user.id.isNotNull(), user.name.isNotNull()), pg: { - text: 'SELECT * FROM "user" WHERE (("user"."id" IS NOT NULL) AND ("user"."name" IS NOT NULL))', + 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))', + 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))', + 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 d07e23c49a00cf5bd120dfbc9d8b123871c837b5 Mon Sep 17 00:00:00 2001 From: bmc Date: Sun, 16 Jun 2013 11:01:59 -0500 Subject: [PATCH 170/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7d5c808..7a151cab 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.23.0", + "version": "0.24.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From ddb32db52be83f6b0579bf0c27f8cc84f72916f2 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 16 Jun 2013 16:00:12 -0700 Subject: [PATCH 171/507] MIT License dating back to 2011 for Brian Carlson --- LICENSE | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..722cf041 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright (C) 2011 Brian Carlson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From a0aed2115074d9106cdb4908d4ee6cf5c741b758 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 17 Jun 2013 21:31:52 -0700 Subject: [PATCH 172/507] Adding some tests to subquery, make visitSubquery return consistent result, add another select star query to from clause test --- lib/dialect/postgres.js | 4 +- test/dialects/from-clause-tests.js | 16 ++++++ test/dialects/subquery-tests.js | 82 ++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 test/dialects/subquery-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 56f92a8b..1730c7b2 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -408,7 +408,7 @@ Postgres.prototype.visitSubquery = function(queryNode) { } var alias = queryNode.alias; - return '(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + alias : ''); + return ['(' + subQuery.output.join(' ') + ')' + (alias ? ' ' + alias : '')]; }; Postgres.prototype.visitTable = function(tableNode) { @@ -422,7 +422,7 @@ Postgres.prototype.visitTable = function(tableNode) { if(table.alias) { txt += ' AS ' + this.quote(table.alias); } - return txt; + return [txt]; }; Postgres.prototype.visitColumn = function(columnNode) { diff --git a/test/dialects/from-clause-tests.js b/test/dialects/from-clause-tests.js index 6e2534d7..d0d8fc01 100644 --- a/test/dialects/from-clause-tests.js +++ b/test/dialects/from-clause-tests.js @@ -19,3 +19,19 @@ Harness.test({ string: 'SELECT `user`.* FROM `user` , `post`' } }); + +Harness.test({ + query: user.select(user.star(), post.star()).from(user).from(post), + pg: { + text : 'SELECT "user".*, "post".* FROM "user" , "post"', + string: 'SELECT "user".*, "post".* FROM "user" , "post"' + }, + sqlite: { + text : 'SELECT "user".*, "post".* FROM "user" , "post"', + string: 'SELECT "user".*, "post".* FROM "user" , "post"' + }, + mysql: { + text : 'SELECT `user`.*, `post`.* FROM `user` , `post`', + string: 'SELECT `user`.*, `post`.* FROM `user` , `post`' + } +}); diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js new file mode 100644 index 00000000..4e001f34 --- /dev/null +++ b/test/dialects/subquery-tests.js @@ -0,0 +1,82 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var user = Harness.defineUserTable(); +var Table = require('../../lib/table'); +var Sql = require('../../lib'); + +Harness.test({ + query: user.name.in( + customer.subQuery().select(customer.name).where( + user.name.in( + customer.subQuery().select(customer.name).where( + user.name.like('%HELLO%'))))), + pg: { + 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%\')))))' + }, + sqlite: { + 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%\')))))' + }, + mysql: { + 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%\')))))' + }, + params: ['%HELLO%'] +}); + +Harness.test({ + query: Sql.select('*').from(user.subQuery()), + pg: { + text : 'SELECT * FROM (SELECT * FROM "user")', + string: 'SELECT * FROM (SELECT * FROM "user")' + }, + sqlite: { + text : 'SELECT * FROM (SELECT * FROM "user")', + string: 'SELECT * FROM (SELECT * FROM "user")' + }, + mysql: { + text : 'SELECT * FROM (SELECT * FROM `user`)', + string: 'SELECT * FROM (SELECT * FROM `user`)' + }, + params: [] +}); + +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' + }, + sqlite: { + 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' + }, + params: [] +}); + +Harness.test({ + query: customer.name.between( + customer.subQuery().select(Sql.functions.MIN(customer.name)), + customer.subQuery().select(Sql.functions.MAX(customer.name)) + ), + pg: { + 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"))' + }, + sqlite: { + 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"))' + }, + mysql: { + 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: [] +}); From 7c1a1c9134648590d83f4d0a34a106bae54bac65 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 17 Jun 2013 21:40:16 -0700 Subject: [PATCH 173/507] update dep --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7a151cab..84ba8b2a 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "node": "*" }, "dependencies": { - "sliced": "0.0.5", - "lodash": "~1.2.1" + "sliced": "0.0.x", + "lodash": "1.3.x" }, "devDependencies": { "jshint": "*", From 15fa7c875fa4971a23b90ffeb7ab7e2582c14461 Mon Sep 17 00:00:00 2001 From: Brian C Date: Tue, 18 Jun 2013 09:22:56 -0500 Subject: [PATCH 174/507] Update README.md Change contribution section to reflect multiple collaborators. --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7b61251a..0cfb115b 100644 --- a/README.md +++ b/README.md @@ -145,11 +145,10 @@ Read the module's documentation for more details. ## contributing -I __love__ contributions. If I could, I would write __love__ 500 times, but that would be readme bloat. +We __love__ contributions. -Still, that's how much I love them. Let's work _together_ on this. - -If you want to contribute here's what you do: +node-sql wouldn't be anything without all the contributors and collaborators who've worked on it. +If you'd like to become a collaborator here's how it's done: 1. fork the repo 2. `git pull https://github.com/(your_username)/node-sql` @@ -157,19 +156,19 @@ If you want to contribute here's what you do: 4. `npm install` 5. `npm test` -At this point the tests should pass for you. If they don't pass please open an issue with the output or you can even send me an email directly. My email address is on my github profile and also on every commit I contributed in the repo. +At this point the tests should pass for you. If they don't pass please open an issue with the output or you can even send me an email directly. +My email address is on my github profile and also on every commit I contributed in the repo. Once the tests are passing, modify as you see fit. _Please_ make sure you write tests to cover your modifications. Once you're ready, commit your changes and submit a pull request. -__As long as your pull request doesn't have completely off-the-wall changes and it does have tests I will almost always merge it right away and push it to npm__ +__As long as your pull request doesn't have completely off-the-wall changes and it does have tests we will almost always merge it and push it to npm__ -If you think your changes are too off-the-wall, open an issue or a pull-request without code so we can discuss them. +If you think your changes are too off-the-wall, open an issue or a pull-request without code so we can discuss them before you begin. -__Seriously:__ +Usually after a few high-quality pull requests and friendly interactions we will gladly share collaboration rights with you. - your contributions >= my contributions +After all, open source belongs to everyone. -I definitely need help with mysql and sqlite syntax. I'm not very familiar...so that's always a good place to start. ##license MIT From 761394738b058ee4365b8594dc8594bfb98ab915 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 18 Jun 2013 14:39:22 -0700 Subject: [PATCH 175/507] unary node isn't being used in column.js --- lib/column.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/column.js b/lib/column.js index d3403a50..8f835b42 100644 --- a/lib/column.js +++ b/lib/column.js @@ -1,11 +1,10 @@ 'use strict'; -var _ = require('lodash'); -var ColumnNode = require(__dirname + '/node/column'); -var valueExpressionMixin = require(__dirname + '/node/valueExpression'); -var OrderByColumnNode = require(__dirname + '/node/orderByColumn'); -var UnaryNode = require(__dirname + '/node/unary'); -var TextNode = require(__dirname + '/node/text'); +var _ = require('lodash'); +var ColumnNode = require('./node/column'); +var OrderByColumnNode = require('./node/orderByColumn'); +var TextNode = require('./node/text'); +var valueExpressionMixin = require('./node/valueExpression'); var Column = function(config) { this.table = config.table; From c221d1aea325ec81b3c369168f3d38195bdc009b Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 23 Jun 2013 00:05:30 -0700 Subject: [PATCH 176/507] adding some toString tests and refactoring parameterNode creation logic --- lib/dialect/postgres.js | 4 + lib/node/functionCall.js | 4 +- lib/node/parameter.js | 14 +++- lib/node/query.js | 2 +- lib/node/valueExpression.js | 5 +- test/dialects/support.js | 2 +- test/dialects/tostring-tests.js | 126 ++++++++++++++++++++++++++++++++ 7 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 test/dialects/tostring-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 1730c7b2..90ed35b1 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -42,6 +42,10 @@ Postgres.prototype._getParameterValue = function(value) { // convert each element of the array value = _.map(value, this._getParameterValue, this); value = '(' + value.join(', ') + ')'; + } else if (_.isFunction(value.toUTCString)) { + // Date object's default toString format does not get parsed well + // Handle date like objects using toUTCString + value = this._getParameterValue(value.toUTCString()); } else { // rich object represent with string value = this._getParameterValue(value.toString()); diff --git a/lib/node/functionCall.js b/lib/node/functionCall.js index da8d8767..6d43c279 100644 --- a/lib/node/functionCall.js +++ b/lib/node/functionCall.js @@ -10,9 +10,7 @@ var FunctionCallNode = Node.define({ constructor: function(name, args) { Node.call(this); this.name = name; - this.addAll(args.map(function (v) { - return v.toNode ? v.toNode() : new ParameterNode(v); - })); + this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); } }); diff --git a/lib/node/parameter.js b/lib/node/parameter.js index 0b190d6e..7b3a8a20 100644 --- a/lib/node/parameter.js +++ b/lib/node/parameter.js @@ -1,7 +1,8 @@ 'use strict'; var Node = require(__dirname); -module.exports = Node.define({ + +var ParameterNode = module.exports = Node.define({ type: 'PARAMETER', constructor: function(val) { Node.call(this); @@ -11,3 +12,14 @@ module.exports = Node.define({ return this._val; } }); + +// wrap a value as a parameter node if value is not already a node +module.exports.getNodeOrParameterNode = function(value) { + if (value && value.toNode) { + // use toNode + return value.toNode(); + } else { + // wrap as parameter node + return new ParameterNode(value); + } +}; diff --git a/lib/node/query.js b/lib/node/query.js index 43d9ac22..597079ea 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -160,7 +160,7 @@ var Query = Node.define({ var update = new Update(); Object.keys(o).forEach(function(key) { var val = o[key]; - update.add(self.table.get(key).value(val && val.toNode ? val.toNode() : new ParameterNode(val))); + update.add(self.table.get(key).value(ParameterNode.getNodeOrParameterNode(val))); }); return this.add(update); }, diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 66de6fea..74584787 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -6,10 +6,7 @@ var ParameterNode = require(__dirname + '/parameter'); // Process values, wrapping them in ParameterNode if necessary. var processParams = function(val) { - var helper = function(v) { - return v.toNode ? v.toNode() : new ParameterNode(v); - }; - return Array.isArray(val) ? val.map(helper) : helper(val); + return Array.isArray(val) ? val.map(ParameterNode.getNodeOrParameterNode) : ParameterNode.getNodeOrParameterNode(val); }; // Value expressions can be composed to form new value expressions. diff --git a/test/dialects/support.js b/test/dialects/support.js index 6c3e6baf..a5b48e59 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -41,7 +41,7 @@ module.exports = { if (undefined !== expectedParams) { assert.equal(expectedParams.length, compiledQuery.values.length, 'params length'); for (var i = 0; i < expectedParams.length; i++) { - assert.equal(expectedParams[i], compiledQuery.values[i], 'param ' + (i + 1)); + assert.deepEqual(expectedParams[i], compiledQuery.values[i], 'param ' + (i + 1)); } } } diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js new file mode 100644 index 00000000..e22be0dc --- /dev/null +++ b/test/dialects/tostring-tests.js @@ -0,0 +1,126 @@ +'use strict'; + +var assert = require('assert'); +var Harness = require('./support'); +var ParameterNode = require('../../lib/node/parameter'); +var post = Harness.definePostTable(); + +// Null +Harness.test({ + query: post.content.equals(null), + pg: { + text : '("post"."content" = $1)', + string: '("post"."content" = NULL)' + }, + sqlite: { + text : '("post"."content" = $1)', + string: '("post"."content" = NULL)' + }, + mysql: { + text : '(`post`.`content` = ?)', + string: '(`post`.`content` = NULL)' + }, + params: [null] +}); + +// Number +Harness.test({ + query: post.content.equals(3.14), + pg: { + text : '("post"."content" = $1)', + string: '("post"."content" = 3.14)' + }, + sqlite: { + text : '("post"."content" = $1)', + string: '("post"."content" = 3.14)' + }, + mysql: { + text : '(`post`.`content` = ?)', + string: '(`post`.`content` = 3.14)' + }, + params: [3.14] +}); + +// String +Harness.test({ + query: post.content.equals('hello\''), + pg: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'hello\'\'\')' + }, + sqlite: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'hello\'\'\')' + }, + mysql: { + text : '(`post`.`content` = ?)', + string: '(`post`.`content` = \'hello\'\'\')' + }, + params: ['hello\''] +}); + +// Array +Harness.test({ + query: post.content.equals([1, '2', null]), + pg: { + text : '("post"."content" = ($1, $2, $3))', + string: '("post"."content" = (1, \'2\', NULL))' + }, + sqlite: { + text : '("post"."content" = ($1, $2, $3))', + string: '("post"."content" = (1, \'2\', NULL))' + }, + mysql: { + text : '(`post`.`content` = (?, ?, ?))', + string: '(`post`.`content` = (1, \'2\', NULL))' + }, + params: [1, '2', null] +}); + +// Date +Harness.test({ + query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), + pg: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'Sat, 01 Jan 2000 00:00:00 GMT\')' + }, + sqlite: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'Sat, 01 Jan 2000 00:00:00 GMT\')' + }, + mysql: { + text : '(`post`.`content` = ?)', + string: '(`post`.`content` = \'Sat, 01 Jan 2000 00:00:00 GMT\')' + }, + params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] +}); + +// Object +var customObject = { + toString: function() { + return 'secretMessage'; + } +}; + +Harness.test({ + query: post.content.equals(customObject), + pg: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'secretMessage\')' + }, + sqlite: { + text : '("post"."content" = $1)', + string: '("post"."content" = \'secretMessage\')' + }, + mysql: { + text : '(`post`.`content` = ?)', + string: '(`post`.`content` = \'secretMessage\')' + }, + params: [customObject] +}); + + +// Undefined +assert.throws(function() { + post.content.equals(undefined).toString(); +}); From d43ced180bf8ee3ac079c18800151f6ec614ee32 Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Mon, 24 Jun 2013 16:17:53 -0600 Subject: [PATCH 177/507] Only test .js files in test/dialects When enumerating dialect test files, the current algorithm attempts to require() all files. This is a problem for editors which create swap/backup/temporary files and on systems where thumbnailers or other system programs create files outside the control of the user. Although we could attempt to exclude each of these files specifically, or perform some exclusions based on hidden file names or attributes, it seems easier to just limit the search to .js files, since that is the only extension of interest currently. Signed-off-by: Kevin Locke --- test/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/index.js b/test/index.js index 20003ffc..eb7a60b0 100644 --- a/test/index.js +++ b/test/index.js @@ -14,6 +14,8 @@ directories.forEach(function (d) { /*jshint boss: true */ for(var i = 0, file; file = files[i]; i++) { var filePath = path.join(d, file); - require(filePath); + if (path.extname(file) === '.js') { + require(filePath); + } } }); From 6bb360094f5eb776fd18d95b71e72f4e62f0c850 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 24 Jun 2013 15:34:45 -0700 Subject: [PATCH 178/507] MySQL does not do date UTCString, but ISOString format works --- lib/dialect/postgres.js | 6 +++--- test/dialects/tostring-tests.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 90ed35b1..585e88df 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -42,10 +42,10 @@ Postgres.prototype._getParameterValue = function(value) { // convert each element of the array value = _.map(value, this._getParameterValue, this); value = '(' + value.join(', ') + ')'; - } else if (_.isFunction(value.toUTCString)) { + } else if (_.isFunction(value.toISOString)) { // Date object's default toString format does not get parsed well - // Handle date like objects using toUTCString - value = this._getParameterValue(value.toUTCString()); + // Handle date like objects using toISOString + value = this._getParameterValue(value.toISOString()); } else { // rich object represent with string value = this._getParameterValue(value.toString()); diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index e22be0dc..df55dda6 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -82,15 +82,15 @@ Harness.test({ query: post.content.equals(new Date('Sat, 01 Jan 2000 00:00:00 GMT')), pg: { text : '("post"."content" = $1)', - string: '("post"."content" = \'Sat, 01 Jan 2000 00:00:00 GMT\')' + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' }, sqlite: { text : '("post"."content" = $1)', - string: '("post"."content" = \'Sat, 01 Jan 2000 00:00:00 GMT\')' + string: '("post"."content" = \'2000-01-01T00:00:00.000Z\')' }, mysql: { text : '(`post`.`content` = ?)', - string: '(`post`.`content` = \'Sat, 01 Jan 2000 00:00:00 GMT\')' + string: '(`post`.`content` = \'2000-01-01T00:00:00.000Z\')' }, params: [new Date('Sat, 01 Jan 2000 00:00:00 GMT')] }); From 5329b03a2c66bf06b7104d4ba9652f674729eb49 Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Mon, 24 Jun 2013 19:02:28 -0600 Subject: [PATCH 179/507] Split Unary into PrefixUnary and PostfixUnary Separate unary nodes into separate prefix- and postfix- unary nodes in preparation for adding prefix unary operators to the supported grammar. Signed-off-by: Kevin Locke --- lib/dialect/postgres.js | 10 ++++++++-- lib/node/postfixUnary.js | 28 +++++++++++++++++++++++++++ lib/node/{unary.js => prefixUnary.js} | 10 +++++----- lib/node/valueExpression.js | 10 +++++----- 4 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 lib/node/postfixUnary.js rename lib/node/{unary.js => prefixUnary.js} (73%) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 585e88df..5319f8d7 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -130,7 +130,8 @@ Postgres.prototype.visit = function(node) { case 'DROP INDEX' : return this.visitDropIndex(node); case 'FUNCTION CALL' : return this.visitFunctionCall(node); - case 'UNARY' : return this.visitUnary(node); + case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); + case 'PREFIX UNARY' : return this.visitPrefixUnary(node); case 'BINARY' : return this.visitBinary(node); case 'TERNARY' : return this.visitTernary(node); @@ -295,7 +296,12 @@ Postgres.prototype.visitHaving = function(having) { return result; }; -Postgres.prototype.visitUnary = function(unary) { +Postgres.prototype.visitPrefixUnary = function(unary) { + var text = '(' + unary.operator + ' ' + this.visit(unary.left) + ')'; + return [text]; +}; + +Postgres.prototype.visitPostfixUnary = function(unary) { var text = '(' + this.visit(unary.left) + ' ' + unary.operator + ')'; return [text]; }; diff --git a/lib/node/postfixUnary.js b/lib/node/postfixUnary.js new file mode 100644 index 00000000..0c132f8a --- /dev/null +++ b/lib/node/postfixUnary.js @@ -0,0 +1,28 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var PostfixUnaryNode = Node.define({ + type: 'POSTFIX UNARY', + constructor: function(config) { + Node.call(this); + this.left = config.left; + this.operator = config.operator; + + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(PostfixUnaryNode.prototype, valueExpressionMixin()); + } + } +}); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(PostfixUnaryNode.prototype, AliasNode.AliasMixin); + +module.exports = PostfixUnaryNode; diff --git a/lib/node/unary.js b/lib/node/prefixUnary.js similarity index 73% rename from lib/node/unary.js rename to lib/node/prefixUnary.js index de503795..67a59fa1 100644 --- a/lib/node/unary.js +++ b/lib/node/prefixUnary.js @@ -5,8 +5,8 @@ var Node = require(__dirname); var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; -var UnaryNode = Node.define({ - type: 'UNARY', +var PrefixUnaryNode = Node.define({ + type: 'PREFIX UNARY', constructor: function(config) { Node.call(this); this.left = config.left; @@ -16,13 +16,13 @@ var UnaryNode = Node.define({ // mixin only once. ValueExpressionMixin has circular dependencies. if (!valueExpressionMixed) { valueExpressionMixed = true; - _.extend(UnaryNode.prototype, valueExpressionMixin()); + _.extend(PrefixUnaryNode.prototype, valueExpressionMixin()); } } }); // allow aliasing var AliasNode = require(__dirname + '/alias'); -_.extend(UnaryNode.prototype, AliasNode.AliasMixin); +_.extend(PrefixUnaryNode.prototype, AliasNode.AliasMixin); -module.exports = UnaryNode; +module.exports = PrefixUnaryNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 74584787..cc8bad4e 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -13,14 +13,14 @@ var processParams = function(val) { // ValueExpressionMixin is evaluated at runtime, hence the // "thunk" around it. var ValueExpressionMixin = module.exports = function() { - var UnaryNode = require(__dirname + '/unary'); + var PostfixUnaryNode = require(__dirname + '/postfixUnary'); var BinaryNode = require(__dirname + '/binary'); var TernaryNode = require(__dirname + '/ternary'); - var unaryMethod = function(operator) { + var postfixUnaryMethod = function(operator) { /*jshint unused: false */ return function(val) { - return new UnaryNode({ + return new PostfixUnaryNode({ left: this.toNode(), operator: operator }); @@ -50,8 +50,8 @@ var ValueExpressionMixin = module.exports = function() { }; return { - isNull : unaryMethod('IS NULL'), - isNotNull : unaryMethod('IS NOT NULL'), + isNull : postfixUnaryMethod('IS NULL'), + isNotNull : postfixUnaryMethod('IS NOT NULL'), or : binaryMethod('OR'), and : binaryMethod('AND'), equals : binaryMethod('='), From 9d71981d738c9123b7901b440e54b163f7a0c74c Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Mon, 24 Jun 2013 19:07:25 -0600 Subject: [PATCH 180/507] Add support for EXISTS and NOT EXISTS expressions Support checking the existence of subqueries using the SQL EXISTS and NOT EXISTS expressions by adding `exists` and `notExists` methods to the `Query` prototype. This syntax is backwards compared to the SQL construction (which is EXISTS [...] rather than [...] EXISTS) but seems more reasonable than a putting `exists` in a shared scope. Note that `notExists` could be implemented just as well with a unary logical negation around the unary EXISTS, but since this is not done elsewhere, it seemed preferable to stick with the existing style of combining the negations with their positive counterparts. Signed-off-by: Kevin Locke --- lib/node/query.js | 67 +++++++++++++++++++++------------ test/dialects/subquery-tests.js | 17 +++++++++ 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 597079ea..d640acf3 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -5,31 +5,32 @@ var util = require('util'); var sliced = require('sliced'); -var Node = require(__dirname); -var Select = require(__dirname + '/select'); -var From = require(__dirname + '/from'); -var Where = require(__dirname + '/where'); -var OrderBy = require(__dirname + '/orderBy'); -var GroupBy = require(__dirname + '/groupBy'); -var Having = require(__dirname + '/having'); -var Insert = require(__dirname + '/insert'); -var Update = require(__dirname + '/update'); -var Delete = require(__dirname + '/delete'); -var Returning = require(__dirname + '/returning'); -var Create = require(__dirname + '/create'); -var Drop = require(__dirname + '/drop'); -var Alter = require(__dirname + '/alter'); -var AddColumn = require(__dirname + '/addColumn'); -var DropColumn = require(__dirname + '/dropColumn'); -var RenameColumn = require(__dirname + '/renameColumn'); -var Rename = require(__dirname + '/rename'); -var Column = require(__dirname + '/../column'); -var ParameterNode = require(__dirname + '/parameter'); -var IfExists = require(__dirname + '/ifExists'); -var IfNotExists = require(__dirname + '/ifNotExists'); -var Indexes = require(__dirname + '/indexes'); -var CreateIndex = require(__dirname + '/createIndex'); -var DropIndex = require(__dirname + '/dropIndex'); +var Node = require(__dirname); +var Select = require(__dirname + '/select'); +var From = require(__dirname + '/from'); +var Where = require(__dirname + '/where'); +var OrderBy = require(__dirname + '/orderBy'); +var GroupBy = require(__dirname + '/groupBy'); +var Having = require(__dirname + '/having'); +var Insert = require(__dirname + '/insert'); +var Update = require(__dirname + '/update'); +var Delete = require(__dirname + '/delete'); +var Returning = require(__dirname + '/returning'); +var Create = require(__dirname + '/create'); +var Drop = require(__dirname + '/drop'); +var Alter = require(__dirname + '/alter'); +var AddColumn = require(__dirname + '/addColumn'); +var DropColumn = require(__dirname + '/dropColumn'); +var RenameColumn = require(__dirname + '/renameColumn'); +var Rename = require(__dirname + '/rename'); +var Column = require(__dirname + '/../column'); +var ParameterNode = require(__dirname + '/parameter'); +var PrefixUnaryNode = require(__dirname + '/prefixUnary'); +var IfExists = require(__dirname + '/ifExists'); +var IfNotExists = require(__dirname + '/ifNotExists'); +var Indexes = require(__dirname + '/indexes'); +var CreateIndex = require(__dirname + '/createIndex'); +var DropIndex = require(__dirname + '/dropIndex'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -253,6 +254,22 @@ var Query = Node.define({ return this.add(new Modifier(this, 'OFFSET', count)); }, + exists: function() { + assert(this.type === 'SUBQUERY', 'exists() can only be used on a subQuery'); + return new PrefixUnaryNode({ + left: this, + operator: "EXISTS" + }); + }, + + notExists: function() { + assert(this.type === 'SUBQUERY', 'notExists() can only be used on a subQuery'); + return new PrefixUnaryNode({ + left: this, + operator: "NOT EXISTS" + }); + }, + ifExists: function() { this.nodes[0].add(new IfExists()); return this; diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 4e001f34..0d9e4159 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -80,3 +80,20 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: user.subQuery().where(user.name.equals(customer.name)).exists(), + pg: { + text : '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', + string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' + }, + sqlite: { + text : '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))', + string: '(EXISTS (SELECT * FROM "user" WHERE ("user"."name" = "customer"."name")))' + }, + mysql: { + text : '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))', + string: '(EXISTS (SELECT * FROM `user` WHERE (`user`.`name` = `customer`.`name`)))' + }, + params: [] +}); From 712edd7c79b2442b22f7e94c0bcfa3a80dd2b5f8 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 25 Jun 2013 09:16:19 -0500 Subject: [PATCH 181/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84ba8b2a..1dc64752 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.24.0", + "version": "0.25.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 0659be5da51d2c8c23a0c54c66a52fe09fd1a343 Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Tue, 25 Jun 2013 10:30:28 -0600 Subject: [PATCH 182/507] Support INSERT with SELECT Add support for inserting the result of a query in addition to inserting literal values. Update Insert to only append to valueSet when appropriate. Update the Postgres dialect to only output "VALUES" as part of an INSERT statement if values are present (including default values). Add tests. Note: There is some ambiguity of the user intent when insert is called without any values. The user may intend to either insert a row consisting entirely of default values or they may intend to insert a row based on a subsequently added SELECT statement. Although we could defer resolution until the SELECT statement is added (or not) through either manipulating the query object from the select method or additional logic in the dialect, the approach taken in this commit is to use a simple heuristic: If the insert includes any columns, it is assumed that a SELECT will follow, otherwise default values are used. This commit addresses issue #111. Signed-off-by: Kevin Locke --- lib/dialect/postgres.js | 31 +++++++++++--------- lib/node/insert.js | 14 ++++++++- test/dialects/insert-tests.js | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 5319f8d7..ab375e5b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -167,25 +167,30 @@ Postgres.prototype.visitInsert = function(insert) { // don't use table.column for inserts this._visitedInsert = true; - var paramNodes = insert.getParameters() - .map(function (paramSet) { - return paramSet.map(function (param) { - return self.visit(param); - }).join(', '); - }).map(function (param) { - return '('+param+')'; - }).join(', '); - var result = [ 'INSERT INTO', this.visit(this._queryNode.table.toNode()), - '(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')', - 'VALUES', paramNodes + '(' + insert.columns.map(this.visit.bind(this)).join(', ') + ')' ]; - if (result.slice(2, 5).join(' ') === '() VALUES ()') { - result.splice(2, 3, 'DEFAULT VALUES'); + var paramNodes = insert.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'); + } } + return result; }; diff --git a/lib/node/insert.js b/lib/node/insert.js index 07156d8c..e3d86f42 100644 --- a/lib/node/insert.js +++ b/lib/node/insert.js @@ -17,6 +17,8 @@ var Insert = Node.define({ module.exports = Insert; Insert.prototype.add = function (nodes) { + var hasColumns = false; + var hasValues = false; var self = this; var values = {}; nodes.forEach(function (node) { @@ -27,9 +29,19 @@ Insert.prototype.add = function (nodes) { self.names.push(name); self.columns.push(column); } + hasColumns = true; + hasValues = hasValues || column.value !== undefined; values[name] = column; }); - this.valueSets.push(values); + + // When none of the columns have a value, it's ambiguous whether the user + // intends to insert 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; }; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 8340faf4..190d00b7 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); +var user = Harness.defineUserTable(); Harness.test({ query: post.insert(post.content.value('test'), post.userId.value(1)), @@ -280,3 +281,57 @@ Harness.test({ params: [1, 2, 'hey'] } }); + +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%\')' + }, + 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%\')' + }, + 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%\')' + }, + params: ['A%'] +}); + +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%\')' + }, + 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%\')' + }, + 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%\')' + }, + params: ['A%'] +}); + +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%\')' + }, + 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%\')' + }, + 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%\')' + }, + params: ['A%'] +}); From 43b11906605f882f4be7541aea75addaddc60d69 Mon Sep 17 00:00:00 2001 From: Kevin Locke Date: Tue, 25 Jun 2013 10:37:00 -0600 Subject: [PATCH 183/507] Clone Column returned by .value() Previously, calling .value() would mutate the Column object. This causes unexpected behavior when subsequent use of the column carries the previously set value. For example: table.insert(col1.value(1)); table.insert(col1).select(col2).from(table2); Would cause a syntax error because insert(col1) would be interpreted as inserting the value 1 into col1 and would not accept an appended select statement. This is a change which could break any users depending on this behavior. Although none of the tests depend on this behavior and the new behavior seems more reasonable (to me, obviously), there is risk of user breakage. Signed-off-by: Kevin Locke --- lib/column.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/column.js b/lib/column.js index 8f835b42..de8d6e2b 100644 --- a/lib/column.js +++ b/lib/column.js @@ -32,8 +32,9 @@ var contextify = function(base) { }; Column.prototype.value = function(value) { - this._value = value; - return this; + var context = contextify(this); + context._value = value; + return context; }; Column.prototype.getValue = function() { From 119600e38d948ae3877239d822a6f009c2ec3677 Mon Sep 17 00:00:00 2001 From: Stefan Matthias Aust Date: Wed, 26 Jun 2013 19:18:24 +0200 Subject: [PATCH 184/507] allow multiple order() calls --- lib/node/query.js | 7 +++++-- test/dialects/order-tests.js | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index d640acf3..0d638532 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -110,8 +110,11 @@ var Query = Node.define({ if(util.isArray(args[0])) { args = args[0]; } - var orderBy = new OrderBy().addAll(args); - return this.add(orderBy); + if (!this.orderBy) { + this.add(this.orderBy = new OrderBy()); + } + this.orderBy.addAll(args); + return this; }, group: function() { var args = sliced(arguments); diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 1e0b3642..64f48e1e 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -70,3 +70,20 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: post.select(post.content).order(post.content).order(post.userId.descending), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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: [] +}); From 000fc3915b21347067d09b988b8930ba574d0052 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 29 Jun 2013 16:45:32 -0700 Subject: [PATCH 185/507] refactor Query.order to fit the style of Query.select --- lib/node/query.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 0d638532..14d1e9e2 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -110,10 +110,15 @@ var Query = Node.define({ if(util.isArray(args[0])) { args = args[0]; } - if (!this.orderBy) { - this.add(this.orderBy = new OrderBy()); + + var orderBy; + if (this._orderBy) { + orderBy = this._orderBy; + } else { + orderBy = this._orderBy = new OrderBy(); + this.add(orderBy); } - this.orderBy.addAll(args); + orderBy.addAll(args); return this; }, group: function() { From 22c3be0311ffd503f7d97310957773409905e3d9 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 29 Jun 2013 16:57:15 -0700 Subject: [PATCH 186/507] refactor query.js --- lib/node/query.js | 170 +++++++++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 76 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 14d1e9e2..e4b32e0e 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -1,36 +1,35 @@ 'use strict'; var assert = require('assert'); -var util = require('util'); - var sliced = require('sliced'); +var util = require('util'); -var Node = require(__dirname); -var Select = require(__dirname + '/select'); -var From = require(__dirname + '/from'); -var Where = require(__dirname + '/where'); -var OrderBy = require(__dirname + '/orderBy'); -var GroupBy = require(__dirname + '/groupBy'); -var Having = require(__dirname + '/having'); -var Insert = require(__dirname + '/insert'); -var Update = require(__dirname + '/update'); -var Delete = require(__dirname + '/delete'); -var Returning = require(__dirname + '/returning'); -var Create = require(__dirname + '/create'); -var Drop = require(__dirname + '/drop'); -var Alter = require(__dirname + '/alter'); -var AddColumn = require(__dirname + '/addColumn'); -var DropColumn = require(__dirname + '/dropColumn'); -var RenameColumn = require(__dirname + '/renameColumn'); -var Rename = require(__dirname + '/rename'); -var Column = require(__dirname + '/../column'); -var ParameterNode = require(__dirname + '/parameter'); -var PrefixUnaryNode = require(__dirname + '/prefixUnary'); -var IfExists = require(__dirname + '/ifExists'); -var IfNotExists = require(__dirname + '/ifNotExists'); -var Indexes = require(__dirname + '/indexes'); -var CreateIndex = require(__dirname + '/createIndex'); -var DropIndex = require(__dirname + '/dropIndex'); +var Node = require('./'); +var Select = require('./select'); +var From = require('./from'); +var Where = require('./where'); +var OrderBy = require('./orderBy'); +var GroupBy = require('./groupBy'); +var Having = require('./having'); +var Insert = require('./insert'); +var Update = require('./update'); +var Delete = require('./delete'); +var Returning = require('./returning'); +var Create = require('./create'); +var Drop = require('./drop'); +var Alter = require('./alter'); +var AddColumn = require('./addColumn'); +var DropColumn = require('./dropColumn'); +var RenameColumn = require('./renameColumn'); +var Rename = require('./rename'); +var Column = require('../column'); +var ParameterNode = require('./parameter'); +var PrefixUnaryNode = require('./prefixUnary'); +var IfExists = require('./ifExists'); +var IfNotExists = require('./ifNotExists'); +var Indexes = require('./indexes'); +var CreateIndex = require('./createIndex'); +var DropIndex = require('./dropIndex'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -40,6 +39,14 @@ var Modifier = Node.define({ } }); +// get the first element of an arguments if it is an array, else return arguments as an array +var getArrayOrArgsAsArray = function(args) { + if (util.isArray(args[0])) { + return args[0]; + } + return sliced(args); +}; + var Query = Node.define({ type: 'QUERY', constructor: function(table) { @@ -49,25 +56,24 @@ var Query = Node.define({ }, select: function() { var select; - if(this._select) { + if (this._select) { select = this._select; } else { select = this._select = new Select(); this.add(select); } - var args = sliced(arguments); - if(util.isArray(args[0])) { - args = args[0]; - } + + var args = getArrayOrArgsAsArray(arguments); select.addAll(args); + // if this is a subquery then add reference to this column - if(this.type === 'SUBQUERY') { - for(var j = 0; j < select.nodes.length; j++) { + if (this.type === 'SUBQUERY') { + for (var j = 0; j < select.nodes.length; j++) { var name = select.nodes[j].alias || select.nodes[j].name; var col = new Column(select.nodes[j]); col.name = name; col.table = this; - if( this[name] === undefined ) { + if (this[name] === undefined) { this[name] = col; } } @@ -75,24 +81,27 @@ var Query = Node.define({ return this; }, star: function() { - assert( this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); - return new Column({table: this, star: true}); + assert(this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); + return new Column({ + table: this, + star: true + }); }, from: function(tableNode) { var from = new From().add(tableNode); return this.add(from); }, where: function(node) { - if(arguments.length > 1) { + if (arguments.length > 1) { // allow multiple where clause arguments var args = sliced(arguments); - for(var i = 0; i < args.length; i++) { + for (var i = 0; i < args.length; i++) { this.where(args[i]); } return this; } // calling #where twice functions like calling #where & then #and - if(this.whereClause) return this.and(node); + if (this.whereClause) return this.and(node); this.whereClause = new Where(this.table); this.whereClause.add(node); return this.add(this.whereClause); @@ -106,11 +115,7 @@ var Query = Node.define({ return this; }, order: function() { - var args = sliced(arguments); - if(util.isArray(args[0])) { - args = args[0]; - } - + var args = getArrayOrArgsAsArray(arguments); var orderBy; if (this._orderBy) { orderBy = this._orderBy; @@ -122,18 +127,12 @@ var Query = Node.define({ return this; }, group: function() { - var args = sliced(arguments); - if(util.isArray(args[0])) { - args = args[0]; - } + var args = getArrayOrArgsAsArray(arguments); var groupBy = new GroupBy().addAll(args); return this.add(groupBy); }, having: function() { - var args = sliced(arguments); - if (util.isArray(args[0])) { - args = args[0]; - } + var args = getArrayOrArgsAsArray(arguments); var having = new Having().addAll(args); return this.add(having); }, @@ -142,12 +141,12 @@ var Query = Node.define({ var args = sliced(arguments); // object literal - if(arguments.length == 1 && !o.toNode && !o.forEach) { + if (arguments.length == 1 && !o.toNode && !o.forEach) { args = Object.keys(o).map(function(key) { return self.table.get(key).value(o[key]); }); } else if (o.forEach) { - o.forEach(function (arg) { + o.forEach(function(arg) { return self.insert.call(self, arg); }); return self; @@ -156,8 +155,7 @@ var Query = Node.define({ if (self.insertClause) { self.insertClause.add(args); return self; - } - else { + } else { self.insertClause = new Insert(); self.insertClause.add(args); return self.add(self.insertClause); @@ -175,17 +173,14 @@ var Query = Node.define({ }, delete: function(params) { var result = this.add(new Delete()); - if(params) { + if (params) { result = this.where(params); } return result; }, returning: function() { + var args = getArrayOrArgsAsArray(arguments); var returning = new Returning(); - var args = sliced(arguments); - if(util.isArray(args[0])) { - args = args[0]; - } returning.addAll(args); return this.add(returning); }, @@ -202,7 +197,7 @@ var Query = Node.define({ drop: function() { if (this.indexesCause) { - var args = Array.prototype.slice.call(arguments); + var args = sliced(arguments); var dropIndex = new DropIndex(this.table, args); this.add(dropIndex); return dropIndex; @@ -217,26 +212,39 @@ var Query = Node.define({ rename: function(newName) { var renameClause = new Rename(); - if (!newName.toNode) - newName = new Column({ name: newName, table: this.table}); + if (!newName.toNode) { + newName = new Column({ + name: newName, + table: this.table + }); + } renameClause.add(newName.toNode()); this.nodes[0].add(renameClause); return this; }, addColumn: function(column, dataType) { var addClause = new AddColumn(); - if (!column.toNode) - column = new Column({name: column, table: this.table}); - if (dataType) + if (!column.toNode) { + column = new Column({ + name: column, + table: this.table + }); + } + if (dataType) { column.dataType = dataType; + } addClause.add(column.toNode()); this.nodes[0].add(addClause); return this; }, dropColumn: function(column) { var dropClause = new DropColumn(); - if (!column.toNode) - column = new Column({name: column, table: this.table}); + if (!column.toNode) { + column = new Column({ + name: column, + table: this.table + }); + } dropClause.add(column.toNode()); this.nodes[0].add(dropClause); return this; @@ -244,10 +252,18 @@ var Query = Node.define({ renameColumn: function(oldColumn, newColumn) { var renameClause = new RenameColumn(); - if (!oldColumn.toNode) - oldColumn = new Column({name: oldColumn, table: this.table}); - if (!newColumn.toNode) - newColumn = new Column({name: newColumn, table: this.table}); + if (!oldColumn.toNode) { + oldColumn = new Column({ + name: oldColumn, + table: this.table + }); + } + if (!newColumn.toNode) { + newColumn = new Column({ + name: newColumn, + table: this.table + }); + } renameClause.add(oldColumn.toNode()); renameClause.add(newColumn.toNode()); this.nodes[0].add(renameClause); @@ -289,7 +305,9 @@ var Query = Node.define({ }, indexes: function() { - this.indexesCause = new Indexes({ table: this.table }); + this.indexesCause = new Indexes({ + table: this.table + }); return this.add(this.indexesCause); } }); From dac2a49e9445a6f801342588ec4f148f9d932f76 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 30 Jun 2013 19:42:11 -0700 Subject: [PATCH 187/507] removing unnecessary code --- lib/node/createIndex.js | 12 +++++------- lib/node/dropIndex.js | 11 +++-------- lib/node/indexes.js | 7 ++----- lib/node/insert.js | 6 +++--- 4 files changed, 13 insertions(+), 23 deletions(-) diff --git a/lib/node/createIndex.js b/lib/node/createIndex.js index b4ca484d..2384ab8e 100644 --- a/lib/node/createIndex.js +++ b/lib/node/createIndex.js @@ -1,6 +1,7 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./'); +var sliced = require('sliced'); module.exports = Node.define({ type: 'CREATE INDEX', @@ -8,11 +9,8 @@ module.exports = Node.define({ constructor: function(table, indexName) { Node.call(this); - this.table = table; - this.names = []; - this.columns = []; - this.valueSets = []; - this.options = { indexName: indexName, columns: [] }; + this.table = table; + this.options = { indexName: indexName, columns: [] }; }, unique: function() { @@ -36,7 +34,7 @@ module.exports = Node.define({ }, on: function() { - var args = Array.prototype.slice.call(arguments); + var args = sliced(arguments); this.options.columns = this.options.columns.concat(args); return this; }, diff --git a/lib/node/dropIndex.js b/lib/node/dropIndex.js index 3b09f517..9b5e020d 100644 --- a/lib/node/dropIndex.js +++ b/lib/node/dropIndex.js @@ -1,13 +1,11 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./'); module.exports = Node.define({ type: 'DROP INDEX', constructor: function(table, indexName) { - var args = Array.prototype.slice.call(arguments); - if (!indexName) { throw new Error('No index defined!'); } else if (Array.isArray(indexName) && (typeof indexName[0] === 'string')) { @@ -19,11 +17,8 @@ module.exports = Node.define({ Node.call(this); - this.table = table; - this.names = []; - this.columns = []; - this.valueSets = []; - this.options = { indexName: indexName }; + this.table = table; + this.options = { indexName: indexName }; }, indexName: function() { diff --git a/lib/node/indexes.js b/lib/node/indexes.js index 7777c8f7..1911db9a 100644 --- a/lib/node/indexes.js +++ b/lib/node/indexes.js @@ -1,15 +1,12 @@ 'use strict'; -var Node = require(__dirname); +var Node = require('./'); var IndexesNode = module.exports = Node.define({ type: 'INDEXES', constructor: function(table) { Node.call(this); - this.table = table; - this.names = []; - this.columns = []; - this.valueSets = []; + this.table = table; } }); diff --git a/lib/node/insert.js b/lib/node/insert.js index 07156d8c..35892326 100644 --- a/lib/node/insert.js +++ b/lib/node/insert.js @@ -1,8 +1,8 @@ 'use strict'; -var Node = require(__dirname); +var DefaultNode = require('./default'); +var Node = require('./'); var ParameterNode = require('./parameter'); -var DefaultNode = require('./default'); var Insert = Node.define({ type: 'INSERT', @@ -34,7 +34,7 @@ Insert.prototype.add = function (nodes) { }; /* - * Get paramters for all values to be inserted. This function + * Get parameters for all values to be inserted. This function * handles handles bulk inserts, where keys may be present * in some objects and not others. When keys are not present, * the insert should refer to the column value as DEFAULT. From 70aedf5f61a2db55a8bc06436105ce567c0aedb4 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Mon, 22 Jul 2013 12:46:06 +0100 Subject: [PATCH 188/507] Add bitwise AND, OR for binary expressions. --- lib/node/valueExpression.js | 2 ++ test/binary-clause-tests.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 66de6fea..450a4767 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -72,6 +72,8 @@ var ValueExpressionMixin = module.exports = function() { modulo : binaryMethod('%'), leftShift : binaryMethod('<<'), rightShift : binaryMethod('>>'), + bitwiseAnd : binaryMethod('&'), + bitwiseOr : binaryMethod('|'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 30607bcf..42a9b980 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -27,6 +27,8 @@ test('operators', function() { assert.equal(Foo.baz.multiply(1).operator, '*'); assert.equal(Foo.baz.leftShift(1).operator, '<<'); assert.equal(Foo.baz.rightShift(1).operator, '>>'); + assert.equal(Foo.baz.bitwiseAnd(1).operator, '&'); + assert.equal(Foo.baz.bitwiseOr(1).operator, '|'); assert.equal(Foo.baz.divide(1).operator, '/'); assert.equal(Foo.baz.modulo(1).operator, '%'); }); From 9182d985c04fa58abf99691700e3e561bc326ef7 Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Mon, 22 Jul 2013 12:30:40 +0100 Subject: [PATCH 189/507] CastNode and tests. --- lib/dialect/postgres.js | 6 ++ lib/node/cast.js | 27 +++++++++ lib/node/valueExpression.js | 8 ++- test/dialects/cast-tests.js | 113 ++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 lib/node/cast.js create mode 100644 test/dialects/cast-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 1730c7b2..00bb06b3 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -102,6 +102,7 @@ Postgres.prototype.visit = function(node) { case 'DROP' : return this.visitDrop(node); case 'ALIAS' : return this.visitAlias(node); case 'ALTER' : return this.visitAlter(node); + case 'CAST' : return this.visitCast(node); case 'FROM' : return this.visitFrom(node); case 'WHERE' : return this.visitWhere(node); case 'ORDER BY' : return this.visitOrderBy(node); @@ -250,6 +251,11 @@ Postgres.prototype.visitAlter = function(alter) { return result; }; +Postgres.prototype.visitCast = function(cast) { + var result = ['CAST(' + this.visit(cast.value) + ' AS ' + cast.data_type + ')']; + return result; +}; + Postgres.prototype.visitFrom = function(from) { var result = []; if (from.skipFromStatement) { diff --git a/lib/node/cast.js b/lib/node/cast.js new file mode 100644 index 00000000..ec7281fc --- /dev/null +++ b/lib/node/cast.js @@ -0,0 +1,27 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var CastNode = Node.define({ + type: 'CAST', + constructor: function(value, data_type) { + Node.call(this); + this.value = value; + this.data_type = data_type; + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(CastNode.prototype, valueExpressionMixin()); + } + } +}); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(CastNode.prototype, AliasNode.AliasMixin); + +module.exports = CastNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 66de6fea..c7fdccdb 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -19,6 +19,7 @@ var ValueExpressionMixin = module.exports = function() { var UnaryNode = require(__dirname + '/unary'); var BinaryNode = require(__dirname + '/binary'); var TernaryNode = require(__dirname + '/ternary'); + var CastNode = require(__dirname + '/cast'); var unaryMethod = function(operator) { /*jshint unused: false */ @@ -52,6 +53,10 @@ var ValueExpressionMixin = module.exports = function() { }; }; + var castMethod = function(data_type) { + return new CastNode(this.toNode(), data_type); + } + return { isNull : unaryMethod('IS NULL'), isNotNull : unaryMethod('IS NOT NULL'), @@ -76,6 +81,7 @@ var ValueExpressionMixin = module.exports = function() { notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), notIn : binaryMethod('NOT IN'), - between : ternaryMethod('BETWEEN', 'AND') + between : ternaryMethod('BETWEEN', 'AND'), + cast : castMethod }; }; diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js new file mode 100644 index 00000000..d7400df1 --- /dev/null +++ b/test/dialects/cast-tests.js @@ -0,0 +1,113 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var post = Harness.definePostTable(); +var Table = require(__dirname + '/../../lib/table'); + +// Cast columns. +Harness.test({ + query: customer.select(customer.age.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`' + }, + params: [] +}); + +Harness.test({ + query: customer.select(customer.name.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`' + }, + params: [] +}); + +// Cast binary expressions. +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"', + }, + 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`', + }, + params: [] +}); + +// Cast cast expressions. +Harness.test({ + query: customer.select(customer.name.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`' + }, + params: [] +}); + +// Cast in WHERE. +Harness.test({ + query: customer.select(customer.name).where(customer.age.cast('int').plus(100).equals(150)), + pg: { + 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)' + }, + sqlite: { + 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)' + }, + mysql: { + 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] +}); + +// Alias cast. +Harness.test({ + query: customer.select(customer.age.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`' + }, + params: [] +}); From 0a6048a128bd02a228b6b5d4364578c9e5105749 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 22 Jul 2013 19:23:48 +0200 Subject: [PATCH 190/507] save the chosen dialect name --- lib/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index 4ab93b01..74f43d4c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,9 +12,8 @@ var Table = require('./table'); var DEFAULT_DIALECT = 'postgres'; var Sql = function(dialect) { - dialect = dialect || DEFAULT_DIALECT; - - this.setDialect(dialect); + this.dialectName = dialect || DEFAULT_DIALECT; + this.setDialect(this.dialectName); // attach the standard SQL functions to this instance this.functions = functions.getStandardFunctions(this); @@ -48,7 +47,8 @@ Sql.prototype.select = function() { // Set the dialect Sql.prototype.setDialect = function(dialect) { - this.dialect = getDialect(dialect); + this.dialectName = dialect; + this.dialect = getDialect(this.dialectName); return this; }; From 4492b582b8bfa6861197f05345a4ed1c724e7244 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 22 Jul 2013 20:11:38 +0200 Subject: [PATCH 191/507] dry --- lib/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 74f43d4c..8999552d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -12,8 +12,7 @@ var Table = require('./table'); var DEFAULT_DIALECT = 'postgres'; var Sql = function(dialect) { - this.dialectName = dialect || DEFAULT_DIALECT; - this.setDialect(this.dialectName); + this.setDialect(dialect || DEFAULT_DIALECT); // attach the standard SQL functions to this instance this.functions = functions.getStandardFunctions(this); @@ -47,8 +46,9 @@ Sql.prototype.select = function() { // Set the dialect Sql.prototype.setDialect = function(dialect) { + this.dialect = getDialect(dialect); this.dialectName = dialect; - this.dialect = getDialect(this.dialectName); + return this; }; From 6ed8932fefe7c8b192a924eb079ab7b62fa2bad4 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Mon, 22 Jul 2013 20:11:47 +0200 Subject: [PATCH 192/507] tests for dialectName --- test/index-tests.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/index-tests.js b/test/index-tests.js index 614aee95..8aa971c8 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -16,6 +16,18 @@ suite('index', function() { }); }); + test('stores the default dialect\'s name if none has been passed', function() { + assert.equal(sql.create().dialectName, 'postgres'); + }); + + test('stores the sqlite dialect', function() { + assert.equal(sql.create('sqlite').dialectName, 'sqlite'); + }); + + test('stores the mysql dialect', function() { + assert.equal(sql.create('mysql').dialectName, 'mysql'); + }); + 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)'); From 42244143471ad4b113591e6337b01563db2558c8 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 22 Jul 2013 12:23:39 -0700 Subject: [PATCH 193/507] data_type to dataType --- lib/dialect/postgres.js | 2 +- lib/node/cast.js | 4 ++-- lib/node/valueExpression.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 00bb06b3..b1d3369a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -252,7 +252,7 @@ Postgres.prototype.visitAlter = function(alter) { }; Postgres.prototype.visitCast = function(cast) { - var result = ['CAST(' + this.visit(cast.value) + ' AS ' + cast.data_type + ')']; + var result = ['CAST(' + this.visit(cast.value) + ' AS ' + cast.dataType + ')']; return result; }; diff --git a/lib/node/cast.js b/lib/node/cast.js index ec7281fc..60966ea9 100644 --- a/lib/node/cast.js +++ b/lib/node/cast.js @@ -7,10 +7,10 @@ var valueExpressionMixin = require(__dirname + '/valueExpression'); var valueExpressionMixed = false; var CastNode = Node.define({ type: 'CAST', - constructor: function(value, data_type) { + constructor: function(value, dataType) { Node.call(this); this.value = value; - this.data_type = data_type; + this.dataType = dataType; // Delay mixin to runtime, when all nodes have been defined, and // mixin only once. ValueExpressionMixin has circular dependencies. if (!valueExpressionMixed) { diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index c7fdccdb..b49e8641 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -53,8 +53,8 @@ var ValueExpressionMixin = module.exports = function() { }; }; - var castMethod = function(data_type) { - return new CastNode(this.toNode(), data_type); + var castMethod = function(dataType) { + return new CastNode(this.toNode(), dataType); } return { From 27291717eb5b5641f921cb3d634465e7a6ba0e64 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 22 Jul 2013 13:43:22 -0700 Subject: [PATCH 194/507] adding bitwise xor and bitwise not --- lib/node/valueExpression.js | 2 ++ test/binary-clause-tests.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 450a4767..33d2474a 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -73,7 +73,9 @@ var ValueExpressionMixin = module.exports = function() { leftShift : binaryMethod('<<'), rightShift : binaryMethod('>>'), bitwiseAnd : binaryMethod('&'), + bitwiseNot : binaryMethod('~'), bitwiseOr : binaryMethod('|'), + bitwiseXor : binaryMethod('#'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 42a9b980..dc5f2f38 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -28,7 +28,9 @@ test('operators', function() { assert.equal(Foo.baz.leftShift(1).operator, '<<'); assert.equal(Foo.baz.rightShift(1).operator, '>>'); assert.equal(Foo.baz.bitwiseAnd(1).operator, '&'); + assert.equal(Foo.baz.bitwiseNot(1).operator, '~'); assert.equal(Foo.baz.bitwiseOr(1).operator, '|'); + assert.equal(Foo.baz.bitwiseXor(1).operator, '#'); assert.equal(Foo.baz.divide(1).operator, '/'); assert.equal(Foo.baz.modulo(1).operator, '%'); }); From 5282772fc73697a191ca8eecfcabec105fb7364c Mon Sep 17 00:00:00 2001 From: bmc Date: Mon, 22 Jul 2013 15:45:45 -0500 Subject: [PATCH 195/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1dc64752..263cf867 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.25.0", + "version": "0.26.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 030f156200f3b1775d1167cb6db67a05642f53d4 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sat, 27 Jul 2013 17:25:46 -0700 Subject: [PATCH 196/507] order by value node --- lib/column.js | 8 +- lib/dialect/postgres.js | 10 +-- .../{orderByColumn.js => orderByValue.js} | 6 +- lib/node/valueExpression.js | 28 ++++-- test/dialects/order-tests.js | 88 ++++++++++++++++++- 5 files changed, 119 insertions(+), 21 deletions(-) rename lib/node/{orderByColumn.js => orderByValue.js} (57%) diff --git a/lib/column.js b/lib/column.js index 8f835b42..d22c6544 100644 --- a/lib/column.js +++ b/lib/column.js @@ -2,7 +2,7 @@ var _ = require('lodash'); var ColumnNode = require('./node/column'); -var OrderByColumnNode = require('./node/orderByColumn'); +var OrderByValueNode = require('./node/orderByValue'); var TextNode = require('./node/text'); var valueExpressionMixin = require('./node/valueExpression'); @@ -13,9 +13,9 @@ var Column = function(config) { } this.asc = this.ascending = this; this.alias = null; - this.desc = this.descending = new OrderByColumnNode({ - column: this.toNode(), - direction: new TextNode('DESC') + this.desc = this.descending = new OrderByValueNode({ + value : this.toNode(), + direction : new TextNode('DESC') }); this.dataType = config.dataType; }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 72ab7adb..bf23a8c4 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -110,7 +110,7 @@ Postgres.prototype.visit = function(node) { case 'FROM' : return this.visitFrom(node); case 'WHERE' : return this.visitWhere(node); case 'ORDER BY' : return this.visitOrderBy(node); - case 'ORDER BY COLUMN' : return this.visitOrderByColumn(node); + case 'ORDER BY VALUE' : return this.visitOrderByValue(node); case 'GROUP BY' : return this.visitGroupBy(node); case 'HAVING' : return this.visitHaving(node); case 'RETURNING' : return this.visitReturning(node); @@ -284,10 +284,10 @@ Postgres.prototype.visitOrderBy = function(orderBy) { return result; }; -Postgres.prototype.visitOrderByColumn = function(column) { - var text = this.visit(column.column); - if (column.direction) { - text += ' ' + this.visit(column.direction); +Postgres.prototype.visitOrderByValue = function(orderByValue) { + var text = this.visit(orderByValue.value); + if (orderByValue.direction) { + text += ' ' + this.visit(orderByValue.direction); } return [text]; }; diff --git a/lib/node/orderByColumn.js b/lib/node/orderByValue.js similarity index 57% rename from lib/node/orderByColumn.js rename to lib/node/orderByValue.js index 376abc3f..90127e55 100644 --- a/lib/node/orderByColumn.js +++ b/lib/node/orderByValue.js @@ -1,11 +1,11 @@ 'use strict'; var Node = require(__dirname); -var OrderByColumn = module.exports = Node.define({ - type: 'ORDER BY COLUMN', +var OrderByValue = module.exports = Node.define({ + type: 'ORDER BY VALUE', constructor: function(config) { Node.call(this); - this.column = config.column; + this.value = config.value; this.direction = config.direction; } }); diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 2d5bc106..e77b968a 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -1,8 +1,10 @@ 'use strict'; -var _ = require('lodash'); -var Node = require(__dirname); -var ParameterNode = require(__dirname + '/parameter'); +var _ = require('lodash'); +var Node = require('./'); +var OrderByValueNode = require('./orderByValue'); +var ParameterNode = require('./parameter'); +var TextNode = require('./text'); // Process values, wrapping them in ParameterNode if necessary. var processParams = function(val) { @@ -13,10 +15,10 @@ var processParams = function(val) { // ValueExpressionMixin is evaluated at runtime, hence the // "thunk" around it. var ValueExpressionMixin = module.exports = function() { - var PostfixUnaryNode = require(__dirname + '/postfixUnary'); - var BinaryNode = require(__dirname + '/binary'); - var TernaryNode = require(__dirname + '/ternary'); - var CastNode = require(__dirname + '/cast'); + var BinaryNode = require('./binary'); + var CastNode = require('./cast'); + var PostfixUnaryNode = require('./postfixUnary'); + var TernaryNode = require('./ternary'); var postfixUnaryMethod = function(operator) { /*jshint unused: false */ @@ -54,6 +56,15 @@ var ValueExpressionMixin = module.exports = function() { return new CastNode(this.toNode(), dataType); } + var orderMethod = function(direction) { + return function() { + return new OrderByValueNode({ + value : this.toNode(), + direction : direction ? new TextNode(direction) : undefined + }); + }; + } + return { isNull : postfixUnaryMethod('IS NULL'), isNotNull : postfixUnaryMethod('IS NOT NULL'), @@ -83,6 +94,7 @@ var ValueExpressionMixin = module.exports = function() { in : binaryMethod('IN'), notIn : binaryMethod('NOT IN'), between : ternaryMethod('BETWEEN', 'AND'), - cast : castMethod + cast : castMethod, + descending : orderMethod('DESC') }; }; diff --git a/test/dialects/order-tests.js b/test/dialects/order-tests.js index 64f48e1e..297ce99d 100644 --- a/test/dialects/order-tests.js +++ b/test/dialects/order-tests.js @@ -1,7 +1,8 @@ 'use strict'; var Harness = require('./support'); -var post = Harness.definePostTable(); +var post = Harness.definePostTable(); +var sql = require('../../lib'); Harness.test({ query: post.select(post.content).order(post.content), @@ -87,3 +88,88 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: post.select(post.content.isNull()).order(post.content.isNull()), + pg: { + 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)' + }, + sqlite: { + 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)' + }, + mysql: { + 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: [] +}); + +Harness.test({ + query: post.select(post.content.isNull()).order(post.content.isNull().descending()), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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: [] +}); + +Harness.test({ + query: post.select(post.content.isNull()).order(post.content.isNull()), + pg: { + 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)' + }, + sqlite: { + 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)' + }, + mysql: { + 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: [] +}); + +Harness.test({ + query: post.select(sql.functions.RTRIM(post.content)).order(sql.functions.RTRIM(post.content)), + pg: { + text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' + }, + sqlite: { + text : 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")', + string: 'SELECT RTRIM("post"."content") FROM "post" ORDER BY RTRIM("post"."content")' + }, + mysql: { + 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: [] +}); + +Harness.test({ + query: post.select(sql.functions.RTRIM(post.content)).order(sql.functions.RTRIM(post.content).descending()), + pg: { + 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' + }, + sqlite: { + 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' + }, + mysql: { + 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 46a6b03efd3a7ed2bff0c9535da874120b8c08c7 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 28 Jul 2013 00:42:00 -0700 Subject: [PATCH 197/507] jshint fix --- lib/node/valueExpression.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index e77b968a..22cf4a6b 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -54,7 +54,7 @@ var ValueExpressionMixin = module.exports = function() { var castMethod = function(dataType) { return new CastNode(this.toNode(), dataType); - } + }; var orderMethod = function(direction) { return function() { @@ -63,7 +63,7 @@ var ValueExpressionMixin = module.exports = function() { direction : direction ? new TextNode(direction) : undefined }); }; - } + }; return { isNull : postfixUnaryMethod('IS NULL'), From ba9823d18869810549beb1cde309e7c6d454095c Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 28 Jul 2013 00:48:59 -0700 Subject: [PATCH 198/507] new version of jshint caught some new issues, fixing issues --- .jshintrc | 9 ++++++++- lib/column.js | 6 ++++-- lib/dialect/index.js | 2 ++ lib/dialect/mysql.js | 4 +++- lib/dialect/postgres.js | 5 +++-- lib/joiner.js | 15 ++++++++------- lib/node/index.js | 11 ++++++----- lib/node/indexes.js | 5 ++++- lib/node/orderByColumn.js | 4 +++- lib/node/query.js | 10 +++++++--- lib/node/valueExpression.js | 8 ++++---- lib/node/where.js | 19 +++++++++++-------- lib/table.js | 18 +++++++++++------- test/binary-clause-tests.js | 1 - test/clause-definition.js | 1 - test/column-tests.js | 2 ++ test/dialects/aggregate-tests.js | 2 -- test/dialects/alias-tests.js | 2 -- test/dialects/binary-clause-tests.js | 1 - test/dialects/cast-tests.js | 2 -- test/dialects/subquery-tests.js | 1 - test/dialects/support.js | 1 - test/dialects/ternary-clause-tests.js | 1 - test/dialects/tostring-tests.js | 7 +++---- test/dialects/unary-clause-tests.js | 1 - test/function-tests.js | 1 - test/index-tests.js | 1 - test/select-tests.js | 1 - test/table-tests.js | 3 --- test/ternary-clause-tests.js | 1 - test/unary-clause-tests.js | 1 - test/value-expression-tests.js | 5 +++-- 32 files changed, 82 insertions(+), 69 deletions(-) diff --git a/.jshintrc b/.jshintrc index c1f2978b..a8e1e5f9 100644 --- a/.jshintrc +++ b/.jshintrc @@ -1,3 +1,10 @@ { - "node": true + "node": true, + "globals": { + "describe" : true, + "it" : true, + "Node" : true, + "suite" : true, + "test" : true + } } diff --git a/lib/column.js b/lib/column.js index 8f835b42..f9710a7d 100644 --- a/lib/column.js +++ b/lib/column.js @@ -8,8 +8,10 @@ var valueExpressionMixin = require('./node/valueExpression'); var Column = function(config) { this.table = config.table; - for(var name in config) { - this[name] = config[name]; + for (var name in config) { + if (config.hasOwnProperty(name)) { + this[name] = config[name]; + } } this.asc = this.ascending = this; this.alias = null; diff --git a/lib/dialect/index.js b/lib/dialect/index.js index e04a1b4e..06dbd8c6 100644 --- a/lib/dialect/index.js +++ b/lib/dialect/index.js @@ -1,3 +1,5 @@ +'use strict'; + // given a dialect name, return the class var getDialect = function(dialect) { switch (dialect.toLowerCase()) { diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 4765fa91..64ad8ef1 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -48,7 +48,9 @@ Mysql.prototype.visitRenameColumn = function(renameColumn) { Mysql.prototype.visitInsert = function(insert) { var result = Postgres.prototype.visitInsert.call(this, insert); - if (result[2] === 'DEFAULT VALUES') result[2] = '() VALUES ()'; + if (result[2] === 'DEFAULT VALUES') { + result[2] = '() VALUES ()'; + } return result; }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 72ab7adb..09886a09 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -59,6 +59,7 @@ Postgres.prototype._getParameterValue = function(value) { }; Postgres.prototype._getParameterPlaceholder = function(index, value) { + /* jshint unused: false */ return '$' + index; }; @@ -245,8 +246,6 @@ Postgres.prototype.visitAlter = function(alter) { this._visitingAlter = true; // don't auto-generate from clause var table = this._queryNode.table; - // TODO: col_nodes is unused? - var col_nodes = table.columns.map(function(col) { return col.toNode(); }); var result = [ 'ALTER TABLE', this.visit(table.toNode()), @@ -508,6 +507,7 @@ Postgres.prototype.visitParameter = function(parameter) { }; Postgres.prototype.visitDefault = function(parameter) { + /* jshint unused: false */ return ['DEFAULT']; }; @@ -557,6 +557,7 @@ Postgres.prototype.visitModifier = function(node) { }; Postgres.prototype.visitIndexes = function(node) { + /* jshint unused: false */ var tableName = this.visit(this._queryNode.table.toNode()); return [ diff --git a/lib/joiner.js b/lib/joiner.js index 249eb1ea..5ce82cf9 100644 --- a/lib/joiner.js +++ b/lib/joiner.js @@ -1,7 +1,9 @@ +'use strict'; + var getPrimaryKeyColumn = function(table) { - for(var i = 0; i < table.columns.length; i++) { + for (var i = 0; i < table.columns.length; i++) { var col = table.columns[i]; - if(col.primaryKey) { + if (col.primaryKey) { return col; } } @@ -9,11 +11,11 @@ var getPrimaryKeyColumn = function(table) { var findReference = function(left, right) { // find reference - for(var i = 0; i < right.columns.length; i++) { + for (var i = 0; i < right.columns.length; i++) { var col = right.columns[i]; - if(col.references) { + if (col.references) { var leftName = left.getName(); - if(col.references == leftName || col.references.table == leftName) { + if (col.references === leftName || col.references.table === leftName) { var leftCol = left[col.references.column] || getPrimaryKeyColumn(left); return { left: leftCol, @@ -29,9 +31,8 @@ module.exports = { // requires one column to have { references: {table: 'foreignTableName', column: 'foreignColumnName'}} // or to have { references: 'foreignTableName'} -- in which case the foreign table's primary key is assumed leftJoin: function(left, right) { - var leftCol, rightCol; var ref = findReference(left, right); - if(!ref) { + if (!ref) { ref = findReference(right, left); } return left.join(right).on(ref.left.equals(ref.right)); diff --git a/lib/node/index.js b/lib/node/index.js index 7112d9be..74e240d0 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,12 +1,11 @@ 'use strict'; -var _ = require('lodash'); var assert = require('assert'); var getDialect = require('../dialect'); var util = require('util'); -/* jshint unused: false */ var Node = function(type) { + /* jshint unused: false */ this.nodes = []; }; @@ -62,12 +61,14 @@ Node.define = function(def) { Node.call(this); }; // allow custom sub-class constructor - if(def.constructor && def.constructor != {}.constructor) { + if(def.constructor && def.constructor !== {}.constructor) { c = def.constructor; } util.inherits(c, Node); - for(var key in def) { - c.prototype[key] = def[key]; + for (var key in def) { + if (def.hasOwnProperty(key)) { + c.prototype[key] = def[key]; + } } return c; }; diff --git a/lib/node/indexes.js b/lib/node/indexes.js index 1911db9a..b1614a9a 100644 --- a/lib/node/indexes.js +++ b/lib/node/indexes.js @@ -1,7 +1,8 @@ 'use strict'; var Node = require('./'); -var IndexesNode = module.exports = Node.define({ + +var IndexesNode = Node.define({ type: 'INDEXES', constructor: function(table) { @@ -10,3 +11,5 @@ var IndexesNode = module.exports = Node.define({ this.table = table; } }); + +module.exports = IndexesNode; diff --git a/lib/node/orderByColumn.js b/lib/node/orderByColumn.js index 376abc3f..22ccc378 100644 --- a/lib/node/orderByColumn.js +++ b/lib/node/orderByColumn.js @@ -1,7 +1,7 @@ 'use strict'; var Node = require(__dirname); -var OrderByColumn = module.exports = Node.define({ +var OrderByColumn = Node.define({ type: 'ORDER BY COLUMN', constructor: function(config) { Node.call(this); @@ -9,3 +9,5 @@ var OrderByColumn = module.exports = Node.define({ this.direction = config.direction; } }); + + module.exports = OrderByColumn; diff --git a/lib/node/query.js b/lib/node/query.js index e4b32e0e..90b12143 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -52,7 +52,9 @@ var Query = Node.define({ constructor: function(table) { Node.call(this); this.table = table; - if (table) this.sql = table.sql; + if (table) { + this.sql = table.sql; + } }, select: function() { var select; @@ -101,7 +103,9 @@ var Query = Node.define({ return this; } // calling #where twice functions like calling #where & then #and - if (this.whereClause) return this.and(node); + if (this.whereClause) { + return this.and(node); + } this.whereClause = new Where(this.table); this.whereClause.add(node); return this.add(this.whereClause); @@ -141,7 +145,7 @@ var Query = Node.define({ var args = sliced(arguments); // object literal - if (arguments.length == 1 && !o.toNode && !o.forEach) { + if (arguments.length === 1 && !o.toNode && !o.forEach) { args = Object.keys(o).map(function(key) { return self.table.get(key).value(o[key]); }); diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 2d5bc106..f0acbb25 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -1,7 +1,5 @@ 'use strict'; -var _ = require('lodash'); -var Node = require(__dirname); var ParameterNode = require(__dirname + '/parameter'); // Process values, wrapping them in ParameterNode if necessary. @@ -12,7 +10,7 @@ var processParams = function(val) { // Value expressions can be composed to form new value expressions. // ValueExpressionMixin is evaluated at runtime, hence the // "thunk" around it. -var ValueExpressionMixin = module.exports = function() { +var ValueExpressionMixin = function() { var PostfixUnaryNode = require(__dirname + '/postfixUnary'); var BinaryNode = require(__dirname + '/binary'); var TernaryNode = require(__dirname + '/ternary'); @@ -52,7 +50,7 @@ var ValueExpressionMixin = module.exports = function() { var castMethod = function(dataType) { return new CastNode(this.toNode(), dataType); - } + }; return { isNull : postfixUnaryMethod('IS NULL'), @@ -86,3 +84,5 @@ var ValueExpressionMixin = module.exports = function() { cast : castMethod }; }; + +module.exports = ValueExpressionMixin; diff --git a/lib/node/where.js b/lib/node/where.js index 3b22ae9d..b7f2be1b 100644 --- a/lib/node/where.js +++ b/lib/node/where.js @@ -6,18 +6,21 @@ var TextNode = require(__dirname + '/text'); var normalizeNode = function(table, node) { var result = node; - if(typeof node == 'string') { + if(typeof node === 'string') { result = new TextNode('(' + node + ')'); } - else if (!node.toNode && typeof node == 'object'){ + else if (!node.toNode && typeof node === 'object'){ result = false; for (var colName in node) { - var column = table.getColumn(colName); - var query = column.equals(node[colName]); - if (!result) - result = query; - else - result = result.and(query); + if (node.hasOwnProperty(colName)) { + var column = table.getColumn(colName); + var query = column.equals(node[colName]); + if (!result) { + result = query; + } else { + result = result.and(query); + } + } } } return result; diff --git a/lib/table.js b/lib/table.js index 9bf84ab7..746cd1e6 100644 --- a/lib/table.js +++ b/lib/table.js @@ -15,20 +15,24 @@ var Table = function(config) { this._initialConfig = config; this.columns = []; this.table = this; - if (!config.sql) config.sql = require('./index'); + if (!config.sql) { + config.sql = require('./index'); + } this.sql = config.sql; }; Table.define = function(config) { var table = new Table(config); // allow hash of columns as well as array - if(config.columns && !util.isArray(config.columns)) { + if (config.columns && !util.isArray(config.columns)) { var cols = []; - for(var key in config.columns) { - var col = config.columns[key]; - col.name = key; - cols.push(col); + for (var key in config.columns) { + if (config.columns.hasOwnProperty(key)) { + var col = config.columns[key]; + col.name = key; + cols.push(col); + } } config.columns = cols; @@ -89,7 +93,7 @@ Table.prototype.get = function(colName) { for(var i = 0; i < this.columns.length; i++) { var col = this.columns[i]; - if(col.name == colName) { + if (col.name === colName) { return col; } } diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index dc5f2f38..8c3cf0ea 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -1,4 +1,3 @@ -/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/clause-definition.js b/test/clause-definition.js index 6f918dad..ebbf936d 100644 --- a/test/clause-definition.js +++ b/test/clause-definition.js @@ -1,4 +1,3 @@ -/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/column-tests.js b/test/column-tests.js index 0db0bca3..93ad715a 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -1,3 +1,5 @@ +'use strict'; + var assert = require('assert'); var sql = require(__dirname + '/../lib'); diff --git a/test/dialects/aggregate-tests.js b/test/dialects/aggregate-tests.js index 84c38873..4eff37b3 100644 --- a/test/dialects/aggregate-tests.js +++ b/test/dialects/aggregate-tests.js @@ -1,7 +1,5 @@ -/* global test */ 'use strict'; -var assert = require('assert'); var Harness = require('./support'); var post = Harness.definePostTable(); diff --git a/test/dialects/alias-tests.js b/test/dialects/alias-tests.js index e0fc8709..6981aaa6 100644 --- a/test/dialects/alias-tests.js +++ b/test/dialects/alias-tests.js @@ -2,8 +2,6 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); -var post = Harness.definePostTable(); -var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select(customer.name.isNull().as('nameIsNull')), diff --git a/test/dialects/binary-clause-tests.js b/test/dialects/binary-clause-tests.js index a2002225..23c299c5 100644 --- a/test/dialects/binary-clause-tests.js +++ b/test/dialects/binary-clause-tests.js @@ -3,7 +3,6 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); var post = Harness.definePostTable(); -var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select(customer.name.plus(customer.age)), diff --git a/test/dialects/cast-tests.js b/test/dialects/cast-tests.js index d7400df1..90e913e4 100644 --- a/test/dialects/cast-tests.js +++ b/test/dialects/cast-tests.js @@ -2,8 +2,6 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); -var post = Harness.definePostTable(); -var Table = require(__dirname + '/../../lib/table'); // Cast columns. Harness.test({ diff --git a/test/dialects/subquery-tests.js b/test/dialects/subquery-tests.js index 0d9e4159..5c60c271 100644 --- a/test/dialects/subquery-tests.js +++ b/test/dialects/subquery-tests.js @@ -3,7 +3,6 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); var user = Harness.defineUserTable(); -var Table = require('../../lib/table'); var Sql = require('../../lib'); Harness.test({ diff --git a/test/dialects/support.js b/test/dialects/support.js index a5b48e59..6eabee5c 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -1,4 +1,3 @@ -/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/dialects/ternary-clause-tests.js b/test/dialects/ternary-clause-tests.js index 37ff8a3b..20ba7c38 100644 --- a/test/dialects/ternary-clause-tests.js +++ b/test/dialects/ternary-clause-tests.js @@ -3,7 +3,6 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); var post = Harness.definePostTable(); -var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select().where(customer.age.between(18, 25)), diff --git a/test/dialects/tostring-tests.js b/test/dialects/tostring-tests.js index df55dda6..d5e56cc8 100644 --- a/test/dialects/tostring-tests.js +++ b/test/dialects/tostring-tests.js @@ -1,9 +1,8 @@ 'use strict'; -var assert = require('assert'); -var Harness = require('./support'); -var ParameterNode = require('../../lib/node/parameter'); -var post = Harness.definePostTable(); +var assert = require('assert'); +var Harness = require('./support'); +var post = Harness.definePostTable(); // Null Harness.test({ diff --git a/test/dialects/unary-clause-tests.js b/test/dialects/unary-clause-tests.js index 8c26c624..e7f6e3bd 100644 --- a/test/dialects/unary-clause-tests.js +++ b/test/dialects/unary-clause-tests.js @@ -3,7 +3,6 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); var post = Harness.definePostTable(); -var Table = require(__dirname + '/../../lib/table'); Harness.test({ query: customer.select().where(customer.age.isNotNull()), diff --git a/test/function-tests.js b/test/function-tests.js index 3cac3a9b..076c2ed5 100644 --- a/test/function-tests.js +++ b/test/function-tests.js @@ -1,4 +1,3 @@ -/* global suite, test */ 'use strict'; var assert = require('assert'); diff --git a/test/index-tests.js b/test/index-tests.js index 8aa971c8..a959d357 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -1,4 +1,3 @@ -/* global suite, test */ 'use strict'; var assert = require('assert'); diff --git a/test/select-tests.js b/test/select-tests.js index af8db6d2..a0befc4c 100644 --- a/test/select-tests.js +++ b/test/select-tests.js @@ -1,4 +1,3 @@ -/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/table-tests.js b/test/table-tests.js index 53401fb2..ae7d529a 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -1,4 +1,3 @@ -/* global suite, test */ 'use strict'; var assert = require('assert'); @@ -148,8 +147,6 @@ test('table with dynamic column definition', function() { table.addColumn('foo'); assert.equal(table.columns.length, 1); - var error = null; - assert.throws(function() { table.addColumn('foo'); }); diff --git a/test/ternary-clause-tests.js b/test/ternary-clause-tests.js index 71d897c3..1e7c975f 100644 --- a/test/ternary-clause-tests.js +++ b/test/ternary-clause-tests.js @@ -1,4 +1,3 @@ -/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/unary-clause-tests.js b/test/unary-clause-tests.js index 745eb20f..f5b36a1b 100644 --- a/test/unary-clause-tests.js +++ b/test/unary-clause-tests.js @@ -1,4 +1,3 @@ -/* global test */ 'use strict'; var assert = require('assert'); diff --git a/test/value-expression-tests.js b/test/value-expression-tests.js index 4ef2b7e0..ec80415a 100644 --- a/test/value-expression-tests.js +++ b/test/value-expression-tests.js @@ -1,4 +1,3 @@ -/* global suite, test */ 'use strict'; var assert = require('assert'); @@ -11,7 +10,9 @@ suite('value-expression', function() { // make sure that the node class doesn't have any conflicting properties for (var key in mixin) { - assert.equal(Node.prototype[key], undefined); + if (mixin.hasOwnProperty(key)) { + assert.equal(Node.prototype[key], undefined); + } } }); }); From e03bb354a6b256fc4bb7c7022ccc84660227ee9e Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 4 Aug 2013 13:04:24 -0700 Subject: [PATCH 199/507] fix merge conflicts --- lib/dialect/postgres.js | 8 ++++---- lib/node/orderByValue.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index ed35950c..7aabf29e 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -132,10 +132,10 @@ Postgres.prototype.visit = function(node) { case 'DROP INDEX' : return this.visitDropIndex(node); case 'FUNCTION CALL' : return this.visitFunctionCall(node); - case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); - case 'PREFIX UNARY' : return this.visitPrefixUnary(node); - case 'BINARY' : return this.visitBinary(node); - case 'TERNARY' : return this.visitTernary(node); + case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); + case 'PREFIX UNARY' : return this.visitPrefixUnary(node); + case 'BINARY' : return this.visitBinary(node); + case 'TERNARY' : return this.visitTernary(node); case 'LIMIT' : case 'OFFSET': diff --git a/lib/node/orderByValue.js b/lib/node/orderByValue.js index 74507fe3..4ac7fd8a 100644 --- a/lib/node/orderByValue.js +++ b/lib/node/orderByValue.js @@ -3,7 +3,7 @@ var Node = require(__dirname); var OrderByColumn = Node.define({ - type: 'ORDER BY COLUMN', + type: 'ORDER BY VALUE', constructor: function(config) { Node.call(this); this.value = config.value; From 6d1c239cc39850f5096af1b40d38e3a96a8f7180 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 4 Aug 2013 15:31:40 -0700 Subject: [PATCH 200/507] indexesCauses typo, corrected to indexesClause --- lib/node/query.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index 90b12143..6ef0daf0 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -190,7 +190,7 @@ var Query = Node.define({ }, create: function(indexName) { - if (this.indexesCause) { + if (this.indexesClause) { var createIndex = new CreateIndex(this.table, indexName); this.add(createIndex); return createIndex; @@ -200,7 +200,7 @@ var Query = Node.define({ }, drop: function() { - if (this.indexesCause) { + if (this.indexesClause) { var args = sliced(arguments); var dropIndex = new DropIndex(this.table, args); this.add(dropIndex); @@ -309,10 +309,10 @@ var Query = Node.define({ }, indexes: function() { - this.indexesCause = new Indexes({ + this.indexesClause = new Indexes({ table: this.table }); - return this.add(this.indexesCause); + return this.add(this.indexesClause); } }); From e5316a6825445c4e734c3a6bc5a6b7e3716ff2a5 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 5 Aug 2013 09:53:55 -0500 Subject: [PATCH 201/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 263cf867..58a9777c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.26.0", + "version": "0.27.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 819c9edc9fb213d6d310e90f993de56419575c55 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Sun, 11 Aug 2013 00:22:31 -0700 Subject: [PATCH 202/507] making primary key work inside create --- lib/dialect/postgres.js | 5 +++++ lib/node/column.js | 1 + test/dialects/create-table-tests.js | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7aabf29e..3ac32d3a 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -490,6 +490,11 @@ Postgres.prototype.visitColumn = function(columnNode) { assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); txt += ' ' + columnNode.dataType; + + if (this._visitingCreate && columnNode.primaryKey) { + // creating a column as a primary key + txt += ' PRIMARY KEY'; + } } return [txt]; }; diff --git a/lib/node/column.js b/lib/node/column.js index 9216d1bc..8c4f9c3b 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -15,6 +15,7 @@ module.exports = Node.define({ this.value = config.getValue(); this.dataType = config.dataType; this.distinct = config.distinct; + this.primaryKey = config.primaryKey; }, as: function(alias) { this.alias = alias; diff --git a/test/dialects/create-table-tests.js b/test/dialects/create-table-tests.js index df2e1a27..d6d9d45f 100644 --- a/test/dialects/create-table-tests.js +++ b/test/dialects/create-table-tests.js @@ -121,3 +121,26 @@ Harness.test({ string: 'CREATE TABLE `user` (`id` varchar(100)) ENGINE=MyISAM DEFAULT CHARSET=latin1' } }); + +Harness.test({ + query: Table.define({ + name: 'user', + columns: [{ + name: 'id', + dataType: 'int', + primaryKey: 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)' + } +}); From 7a120de2cee7afc7453af9e82361ca864e222a0c Mon Sep 17 00:00:00 2001 From: Joyce Chen Date: Fri, 16 Aug 2013 12:34:11 -0700 Subject: [PATCH 203/507] Introduce CASE expression. --- lib/dialect/postgres.js | 21 +++++ lib/node/case.js | 29 +++++++ lib/node/valueExpression.js | 35 ++++++--- test/dialects/case-tests.js | 148 ++++++++++++++++++++++++++++++++++++ 4 files changed, 222 insertions(+), 11 deletions(-) create mode 100644 lib/node/case.js create mode 100644 test/dialects/case-tests.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 7aabf29e..ea1abdd4 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -136,6 +136,7 @@ Postgres.prototype.visit = function(node) { case 'PREFIX UNARY' : return this.visitPrefixUnary(node); case 'BINARY' : return this.visitBinary(node); case 'TERNARY' : return this.visitTernary(node); + case 'CASE' : return this.visitCase(node); case 'LIMIT' : case 'OFFSET': @@ -351,6 +352,26 @@ Postgres.prototype.visitTernary = function(ternary) { return [text]; }; +Postgres.prototype.visitCase = function(caseExp) { + assert(caseExp.whenList.length == caseExp.thenList.length); + + var self = this; + var text = '(CASE'; + + for (var i = 0; i < caseExp.whenList.length; i++) { + var whenExp = ' WHEN ' + this.visit(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); + } + + text += ' END)'; + return [text]; +} + Postgres.prototype.visitQuery = function(queryNode) { this._queryNode = queryNode; // need to sort the top level query nodes on visitation priority diff --git a/lib/node/case.js b/lib/node/case.js new file mode 100644 index 00000000..b8729314 --- /dev/null +++ b/lib/node/case.js @@ -0,0 +1,29 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var CaseNode = Node.define(_.extend({ + type: 'CASE', + constructor: function(config) { + Node.call(this); + this.whenList = config.whenList; + this.thenList = config.thenList; + this.else = config.else; + + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(CaseNode.prototype, valueExpressionMixin()); + } + }, +})); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(CaseNode.prototype, AliasNode.AliasMixin); + +module.exports = CaseNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index afe421ad..02fc2291 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -17,13 +17,14 @@ var ValueExpressionMixin = function() { var CastNode = require('./cast'); var PostfixUnaryNode = require('./postfixUnary'); var TernaryNode = require('./ternary'); + var CaseNode = require('./case'); var postfixUnaryMethod = function(operator) { /*jshint unused: false */ return function(val) { return new PostfixUnaryNode({ - left: this.toNode(), - operator: operator + left : this.toNode(), + operator : operator }); }; }; @@ -31,9 +32,9 @@ var ValueExpressionMixin = function() { var binaryMethod = function(operator) { return function(val) { return new BinaryNode({ - left: this.toNode(), - operator: operator, - right: processParams(val) + left : this.toNode(), + operator : operator, + right : processParams(val) }); }; }; @@ -41,11 +42,11 @@ var ValueExpressionMixin = function() { var ternaryMethod = function(operator, separator) { return function(middle, right) { return new TernaryNode({ - left: this.toNode(), - operator: operator, - middle: processParams(middle), - separator: separator, - right: processParams(right) + left : this.toNode(), + operator : operator, + middle : processParams(middle), + separator : separator, + right : processParams(right) }); }; }; @@ -63,6 +64,17 @@ var ValueExpressionMixin = function() { }; }; + var caseMethod = function(whenList, thenList, elseBranch) { + if (undefined != elseBranch) { + elseBranch = processParams(elseBranch); + } + return new CaseNode({ + whenList : processParams(whenList), + thenList : processParams(thenList), + else : elseBranch + }) + } + return { isNull : postfixUnaryMethod('IS NULL'), isNotNull : postfixUnaryMethod('IS NOT NULL'), @@ -93,7 +105,8 @@ var ValueExpressionMixin = function() { notIn : binaryMethod('NOT IN'), between : ternaryMethod('BETWEEN', 'AND'), cast : castMethod, - descending : orderMethod('DESC') + descending : orderMethod('DESC'), + case : caseMethod }; }; diff --git a/test/dialects/case-tests.js b/test/dialects/case-tests.js new file mode 100644 index 00000000..61f193ec --- /dev/null +++ b/test/dialects/case-tests.js @@ -0,0 +1,148 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); + +// Check case expression with primary when expressions and else branch. +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"', + }, + 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"', + }, + 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`', + }, + params: [true, 0, false, 1, 2] +}); + +// Check case expression as a subexpression. +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"', + }, + 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"', + }, + 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`', + }, + params: [true, 0, false, 1, 2] +}); + +// Check case expression as subexpression on the left. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1], 2).plus(3)), + pg: { + 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"', + }, + 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"', + }, + 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`', + }, + params: [true, 0, false, 1, 2, 3] +}); + +// Check case expression with primary when expressions and compound else expression. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1], customer.age.between(10, 20))), + pg: { + 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"', + }, + 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"', + }, + 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`', + }, + params: [true, 0, false, 1, 10, 20] +}); + +// Check case expression with primary when expressions without else branch. +Harness.test({ + query: customer.select(customer.age.case([true, false], [0, 1])), + pg: { + 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"', + }, + 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"', + }, + 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`', + }, + params: [true, 0, false, 1] +}); + +// Check case expression with compound when expressions and else branch. +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"', + }, + 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"', + }, + 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`', + }, + params: [10, 20, 30, 0, 60, 1, 2] +}); + +// Check case expression without else branch. +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"', + }, + 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"', + }, + 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`', + }, + params: [10, 20, 30, 0, 60, 1] +}); + +// Check case expression with compound then expressions. +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"', + }, + 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"', + }, + 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`', + }, + params: [10, 20, 30, 5, 60, 1] +}); From 9c1c2d2eff1f846218c5c1008cfc7b79e9ba9646 Mon Sep 17 00:00:00 2001 From: janstice Date: Fri, 23 Aug 2013 16:23:48 +1200 Subject: [PATCH 204/507] Allow qualified column names w/ aggregate functions I bumped into a problem when attempting to generate something like COUNT('tablename'.'column'). --- 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 7aabf29e..49234e17 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -463,10 +463,10 @@ Postgres.prototype.visitColumn = function(columnNode) { } if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { if(table.alias) { - txt = this.quote(table.alias); + txt += this.quote(table.alias); } else { if(table.getSchema()) { - txt = this.quote(table.getSchema()); + txt += this.quote(table.getSchema()); txt += '.'; } txt += this.quote(table.getName()); From 72b97cee3ee977c0382f64fc5909dbe7fc6fb048 Mon Sep 17 00:00:00 2001 From: Shern Shiou Tan Date: Fri, 23 Aug 2013 20:10:27 +0800 Subject: [PATCH 205/507] Add prototype to change schema name --- lib/table.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/table.js b/lib/table.js index 746cd1e6..68b801ea 100644 --- a/lib/table.js +++ b/lib/table.js @@ -104,6 +104,10 @@ Table.prototype.getSchema = function() { return this._schema; }; +Table.prototype.setSchema = function(schema) { + this._schema = schema; +}; + Table.prototype.getName = function() { return this._name; }; From fb59d6bd07f469b300082b93c3945e5e9de04dd7 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 23 Aug 2013 17:04:54 -0700 Subject: [PATCH 206/507] test for schema with aggregation --- test/dialects/schema-tests.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/dialects/schema-tests.js b/test/dialects/schema-tests.js index 1068a1ce..a0fca635 100644 --- a/test/dialects/schema-tests.js +++ b/test/dialects/schema-tests.js @@ -27,6 +27,23 @@ Harness.test({ params: [] }); +Harness.test({ + query: userWithSchema.select(userWithSchema.id.count()).from(userWithSchema), + pg: { + text : 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"', + string: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"' + }, + sqlite: { + text : 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"', + string: 'SELECT COUNT("staging"."user"."id") AS "id_count" FROM "staging"."user"' + }, + mysql: { + 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: [] +}); + Harness.test({ query: userWithSchema.select(userWithSchema.id, userWithSchema.name).from(userWithSchema), pg: { From 5589ed44154f8ae76bc0040bfbbc1c4255e912d5 Mon Sep 17 00:00:00 2001 From: Shern Shiou Tan Date: Sat, 24 Aug 2013 14:13:49 +0800 Subject: [PATCH 207/507] Add change schema test --- test/table-tests.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/table-tests.js b/test/table-tests.js index ae7d529a..f58fd5e4 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -178,3 +178,10 @@ test('getColumn returns the from column', function() { assert(table.getColumn('from') instanceof Column); assert(table.get('from') instanceof Column); }); + +test('set and get schema', function () { + var table = Table.define({ name: 'foo', schema: 'bar', columns: [] }); + assert.equal(table.getSchema(), 'bar'); + table.setSchema('barbarz'); + assert.equal(table.getSchema(), 'barbarz'); +}); \ No newline at end of file From a9bdc3db8837a8c95a75e760246badaaf5f8fea6 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 31 Aug 2013 12:31:53 -0400 Subject: [PATCH 208/507] 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 209/507] - 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 210/507] 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 211/507] - 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 212/507] - 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 213/507] - 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 214/507] - 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 215/507] - 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 6e0d36e13236d23cfaa7d34e814e76f093a86eba Mon Sep 17 00:00:00 2001 From: Di Wu Date: Mon, 2 Sep 2013 14:20:59 -0700 Subject: [PATCH 216/507] Sqlite and Mysql don't support returning clause --- lib/dialect/mysql.js | 7 +++++-- lib/dialect/sqlite.js | 13 +++++++------ test/dialects/insert-tests.js | 30 ++++++++++-------------------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 64ad8ef1..cfb7e61d 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -18,11 +18,14 @@ Mysql.prototype._quoteCharacter = '`'; Mysql.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; -/* jshint unused: false */ -Mysql.prototype._getParameterPlaceholder = function(index, value) { +Mysql.prototype._getParameterPlaceholder = function() { return '?'; }; +Mysql.prototype.visitReturning = function() { + throw new Error('MySQL does not allow returning clause.'); +}; + Mysql.prototype.visitCreate = function(create) { var result = Mysql.super_.prototype.visitCreate.call(this, create); var engine = this._queryNode.table._initialConfig.engine; diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index bef7e3ac..decea81f 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -17,21 +17,22 @@ Sqlite.prototype._myClass = Sqlite; Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; -/*jshint unused: false */ -Sqlite.prototype.visitDefault = function(parameter) { +Sqlite.prototype.visitDefault = function() { throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.'); }; -/*jshint unused: false */ -Sqlite.prototype.visitDropColumn = function(dropColumn) { +Sqlite.prototype.visitDropColumn = function() { throw new Error('SQLite does not allow dropping columns.'); }; -/*jshint unused: false */ -Sqlite.prototype.visitRenameColumn = function(renameColumn) { +Sqlite.prototype.visitRenameColumn = function() { throw new Error('SQLite does not allow renaming columns.'); }; +Sqlite.prototype.visitReturning = function() { + throw new Error('SQLite does not allow returning clause.'); +}; + Sqlite.prototype.visitAddColumn = function(addColumn) { assert(!this._hasAddedAColumn, 'SQLite can not add more that one column at a time'); var result = Postgres.prototype.visitAddColumn.call(this, addColumn); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 190d00b7..29e40020 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -155,12 +155,10 @@ Harness.test({ string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, sqlite: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' + throws: true }, mysql: { - text : 'INSERT INTO `post` () VALUES () RETURNING *', - string: 'INSERT INTO `post` () VALUES () RETURNING *' + throws: true }, params: [] }); @@ -172,12 +170,10 @@ Harness.test({ string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' }, sqlite: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING *', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING *' + throws: true }, mysql: { - text : 'INSERT INTO `post` () VALUES () RETURNING *', - string: 'INSERT INTO `post` () VALUES () RETURNING *' + throws: true }, params: [] }); @@ -189,12 +185,10 @@ Harness.test({ string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' }, sqlite: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id"' + throws: true }, mysql: { - text : 'INSERT INTO `post` () VALUES () RETURNING `id`', - string: 'INSERT INTO `post` () VALUES () RETURNING `id`' + throws: true }, params: [] }); @@ -206,12 +200,10 @@ Harness.test({ string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' }, sqlite: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + throws: true }, mysql: { - text : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', - string: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`' + throws: true }, params: [] }); @@ -223,12 +215,10 @@ Harness.test({ string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' }, sqlite: { - text : 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"', - string: 'INSERT INTO "post" DEFAULT VALUES RETURNING "id", "content"' + throws: true }, mysql: { - text : 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`', - string: 'INSERT INTO `post` () VALUES () RETURNING `id`, `content`' + throws: true }, params: [] }); From a8dc4ff31322b72c018b037792ad11047e929044 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Mon, 2 Sep 2013 22:35:19 -0400 Subject: [PATCH 217/507] 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 218/507] 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 219/507] 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 220/507] 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 221/507] 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 222/507] 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 223/507] 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 224/507] 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 225/507] 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 226/507] 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 227/507] 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 228/507] 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 229/507] 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 230/507] 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 231/507] 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 232/507] 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 233/507] 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 234/507] 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 fd6291a591ddae9d2bc6457b47868536b54e6375 Mon Sep 17 00:00:00 2001 From: phestermcs Date: Thu, 12 Sep 2013 22:29:05 -0600 Subject: [PATCH 235/507] Improved support for mapping javascript properties to columns. Objects passed to insert, update can use property names, and they get mapped to column names. If a column's property name different than its sql name, property name used as column alias in generated SELECT statement. Added boolean columnWhiteList config option for table.define(). For insert, update, if table.columnWhiteList is true and passed object has properties that don't map to columns, they're ignored rather than throwing exceptions. Added boolean snakeToCamel config option for table.define(). If a column has no explicit 'property' property and table.snakeToCamel is true, column's property is set to its name converted to camelCase; i.e. make_to_camel becomes makeToCamel, and then table.makeToCamel can be used. --- lib/dialect/postgres.js | 54 ++++++++++++++++---------- lib/node/column.js | 2 + lib/node/query.js | 15 ++++++-- lib/table.js | 17 +++++++-- test/column-tests.js | 84 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 28 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a01d6311..cc435dd9 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -447,61 +447,75 @@ Postgres.prototype.visitTable = function(tableNode) { Postgres.prototype.visitColumn = function(columnNode) { var table = columnNode.table; - var inSelectClause = !this._selectOrDeleteEndIndex; - var txt = ""; + var inInsertUpdateClause = this._visitedInsert || this._visitingUpdateTargetColumn; + var inDdlClause = this._visitingAddColumn || this._visitingAlter || this._visitingCreate; + var inSelectClause = + !this._selectOrDeleteEndIndex + && !inInsertUpdateClause + && !inDdlClause + var txt = []; var closeParen = 0; if(inSelectClause && !table.alias) { if (columnNode.asArray) { closeParen++; - txt += this._arrayAggFunctionName+'('; + txt.push(this._arrayAggFunctionName+'('); } if (!!columnNode.aggregator) { closeParen++; - txt += columnNode.aggregator + '('; + txt.push(columnNode.aggregator + '('); } if (columnNode.distinct === true) { closeParen++; - txt += 'DISTINCT('; + txt.push('DISTINCT('); } } - if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) { + if(!inInsertUpdateClause && !this._visitingCreate && !this._visitingAlter) { if(table.alias) { - txt += this.quote(table.alias); + txt.push(this.quote(table.alias)); } else { if(table.getSchema()) { - txt += this.quote(table.getSchema()); - txt += '.'; + txt.push(this.quote(table.getSchema())); + txt.push('.'); } - txt += this.quote(table.getName()); + txt.push(this.quote(table.getName())); } - txt += '.'; + txt.push('.'); } if (columnNode.star) { - txt += '*'; - } else { - txt += this.quote(columnNode.name); + 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) : '')); + } + txt.push(hasAliases ? allCols.join(', ') : '*'); + } + else { + txt.push(this.quote(columnNode.name)); } if(closeParen) { for(var i = 0; i < closeParen; i++) { - txt += ')'; + txt.push(')'); } } - if(inSelectClause && columnNode.alias) { - txt += ' AS ' + this.quote(columnNode.alias); + if(inSelectClause && (columnNode.alias || columnNode.property !== columnNode.name)) { + txt.push(' AS ' + this.quote(columnNode.alias || columnNode.property)); } if(this._visitingCreate || this._visitingAddColumn) { assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name + ' (CREATE TABLE and ADD COLUMN statements require a dataType)'); - txt += ' ' + columnNode.dataType; + txt.push(' ' + columnNode.dataType); if (this._visitingCreate && columnNode.primaryKey) { // creating a column as a primary key - txt += ' PRIMARY KEY'; + txt.push(' PRIMARY KEY'); } } - return [txt]; + return [txt.join('')]; }; Postgres.prototype.visitFunctionCall = function(functionCall) { diff --git a/lib/node/column.js b/lib/node/column.js index 8c4f9c3b..98baa363 100644 --- a/lib/node/column.js +++ b/lib/node/column.js @@ -7,6 +7,7 @@ module.exports = Node.define({ constructor: function(config) { Node.call(this); this.name = config.name; + this.property = config.property || config.name; this.alias = config.alias; this.star = config.star; this.asArray = config.asArray; @@ -16,6 +17,7 @@ module.exports = Node.define({ this.dataType = config.dataType; this.distinct = config.distinct; this.primaryKey = config.primaryKey; + this.autoGenerated = !!config.autoGenerated; }, as: function(alias) { this.alias = alias; diff --git a/lib/node/query.js b/lib/node/query.js index 6ef0daf0..20a38a29 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -74,6 +74,7 @@ var Query = Node.define({ var name = select.nodes[j].alias || select.nodes[j].name; var col = new Column(select.nodes[j]); col.name = name; + col.property = name; col.table = this; if (this[name] === undefined) { this[name] = col; @@ -146,8 +147,11 @@ var Query = Node.define({ var args = sliced(arguments); // object literal if (arguments.length === 1 && !o.toNode && !o.forEach) { - args = Object.keys(o).map(function(key) { - return self.table.get(key).value(o[key]); + 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) { @@ -170,8 +174,11 @@ var Query = Node.define({ var self = this; var update = new Update(); Object.keys(o).forEach(function(key) { - var val = o[key]; - update.add(self.table.get(key).value(ParameterNode.getNodeOrParameterNode(val))); + var col = self.table.get(key); + if(col && !col.autoGenerated) { + var val = o[key]; + update.add(col.value(ParameterNode.getNodeOrParameterNode(val))); + } }); return this.add(update); }, diff --git a/lib/table.js b/lib/table.js index 68b801ea..605bd9b7 100644 --- a/lib/table.js +++ b/lib/table.js @@ -13,6 +13,8 @@ var Table = function(config) { this._schema = config.schema; this._name = config.name; this._initialConfig = config; + this.columnWhiteList = !!config.columnWhiteList; + this.snakeToCamel = !!config.snakeToCamel; this.columns = []; this.table = this; if (!config.sql) { @@ -73,7 +75,12 @@ Table.prototype.addColumn = function(col, options) { 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); - var property = col.property || col.name; + + function snakeToCamel(snakeName) { + return snakeName.replace(/[\-_]([a-z])/g, function(m, $1){ return $1.toUpperCase(); }); + } + + var property = col.property = col.property || (this.snakeToCamel ? snakeToCamel(col.name) : col.name); this[property] = this[property] || col; return this; }; @@ -82,7 +89,7 @@ Table.prototype.hasColumn = function(col) { col = this.createColumn(col); var cols = this.columns.filter(function(column) { - return column.name === col.name; + return column.property === col.property || column.name === col.name; }); return cols.length > 0; @@ -93,11 +100,13 @@ Table.prototype.get = function(colName) { for(var i = 0; i < this.columns.length; i++) { var col = this.columns[i]; - if (col.name === colName) { + if (colName === col.property || colName === col.name) { return col; } } - throw new Error('Table ' + this._name + ' does not have a column named ' + colName); + if(this.columnWhiteList) + return null; + throw new Error('Table ' + this._name + ' does not have a column or property named ' + colName); }; Table.prototype.getSchema = function() { diff --git a/test/column-tests.js b/test/column-tests.js index 93ad715a..1cf993c9 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -31,5 +31,89 @@ describe('column', function() { var col = subquery.subId.toQuery().text; assert.equal(col, '"subTable"."subId"'); }); + + describe('property', function() { + var table = sql.define({ + name: 'roundtrip', + columns: { + column_name: { property: 'propertyName' } + } + }); + it('used as alias when !== column name', function() { + assert.equal(table.propertyName.toQuery().text, '"roundtrip"."column_name" AS "propertyName"'); + }); + it('uses explicit alias when !== column name', function() { + assert.equal(table.propertyName.as('alias').toQuery().text, '"roundtrip"."column_name" AS "alias"'); + }); + it('maps to column name in insert', function() { + assert.equal(table.insert({propertyName:'propVal'}).toQuery().text, 'INSERT INTO "roundtrip" ("column_name") VALUES ($1)'); + }); + it('maps to column name in update', function() { + assert.equal(table.update({propertyName:'propVal'}).toQuery().text, 'UPDATE "roundtrip" SET "column_name" = $1'); + }); + it('explicitly selected by *', function() { + assert.equal(table.select(table.star()).from(table).toQuery().text, 'SELECT "roundtrip"."column_name" AS "propertyName" FROM "roundtrip"'); + }); + }); + + describe('autoGenerate', function() { + var table = sql.define({ + name: 'ag', + columns: { + id: {autoGenerated: true}, + name: {} + } + }); + it('does not include auto generated columns in insert', function() { + assert.equal(table.insert({id:0, name:'name'}).toQuery().text,'INSERT INTO "ag" ("name") VALUES ($1)'); + }); + it('does not include auto generated columns in update', function() { + assert.equal(table.update({id:0, name:'name'}).toQuery().text,'UPDATE "ag" SET "name" = $1'); + }); + }); + + describe('white listed', function() { + var table = sql.define({ + name: 'wl', + columnWhiteList: true, + columns: ['id', 'name'] + }); + it('excludes insert properties that are not a column', function() { + assert.equal(table.insert({id:0, _private:'_private', name:'name'}).toQuery().text, 'INSERT INTO "wl" ("id", "name") VALUES ($1, $2)'); + }); + it('excludes update properties that are not a column', function() { + assert.equal(table.update({id:0, _private:'_private', name:'name'}).toQuery().text, 'UPDATE "wl" SET "id" = $1, "name" = $2'); + }); + }); + + describe('not white listed', function() { + var table = sql.define({ + name: 'wl', + 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); + }); + it('throws for update properties that are not a column', function() { + assert.throws(function() { table.update({id:0, _private:'_private', name:'name'}) }, Error); + }); + }); + + describe('snake to camel', function() { + var table = sql.define({ + name: 'sc', + snakeToCamel: true, + columns: { + make_me_camel: {}, + not_to_camel: {property: 'not2Cam'} + } + }); + it('for snake column names with no explicit property name', function(){ + assert.equal(table.makeMeCamel.toQuery().text, '"sc"."make_me_camel" AS "makeMeCamel"'); + }); + it('but not when with explicit property name', function() { + assert.equal(table.not2Cam.toQuery().text, '"sc"."not_to_camel" AS "not2Cam"'); + }); + }) }); }); From c99ae65da38a9fc985bb9abeb8d0d5f6e1dfb877 Mon Sep 17 00:00:00 2001 From: Matin Movassate Date: Fri, 13 Sep 2013 03:39:53 -0700 Subject: [PATCH 236/507] Add first-class Array support to Postgres dialect. --- lib/dialect/postgres.js | 19 +++++++++++++++++++ lib/index.js | 8 ++++++++ lib/node/arrayCall.js | 24 ++++++++++++++++++++++++ lib/node/at.js | 27 +++++++++++++++++++++++++++ lib/node/slice.js | 28 ++++++++++++++++++++++++++++ lib/node/valueExpression.js | 14 ++++++++++++++ 6 files changed, 120 insertions(+) create mode 100644 lib/node/arrayCall.js create mode 100644 lib/node/at.js create mode 100644 lib/node/slice.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a01d6311..9165799b 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -131,11 +131,14 @@ Postgres.prototype.visit = function(node) { case 'CREATE INDEX' : return this.visitCreateIndex(node); case 'DROP INDEX' : return this.visitDropIndex(node); case 'FUNCTION CALL' : return this.visitFunctionCall(node); + case 'ARRAY CALL' : return this.visitArrayCall(node); case 'POSTFIX UNARY' : return this.visitPostfixUnary(node); case 'PREFIX UNARY' : return this.visitPrefixUnary(node); case 'BINARY' : return this.visitBinary(node); case 'TERNARY' : return this.visitTernary(node); + case 'AT' : return this.visitAt(node); + case 'SLICE' : return this.visitSlice(node); case 'LIMIT' : case 'OFFSET': @@ -356,6 +359,17 @@ Postgres.prototype.visitTernary = function(ternary) { return [text]; }; +Postgres.prototype.visitAt = function(at) { + var text = '(' + this.visit(at.value) + ')[' + this.visit(at.index) + ']'; + return [text]; +}; + +Postgres.prototype.visitSlice = function(slice) { + var text = '(' + this.visit(slice.value) + ')'; + text += '[' + this.visit(slice.start) + ':' + this.visit(slice.end) + ']'; + return [text]; +}; + Postgres.prototype.visitQuery = function(queryNode) { this._queryNode = queryNode; // need to sort the top level query nodes on visitation priority @@ -509,6 +523,11 @@ Postgres.prototype.visitFunctionCall = function(functionCall) { return [txt]; }; +Postgres.prototype.visitArrayCall = function(arrayCall) { + var txt = 'ARRAY[' + arrayCall.nodes.map(this.visit.bind(this)).join(', ') + ']'; + return [txt]; +}; + Postgres.prototype.visitParameter = function(parameter) { // save the value into the parameters array var value = parameter.value(); diff --git a/lib/index.js b/lib/index.js index 8999552d..75d1c2e7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,6 +2,7 @@ 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'); @@ -37,6 +38,13 @@ Sql.prototype.functionCallCreator = function(name) { }; }; +// Returns a bracketed call creator literal +Sql.prototype.array = function() { + var arrayCall = new ArrayCall(sliced(arguments)); + arrayCall.sql = this; + return arrayCall; +}; + // Returns a select statement Sql.prototype.select = function() { var query = new Query({sql: this}); diff --git a/lib/node/arrayCall.js b/lib/node/arrayCall.js new file mode 100644 index 00000000..4f2f657b --- /dev/null +++ b/lib/node/arrayCall.js @@ -0,0 +1,24 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var ParameterNode = require(__dirname + '/parameter'); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var ArrayCallNode = Node.define({ + type: 'ARRAY CALL', + constructor: function(args) { + Node.call(this); + args = _.flatten(args); + this.addAll(args.map(ParameterNode.getNodeOrParameterNode)); + } +}); + +// mix in value expression +_.extend(ArrayCallNode.prototype, valueExpressionMixin()); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(ArrayCallNode.prototype, AliasNode.AliasMixin); + +module.exports = ArrayCallNode; diff --git a/lib/node/at.js b/lib/node/at.js new file mode 100644 index 00000000..2ded9362 --- /dev/null +++ b/lib/node/at.js @@ -0,0 +1,27 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var AtNode = Node.define({ + type: 'AT', + constructor: function(value, index) { + Node.call(this); + this.value = value; + this.index = index; + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(AtNode.prototype, valueExpressionMixin()); + } + } +}); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(AtNode.prototype, AliasNode.AliasMixin); + +module.exports = AtNode; diff --git a/lib/node/slice.js b/lib/node/slice.js new file mode 100644 index 00000000..ab32f314 --- /dev/null +++ b/lib/node/slice.js @@ -0,0 +1,28 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var SliceNode = Node.define({ + type: 'SLICE', + constructor: function(value, start, end) { + Node.call(this); + this.value = value; + this.start = start; + this.end = end; + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(SliceNode.prototype, valueExpressionMixin()); + } + } +}); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(SliceNode.prototype, AliasNode.AliasMixin); + +module.exports = SliceNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index afe421ad..8afebd66 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -17,6 +17,8 @@ var ValueExpressionMixin = function() { var CastNode = require('./cast'); var PostfixUnaryNode = require('./postfixUnary'); var TernaryNode = require('./ternary'); + var AtNode = require('./at'); + var SliceNode = require('./slice'); var postfixUnaryMethod = function(operator) { /*jshint unused: false */ @@ -50,6 +52,14 @@ var ValueExpressionMixin = function() { }; }; + var atMethod = function(index) { + return new AtNode(this.toNode(), processParams(index)); + }; + + var sliceMethod = function(start, end) { + return new SliceNode(this.toNode(), processParams(start), processParams(end)); + }; + var castMethod = function(dataType) { return new CastNode(this.toNode(), dataType); }; @@ -87,11 +97,15 @@ var ValueExpressionMixin = function() { bitwiseNot : binaryMethod('~'), bitwiseOr : binaryMethod('|'), bitwiseXor : binaryMethod('#'), + concat : binaryMethod('||'), + key : binaryMethod('->'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), notIn : binaryMethod('NOT IN'), between : ternaryMethod('BETWEEN', 'AND'), + at : atMethod, + slice : sliceMethod, cast : castMethod, descending : orderMethod('DESC') }; From 48d44d0d69a265f6b0499eaada1aa8138cbea208 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sun, 15 Sep 2013 01:46:10 -0400 Subject: [PATCH 237/507] 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 238/507] 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 239/507] 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 240/507] 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 2f94f5653920d05927a7999569e1747414021900 Mon Sep 17 00:00:00 2001 From: phestermcs Date: Tue, 17 Sep 2013 02:37:51 -0600 Subject: [PATCH 241/507] Improved support for mapping javascript properties to columns. Objects passed to insert, update can use property names, and they get mapped to column names. If a column's property name different than its sql name, property name used as column alias in generated SELECT statement. Added boolean columnWhiteList config option for table.define(). For insert, update, if table.columnWhiteList is true and passed object has properties that don't map to columns, they're ignored rather than throwing exceptions. Added boolean snakeToCamel config option for table.define(). If a column has no explicit 'property' property and table.snakeToCamel is true, column's property is set to its name converted to camelCase; i.e. make_to_camel becomes makeToCamel, and then table.makeToCamel can be used. --- lib/dialect/postgres.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index cc435dd9..c63300c3 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -279,7 +279,9 @@ Postgres.prototype.visitFrom = function(from) { }; Postgres.prototype.visitWhere = function(where) { + this._visitingWhere = true; var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')]; + this._visitingWhere = false; return result; }; @@ -451,6 +453,7 @@ Postgres.prototype.visitColumn = function(columnNode) { var inDdlClause = this._visitingAddColumn || this._visitingAlter || this._visitingCreate; var inSelectClause = !this._selectOrDeleteEndIndex + && !this._visitingWhere && !inInsertUpdateClause && !inDdlClause var txt = []; From 7e18ea8dc65210ac92bc2e33f00e8a3eb2a153c2 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 18 Sep 2013 22:30:36 +1000 Subject: [PATCH 242/507] BLOB support for postgres, mysql and sqlite. --- lib/dialect/mysql.js | 9 +++++ lib/dialect/postgres.js | 2 ++ lib/dialect/sqlite.js | 9 +++++ test/dialects/insert-tests.js | 62 ++++++++++++++++++++++++++++++++++- 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index cfb7e61d..e6799da3 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -22,6 +22,15 @@ Mysql.prototype._getParameterPlaceholder = function() { return '?'; }; +Mysql.prototype._getParameterValue = function(value) { + if (Buffer.isBuffer(value)) { + value = 'x' + this._getParameterValue(value.toString('hex')); + } else { + value = Postgres.prototype._getParameterValue.call(this, value); + } + return value; +}; + 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 a01d6311..9f9840d6 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -46,6 +46,8 @@ Postgres.prototype._getParameterValue = function(value) { // Date object's default toString format does not get parsed well // Handle date like objects using toISOString value = this._getParameterValue(value.toISOString()); + } else if (Buffer.isBuffer(value)) { + value = "DECODE(" + this._getParameterValue(value.toString('hex')) + ", 'hex')"; } else { // rich object represent with string value = this._getParameterValue(value.toString()); diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index decea81f..b105cafd 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -17,6 +17,15 @@ Sqlite.prototype._myClass = Sqlite; Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT'; +Sqlite.prototype._getParameterValue = function(value) { + if (Buffer.isBuffer(value)) { + value = 'x' + this._getParameterValue(value.toString('hex')); + } else { + value = Postgres.prototype._getParameterValue.call(this, value); + } + return value; +}; + Sqlite.prototype.visitDefault = function() { throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.'); }; diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 29e40020..2fc2a5b4 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -21,7 +21,6 @@ Harness.test({ params: ['test', 1] }); - Harness.test({ query: post.insert(post.content.value('whoah')), pg: { @@ -325,3 +324,64 @@ Harness.test({ }, params: ['A%'] }); + +// Binary inserts +Harness.test({ + query: post.insert(post.content.value(new Buffer('test')), post.userId.value(2)), + pg: { + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (DECODE(\'74657374\', \'hex\'), 2)' + }, + sqlite: { + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' + }, + params: [new Buffer('test'), 2] +}); + +Harness.test({ + query: post.insert({ + content: new Buffer('test'), + userId: 2 + }), + pg: { + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (DECODE(\'74657374\', \'hex\'), 2)' + }, + sqlite: { + text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (x\'74657374\', 2)' + }, + mysql: { + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (?, ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (x\'74657374\', 2)' + }, + params: [new Buffer('test'), 2] +}); + +Harness.test({ + query: post.insert([{ + content: new Buffer('whoah') + }, { + content: new Buffer('hey') + } + ]), + pg: { + text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") ' + + 'VALUES (DECODE(\'77686f6168\', \'hex\')), (DECODE(\'686579\', \'hex\'))' + }, + sqlite: { + text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', + string: 'INSERT INTO "post" ("content") VALUES (x\'77686f6168\'), (x\'686579\')' + }, + mysql: { + text : 'INSERT INTO `post` (`content`) VALUES (?), (?)', + string: 'INSERT INTO `post` (`content`) VALUES (x\'77686f6168\'), (x\'686579\')' + }, + params: [new Buffer('whoah'), new Buffer('hey')] +}); From 3ae2579cdc21f01b3f732a0be93aea277c6518a2 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 18 Sep 2013 22:36:47 +1000 Subject: [PATCH 243/507] update tests --- test/dialects/update-tests.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index bd4f6e46..95a2b6ce 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -121,3 +121,23 @@ Harness.test({ }, params: [] }); + +// Binary updates +Harness.test({ + query: post.update({ + content: new Buffer('test') + }), + pg: { + text : 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = DECODE(\'74657374\', \'hex\')' + }, + sqlite: { + text : 'UPDATE "post" SET "content" = $1', + string: 'UPDATE "post" SET "content" = x\'74657374\'' + }, + mysql: { + text : 'UPDATE `post` SET `content` = ?', + string: 'UPDATE `post` SET `content` = x\'74657374\'' + }, + params: [new Buffer('test')] +}); From 19c68d877d7281cfea01f5530411e69c2be9403d Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Wed, 18 Sep 2013 22:45:14 +1000 Subject: [PATCH 244/507] where clause value expression test --- test/dialects/value-expression-tests.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index b9e335f6..35d5dfad 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var customer = Harness.defineCustomerTable(); +var post = Harness.definePostTable(); var v = Harness.defineVariableTable(); // Test composition of binary methods +, *, -, =. @@ -76,3 +77,21 @@ Harness.test({ }, params: [] }); + +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" = DECODE(\'74657374\', \'hex\'))', + }, + sqlite: { + text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', + 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\')', + }, + params: [new Buffer('test')] +}); + From b1ede85934cc8b46c727975f141802f4a9b90e03 Mon Sep 17 00:00:00 2001 From: Eugene Ware Date: Thu, 19 Sep 2013 21:17:31 +1000 Subject: [PATCH 245/507] Use bytea hex encoding as recommended by http://www.postgresql.org/docs/9.0/static/datatype-binary.html --- lib/dialect/postgres.js | 2 +- test/dialects/insert-tests.js | 6 +++--- test/dialects/update-tests.js | 2 +- test/dialects/value-expression-tests.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 9f9840d6..8a00b0d5 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -47,7 +47,7 @@ Postgres.prototype._getParameterValue = function(value) { // Handle date like objects using toISOString value = this._getParameterValue(value.toISOString()); } else if (Buffer.isBuffer(value)) { - value = "DECODE(" + this._getParameterValue(value.toString('hex')) + ", 'hex')"; + value = this._getParameterValue('\\x' + value.toString('hex')); } else { // rich object represent with string value = this._getParameterValue(value.toString()); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 2fc2a5b4..56abd8dc 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -330,7 +330,7 @@ Harness.test({ query: post.insert(post.content.value(new Buffer('test')), post.userId.value(2)), pg: { text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (DECODE(\'74657374\', \'hex\'), 2)' + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'\\x74657374\', 2)' }, sqlite: { text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', @@ -350,7 +350,7 @@ Harness.test({ }), pg: { text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', - string: 'INSERT INTO "post" ("content", "userId") VALUES (DECODE(\'74657374\', \'hex\'), 2)' + string: 'INSERT INTO "post" ("content", "userId") VALUES (\'\\x74657374\', 2)' }, sqlite: { text : 'INSERT INTO "post" ("content", "userId") VALUES ($1, $2)', @@ -373,7 +373,7 @@ Harness.test({ pg: { text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', string: 'INSERT INTO "post" ("content") ' + - 'VALUES (DECODE(\'77686f6168\', \'hex\')), (DECODE(\'686579\', \'hex\'))' + 'VALUES (\'\\x77686f6168\'), (\'\\x686579\')' }, sqlite: { text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', diff --git a/test/dialects/update-tests.js b/test/dialects/update-tests.js index 95a2b6ce..1553e7a5 100644 --- a/test/dialects/update-tests.js +++ b/test/dialects/update-tests.js @@ -129,7 +129,7 @@ Harness.test({ }), pg: { text : 'UPDATE "post" SET "content" = $1', - string: 'UPDATE "post" SET "content" = DECODE(\'74657374\', \'hex\')' + string: 'UPDATE "post" SET "content" = \'\\x74657374\'' }, sqlite: { text : 'UPDATE "post" SET "content" = $1', diff --git a/test/dialects/value-expression-tests.js b/test/dialects/value-expression-tests.js index 35d5dfad..b8b30d8e 100644 --- a/test/dialects/value-expression-tests.js +++ b/test/dialects/value-expression-tests.js @@ -82,7 +82,7 @@ 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" = DECODE(\'74657374\', \'hex\'))', + string: 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = \'\\x74657374\')', }, sqlite: { text : 'SELECT "post"."id" FROM "post" WHERE ("post"."content" = $1)', From a192311c8e960083f2c251dd6f8b5b68a855f956 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Fri, 20 Sep 2013 11:50:41 +0200 Subject: [PATCH 246/507] resolve the array --- lib/dialect/mysql.js | 2 +- lib/dialect/postgres.js | 2 +- lib/dialect/sqlite.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index cfb7e61d..827fae34 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -58,7 +58,7 @@ Mysql.prototype.visitInsert = function(insert) { }; Mysql.prototype.visitIndexes = function(node) { - var tableName = this.visit(this._queryNode.table.toNode()); + var tableName = this.visit(this._queryNode.table.toNode())[0]; return "SHOW INDEX FROM " + tableName; }; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index a01d6311..5ed42af3 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -568,7 +568,7 @@ Postgres.prototype.visitModifier = function(node) { Postgres.prototype.visitIndexes = function(node) { /* jshint unused: false */ - var tableName = this.visit(this._queryNode.table.toNode()); + var tableName = this.visit(this._queryNode.table.toNode())[0]; return [ "SELECT relname", diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index decea81f..36fc4795 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -41,7 +41,7 @@ Sqlite.prototype.visitAddColumn = function(addColumn) { }; Sqlite.prototype.visitIndexes = function(node) { - var tableName = this.visit(this._queryNode.table.toNode()); + var tableName = this.visit(this._queryNode.table.toNode())[0]; return "PRAGMA INDEX_LIST(" + tableName + ")"; }; From b75f65e7ea6262eef8c9d03c86db42c7ab4922a8 Mon Sep 17 00:00:00 2001 From: Sascha Depold Date: Fri, 20 Sep 2013 11:50:55 +0200 Subject: [PATCH 247/507] pg needs single quotes for values. --- lib/dialect/postgres.js | 2 +- test/dialects/indexes-tests.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 5ed42af3..1116cffe 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -575,7 +575,7 @@ Postgres.prototype.visitIndexes = function(node) { "FROM pg_class", "WHERE oid IN (", "SELECT indexrelid", - "FROM pg_index, pg_class WHERE pg_class.relname=" + tableName, + "FROM pg_index, pg_class WHERE pg_class.relname=" + tableName.replace(/"/g, "'"), "AND pg_class.oid=pg_index.indrelid)" ].join(' '); }; diff --git a/test/dialects/indexes-tests.js b/test/dialects/indexes-tests.js index 916b4eef..132c01fb 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.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)' }, mysql: { text : 'SHOW INDEX FROM `post`', From 01ddd0fed9dd8e2ed68448e5d548b6ac02923f88 Mon Sep 17 00:00:00 2001 From: phestermcs Date: Mon, 23 Sep 2013 12:06:42 -0600 Subject: [PATCH 248/507] Added 'parameter(value)' method to 'query' node to manually added parameter values to a query. If inline text added to a query includes a parameter, like '$1', then calling 'parameter(v)' allows '$1' to be set with 'v', providing protection from sql injection. --- lib/node/query.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/node/query.js b/lib/node/query.js index 20a38a29..099eb100 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -182,6 +182,10 @@ var Query = Node.define({ }); return this.add(update); }, + parameter: function(v) { + this.add(ParameterNode.getNodeOrParameterNode(v)); + return this; + }, delete: function(params) { var result = this.add(new Delete()); if (params) { From e1d42c2517c86de00d01b6b43ccbd73004527805 Mon Sep 17 00:00:00 2001 From: phestermcs Date: Mon, 23 Sep 2013 16:43:34 -0600 Subject: [PATCH 249/507] Added 'parameter(value)' method to 'query' node to manually added parameter values to a query. If inline text added to a query includes a parameter, like '$1', then calling 'parameter(v)' allows '$1' to be set with 'v', providing protection from sql injection. --- lib/dialect/postgres.js | 2 +- lib/node/parameter.js | 1 + lib/node/query.js | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index c63300c3..7041c9d0 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -530,7 +530,7 @@ Postgres.prototype.visitParameter = function(parameter) { // save the value into the parameters array var value = parameter.value(); this.params.push(value); - return [this._getParameterText(this.params.length, value)]; + return parameter.isExplicit ? [] : [this._getParameterText(this.params.length, value)]; }; Postgres.prototype.visitDefault = function(parameter) { diff --git a/lib/node/parameter.js b/lib/node/parameter.js index 7b3a8a20..9d825d42 100644 --- a/lib/node/parameter.js +++ b/lib/node/parameter.js @@ -7,6 +7,7 @@ var ParameterNode = module.exports = Node.define({ constructor: function(val) { Node.call(this); this._val = val; + this.isExplicit = false; }, value: function() { return this._val; diff --git a/lib/node/query.js b/lib/node/query.js index 099eb100..a6afc7a1 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -183,8 +183,9 @@ var Query = Node.define({ return this.add(update); }, parameter: function(v) { - this.add(ParameterNode.getNodeOrParameterNode(v)); - return this; + var param = ParameterNode.getNodeOrParameterNode(v); + param.isExplicit = true; + return this.add(param); }, delete: function(params) { var result = this.add(new Delete()); From 1bf9ae167c7666b3467b68ccca83b2a8358a0fd0 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 28 Sep 2013 00:42:29 -0400 Subject: [PATCH 250/507] - 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 251/507] - 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 252/507] - 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 47ddb4246914fa43a26b550ffda5f2941134eb09 Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 1 Oct 2013 09:13:05 -0500 Subject: [PATCH 253/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 58a9777c..5a1e92cf 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.27.0", + "version": "0.28.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 26346fbbb243d380f677eb13b8bc4bf33d93ac92 Mon Sep 17 00:00:00 2001 From: tmont Date: Fri, 4 Oct 2013 18:38:08 -0700 Subject: [PATCH 254/507] added 'prefix' option to Table.prototype.star() --- lib/table.js | 9 ++++++++- test/dialects/table-tests.js | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/table.js b/lib/table.js index 605bd9b7..e1e91e63 100644 --- a/lib/table.js +++ b/lib/table.js @@ -121,7 +121,14 @@ Table.prototype.getName = function() { return this._name; }; -Table.prototype.star = function() { +Table.prototype.star = function(options) { + options = options || {}; + if (options.prefix) { + return this.columns.map(function(column) { + return this[column.name].as(options.prefix + column.name); + }.bind(this)); + } + return new Column({table: this, star: true}); }; diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 01c2c1aa..b01f7432 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -54,6 +54,23 @@ Harness.test({ params: [] }); +Harness.test({ + query: user.select(user.star({ prefix: 'foo_' })).from(user), + pg: { + text: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"', + string: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"', + string: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name` FROM `user`', + string: 'SELECT `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name` FROM `user`' + }, + params: [] +}); + Harness.test({ query: user.select(user.id).from(user).where(user.name.equals('foo')), pg: { From 1ebe475d8f380ada8c8b9c940ef4f4b43b168dea Mon Sep 17 00:00:00 2001 From: Matin Movassate Date: Sun, 6 Oct 2013 14:17:27 -0700 Subject: [PATCH 255/507] Add array tests, for both literals and array columns. --- test/dialects/array-tests.js | 52 ++++++++++++++++++++++++++++++++++++ test/dialects/support.js | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 test/dialects/array-tests.js diff --git a/test/dialects/array-tests.js b/test/dialects/array-tests.js new file mode 100644 index 00000000..74a7b6e4 --- /dev/null +++ b/test/dialects/array-tests.js @@ -0,0 +1,52 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); +var Sql = require('../../lib'); + +// Array columns +Harness.test({ + query: post.select(post.tags.slice(2,3)), + pg: { + text : 'SELECT ("post"."tags")[$1:$2] FROM "post"', + string: 'SELECT ("post"."tags")[2:3] FROM "post"' + }, + params: [2, 3] +}); + +Harness.test({ + query: post.select(post.tags.at(2)), + pg: { + text : 'SELECT ("post"."tags")[$1] FROM "post"', + string: 'SELECT ("post"."tags")[2] FROM "post"' + }, + params: [2] +}); + +// Array literals +Harness.test({ + query: post.select(Sql.array(1,2,3)), + pg: { + text : 'SELECT ARRAY[$1, $2, $3] FROM "post"', + string: 'SELECT ARRAY[1, 2, 3] FROM "post"' + }, + params: [1, 2, 3] +}); + +Harness.test({ + query: post.select(Sql.array(1,2,3).slice(2,3)), + pg: { + text : 'SELECT (ARRAY[$1, $2, $3])[$4:$5] FROM "post"', + string: 'SELECT (ARRAY[1, 2, 3])[2:3] FROM "post"' + }, + params: [1,2,3,2,3] +}); + +Harness.test({ + query: post.select(Sql.array(1,2,3).at(2)), + pg: { + text : 'SELECT (ARRAY[$1, $2, $3])[$4] FROM "post"', + string: 'SELECT (ARRAY[1, 2, 3])[2] FROM "post"' + }, + params: [1,2,3,2] +}); diff --git a/test/dialects/support.js b/test/dialects/support.js index 6eabee5c..2d528c62 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -74,7 +74,7 @@ module.exports = { definePostTable: function() { return Table.define({ name: 'post', - columns: ['id', 'userId', 'content'] + columns: ['id', 'userId', 'content', 'tags'] }); }, From 470d8aee7f98d344272196bf2ce464ee54c16f2e Mon Sep 17 00:00:00 2001 From: Matin Movassate Date: Sun, 6 Oct 2013 14:43:47 -0700 Subject: [PATCH 256/507] Add HSTORE as top-level Postgres function. --- lib/functions.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/functions.js b/lib/functions.js index 503980df..8186161a 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -47,7 +47,10 @@ var scalarFunctions = [ 'UPPER' ]; -var standardFunctionNames = aggregateFunctions.concat(scalarFunctions); +// hstore function available to Postgres +var hstoreFunction = 'HSTORE'; + +var standardFunctionNames = aggregateFunctions.concat(scalarFunctions).concat(hstoreFunction); // creates a hash of standard functions for a sql instance var getStandardFunctions = function(sql) { From 9763324bc2d7097740d4cc98a6676c991f54f16d Mon Sep 17 00:00:00 2001 From: Matin Movassate Date: Sun, 6 Oct 2013 14:45:21 -0700 Subject: [PATCH 257/507] Add hstore tests for literals, concatenations, and key access. --- test/dialects/hstore-tests.js | 25 +++++++++++++++++++++++++ test/dialects/support.js | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/dialects/hstore-tests.js diff --git a/test/dialects/hstore-tests.js b/test/dialects/hstore-tests.js new file mode 100644 index 00000000..54ba2d22 --- /dev/null +++ b/test/dialects/hstore-tests.js @@ -0,0 +1,25 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var Sql = require('../../lib').setDialect('postgres'); + +Harness.test({ + query: customer.update({ + metadata: customer.metadata.concat(Sql.functions.HSTORE('age', 20)) + }), + pg: { + text : 'UPDATE "customer" SET "metadata" = ("customer"."metadata" || HSTORE($1, $2))', + string: 'UPDATE "customer" SET "metadata" = ("customer"."metadata" || HSTORE(\'age\', 20))' + }, + params: ['age', 20] +}); + +Harness.test({ + query: customer.select(customer.metadata.key('age')), + pg: { + text : 'SELECT ("customer"."metadata" -> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" -> \'age\') FROM "customer"' + }, + params: ['age'] +}); diff --git a/test/dialects/support.js b/test/dialects/support.js index 2d528c62..a85fabe7 100644 --- a/test/dialects/support.js +++ b/test/dialects/support.js @@ -88,7 +88,7 @@ module.exports = { defineCustomerTable: function() { return Table.define({ name: 'customer', - columns: ['id', 'name', 'age', 'income'] + columns: ['id', 'name', 'age', 'income', 'metadata'] }); }, From a6486808235889f542390512ab5f84f5da5e3e40 Mon Sep 17 00:00:00 2001 From: Matin Movassate Date: Sun, 6 Oct 2013 14:48:08 -0700 Subject: [PATCH 258/507] Add tests for array concatenation. --- test/dialects/array-tests.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/dialects/array-tests.js b/test/dialects/array-tests.js index 74a7b6e4..879c3fd4 100644 --- a/test/dialects/array-tests.js +++ b/test/dialects/array-tests.js @@ -5,6 +5,17 @@ var post = Harness.definePostTable(); var Sql = require('../../lib'); // Array columns +Harness.test({ + query: post.update({ + tags: post.tags.concat(Sql.array('nodejs')) + }), + pg: { + text : 'UPDATE "post" SET "tags" = ("post"."tags" || ARRAY[$1])', + string: 'UPDATE "post" SET "tags" = ("post"."tags" || ARRAY[\'nodejs\'])' + }, + params: ['nodejs'] +}); + Harness.test({ query: post.select(post.tags.slice(2,3)), pg: { From 25d8cef8415176cbf4448807ebeb6cbba248fb7b Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Sun, 6 Oct 2013 19:40:43 -0500 Subject: [PATCH 259/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a1e92cf..b81acfa8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.28.0", + "version": "0.29.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 0347ce60733704b52664c2a22c26a08454c64fdd Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Mon, 7 Oct 2013 16:52:23 -0500 Subject: [PATCH 260/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b81acfa8..f9de604d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.29.0", + "version": "0.30.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From f0ce6b3f922eb38b4a9f0a2179ad0ff82875ca2e Mon Sep 17 00:00:00 2001 From: tmont Date: Mon, 7 Oct 2013 23:25:29 -0700 Subject: [PATCH 261/507] fixed issue when doing '.select(a.id, [ b.id, b.name ])' --- lib/node/query.js | 12 +++++++++++- test/dialects/table-tests.js | 14 +++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/node/query.js b/lib/node/query.js index a6afc7a1..f0f9c536 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -65,7 +65,17 @@ var Query = Node.define({ this.add(select); } - var args = getArrayOrArgsAsArray(arguments); + //allow things like .select(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; + }, []); + select.addAll(args); // if this is a subquery then add reference to this column diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index b01f7432..2e2e99d6 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -55,18 +55,18 @@ Harness.test({ }); Harness.test({ - query: user.select(user.star({ prefix: 'foo_' })).from(user), + query: user.select(user.star(), user.star({ prefix: 'foo_' }), user.star({ prefix: 'bar_' })).from(user), pg: { - text: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"', - string: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"' + 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"' }, sqlite: { - text: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"', - string: 'SELECT "user"."id" AS "foo_id", "user"."name" AS "foo_name" FROM "user"' + 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"' }, mysql: { - text: 'SELECT `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name` FROM `user`', - string: 'SELECT `user`.`id` AS `foo_id`, `user`.`name` AS `foo_name` FROM `user`' + 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`' }, params: [] }); From e8979edd1d78af671eed1053bc46afaf1e69b5a0 Mon Sep 17 00:00:00 2001 From: tmont Date: Mon, 7 Oct 2013 23:34:32 -0700 Subject: [PATCH 262/507] added a few more tests for query.select()'s handling of arrays --- test/dialects/table-tests.js | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/dialects/table-tests.js b/test/dialects/table-tests.js index 2e2e99d6..eae326bc 100644 --- a/test/dialects/table-tests.js +++ b/test/dialects/table-tests.js @@ -54,6 +54,57 @@ Harness.test({ params: [] }); +Harness.test({ + query: user.select(user.id, [ user.name ]).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + params: [] +}); + +Harness.test({ + query: user.select([ user.id ], user.name).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + params: [] +}); + +Harness.test({ + query: user.select([ user.id , user.name ]).from(user), + pg: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + sqlite: { + text: 'SELECT "user"."id", "user"."name" FROM "user"', + string: 'SELECT "user"."id", "user"."name" FROM "user"' + }, + mysql: { + text: 'SELECT `user`.`id`, `user`.`name` FROM `user`', + string: 'SELECT `user`.`id`, `user`.`name` FROM `user`' + }, + params: [] +}); + Harness.test({ query: user.select(user.star(), user.star({ prefix: 'foo_' }), user.star({ prefix: 'bar_' })).from(user), pg: { From 7cec73556417f56e7fe687537133e617a775cb25 Mon Sep 17 00:00:00 2001 From: Brian Carlson Date: Tue, 8 Oct 2013 14:18:26 -0500 Subject: [PATCH 263/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f9de604d..b745fbe4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.30.0", + "version": "0.31.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From ce1731beee86307df0fe4aaf45a116bd8f944948 Mon Sep 17 00:00:00 2001 From: Dan Rzeppa Date: Sat, 19 Oct 2013 15:27:17 -0400 Subject: [PATCH 264/507] - 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 265/507] - 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 080cc338f23c4cff89829be7bcd5599c2a67500b Mon Sep 17 00:00:00 2001 From: tmont Date: Wed, 30 Oct 2013 13:06:50 -0700 Subject: [PATCH 266/507] support for deletions with joins --- lib/dialect/postgres.js | 12 +++++--- lib/node/query.js | 21 +++++++++++-- test/dialects/delete-tests.js | 55 +++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index feb38db8..dbd96fa2 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -104,7 +104,7 @@ Postgres.prototype.visit = function(node) { case 'SELECT' : return this.visitSelect(node); case 'INSERT' : return this.visitInsert(node); case 'UPDATE' : return this.visitUpdate(node); - case 'DELETE' : return this.visitDelete(); + case 'DELETE' : return this.visitDelete(node); case 'CREATE' : return this.visitCreate(node); case 'DROP' : return this.visitDrop(node); case 'ALIAS' : return this.visitAlias(node); @@ -221,9 +221,13 @@ Postgres.prototype.visitUpdate = function(update) { return result; }; -Postgres.prototype.visitDelete = function() { - this._selectOrDeleteEndIndex = 1; - return ['DELETE']; +Postgres.prototype.visitDelete = function (del) { + var result = ['DELETE']; + if (del.nodes.length) { + result.push(del.nodes.map(this.visit.bind(this)).join(', ')); + } + this._selectOrDeleteEndIndex = result.length; + return result; }; Postgres.prototype.visitCreate = function(create) { diff --git a/lib/node/query.js b/lib/node/query.js index f0f9c536..3ccec35a 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -30,6 +30,7 @@ var IfNotExists = require('./ifNotExists'); var Indexes = require('./indexes'); var CreateIndex = require('./createIndex'); var DropIndex = require('./dropIndex'); +var Table = require('./table'); var Modifier = Node.define({ constructor: function(table, type, count) { @@ -198,9 +199,25 @@ var Query = Node.define({ return this.add(param); }, delete: function(params) { - var result = this.add(new Delete()); + var result; if (params) { - result = this.where(params); + var TableDefinition = require('../table'); + if (params instanceof TableDefinition || Array.isArray(params)) { + //handle explicit delete queries: + // e.g. post.delete(post).from(post) -> DELETE post FROM post + // e.g. post.delete([post, user]).from(post) -> DELETE post, user FROM post + if (Array.isArray(params)) { + params = params.map(function(table) { return new Table(table); }); + } else { + params = [ new Table(params) ]; + } + result = this.add(new Delete().addAll(params)); + } else { + //syntax sugar for post.delete().from(post).where(params) + result = this.add(new Delete()).where(params); + } + } else{ + result = this.add(new Delete()); } return result; }, diff --git a/test/dialects/delete-tests.js b/test/dialects/delete-tests.js index 71c27d95..58e6d0d6 100644 --- a/test/dialects/delete-tests.js +++ b/test/dialects/delete-tests.js @@ -2,6 +2,7 @@ var Harness = require('./support'); var post = Harness.definePostTable(); +var user = Harness.defineUserTable(); Harness.test({ query: post.delete().where(post.content.equals("hello's world")), @@ -20,6 +21,60 @@ Harness.test({ params: ["hello's world"] }); +Harness.test({ + query: post.delete(post).from(post), + pg: { + text: 'DELETE "post" FROM "post"', + string: 'DELETE "post" FROM "post"' + }, + sqlite: { + text: 'DELETE "post" FROM "post"', + string: 'DELETE "post" FROM "post"' + }, + mysql: { + text: 'DELETE `post` FROM `post`', + string: 'DELETE `post` FROM `post`' + }, + params: [] +}); + +Harness.test({ + query: post.delete([post, post]).from(post), + pg: { + text: 'DELETE "post", "post" FROM "post"', + string: 'DELETE "post", "post" FROM "post"' + }, + sqlite: { + text: 'DELETE "post", "post" FROM "post"', + string: 'DELETE "post", "post" FROM "post"' + }, + mysql: { + text: 'DELETE `post`, `post` FROM `post`', + string: 'DELETE `post`, `post` FROM `post`' + }, + params: [] +}); + +Harness.test({ + query: user + .delete(user) + .from(user.join(post).on(post.userId.equals(user.id))) + .where(post.content.equals('foo')), + pg: { + 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\')' + }, + sqlite: { + 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\')' + }, + mysql: { + 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\')' + }, + params: [ 'foo' ] +}); + Harness.test({ query: post.delete().where({ content: '' From dc4b97c526806895fa0673f0550212b631891255 Mon Sep 17 00:00:00 2001 From: brianc Date: Tue, 12 Nov 2013 08:47:09 -0600 Subject: [PATCH 267/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b745fbe4..89e3a3ec 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.31.0", + "version": "0.32.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 100723579573adc72f7601bc17f398e6a2e19037 Mon Sep 17 00:00:00 2001 From: Jonnathan Date: Mon, 25 Nov 2013 19:01:20 -0200 Subject: [PATCH 268/507] Add support for CASCADE in DROP TABLE. --- lib/dialect/postgres.js | 11 +++++++++- lib/dialect/sqlite.js | 8 ++++++++ lib/node/cascade.js | 7 +++++++ lib/node/drop.js | 7 ++++++- lib/node/index.js | 6 ++++++ lib/node/query.js | 18 +++++++++++++--- lib/node/restrict.js | 7 +++++++ test/dialects/drop-table-tests.js | 34 +++++++++++++++++++++++++++++++ 8 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 lib/node/cascade.js create mode 100644 lib/node/restrict.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index dbd96fa2..9ae898bf 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -125,6 +125,8 @@ 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 'CASCADE' : return this.visitCascade(); + case 'RESTRICT' : return this.visitRestrict(); case 'RENAME' : return this.visitRename(node); case 'ADD COLUMN' : return this.visitAddColumn(node); case 'DROP COLUMN' : return this.visitDropColumn(node); @@ -248,7 +250,6 @@ Postgres.prototype.visitDrop = function(drop) { // don't auto-generate from clause var result = ['DROP TABLE']; result = result.concat(drop.nodes.map(this.visit.bind(this))); - result.push(this.visit(this._queryNode.table.toNode())); return result; }; @@ -611,6 +612,14 @@ Postgres.prototype.visitIfNotExists = function() { return ['IF NOT EXISTS']; }; +Postgres.prototype.visitCascade = function() { + return ['CASCADE']; +}; + +Postgres.prototype.visitRestrict = function() { + return ['RESTRICT']; +}; + Postgres.prototype.visitJoin = function(join) { var result = []; result = result.concat(this.visit(join.from)); diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index 669998f6..ac7e1c0d 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -54,4 +54,12 @@ Sqlite.prototype.visitIndexes = function(node) { return "PRAGMA INDEX_LIST(" + tableName + ")"; }; +Sqlite.prototype.visitCascade = function() { + throw new Error('Sqlite do not support CASCADE in DROP TABLE'); +}; + +Sqlite.prototype.visitRestrict = function() { + throw new Error('Sqlite do not support RESTRICT in DROP TABLE'); +}; + module.exports = Sqlite; diff --git a/lib/node/cascade.js b/lib/node/cascade.js new file mode 100644 index 00000000..1dea1eef --- /dev/null +++ b/lib/node/cascade.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'CASCADE' +}); diff --git a/lib/node/drop.js b/lib/node/drop.js index 24e19062..aa37b3ed 100644 --- a/lib/node/drop.js +++ b/lib/node/drop.js @@ -3,5 +3,10 @@ var Node = require(__dirname); module.exports = Node.define({ - type: 'DROP' + type: 'DROP', + + constructor: function(table) { + Node.call(this); + this.add(table); + } }); diff --git a/lib/node/index.js b/lib/node/index.js index 74e240d0..ec7e0a12 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -19,6 +19,12 @@ Node.prototype.add = function(node) { return this; }; +Node.prototype.unshift = function(node) { + assert(node, 'Error while trying to add a non-existant node to a query'); + this.nodes.unshift(typeof node === 'string' ? new TextNode(node) : node.toNode()); + return this; +}; + // Before the change that introduced parallel dialects, every node could be turned // into a query. The parallel dialects change made it impossible to change some nodes // into a query because not all nodes are constructed with the sql instance. diff --git a/lib/node/query.js b/lib/node/query.js index 3ccec35a..d0ce096d 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -27,6 +27,8 @@ var ParameterNode = require('./parameter'); var PrefixUnaryNode = require('./prefixUnary'); var IfExists = require('./ifExists'); var IfNotExists = require('./ifNotExists'); +var Cascade = require('./cascade'); +var Restrict = require('./restrict'); var Indexes = require('./indexes'); var CreateIndex = require('./createIndex'); var DropIndex = require('./dropIndex'); @@ -245,7 +247,7 @@ var Query = Node.define({ this.add(dropIndex); return dropIndex; } else { - return this.add(new Drop()); + return this.add(new Drop(this.table)); } }, @@ -338,12 +340,22 @@ var Query = Node.define({ }, ifExists: function() { - this.nodes[0].add(new IfExists()); + this.nodes[0].unshift(new IfExists()); return this; }, ifNotExists: function() { - this.nodes[0].add(new IfNotExists()); + this.nodes[0].unshift(new IfNotExists()); + return this; + }, + + cascade: function() { + this.nodes[0].add(new Cascade()); + return this; + }, + + restrict: function() { + this.nodes[0].add(new Restrict()); return this; }, diff --git a/lib/node/restrict.js b/lib/node/restrict.js new file mode 100644 index 00000000..f7c63c15 --- /dev/null +++ b/lib/node/restrict.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'RESTRICT' +}); diff --git a/test/dialects/drop-table-tests.js b/test/dialects/drop-table-tests.js index 6e8943b5..e44a989b 100644 --- a/test/dialects/drop-table-tests.js +++ b/test/dialects/drop-table-tests.js @@ -36,3 +36,37 @@ Harness.test({ }, params: [] }); + +Harness.test({ + query: post.drop().cascade(), + pg: { + text : 'DROP TABLE "post" CASCADE', + string: 'DROP TABLE "post" CASCADE' + }, + sqlite: { + text : 'Sqlite do not support CASCADE in DROP TABLE', + throws: true + }, + mysql: { + text : 'DROP TABLE `post` CASCADE', + string: 'DROP TABLE `post` CASCADE' + }, + params: [] +}); + +Harness.test({ + query: post.drop().restrict(), + pg: { + text : 'DROP TABLE "post" RESTRICT', + string: 'DROP TABLE "post" RESTRICT' + }, + sqlite: { + text : 'Sqlite do not support RESTRICT in DROP TABLE', + throws: true + }, + mysql: { + text : 'DROP TABLE `post` RESTRICT', + string: 'DROP TABLE `post` RESTRICT' + }, + params: [] +}); From 7f6dbb085a920cb4a4a3a6b0516748916e535aa7 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Tue, 26 Nov 2013 23:12:01 -0600 Subject: [PATCH 269/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 89e3a3ec..ec8bffc2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.32.0", + "version": "0.33.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 2f223a79e4f6a0027e629f3088789e60117dbf0e Mon Sep 17 00:00:00 2001 From: Derek Watson Date: Wed, 27 Nov 2013 00:12:17 -0500 Subject: [PATCH 270/507] added json value expressions --- lib/node/valueExpression.js | 3 +++ test/dialects/json-tests.js | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 test/dialects/json-tests.js diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index 21a0072d..f26d822b 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -111,6 +111,9 @@ var ValueExpressionMixin = function() { bitwiseXor : binaryMethod('#'), concat : binaryMethod('||'), key : binaryMethod('->'), + keyText : binaryMethod('->>'), + path : binaryMethod('#>'), + pathText : binaryMethod('#>>'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), in : binaryMethod('IN'), diff --git a/test/dialects/json-tests.js b/test/dialects/json-tests.js new file mode 100644 index 00000000..8880c50d --- /dev/null +++ b/test/dialects/json-tests.js @@ -0,0 +1,41 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var Sql = require('../../lib').setDialect('postgres'); + +Harness.test({ + query: customer.select(customer.metadata.key('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.keyText('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.path('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.pathText('age')), + pg: { + text : 'SELECT ("customer"."metadata" #>> $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" #>> \'age\') FROM "customer"' + }, + params: ['age'] +}); From a1f19a6f162f3320bee459bef72621cce0f01aaf Mon Sep 17 00:00:00 2001 From: Derek Watson Date: Wed, 27 Nov 2013 01:19:33 -0500 Subject: [PATCH 271/507] improved tests --- test/dialects/json-tests.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/dialects/json-tests.js b/test/dialects/json-tests.js index 8880c50d..b610b96f 100644 --- a/test/dialects/json-tests.js +++ b/test/dialects/json-tests.js @@ -23,19 +23,19 @@ Harness.test({ }); Harness.test({ - query: customer.select(customer.metadata.path('age')), + query: customer.select(customer.metadata.path('{address,city}')), pg: { text : 'SELECT ("customer"."metadata" #> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" #> \'age\') FROM "customer"' + string: 'SELECT ("customer"."metadata" #> \'{address,city}\') FROM "customer"' }, - params: ['age'] + params: ['{address,city}'] }); Harness.test({ - query: customer.select(customer.metadata.pathText('age')), + query: customer.select(customer.metadata.pathText('{address,city}')), pg: { text : 'SELECT ("customer"."metadata" #>> $1) FROM "customer"', - string: 'SELECT ("customer"."metadata" #>> \'age\') FROM "customer"' + string: 'SELECT ("customer"."metadata" #>> \'{address,city}\') FROM "customer"' }, - params: ['age'] + params: ['{address,city}'] }); From 2cb9977912d5692bee98531119bb65d8c0cf94fe Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Mon, 2 Dec 2013 09:11:33 -0600 Subject: [PATCH 272/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ec8bffc2..b85213f9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.33.0", + "version": "0.34.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 63cd294aa06d3c1862b06ddce3ee90ad280f084f Mon Sep 17 00:00:00 2001 From: phestermcs Date: Mon, 23 Dec 2013 13:00:42 -0700 Subject: [PATCH 273/507] Pull request that added support for CASE WHEN broke Postgres.visitColumn in cases where CASE expression was aliased. Pull request to better support js property to column-name mapping broke AS aliasing during Postgres.visitReturning. This change fixes both issues. --- lib/dialect/postgres.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 9ae898bf..59473fac 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -375,6 +375,8 @@ Postgres.prototype.visitCase = function(caseExp) { var self = this; var text = '(CASE'; + this.visitingCase = true; + for (var i = 0; i < caseExp.whenList.length; i++) { var whenExp = ' WHEN ' + this.visit(caseExp.whenList[i]); var thenExp = ' THEN ' + this.visit(caseExp.thenList[i]); @@ -385,6 +387,8 @@ Postgres.prototype.visitCase = function(caseExp) { text += ' ELSE ' + this.visit(caseExp.else); } + this.visitingCase = false; + text += ' END)'; return [text]; } @@ -494,10 +498,13 @@ Postgres.prototype.visitColumn = function(columnNode) { var inInsertUpdateClause = this._visitedInsert || this._visitingUpdateTargetColumn; var inDdlClause = this._visitingAddColumn || this._visitingAlter || this._visitingCreate; var inSelectClause = - !this._selectOrDeleteEndIndex - && !this._visitingWhere - && !inInsertUpdateClause - && !inDdlClause + this.visitingReturning || + (!this._selectOrDeleteEndIndex + && !this._visitingWhere + && !inInsertUpdateClause + && !inDdlClause + && !this.visitingCase + ); var txt = []; var closeParen = 0; if(inSelectClause && !table.alias) { @@ -631,7 +638,11 @@ Postgres.prototype.visitJoin = function(join) { }; Postgres.prototype.visitReturning = function(returning) { - return ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; + this.visitingReturning = true; + var r = ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; + this.visitingReturning = false; + + return r; }; Postgres.prototype.visitModifier = function(node) { From 60da34954097055ac97fa1b8b390542447d64881 Mon Sep 17 00:00:00 2001 From: phestermcs Date: Mon, 23 Dec 2013 18:22:00 -0700 Subject: [PATCH 274/507] Pull request that added support for CASE WHEN broke Postgres.visitColumn when column implicitly aliased is used in CASE. Pull request to better support js property to column-name mapping broke AS aliasing during Postgres.visitReturning. This change fixes both issues. --- test/column-tests.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/column-tests.js b/test/column-tests.js index 1cf993c9..f8b47d12 100644 --- a/test/column-tests.js +++ b/test/column-tests.js @@ -114,6 +114,14 @@ describe('column', function() { it('but not when with explicit property name', function() { assert.equal(table.not2Cam.toQuery().text, '"sc"."not_to_camel" AS "not2Cam"'); }); - }) + it('does not use property alias within CASE ... END', function() { + assert.equal(table.makeMeCamel.case([table.makeMeCamel.equals(0)],[table.makeMeCamel]).as('rename').toQuery().text, + '(CASE WHEN ("sc"."make_me_camel" = $1) THEN "sc"."make_me_camel" END) AS "rename"'); + }); + 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"'); + }); + }); }); }); From 604bc161039f0324a5737fe3893c08b6e55e8fa3 Mon Sep 17 00:00:00 2001 From: Sylvain Gizard Date: Fri, 10 Jan 2014 11:01:50 +0100 Subject: [PATCH 275/507] Add toNamedQuery method --- lib/node/index.js | 9 ++++++++ test/index-tests.js | 54 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/lib/node/index.js b/lib/node/index.js index ec7e0a12..e0dabff5 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -50,6 +50,15 @@ Node.prototype.toQuery = function(dialect) { return new Dialect().getQuery(this); }; +Node.prototype.toNamedQuery = function(name, dialect) { + if (!name || typeof name !== 'string' || name === '') { + throw new Error('A query name has to be a non-empty String.'); + } + var query = this.toQuery(dialect); + query.name = name; + return query; +}; + Node.prototype.toString = function(dialect) { var Dialect = determineDialect(this, dialect); return new Dialect().getString(this); diff --git a/test/index-tests.js b/test/index-tests.js index a959d357..79cbd6ce 100644 --- a/test/index-tests.js +++ b/test/index-tests.js @@ -100,4 +100,58 @@ suite('index', function() { query.toQuery('invalid'); }); }); + + test('using named queries with toNamedQuery', function() { + var query = sql.select(user.id).from(user).where(user.email.equals('brian.m.carlson@gmail.com')).toNamedQuery('users'); + assert.equal(query.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + assert.equal(query.values[0], 'brian.m.carlson@gmail.com'); + assert.equal(query.name, 'users'); + }); + + test('provide an empty query name for toNamedQuery', function() { + var query = sql.select(user.id).from(user); + assert.throws(function() { + query.toNamedQuery(''); + }); + }); + + test('provide an undefined query name for toNamedQuery', function() { + var query = sql.select(user.id).from(user); + assert.throws(function() { + query.toNamedQuery(); + }); + }); + + test('override dialect for toNamedQuery using dialect name', function() { + var Sql = sql.Sql; + var mysql = new Sql('mysql'); + var postgres = new Sql('postgres'); + var sqlite = new Sql('sqlite'); + + 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 values = ['brian.m.carlson@gmail.com']; + assert.equal(sqliteQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + assert.deepEqual(sqliteQuery.values, values); + assert.equal('user.select_brian', sqliteQuery.name); + + assert.equal(postgresQuery.text, 'SELECT "user"."id" FROM "user" WHERE ("user"."email" = $1)'); + assert.deepEqual(postgresQuery.values, values); + assert.equal('user.select_brian', postgresQuery.name); + + assert.equal(mysqlQuery.text, 'SELECT `user`.`id` FROM `user` WHERE (`user`.`email` = ?)'); + assert.deepEqual(mysqlQuery.values, values); + assert.equal('user.select_brian', mysqlQuery.name); + + }); + + test('override dialect for toNamedQuery using invalid dialect name', function() { + var query = sql.select(user.id).from(user); + assert.throws(function() { + query.toNamedQuery('name', 'invalid'); + }); + }); + }); From 318359e2e5e90b178afb1635293093d14eb81f7e Mon Sep 17 00:00:00 2001 From: Sylvain Gizard Date: Fri, 10 Jan 2014 11:09:21 +0100 Subject: [PATCH 276/507] Update README --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0cfb115b..5b16559e 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,9 @@ console.log(query.text); //SELECT "user"."id" FROM "user" WHERE ((("user"."name" console.log(query.values); //['boom', 1, 'bang', 2] +//queries can be named +var query = user.select(user.star()).from(user).toNamedQuery('user.all'); +console.log(query.name); //'user.all' //how about a join? var query = user.select(user.name, post.body) @@ -147,7 +150,7 @@ Read the module's documentation for more details. We __love__ contributions. -node-sql wouldn't be anything without all the contributors and collaborators who've worked on it. +node-sql wouldn't be anything without all the contributors and collaborators who've worked on it. If you'd like to become a collaborator here's how it's done: 1. fork the repo @@ -156,7 +159,7 @@ If you'd like to become a collaborator here's how it's done: 4. `npm install` 5. `npm test` -At this point the tests should pass for you. If they don't pass please open an issue with the output or you can even send me an email directly. +At this point the tests should pass for you. If they don't pass please open an issue with the output or you can even send me an email directly. My email address is on my github profile and also on every commit I contributed in the repo. Once the tests are passing, modify as you see fit. _Please_ make sure you write tests to cover your modifications. Once you're ready, commit your changes and submit a pull request. @@ -165,7 +168,7 @@ __As long as your pull request doesn't have completely off-the-wall changes and If you think your changes are too off-the-wall, open an issue or a pull-request without code so we can discuss them before you begin. -Usually after a few high-quality pull requests and friendly interactions we will gladly share collaboration rights with you. +Usually after a few high-quality pull requests and friendly interactions we will gladly share collaboration rights with you. After all, open source belongs to everyone. From 9633a637a8c9e655a264ae396116efe9c6fc7c52 Mon Sep 17 00:00:00 2001 From: phestermcs Date: Fri, 10 Jan 2014 06:42:26 -0700 Subject: [PATCH 277/507] added join() method to returned subQuery Query --- lib/table.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/table.js b/lib/table.js index e1e91e63..b6172466 100644 --- a/lib/table.js +++ b/lib/table.js @@ -161,6 +161,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); + } return query; }; From 863e6e3cb3b3868342c9560f377f1885642013a2 Mon Sep 17 00:00:00 2001 From: Gerasimos Athanasopoulos Date: Sat, 18 Jan 2014 13:47:54 +0200 Subject: [PATCH 278/507] [FIX] the INSERT query to accept function calls as values --- lib/node/insert.js | 2 +- test/dialects/insert-tests.js | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/node/insert.js b/lib/node/insert.js index 7232a0d7..9cd12fbe 100644 --- a/lib/node/insert.js +++ b/lib/node/insert.js @@ -59,7 +59,7 @@ Insert.prototype.getParameters = function () { self.names.forEach(function (name) { var node = nodeDict[name]; if (node) { - set.push(new ParameterNode(node.value)); + set.push(ParameterNode.getNodeOrParameterNode(node.value)); } else { set.push(new DefaultNode()); diff --git a/test/dialects/insert-tests.js b/test/dialects/insert-tests.js index 56abd8dc..69daa9f8 100644 --- a/test/dialects/insert-tests.js +++ b/test/dialects/insert-tests.js @@ -58,6 +58,26 @@ Harness.test({ params: ['test', 2] }); +Harness.test({ + query: post.insert({ + content: post.sql.functions.LOWER('TEST'), + userId: 2 + }), + pg: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + sqlite: { + text : 'INSERT INTO "post" ("content", "userId") VALUES (LOWER($1), $2)', + string: 'INSERT INTO "post" ("content", "userId") VALUES (LOWER(\'TEST\'), 2)' + }, + mysql: { + text : 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(?), ?)', + string: 'INSERT INTO `post` (`content`, `userId`) VALUES (LOWER(\'TEST\'), 2)' + }, + params: ['TEST', 2] +}); + // allow bulk insert Harness.test({ query: post.insert([{ @@ -372,7 +392,7 @@ Harness.test({ ]), pg: { text : 'INSERT INTO "post" ("content") VALUES ($1), ($2)', - string: 'INSERT INTO "post" ("content") ' + + string: 'INSERT INTO "post" ("content") ' + 'VALUES (\'\\x77686f6168\'), (\'\\x686579\')' }, sqlite: { From 557fe7b58b504292e9c5ad120853076c9f229e9c Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sat, 18 Jan 2014 12:18:16 -0600 Subject: [PATCH 279/507] Do not test on v0.6.x due to npm & travis issue --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b02f3658..2ceb35c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: node_js node_js: - - "0.4" - - "0.6" - "0.8" - "0.10" - "0.11" From 989e14b799ddc4c329fa75aef69be586f661bf12 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sat, 18 Jan 2014 12:18:26 -0600 Subject: [PATCH 280/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b85213f9..e6d113ac 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.34.0", + "version": "0.35.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From b8dcbe656bbea424b8d7b903cae53955b8966c81 Mon Sep 17 00:00:00 2001 From: Ray Solomon Date: Sun, 2 Feb 2014 11:45:29 -0800 Subject: [PATCH 281/507] add regex operator support --- lib/node/valueExpression.js | 2 ++ test/binary-clause-tests.js | 2 ++ test/dialects/regex-tests.js | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 test/dialects/regex-tests.js diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index f26d822b..6d49de54 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -109,6 +109,8 @@ var ValueExpressionMixin = function() { bitwiseNot : binaryMethod('~'), bitwiseOr : binaryMethod('|'), bitwiseXor : binaryMethod('#'), + regex : binaryMethod('~'), + notRegex : binaryMethod('!~'), concat : binaryMethod('||'), key : binaryMethod('->'), keyText : binaryMethod('->>'), diff --git a/test/binary-clause-tests.js b/test/binary-clause-tests.js index 8c3cf0ea..438a3761 100644 --- a/test/binary-clause-tests.js +++ b/test/binary-clause-tests.js @@ -32,4 +32,6 @@ test('operators', function() { assert.equal(Foo.baz.bitwiseXor(1).operator, '#'); 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.notRegex(1).operator, '!~'); }); diff --git a/test/dialects/regex-tests.js b/test/dialects/regex-tests.js new file mode 100644 index 00000000..afddce99 --- /dev/null +++ b/test/dialects/regex-tests.js @@ -0,0 +1,23 @@ +'use strict'; + +var Harness = require('./support'); +var customer = Harness.defineCustomerTable(); +var Sql = require('../../lib').setDialect('postgres'); + +Harness.test({ + query: customer.select(customer.metadata.regex('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: { + text : 'SELECT ("customer"."metadata" !~ $1) FROM "customer"', + string: 'SELECT ("customer"."metadata" !~ \'age\') FROM "customer"' + }, + params: ['age'] +}); From 6b1b198b935bef8c22ba51ab1e0c4533c3e64bab Mon Sep 17 00:00:00 2001 From: tmont Date: Wed, 19 Feb 2014 00:01:55 -0800 Subject: [PATCH 282/507] ensure that dialect is set properly some nodes (join, in this case) did not have the proper sql instance set on them. --- lib/node/join.js | 1 + test/table-tests.js | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/lib/node/join.js b/lib/node/join.js index a16067e6..7186f694 100644 --- a/lib/node/join.js +++ b/lib/node/join.js @@ -5,6 +5,7 @@ var JoinNode = module.exports = Node.define({ type: 'JOIN', constructor: function(subType, from, to) { Node.call(this); + this.sql = (from.table && from.table.sql) || (to.table && to.table.sql); this.subType = subType; this.from = from.toNode(); this.to = to.toNode(); diff --git a/test/table-tests.js b/test/table-tests.js index f58fd5e4..43c13791 100644 --- a/test/table-tests.js +++ b/test/table-tests.js @@ -3,6 +3,7 @@ var assert = require('assert'); var Table = require(__dirname + '/../lib/table'); var Column = require(__dirname + '/../lib/column'); +var Sql = require('../'); suite('table', function() { var table = new Table({ @@ -184,4 +185,19 @@ test('set and get schema', function () { assert.equal(table.getSchema(), 'bar'); table.setSchema('barbarz'); assert.equal(table.getSchema(), 'barbarz'); +}); + +test('dialects', function () { + var sql = new Sql.Sql('mysql'); + var foo = sql.define({ name: 'foo', columns: [ 'id' ] }), + bar = sql.define({ name: 'bar', columns: [ 'id' ] }); + + var actual = foo.join(bar).on(bar.id.equals(1)).toString(); + assert.equal(actual, '`foo` INNER JOIN `bar` ON (`bar`.`id` = 1)'); + + sql = new Sql.Sql('postgres'); + foo = sql.define({ name: 'foo', columns: [ 'id' ] }); + 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 21f003885995f606379261a51244e8b25776fd5b Mon Sep 17 00:00:00 2001 From: martinandert Date: Tue, 11 Mar 2014 10:15:37 +0100 Subject: [PATCH 283/507] add failing tests for (NOT) IN operator with empty array or array containing null params --- test/dialects/in-clause-tests.js | 123 +++++++++++++++++++++++++++ test/dialects/not-in-clause-tests.js | 123 +++++++++++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 test/dialects/in-clause-tests.js create mode 100644 test/dialects/not-in-clause-tests.js diff --git a/test/dialects/in-clause-tests.js b/test/dialects/in-clause-tests.js new file mode 100644 index 00000000..a8410e14 --- /dev/null +++ b/test/dialects/in-clause-tests.js @@ -0,0 +1,123 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE (1=0)', + string: 'SELECT "post".* FROM "post" WHERE (1=0)' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE (1=0)', + string: 'SELECT "post".* FROM "post" WHERE (1=0)' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (1=0)', + string: 'SELECT `post`.* FROM `post` WHERE (1=0)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1))' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1))' + }, + params: [1] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([null])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1, 2])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IN (1, 2))' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (?, ?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IN (1, 2))' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([null, null])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NULL)' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1, null, 2])), + pg: { + 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)' + }, + sqlite: { + 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)' + }, + mysql: { + 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)' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.in([1, null, 2, null])), + pg: { + 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)' + }, + sqlite: { + 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)' + }, + mysql: { + 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)' + }, + params: [1, 2] +}); diff --git a/test/dialects/not-in-clause-tests.js b/test/dialects/not-in-clause-tests.js new file mode 100644 index 00000000..b6655e3a --- /dev/null +++ b/test/dialects/not-in-clause-tests.js @@ -0,0 +1,123 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE (1=1)', + string: 'SELECT "post".* FROM "post" WHERE (1=1)' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE (1=1)', + string: 'SELECT "post".* FROM "post" WHERE (1=1)' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (1=1)', + string: 'SELECT `post`.* FROM `post` WHERE (1=1)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1))' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1))' + }, + params: [1] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([null])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1, 2])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN ($1, $2))', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" NOT IN (1, 2))' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (?, ?))', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` NOT IN (1, 2))' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([null, null])), + pg: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + sqlite: { + text : 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)', + string: 'SELECT "post".* FROM "post" WHERE ("post"."id" IS NOT NULL)' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)', + string: 'SELECT `post`.* FROM `post` WHERE (`post`.`id` IS NOT NULL)' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1, null, 2])), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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))' + }, + params: [1, 2] +}); + +Harness.test({ + query: post.select(post.star()).where(post.id.notIn([1, null, 2, null])), + pg: { + 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))' + }, + sqlite: { + 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))' + }, + mysql: { + 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))' + }, + params: [1, 2] +}); From 1e2515b103a0742e19902a0a7d2c39f81cd04468 Mon Sep 17 00:00:00 2001 From: martinandert Date: Tue, 11 Mar 2014 10:25:22 +0100 Subject: [PATCH 284/507] properly handle empty arrays or arrays containing null values given to IN / NOT IN operator --- lib/dialect/postgres.js | 83 +++++++++++++++++++++++++++++++++++-- lib/node/in.js | 28 +++++++++++++ lib/node/notIn.js | 28 +++++++++++++ lib/node/valueExpression.js | 22 ++++++++-- 4 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 lib/node/in.js create mode 100644 lib/node/notIn.js diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 59473fac..6fbf7f9d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -141,6 +141,8 @@ Postgres.prototype.visit = function(node) { case 'PREFIX UNARY' : return this.visitPrefixUnary(node); case 'BINARY' : return this.visitBinary(node); case 'TERNARY' : return this.visitTernary(node); + case 'IN' : return this.visitIn(node); + case 'NOT IN' : return this.visitNotIn(node); case 'CASE' : return this.visitCase(node); case 'AT' : return this.visitAt(node); case 'SLICE' : return this.visitSlice(node); @@ -290,9 +292,9 @@ Postgres.prototype.visitFrom = function(from) { }; Postgres.prototype.visitWhere = function(where) { - this._visitingWhere = true; + this._visitingWhere = true; var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')]; - this._visitingWhere = false; + this._visitingWhere = false; return result; }; @@ -369,6 +371,81 @@ Postgres.prototype.visitTernary = function(ternary) { return [text]; }; +Postgres.prototype.visitIn = function(binary) { + var self = this; + var text = '('; + + if (Array.isArray(binary.right)) { + if (binary.right.length) { + var params = []; + var hasNull = false; + + binary.right.forEach(function(node) { + if (node.type === 'PARAMETER' && node._val === null) { + hasNull = true; + } else { + params.push(self.visit(node)); + } + }); + + if (params.length) { + text += this.visit(binary.left) + ' IN (' + params.join(', ') + ')'; + + if (hasNull) { + text += ' OR ' + this.visit(binary.left) + ' IS NULL'; + } + } else { // implicitely has null + text += this.visit(binary.left) + ' IS NULL'; + } + } else { + text += '1=0'; + } + } else { + text += this.visit(binary.left) + ' IN ' + this.visit(binary.right); + } + + text += ')'; + return [text]; +}; + +Postgres.prototype.visitNotIn = function(binary) { + var self = this; + var text = '('; + + if (Array.isArray(binary.right)) { + if (binary.right.length) { + var params = []; + var hasNull = false; + + binary.right.forEach(function(node) { + if (node.type === 'PARAMETER' && node._val === null) { + hasNull = true; + } else { + params.push(self.visit(node)); + } + }); + + if (params.length && hasNull) { + text += 'NOT ('; + text += this.visit(binary.left) + ' IN (' + params.join(', ') + ')'; + text += ' OR ' + this.visit(binary.left) + ' IS NULL'; + text += ')'; + } else if (params.length) { + text += this.visit(binary.left) + ' NOT IN (' + params.join(', ') + ')'; + } else { // implicitely has null + text += this.visit(binary.left) + ' IS NOT NULL'; + } + } else { + text += '1=1'; + } + } else { + text += this.visit(binary.left) + ' NOT IN ' + this.visit(binary.right); + } + + text += ')'; + return [text]; +}; + Postgres.prototype.visitCase = function(caseExp) { assert(caseExp.whenList.length == caseExp.thenList.length); @@ -542,7 +619,7 @@ Postgres.prototype.visitColumn = function(columnNode) { 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(this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : '')); } txt.push(hasAliases ? allCols.join(', ') : '*'); } diff --git a/lib/node/in.js b/lib/node/in.js new file mode 100644 index 00000000..4c807331 --- /dev/null +++ b/lib/node/in.js @@ -0,0 +1,28 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var InNode = Node.define(_.extend({ + type: 'IN', + constructor: function(config) { + Node.call(this); + this.left = config.left; + this.right = config.right; + + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(InNode.prototype, valueExpressionMixin()); + } + }, +})); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(InNode.prototype, AliasNode.AliasMixin); + +module.exports = InNode; diff --git a/lib/node/notIn.js b/lib/node/notIn.js new file mode 100644 index 00000000..e363f7f3 --- /dev/null +++ b/lib/node/notIn.js @@ -0,0 +1,28 @@ +'use strict'; + +var _ = require('lodash'); +var Node = require(__dirname); +var valueExpressionMixin = require(__dirname + '/valueExpression'); + +var valueExpressionMixed = false; +var NotInNode = Node.define(_.extend({ + type: 'NOT IN', + constructor: function(config) { + Node.call(this); + this.left = config.left; + this.right = config.right; + + // Delay mixin to runtime, when all nodes have been defined, and + // mixin only once. ValueExpressionMixin has circular dependencies. + if (!valueExpressionMixed) { + valueExpressionMixed = true; + _.extend(NotInNode.prototype, valueExpressionMixin()); + } + }, +})); + +// allow aliasing +var AliasNode = require(__dirname + '/alias'); +_.extend(NotInNode.prototype, AliasNode.AliasMixin); + +module.exports = NotInNode; diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index f26d822b..08d711b6 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -14,6 +14,8 @@ var processParams = function(val) { // "thunk" around it. var ValueExpressionMixin = function() { var BinaryNode = require('./binary'); + var InNode = require('./in'); + var NotInNode = require('./notIn'); var CastNode = require('./cast'); var PostfixUnaryNode = require('./postfixUnary'); var TernaryNode = require('./ternary'); @@ -25,7 +27,7 @@ var ValueExpressionMixin = function() { /*jshint unused: false */ return function(val) { return new PostfixUnaryNode({ - left : this.toNode(), + left : this.toNode(), operator : operator }); }; @@ -41,6 +43,20 @@ var ValueExpressionMixin = function() { }; }; + var inMethod = function(val) { + return new InNode({ + left : this.toNode(), + right : processParams(val) + }); + }; + + var notInMethod = function(val) { + return new NotInNode({ + left : this.toNode(), + right : processParams(val) + }); + }; + var ternaryMethod = function(operator, separator) { return function(middle, right) { return new TernaryNode({ @@ -116,8 +132,8 @@ var ValueExpressionMixin = function() { pathText : binaryMethod('#>>'), like : binaryMethod('LIKE'), notLike : binaryMethod('NOT LIKE'), - in : binaryMethod('IN'), - notIn : binaryMethod('NOT IN'), + in : inMethod, + notIn : notInMethod, between : ternaryMethod('BETWEEN', 'AND'), at : atMethod, slice : sliceMethod, From 5dd378a0e35f016d7451892b3020f0cb1c7ab439 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sat, 15 Mar 2014 13:38:22 -0500 Subject: [PATCH 285/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e6d113ac..7e76347d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.35.0", + "version": "0.36.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 2b4dc8c24776c94a3a2a527736bddd315c06b856 Mon Sep 17 00:00:00 2001 From: martinandert Date: Sun, 16 Mar 2014 20:40:46 +0100 Subject: [PATCH 286/507] introduce literal node type --- lib/dialect/postgres.js | 11 ++++++++++- lib/table.js | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 59473fac..6d74ccb7 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -120,6 +120,7 @@ Postgres.prototype.visit = function(node) { case 'TABLE' : return this.visitTable(node); case 'COLUMN' : return this.visitColumn(node); case 'JOIN' : return this.visitJoin(node); + case 'LITERAL' : return this.visitLiteral(node); case 'TEXT' : return node.text; case 'PARAMETER' : return this.visitParameter(node); case 'DEFAULT' : return this.visitDefault(node); @@ -507,7 +508,7 @@ Postgres.prototype.visitColumn = function(columnNode) { ); var txt = []; var closeParen = 0; - if(inSelectClause && !table.alias) { + if(inSelectClause && (!table.alias || !!columnNode.alias)) { if (columnNode.asArray) { closeParen++; txt.push(this._arrayAggFunctionName+'('); @@ -637,6 +638,14 @@ Postgres.prototype.visitJoin = function(join) { return result; }; +Postgres.prototype.visitLiteral = function(node) { + var txt = [node.literal]; + if(node.alias) { + txt.push(' AS ' + this.quote(node.alias)); + } + return [txt.join('')]; +}; + Postgres.prototype.visitReturning = function(returning) { this.visitingReturning = true; var r = ['RETURNING', returning.nodes.map(this.visit.bind(this)).join(', ')]; diff --git a/lib/table.js b/lib/table.js index b6172466..1a7338f7 100644 --- a/lib/table.js +++ b/lib/table.js @@ -7,6 +7,7 @@ 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 Table = function(config) { @@ -132,6 +133,10 @@ Table.prototype.star = function(options) { return new Column({table: this, star: true}); }; +Table.prototype.literal = function(literal) { + return new LiteralNode(literal); +} + Table.prototype.count = function(alias) { var name = this.alias || this._name, col = new Column({table: this, star: true}); From 842a58f4d2b3dc48f79805ea3f76250e21454311 Mon Sep 17 00:00:00 2001 From: martinandert Date: Sun, 16 Mar 2014 20:48:19 +0100 Subject: [PATCH 287/507] introduce literal node type: new files --- lib/node/literal.js | 16 +++++++++ test/dialects/literal-tests.js | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 lib/node/literal.js create mode 100644 test/dialects/literal-tests.js diff --git a/lib/node/literal.js b/lib/node/literal.js new file mode 100644 index 00000000..9f1c4da0 --- /dev/null +++ b/lib/node/literal.js @@ -0,0 +1,16 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'LITERAL', + constructor: function(literal) { + Node.call(this); + this.literal = literal; + this.alias = null; + }, + as: function(alias) { + this.alias = alias; + return this; + } +}); \ No newline at end of file diff --git a/test/dialects/literal-tests.js b/test/dialects/literal-tests.js new file mode 100644 index 00000000..e1940f5a --- /dev/null +++ b/test/dialects/literal-tests.js @@ -0,0 +1,60 @@ +'use strict'; + +var Harness = require('./support'); +var user = Harness.defineUserTable(); + +Harness.test({ + query: user.select(user.literal('foo'), user.name, user.literal('123').as('onetwothree')), + pg: { + text : 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"', + string: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"' + }, + sqlite: { + text : 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"', + string: 'SELECT foo, "user"."name", 123 AS "onetwothree" FROM "user"' + }, + mysql: { + text : 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`', + string: 'SELECT foo, `user`.`name`, 123 AS `onetwothree` FROM `user`' + }, + params: [] +}); + + +Harness.test({ + query: user.select().where(user.literal('foo = bar')), + pg: { + text : 'SELECT "user".* FROM "user" WHERE foo = bar', + string: 'SELECT "user".* FROM "user" WHERE foo = bar' + }, + sqlite: { + text : 'SELECT "user".* FROM "user" WHERE foo = bar', + string: 'SELECT "user".* FROM "user" WHERE foo = bar' + }, + mysql: { + text : 'SELECT `user`.* FROM `user` WHERE foo = bar', + string: 'SELECT `user`.* FROM `user` WHERE foo = bar' + }, + params: [] +}); + +// A real world example: "How many records does page 3 have?" +// This could be less than 10 (the limit) if we are on the last page. +var subquery = user.subQuery('subquery_for_count').select(user.literal(1).as('count_column')).limit(10).offset(20); + +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' + }, + 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' + }, + 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' + }, + params: [] +}); From c4db732be5f87b59f099ac67f7cfd7967a6230c5 Mon Sep 17 00:00:00 2001 From: martinandert Date: Sun, 16 Mar 2014 20:49:44 +0100 Subject: [PATCH 288/507] fix whitespace --- lib/node/literal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node/literal.js b/lib/node/literal.js index 9f1c4da0..c4f539bb 100644 --- a/lib/node/literal.js +++ b/lib/node/literal.js @@ -13,4 +13,4 @@ module.exports = Node.define({ this.alias = alias; return this; } -}); \ No newline at end of file +}); From f825d75bbc7ed9c2590db7e79573046ffaae960f Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Sun, 16 Mar 2014 21:28:16 -0500 Subject: [PATCH 289/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7e76347d..dec3f7b4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.36.0", + "version": "0.37.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From 5f0b3ba921fdf7125390389e0ebc69d6fc845aa0 Mon Sep 17 00:00:00 2001 From: Gerasimos Athanasopoulos Date: Thu, 27 Mar 2014 00:14:42 +0200 Subject: [PATCH 290/507] [ADD] FOR UPDATE and FOR SHARE statements --- lib/dialect/mysql.js | 4 ++++ lib/dialect/postgres.js | 10 ++++++++++ lib/dialect/sqlite.js | 8 ++++++++ lib/node/forShare.js | 7 +++++++ lib/node/forUpdate.js | 7 +++++++ lib/node/query.js | 33 ++++++++++++++++++++++++++++++- test/dialects/for-share-tests.js | 18 +++++++++++++++++ test/dialects/for-update-tests.js | 31 +++++++++++++++++++++++++++++ 8 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 lib/node/forShare.js create mode 100644 lib/node/forUpdate.js create mode 100644 test/dialects/for-share-tests.js create mode 100644 test/dialects/for-update-tests.js diff --git a/lib/dialect/mysql.js b/lib/dialect/mysql.js index 976e8cfa..f8d31890 100644 --- a/lib/dialect/mysql.js +++ b/lib/dialect/mysql.js @@ -35,6 +35,10 @@ Mysql.prototype.visitReturning = function() { throw new Error('MySQL does not allow returning clause.'); }; +Mysql.prototype.visitForShare = function() { + throw new Error('MySQL does not allow FOR SHARE clause.'); +}; + Mysql.prototype.visitCreate = function(create) { var result = Mysql.super_.prototype.visitCreate.call(this, create); var engine = this._queryNode.table._initialConfig.engine; diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 9d4ebf15..15b1b0ab 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -117,6 +117,8 @@ 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 'FOR UPDATE' : return this.visitForUpdate(); + case 'FOR SHARE' : return this.visitForShare(); case 'TABLE' : return this.visitTable(node); case 'COLUMN' : return this.visitColumn(node); case 'JOIN' : return this.visitJoin(node); @@ -705,6 +707,14 @@ Postgres.prototype.visitRestrict = function() { return ['RESTRICT']; }; +Postgres.prototype.visitForUpdate = function() { + return ['FOR UPDATE']; +}; + +Postgres.prototype.visitForShare = function() { + return ['FOR SHARE']; +}; + Postgres.prototype.visitJoin = function(join) { var result = []; result = result.concat(this.visit(join.from)); diff --git a/lib/dialect/sqlite.js b/lib/dialect/sqlite.js index ac7e1c0d..33dedc89 100644 --- a/lib/dialect/sqlite.js +++ b/lib/dialect/sqlite.js @@ -42,6 +42,14 @@ Sqlite.prototype.visitReturning = function() { throw new Error('SQLite does not allow returning clause.'); }; +Sqlite.prototype.visitForUpdate = function() { + throw new Error('SQLite does not allow FOR UPDATE clause.'); +}; + +Sqlite.prototype.visitForShare = function() { + throw new Error('SQLite does not allow FOR SHARE clause.'); +}; + Sqlite.prototype.visitAddColumn = function(addColumn) { assert(!this._hasAddedAColumn, 'SQLite can not add more that one column at a time'); var result = Postgres.prototype.visitAddColumn.call(this, addColumn); diff --git a/lib/node/forShare.js b/lib/node/forShare.js new file mode 100644 index 00000000..328a4ebe --- /dev/null +++ b/lib/node/forShare.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'FOR SHARE' +}); diff --git a/lib/node/forUpdate.js b/lib/node/forUpdate.js new file mode 100644 index 00000000..c869f981 --- /dev/null +++ b/lib/node/forUpdate.js @@ -0,0 +1,7 @@ +'use strict'; + +var Node = require(__dirname); + +module.exports = Node.define({ + type: 'FOR UPDATE' +}); diff --git a/lib/node/query.js b/lib/node/query.js index d0ce096d..0613d1a3 100644 --- a/lib/node/query.js +++ b/lib/node/query.js @@ -15,6 +15,8 @@ var Insert = require('./insert'); var Update = require('./update'); var Delete = require('./delete'); var Returning = require('./returning'); +var ForUpdate = require('./forUpdate'); +var ForShare = require('./forShare'); var Create = require('./create'); var Drop = require('./drop'); var Alter = require('./alter'); @@ -52,6 +54,7 @@ var getArrayOrArgsAsArray = function(args) { var Query = Node.define({ type: 'QUERY', + constructor: function(table) { Node.call(this); this.table = table; @@ -59,6 +62,7 @@ var Query = Node.define({ this.sql = table.sql; } }, + select: function() { var select; if (this._select) { @@ -96,6 +100,7 @@ var Query = Node.define({ } return this; }, + star: function() { assert(this.type === 'SUBQUERY', 'star() can only be used on a subQuery'); return new Column({ @@ -103,10 +108,12 @@ var Query = Node.define({ star: true }); }, + from: function(tableNode) { var from = new From().add(tableNode); return this.add(from); }, + where: function(node) { if (arguments.length > 1) { // allow multiple where clause arguments @@ -124,14 +131,17 @@ var Query = Node.define({ this.whereClause.add(node); return this.add(this.whereClause); }, + or: function(node) { this.whereClause.or(node); return this; }, + and: function(node) { this.whereClause.and(node); return this; }, + order: function() { var args = getArrayOrArgsAsArray(arguments); var orderBy; @@ -144,16 +154,19 @@ var Query = Node.define({ orderBy.addAll(args); return this; }, + group: function() { var args = getArrayOrArgsAsArray(arguments); var groupBy = new GroupBy().addAll(args); return this.add(groupBy); }, + having: function() { var args = getArrayOrArgsAsArray(arguments); var having = new Having().addAll(args); return this.add(having); }, + insert: function(o) { var self = this; @@ -183,6 +196,7 @@ var Query = Node.define({ } }, + update: function(o) { var self = this; var update = new Update(); @@ -195,11 +209,13 @@ var Query = Node.define({ }); return this.add(update); }, - parameter: function(v) { + + parameter: function(v) { var param = ParameterNode.getNodeOrParameterNode(v); param.isExplicit = true; return this.add(param); }, + delete: function(params) { var result; if (params) { @@ -223,6 +239,7 @@ var Query = Node.define({ } return result; }, + returning: function() { var args = getArrayOrArgsAsArray(arguments); var returning = new Returning(); @@ -230,6 +247,18 @@ var Query = Node.define({ return this.add(returning); }, + forUpdate: function() { + assert(typeof this._select !== 'undefined', 'FOR UPDATE can be used only in a select statement'); + this.add(new ForUpdate()); + return this; + }, + + forShare: function() { + assert(typeof this._select !== 'undefined', 'FOR SHARE can be used only in a select statement'); + this.add(new ForShare()); + return this; + }, + create: function(indexName) { if (this.indexesClause) { var createIndex = new CreateIndex(this.table, indexName); @@ -267,6 +296,7 @@ var Query = Node.define({ this.nodes[0].add(renameClause); return this; }, + addColumn: function(column, dataType) { var addClause = new AddColumn(); if (!column.toNode) { @@ -282,6 +312,7 @@ var Query = Node.define({ this.nodes[0].add(addClause); return this; }, + dropColumn: function(column) { var dropClause = new DropColumn(); if (!column.toNode) { diff --git a/test/dialects/for-share-tests.js b/test/dialects/for-share-tests.js new file mode 100644 index 00000000..1b19e1de --- /dev/null +++ b/test/dialects/for-share-tests.js @@ -0,0 +1,18 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); +var bar = Harness.definePostTable(); + +Harness.test({ + query: post.select(post.star()).forUpdate(), + pg: { + text : 'SELECT "post".* FROM "post" FOR UPDATE', + string: 'SELECT "post".* FROM "post" FOR UPDATE' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` FOR UPDATE', + string: 'SELECT `post`.* FROM `post` FOR UPDATE' + }, + params: [] +}); diff --git a/test/dialects/for-update-tests.js b/test/dialects/for-update-tests.js new file mode 100644 index 00000000..19a01e20 --- /dev/null +++ b/test/dialects/for-update-tests.js @@ -0,0 +1,31 @@ +'use strict'; + +var Harness = require('./support'); +var post = Harness.definePostTable(); +var user = Harness.defineUserTable(); + +Harness.test({ + query: post.select(post.star()).forUpdate(), + pg: { + text : 'SELECT "post".* FROM "post" FOR UPDATE', + string: 'SELECT "post".* FROM "post" FOR UPDATE' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` FOR UPDATE', + string: 'SELECT `post`.* FROM `post` FOR UPDATE' + }, + params: [] +}); + +Harness.test({ + query: post.select(post.star()).from(post.join(user).on(user.id.equals(post.userId))).where(post.content.equals('foo')).forUpdate(), + pg: { + text : 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = $1) FOR UPDATE', + string: 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = \'foo\') FOR UPDATE' + }, + mysql: { + text : 'SELECT `post`.* FROM `post` INNER JOIN `user` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`content` = ?) FOR UPDATE', + string: 'SELECT `post`.* FROM `post` INNER JOIN `user` ON (`user`.`id` = `post`.`userId`) WHERE (`post`.`content` = \'foo\') FOR UPDATE' + }, + params: ["foo"] +}); From dbad8c5ab4c007323ddbac2b2de035a9e8fd7f5c Mon Sep 17 00:00:00 2001 From: Gerasimos Athanasopoulos Date: Thu, 27 Mar 2014 00:17:57 +0200 Subject: [PATCH 291/507] [ADD] tests for for share --- test/dialects/for-share-tests.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/dialects/for-share-tests.js b/test/dialects/for-share-tests.js index 1b19e1de..4b9627fa 100644 --- a/test/dialects/for-share-tests.js +++ b/test/dialects/for-share-tests.js @@ -2,17 +2,22 @@ var Harness = require('./support'); var post = Harness.definePostTable(); -var bar = Harness.definePostTable(); +var user = Harness.defineUserTable(); Harness.test({ - query: post.select(post.star()).forUpdate(), + query: post.select(post.star()).forShare(), pg: { - text : 'SELECT "post".* FROM "post" FOR UPDATE', - string: 'SELECT "post".* FROM "post" FOR UPDATE' - }, - mysql: { - text : 'SELECT `post`.* FROM `post` FOR UPDATE', - string: 'SELECT `post`.* FROM `post` FOR UPDATE' + text : 'SELECT "post".* FROM "post" FOR SHARE', + string: 'SELECT "post".* FROM "post" FOR SHARE' }, params: [] }); + +Harness.test({ + query: post.select(post.star()).from(post.join(user).on(user.id.equals(post.userId))).where(post.content.equals('foo')).forShare(), + pg: { + text : 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = $1) FOR SHARE', + string: 'SELECT "post".* FROM "post" INNER JOIN "user" ON ("user"."id" = "post"."userId") WHERE ("post"."content" = \'foo\') FOR SHARE' + }, + params: ["foo"] +}); From 86c88afbaad3540aa384dddc14279bf4ab6c6849 Mon Sep 17 00:00:00 2001 From: Scott Tadman Date: Mon, 31 Mar 2014 17:45:10 -0400 Subject: [PATCH 292/507] Adding support for Postgres <@, @>, && ARRAY operations --- lib/dialect/postgres.js | 21 +++++++++++++++++++++ lib/node/valueExpression.js | 15 +++++++++++++++ test/dialects/array-tests.js | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index dbd96fa2..25a1a883 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -142,6 +142,9 @@ Postgres.prototype.visit = function(node) { case 'CASE' : return this.visitCase(node); case 'AT' : return this.visitAt(node); case 'SLICE' : return this.visitSlice(node); + case 'CONTAINS' : return this.visitContains(node); + case 'CONTAINED BY' : return this.visitContainedBy(node); + case 'OVERLAP' : return this.visitOverlap(node); case 'LIMIT' : case 'OFFSET': @@ -399,6 +402,24 @@ Postgres.prototype.visitSlice = function(slice) { return [text]; }; +Postgres.prototype.visitContains = function(contains) { + var text = this.visit(contains.value); + text += ' @> ' + this.visit(contains.set); + return [text]; +}; + +Postgres.prototype.visitContainedBy = function(containedBy) { + var text = this.visit(containedBy.value); + text += ' <@ ' + this.visit(containedBy.set); + return [text]; +}; + +Postgres.prototype.visitOverlap = function(overlap) { + var text = this.visit(overlap.value); + text += ' && ' + this.visit(overlap.set); + return [text]; +}; + Postgres.prototype.visitQuery = function(queryNode) { this._queryNode = queryNode; // need to sort the top level query nodes on visitation priority diff --git a/lib/node/valueExpression.js b/lib/node/valueExpression.js index f26d822b..67801166 100644 --- a/lib/node/valueExpression.js +++ b/lib/node/valueExpression.js @@ -61,6 +61,18 @@ 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); }; @@ -120,6 +132,9 @@ var ValueExpressionMixin = function() { notIn : binaryMethod('NOT IN'), between : ternaryMethod('BETWEEN', 'AND'), at : atMethod, + contains : binaryMethod('@>'), + containedBy : binaryMethod('<@'), + overlap : binaryMethod('&&'), slice : sliceMethod, cast : castMethod, descending : orderMethod('DESC'), diff --git a/test/dialects/array-tests.js b/test/dialects/array-tests.js index 879c3fd4..f4191400 100644 --- a/test/dialects/array-tests.js +++ b/test/dialects/array-tests.js @@ -16,6 +16,39 @@ Harness.test({ params: ['nodejs'] }); +Harness.test({ + query: post.select( + post.tags.contains(Sql.array('nodejs', 'js')) + ), + pg: { + text : 'SELECT ("post"."tags" @> ARRAY[$1, $2]) FROM "post"', + string: 'SELECT ("post"."tags" @> ARRAY[\'nodejs\', \'js\']) FROM "post"' + }, + params: ['nodejs', 'js'] +}); + +Harness.test({ + query: post.select( + post.tags.containedBy(Sql.array('nodejs', 'js')) + ), + pg: { + text : 'SELECT ("post"."tags" <@ ARRAY[$1, $2]) FROM "post"', + string: 'SELECT ("post"."tags" <@ ARRAY[\'nodejs\', \'js\']) FROM "post"' + }, + params: ['nodejs', 'js'] +}); + +Harness.test({ + query: post.select( + post.tags.overlap(Sql.array('nodejs', 'js')) + ), + pg: { + text : 'SELECT ("post"."tags" && ARRAY[$1, $2]) FROM "post"', + string: 'SELECT ("post"."tags" && ARRAY[\'nodejs\', \'js\']) FROM "post"' + }, + params: ['nodejs', 'js'] +}); + Harness.test({ query: post.select(post.tags.slice(2,3)), pg: { From 063cda0c0bf3334609befb793cd55997ca86a36f Mon Sep 17 00:00:00 2001 From: Scott Tadman Date: Mon, 31 Mar 2014 17:49:50 -0400 Subject: [PATCH 293/507] Clearing up modifications to postgres.js --- lib/dialect/postgres.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/dialect/postgres.js b/lib/dialect/postgres.js index 25a1a883..f8933e7d 100644 --- a/lib/dialect/postgres.js +++ b/lib/dialect/postgres.js @@ -142,9 +142,6 @@ Postgres.prototype.visit = function(node) { case 'CASE' : return this.visitCase(node); case 'AT' : return this.visitAt(node); case 'SLICE' : return this.visitSlice(node); - case 'CONTAINS' : return this.visitContains(node); - case 'CONTAINED BY' : return this.visitContainedBy(node); - case 'OVERLAP' : return this.visitOverlap(node); case 'LIMIT' : case 'OFFSET': From 45d58a2020c5ce69724fc9ee628302b90d334d59 Mon Sep 17 00:00:00 2001 From: "Brian M. Carlson" Date: Wed, 9 Apr 2014 09:12:10 -0500 Subject: [PATCH 294/507] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dec3f7b4..e344a719 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "author": "brianc ", "name": "sql", "description": "sql builder", - "version": "0.37.0", + "version": "0.38.0", "homepage": "https://github.com/brianc/node-sql", "repository": { "type": "git", From cf1d697638b30ab6d70c48ed0948420b0d282795 Mon Sep 17 00:00:00 2001 From: thadclay Date: Thu, 24 Apr 2014 17:45:15 -0400 Subject: [PATCH 295/507] 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 296/507] 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 297/507] 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 298/507] 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 299/507] 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 300/507] 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 301/507] 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 302/507] 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 303/507] 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 304/507] 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 305/507] 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 306/507] 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 307/507] 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 308/507] 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 309/507] 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 310/507] 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 311/507] 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 312/507] 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 313/507] 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 314/507] 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 315/507] 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 316/507] 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 317/507] 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 318/507] 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 319/507] 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 320/507] 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 321/507] 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 322/507] 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 323/507] 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 324/507] 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 325/507] 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 326/507] 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 327/507] 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 328/507] 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 329/507] 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 330/507] 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 331/507] 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 332/507] - 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 333/507] 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 334/507] 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 335/507] 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 336/507] 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 337/507] 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 338/507] 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 339/507] 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 340/507] 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 341/507] 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 342/507] 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 343/507] 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 344/507] 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 345/507] 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 346/507] 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 347/507] - 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 348/507] 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 349/507] 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 350/507] 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 351/507] 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 352/507] - 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 353/507] - 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 354/507] 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 355/507] 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 356/507] 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 357/507] 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 358/507] 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 359/507] 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 360/507] 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 361/507] 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 362/507] 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 363/507] 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 364/507] 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 365/507] 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 366/507] 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 367/507] 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 368/507] 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 369/507] - 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 370/507] 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 371/507] 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 372/507] 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 373/507] 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 374/507] 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 375/507] 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 376/507] 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 377/507] 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 378/507] 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 379/507] 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 380/507] 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 381/507] 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 382/507] 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 383/507] 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 384/507] 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 385/507] 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 386/507] 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 387/507] 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 388/507] 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 389/507] 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 390/507] 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 391/507] 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 392/507] 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 393/507] 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 394/507] 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 395/507] 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 396/507] 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 397/507] 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 398/507] 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 399/507] 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 400/507] 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 401/507] 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 402/507] 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 403/507] 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 404/507] 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 405/507] 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 406/507] 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 407/507] 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 408/507] 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 409/507] 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 410/507] 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 411/507] 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 412/507] 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 413/507] 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 414/507] 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 415/507] 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 416/507] 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 417/507] 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 418/507] 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 419/507] 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 420/507] 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 421/507] 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 422/507] 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 423/507] 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 424/507] 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 425/507] 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 426/507] 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 427/507] 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 428/507] 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 429/507] 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 430/507] 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 431/507] 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 432/507] 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 433/507] 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 434/507] 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 435/507] 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 436/507] 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 437/507] 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 438/507] 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 439/507] 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 440/507] 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 441/507] 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 442/507] 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 443/507] 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 444/507] 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 445/507] 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 446/507] 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 447/507] 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 448/507] 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 449/507] 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 450/507] 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 451/507] 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 452/507] 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 453/507] 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 454/507] 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 455/507] 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 456/507] 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 457/507] 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 458/507] 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 459/507] 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 460/507] 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 461/507] 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 462/507] 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 463/507] 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 464/507] 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 465/507] 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 466/507] 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 467/507] _.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 468/507] 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 469/507] 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 470/507] 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 471/507] 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 472/507] 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 473/507] 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 474/507] =?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 475/507] 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 476/507] 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 477/507] 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 478/507] 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 479/507] 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 480/507] 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 481/507] 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 482/507] 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 483/507] 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 484/507] 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 485/507] 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 486/507] 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 487/507] 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 488/507] 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 489/507] 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 490/507] 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 491/507] 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 492/507] 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 493/507] 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 494/507] 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 495/507] 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 496/507] 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 497/507] - 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 498/507] - 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 499/507] 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 500/507] 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 501/507] - 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 502/507] - 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 503/507] 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 504/507] 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 505/507] 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 506/507] 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 507/507] 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?: {