Browse Source

Merge pull request #49 from brianc/object-literals

Object literals
auto-join
Brian C 12 years ago
parent
commit
98f32243c1
  1. 5
      lib/node/binary.js
  2. 1
      lib/node/column.js
  3. 2
      lib/node/default.js
  4. 22
      lib/node/index.js
  5. 1
      lib/node/insert.js
  6. 4
      lib/node/join.js
  7. 4
      lib/node/orderByColumn.js
  8. 4
      lib/node/parameter.js
  9. 70
      lib/node/query.js
  10. 4
      lib/node/table.js
  11. 1
      lib/node/text.js
  12. 4
      lib/node/unary.js
  13. 40
      lib/node/where.js
  14. 8
      lib/table.js
  15. 4
      package.json
  16. 1
      test/clause-definition.js
  17. 25
      test/dialects/delete-tests.js
  18. 9
      test/dialects/group-by-tests.js
  19. 38
      test/dialects/insert-tests.js
  20. 1
      test/dialects/join-tests.js
  21. 3
      test/dialects/namespace-tests.js
  22. 7
      test/dialects/order-tests.js
  23. 9
      test/dialects/shortcut-tests.js
  24. 8
      test/dialects/table-tests.js

5
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;

1
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;

2
lib/node/default.js

@ -2,8 +2,6 @@
module.exports = require(__dirname).define({
type: 'DEFAULT',
constructor: function() {
},
value: function() {
return;
}

22
lib/node/index.js

@ -1,5 +1,6 @@
'use strict';
var util = require('util');
var assert = require('assert');
var Node = function(type) {
@ -16,18 +17,23 @@ 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);
if(def.constructor) {
def.constructor.apply(this, arguments);
}
Node.call(this);
};
var key;
for(key in Node.prototype) {
c.prototype[key] = Node.prototype[key];
//allow custom sub-class constructor
if(def.constructor && def.constructor != {}.constructor) {
c = def.constructor;
}
for(key in def) {
util.inherits(c, Node);
for(var key in def) {
c.prototype[key] = def[key];
}
return c;

1
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 = [];

4
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();

4
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;
}

4
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() {

70
lib/node/query.js

@ -1,4 +1,7 @@
'use strict';
var util = require('util');
var sliced = require('sliced');
var Node = require(__dirname);
var Select = require(__dirname + '/select');
@ -32,15 +35,16 @@ var Modifier = Node.define({
var Query = Node.define({
type: 'QUERY',
constructor: function(table) {
Node.call(this);
this.table = table;
},
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 = sliced(arguments);
if(util.isArray(args[0])) {
args = args[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++) {
@ -64,28 +68,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;
@ -95,25 +83,25 @@ var Query = Node.define({
return this;
},
order: function() {
var args = Array.prototype.slice.call(arguments, 0);
var orderBy = new OrderBy();
var nodes = args.forEach(function(arg) {
orderBy.add(arg.toNode());
});
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 = Array.prototype.slice.call(arguments, 0);
var groupBy = new GroupBy();
var nodes = args.forEach(function(arg) {
groupBy.add(arg.toNode());
});
var args = sliced(arguments);
if(util.isArray(args[0])) {
args = args[0];
}
var groupBy = new GroupBy().addAll(args);
return this.add(groupBy);
},
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) {
@ -146,16 +134,20 @@ 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();
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 = sliced(arguments);
if(util.isArray(args[0])) {
args = args[0];
}
returning.addAll(args);
return this.add(returning);
},
create: function() {

4
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;
}
});

1
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;
}
});

4
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;
}

40
lib/node/where.js

@ -1,24 +1,54 @@
'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 normalizeNode = function(table, node) {
var result = node;
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});
var query = column.equals(node[colName]);
if (!result)
result = query;
else
result.and(query);
}
}
return result;
};
module.exports = Node.define({
constructor: function(table) {
Node.call(this);
this.table = table;
},
type: 'WHERE',
expr: function(other) {
return typeof other === 'string' ? new TextNode('('+other+')') : other;
add: function(node) {
var node = normalizeNode(this.table, node);
return Node.prototype.add.call(this, node);
},
or: function(other) {
var right = normalizeNode(this.table, other);
return this.nodes.push(new BinaryNode({
left: this.nodes.pop(),
operator: 'OR',
right: this.expr(other)
right: right
}));
},
and: function(other) {
var right = normalizeNode(this.table, other);
return this.nodes.push(new BinaryNode({
left: this.nodes.pop(),
operator: 'AND',
right: this.expr(other)
right: right
}));
}
});

8
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;
};

4
package.json

@ -15,7 +15,9 @@
"engines": {
"node": "*"
},
"dependencies": {},
"dependencies": {
"sliced": "0.0.5"
},
"devDependencies": {
"test-dir" : "*",
"tap" : "*"

1
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;
}
});

25
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: ['']
});

9
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: []
});

38
test/dialects/insert-tests.js

@ -97,4 +97,42 @@ 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: []
});
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: []
});

1
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`)'
});

3
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`'
});

7
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'
});

9
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]
});

8
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

Loading…
Cancel
Save