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

Commit 72291654 by Shawn Woodtke Committed by sdepold

Add more tests for the postgres dialect. Fix issues found while testing.

1 parent c05b57d8
...@@ -59,8 +59,11 @@ module.exports = (function() { ...@@ -59,8 +59,11 @@ module.exports = (function() {
this.client.connect(function(err, client) { this.client.connect(function(err, client) {
self.isConnecting = false self.isConnecting = false
if (!err && client) { if (!err && client) {
self.isConnected = true client.query("SET TIME ZONE 'UTC'")
this.client = client .on('end', function() {
self.isConnected = true
this.client = client
});
} else { } else {
this.client = null this.client = null
} }
......
...@@ -2,6 +2,17 @@ var Utils = require("../../utils") ...@@ -2,6 +2,17 @@ var Utils = require("../../utils")
, util = require("util") , util = require("util")
tables = {} tables = {}
primaryKeys = {}
function removeQuotes(s, quoteChar) {
quoteChar = quoteChar || '"'
return s.replace(new RegExp(quoteChar, 'g'), '')
}
function addQuotes(s, quoteChar) {
quoteChar = quoteChar || '"'
return quoteChar + removeQuotes(s) + quoteChar
}
function pgEscape(s) { function pgEscape(s) {
s = Utils.escape(s) s = Utils.escape(s)
...@@ -9,66 +20,72 @@ function pgEscape(s) { ...@@ -9,66 +20,72 @@ function pgEscape(s) {
return s return s
} }
function padInt(i) {
return (i < 10) ? '0' + i.toString() : i.toString()
}
function pgSqlDate(dt) {
var date = [ dt.getUTCFullYear(), padInt(dt.getUTCMonth()+1), padInt(dt.getUTCDate()) ].join('-')
var time = [ dt.getUTCHours(), padInt(dt.getUTCMinutes()), padInt(dt.getUTCSeconds())].join(':')
return date + ' ' + time + '.' + ((dt.getTime() % 1000) * 1000)
}
function pgDataTypeMapping(tableName, attr, dataType) {
if (Utils._.includes(dataType, 'PRIMARY KEY')) {
primaryKeys[tableName].push(attr)
dataType = dataType.replace(/PRIMARY KEY/, '')
}
if (Utils._.includes(dataType, 'TINYINT(1)')) {
dataType = dataType.replace(/TINYINT\(1\)/, 'BOOLEAN')
}
if (Utils._.includes(dataType, 'DATETIME')) {
dataType = dataType.replace(/DATETIME/, 'TIMESTAMP')
}
if (Utils._.includes(dataType, 'SERIAL')) {
dataType = dataType.replace(/INTEGER/, '')
dataType = dataType.replace(/NOT NULL/, '')
tables[tableName][attr] = 'serial'
}
return dataType
}
module.exports = (function() { module.exports = (function() {
var QueryGenerator = { var QueryGenerator = {
createTableQuery: function(tableName, attributes, options) { createTableQuery: function(tableName, attributes, options) {
options = Utils._.extend({ options = Utils._.extend({
}, options || {}) }, options || {})
primaryKeys[tableName] = []
tables[tableName] = {} tables[tableName] = {}
var query = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>)" var query = "CREATE TABLE IF NOT EXISTS <%= table %> (<%= attributes%>)"
, primaryKeys = []
, attrStr = Utils._.map(attributes, function(dataType, attr) { , attrStr = Utils._.map(attributes, function(dataType, attr) {
if (Utils._.includes(dataType, 'PRIMARY KEY')) { dataType = pgDataTypeMapping(tableName, attr, dataType)
primaryKeys.push(attr) return addQuotes(attr) + " " + dataType
dataType = dataType.replace(/PRIMARY KEY/, '')
}
if (Utils._.includes(dataType, 'DATETIME')) {
dataType = dataType.replace(/DATETIME/, 'TIMESTAMP')
}
if (Utils._.includes(dataType, 'TINYINT(1)')) {
dataType = dataType.replace(/TINYINT\(1\)/, 'BOOLEAN')
}
if (Utils._.includes(dataType, 'DATETIME')) {
dataType = dataType.replace(/DATETIME/, 'TIMESTAMP')
}
if (Utils._.includes(dataType, 'SERIAL')) {
dataType = dataType.replace(/INTEGER/, '')
dataType = dataType.replace(/NOT NULL/, '')
tables[tableName][attr] = 'serial'
}
return attr + " " + dataType
}).join(", ") }).join(", ")
, values = { , values = {
table: tableName, table: addQuotes(tableName),
attributes: attrStr, attributes: attrStr,
engine: options.engine,
charset: (options.charset ? "DEFAULT CHARSET=" + options.charset : "")
} }
, pkString = primaryKeys.map(function(pk) {return pk}).join(", ")
if(pkString.length > 0) values.attributes += ", PRIMARY KEY (" + pkString + ")" var pks = primaryKeys[tableName].map(function(pk){return addQuotes(pk)}).join(",")
if (pks.length > 0) values.attributes += ", PRIMARY KEY (" + pks + ")"
return Utils._.template(query)(values).trim() + ";" return Utils._.template(query)(values).trim() + ";"
}, },
dropTableQuery: function(tableName, options) { dropTableQuery: function(tableName, options) {
options = options || {} options = options || {}
var query = "DROP TABLE IF EXISTS <%= table %>;" var query = "DROP TABLE IF EXISTS <%= table %>;"
return Utils._.template(query)({table: addQuotes(tableName)})
return Utils._.template(query)({table: tableName})
}, },
renameTableQuery: function(before, after) { renameTableQuery: function(before, after) {
var query = "ALTER TABLE <%= before %> RENAME TO <%= after %>;" var query = "ALTER TABLE <%= before %> RENAME TO <%= after %>;"
return Utils._.template(query)({ before: before, after: after }) return Utils._.template(query)({ before: addQuotes(before), after: addQuotes(after) })
}, },
showTablesQuery: function() { showTablesQuery: function() {
...@@ -79,51 +96,54 @@ module.exports = (function() { ...@@ -79,51 +96,54 @@ module.exports = (function() {
var query = "ALTER TABLE <%= tableName %> ADD COLUMN <%= attributes %>;" var query = "ALTER TABLE <%= tableName %> ADD COLUMN <%= attributes %>;"
, attrString = Utils._.map(attributes, function(definition, attributeName) { , attrString = Utils._.map(attributes, function(definition, attributeName) {
return Utils._.template('<%= attributeName %> <%= definition %>')({ return Utils._.template('<%= attributeName %> <%= definition %>')({
attributeName: attributeName, attributeName: addQuotes(attributeName),
definition: definition definition: pgDataTypeMapping(tableName, attributeName, definition)
}) })
}).join(', ') }).join(', ')
return Utils._.template(query)({ tableName: tableName, attributes: attrString }) return Utils._.template(query)({ tableName: addQuotes(tableName), attributes: attrString })
}, },
removeColumnQuery: function(tableName, attributeName) { removeColumnQuery: function(tableName, attributeName) {
var query = "ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;" var query = "ALTER TABLE <%= tableName %> DROP COLUMN <%= attributeName %>;"
return Utils._.template(query)({ tableName: tableName, attributeName: attributeName }) return Utils._.template(query)({ tableName: addQuotes(tableName), attributeName: addQuotes(attributeName) })
}, },
changeColumnQuery: function(tableName, attributes) { changeColumnQuery: function(tableName, attributes) {
var query = "ALTER TABLE <%= tableName %> ALTER COLUMN <%= attributes %>;" var query = "ALTER TABLE <%= tableName %> ALTER COLUMN <%= attributes %>;"
var attrString = Utils._.map(attributes, function(definition, attributeName) { var attrString = Utils._.map(attributes, function(definition, attributeName) {
return Utils._.template('<%= attributeName %> <%= attributeName %> <%= definition %>')({ return Utils._.template('<%= attributeName %> <%= attributeName %> <%= definition %>')({
attributeName: attributeName, attributeName: addQuotes(attributeName),
definition: definition definition: pgDataTypeMapping(tableName, attributeName, definition)
}) })
}).join(', ') }).join(', ')
return Utils._.template(query)({ tableName: tableName, attributes: attrString }) return Utils._.template(query)({ tableName: addQuotes(tableName), attributes: attrString })
}, },
renameColumnQuery: function(tableName, attrBefore, attributes) { renameColumnQuery: function(tableName, attrBefore, attributes) {
var query = "ALTER TABLE <%= tableName %> RENAME COLUMN <%= attributes %>;" var query = "ALTER TABLE <%= tableName %> RENAME COLUMN <%= attributes %>;"
var attrString = Utils._.map(attributes, function(definition, attributeName) { var attrString = Utils._.map(attributes, function(definition, attributeName) {
return Utils._.template('<%= before %> TO <%= after %>')({ return Utils._.template('<%= before %> TO <%= after %>')({
before: attrBefore, before: addQuotes(attrBefore),
after: attributeName, after: addQuotes(attributeName),
}) })
}).join(', ') }).join(', ')
return Utils._.template(query)({ tableName: tableName, attributes: attrString }) return Utils._.template(query)({ tableName: addQuotes(tableName), attributes: attrString })
}, },
selectQuery: function(tableName, options) { selectQuery: function(tableName, options) {
options = options || {} options = options || {}
options.table = Array.isArray(tableName) ? tableName.map(function(tbl){return tbl}).join(", ") : tableName options.table = Array.isArray(tableName) ? tableName.map(function(t){return addQuotes(t);}).join(", ") : addQuotes(tableName)
options.attributes = options.attributes && options.attributes.map(function(attr){ options.attributes = options.attributes && options.attributes.map(function(attr){
if(Array.isArray(attr) && attr.length == 2) if(Array.isArray(attr) && attr.length == 2) {
return [attr[0], attr[1]].join(' as ') return [attr[0], addQuotes(removeQuotes(attr[1], '`'))].join(' as ')
else } else if (attr.indexOf('`') >= 0) {
return attr.indexOf(Utils.TICK_CHAR)<0 ? attr : attr return attr.replace(/`/g, '"')
} else {
return addQuotes(attr)
}
}).join(", ") }).join(", ")
options.attributes = options.attributes || '*' options.attributes = options.attributes || '*'
...@@ -134,9 +154,12 @@ module.exports = (function() { ...@@ -134,9 +154,12 @@ module.exports = (function() {
options.where = QueryGenerator.getWhereConditions(options.where) options.where = QueryGenerator.getWhereConditions(options.where)
query += " WHERE <%= where %>" query += " WHERE <%= where %>"
} }
if(options.order) query += " ORDER BY <%= order %>" if(options.order) {
options.order = options.order.replace(/([^ ]+)(.*)/, function(m, g1, g2) { return addQuotes(g1)+g2 })
query += " ORDER BY <%= order %>"
}
if(options.group) { if(options.group) {
options.group = options.group options.group = addQuotes(options.group)
query += " GROUP BY <%= group %>" query += " GROUP BY <%= group %>"
} }
if(options.limit) query += " LIMIT <%= limit %>" if(options.limit) query += " LIMIT <%= limit %>"
...@@ -162,10 +185,10 @@ module.exports = (function() { ...@@ -162,10 +185,10 @@ module.exports = (function() {
}); });
var replacements = { var replacements = {
table: tableName, table: addQuotes(tableName),
attributes: Utils._.keys(attrValueHash).map(function(attr){return attr}).join(","), attributes: Utils._.keys(attrValueHash).map(function(attr){return addQuotes(attr)}).join(","),
values: Utils._.values(attrValueHash).map(function(value){ values: Utils._.values(attrValueHash).map(function(value){
return pgEscape((value instanceof Date) ? Utils.toSqlDate(value) : value) return pgEscape((value instanceof Date) ? pgSqlDate(value) : value)
}).join(",") }).join(",")
} }
...@@ -175,9 +198,9 @@ module.exports = (function() { ...@@ -175,9 +198,9 @@ module.exports = (function() {
updateQuery: function(tableName, values, where) { updateQuery: function(tableName, values, where) {
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>" var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
var replacements = { var replacements = {
table: tableName, table: addQuotes(tableName),
values: Utils._.map(values, function(value, key){ values: Utils._.map(values, function(value, key){
return key + "=" + pgEscape((value instanceof Date) ? Utils.toSqlDate(value) : value) return addQuotes(key) + "=" + pgEscape((value instanceof Date) ? pgSqlDate(value) : value)
}).join(","), }).join(","),
where: QueryGenerator.getWhereConditions(where) where: QueryGenerator.getWhereConditions(where)
} }
...@@ -189,11 +212,21 @@ module.exports = (function() { ...@@ -189,11 +212,21 @@ module.exports = (function() {
options = options || {} options = options || {}
options.limit = options.limit || 1 options.limit = options.limit || 1
var query = "DELETE FROM <%= table %> WHERE <%= where %>" var query = "DELETE FROM <%= table %> WHERE <%= primaryKeys %> IN (SELECT <%= primaryKeysSelection %> FROM <%= table %> WHERE <%= where %> LIMIT <%= limit %>)"
var pks;
if (primaryKeys[tableName] && primaryKeys[tableName].length > 0) {
pks = primaryKeys[tableName].map(function(pk) { return addQuotes(pk) }).join(',')
} else {
pks = addQuotes('id')
}
var replacements = { var replacements = {
table: tableName, table: addQuotes(tableName),
where: QueryGenerator.getWhereConditions(where), where: QueryGenerator.getWhereConditions(where),
limit: pgEscape(options.limit) limit: pgEscape(options.limit),
primaryKeys: primaryKeys[tableName].length > 1 ? '(' + pks + ')' : pks,
primaryKeysSelection: pks
} }
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
...@@ -202,14 +235,14 @@ module.exports = (function() { ...@@ -202,14 +235,14 @@ module.exports = (function() {
addIndexQuery: function(tableName, attributes, options) { addIndexQuery: function(tableName, attributes, options) {
var transformedAttributes = attributes.map(function(attribute) { var transformedAttributes = attributes.map(function(attribute) {
if(typeof attribute == 'string') if(typeof attribute == 'string')
return attribute return addQuotes(attribute)
else { else {
var result = "" var result = ""
if(!attribute.attribute) if(!attribute.attribute)
throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute)) throw new Error('The following index attribute has no attribute: ' + util.inspect(attribute))
result += attribute.attribute result += addQuotes(attribute.attribute)
if(attribute.length) if(attribute.length)
result += '(' + attribute.length + ')' result += '(' + attribute.length + ')'
...@@ -232,29 +265,24 @@ module.exports = (function() { ...@@ -232,29 +265,24 @@ module.exports = (function() {
}, options || {}) }, options || {})
return Utils._.compact([ return Utils._.compact([
"CREATE", options.indicesType, "INDEX", options.indexName, "CREATE", options.indicesType, "INDEX", addQuotes(options.indexName),
(options.indexType ? ('USING ' + options.indexType) : undefined), (options.indexType ? ('USING ' + options.indexType) : undefined),
"ON", tableName, '(' + transformedAttributes.join(', ') + ')', "ON", addQuotes(tableName), '(' + transformedAttributes.join(', ') + ')'
(options.parser ? "WITH PARSER " + options.parser : undefined)
]).join(' ') ]).join(' ')
}, },
showIndexQuery: function(tableName, options) { showIndexQuery: function(tableName, options) {
var sql = "SHOW INDEX FROM <%= tableName %><%= options %>" throw new Error('showIndexQuery is not implemented for PostgreSQL')
return Utils._.template(sql)({
tableName: tableName,
options: (options || {}).database ? ' FROM ' + options.database : ''
})
}, },
removeIndexQuery: function(tableName, indexNameOrAttributes) { removeIndexQuery: function(tableName, indexNameOrAttributes) {
var sql = "DROP INDEX <%= indexName %> ON <%= tableName %>" var sql = "DROP INDEX IF EXISTS <%= indexName %>"
, indexName = indexNameOrAttributes , indexName = indexNameOrAttributes
if(typeof indexName != 'string') if(typeof indexName != 'string')
indexName = Utils._.underscored(tableName + '_' + indexNameOrAttributes.join('_')) indexName = Utils._.underscored(tableName + '_' + indexNameOrAttributes.join('_'))
return Utils._.template(sql)({ tableName: tableName, indexName: indexName }) return Utils._.template(sql)({ tableName: addQuotes(tableName), indexName: addQuotes(indexName) })
}, },
getWhereConditions: function(smth) { getWhereConditions: function(smth) {
...@@ -263,7 +291,7 @@ module.exports = (function() { ...@@ -263,7 +291,7 @@ module.exports = (function() {
if(Utils.isHash(smth)) if(Utils.isHash(smth))
result = QueryGenerator.hashToWhereConditions(smth) result = QueryGenerator.hashToWhereConditions(smth)
else if(typeof smth == 'number') else if(typeof smth == 'number')
result = 'id' + "=" + pgEscape(smth) result = '\"id\"' + "=" + pgEscape(smth)
else if(typeof smth == "string") else if(typeof smth == "string")
result = smth result = smth
else if(Array.isArray(smth)) else if(Array.isArray(smth))
...@@ -275,7 +303,7 @@ module.exports = (function() { ...@@ -275,7 +303,7 @@ module.exports = (function() {
hashToWhereConditions: function(hash) { hashToWhereConditions: function(hash) {
return Utils._.map(hash, function(value, key) { return Utils._.map(hash, function(value, key) {
//handle qualified key names //handle qualified key names
var _key = key.split('.').map(function(col){return col}).join(".") var _key = key.split('.').map(function(col){return addQuotes(col)}).join(".")
, _value = null , _value = null
if(Array.isArray(value)) { if(Array.isArray(value)) {
...@@ -287,7 +315,7 @@ module.exports = (function() { ...@@ -287,7 +315,7 @@ module.exports = (function() {
} }
else if ((value) && (typeof value == 'object')) { else if ((value) && (typeof value == 'object')) {
//using as sentinel for join column => value //using as sentinel for join column => value
_value = value.join.split('.').map(function(col){return col}).join(".") _value = value.join.split('.').map(function(col){return addQuotes(col)}).join(".")
return [_key, _value].join("=") return [_key, _value].join("=")
} else { } else {
_value = pgEscape(value) _value = pgEscape(value)
...@@ -300,7 +328,6 @@ module.exports = (function() { ...@@ -300,7 +328,6 @@ module.exports = (function() {
var result = {} var result = {}
Utils._.map(attributes, function(dataType, name) { Utils._.map(attributes, function(dataType, name) {
//console.log(name, 'dataType:', dataType)
if(Utils.isHash(dataType)) { if(Utils.isHash(dataType)) {
var template = "<%= type %>" var template = "<%= type %>"
, replacements = { type: dataType.type } , replacements = { type: dataType.type }
......
...@@ -24,7 +24,7 @@ module.exports = (function() { ...@@ -24,7 +24,7 @@ module.exports = (function() {
var query = this.client.query(sql) var query = this.client.query(sql)
query.on('row', function(row) { query.on('row', function(row) {
if (self.callee && self.sql.indexOf('INSERT INTO') == 0) { if (self.callee && (self.sql.indexOf('INSERT INTO') == 0 || self.sql.indexOf('UPDATE') == 0)) {
Utils._.forEach(row, function(value, key) { Utils._.forEach(row, function(value, key) {
self.callee[key] = value self.callee[key] = value
}) })
......
...@@ -364,9 +364,7 @@ describe('DAO', function() { ...@@ -364,9 +364,7 @@ describe('DAO', function() {
setTimeout(function() { setTimeout(function() {
user = User.build({ username: 'user' }) user = User.build({ username: 'user' })
updatedAt = user.updatedAt updatedAt = user.updatedAt
expect(updatedAt.getTime()).toBeGreaterThan(now) expect(updatedAt.getTime()).toBeGreaterThan(now)
done() done()
}, 10) }, 10)
}) })
...@@ -477,7 +475,7 @@ describe('DAO', function() { ...@@ -477,7 +475,7 @@ describe('DAO', function() {
}).success(function(user) { }).success(function(user) {
var emitter = user.updateAttributes({name: 'foobar'}) var emitter = user.updateAttributes({name: 'foobar'})
emitter.success(function() { emitter.success(function() {
expect(emitter.query.sql).toMatch(/WHERE `?identifier`?..identifier./) expect(emitter.query.sql).toMatch(/WHERE [`"]identifier[`"]..identifier./)
done() done()
}) })
}) })
......
var config = require("../config/config")
, Sequelize = require("../../index")
, sequelize = new Sequelize(config.postgres.database, config.postgres.username, config.postgres.password, {
logging: false,
port: config.postgres.port,
dialect: 'postgres'
})
, Helpers = new (require("../config/helpers"))(sequelize)
describe('HasMany', function() {
beforeEach(function() { Helpers.sync() })
afterEach(function() { Helpers.drop() })
//prevent periods from occurring in the table name since they are used to delimit (table.column)
var User = sequelize.define('User' + Math.ceil(Math.random()*10000000), { name: Sequelize.STRING })
, Task = sequelize.define('Task' + Math.ceil(Math.random()*10000000), { name: Sequelize.STRING })
, users = null
, tasks = null
User.hasMany(Task, {as:'Tasks'})
Task.hasMany(User, {as:'Users'})
beforeEach(function() {
Helpers.async(function(_done) {
Helpers.Factories.DAO(User.name, {name: 'User' + Math.random()}, function(_users) {
users = _users; _done()
}, 5)
})
Helpers.async(function(_done) {
Helpers.Factories.DAO(Task.name, {name: 'Task' + Math.random()}, function(_tasks) {
tasks = _tasks; _done()
}, 2)
})
})
describe('addDAO / getDAO', function() {
var user = null
, task = null
beforeEach(function() {
Helpers.async(function(done) {
User.all().on('success', function(_users) {
Task.all().on('success', function(_tasks) {
user = _users[0]
task = _tasks[0]
done()
})
})
})
})
it('should correctly add an association to the dao', function() {
Helpers.async(function(done) {
user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).toEqual(0)
user.addTask(task).on('success', function() {
user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).toEqual(1)
done()
})
})
})
})
})
})
describe('removeDAO', function() {
var user = null
, tasks = null
beforeEach(function() {
Helpers.async(function(done) {
User.all().on('success', function(users) {
Task.all().on('success', function(_tasks) {
user = users[0]
tasks = _tasks
done()
})
})
})
})
it("should correctly remove associated objects", function() {
Helpers.async(function(done) {
user.getTasks().on('success', function(__tasks) {
expect(__tasks.length).toEqual(0)
user.setTasks(tasks).on('success', function() {
user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).toEqual(tasks.length)
user.removeTask(tasks[0]).on('success', function() {
user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).toEqual(tasks.length - 1)
done()
})
})
})
})
})
})
})
})
})
var config = require("../config/config")
, Sequelize = require("../../index")
, sequelize = new Sequelize(config.postgres.database, config.postgres.username, config.postgres.password, {
logging: false,
port: config.postgres.port,
dialect: 'postgres'
})
, Helpers = new (require("../config/helpers"))(sequelize)
describe('Associations', function() {
beforeEach(function() { Helpers.sync() })
afterEach(function() { Helpers.drop() })
/////////// many-to-many with same prefix ////////////
describe('many-to-many', function() {
describe('where tables have the same prefix', function() {
var Table2 = sequelize.define('wp_table2', {foo: Sequelize.STRING})
, Table1 = sequelize.define('wp_table1', {foo: Sequelize.STRING})
Table1.hasMany(Table2)
Table2.hasMany(Table1)
it("should create a table wp_table1wp_table2s", function() {
Helpers.async(function(done) {
expect(sequelize.daoFactoryManager.getDAO('wp_table1swp_table2s')).toBeDefined()
done()
})
})
})
describe('when join table name is specified', function() {
var Table2 = sequelize.define('ms_table1', {foo: Sequelize.STRING})
, Table1 = sequelize.define('ms_table2', {foo: Sequelize.STRING})
Table1.hasMany(Table2, {joinTableName: 'table1_to_table2'})
Table2.hasMany(Table1, {joinTableName: 'table1_to_table2'})
it("should not use a combined name", function() {
expect(sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).toBeUndefined()
})
it("should use the specified name", function() {
expect(sequelize.daoFactoryManager.getDAO('table1_to_table2')).toBeDefined()
})
})
})
})
var config = require("../config/config")
, Sequelize = require("../../index")
, sequelize = new Sequelize(config.postgres.database, config.postgres.username, config.postgres.password, {
logging: false,
dialect: 'postgres',
port: config.postgres.port
})
, Helpers = new (require("../config/helpers"))(sequelize)
, QueryGenerator = require("../../lib/dialects/postgres/query-generator")
, util = require("util")
describe('QueryGenerator', function() {
beforeEach(function() { Helpers.sync() })
afterEach(function() { Helpers.drop() })
var suites = {
createTableQuery: [
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" VARCHAR(255), \"name\" VARCHAR(255));"
},
],
dropTableQuery: [
{
arguments: ['myTable'],
expectation: "DROP TABLE IF EXISTS \"myTable\";"
}
],
selectQuery: [
{
arguments: ['myTable'],
expectation: "SELECT * FROM \"myTable\";"
}, {
arguments: ['myTable', {attributes: ['id', 'name']}],
expectation: "SELECT \"id\", \"name\" FROM \"myTable\";"
}, {
arguments: ['myTable', {where: {id: 2}}],
expectation: "SELECT * FROM \"myTable\" WHERE \"id\"=2;"
}, {
arguments: ['myTable', {where: {name: 'foo'}}],
expectation: "SELECT * FROM \"myTable\" WHERE \"name\"='foo';"
}, {
arguments: ['myTable', {where: {name: "foo';DROP TABLE myTable;"}}],
expectation: "SELECT * FROM \"myTable\" WHERE \"name\"='foo\\';DROP TABLE myTable;';"
}, {
arguments: ['myTable', {where: 2}],
expectation: "SELECT * FROM \"myTable\" WHERE \"id\"=2;"
}, {
arguments: ['foo', { attributes: [['count(*)', 'count']] }],
expectation: 'SELECT count(*) as \"count\" FROM \"foo\";'
}, {
arguments: ['myTable', {where: "foo='bar'"}],
expectation: "SELECT * FROM \"myTable\" WHERE foo='bar';"
}, {
arguments: ['myTable', {order: "id DESC"}],
expectation: "SELECT * FROM \"myTable\" ORDER BY \"id\" DESC;"
}, {
arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\";"
}, {
arguments: ['myTable', {limit: 10}],
expectation: "SELECT * FROM \"myTable\" LIMIT 10;"
}, {
arguments: ['myTable', {limit: 10, offset: 2}],
expectation: "SELECT * FROM \"myTable\" LIMIT 10 OFFSET 2;"
}, {
title: 'uses offset even if no limit was passed',
arguments: ['myTable', {offset: 2}],
expectation: "SELECT * FROM \"myTable\" OFFSET 2;"
}
],
insertQuery: [
{
arguments: ['myTable', {name: 'foo'}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo\\';DROP TABLE myTable;') RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', birthday: new Date(Date.UTC(2011, 2, 27, 10, 1, 55))}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.0') RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', foo: 1}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1) RETURNING *;"
}
],
updateQuery: [
{
arguments: ['myTable', {name: 'foo', birthday: new Date(Date.UTC(2011, 2, 27, 10, 1, 55))}, {id: 2}],
expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.0' WHERE \"id\"=2"
}, {
arguments: ['myTable', {name: 'foo', birthday: new Date(Date.UTC(2011, 2, 27, 10, 1, 55))}, 2],
expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.0' WHERE \"id\"=2"
}, {
arguments: ['myTable', {bar: 2}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo'"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"name\"='foo\\';DROP TABLE myTable;' WHERE \"name\"='foo'"
}
],
deleteQuery: [
{
arguments: ['myTable', {name: 'foo'}],
expectation: "DELETE FROM \"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"myTable\" WHERE \"name\"='foo' LIMIT 1)"
}, {
arguments: ['myTable', 1],
expectation: "DELETE FROM \"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"myTable\" WHERE \"id\"=1 LIMIT 1)"
}, {
arguments: ['myTable', 1, {limit: 10}],
expectation: "DELETE FROM \"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"myTable\" WHERE \"id\"=1 LIMIT 10)"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {limit: 10}],
expectation: "DELETE FROM \"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"myTable\" WHERE \"name\"='foo\\';DROP TABLE myTable;' LIMIT 10)"
}
],
addIndexQuery: [
{
arguments: ['User', ['username', 'isAdmin']],
expectation: 'CREATE INDEX \"user_username_is_admin\" ON \"User\" (\"username\", \"isAdmin\")'
}, {
arguments: [
'User', [
{ attribute: 'username', length: 10, order: 'ASC'},
'isAdmin'
]
],
expectation: "CREATE INDEX \"user_username_is_admin\" ON \"User\" (\"username\"(10) ASC, \"isAdmin\")"
}, {
arguments: [
'User', ['username', 'isAdmin'], { indicesType: 'FULLTEXT', indexName: 'bar'}
],
expectation: "CREATE FULLTEXT INDEX \"bar\" ON \"User\" (\"username\", \"isAdmin\")"
}
],
// FIXME: not implemented
//showIndexQuery: [
// {
// arguments: ['User'],
// expectation: 'SHOW INDEX FROM \"User\"'
// }, {
// arguments: ['User', { database: 'sequelize' }],
// expectation: "SHOW INDEX FROM \"User\" FROM \"sequelize\""
// }
//],
removeIndexQuery: [
{
arguments: ['User', 'user_foo_bar'],
expectation: "DROP INDEX IF EXISTS \"user_foo_bar\""
}, {
arguments: ['User', ['foo', 'bar']],
expectation: "DROP INDEX IF EXISTS \"user_foo_bar\""
}
],
hashToWhereConditions: [
{
arguments: [{ id: [1,2,3] }],
expectation: "\"id\" IN (1,2,3)"
}
]
}
Sequelize.Utils._.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() {
tests.forEach(function(test) {
var title = test.title || 'correctly returns ' + test.expectation + ' for ' + util.inspect(test.arguments)
it(title, function() {
var conditions = QueryGenerator[suiteTitle].apply(null, test.arguments)
expect(conditions).toEqual(test.expectation)
})
})
})
})
})
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!