不要怂,就是干,撸起袖子干!

Commit 49f01691 by Jan Aagaard Meier

Make the ordering / quoting API consitent

1 parent 4dbb571f
......@@ -228,11 +228,12 @@ module.exports = (function() {
}
if (options.group) {
options.group = Array.isArray(options.group) ? options.group.map(function(t) { return this.quoteIdentifiers(t)}.bind(this)).join(', ') : this.quoteIdentifiers(options.group)
options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group
query += " GROUP BY " + options.group
}
if (options.order) {
options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order
query += " ORDER BY " + options.order
}
......
......@@ -300,14 +300,12 @@ module.exports = (function() {
}
if(options.group) {
options.group = Array.isArray(options.group) ? options.group.map(function(t) { return this.quoteIdentifiers(t) }.bind(this)).join(', ') : this.quoteIdentifiers(options.group)
options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group
query += " GROUP BY <%= group %>"
}
if(options.order) {
options.order = options.order.replace(/([^ ]+)(.*)/, function(m, g1, g2) {
return this.quoteIdentifiers(g1) + g2
}.bind(this))
options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order
query += " ORDER BY <%= order %>"
}
......
var Utils = require("../utils")
module.exports = (function() {
var QueryGenerator = {
addSchema: function(opts) {
......@@ -272,6 +274,43 @@ module.exports = (function() {
},
/*
Quote an object based on its type. This is a more general version of quoteIdentifier
Strings: should proxy to quoteIdentifiers
Arrays: First argument should be qouted, second argument should be append without quoting
Objects:
If fn is set, the string should start with the value of fn, starting paren,
the values of cols (which is assumed to be an array), quoted and joined with ', ', unless they are themselves functions
If direction is set, should be prepended
Currently this function is only used for ordering / grouping columns, but it could
potentially also be used for other places where we want to be able to call SQL functions (e.g. as default values)
*/
quote: function(obj, force) {
if (Utils._.isString(obj)) {
return this.quoteIdentifiers(obj, force)
} else if (Array.isArray(obj)) {
return this.quote(obj[0], force) + ' ' + obj[1]
} else { // assumes object
var s = ''
if (obj.raw) {
s = obj.raw
} else if (obj.fn) {
s += obj.fn + '('
s += obj.cols.map(function (elem) {
return this.quote(elem, force)
}.bind(this)).join(', ') + ')'
}
if (obj.direction) {
s += ' ' + obj.direction
}
return s
}
},
/*
Escape an identifier (e.g. a table or attribute name)
*/
quoteIdentifier: function(identifier, force) {
......
......@@ -211,11 +211,12 @@ module.exports = (function() {
}
if (options.group) {
options.group = Array.isArray(options.group) ? options.group.map(function(t) { return this.quoteIdentifiers(t)}.bind(this)).join(', ') : qa(options.group)
options.group = Array.isArray(options.group) ? options.group.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.group
query += " GROUP BY " + options.group
}
if (options.order) {
options.order = Array.isArray(options.order) ? options.order.map(function (t) { return this.quote(t) }.bind(this)).join(', ') : options.order
query += " ORDER BY " + options.order
}
......
......@@ -163,20 +163,48 @@ if (dialect.match(/^mysql/)) {
expectation: "SELECT * FROM `myTable` ORDER BY id DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: ["id"]}],
expectation: "SELECT * FROM `myTable` ORDER BY `id`;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: ["myTable.id"]}],
expectation: "SELECT * FROM `myTable` ORDER BY `myTable`.`id`;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: [["id", 'DESC']]}],
expectation: "SELECT * FROM `myTable` ORDER BY `id` DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: [{raw: 'f1(f2(id))', direction: 'DESC'}]}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(id)) DESC;",
context: QueryGenerator
}, { // Function-ception!
arguments: ['myTable', {order: [{fn: 'f1', cols: [ { fn: 'f2', cols: ['id']}], direction: 'DESC'}]}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: [[{ fn: 'max', cols: ['id']}, 'DESC'], { fn: 'min', cols: ['first', 'second'], direction: 'ASC'}]}],
expectation: "SELECT * FROM `myTable` ORDER BY max(`id`) DESC, min(`first`, `second`) ASC;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM `myTable` GROUP BY `name`;",
expectation: "SELECT * FROM `myTable` GROUP BY name;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: ["name"]}],
expectation: "SELECT * FROM `myTable` GROUP BY `name`;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: [{ fn: 'max', cols: ['id']}]}],
expectation: "SELECT * FROM `myTable` GROUP BY max(`id`);",
context: QueryGenerator
}, {
arguments: ['myTable', {group: ["name", "title"]}],
expectation: "SELECT * FROM `myTable` GROUP BY `name`, `title`;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: "name", order: "id DESC"}],
expectation: "SELECT * FROM `myTable` GROUP BY `name` ORDER BY id DESC;",
expectation: "SELECT * FROM `myTable` GROUP BY name ORDER BY id DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {limit: 10}],
......
......@@ -246,14 +246,41 @@ if (dialect.match(/^postgres/)) {
expectation: "SELECT * FROM \"myTable\" WHERE foo='bar';"
}, {
arguments: ['myTable', {order: "id DESC"}],
expectation: "SELECT * FROM \"myTable\" ORDER BY \"id\" DESC;"
expectation: "SELECT * FROM \"myTable\" ORDER BY id DESC;"
}, {
arguments: ['myTable', {order: ["id"]}],
expectation: 'SELECT * FROM "myTable" ORDER BY "id";',
context: QueryGenerator
}, {
arguments: ['myTable', {order: ["myTable.id"]}],
expectation: 'SELECT * FROM "myTable" ORDER BY "myTable"."id";',
context: QueryGenerator
}, {
arguments: ['myTable', {order: [["id", 'DESC']]}],
expectation: 'SELECT * FROM "myTable" ORDER BY "id" DESC;',
context: QueryGenerator
}, {
arguments: ['myTable', {order: [{raw: 'f1(f2(id))', direction: 'DESC'}]}],
expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2(id)) DESC;',
context: QueryGenerator
}, { // Function-ception!
arguments: ['myTable', {order: [{fn: 'f1', cols: [ { fn: 'f2', cols: ['id']}], direction: 'DESC'}]}],
expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2("id")) DESC;',
context: QueryGenerator
}, {
arguments: ['myTable', {order: [[{ fn: 'max', cols: ['id']}, 'DESC'], { fn: 'min', cols: ['first', 'second'], direction: 'ASC'}]}],
expectation: 'SELECT * FROM "myTable" ORDER BY max("id") DESC, min("first", "second") ASC;',
context: QueryGenerator
}, {
arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\";"
expectation: "SELECT * FROM \"myTable\" GROUP BY name;"
}, {
arguments: ['myTable', {group: ["name"]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\";"
}, {
arguments: ['myTable', {group: [{ fn: 'max', cols: ['id']}]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY max(\"id\");"
},{
arguments: ['myTable', {group: ["name","title"]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\", \"title\";"
}, {
......
......@@ -104,6 +104,123 @@ if (dialect === 'sqlite') {
}
],
selectQuery: [
{
arguments: ['myTable'],
expectation: "SELECT * FROM `myTable`;",
context: QueryGenerator
}, {
arguments: ['myTable', {attributes: ['id', 'name']}],
expectation: "SELECT `id`, `name` FROM `myTable`;",
context: QueryGenerator
}, {
arguments: ['myTable', {where: {id: 2}}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`id`=2;",
context: QueryGenerator
}, {
arguments: ['myTable', {where: {name: 'foo'}}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`name`='foo';",
context: QueryGenerator
}, {
arguments: ['myTable', {where: {name: "foo';DROP TABLE myTable;"}}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`name`='foo\'\';DROP TABLE myTable;';",
context: QueryGenerator
}, {
arguments: ['myTable', {where: 2}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`id`=2;",
context: QueryGenerator
}, {
arguments: ['foo', { attributes: [['count(*)', 'count']] }],
expectation: 'SELECT count(*) as `count` FROM `foo`;',
context: QueryGenerator
}, {
arguments: ['myTable', {where: "foo='bar'"}],
expectation: "SELECT * FROM `myTable` WHERE foo='bar';",
context: QueryGenerator
}, {
arguments: ['myTable', {order: "id DESC"}],
expectation: "SELECT * FROM `myTable` ORDER BY id DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: ["id"]}],
expectation: "SELECT * FROM `myTable` ORDER BY `id`;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: ["myTable.id"]}],
expectation: "SELECT * FROM `myTable` ORDER BY `myTable`.`id`;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: [["id", 'DESC']]}],
expectation: "SELECT * FROM `myTable` ORDER BY `id` DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: [{raw: 'f1(f2(id))', direction: 'DESC'}]}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(id)) DESC;",
context: QueryGenerator
}, { // Function-ception!
arguments: ['myTable', {order: [{fn: 'f1', cols: [ { fn: 'f2', cols: ['id']}], direction: 'DESC'}]}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {order: [[{ fn: 'max', cols: ['id']}, 'DESC'], { fn: 'min', cols: ['first', 'second'], direction: 'ASC'}]}],
expectation: "SELECT * FROM `myTable` ORDER BY max(`id`) DESC, min(`first`, `second`) ASC;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM `myTable` GROUP BY name;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: ["name"]}],
expectation: "SELECT * FROM `myTable` GROUP BY `name`;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: [{ fn: 'max', cols: ['id']}]}],
expectation: "SELECT * FROM `myTable` GROUP BY max(`id`);",
context: QueryGenerator
}, {
arguments: ['myTable', {group: ["name", "title"]}],
expectation: "SELECT * FROM `myTable` GROUP BY `name`, `title`;",
context: QueryGenerator
}, {
arguments: ['myTable', {group: "name", order: "id DESC"}],
expectation: "SELECT * FROM `myTable` GROUP BY name ORDER BY id DESC;",
context: QueryGenerator
}, {
arguments: ['myTable', {limit: 10}],
expectation: "SELECT * FROM `myTable` LIMIT 10;",
context: QueryGenerator
}, {
arguments: ['myTable', {limit: 10, offset: 2}],
expectation: "SELECT * FROM `myTable` LIMIT 2, 10;",
context: QueryGenerator
}, {
title: 'uses default limit if only offset is specified',
arguments: ['myTable', {offset: 2}],
expectation: "SELECT * FROM `myTable` LIMIT 2, 10000000000000;",
context: QueryGenerator
}, {
title: 'multiple where arguments',
arguments: ['myTable', {where: {boat: 'canoe', weather: 'cold'}}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`boat`='canoe' AND `myTable`.`weather`='cold';",
context: QueryGenerator
}, {
title: 'no where arguments (object)',
arguments: ['myTable', {where: {}}],
expectation: "SELECT * FROM `myTable` WHERE 1=1;",
context: QueryGenerator
}, {
title: 'no where arguments (string)',
arguments: ['myTable', {where: ''}],
expectation: "SELECT * FROM `myTable` WHERE 1=1;",
context: QueryGenerator
}, {
title: 'no where arguments (null)',
arguments: ['myTable', {where: null}],
expectation: "SELECT * FROM `myTable` WHERE 1=1;",
context: QueryGenerator
}
],
insertQuery: [
{
arguments: ['myTable', { name: 'foo' }],
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!