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

Commit c075cacb by Jan Aagaard Meier

Change ordering to use fn and col

1 parent 667cae4f
...@@ -292,23 +292,12 @@ module.exports = (function() { ...@@ -292,23 +292,12 @@ module.exports = (function() {
return this.quoteIdentifiers(obj, force) return this.quoteIdentifiers(obj, force)
} else if (Array.isArray(obj)) { } else if (Array.isArray(obj)) {
return this.quote(obj[0], force) + ' ' + obj[1] return this.quote(obj[0], force) + ' ' + obj[1]
} else { // assumes object } else if (obj instanceof Utils.fn || obj instanceof Utils.col) {
var s = '' return obj.toString(this)
if (obj.raw) { } else if (Utils._.isObject(obj) && 'raw' in obj) {
s = obj.raw return obj.raw
} else if (obj.fn) { } else {
s += obj.fn + '(' throw new Error('Unknown structure passed to order / group: ' + JSON.stringify(ojb))
s += obj.cols.map(function (elem) {
return this.quote(elem, force)
}.bind(this)).join(', ') + ')'
}
if (obj.direction) {
s += ' ' + obj.direction
}
return s
} }
}, },
......
...@@ -318,5 +318,13 @@ module.exports = (function() { ...@@ -318,5 +318,13 @@ module.exports = (function() {
}).run() }).run()
} }
Sequelize.prototype.fn = function (fn) {
return new Utils.fn(fn, Array.prototype.slice.call(arguments, 1))
}
Sequelize.prototype.col = function (col) {
return new Utils.col(col)
}
return Sequelize return Sequelize
})() })()
...@@ -468,9 +468,33 @@ var Utils = module.exports = { ...@@ -468,9 +468,33 @@ var Utils = module.exports = {
removeTicks: function(s, tickChar) { removeTicks: function(s, tickChar) {
tickChar = tickChar || Utils.TICK_CHAR tickChar = tickChar || Utils.TICK_CHAR
return s.replace(new RegExp(tickChar, 'g'), "") return s.replace(new RegExp(tickChar, 'g'), "")
},
/*
* Utility functions for representing SQL functions, and columns that should be escaped.
* Please do not use these functions directly, use Sequelize.fn and Sequelize.col instead.
*/
fn: function (fn, args) {
this.fn = fn
this.args = args
},
col: function (col) {
this.col = col
} }
} }
Utils.fn.prototype.toString = function(queryGenerator) {
return this.fn + '(' + this.args.map(function (arg) {
if (arg instanceof Utils.fn || arg instanceof Utils.col) {
return arg.toString(queryGenerator)
} else {
return queryGenerator.escape(arg)
}
}).join(', ') + ')'
}
Utils.col.prototype.toString = function (queryGenerator) {
return queryGenerator.quote(this.col)
}
Utils.CustomEventEmitter = require(__dirname + "/emitters/custom-event-emitter") Utils.CustomEventEmitter = require(__dirname + "/emitters/custom-event-emitter")
Utils.QueryChainer = require(__dirname + "/query-chainer") Utils.QueryChainer = require(__dirname + "/query-chainer")
Utils.Lingo = require("lingo") Utils.Lingo = require("lingo")
\ No newline at end of file
...@@ -175,33 +175,62 @@ if (dialect.match(/^mysql/)) { ...@@ -175,33 +175,62 @@ if (dialect.match(/^mysql/)) {
expectation: "SELECT * FROM `myTable` ORDER BY `id` DESC;", expectation: "SELECT * FROM `myTable` ORDER BY `id` DESC;",
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {order: [{raw: 'f1(f2(id))', direction: 'DESC'}]}], title: 'raw arguments are neither quoted nor escaped',
arguments: ['myTable', {order: [[{raw: 'f1(f2(id))'}, 'DESC']]}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(id)) DESC;", expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(id)) DESC;",
context: QueryGenerator 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'}]}], title: 'functions can take functions as arguments',
expectation: "SELECT * FROM `myTable` ORDER BY max(`id`) DESC, min(`first`, `second`) ASC;", arguments: ['myTable', function (sequelize) {
context: QueryGenerator return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
}
}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator,
needsSequelize: true
}, {
title: 'functions can take all types as arguments',
arguments: ['myTable', function (sequelize) {
return {
order: [
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC']
]
}
}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(`myTable`.`id`) DESC, f2(12, 'lalala', '2011-03-27 10:01:55') ASC;",
context: QueryGenerator,
needsSequelize: true
}, { }, {
title: 'single string argument is not quoted',
arguments: ['myTable', {group: "name"}], arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM `myTable` GROUP BY name;", expectation: "SELECT * FROM `myTable` GROUP BY name;",
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {group: ["name"]}], arguments: ['myTable', { group: ["name"] }],
expectation: "SELECT * FROM `myTable` GROUP BY `name`;", expectation: "SELECT * FROM `myTable` GROUP BY `name`;",
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {group: [{ fn: 'max', cols: ['id']}]}], title: 'functions work for group by',
expectation: "SELECT * FROM `myTable` GROUP BY max(`id`);", arguments: ['myTable', function (sequelize) {
context: QueryGenerator return {
}, { group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
arguments: ['myTable', {group: ["name", "title"]}], }
expectation: "SELECT * FROM `myTable` GROUP BY `name`, `title`;", }],
context: QueryGenerator expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);",
context: QueryGenerator,
needsSequelize: true
}, {
title: 'It is possible to mix sequelize.fn and string arguments to group by',
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
}
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;",
context: QueryGenerator,
needsSequelize: true
}, { }, {
arguments: ['myTable', {group: "name", order: "id DESC"}], 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;",
...@@ -454,6 +483,9 @@ if (dialect.match(/^mysql/)) { ...@@ -454,6 +483,9 @@ if (dialect.match(/^mysql/)) {
it(title, function(done) { it(title, function(done) {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
var context = test.context || {options: {}}; var context = test.context || {options: {}};
if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize)
}
QueryGenerator.options = context.options QueryGenerator.options = context.options
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments) var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation) expect(conditions).to.deep.equal(test.expectation)
......
...@@ -260,27 +260,60 @@ if (dialect.match(/^postgres/)) { ...@@ -260,27 +260,60 @@ if (dialect.match(/^postgres/)) {
expectation: 'SELECT * FROM "myTable" ORDER BY "id" DESC;', expectation: 'SELECT * FROM "myTable" ORDER BY "id" DESC;',
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {order: [{raw: 'f1(f2(id))', direction: 'DESC'}]}], title: 'raw arguments are neither quoted nor escaped',
arguments: ['myTable', {order: [[{raw: 'f1(f2(id))'},'DESC']]}],
expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2(id)) DESC;', expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2(id)) DESC;',
context: QueryGenerator 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'}]}], title: 'functions can take functions as arguments',
expectation: 'SELECT * FROM "myTable" ORDER BY max("id") DESC, min("first", "second") ASC;', arguments: ['myTable', function (sequelize) {
context: QueryGenerator return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
}
}],
expectation: 'SELECT * FROM "myTable" ORDER BY f1(f2("id")) DESC;',
context: QueryGenerator,
needsSequelize: true
}, {
title: 'functions can take all types as arguments',
arguments: ['myTable', function (sequelize) {
return {
order: [
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC']
]
}
}],
expectation: 'SELECT * FROM "myTable" ORDER BY f1("myTable"."id") DESC, f2(12, \'lalala\', \'2011-03-27 10:01:55.000 +00:00\') ASC;',
context: QueryGenerator,
needsSequelize: true
}, { }, {
title: 'single string argument is not quoted',
arguments: ['myTable', {group: "name"}], arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM \"myTable\" GROUP BY name;" expectation: "SELECT * FROM \"myTable\" GROUP BY name;"
}, { }, {
arguments: ['myTable', {group: ["name"]}], arguments: ['myTable', {group: ["name"]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\";" expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\";"
}, { }, {
arguments: ['myTable', {group: [{ fn: 'max', cols: ['id']}]}], title: 'functions work for group by',
expectation: "SELECT * FROM \"myTable\" GROUP BY max(\"id\");" arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
}
}],
expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\");",
needsSequelize: true
},{ },{
title: 'It is possible to mix sequelize.fn and string arguments to group by',
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
}
}],
expectation: "SELECT * FROM \"myTable\" GROUP BY YEAR(\"createdAt\"), \"title\";",
context: QueryGenerator,
needsSequelize: true
}, {
arguments: ['myTable', {group: ["name","title"]}], arguments: ['myTable', {group: ["name","title"]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\", \"title\";" expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\", \"title\";"
}, { }, {
...@@ -819,6 +852,9 @@ if (dialect.match(/^postgres/)) { ...@@ -819,6 +852,9 @@ if (dialect.match(/^postgres/)) {
it(title, function(done) { it(title, function(done) {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
var context = test.context || {options: {}}; var context = test.context || {options: {}};
if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize)
}
QueryGenerator.options = context.options QueryGenerator.options = context.options
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments) var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation) expect(conditions).to.deep.equal(test.expectation)
......
...@@ -154,18 +154,35 @@ if (dialect === 'sqlite') { ...@@ -154,18 +154,35 @@ if (dialect === 'sqlite') {
expectation: "SELECT * FROM `myTable` ORDER BY `id` DESC;", expectation: "SELECT * FROM `myTable` ORDER BY `id` DESC;",
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {order: [{raw: 'f1(f2(id))', direction: 'DESC'}]}], title: 'raw arguments are neither quoted nor escaped',
arguments: ['myTable', {order: [[{raw: 'f1(f2(id))'}, 'DESC']]}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(id)) DESC;", expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(id)) DESC;",
context: QueryGenerator 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'}]}], title: 'functions can take functions as arguments',
expectation: "SELECT * FROM `myTable` ORDER BY max(`id`) DESC, min(`first`, `second`) ASC;", arguments: ['myTable', function (sequelize) {
context: QueryGenerator return {
order: [[sequelize.fn('f1', sequelize.fn('f2', sequelize.col('id'))), 'DESC']]
}
}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(f2(`id`)) DESC;",
context: QueryGenerator,
needsSequelize: true
}, {
title: 'functions can take all types as arguments',
arguments: ['myTable', function (sequelize) {
return {
order: [
[sequelize.fn('f1', sequelize.col('myTable.id')), 'DESC'],
[sequelize.fn('f2', 12, 'lalala', new Date(Date.UTC(2011, 2, 27, 10, 1, 55))), 'ASC']
]
}
}],
expectation: "SELECT * FROM `myTable` ORDER BY f1(`myTable`.`id`) DESC, f2(12, 'lalala', '2011-03-27 10:01:55') ASC;",
context: QueryGenerator,
needsSequelize: true
}, { }, {
title: 'single string argument is not quoted',
arguments: ['myTable', {group: "name"}], arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM `myTable` GROUP BY name;", expectation: "SELECT * FROM `myTable` GROUP BY name;",
context: QueryGenerator context: QueryGenerator
...@@ -174,9 +191,25 @@ if (dialect === 'sqlite') { ...@@ -174,9 +191,25 @@ if (dialect === 'sqlite') {
expectation: "SELECT * FROM `myTable` GROUP BY `name`;", expectation: "SELECT * FROM `myTable` GROUP BY `name`;",
context: QueryGenerator context: QueryGenerator
}, { }, {
arguments: ['myTable', {group: [{ fn: 'max', cols: ['id']}]}], title: 'functions work for group by',
expectation: "SELECT * FROM `myTable` GROUP BY max(`id`);", arguments: ['myTable', function (sequelize) {
context: QueryGenerator return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt'))]
}
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`);",
context: QueryGenerator,
needsSequelize: true
}, {
title: 'It is possible to mix sequelize.fn and string arguments to group by',
arguments: ['myTable', function (sequelize) {
return {
group: [sequelize.fn('YEAR', sequelize.col('createdAt')), 'title']
}
}],
expectation: "SELECT * FROM `myTable` GROUP BY YEAR(`createdAt`), `title`;",
context: QueryGenerator,
needsSequelize: true
}, { }, {
arguments: ['myTable', {group: ["name", "title"]}], arguments: ['myTable', {group: ["name", "title"]}],
expectation: "SELECT * FROM `myTable` GROUP BY `name`, `title`;", expectation: "SELECT * FROM `myTable` GROUP BY `name`, `title`;",
...@@ -374,6 +407,9 @@ if (dialect === 'sqlite') { ...@@ -374,6 +407,9 @@ if (dialect === 'sqlite') {
it(title, function(done) { it(title, function(done) {
// Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly // Options would normally be set by the query interface that instantiates the query-generator, but here we specify it explicitly
var context = test.context || {options: {}}; var context = test.context || {options: {}};
if (test.needsSequelize) {
test.arguments[1] = test.arguments[1](this.sequelize)
}
QueryGenerator.options = context.options QueryGenerator.options = context.options
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments) var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation) expect(conditions).to.deep.equal(test.expectation)
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!