Brian C
12 years ago
11 changed files with 202 additions and 15 deletions
@ -0,0 +1,57 @@ |
|||
'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' |
|||
]; |
|||
|
|||
// common scalar functions available to most databases
|
|||
var scalarFunctions = [ |
|||
'ABS', |
|||
'COALESC', |
|||
'LENGTH', |
|||
'LOWER', |
|||
'LTRIM', |
|||
'RANDOM', |
|||
'ROUND', |
|||
'RTRIM', |
|||
'SUBSTR', |
|||
'TRIM', |
|||
'UPPER' |
|||
]; |
|||
|
|||
var standardFunctionNames = aggregateFunctions.concat(scalarFunctions); |
|||
|
|||
// creates a hash of standard functions for a sql instance
|
|||
var getStandardFunctions = function(sql) { |
|||
return getFunctions(standardFunctionNames, sql); |
|||
}; |
|||
|
|||
module.exports.getStandardFunctions = getStandardFunctions; |
@ -0,0 +1,22 @@ |
|||
'use strict'; |
|||
|
|||
var _ = require('lodash'); |
|||
var Node = require(__dirname); |
|||
var ParameterNode = require(__dirname + '/parameter'); |
|||
var valueExpressionMixin = require(__dirname + '/valueExpression'); |
|||
|
|||
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); |
|||
})); |
|||
} |
|||
}); |
|||
|
|||
// mix in value expression
|
|||
_.extend(FunctionCallNode.prototype, valueExpressionMixin()); |
|||
|
|||
module.exports = FunctionCallNode; |
@ -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); |
|||
}); |
|||
}); |
@ -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); |
|||
} |
|||
}); |
|||
}); |
Loading…
Reference in new issue