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

Commit 0638842a by Sascha Depold

Merge branch 'mocha'

2 parents 8e583002 394b5ad5
Showing with 10086 additions and 2653 deletions
...@@ -3,7 +3,7 @@ before_script: ...@@ -3,7 +3,7 @@ before_script:
- "psql -c 'create database sequelize_test;' -U postgres" - "psql -c 'create database sequelize_test;' -U postgres"
script: script:
- "npm run test-buster-travis" - "make test"
notifications: notifications:
email: email:
......
REPORTER ?= dot
TESTS = $(shell find ./test/* -name "*.test.js")
DIALECT ?= mysql
# test commands
teaser:
@echo "" && \
node -pe "Array(20 + '$(DIALECT)'.length + 3).join('#')" && \
echo '# Running tests for $(DIALECT) #' && \
node -pe "Array(20 + '$(DIALECT)'.length + 3).join('#')" && \
echo ''
test:
@make teaser && \
./node_modules/mocha/bin/mocha \
--colors \
--reporter $(REPORTER) \
$(TESTS)
sqlite:
@DIALECT=sqlite make test
mysql:
@DIALECT=mysql make test
postgres:
@DIALECT=postgres make test
postgres-native:
@DIALECT=postgres-native make test
# test aliases
pgsql: postgres
postgresn: postgres-native
# test all the dialects \o/
all: sqlite mysql postgres postgres-native
.PHONY: sqlite mysql postgres pgsql postgres-native postgresn all test
\ No newline at end of file
...@@ -43,7 +43,7 @@ module.exports = (function() { ...@@ -43,7 +43,7 @@ module.exports = (function() {
if (obsoleteAssociations.length > 0) { if (obsoleteAssociations.length > 0) {
// clear the old associations // clear the old associations
var obsoleteIds = obsoleteAssociations.map(function(associatedObject) { var obsoleteIds = obsoleteAssociations.map(function(associatedObject) {
associatedObject[self.__factory.identifier] = null associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
return associatedObject.id return associatedObject.id
}) })
...@@ -55,12 +55,12 @@ module.exports = (function() { ...@@ -55,12 +55,12 @@ module.exports = (function() {
if (unassociatedObjects.length > 0) { if (unassociatedObjects.length > 0) {
// set the new associations // set the new associations
var unassociatedIds = unassociatedObjects.map(function(associatedObject) { var unassociatedIds = unassociatedObjects.map(function(associatedObject) {
associatedObject[self.__factory.identifier] = self.instance.id associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
return associatedObject.id return associatedObject.id
}) })
update = {} update = {}
update[self.__factory.identifier] = self.instance.id update[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
chainer.add(this.__factory.target.update(update, { id: unassociatedIds })) chainer.add(this.__factory.target.update(update, { id: unassociatedIds }))
} }
......
...@@ -70,17 +70,25 @@ module.exports = (function() { ...@@ -70,17 +70,25 @@ module.exports = (function() {
HasOne.prototype.injectSetter = function(obj) { HasOne.prototype.injectSetter = function(obj) {
var self = this var self = this
, options = self.options || {}
obj[this.accessors.set] = function(associatedObject) { obj[this.accessors.set] = function(associatedObject) {
var instance = this; var instance = this
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]().success(function(oldObj) { instance[self.accessors.get]().success(function(oldObj) {
if (oldObj) { if (oldObj) {
oldObj[self.identifier] = null oldObj[self.identifier] = null
oldObj.save() oldObj.save().success(function() {
if (associatedObject) {
associatedObject[self.identifier] = instance.id
associatedObject
.save()
.success(function() { emitter.emit('success', associatedObject) })
.error(function(err) { emitter.emit('error', err) })
} else {
emitter.emit('success', null)
} }
})
} else {
if (associatedObject) { if (associatedObject) {
associatedObject[self.identifier] = instance.id associatedObject[self.identifier] = instance.id
associatedObject associatedObject
...@@ -90,7 +98,7 @@ module.exports = (function() { ...@@ -90,7 +98,7 @@ module.exports = (function() {
} else { } else {
emitter.emit('success', null) emitter.emit('success', null)
} }
}
}) })
}).run() }).run()
} }
......
...@@ -82,7 +82,9 @@ module.exports = (function() { ...@@ -82,7 +82,9 @@ module.exports = (function() {
read: Pooling.Pool({ read: Pooling.Pool({
name: 'sequelize-read', name: 'sequelize-read',
create: function (done) { create: function (done) {
if (reads >= self.config.replication.read.length) reads = 0; if (reads >= self.config.replication.read.length) {
reads = 0
}
var config = self.config.replication.read[reads++]; var config = self.config.replication.read[reads++];
connect.call(self, function (err, connection) { connect.call(self, function (err, connection) {
...@@ -168,11 +170,12 @@ module.exports = (function() { ...@@ -168,11 +170,12 @@ module.exports = (function() {
query.done(function() { query.done(function() {
self.pendingQueries--; self.pendingQueries--;
if (self.pool) self.pool.release(query.client); if (self.pool) {
else { self.pool.release(query.client);
} else {
if (self.pendingQueries === 0) { if (self.pendingQueries === 0) {
setTimeout(function() { setTimeout(function() {
self.pendingQueries === 0 && self.disconnect.call(self); self.pendingQueries === 0 && self.disconnect.call(self)
}, 100); }, 100);
} }
} }
...@@ -180,16 +183,16 @@ module.exports = (function() { ...@@ -180,16 +183,16 @@ module.exports = (function() {
if (!this.pool) { if (!this.pool) {
query.run(sql); query.run(sql);
} } else {
else {
this.pool.acquire(function(err, client) { this.pool.acquire(function(err, client) {
if (err) return query.emit('error', err); if (err) {
return query.emit('error', err)
}
query.client = client; query.client = client
query.run(sql); query.run(sql)
return; return;
}, undefined, options.type); }, undefined, options.type)
} }
return query; return query;
...@@ -209,8 +212,10 @@ module.exports = (function() { ...@@ -209,8 +212,10 @@ module.exports = (function() {
}; };
ConnectorManager.prototype.disconnect = function() { ConnectorManager.prototype.disconnect = function() {
if (this.client) disconnect.call(this, this.client); if (this.client) {
return; disconnect.call(this, this.client)
}
return
}; };
...@@ -265,12 +270,12 @@ module.exports = (function() { ...@@ -265,12 +270,12 @@ module.exports = (function() {
switch(err.code) { switch(err.code) {
case 'ECONNREFUSED': case 'ECONNREFUSED':
case 'ER_ACCESS_DENIED_ERROR': case 'ER_ACCESS_DENIED_ERROR':
emitter.emit('error', new Error("Failed to authenticate for MySQL. Please double check your settings.")) emitter.emit('error', 'Failed to authenticate for MySQL. Please double check your settings.')
break break
case 'ENOTFOUND': case 'ENOTFOUND':
case 'EHOSTUNREACH': case 'EHOSTUNREACH':
case 'EINVAL': case 'EINVAL':
emitter.emit('error', new Error("Failed to find MySQL server. Please double check your settings.")) emitter.emit('error', 'Failed to find MySQL server. Please double check your settings.')
break break
} }
} }
...@@ -295,7 +300,7 @@ module.exports = (function() { ...@@ -295,7 +300,7 @@ module.exports = (function() {
} }
var validateConnection = function(client) { var validateConnection = function(client) {
return client && client.state != 'disconnected' return client && client.state !== 'disconnected'
} }
var enqueue = function(queueItem, options) { var enqueue = function(queueItem, options) {
...@@ -342,8 +347,6 @@ module.exports = (function() { ...@@ -342,8 +347,6 @@ module.exports = (function() {
} }
var afterQuery = function(queueItem) { var afterQuery = function(queueItem) {
var self = this
dequeue.call(this, queueItem) dequeue.call(this, queueItem)
transferQueuedItems.call(this, this.maxConcurrentQueries - this.activeQueue.length) transferQueuedItems.call(this, this.maxConcurrentQueries - this.activeQueue.length)
disconnectIfNoConnections.call(this) disconnectIfNoConnections.call(this)
......
...@@ -29,9 +29,8 @@ module.exports = (function() { ...@@ -29,9 +29,8 @@ module.exports = (function() {
return Utils._.template(query)({}) return Utils._.template(query)({})
}, },
dropSchema: function() { dropSchema: function(tableName, options) {
var query = "SHOW TABLES" return QueryGenerator.dropTableQuery(tableName, options)
return Utils._.template(query)({})
}, },
showSchemasQuery: function() { showSchemasQuery: function() {
...@@ -377,7 +376,7 @@ module.exports = (function() { ...@@ -377,7 +376,7 @@ module.exports = (function() {
}, options || {}) }, options || {})
return Utils._.compact([ return Utils._.compact([
"CREATE", options.indicesType, "INDEX IF NOT EXISTS", options.indexName, "CREATE", options.indicesType, "INDEX", options.indexName,
(options.indexType ? ('USING ' + options.indexType) : undefined), (options.indexType ? ('USING ' + options.indexType) : undefined),
"ON", tableName, '(' + transformedAttributes.join(', ') + ')', "ON", tableName, '(' + transformedAttributes.join(', ') + ')',
(options.parser ? "WITH PARSER " + options.parser : undefined) (options.parser ? "WITH PARSER " + options.parser : undefined)
......
...@@ -9,8 +9,9 @@ module.exports = (function() { ...@@ -9,8 +9,9 @@ module.exports = (function() {
this.client = null this.client = null
this.config = config || {} this.config = config || {}
this.config.port = this.config.port || 5432 this.config.port = this.config.port || 5432
this.pooling = (!!this.config.poolCfg && (this.config.poolCfg.maxConnections > 0)) this.pooling = (!!this.config.pool && (this.config.pool.maxConnections > 0))
this.pg = this.config.native ? require(pgModule).native : require(pgModule) this.pg = this.config.native ? require(pgModule).native : require(pgModule)
this.poolIdentifier = null
// Better support for BigInts // Better support for BigInts
// https://github.com/brianc/node-postgres/issues/166#issuecomment-9514935 // https://github.com/brianc/node-postgres/issues/166#issuecomment-9514935
...@@ -18,52 +19,60 @@ module.exports = (function() { ...@@ -18,52 +19,60 @@ module.exports = (function() {
// set pooling parameters if specified // set pooling parameters if specified
if (this.pooling) { if (this.pooling) {
this.pg.defaults.poolSize = this.config.poolCfg.maxConnections this.pg.defaults.poolSize = this.config.pool.maxConnections
this.pg.defaults.poolIdleTimeout = this.config.poolCfg.maxIdleTime this.pg.defaults.poolIdleTimeout = this.config.pool.maxIdleTime
} }
this.disconnectTimeoutId = null this.disconnectTimeoutId = null
this.pendingQueries = 0 this.pendingQueries = 0
this.maxConcurrentQueries = (this.config.maxConcurrentQueries || 50) this.maxConcurrentQueries = (this.config.maxConcurrentQueries || 50)
process.on('exit', function() {
this.disconnect()
}.bind(this))
} }
Utils._.extend(ConnectorManager.prototype, require("../connector-manager").prototype) Utils._.extend(ConnectorManager.prototype, require("../connector-manager").prototype)
var isConnecting = false ConnectorManager.prototype.endQuery = function() {
var isConnected = false
ConnectorManager.prototype.query = function(sql, callee, options) {
var self = this var self = this
if (this.client === null) { if (!self.pooling && self.pendingQueries === 0) {
this.connect() setTimeout(function() {
self.pendingQueries === 0 && self.disconnect.call(self)
}, 100)
} }
var query = new Query(this.client, this.sequelize, callee, options || {})
self.pendingQueries += 1
return query.run(sql)
.success(function() { self.endQuery.call(self) })
.error(function() { self.endQuery.call(self) })
} }
ConnectorManager.prototype.endQuery = function() { ConnectorManager.prototype.query = function(sql, callee, options) {
var self = this var self = this
self.pendingQueries -= 1
if (self.pendingQueries == 0) { self.pendingQueries++
setTimeout(function() {
self.pendingQueries == 0 && self.disconnect.call(self) return new Utils.CustomEventEmitter(function(emitter) {
}, 100) self.connect()
} .on('error', function(err) {
emitter.emit('error', err)
})
.on('success', function(done) {
var query = new Query(self.client, self.sequelize, callee, options || {})
done = done || null
query.run(sql, done)
.success(function(results) { emitter.emit('success', results); self.endQuery.call(self) })
.error(function(err) { emitter.emit('error', err); self.endQuery.call(self) })
.on('sql', function(sql) { emitter.emit('sql', sql) })
})
}).run().complete(function() { self.pendingQueries-- })
} }
ConnectorManager.prototype.connect = function() { ConnectorManager.prototype.connect = function(callback) {
var self = this var self = this
var emitter = new (require('events').EventEmitter)() var emitter = new (require('events').EventEmitter)()
// in case database is slow to connect, prevent orphaning the client // in case database is slow to connect, prevent orphaning the client
if (this.isConnecting) { if (this.isConnecting) {
return emitter.emit('success')
return emitter
} }
this.isConnecting = true this.isConnecting = true
...@@ -71,10 +80,14 @@ module.exports = (function() { ...@@ -71,10 +80,14 @@ module.exports = (function() {
var uri = this.sequelize.getQueryInterface().QueryGenerator.databaseConnectionUri(this.config) var uri = this.sequelize.getQueryInterface().QueryGenerator.databaseConnectionUri(this.config)
var connectCallback = function(err, client) { var connectCallback = function(err, client, done) {
self.isConnecting = false self.isConnecting = false
if (!!err) { if (!!err) {
// release the pool immediately, very important.
done && done(err)
if (err.code) {
switch(err.code) { switch(err.code) {
case 'ECONNREFUSED': case 'ECONNREFUSED':
emitter.emit('error', new Error("Failed to authenticate for PostgresSQL. Please double check your settings.")) emitter.emit('error', new Error("Failed to authenticate for PostgresSQL. Please double check your settings."))
...@@ -86,21 +99,25 @@ module.exports = (function() { ...@@ -86,21 +99,25 @@ module.exports = (function() {
break break
default: default:
emitter.emit('error', err) emitter.emit('error', err)
break
}
} }
} else if (client) { } else if (client) {
client.query("SET TIME ZONE 'UTC'") client.query("SET TIME ZONE 'UTC'").on('end', function() {
.on('end', function() {
self.isConnected = true self.isConnected = true
this.client = client self.client = client
emitter.emit('success', done)
}); });
} else { } else {
this.client = null self.client = null
emitter.emit('success', done)
} }
} }
if (this.pooling) { if (this.pooling) {
// acquire client from pool // acquire client from pool
this.pg.connect(uri, connectCallback) this.poolIdentifier = this.pg.pools.getOrCreate(this.sequelize.config)
this.poolIdentifier.connect(connectCallback)
} else { } else {
//create one-off client //create one-off client
this.client = new this.pg.Client(uri) this.client = new this.pg.Client(uri)
...@@ -111,8 +128,14 @@ module.exports = (function() { ...@@ -111,8 +128,14 @@ module.exports = (function() {
} }
ConnectorManager.prototype.disconnect = function() { ConnectorManager.prototype.disconnect = function() {
var self = this if (this.poolIdentifier) {
if (this.client) this.client.end() this.poolIdentifier.destroyAllNow()
}
if (this.client) {
this.client.end()
}
this.client = null this.client = null
this.isConnecting = false this.isConnecting = false
this.isConnected = false this.isConnected = false
......
...@@ -112,7 +112,7 @@ module.exports = (function() { ...@@ -112,7 +112,7 @@ module.exports = (function() {
}, },
describeTableQuery: function(tableName) { describeTableQuery: function(tableName) {
var query = 'SELECT c.column_name as "Field", c.column_default as "Default", c.is_nullable as "Null", c.data_type as "Type", (SELECT array_agg(e.enumlabel) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid=e.enumtypid WHERE t.typname=c.udt_name) AS special FROM information_schema.columns c WHERE table_name = <%= table %>;' var query = 'SELECT c.column_name as "Field", c.column_default as "Default", c.is_nullable as "Null", c.data_type as "Type", (SELECT array_agg(e.enumlabel) FROM pg_catalog.pg_type t JOIN pg_catalog.pg_enum e ON t.oid=e.enumtypid WHERE t.typname=c.udt_name) AS "special" FROM information_schema.columns c WHERE table_name = <%= table %>;'
return Utils._.template(query)({ return Utils._.template(query)({
table: this.escape(tableName) table: this.escape(tableName)
}) })
......
...@@ -18,8 +18,9 @@ module.exports = (function() { ...@@ -18,8 +18,9 @@ module.exports = (function() {
} }
Utils.inherit(Query, AbstractQuery) Utils.inherit(Query, AbstractQuery)
Query.prototype.run = function(sql) { Query.prototype.run = function(sql, done) {
this.sql = sql this.sql = sql
var self = this
if (this.options.logging !== false) { if (this.options.logging !== false) {
this.options.logging('Executing: ' + this.sql) this.options.logging('Executing: ' + this.sql)
...@@ -39,13 +40,14 @@ module.exports = (function() { ...@@ -39,13 +40,14 @@ module.exports = (function() {
}.bind(this)) }.bind(this))
query.on('end', function() { query.on('end', function() {
done && done()
this.emit('sql', this.sql) this.emit('sql', this.sql)
if (receivedError) { if (receivedError) {
return return
} }
onSuccess.call(this, rows) onSuccess.call(this, rows, sql)
}.bind(this)) }.bind(this))
return this return this
...@@ -55,11 +57,11 @@ module.exports = (function() { ...@@ -55,11 +57,11 @@ module.exports = (function() {
return 'id' return 'id'
} }
var onSuccess = function(rows) { var onSuccess = function(rows, sql) {
var results = [] var results = []
, self = this , self = this
, isTableNameQuery = (this.sql.indexOf('SELECT table_name FROM information_schema.tables') === 0) , isTableNameQuery = (sql.indexOf('SELECT table_name FROM information_schema.tables') === 0)
, isRelNameQuery = (this.sql.indexOf('SELECT relname FROM pg_class WHERE oid IN') === 0) , isRelNameQuery = (sql.indexOf('SELECT relname FROM pg_class WHERE oid IN') === 0)
if (isTableNameQuery || isRelNameQuery) { if (isTableNameQuery || isRelNameQuery) {
if (isRelNameQuery) { if (isRelNameQuery) {
......
...@@ -22,7 +22,7 @@ module.exports = (function() { ...@@ -22,7 +22,7 @@ module.exports = (function() {
this.database = db = new sqlite3.Database(self.sequelize.options.storage || ':memory:', function(err) { this.database = db = new sqlite3.Database(self.sequelize.options.storage || ':memory:', function(err) {
if (err) { if (err) {
if (err.code === "SQLITE_CANTOPEN") { if (err.code === "SQLITE_CANTOPEN") {
emitter.emit('error', new Error("Failed to find SQL server. Please double check your settings.")) emitter.emit('error', 'Failed to find SQL server. Please double check your settings.')
} }
} }
......
...@@ -37,9 +37,8 @@ module.exports = (function() { ...@@ -37,9 +37,8 @@ module.exports = (function() {
return Utils._.template(query)({}) return Utils._.template(query)({})
}, },
dropSchema: function() { dropSchema: function(tableName, options) {
var query = "SELECT name FROM sqlite_master WHERE type='table' and name!='sqlite_sequence';" return this.dropTableQuery(tableName, options)
return Utils._.template(query)({})
}, },
showSchemasQuery: function() { showSchemasQuery: function() {
...@@ -89,6 +88,16 @@ module.exports = (function() { ...@@ -89,6 +88,16 @@ module.exports = (function() {
return this.replaceBooleanDefaults(sql) return this.replaceBooleanDefaults(sql)
}, },
dropTableQuery: function(tableName, options) {
options = options || {}
var query = "DROP TABLE IF EXISTS <%= table %>;"
return Utils._.template(query)({
table: this.quoteIdentifier(tableName)
})
},
addColumnQuery: function() { addColumnQuery: function() {
var sql = MySqlQueryGenerator.addColumnQuery.apply(this, arguments) var sql = MySqlQueryGenerator.addColumnQuery.apply(this, arguments)
return this.replaceBooleanDefaults(sql) return this.replaceBooleanDefaults(sql)
...@@ -134,6 +143,7 @@ module.exports = (function() { ...@@ -134,6 +143,7 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
selectQuery: function(tableName, options) { selectQuery: function(tableName, options) {
var table = null, var table = null,
joinQuery = "" joinQuery = ""
......
...@@ -54,6 +54,12 @@ module.exports = (function() { ...@@ -54,6 +54,12 @@ module.exports = (function() {
return this return this
} }
CustomEventEmitter.prototype.sql =
function(fct) {
this.on('sql', bindToProcess(fct))
return this;
}
CustomEventEmitter.prototype.proxy = function(emitter) { CustomEventEmitter.prototype.proxy = function(emitter) {
proxyEventKeys.forEach(function (eventKey) { proxyEventKeys.forEach(function (eventKey) {
this.on(eventKey, function (result) { this.on(eventKey, function (result) {
......
const fs = require("fs") const fs = require("fs")
, moment = require("moment") , moment = require("moment")
var Utils = require("./utils") var Utils = require(__dirname + "/utils")
, Migration = require("./migration") , Migration = require(__dirname + "/migration")
, DataTypes = require("./data-types") , DataTypes = require(__dirname + "/data-types")
module.exports = (function() { module.exports = (function() {
var Migrator = function(sequelize, options) { var Migrator = function(sequelize, options) {
...@@ -45,7 +45,7 @@ module.exports = (function() { ...@@ -45,7 +45,7 @@ module.exports = (function() {
if (err) { if (err) {
emitter.emit('error', err) emitter.emit('error', err)
} else { } else {
var chainer = new Utils.QueryChainer var chainer = new Utils.QueryChainer()
, from = migrations[0] , from = migrations[0]
if (options.method === 'down') { if (options.method === 'down') {
...@@ -188,7 +188,7 @@ module.exports = (function() { ...@@ -188,7 +188,7 @@ module.exports = (function() {
var self = this; var self = this;
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer; var chainer = new Utils.QueryChainer()
var addMigration = function(filename) { var addMigration = function(filename) {
self.options.logging('Adding migration script at ' + filename) self.options.logging('Adding migration script at ' + filename)
var migration = new Migration(self, filename) var migration = new Migration(self, filename)
......
var Utils = require("./utils") var Utils = require(__dirname + "/utils")
module.exports = (function() { module.exports = (function() {
var QueryChainer = function(emitters) { var QueryChainer = function(emitters) {
......
var Utils = require('./utils') var Utils = require(__dirname + '/utils')
, DataTypes = require('./data-types') , DataTypes = require(__dirname + '/data-types')
, SQLiteQueryInterface = require('./dialects/sqlite/query-interface') , SQLiteQueryInterface = require(__dirname + '/dialects/sqlite/query-interface')
module.exports = (function() { module.exports = (function() {
var QueryInterface = function(sequelize) { var QueryInterface = function(sequelize) {
...@@ -54,7 +54,7 @@ module.exports = (function() { ...@@ -54,7 +54,7 @@ module.exports = (function() {
var showSchemasSql = self.QueryGenerator.showSchemasQuery() var showSchemasSql = self.QueryGenerator.showSchemasQuery()
self.sequelize.query(showSchemasSql, null, { raw: true }).success(function(schemaNames) { self.sequelize.query(showSchemasSql, null, { raw: true }).success(function(schemaNames) {
self.emit('showAllSchemas', null) self.emit('showAllSchemas', null)
emitter.emit('success', Utils._.flatten(Utils._.map(schemaNames, function(value){ return value.schema_name }))) emitter.emit('success', Utils._.flatten(Utils._.map(schemaNames, function(value){ return (!!value.schema_name ? value.schema_name : value) })))
}).error(function(err) { }).error(function(err) {
self.emit('showAllSchemas', err) self.emit('showAllSchemas', err)
emitter.emit('error', err) emitter.emit('error', err)
...@@ -266,23 +266,128 @@ module.exports = (function() { ...@@ -266,23 +266,128 @@ module.exports = (function() {
} }
QueryInterface.prototype.update = function(dao, tableName, values, identifier) { QueryInterface.prototype.update = function(dao, tableName, values, identifier) {
var sql = this.QueryGenerator.updateQuery(tableName, values, identifier) var self = this
return queryAndEmit.call(this, [sql, dao], 'update') , restrict = false
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier)
// Check for a restrict field
if (!!dao.daoFactory && !!dao.daoFactory.associations) {
var keys = Object.keys(dao.daoFactory.associations)
, length = keys.length
for (var i = 0; i < length; i++) {
if (dao.daoFactory.associations[keys[i]].options && dao.daoFactory.associations[keys[i]].options.onUpdate && dao.daoFactory.associations[keys[i]].options.onUpdate === "restrict") {
restrict = true
}
}
}
return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer()
chainer.add(self, 'enableForeignKeyConstraints', [])
chainer.add(self, 'queryAndEmit', [[sql, dao], 'delete'])
chainer.runSerially()
.success(function(results){
emitter.query = { sql: sql }
emitter.emit('success', results[1])
emitter.emit('sql', sql)
})
.error(function(err) {
emitter.query = { sql: sql }
emitter.emit('error', err)
emitter.emit('sql', sql)
})
.on('sql', function(sql) {
emitter.emit('sql', sql)
})
}).run()
} }
QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier) { QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier) {
var sql = this.QueryGenerator.updateQuery(tableName, values, identifier) var self = this
return queryAndEmit.call(this, sql, 'bulkUpdate') , sql = self.QueryGenerator.updateQuery(tableName, values, identifier)
return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer()
chainer.add(self, 'enableForeignKeyConstraints', [])
chainer.add(self, 'queryAndEmit', [sql, 'bulkUpdate'])
return chainer.runSerially()
.success(function(results){
emitter.query = { sql: sql }
emitter.emit('sql', sql)
emitter.emit('success', results[1])
})
.error(function(err) {
emitter.query = { sql: sql }
emitter.emit('sql', sql)
emitter.emit('error', err)
})
}).run()
} }
QueryInterface.prototype.delete = function(dao, tableName, identifier) { QueryInterface.prototype.delete = function(dao, tableName, identifier) {
var sql = this.QueryGenerator.deleteQuery(tableName, identifier) var self = this
return queryAndEmit.call(this, [sql, dao], 'delete') , restrict = false
, sql = self.QueryGenerator.deleteQuery(tableName, identifier)
// Check for a restrict field
if (!!dao.daoFactory && !!dao.daoFactory.associations) {
var keys = Object.keys(dao.daoFactory.associations)
, length = keys.length
for (var i = 0; i < length; i++) {
if (dao.daoFactory.associations[keys[i]].options && dao.daoFactory.associations[keys[i]].options.onDelete && dao.daoFactory.associations[keys[i]].options.onDelete === "restrict") {
restrict = true
}
}
}
return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer()
chainer.add(self, 'enableForeignKeyConstraints', [])
chainer.add(self, 'queryAndEmit', [[sql, dao], 'delete'])
chainer.runSerially()
.success(function(results){
emitter.query = { sql: sql }
emitter.emit('sql', sql)
emitter.emit('success', results[1])
})
.error(function(err) {
emitter.query = { sql: sql }
emitter.emit('sql', sql)
emitter.emit('error', err)
})
}).run()
} }
QueryInterface.prototype.bulkDelete = function(tableName, identifier, options) { QueryInterface.prototype.bulkDelete = function(tableName, identifier, options) {
var sql = this.QueryGenerator.deleteQuery(tableName, identifier, Utils._.defaults(options || {}, {limit: null})) var self = this
return queryAndEmit.call(this, sql, 'bulkDelete') var sql = self.QueryGenerator.deleteQuery(tableName, identifier, Utils._.defaults(options || {}, {limit: null}))
return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer()
chainer.add(self, 'enableForeignKeyConstraints', [])
chainer.add(self, 'queryAndEmit', [sql, 'bulkDelete', options])
chainer.runSerially()
.success(function(results){
emitter.query = { sql: sql }
emitter.emit('sql', sql)
emitter.emit('success', results[1])
})
.error(function(err) {
emitter.query = { sql: sql }
emitter.emit('sql', sql)
emitter.emit('error', err)
})
}).run()
} }
QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) { QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) {
...@@ -385,9 +490,7 @@ module.exports = (function() { ...@@ -385,9 +490,7 @@ module.exports = (function() {
return this.QueryGenerator.escape(value) return this.QueryGenerator.escape(value)
} }
// private var queryAndEmit = QueryInterface.prototype.queryAndEmit = function(sqlOrQueryParams, methodName, options, emitter) {
var queryAndEmit = function(sqlOrQueryParams, methodName, options, emitter) {
options = Utils._.extend({ options = Utils._.extend({
success: function(){}, success: function(){},
error: function(){} error: function(){}
......
...@@ -88,9 +88,12 @@ var Utils = module.exports = { ...@@ -88,9 +88,12 @@ var Utils = module.exports = {
type = typeof where[i] type = typeof where[i]
_where[i] = _where[i] || {} _where[i] = _where[i] || {}
if (Array.isArray(where[i])) { if (where[i] === null) {
// skip nulls
}
else if (Array.isArray(where[i])) {
_where[i].in = _where[i].in || [] _where[i].in = _where[i].in || []
_where[i].in.concat(where[i]); _where[i].in.concat(where[i])
} }
else if (type === "object") { else if (type === "object") {
Object.keys(where[i]).forEach(function(ii) { Object.keys(where[i]).forEach(function(ii) {
...@@ -380,6 +383,6 @@ var Utils = module.exports = { ...@@ -380,6 +383,6 @@ var Utils = module.exports = {
} }
} }
Utils.CustomEventEmitter = require("./emitters/custom-event-emitter") Utils.CustomEventEmitter = require(__dirname + "/emitters/custom-event-emitter")
Utils.QueryChainer = require("./query-chainer") Utils.QueryChainer = require(__dirname + "/query-chainer")
Utils.Lingo = require("lingo") Utils.Lingo = require("lingo")
...@@ -46,11 +46,14 @@ ...@@ -46,11 +46,14 @@
"devDependencies": { "devDependencies": {
"sqlite3": "~2.1.12", "sqlite3": "~2.1.12",
"mysql": "~2.0.0-alpha8", "mysql": "~2.0.0-alpha8",
"pg": "~2.1.0", "pg": "~2.2.0",
"buster": "~0.6.3", "buster": "~0.6.3",
"watchr": "~2.4.3", "watchr": "~2.4.3",
"yuidocjs": "~0.3.36", "yuidocjs": "~0.3.36",
"semver": "~2.0.8" "chai": "~1.7.2",
"mocha": "~1.12.0",
"chai-datetime": "~1.0.0",
"sinon": "~1.7.3"
}, },
"keywords": [ "keywords": [
"mysql", "mysql",
...@@ -60,13 +63,7 @@ ...@@ -60,13 +63,7 @@
], ],
"main": "index", "main": "index",
"scripts": { "scripts": {
"test": "npm run test-buster", "test": "make all",
"test-buster": "npm run test-buster-mysql && npm run test-buster-postgres && npm run test-buster-postgres-native && npm run test-buster-sqlite",
"test-buster-travis": "buster-test",
"test-buster-mysql": "DIALECT=mysql buster-test",
"test-buster-postgres": "DIALECT=postgres buster-test",
"test-buster-postgres-native": "DIALECT=postgres-native buster-test",
"test-buster-sqlite": "DIALECT=sqlite buster-test",
"docs": "node_modules/.bin/yuidoc . -o docs" "docs": "node_modules/.bin/yuidoc . -o docs"
}, },
"bin": { "bin": {
......
/* jshint camelcase: false */ /* jshint camelcase: false */
if (typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, Sequelize = require('../../index') , Sequelize = require('../../index')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 500 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize) {
this.sequelize = sequelize this.sequelize = sequelize
}.bind(this), Helpers.clearDatabase(this.sequelize, done)
onComplete: done
})
}) })
describe('general usage', function() { describe('general usage', function() {
before(function(done) { before(function(done) {
this.User = this.sequelize.define('User', { var self = this
username: Helpers.Sequelize.STRING, self.User = this.sequelize.define('User', {
username: DataTypes.STRING,
enabled: { enabled: {
type: Helpers.Sequelize.BOOLEAN, type: Helpers.Sequelize.BOOLEAN,
defaultValue: true defaultValue: true
} }
}) })
this.Task = this.sequelize.define('Task', {
title: Helpers.Sequelize.STRING self.Task = this.sequelize.define('Task', {
title: DataTypes.STRING
}) })
this.sequelize.sync({ force: true }).success(done) self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(done)
})
}) })
it('adds the foreign key', function(done) { it('adds the foreign key', function(done) {
...@@ -44,6 +44,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -44,6 +44,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
it("underscores the foreign key", function(done) { it("underscores the foreign key", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }, {underscored: true}) var Task = this.sequelize.define('Task', { title: Sequelize.STRING }, {underscored: true})
Task.belongsTo(this.User) Task.belongsTo(this.User)
expect(Task.attributes.user_id).toEqual("INTEGER") expect(Task.attributes.user_id).toEqual("INTEGER")
done() done()
...@@ -97,7 +98,8 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -97,7 +98,8 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
var self = this var self = this
this.Task.belongsTo(this.User, {as: 'User'}) this.Task.belongsTo(this.User, {as: 'User'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.create({username: 'asd'}).success(function(u) { self.User.create({username: 'asd'}).success(function(u) {
self.Task.create({title: 'a task'}).success(function(t) { self.Task.create({title: 'a task'}).success(function(t) {
t.setUser(u).success(function() { t.setUser(u).success(function() {
...@@ -110,12 +112,14 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -110,12 +112,14 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
it('extends the id where param with the supplied where params', function(done) { it('extends the id where param with the supplied where params', function(done) {
var self = this var self = this
this.Task.belongsTo(this.User, {as: 'User'}) this.Task.belongsTo(this.User, {as: 'User'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.create({username: 'asd', enabled: false}).success(function(u) { self.User.create({username: 'asd', enabled: false}).success(function(u) {
self.Task.create({title: 'a task'}).success(function(t) { self.Task.create({title: 'a task'}).success(function(t) {
t.setUser(u).success(function() { t.setUser(u).success(function() {
...@@ -128,6 +132,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -128,6 +132,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
it("handles self associations", function(done) { it("handles self associations", function(done) {
var Person = this.sequelize.define('Person', { name: Helpers.Sequelize.STRING }) var Person = this.sequelize.define('Person', { name: Helpers.Sequelize.STRING })
...@@ -158,20 +163,20 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -158,20 +163,20 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
Task.belongsTo(User) Task.belongsTo(User)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
task.setUserXYZ(user).success(function() { task.setUserXYZ(user).success(function() {
task.getUserXYZ().success(function(user) { task.getUserXYZ().success(function(user) {
expect(user).not.toEqual(null) expect(user).not.toEqual(null)
task.setUserXYZ(null).success(function() { task.setUserXYZ(null).success(function() {
task.getUserXYZ().success(function(user) { task.getUserXYZ().success(function(user) {
expect(user).toEqual(null) expect(user).toEqual(null)
done() done()
}) })
}) })
})
}) })
}) })
}) })
...@@ -181,18 +186,23 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -181,18 +186,23 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
describe("Foreign key constraints", function() { describe("Foreign key constraints", function() {
it("are not enabled by default", function(done) { before(function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) this.Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING }) this.User = this.sequelize.define('User', { username: DataTypes.STRING })
done()
})
Task.belongsTo(User) it("are not enabled by default", function(done) {
var self = this
self.Task.belongsTo(self.User)
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { self.Task.sync({ force: true }).success(function() {
Task.create({ title: 'task' }).success(function(task) { self.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
user.destroy().success(function() { user.destroy().success(function() {
Task.findAll().success(function(tasks) { self.Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -202,19 +212,19 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -202,19 +212,19 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
it("can cascade deletes", function(done) { it("can cascade deletes", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) self.Task.belongsTo(self.User, {onDelete: 'cascade'})
Task.belongsTo(User, {onDelete: 'cascade'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { self.Task.sync({ force: true }).success(function() {
Task.create({ title: 'task' }).success(function(task) { self.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
user.destroy().success(function() { user.destroy().success(function() {
Task.findAll().success(function(tasks) { self.Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(0) expect(tasks.length).toEqual(0)
done() done()
}) })
...@@ -224,20 +234,20 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -224,20 +234,20 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
it("can restrict deletes", function(done) { it("can restrict deletes", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) self.Task.belongsTo(self.User, {onDelete: 'restrict'})
Task.belongsTo(User, {onDelete: 'restrict'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { self.Task.sync({ force: true }).success(function() {
Task.create({ title: 'task' }).success(function(task) { self.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
user.destroy().error(function() { user.destroy().error(function() {
// Should fail due to FK restriction // Should fail due to FK restriction
Task.findAll().success(function(tasks) { self.Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -247,16 +257,16 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -247,16 +257,16 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
it("can cascade updates", function(done) { it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) self.Task.belongsTo(self.User, {onUpdate: 'cascade'})
Task.belongsTo(User, {onUpdate: 'cascade'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { self.Task.sync({ force: true }).success(function() {
Task.create({ title: 'task' }).success(function(task) { self.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
// Changing the id of a DAO requires a little dance since // Changing the id of a DAO requires a little dance since
...@@ -266,7 +276,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -266,7 +276,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory) var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id) user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.success(function() { .success(function() {
Task.findAll().success(function(tasks) { self.Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
expect(tasks[0].UserId).toEqual(999) expect(tasks[0].UserId).toEqual(999)
done() done()
...@@ -277,16 +287,16 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -277,16 +287,16 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
it("can restrict updates", function(done) { it("can restrict updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) self.Task.belongsTo(self.User, {onUpdate: 'restrict'})
Task.belongsTo(User, {onUpdate: 'restrict'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { self.Task.sync({ force: true }).success(function() {
Task.create({ title: 'task' }).success(function(task) { self.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
// Changing the id of a DAO requires a little dance since // Changing the id of a DAO requires a little dance since
...@@ -297,7 +307,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -297,7 +307,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
user.QueryInterface.update(user, tableName, {id: 999}, user.id) user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.error(function() { .error(function() {
// Should fail due to FK restriction // Should fail due to FK restriction
Task.findAll().success(function(tasks) { self.Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -308,11 +318,12 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -308,11 +318,12 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
})
describe("Association options", function() { describe("Association options", function() {
it('can specify data type for autogenerated relational keys', function(done) { it('can specify data type for autogenerated relational keys', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }) var User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING] , dataTypes = [DataTypes.INTEGER, DataTypes.BIGINT, DataTypes.STRING]
, self = this , self = this
dataTypes.forEach(function(dataType) { dataTypes.forEach(function(dataType) {
...@@ -321,7 +332,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -321,7 +332,7 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
Task.belongsTo(User, { foreignKey: 'userId', keyType: dataType }) Task.belongsTo(User, { foreignKey: 'userId', keyType: dataType })
self.sequelize.sync({ force: true }).success(function() { Task.sync({ force: true }).success(function() {
expect(Task.rawAttributes.userId.type.toString()) expect(Task.rawAttributes.userId.type.toString())
.toEqual(dataType.toString()) .toEqual(dataType.toString())
...@@ -333,5 +344,4 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() { ...@@ -333,5 +344,4 @@ describe(Helpers.getTestDialectTeaser("BelongsTo"), function() {
}) })
}) })
}) })
}) })
/* jshint camelcase: false */
var buster = require("buster")
, Helpers = require('../buster-helpers')
, Sequelize = require('../../index')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Helpers.getTestDialect()
buster.spec.expose()
buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("ForeignKeys"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) {
var self = this
self.sequelize = Object.create(sequelize)
Helpers.clearDatabase(this.sequelize, done)
})
afterAll(function(done) {
Helpers.clearDatabase(sequelize, done)
})
describe("Foreign key constraints", function() {
it("are not enabled by default", function(done) {
var self = Object.create(this.sequelize)
, Task = self.define('Task1', { title: Sequelize.STRING })
, User = self.define('User1', { username: Sequelize.STRING })
User.hasMany(Task)
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask1s([task]).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1)
done()
})
})
})
})
})
})
})
})
it("can cascade deletes", function(done) {
var self = Object.create(this.sequelize)
, Task = self.define('Task2', { title: DataTypes.STRING })
, User = self.define('User2', { username: DataTypes.STRING })
User.hasMany(Task, {onDelete: 'cascade'})
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask2s([task]).success(function() {
user.destroy()
.error(function(err) {
expect(false).toEqual('This shouldn\'t error.')
done()
})
.success(function() {
Task.all({where: {User2Id: user.id}}).success(function(tasks) {
expect(tasks.length).toEqual(0)
done()
})
})
})
})
})
})
})
})
it("can restrict deletes", function(done) {
var self = Object.create(this.sequelize)
, Task = self.define('Task3', { title: DataTypes.STRING })
, User = self.define('User3', { username: DataTypes.STRING })
User.hasMany(Task, {onDelete: 'restrict'})
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask3s([task]).success(function() {
user.destroy()
.success(function(success) {
expect(false).toEqual('This shouldn\'t succeed.')
done()
})
.error(function(err) {
// Should fail due to FK restriction
Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1)
done()
})
})
})
})
})
})
})
})
it("can cascade updates", function(done) {
var self = Object.create(this.sequelize)
, Task = self.define('Task4', { title: DataTypes.STRING })
, User = self.define('User4', { username: DataTypes.STRING })
User.hasMany(Task, {onUpdate: 'cascade'})
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask4s([task]).success(function() {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.error(function() {
expect(false).toEqual('This shouldn\'t error.')
done()
})
.success(function() {
Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1)
expect(tasks[0].User4Id).toEqual(999)
done()
})
})
})
})
})
})
})
})
it("can restrict updates", function(done) {
var self = Object.create(this.sequelize)
, Task = self.define('Task5', { title: DataTypes.STRING })
, User = self.define('User5', { username: DataTypes.STRING })
User.hasMany(Task, {onUpdate: 'restrict'})
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTask5s([task]).success(function() {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.success(function() {
expect(false).toEqual('You shouldn\'t reach this.')
done()
})
.error(function() {
// Should fail due to FK restriction
Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1)
done()
})
})
})
})
})
})
})
})
})
})
/* jshint camelcase: false */ /* jshint camelcase: false */
if (typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, Sequelize = require('../../index') , Sequelize = require('../../index')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, _ = require('lodash') , _ = require('lodash')
, moment = require('moment') , moment = require('moment')
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 500 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("HasMany"), function() { describe(Helpers.getTestDialectTeaser("HasMany"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
var self = this var self = this
self.sequelize = Object.create(sequelize)
Helpers.initTests({ Helpers.clearDatabase(this.sequelize, done)
dialect: dialect,
beforeComplete: function(sequelize) { self.sequelize = sequelize },
onComplete: done
}) })
afterAll(function(done) {
Helpers.clearDatabase(sequelize, done)
}) })
describe('general usage', function() { describe('general usage', function() {
before(function(done) { before(function(done) {
this.User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }) var self = this
this.Task = this.sequelize.define('Task', { title: Helpers.Sequelize.STRING }) self.User = self.sequelize.define('User', { username: Helpers.Sequelize.STRING })
this.sequelize.sync({ force: true }).success(done) self.Task = self.sequelize.define('Task', { title: Helpers.Sequelize.STRING })
self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(done)
})
}) })
describe('mono-directional', function() { describe('mono-directional', function() {
it("adds the foreign key", function(done) { it("adds the foreign key", function(done) {
this.User.hasMany(this.Task) var self = this
expect(this.Task.attributes.UserId).toEqual("INTEGER") self.User.hasMany(self.Task)
expect(self.Task.attributes.UserId).toEqual("INTEGER")
done() done()
}) })
it('adds the foreign key with underscore', function(done) { it('adds the foreign key with underscore', function(done) {
var User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }) var self = Object.create(this.sequelize)
, Task = this.sequelize.define('Task', { title: Helpers.Sequelize.STRING }, { underscored: true }) , User = self.define('User', { username: Helpers.Sequelize.STRING })
, Task = self.define('Task', { title: Helpers.Sequelize.STRING }, { underscored: true })
Task.hasMany(User) Task.hasMany(User)
...@@ -47,23 +52,26 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -47,23 +52,26 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
it('uses the passed foreign key', function(done) { it('uses the passed foreign key', function(done) {
this.User.hasMany(this.Task, { foreignKey: 'person_id' }) var self = this
expect(this.Task.attributes.person_id).toEqual("INTEGER") self.User.hasMany(self.Task, { foreignKey: 'person_id' })
expect(self.Task.attributes.person_id).toEqual("INTEGER")
done() done()
}) })
it('defines getters and setters', function(done) { it('defines getters and setters', function(done) {
this.User.hasMany(this.Task) var self = this
self.User.hasMany(self.Task)
var u = this.User.build({username: 'asd'}) var u = self.User.build({username: 'asd'})
expect(u.setTasks).toBeDefined() expect(u.setTasks).toBeDefined()
expect(u.getTasks).toBeDefined() expect(u.getTasks).toBeDefined()
done() done()
}) })
it("defines getters and setters according to the 'as' option", function(done) { it("defines getters and setters according to the 'as' option", function(done) {
this.User.hasMany(this.Task, {as: 'Tasks'}) var self = this
var u = this.User.build({username: 'asd'}) self.User.hasMany(self.Task, {as: 'Tasks'})
var u = self.User.build({username: 'asd'})
expect(u.setTasks).toBeDefined() expect(u.setTasks).toBeDefined()
expect(u.getTasks).toBeDefined() expect(u.getTasks).toBeDefined()
...@@ -73,8 +81,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -73,8 +81,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
it("sets and gets associated objects", function(done) { it("sets and gets associated objects", function(done) {
var self = this var self = this
this.User.hasMany(this.Task, { as: 'Tasks' }) self.User.hasMany(self.Task, { as: 'Tasks' })
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.create({username: 'name'}).success(function(user) { self.User.create({username: 'name'}).success(function(user) {
self.Task.create({title: 'task1'}).success(function(task1) { self.Task.create({title: 'task1'}).success(function(task1) {
self.Task.create({title: 'task2'}).success(function(task2) { self.Task.create({title: 'task2'}).success(function(task2) {
...@@ -94,17 +103,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -94,17 +103,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
it("should allow selfAssociation to be single linked (only one DAO is created)", function(done) { it("should allow selfAssociation to be single linked (only one DAO is created)", function(done) {
var oldLength = this.sequelize.daoFactoryManager.daos.length var self = Object.create(this.sequelize)
, Comment = this.sequelize.define('Comment', { content: Helpers.Sequelize.STRING }) , oldLength = self.daoFactoryManager.daos.length
, Comment = self.define('Comment', { content: Helpers.Sequelize.STRING })
Comment.belongsTo(Comment, {as: "Parent"}); Comment.belongsTo(Comment, {as: "Parent"});
Comment.hasMany(Comment, {as: 'Children', foreignKey: "ParentId", useJunctionTable: false}) Comment.hasMany(Comment, {as: 'Children', foreignKey: "ParentId", useJunctionTable: false})
expect(this.sequelize.daoFactoryManager.daos.length).toEqual(oldLength + 1) expect(self.daoFactoryManager.daos.length).toEqual(oldLength + 1)
Comment.sync({force: true}).success(function() { Comment.sync({ force: true }).success(function() {
Comment.create({ content: 'parentComment' }).success(function(parent) { Comment.create({ content: 'parentComment' }).success(function(parent) {
Comment.create({ content: 'child1' }).success(function(child1) { Comment.create({ content: 'child1' }).success(function(child1) {
child1.setParent(parent).success(function() { child1.setParent(parent).success(function() {
...@@ -124,29 +135,30 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -124,29 +135,30 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
it("should still use many to many for selfAssociation by default (two DAOs are created)", function(done) { it("should still use many to many for selfAssociation by default (two DAOs are created)", function() {
var oldLength = this.sequelize.daoFactoryManager.daos.length var self = this
, Comment = this.sequelize.define('Comment', { content: Sequelize.STRING }) , oldLength = self.sequelize.daoFactoryManager.daos.length
, Comment = self.sequelize.define('Comment', { content: Sequelize.STRING })
Comment.belongsTo(Comment, {as: "Parent"}) Comment.belongsTo(Comment, {as: "Parent"})
Comment.hasMany(Comment, {as: 'Children'}) Comment.hasMany(Comment, {as: 'Children'})
expect(this.sequelize.daoFactoryManager.daos.length).toEqual(oldLength + 2) expect(self.sequelize.daoFactoryManager.daos.length).toEqual(oldLength + 2)
done();
}) })
describe('bi-directional', function() { describe('bi-directional', function() {
it('adds the foreign key', function(done) { it('adds the foreign key', function(done) {
var self = this var self = Object.create(this.sequelize)
, selfx = this
this.Task.hasMany(this.User) selfx.Task.hasMany(selfx.User)
this.User.hasMany(this.Task) selfx.User.hasMany(selfx.Task)
expect(this.Task.attributes.UserId).not.toBeDefined() expect(selfx.Task.attributes.UserId).not.toBeDefined()
expect(this.User.attributes.UserId).not.toBeDefined() expect(selfx.User.attributes.UserId).not.toBeDefined()
var daos = this.sequelize.daoFactoryManager.daos.filter(function(dao) { var daos = self.daoFactoryManager.daos.filter(function(dao) {
return (dao.tableName == (self.Task.tableName + self.User.tableName)) return (dao.tableName == (selfx.Task.tableName + selfx.User.tableName))
}) })
daos.forEach(function(dao) { daos.forEach(function(dao) {
...@@ -157,8 +169,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -157,8 +169,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
it("adds the foreign key with underscores", function(done) { it("adds the foreign key with underscores", function(done) {
var User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }, { underscored: true }) var self = Object.create(this.sequelize)
, Task = this.sequelize.define('Task', { title: Helpers.Sequelize.STRING }) , User = self.define('User', { username: Helpers.Sequelize.STRING }, { underscored: true })
, Task = self.define('Task', { title: Helpers.Sequelize.STRING })
Task.hasMany(User) Task.hasMany(User)
User.hasMany(Task) User.hasMany(Task)
...@@ -166,7 +179,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -166,7 +179,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
expect(Task.attributes.user_id).not.toBeDefined() expect(Task.attributes.user_id).not.toBeDefined()
expect(User.attributes.user_id).not.toBeDefined() expect(User.attributes.user_id).not.toBeDefined()
var daos = this.sequelize.daoFactoryManager.daos.filter(function(dao) { var daos = self.daoFactoryManager.daos.filter(function(dao) {
return (dao.tableName == (Task.tableName + User.tableName)) return (dao.tableName == (Task.tableName + User.tableName))
}) })
...@@ -178,13 +191,14 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -178,13 +191,14 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
it("uses the passed foreign keys", function(done) { it("uses the passed foreign keys", function(done) {
var self = this var self = Object.create(this.sequelize)
, selfx = this
this.User.hasMany(this.Task, { foreignKey: 'person_id' }) this.User.hasMany(this.Task, { foreignKey: 'person_id' })
this.Task.hasMany(this.User, { foreignKey: 'work_item_id' }) this.Task.hasMany(this.User, { foreignKey: 'work_item_id' })
var daos = this.sequelize.daoFactoryManager.daos.filter(function(dao) { var daos = self.daoFactoryManager.daos.filter(function(dao) {
return (dao.tableName == (self.Task.tableName + self.User.tableName)) return (dao.tableName == (selfx.Task.tableName + selfx.User.tableName))
}) })
daos.forEach(function(dao) { daos.forEach(function(dao) {
...@@ -229,7 +243,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -229,7 +243,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
this.User.hasMany(this.Task, {as: 'Tasks'}) this.User.hasMany(this.Task, {as: 'Tasks'})
this.Task.hasMany(this.User, {as: 'Users'}) this.Task.hasMany(this.User, {as: 'Users'})
this.sequelize.sync({ force: true }).success(function() {
self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.create({username: 'name'}).success(function(user1) { self.User.create({username: 'name'}).success(function(user1) {
self.User.create({username: 'name2'}).success(function(user2) { self.User.create({username: 'name2'}).success(function(user2) {
self.Task.create({title: 'task1'}).success(function(task1) { self.Task.create({title: 'task1'}).success(function(task1) {
...@@ -258,17 +274,18 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -258,17 +274,18 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
it("build the connector daos name", function(done) { it("build the connector daos name", function(done) {
var self = this var self = Object.create(this.sequelize)
, Person = this.sequelize.define('Person', { name: Helpers.Sequelize.STRING }) , Person = self.define('Person', { name: Helpers.Sequelize.STRING })
Person.hasMany(Person, {as: 'Children'}) Person.hasMany(Person, {as: 'Children'})
Person.hasMany(Person, {as: 'Friends'}) Person.hasMany(Person, {as: 'Friends'})
Person.hasMany(Person, {as: 'CoWorkers'}) Person.hasMany(Person, {as: 'CoWorkers'})
Person.sync({force: true}).success(function() { Person.sync({ force: true }).success(function() {
var daoNames = self.sequelize.daoFactoryManager.daos.map(function(dao) { return dao.tableName }) var daoNames = self.daoFactoryManager.daos.map(function(dao) { return dao.tableName })
, expectation = ["Persons", "ChildrenPersons", "CoWorkersPersons", "FriendsPersons"] , expectation = ["Persons", "ChildrenPersons", "CoWorkersPersons", "FriendsPersons"]
expectation.forEach(function(ex) { expectation.forEach(function(ex) {
...@@ -288,7 +305,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -288,7 +305,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
Parent.hasMany(Child, {as: 'Children', foreignKey: 'child_id', joinTableName: 'ParentRelationship'}) Parent.hasMany(Child, {as: 'Children', foreignKey: 'child_id', joinTableName: 'ParentRelationship'})
Child.hasMany(Parent, {as: 'Parents', foreignKey: 'parent_id', joinTableName: 'ParentRelationship'}) Child.hasMany(Parent, {as: 'Parents', foreignKey: 'parent_id', joinTableName: 'ParentRelationship'})
this.sequelize.sync({ force: true }).success(function() { ParentJoin.sync({ force: true }).success(function() {
Parent.sync({ force: true }).success(function() {
Child.sync({ force: true }).success(function() {
Parent.create({name: 'mom'}).success(function(mom) { Parent.create({name: 'mom'}).success(function(mom) {
parents.push(mom) parents.push(mom)
Parent.create({name: 'dad'}).success(function(dad) { Parent.create({name: 'dad'}).success(function(dad) {
...@@ -309,6 +328,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -309,6 +328,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
})
it("allows join table to be mapped and specified", function(done) { it("allows join table to be mapped and specified", function(done) {
var User = this.sequelize.define('User', { name: Helpers.Sequelize.STRING }, {underscore: true, freezeTableName: true}) var User = this.sequelize.define('User', { name: Helpers.Sequelize.STRING }, {underscore: true, freezeTableName: true})
...@@ -321,7 +342,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -321,7 +342,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
User.hasMany(Company, {as: 'Companies', foreignKey: 'user_id', joinTableName: 'CompanyAccess'}) User.hasMany(Company, {as: 'Companies', foreignKey: 'user_id', joinTableName: 'CompanyAccess'})
Company.hasMany(User, {as: 'Users', foreignKey: 'company_id', joinTableName: 'CompanyAccess'}) Company.hasMany(User, {as: 'Users', foreignKey: 'company_id', joinTableName: 'CompanyAccess'})
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Company.sync({ force: true }).success(function() {
CompanyAccess.sync({ force: true }).success(function() {
Company.create({name: 'IBM'}).success(function(ibm) { Company.create({name: 'IBM'}).success(function(ibm) {
companies.push(ibm) companies.push(ibm)
Company.create({name: 'EA'}).success(function(ea) { Company.create({name: 'EA'}).success(function(ea) {
...@@ -342,9 +365,12 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -342,9 +365,12 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
})
it("gets and sets the connector daos", function(done) { it("gets and sets the connector daos", function(done) {
var Person = this.sequelize.define('Person', { name: Helpers.Sequelize.STRING }) var self = this
, Person = self.sequelize.define('Person', { name: Helpers.Sequelize.STRING })
Person.hasMany(Person, {as: 'Children'}) Person.hasMany(Person, {as: 'Children'})
Person.hasMany(Person, {as: 'Friends'}) Person.hasMany(Person, {as: 'Friends'})
...@@ -369,6 +395,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -369,6 +395,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
describe('(1:N)', function() { describe('(1:N)', function() {
describe('hasSingle', function() { describe('hasSingle', function() {
before(function(done) { before(function(done) {
var self = this
this.Article = this.sequelize.define('Article', { this.Article = this.sequelize.define('Article', {
'title': Sequelize.STRING 'title': Sequelize.STRING
}) })
...@@ -378,7 +405,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -378,7 +405,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
this.Article.hasMany(this.Label) this.Article.hasMany(this.Label)
this.sequelize.sync({ force: true }).success(done) self.Article.sync({ force: true }).success(function() {
self.Label.sync({ force: true }).success(done)
})
}) })
it('does not have any labels assigned to it initially', function(done) { it('does not have any labels assigned to it initially', function(done) {
...@@ -428,6 +457,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -428,6 +457,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
describe('hasAll', function() { describe('hasAll', function() {
before(function(done) { before(function(done) {
var self = this
this.Article = this.sequelize.define('Article', { this.Article = this.sequelize.define('Article', {
'title': Sequelize.STRING 'title': Sequelize.STRING
}) })
...@@ -437,7 +467,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -437,7 +467,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
this.Article.hasMany(this.Label) this.Article.hasMany(this.Label)
this.sequelize.sync({ force: true }).success(done) self.Article.sync({ force: true }).success(function() {
self.Label.sync({ force: true }).success(done)
})
}) })
it('answers false if only some labels have been assigned', function(done) { it('answers false if only some labels have been assigned', function(done) {
...@@ -477,18 +509,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -477,18 +509,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
describe('setAssociations', function() { describe('setAssociations', function() {
it("clears associations when passing null to the set-method", function(done) { it("clears associations when passing null to the set-method", function(done) {
var User = this.sequelize.define('User', { username: Sequelize.STRING }) var self = Object.create(this.sequelize)
, Task = this.sequelize.define('Task', { title: Sequelize.STRING }) , User = self.define('User', { username: Sequelize.STRING })
, Task = self.define('Task', { title: Sequelize.STRING })
Task.hasMany(User) Task.hasMany(User)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
task.setUsers([ user ]).success(function() { task.setUsers([ user ]).success(function() {
task.getUsers().success(function(_users) { task.getUsers().success(function(_users) {
expect(_users.length).toEqual(1) expect(_users.length).toEqual(1)
task.setUsers(null).success(function() { task.setUsers(null).success(function() {
task.getUsers().success(function(_users) { task.getUsers().success(function(_users) {
expect(_users.length).toEqual(0) expect(_users.length).toEqual(0)
...@@ -502,22 +535,24 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -502,22 +535,24 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
it("clears associations when passing null to the set-method with omitNull set to true", function(done) { it("clears associations when passing null to the set-method with omitNull set to true", function(done) {
this.sequelize.options.omitNull = true var self = Object.create(this.sequelize)
self.options.omitNull = true
var User = this.sequelize.define('User', { username: Sequelize.STRING }) var User = self.define('User', { username: Sequelize.STRING })
, Task = this.sequelize.define('Task', { title: Sequelize.STRING }) , Task = self.define('Task', { title: Sequelize.STRING })
Task.hasMany(User) Task.hasMany(User)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
task.setUsers([ user ]).success(function() { task.setUsers([ user ]).success(function() {
task.getUsers().success(function(_users) { task.getUsers().success(function(_users) {
expect(_users.length).toEqual(1) expect(_users.length).toEqual(1)
task.setUsers(null).success(function() { task.setUsers(null).success(function() {
task.getUsers().success(function(_users) { task.getUsers().success(function(_users) {
expect(_users.length).toEqual(0) expect(_users.length).toEqual(0)
...@@ -530,17 +565,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -530,17 +565,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
describe("getting assocations with options", function() { describe("getting assocations with options", function() {
before(function(done) { before(function(done) {
var self = this var self = this
this.User = this.sequelize.define('User', { username: Sequelize.STRING }) self.User = self.sequelize.define('User', { username: Sequelize.STRING })
this.Task = this.sequelize.define('Task', { title: Sequelize.STRING, active: Sequelize.BOOLEAN }) self.Task = self.sequelize.define('Task', { title: Sequelize.STRING, active: Sequelize.BOOLEAN })
this.User.hasMany(self.Task) self.User.hasMany(self.Task)
this.sequelize.sync({ force: true }).done(function() { self.User.sync({ force: true }).done(function() {
self.Task.sync({ force: true }).success(function() {
var chainer = new Sequelize.Utils.QueryChainer([ var chainer = new Sequelize.Utils.QueryChainer([
self.User.create({ username: 'John'}), self.User.create({ username: 'John'}),
self.Task.create({ title: 'Get rich', active: true}), self.Task.create({ title: 'Get rich', active: true}),
...@@ -552,6 +589,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -552,6 +589,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
it('should treat the where object of associations as a first class citizen', function(done) { it('should treat the where object of associations as a first class citizen', function(done) {
var self = this var self = this
...@@ -565,7 +603,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -565,7 +603,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
this.Article.hasMany(this.Label) this.Article.hasMany(this.Label)
this.sequelize.sync({ force: true }).success(function() { self.Article.sync({ force: true }).success(function() {
self.Label.sync({ force: true }).success(function() {
var chainer = new Sequelize.Utils.QueryChainer([ var chainer = new Sequelize.Utils.QueryChainer([
self.Article.create({ title: 'Article' }), self.Article.create({ title: 'Article' }),
self.Label.create({ text: 'Awesomeness', until: '2014-01-01 01:00:00' }), self.Label.create({ text: 'Awesomeness', until: '2014-01-01 01:00:00' }),
...@@ -584,6 +623,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -584,6 +623,7 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
it("gets all associated objects when no options are passed", function(done) { it("gets all associated objects when no options are passed", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) { this.User.find({where: {username: 'John'}}).success(function (john) {
...@@ -605,39 +645,45 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -605,39 +645,45 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
describe('optimizations using bulk create, destroy and update', function () { describe('optimizations using bulk create, destroy and update', function () {
before(function (done) { before(function(done) {
this.User = this.sequelize.define('User', { username: Sequelize.STRING }, {timestamps: false}) var self = Object.create(this.sequelize)
this.Task = this.sequelize.define('Task', { title: Sequelize.STRING }, {timestamps: false}) , selfx = this
this.User = self.define('User', { username: Sequelize.STRING }, {timestamps: false})
this.Task = self.define('Task', { title: Sequelize.STRING }, {timestamps: false})
this.User.hasMany(this.Task) this.User.hasMany(this.Task)
this.sequelize.sync({force: true}).success(done) selfx.User.sync({ force: true }).success(function() {
selfx.Task.sync({force: true}).success(done)
})
}) })
it('uses one UPDATE statement', function (done) { it('uses one UPDATE statement', function(done) {
var spy = this.spy() var spy = this.spy()
, self = this
this.User.create({ username: 'foo' }).success(function(user) { this.User.create({ username: 'foo' }).success(function(user) {
this.Task.create({ title: 'task1' }).success(function(task1) { self.Task.create({ title: 'task1' }).success(function(task1) {
this.Task.create({ title: 'task2' }).success(function(task2) { self.Task.create({ title: 'task2' }).success(function(task2) {
user.setTasks([task1, task2]).on('sql', spy).on('sql', _.after(2, function (sql) { // We don't care about SELECt, only UPDAET user.setTasks([task1, task2]).on('sql', spy).on('sql', _.after(2, function (sql) { // We don't care about SELECT, only UPDAET
expect(sql).toMatch("UPDATE") expect(sql).toMatch("UPDATE")
expect(sql).toMatch("IN (1,2)") expect(sql).toMatch("IN (1,2)")
})).success(function () { })).success(function () {
expect(spy).toHaveBeenCalledTwice() // Once for SELECT, once for UPDATE expect(spy).toHaveBeenCalledTwice() // Once for SELECT, once for UPDATE
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it('uses one UPDATE statement', function (done) { it('uses one UPDATE statement', function(done) {
var spy = this.spy() var spy = this.spy()
, self = this
this.User.create({ username: 'foo' }).success(function (user) { this.User.create({ username: 'foo' }).success(function (user) {
this.Task.create({ title: 'task1' }).success(function (task1) { self.Task.create({ title: 'task1' }).success(function (task1) {
this.Task.create({ title: 'task2' }).success(function (task2) { self.Task.create({ title: 'task2' }).success(function (task2) {
user.setTasks([task1, task2]).success(function () { user.setTasks([task1, task2]).success(function () {
user.setTasks(null).on('sql', spy).on('sql', _.after(2, function (sql) { // We don't care about SELECT, only UPDATE user.setTasks(null).on('sql', spy).on('sql', _.after(2, function (sql) { // We don't care about SELECT, only UPDATE
expect(sql).toMatch("UPDATE") expect(sql).toMatch("UPDATE")
...@@ -647,9 +693,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -647,9 +693,9 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
done() done()
}) })
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) // end optimization using bulk create, destroy and update }) // end optimization using bulk create, destroy and update
}) })
...@@ -657,19 +703,21 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -657,19 +703,21 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
describe('(N:M)', function() { describe('(N:M)', function() {
describe("getting assocations with options", function() { describe("getting assocations with options", function() {
before(function(done) { before(function(done) {
var self = this var self = Object.create(this.sequelize)
, selfx = this
this.User = this.sequelize.define('User', { username: Sequelize.STRING }) selfx.User = self.define('User', { username: Sequelize.STRING })
this.Task = this.sequelize.define('Task', { title: Sequelize.STRING, active: Sequelize.BOOLEAN }) selfx.Task = self.define('Task', { title: Sequelize.STRING, active: Sequelize.BOOLEAN })
self.User.hasMany(self.Task) selfx.User.hasMany(selfx.Task)
self.Task.hasMany(self.User) selfx.Task.hasMany(selfx.User)
this.sequelize.sync({ force: true }).done(function() { selfx.User.sync({ force: true }).done(function() {
selfx.Task.sync({ force: true }).success(function() {
var chainer = new Sequelize.Utils.QueryChainer([ var chainer = new Sequelize.Utils.QueryChainer([
self.User.create({ username: 'John'}), selfx.User.create({ username: 'John'}),
self.Task.create({ title: 'Get rich', active: true}), selfx.Task.create({ title: 'Get rich', active: true}),
self.Task.create({ title: 'Die trying', active: false}) selfx.Task.create({ title: 'Die trying', active: false})
]) ])
chainer.run().success(function (results, john, task1, task2) { chainer.run().success(function (results, john, task1, task2) {
...@@ -677,10 +725,11 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -677,10 +725,11 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
})
it("gets all associated objects when no options are passed", function(done) { it("gets all associated objects when no options are passed", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) { this.User.find({where: {username: 'John'}}).success(function(john) {
john.getTasks().success(function (tasks) { john.getTasks().success(function(tasks) {
expect(tasks.length).toEqual(2) expect(tasks.length).toEqual(2)
done() done()
}) })
...@@ -688,8 +737,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -688,8 +737,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
it("only get objects that fulfill the options", function(done) { it("only get objects that fulfill the options", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) { this.User.find({where: {username: 'John'}}).success(function(john) {
john.getTasks({where: {active: true}}).success(function (tasks) { john.getTasks({where: {active: true}}).success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -697,8 +746,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -697,8 +746,8 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
it("only gets objects that fulfill options with a formatted value", function(done) { it("only gets objects that fulfill options with a formatted value", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) { this.User.find({where: {username: 'John'}}).success(function(john) {
john.getTasks({where: ['active = ?', true]}).success(function (tasks) { john.getTasks({where: ['active = ?', true]}).success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -706,20 +755,23 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -706,20 +755,23 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
it("removes the reference id, which was added in the first place", function() { it("removes the reference id, which was added in the first place", function(done) {
var User = this.sequelize.define('User', { username: Sequelize.STRING }) var self = Object.create(this.sequelize)
, Task = this.sequelize.define('Task', { title: Sequelize.STRING }) , User = self.define('User', { username: Sequelize.STRING })
, Task = self.define('Task', { title: Sequelize.STRING })
User.hasMany(Task) User.hasMany(Task)
expect(Task.attributes.UserId).toBeDefined() expect(Task.attributes.UserId).toBeDefined()
Task.hasMany(User) Task.hasMany(User)
expect(Task.attributes.UserId).not.toBeDefined() expect(Task.attributes.UserId).not.toBeDefined()
done()
}) })
it("adds three items to the query chainer when calling sync", function() { it("adds three items to the query chainer when calling sync", function(done) {
var User = this.sequelize.define('User', { username: Sequelize.STRING }) var self = Object.create(this.sequelize)
, Task = this.sequelize.define('Task', { title: Sequelize.STRING }) , User = self.define('User', { username: Sequelize.STRING })
, Task = self.define('Task', { title: Sequelize.STRING })
User.hasMany(Task) User.hasMany(Task)
Task.hasMany(User) Task.hasMany(User)
...@@ -728,19 +780,22 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -728,19 +780,22 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
this.stub(Sequelize.Utils, 'QueryChainer').returns({ add: add, runSerially: function(){} }) this.stub(Sequelize.Utils, 'QueryChainer').returns({ add: add, runSerially: function(){} })
this.sequelize.sync({ force: true }) self.sync({ force: true })
expect(add).toHaveBeenCalledThrice() expect(add).toHaveBeenCalledThrice()
done()
}) })
describe('setAssociations', function() { describe('setAssociations', function() {
it("clears associations when passing null to the set-method", function(done) { it("clears associations when passing null to the set-method", function(done) {
var User = this.sequelize.define('User', { username: Sequelize.STRING }) var self = Object.create(this.sequelize)
, Task = this.sequelize.define('Task', { title: Sequelize.STRING }) , User = self.define('User', { username: Sequelize.STRING })
, Task = self.define('Task', { title: Sequelize.STRING })
User.hasMany(Task) User.hasMany(Task)
Task.hasMany(User) Task.hasMany(User)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
task.setUsers([ user ]).success(function() { task.setUsers([ user ]).success(function() {
...@@ -760,24 +815,23 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -760,24 +815,23 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
describe('optimizations using bulk create, destroy and update', function () {
before(function (done) {
this.User = this.sequelize.define('User', { username: Sequelize.STRING }, {timestamps: false})
this.Task = this.sequelize.define('Task', { title: Sequelize.STRING }, {timestamps: false})
this.User.hasMany(this.Task)
this.Task.hasMany(this.User)
this.sequelize.sync({force: true}).success(done)
}) })
it('uses one insert into statement', function (done) { describe('optimizations using bulk create, destroy and update', function () {
it('uses one insert into statement', function(done) {
var spy = this.spy() var spy = this.spy()
, selfx = Object.create(this.sequelize)
, User = selfx.define('User', { username: Sequelize.STRING }, {timestamps: false})
, Task = selfx.define('Task', { title: Sequelize.STRING }, {timestamps: false})
this.User.create({ username: 'foo' }).success(function(user) { User.hasMany(Task)
this.Task.create({ title: 'task1' }).success(function(task1) { Task.hasMany(User)
this.Task.create({ title: 'task2' }).success(function(task2) {
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task1' }).success(function(task1) {
Task.create({ title: 'task2' }).success(function(task2) {
user.setTasks([task1, task2]).on('sql', spy).on('sql', _.after(2, function (sql) { user.setTasks([task1, task2]).on('sql', spy).on('sql', _.after(2, function (sql) {
expect(sql).toMatch("INSERT INTO") expect(sql).toMatch("INSERT INTO")
expect(sql).toMatch("VALUES (1,1),(2,1)") expect(sql).toMatch("VALUES (1,1),(2,1)")
...@@ -785,17 +839,27 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -785,17 +839,27 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
expect(spy).toHaveBeenCalledTwice() // Once for SELECT, once for INSERT into expect(spy).toHaveBeenCalledTwice() // Once for SELECT, once for INSERT into
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
})
}) })
it('uses one delete from statement', function (done) { it('uses one delete from statement', function(done) {
var spy = this.spy() var spy = this.spy()
, selfx = Object.create(this.sequelize)
, User = selfx.define('User', { username: Sequelize.STRING }, {timestamps: false})
, Task = selfx.define('Task', { title: Sequelize.STRING }, {timestamps: false})
this.User.create({ username: 'foo' }).success(function (user) { User.hasMany(Task)
this.Task.create({ title: 'task1' }).success(function (task1) { Task.hasMany(User)
this.Task.create({ title: 'task2' }).success(function (task2) {
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function (user) {
Task.create({ title: 'task1' }).success(function (task1) {
Task.create({ title: 'task2' }).success(function (task2) {
user.setTasks([task1, task2]).success(function () { user.setTasks([task1, task2]).success(function () {
user.setTasks(null).on('sql', spy).on('sql', _.after(2, function (sql) { user.setTasks(null).on('sql', spy).on('sql', _.after(2, function (sql) {
expect(sql).toMatch("DELETE FROM") expect(sql).toMatch("DELETE FROM")
...@@ -805,14 +869,17 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -805,14 +869,17 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
done() done()
}) })
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
})
}) })
}) // end optimization using bulk create, destroy and update }) // end optimization using bulk create, destroy and update
describe('join table creation', function () { describe('join table creation', function () {
before(function (done) { before(function(done) {
var self = this
this.User = this.sequelize.define('User', this.User = this.sequelize.define('User',
{ username: Sequelize.STRING }, { username: Sequelize.STRING },
{ tableName: 'users'} { tableName: 'users'}
...@@ -827,19 +894,22 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -827,19 +894,22 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
) )
this.Task.hasMany(this.User) this.Task.hasMany(this.User)
this.sequelize.sync({force: true}).success(done) self.User.sync({ force: true }).success(function() {
self.Task.sync({force: true}).success(done)
})
}) })
it('uses the specified joinTableName or a reasonable default', function(done) { it('uses the specified joinTableName or a reasonable default', function(done) {
for (var associationName in this.User.associations) { var self = this
expect(associationName).not.toEqual(this.User.tableName) for (var associationName in self.User.associations) {
expect(associationName).not.toEqual(this.Task.tableName) expect(associationName).not.toEqual(self.User.tableName)
expect(associationName).not.toEqual(self.Task.tableName)
var joinTableName = this.User.associations[associationName].options.joinTableName var joinTableName = self.User.associations[associationName].options.joinTableName
if (typeof joinTableName !== 'undefined') { if (typeof joinTableName !== 'undefined') {
expect(joinTableName).toEqual(associationName) expect(joinTableName).toEqual(associationName)
} }
var tableName = this.User.associations[associationName].options.tableName var tableName = self.User.associations[associationName].options.tableName
if (typeof tableName !== 'undefined') { if (typeof tableName !== 'undefined') {
expect(tableName).toEqual(associationName) expect(tableName).toEqual(associationName)
} }
...@@ -849,150 +919,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() { ...@@ -849,150 +919,19 @@ describe(Helpers.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
describe("Foreign key constraints", function() {
it("are not enabled by default", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasMany(Task)
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTasks([task]).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1)
done()
})
})
})
})
})
})
})
it("can cascade deletes", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasMany(Task, {onDelete: 'cascade'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTasks([task]).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(0)
done()
})
})
})
})
})
})
})
it("can restrict deletes", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasMany(Task, {onDelete: 'restrict'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTasks([task]).success(function() {
user.destroy().error(function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1)
done()
})
})
})
})
})
})
})
it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasMany(Task, {onUpdate: 'cascade'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTasks([task]).success(function() {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.success(function() {
Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1)
expect(tasks[0].UserId).toEqual(999)
done()
})
})
})
})
})
})
})
it("can restrict updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING })
, User = this.sequelize.define('User', { username: Sequelize.STRING })
User.hasMany(Task, {onUpdate: 'restrict'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
user.setTasks([task]).success(function() {
// Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.error(function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks.length).toEqual(1)
done()
})
})
})
})
})
})
})
})
describe("Association options", function() { describe("Association options", function() {
it('can specify data type for autogenerated relational keys', function(done) { it('can specify data type for autogenerated relational keys', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }) var self = Object.create(this.sequelize)
, User = self.define('UserXYZ', { username: Sequelize.STRING })
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING] , dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING]
, self = this
dataTypes.forEach(function(dataType) { dataTypes.forEach(function(dataType) {
var tableName = 'TaskXYZ_' + dataType.toString() var tableName = 'TaskXYZ_' + dataType.toString()
, Task = self.sequelize.define(tableName, { title: Sequelize.STRING }) , Task = self.define(tableName, { title: Sequelize.STRING })
User.hasMany(Task, { foreignKey: 'userId', keyType: dataType }) User.hasMany(Task, { foreignKey: 'userId', keyType: dataType })
self.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
expect(Task.rawAttributes.userId.type.toString()) expect(Task.rawAttributes.userId.type.toString())
.toEqual(dataType.toString()) .toEqual(dataType.toString())
......
/* jshint camelcase: false */ /* jshint camelcase: false */
if (typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Sequelize = require("../../index")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
} , DataTypes = require(__dirname + "/../../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1500 buster.testRunner.timeout = 1500
describe(Helpers.getTestDialectTeaser("HasOne"), function() { describe(Helpers.getTestDialectTeaser("HasOne"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
var self = this var self = this
self.sequelize = Object.create(sequelize)
Helpers.initTests({ Helpers.clearDatabase(self.sequelize, done)
dialect: dialect,
beforeComplete: function(sequelize) { self.sequelize = sequelize },
onComplete: done
})
}) })
describe('general usage', function() { describe('general usage', function() {
before(function(done) { before(function(done) {
this.User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }) var self = this
this.Task = this.sequelize.define('Task', { title: Helpers.Sequelize.STRING }) Helpers.clearDatabase(self.sequelize, function() {
this.sequelize.sync({ force: true }).success(done) self.User = self.sequelize.define('User', { username: DataTypes.STRING })
self.Task = self.sequelize.define('Task', { title: DataTypes.STRING })
self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(done)
})
})
}) })
it("adds the foreign key", function(done) { it("adds the foreign key", function() {
this.User.hasOne(this.Task) var self = this
expect(this.Task.attributes.UserId).toEqual("INTEGER") self.User.hasOne(self.Task)
done() expect(self.Task.attributes.UserId).toEqual("INTEGER")
}) })
it("adds an underscored foreign key", function(done) { it("adds an underscored foreign key", function() {
var User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }, {underscored: true}) var self = this
, Task = this.sequelize.define('Task', { title: Helpers.Sequelize.STRING }) , User = self.sequelize.define('User', { username: DataTypes.STRING }, {underscored: true})
, Task = self.sequelize.define('Task', { title: DataTypes.STRING })
User.hasOne(Task) User.hasOne(Task)
expect(Task.attributes.user_id).toEqual("INTEGER") expect(Task.attributes.user_id).toEqual("INTEGER")
done()
}) })
it("uses the passed foreign key", function(done) { it("uses the passed foreign key", function() {
var User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }, {underscored: true}) var self = this
, Task = this.sequelize.define('Task', { title: Helpers.Sequelize.STRING }) , User = self.sequelize.define('User', { username: DataTypes.STRING }, {underscored: true})
, Task = self.sequelize.define('Task', { title: DataTypes.STRING })
User.hasOne(Task, {foreignKey: 'person_id'}) User.hasOne(Task, {foreignKey: 'person_id'})
expect(Task.attributes.person_id).toEqual("INTEGER") expect(Task.attributes.person_id).toEqual("INTEGER")
done()
}) })
it("defines the getter and the setter", function(done) { it("defines the getter and the setter", function() {
this.User.hasOne(this.Task) var self = this
var u = this.User.build({username: 'asd'}) self.User.hasOne(self.Task)
var u = self.User.build({username: 'asd'})
expect(u.setTask).toBeDefined() expect(u.setTask).toBeDefined()
expect(u.getTask).toBeDefined() expect(u.getTask).toBeDefined()
done()
}) })
it("defined the getter and the setter according to the passed 'as' option", function(done) { it("defined the getter and the setter according to the passed 'as' option", function() {
this.User.hasOne(this.Task, {as: 'Work'}) var self = this
var u = this.User.build({username: 'asd'}) self.User.hasOne(self.Task, {as: 'Work'})
var u = self.User.build({username: 'asd'})
expect(u.setWork).toBeDefined() expect(u.setWork).toBeDefined()
expect(u.getWork).toBeDefined() expect(u.getWork).toBeDefined()
done()
}) })
it("aliases associations to the same table according to the passed 'as' option", function(done) { it("aliases associations to the same table according to the passed 'as' option", function() {
this.User.hasOne(this.Task, {as: 'Work'}); var self = this
this.User.hasOne(this.Task, {as: 'Play'}); self.User.hasOne(self.Task, {as: 'Work'});
self.User.hasOne(self.Task, {as: 'Play'});
var u = this.User.build({username: 'asd'}) var u = self.User.build({username: 'asd'})
expect(u.getWork).toBeDefined() expect(u.getWork).toBeDefined()
expect(u.setWork).toBeDefined() expect(u.setWork).toBeDefined()
expect(u.getPlay).toBeDefined() expect(u.getPlay).toBeDefined()
expect(u.setPlay).toBeDefined() expect(u.setPlay).toBeDefined()
done()
}) })
it("gets and sets the correct objects", function(done) { it("gets and sets the correct objects", function(done) {
var self = this var self = this
this.User.hasOne(this.Task, {as: 'Task'}) self.User.hasOne(self.Task, {as: 'Task'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.create({username: 'name'}).success(function(user) { self.User.create({username: 'name'}).success(function(user) {
self.Task.create({title: 'snafu'}).success(function(task) { self.Task.create({title: 'snafu'}).success(function(task) {
user.setTask(task).on('success', function() { user.setTask(task).on('success', function() {
...@@ -102,12 +104,14 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -102,12 +104,14 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
it("unsets unassociated objects", function(done) { it("unsets unassociated objects", function(done) {
var self = this var self = this
this.User.hasOne(this.Task, {as: 'Task'}) self.User.hasOne(self.Task, {as: 'Task'})
this.sequelize.sync({ force: true }).success(function() { self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.create({username: 'name'}).success(function(user) { self.User.create({username: 'name'}).success(function(user) {
self.Task.create({title: 'snafu'}).success(function(task1) { self.Task.create({title: 'snafu'}).success(function(task1) {
self.Task.create({title: 'another task'}).success(function(task2) { self.Task.create({title: 'another task'}).success(function(task2) {
...@@ -127,13 +131,14 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -127,13 +131,14 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
it("sets self associations", function(done) { it("sets self associations", function(done) {
var Person = this.sequelize.define('Person', { name: Helpers.Sequelize.STRING }) var Person = this.sequelize.define('Person', { name: Helpers.Sequelize.STRING })
Person.hasOne(Person, {as: 'Mother', foreignKey: 'MotherId'}) Person.hasOne(Person, {as: 'Mother', foreignKey: 'MotherId'})
Person.hasOne(Person, {as: 'Father', foreignKey: 'FatherId'}) Person.hasOne(Person, {as: 'Father', foreignKey: 'FatherId'})
Person.sync({force: true}).success(function() { Person.sync({ force: true }).success(function() {
var p = Person.build() var p = Person.build()
expect(p.setFather).toBeDefined() expect(p.setFather).toBeDefined()
expect(p.setMother).toBeDefined() expect(p.setMother).toBeDefined()
...@@ -152,11 +157,13 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -152,11 +157,13 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
describe('getAssocation', function() { describe('getAssocation', function() {
it('should be able to handle a where object that\'s a first class citizen.', function(done) { it('should be able to handle a where object that\'s a first class citizen.', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }) var self = this
, Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING, status: Sequelize.STRING }) , User = self.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, Task = self.sequelize.define('TaskXYZ', { title: DataTypes.STRING, status: DataTypes.STRING })
User.hasOne(Task) User.hasOne(Task)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task', status: 'inactive' }).success(function(task) { Task.create({ title: 'task', status: 'inactive' }).success(function(task) {
user.setTaskXYZ(task).success(function() { user.setTaskXYZ(task).success(function() {
...@@ -170,28 +177,29 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -170,28 +177,29 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
describe('setAssociation', function() { describe('setAssociation', function() {
it('clears the association if null is passed', function(done) { it('clears the association if null is passed', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }) var self = this
, Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING }) , User = self.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, Task = self.sequelize.define('TaskXYZ', { title: DataTypes.STRING })
User.hasOne(Task) User.hasOne(Task)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
user.setTaskXYZ(task).success(function() { user.setTaskXYZ(task).success(function() {
user.getTaskXYZ().success(function(task) { user.getTaskXYZ().success(function(task) {
expect(task).not.toEqual(null) expect(task).not.toEqual(null)
user.setTaskXYZ(null).success(function() { user.setTaskXYZ(null).success(function() {
user.getTaskXYZ().success(function(task) { user.getTaskXYZ().success(function(task) {
expect(task).toEqual(null) expect(task).toEqual(null)
done() done()
}) })
}) })
})
}) })
}) })
}) })
...@@ -201,18 +209,26 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -201,18 +209,26 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
describe("Foreign key constraints", function() { describe("Foreign key constraints", function() {
it("are not enabled by default", function(done) { before(function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) self.sequelize = Object.create(self.sequelize)
Helpers.clearDatabase(self.sequelize, done)
})
it("is not enabled by default", function(done) {
var self = this
, Task = self.sequelize.define('Task1', { title: DataTypes.STRING })
, User = self.sequelize.define('User1', { username: DataTypes.STRING })
User.hasOne(Task) User.hasOne(Task)
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() { user.setTask1(task).success(function() {
user.destroy().success(function() { user.destroy().success(function() {
Task.findAll().success(function(tasks) { Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -222,19 +238,22 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -222,19 +238,22 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
it("can cascade deletes", function(done) { it("can cascade deletes", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) , Task = self.sequelize.define('Task2', { title: DataTypes.STRING })
, User = self.sequelize.define('User2', { username: DataTypes.STRING })
User.hasOne(Task, {onDelete: 'cascade'}) User.hasOne(Task, {onDelete: 'cascade'})
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() { user.setTask2(task).success(function() {
user.destroy().success(function() { user.destroy().success(function() {
Task.findAll().success(function(tasks) { Task.all().success(function(tasks) {
expect(tasks.length).toEqual(0) expect(tasks.length).toEqual(0)
done() done()
}) })
...@@ -244,20 +263,27 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -244,20 +263,27 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
it("can restrict deletes", function(done) { it("can restrict deletes", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) , Task = self.sequelize.define('Task3', { title: DataTypes.STRING })
, User = self.sequelize.define('User3', { username: DataTypes.STRING })
User.hasOne(Task, {onDelete: 'restrict'}) User.hasOne(Task, {onDelete: 'restrict'})
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() { user.setTask3(task).success(function() {
user.destroy().error(function() { user.destroy().success(function() {
expect(false).toEqual('You shouldn\'t reach here.')
done()
})
.error(function() {
// Should fail due to FK restriction // Should fail due to FK restriction
Task.findAll().success(function(tasks) { Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -267,17 +293,20 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -267,17 +293,20 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
it("can cascade updates", function(done) { it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) , Task = self.sequelize.define('Task4', { title: DataTypes.STRING })
, User = self.sequelize.define('User4', { username: DataTypes.STRING })
User.hasOne(Task, {onUpdate: 'cascade'}) User.hasOne(Task, {onUpdate: 'cascade'})
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() { user.setTask4(task).success(function() {
// Changing the id of a DAO requires a little dance since // Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the // the `UPDATE` query generated by `save()` uses `id` in the
...@@ -286,9 +315,9 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -286,9 +315,9 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory) var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id) user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.success(function() { .success(function() {
Task.findAll().success(function(tasks) { Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
expect(tasks[0].UserId).toEqual(999) expect(tasks[0].User4Id).toEqual(999)
done() done()
}) })
}) })
...@@ -297,27 +326,33 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -297,27 +326,33 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
it("can restrict updates", function(done) { it("can restrict updates", function(done) {
var Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
, User = this.sequelize.define('User', { username: Sequelize.STRING }) , Task = self.sequelize.define('Task5', { title: DataTypes.STRING })
, User = self.sequelize.define('User5', { username: DataTypes.STRING })
User.hasOne(Task, {onUpdate: 'restrict'}) User.hasOne(Task, {onUpdate: 'restrict'})
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) { User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
user.setTask(task).success(function() { user.setTask5(task).success(function() {
// Changing the id of a DAO requires a little dance since // Changing the id of a DAO requires a little dance since
// the `UPDATE` query generated by `save()` uses `id` in the // the `UPDATE` query generated by `save()` uses `id` in the
// `WHERE` clause // `WHERE` clause
var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory) var tableName = user.QueryInterface.QueryGenerator.addSchema(user.__factory)
user.QueryInterface.update(user, tableName, {id: 999}, user.id) user.QueryInterface.update(user, tableName, {id: 999}, user.id)
.success(function() {
expect(1).toEqual(2)
done()
})
.error(function() { .error(function() {
// Should fail due to FK restriction // Should fail due to FK restriction
Task.findAll().success(function(tasks) { Task.all().success(function(tasks) {
expect(tasks.length).toEqual(1) expect(tasks.length).toEqual(1)
done() done()
}) })
...@@ -327,22 +362,22 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() { ...@@ -327,22 +362,22 @@ describe(Helpers.getTestDialectTeaser("HasOne"), function() {
}) })
}) })
}) })
})
}) })
describe("Association options", function() { describe("Association options", function() {
it('can specify data type for autogenerated relational keys', function(done) { it('can specify data type for autogenerated relational keys', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING }) var User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING] , dataTypes = [DataTypes.INTEGER, DataTypes.BIGINT, DataTypes.STRING]
, self = this , self = this
dataTypes.forEach(function(dataType) { dataTypes.forEach(function(dataType) {
var tableName = 'TaskXYZ_' + dataType.toString() var tableName = 'TaskXYZ_' + dataType.toString()
, Task = self.sequelize.define(tableName, { title: Sequelize.STRING }) , Task = self.sequelize.define(tableName, { title: DataTypes.STRING })
User.hasOne(Task, { foreignKey: 'userId', keyType: dataType }) User.hasOne(Task, { foreignKey: 'userId', keyType: dataType })
self.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
expect(Task.rawAttributes.userId.type.toString()) expect(Task.rawAttributes.userId.type.toString())
.toEqual(dataType.toString()) .toEqual(dataType.toString())
......
if (typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, Sequelize = require('../../index') , Sequelize = require('../../index')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("Mixin"), function() { describe(Helpers.getTestDialectTeaser("Mixin"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize) {
this.sequelize = sequelize this.sequelize = sequelize
}.bind(this), Helpers.clearDatabase(this.sequelize, done)
onComplete: done
})
}) })
describe('Mixin', function() { describe('Mixin', function() {
var DAOFactory = require("../../lib/dao-factory") var DAOFactory = require("../../lib/dao-factory")
it("adds the mixed-in functions to the dao", function() { it("adds the mixed-in functions to the dao", function(done) {
expect(DAOFactory.prototype.hasOne).toBeDefined() expect(DAOFactory.prototype.hasOne).toBeDefined()
expect(DAOFactory.prototype.hasMany).toBeDefined() expect(DAOFactory.prototype.hasMany).toBeDefined()
expect(DAOFactory.prototype.belongsTo).toBeDefined() expect(DAOFactory.prototype.belongsTo).toBeDefined()
done()
}) })
}) })
describe('getAssociation', function() { describe('getAssociation', function() {
it('returns the respective part of the association for 1:1 associations', function() { it('returns the respective part of the association for 1:1 associations', function(done) {
var User = this.sequelize.define('User', {}) var User = this.sequelize.define('User', {})
var Task = this.sequelize.define('Task', {}) var Task = this.sequelize.define('Task', {})
...@@ -37,6 +34,7 @@ describe(Helpers.getTestDialectTeaser("Mixin"), function() { ...@@ -37,6 +34,7 @@ describe(Helpers.getTestDialectTeaser("Mixin"), function() {
Task.belongsTo(User) Task.belongsTo(User)
expect(User.getAssociation(Task).target).toEqual(Task) expect(User.getAssociation(Task).target).toEqual(Task)
done()
}) })
it('can handle multiple associations just fine', function(done) { it('can handle multiple associations just fine', function(done) {
......
...@@ -6,7 +6,7 @@ module.exports = { ...@@ -6,7 +6,7 @@ module.exports = {
pool: { maxConnections: 5, maxIdleTime: 30000}, pool: { maxConnections: 5, maxIdleTime: 30000},
rand: function() { rand: function() {
return parseInt(Math.random() * 999) return parseInt(Math.random() * 999, 10)
}, },
//make maxIdleTime small so that tests exit promptly //make maxIdleTime small so that tests exit promptly
......
if(typeof require === 'function') {
const buster = require("buster")
, semver = require("semver")
, CustomEventEmitter = require("../lib/emitters/custom-event-emitter")
, Helpers = require('./buster-helpers')
, config = require(__dirname + "/config/config")
, dialect = Helpers.getTestDialect()
}
buster.spec.expose()
buster.testRunner.timeout = 1000
var Sequelize = require(__dirname + '/../index')
, noDomains = semver.lt(process.version, '0.8.0')
describe(Helpers.getTestDialectTeaser("Configuration"), function() {
describe('Connections problems should fail with a nice message', function() {
it('when we don\'t have the correct server details', function(done) {
if (noDomains === true) {
console.log('WARNING: Configuration specs requires NodeJS version >= 0.8 for full compatibility')
expect('').toEqual('') // Silence Buster!
return done()
}
var sequelize = new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {storage: '/path/to/no/where/land', logging: false, host: '0.0.0.1', port: config[dialect].port, dialect: dialect})
, domain = require('domain')
, d = domain.create()
d.on('error', function(err){
var msg = 'Failed to find SQL server. Please double check your settings.'
if (dialect === "postgres" || dialect === "postgres-native") {
msg = 'Failed to find PostgresSQL server. Please double check your settings.'
}
else if (dialect === "mysql") {
msg = 'Failed to find MySQL server. Please double check your settings.'
}
expect(err.message).toEqual(msg)
d.remove(sequelize.query)
done()
})
d.run(function(){
d.add(sequelize.query)
sequelize.query('select 1 as hello')
.success(function(){})
})
})
it('when we don\'t have the correct login information', function(done) {
if (dialect !== "postgres" && dialect !== "postgres-native" && dialect !== "mysql") {
console.log('This dialect doesn\'t support me :(')
expect('').toEqual('') // Silence Buster
return done()
}
if (noDomains === true) {
console.log('WARNING: Configuration specs requires NodeJS version >= 0.8 for full compatibility')
expect('').toEqual('') // Silence Buster!
return done()
}
var sequelize = new Sequelize(config[dialect].database, config[dialect].username, 'fakepass123', {logging: false, host: config[dialect].host, port: 1, dialect: dialect})
, domain = require('domain')
, d = domain.create()
d.on('error', function(err){
var msg = 'Failed to authenticate for SQL. Please double check your settings.'
if (dialect === "postgres" || dialect === "postgres-native") {
msg = 'Failed to authenticate for PostgresSQL. Please double check your settings.'
}
else if (dialect === "mysql") {
msg = 'Failed to authenticate for MySQL. Please double check your settings.'
}
expect(err.message).toEqual(msg)
d.remove(sequelize.query)
done()
})
d.run(function(){
d.add(sequelize.query)
sequelize.query('select 1 as hello')
.success(function(){})
})
})
it('when we don\'t have a valid dialect.', function() {
Helpers.assertException(function() {
new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {host: '0.0.0.1', port: config[dialect].port, dialect: undefined})
}.bind(this), 'The dialect undefined is not supported.')
})
})
describe('Instantiation with a URL string', function() {
it('should accept username, password, host, port, and database', function() {
var sequelize = new Sequelize('mysql://user:pass@example.com:9821/dbname')
var config = sequelize.config
var options = sequelize.options
expect(options.dialect).toEqual('mysql')
expect(config.database).toEqual('dbname')
expect(config.host).toEqual('example.com')
expect(config.username).toEqual('user')
expect(config.password).toEqual('pass')
expect(config.port).toEqual(9821)
})
it('should work with no authentication options', function() {
var sequelize = new Sequelize('mysql://example.com:9821/dbname')
var config = sequelize.config
expect(config.username).toEqual(undefined)
expect(config.password).toEqual(null)
})
it('should use the default port when no other is specified', function() {
var sequelize = new Sequelize('mysql://example.com/dbname')
var config = sequelize.config
// The default port should be set
expect(config.port).toEqual(3306)
})
})
describe('Intantiation with arguments', function() {
it('should accept two parameters (database, username)', function() {
var sequelize = new Sequelize('dbname', 'root')
var config = sequelize.config
expect(config.database).toEqual('dbname')
expect(config.username).toEqual('root')
})
it('should accept three parameters (database, username, password)', function() {
var sequelize = new Sequelize('dbname', 'root', 'pass')
var config = sequelize.config
expect(config.database).toEqual('dbname')
expect(config.username).toEqual('root')
expect(config.password).toEqual('pass')
})
it('should accept four parameters (database, username, password, options)', function() {
var sequelize = new Sequelize('dbname', 'root', 'pass', { port: 999 })
var config = sequelize.config
expect(config.database).toEqual('dbname')
expect(config.username).toEqual('root')
expect(config.password).toEqual('pass')
expect(config.port).toEqual(999)
})
})
})
if(typeof require === 'function') { /* jshint camelcase: false */
const buster = require("buster") var buster = require("buster")
, Sequelize = require("../index") , Sequelize = require("../index")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, _ = require('lodash') , _ = require('lodash')
, moment = require('moment') , moment = require('moment')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
} , DataTypes = require(__dirname + "/../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
before(function(done) { var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
Helpers.initTests({ , User = sequelize.define('User', {
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
this.DataTypes = DataTypes
this.sequelize = sequelize
this.User = sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
secretValue: DataTypes.STRING, secretValue: DataTypes.STRING,
data: DataTypes.STRING, data: DataTypes.STRING,
intVal: DataTypes.INTEGER, intVal: DataTypes.INTEGER,
theDate: DataTypes.DATE theDate: DataTypes.DATE
}) })
}.bind(this),
onComplete: function() { before(function(done) {
this.User.sync({ force: true }).success(done) this.sequelize = Object.create(sequelize)
}.bind(this) this.User = User
var self = this
Helpers.clearDatabase(this.sequelize, function() {
self.User.sync({ force: true }).success(done)
}) })
}) })
describe('constructor', function() { describe('constructor', function() {
it("uses the passed dao name as tablename if freezeTableName", function() { it("uses the passed dao name as tablename if freezeTableName", function(done) {
var User = this.sequelize.define('FrozenUser', {}, { freezeTableName: true }) var User = this.sequelize.define('FrozenUser', {}, { freezeTableName: true })
expect(User.tableName).toEqual('FrozenUser') expect(User.tableName).toEqual('FrozenUser')
done()
}) })
it("uses the pluralized dao name as tablename unless freezeTableName", function() { it("uses the pluralized dao name as tablename unless freezeTableName", function(done) {
var User = this.sequelize.define('SuperUser', {}, { freezeTableName: false }) var User = this.sequelize.define('SuperUser', {}, { freezeTableName: false })
expect(User.tableName).toEqual('SuperUsers') expect(User.tableName).toEqual('SuperUsers')
done()
}) })
it("uses checks to make sure dao factory isnt leaking on multiple define", function() { it("uses checks to make sure dao factory isnt leaking on multiple define", function(done) {
var User = this.sequelize.define('SuperUser', {}, { freezeTableName: false }) this.sequelize.define('SuperUser', {}, { freezeTableName: false })
var factorySize = this.sequelize.daoFactoryManager.all.length var factorySize = this.sequelize.daoFactoryManager.all.length
var User2 = this.sequelize.define('SuperUser', {}, { freezeTableName: false }) this.sequelize.define('SuperUser', {}, { freezeTableName: false })
var factorySize2 = this.sequelize.daoFactoryManager.all.length var factorySize2 = this.sequelize.daoFactoryManager.all.length
expect(factorySize).toEqual(factorySize2) expect(factorySize).toEqual(factorySize2)
done()
}) })
it("attaches class and instance methods", function() { it("attaches class and instance methods", function(done) {
var User = this.sequelize.define('UserWithClassAndInstanceMethods', {}, { var User = this.sequelize.define('UserWithClassAndInstanceMethods', {}, {
classMethods: { doSmth: function(){ return 1 } }, classMethods: { doSmth: function(){ return 1 } },
instanceMethods: { makeItSo: function(){ return 2}} instanceMethods: { makeItSo: function(){ return 2}}
...@@ -65,43 +66,46 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -65,43 +66,46 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(User.build().doSmth).not.toBeDefined() expect(User.build().doSmth).not.toBeDefined()
expect(User.build().makeItSo).toBeDefined() expect(User.build().makeItSo).toBeDefined()
expect(User.build().makeItSo()).toEqual(2) expect(User.build().makeItSo()).toEqual(2)
done()
}) })
it("throws an error if 2 autoIncrements are passed", function() { it("throws an error if 2 autoIncrements are passed", function(done) {
Helpers.assertException(function() { var self = this
this.sequelize.define('UserWithTwoAutoIncrements', { expect(function() {
self.sequelize.define('UserWithTwoAutoIncrements', {
userid: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }, userid: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true } userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }
}) })
}.bind(this), 'Invalid DAO definition. Only one autoincrement field allowed.') }).toThrow('Error', 'Invalid DAO definition. Only one autoincrement field allowed.')
done()
}) })
it('throws an error if a custom model-wide validation is not a function', function() { it('throws an error if a custom model-wide validation is not a function', function(done) {
Helpers.assertException(function() { var self = this
this.sequelize.define('Foo', { expect(function() {
field: { self.sequelize.define('Foo', {
type: Sequelize.INTEGER field: Sequelize.INTEGER
}
}, { }, {
validate: { validate: {
notFunction: 33 notFunction: 33
} }
}) })
}.bind(this), 'Members of the validate option must be functions. Model: Foo, error with validate member notFunction') }).toThrow('Error', 'Members of the validate option must be functions. Model: Foo, error with validate member notFunction')
done()
}) })
it('throws an error if a custom model-wide validation has the same name as a field', function() { it('throws an error if a custom model-wide validation has the same name as a field', function(done) {
Helpers.assertException(function() { var self = this
this.sequelize.define('Foo', { expect(function() {
field: { self.sequelize.define('Foo', {
type: Sequelize.INTEGER field: Sequelize.INTEGER
}
}, { }, {
validate: { validate: {
field: function() {} field: function() {}
} }
}) })
}.bind(this), 'A model validator function must not have the same name as a field. Model: Foo, field/validation name: field') }).toThrow('Error', 'A model validator function must not have the same name as a field. Model: Foo, field/validation name: field')
done()
}) })
}) })
...@@ -114,8 +118,8 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -114,8 +118,8 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
it("fills the objects with default values", function() { it("fills the objects with default values", function(done) {
var Task = this.sequelize.define('Task', { var Task = this.sequelize.define('TaskBuild', {
title: {type: Sequelize.STRING, defaultValue: 'a task!'}, title: {type: Sequelize.STRING, defaultValue: 'a task!'},
foo: {type: Sequelize.INTEGER, defaultValue: 2}, foo: {type: Sequelize.INTEGER, defaultValue: 2},
bar: {type: Sequelize.DATE}, bar: {type: Sequelize.DATE},
...@@ -127,10 +131,11 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -127,10 +131,11 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(Task.build().bar).toEqual(undefined) expect(Task.build().bar).toEqual(undefined)
expect(Task.build().foobar).toEqual('asd') expect(Task.build().foobar).toEqual('asd')
expect(Task.build().flag).toEqual(false) expect(Task.build().flag).toEqual(false)
done()
}) })
it("fills the objects with default values", function() { it("fills the objects with default values", function(done) {
var Task = this.sequelize.define('Task', { var Task = this.sequelize.define('TaskBuild', {
title: {type: Sequelize.STRING, defaultValue: 'a task!'}, title: {type: Sequelize.STRING, defaultValue: 'a task!'},
foo: {type: Sequelize.INTEGER, defaultValue: 2}, foo: {type: Sequelize.INTEGER, defaultValue: 2},
bar: {type: Sequelize.DATE}, bar: {type: Sequelize.DATE},
...@@ -142,92 +147,92 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -142,92 +147,92 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(Task.build().bar).toEqual(undefined) expect(Task.build().bar).toEqual(undefined)
expect(Task.build().foobar).toEqual('asd') expect(Task.build().foobar).toEqual('asd')
expect(Task.build().flag).toEqual(false) expect(Task.build().flag).toEqual(false)
done()
}) })
it("stores the the passed values in a special variable", function() { it("stores the the passed values in a special variable", function(done) {
var user = this.User.build({ username: 'John Wayne' }) var user = this.User.build({ username: 'John Wayne' })
expect(user.selectedValues).toEqual({ username: 'John Wayne' }) expect(user.selectedValues).toEqual({ username: 'John Wayne' })
done()
}) })
it("attaches getter and setter methods from attribute definition", function() { it("attaches getter and setter methods from attribute definition", function(done) {
var Product = this.sequelize.define('ProductWithSettersAndGetters1', { var Product = this.sequelize.define('ProductWithSettersAndGetters1', {
price: { price: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
get : function() { get : function() {
return 'answer = ' + this.getDataValue('price'); return 'answer = ' + this.getDataValue('price')
}, },
set : function(v) { set : function(v) {
return this.setDataValue('price', v + 42); return this.setDataValue('price', v + 42)
} }
} }
},{ })
});
expect(Product.build({price: 42}).price).toEqual('answer = 84');
var p = Product.build({price: 1}); expect(Product.build({price: 42}).price).toEqual('answer = 84')
var p = Product.build({price: 1})
expect(p.price).toEqual('answer = 43'); expect(p.price).toEqual('answer = 43');
p.price = 0; p.price = 0
expect(p.price).toEqual('answer = 42')
expect(p.price).toEqual('answer = 42'); // ah finally the right answer :-) done()
}) })
it("attaches getter and setter methods from options", function() { it("attaches getter and setter methods from options", function(done) {
var Product = this.sequelize.define('ProductWithSettersAndGetters2', { var Product = this.sequelize.define('ProductWithSettersAndGetters2', {
priceInCents: { priceInCents: Sequelize.INTEGER
type: Sequelize.INTEGER
}
},{ },{
setterMethods: { setterMethods: {
price: function(value) { price: function(value) {
this.dataValues.priceInCents = value * 100; this.dataValues.priceInCents = value * 100
} }
}, },
getterMethods: { getterMethods: {
price: function() { price: function() {
return '$' + (this.getDataValue('priceInCents') / 100); return '$' + (this.getDataValue('priceInCents') / 100)
}, },
priceInCents: function() { priceInCents: function() {
return this.dataValues.priceInCents; return this.dataValues.priceInCents
} }
} }
}); });
expect(Product.build({price: 20}).priceInCents).toEqual(20 * 100); expect(Product.build({price: 20}).priceInCents).toEqual(20 * 100)
expect(Product.build({priceInCents: 30 * 100}).price).toEqual('$' + 30); expect(Product.build({priceInCents: 30 * 100}).price).toEqual('$' + 30)
done()
}) })
it("attaches getter and setter methods from options only if not defined in attribute", function() { it("attaches getter and setter methods from options only if not defined in attribute", function(done) {
var Product = this.sequelize.define('ProductWithSettersAndGetters3', { var Product = this.sequelize.define('ProductWithSettersAndGetters3', {
price1: { price1: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
set : function(v) { this.setDataValue('price1', v * 10); } set : function(v) { this.setDataValue('price1', v * 10) }
}, },
price2: { price2: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
get : function(v) { return this.getDataValue('price2') * 10; } get : function() { return this.getDataValue('price2') * 10 }
} }
},{ },{
setterMethods: { setterMethods: {
price1: function(v) { this.setDataValue('price1', v * 100); } price1: function(v) { this.setDataValue('price1', v * 100) }
}, },
getterMethods: { getterMethods: {
price2: function() { return '$' + this.getDataValue('price2'); } price2: function() { return '$' + this.getDataValue('price2') }
} }
}); });
var p = Product.build({ price1: 1, price2: 2 }); var p = Product.build({ price1: 1, price2: 2 })
expect(p.price1).toEqual(10); expect(p.price1).toEqual(10)
expect(p.price2).toEqual(20); expect(p.price2).toEqual(20)
done()
}) })
}) })
describe('findOrCreate', function () { describe('findOrCreate', function () {
it("Returns instace if already existent. Single find field.", function (done) { it("Returns instace if already existent. Single find field.", function(done) {
var self = this, var self = this,
data = { data = {
username: 'Username' username: 'Username'
...@@ -240,13 +245,12 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -240,13 +245,12 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(_user.id).toEqual(user.id) expect(_user.id).toEqual(user.id)
expect(_user.username).toEqual('Username') expect(_user.username).toEqual('Username')
expect(created).toBeFalse() expect(created).toBeFalse()
done() done()
}) })
}) })
}) })
it("Returns instace if already existent. Multiple find fields.", function (done) { it("Returns instace if already existent. Multiple find fields.", function(done) {
var self = this, var self = this,
data = { data = {
username: 'Username', username: 'Username',
...@@ -259,26 +263,23 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -259,26 +263,23 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(_user.username).toEqual('Username') expect(_user.username).toEqual('Username')
expect(_user.data).toEqual('ThisIsData') expect(_user.data).toEqual('ThisIsData')
expect(created).toBeFalse() expect(created).toBeFalse()
done() done()
}) })
}) })
}) })
it("creates new instance with default value.", function (done) { it("creates new instance with default value.", function(done) {
var self = this, var data = {
data = {
username: 'Username' username: 'Username'
}, },
default_values = { default_values = {
data: 'ThisIsData' data: 'ThisIsData'
}; };
this.User.findOrCreate(data, default_values).success(function (user, created) { this.User.findOrCreate(data, default_values).success(function(user, created) {
expect(user.username).toEqual('Username') expect(user.username).toEqual('Username')
expect(user.data).toEqual('ThisIsData') expect(user.data).toEqual('ThisIsData')
expect(created).toBeTrue() expect(created).toBeTrue()
done() done()
}) })
}) })
...@@ -328,23 +329,25 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -328,23 +329,25 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it("raises an error if created object breaks definition contraints", function(done) { it("raises an error if created object breaks definition contraints", function(done) {
var User = this.sequelize.define('UserWithNonNullSmth', { var UserNull = this.sequelize.define('UserWithNonNullSmth', {
username: { type: Sequelize.STRING, unique: true }, username: { type: Sequelize.STRING, unique: true },
smth: { type: Sequelize.STRING, allowNull: false } smth: { type: Sequelize.STRING, allowNull: false }
}) })
User.sync({ force: true }).success(function() { UserNull.sync({ force: true }).success(function() {
User.create({ username: 'foo', smth: null }).error(function(err) { UserNull.create({ username: 'foo', smth: null }).error(function(err) {
expect(err).toBeDefined() expect(err).toBeDefined()
Helpers.checkMatchForDialects(dialect, err.message, { Helpers.checkMatchForDialects(dialect, err.message, {
sqlite: /.*SQLITE_CONSTRAINT.*/, sqlite: /.*SQLITE_CONSTRAINT.*/,
mysql: "Column 'smth' cannot be null", // We need to allow two different errors for MySQL, see:
// http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_trans_tables
mysql: /(Column 'smth' cannot be null|Field 'smth' doesn't have a default value)/,
postgres: /.*column "smth" violates not-null.*/ postgres: /.*column "smth" violates not-null.*/
}) })
User.create({ username: 'foo', smth: 'foo' }).success(function() { UserNull.create({ username: 'foo', smth: 'foo' }).success(function() {
User.create({ username: 'foo', smth: 'bar' }).error(function(err) { UserNull.create({ username: 'foo', smth: 'bar' }).error(function(err) {
expect(err).toBeDefined() expect(err).toBeDefined()
Helpers.checkMatchForDialects(dialect, err.message, { Helpers.checkMatchForDialects(dialect, err.message, {
...@@ -360,18 +363,20 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -360,18 +363,20 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
it('raises an error if you mess up the datatype', function() { it('raises an error if you mess up the datatype', function(done) {
Helpers.assertException(function() { var self = this
this.sequelize.define('UserBadDataType', { expect(function() {
self.sequelize.define('UserBadDataType', {
activity_date: Sequelize.DATe activity_date: Sequelize.DATe
}) })
}.bind(this), 'Unrecognized data type for field activity_date') }).toThrow('Error', 'Unrecognized data type for field activity_date')
Helpers.assertException(function() { expect(function() {
this.sequelize.define('UserBadDataType', { self.sequelize.define('UserBadDataType', {
activity_date: {type: Sequelize.DATe} activity_date: {type: Sequelize.DATe}
}) })
}.bind(this), 'Unrecognized data type for field activity_date') }).toThrow('Error', 'Unrecognized data type for field activity_date')
done()
}) })
it('sets a 64 bit int in bigint', function(done) { it('sets a 64 bit int in bigint', function(done) {
...@@ -470,26 +475,33 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -470,26 +475,33 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
var self = this var self = this
, data = { title: 'Iliad' } , data = { title: 'Iliad' }
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT] , dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT]
, chain = new Sequelize.Utils.QueryChainer()
, chain2 = new Sequelize.Utils.QueryChainer()
, books = []
dataTypes.forEach(function(dataType, index) { dataTypes.forEach(function(dataType, index) {
var Book = self.sequelize.define('Book'+index, { books[index] = self.sequelize.define('Book'+index, {
id: { type: dataType, primaryKey: true, autoIncrement: true }, id: { type: dataType, primaryKey: true, autoIncrement: true },
title: Sequelize.TEXT title: Sequelize.TEXT
}) })
Book.sync({ force: true }).success(function() { })
Book
.create(data) books.forEach(function(b) {
.success(function(book) { chain.add(b.sync({ force: true }))
})
chain.run().success(function() {
books.forEach(function(b) {
chain2.add(b.create(data))
})
chain2.run().success(function(results) {
results.forEach(function(book, index) {
expect(book.title).toEqual(data.title) expect(book.title).toEqual(data.title)
expect(book.author).toEqual(data.author) expect(book.author).toEqual(data.author)
expect(Book.rawAttributes.id.type.toString()) expect(books[index].rawAttributes.id.type.toString())
.toEqual(dataTypes[index].toString()) .toEqual(dataTypes[index].toString())
Book.drop()
if (index >= dataTypes.length - 1) {
done()
}
}) })
done()
}) })
}) })
}) })
...@@ -537,41 +549,38 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -537,41 +549,38 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
it('stores the current date in createdAt', function(done) { it('stores the current date in createdAt', function(done) {
this.User.create({ username: 'foo' }).success(function(user) { this.User.create({ username: 'foo' }).success(function(user) {
expect(parseInt(+user.createdAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+user.createdAt/5000, 10)).toEqual(parseInt(+new Date()/5000, 10))
done() done()
}) })
}) })
it('allows setting custom IDs', function (done) { it('allows setting custom IDs', function(done) {
var self = this
this.User.create({ id: 42 }).success(function (user) { this.User.create({ id: 42 }).success(function (user) {
expect(user.id).toEqual(42) expect(user.id).toEqual(42)
this.User.find(42).success(function (user) { self.User.find(42).success(function (user) {
expect(user).toBeDefined() expect(user).toBeDefined()
done() done()
}) })
}.bind(this)) })
}) })
describe('enums', function() { describe('enums', function() {
before(function(done) { it('correctly restores enum values', function(done) {
this.Item = this.sequelize.define('Item', { var self = this
, Item = self.sequelize.define('Item', {
state: { type: Helpers.Sequelize.ENUM, values: ['available', 'in_cart', 'shipped'] } state: { type: Helpers.Sequelize.ENUM, values: ['available', 'in_cart', 'shipped'] }
}) })
this.sequelize.sync({ force: true }).success(function() { Item.sync({ force: true }).success(function() {
this.Item.create({ state: 'available' }).success(function(item) { Item.create({ state: 'available' }).success(function(_item) {
this.item = item Item.find({ where: { state: 'available' }}).success(function(item) {
expect(item.id).toEqual(_item.id)
done() done()
}.bind(this))
}.bind(this))
}) })
})
it('correctly restores enum values', function(done) { })
this.Item.find({ where: { state: 'available' }}).success(function(item) {
expect(item.id).toEqual(this.item.id)
done()
}.bind(this))
}) })
}) })
}) })
...@@ -586,10 +595,8 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -586,10 +595,8 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.findAll({where: {username: 'Paul'}}).success(function(users) { self.User.findAll({where: {username: 'Paul'}}).success(function(users) {
expect(users.length).toEqual(1) expect(users.length).toEqual(1)
expect(users[0].username).toEqual("Paul") expect(users[0].username).toEqual("Paul")
expect(users[0].secretValue).toBeNull() expect(users[0].secretValue).toBeNull()
done() done()
}) })
}) })
...@@ -603,13 +610,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -603,13 +610,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data, ['username']).success(function() { this.User.bulkCreate(data, ['username']).success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(users[0].secretValue).toBeNull(); expect(users[0].secretValue).toBeNull();
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(users[1].secretValue).toBeNull(); expect(users[1].secretValue).toBeNull();
done() done()
}) })
}) })
...@@ -623,13 +627,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -623,13 +627,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(users[0].secretValue).toEqual('42') expect(users[0].secretValue).toEqual('42')
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(users[1].secretValue).toEqual('23') expect(users[1].secretValue).toEqual('23')
done() done()
}) })
}) })
...@@ -644,13 +645,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -644,13 +645,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(users[0].data).toEqual(quote) expect(users[0].data).toEqual(quote)
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(users[1].data).toEqual(quote) expect(users[1].data).toEqual(quote)
done() done()
}) })
}) })
...@@ -665,13 +663,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -665,13 +663,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(users[0].data).toEqual(quote) expect(users[0].data).toEqual(quote)
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(users[1].data).toEqual(quote) expect(users[1].data).toEqual(quote)
done() done()
}) })
}) })
...@@ -686,13 +681,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -686,13 +681,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(users[0].data).toEqual(json) expect(users[0].data).toEqual(json)
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(users[1].data).toEqual(json) expect(users[1].data).toEqual(json)
done() done()
}) })
}) })
...@@ -706,41 +698,34 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -706,41 +698,34 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(parseInt(+users[0].createdAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+users[0].createdAt/5000, 10)).toEqual(parseInt(+new Date()/5000, 10))
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(parseInt(+users[1].createdAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+users[1].createdAt/5000, 10)).toEqual(parseInt(+new Date()/5000, 10))
done() done()
}) })
}) })
}) })
describe('enums', function() { describe('enums', function() {
before(function(done) { it('correctly restores enum values', function(done) {
this.Item = this.sequelize.define('Item', { var self = this
, Item = self.sequelize.define('Item', {
state: { type: Helpers.Sequelize.ENUM, values: ['available', 'in_cart', 'shipped'] }, state: { type: Helpers.Sequelize.ENUM, values: ['available', 'in_cart', 'shipped'] },
name: Sequelize.STRING name: Sequelize.STRING
}) })
this.sequelize.sync({ force: true }).success(function() { Item.sync({ force: true }).success(function() {
this.Item.bulkCreate([{state: 'in_cart', name: 'A'}, { state: 'available', name: 'B'}]).success(function() { Item.bulkCreate([{state: 'in_cart', name: 'A'}, { state: 'available', name: 'B'}]).success(function() {
done() Item.find({ where: { state: 'available' }}).success(function(item) {
}.bind(this))
}.bind(this))
})
it('correctly restores enum values', function(done) {
this.Item.find({ where: { state: 'available' }}).success(function(item) {
expect(item.name).toEqual('B') expect(item.name).toEqual('B')
done() done()
}.bind(this))
}) })
}) })
})
}) // - bulkCreate })
})
})
describe('update', function() { describe('update', function() {
it('allows sql logging of updated statements', function(done) { it('allows sql logging of updated statements', function(done) {
...@@ -751,7 +736,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -751,7 +736,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
paranoid:true paranoid:true
}) })
this.sequelize.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.create({ name: 'meg', bio: 'none' }).success(function(u) { User.create({ name: 'meg', bio: 'none' }).success(function(u) {
expect(u).toBeDefined() expect(u).toBeDefined()
expect(u).not.toBeNull() expect(u).not.toBeNull()
...@@ -798,9 +783,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -798,9 +783,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
{ username: 'Bob', secretValue: '43' }] { username: 'Bob', secretValue: '43' }]
this.User.bulkCreate(data).success(function() { this.User.bulkCreate(data).success(function() {
self.User.update({username: 'Bill'}, {secretValue: '42'}).success(function() {
self.User.update({username: 'Bill'}, {secretValue: '42'})
.success(function() {
self.User.findAll({order: 'id'}).success(function(users) { self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(3) expect(users.length).toEqual(3)
...@@ -808,29 +791,29 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -808,29 +791,29 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(users[1].username).toEqual("Bill") expect(users[1].username).toEqual("Bill")
expect(users[2].username).toEqual("Bob") expect(users[2].username).toEqual("Bob")
expect(parseInt(+users[0].updatedAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+users[0].updatedAt/5000, 10)).toEqual(parseInt(+new Date()/5000, 10))
expect(parseInt(+users[1].updatedAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+users[1].updatedAt/5000, 10)).toEqual(parseInt(+new Date()/5000, 10))
done() done()
}) })
}) })
}) })
}) })
})
}) // - update
describe('destroy', function() { describe('destroy', function() {
it('deletes a record from the database if dao is not paranoid', function(done) { it('deletes a record from the database if dao is not paranoid', function(done) {
var User = this.sequelize.define('User', { var UserDestroy = this.sequelize.define('UserDestory', {
name: Sequelize.STRING, name: Sequelize.STRING,
bio: Sequelize.TEXT bio: Sequelize.TEXT
}) })
this.sequelize.sync({ force: true }).success(function() {
User.create({name: 'hallo', bio: 'welt'}).success(function(u) { UserDestroy.sync({ force: true }).success(function() {
User.all().success(function(users) { UserDestroy.create({name: 'hallo', bio: 'welt'}).success(function(u) {
UserDestroy.all().success(function(users) {
expect(users.length).toEqual(1) expect(users.length).toEqual(1)
u.destroy().success(function() { u.destroy().success(function() {
User.all().success(function(users) { UserDestroy.all().success(function(users) {
expect(users.length).toEqual(0) expect(users.length).toEqual(0)
done() done()
}) })
...@@ -841,14 +824,14 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -841,14 +824,14 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it('allows sql logging of delete statements', function(done) { it('allows sql logging of delete statements', function(done) {
var User = this.sequelize.define('User', { var UserDelete = this.sequelize.define('UserDelete', {
name: Sequelize.STRING, name: Sequelize.STRING,
bio: Sequelize.TEXT bio: Sequelize.TEXT
}) })
this.sequelize.sync({ force: true }).success(function() { UserDelete.sync({ force: true }).success(function() {
User.create({name: 'hallo', bio: 'welt'}).success(function(u) { UserDelete.create({name: 'hallo', bio: 'welt'}).success(function(u) {
User.all().success(function(users) { UserDelete.all().success(function(users) {
expect(users.length).toEqual(1) expect(users.length).toEqual(1)
u.destroy().on('sql', function(sql) { u.destroy().on('sql', function(sql) {
expect(sql).toBeDefined() expect(sql).toBeDefined()
...@@ -880,7 +863,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -880,7 +863,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
it('sets deletedAt to the current timestamp if paranoid is true', function(done) { it('sets deletedAt to the current timestamp if paranoid is true', function(done) {
var self = this var self = this
, User = this.sequelize.define('ParanoidUser', { , ParanoidUser = self.sequelize.define('ParanoidUser', {
username: Sequelize.STRING, username: Sequelize.STRING,
secretValue: Sequelize.STRING, secretValue: Sequelize.STRING,
data: Sequelize.STRING, data: Sequelize.STRING,
...@@ -892,19 +875,19 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -892,19 +875,19 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
{ username: 'Paul', secretValue: '42' }, { username: 'Paul', secretValue: '42' },
{ username: 'Bob', secretValue: '43' }] { username: 'Bob', secretValue: '43' }]
User.sync({ force: true }).success(function() { ParanoidUser.sync({ force: true }).success(function() {
User.bulkCreate(data).success(function() { ParanoidUser.bulkCreate(data).success(function() {
User.destroy({secretValue: '42'}) var date = parseInt(+new Date()/5000, 10)
.success(function() { ParanoidUser.destroy({secretValue: '42'}).success(function() {
User.findAll({order: 'id'}).success(function(users) { ParanoidUser.findAll({order: 'id'}).success(function(users) {
expect(users.length).toEqual(3) expect(users.length).toEqual(3)
expect(users[0].username).toEqual("Peter") expect(users[0].username).toEqual("Peter")
expect(users[1].username).toEqual("Paul") expect(users[1].username).toEqual("Paul")
expect(users[2].username).toEqual("Bob") expect(users[2].username).toEqual("Bob")
expect(parseInt(+users[0].deletedAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+users[0].deletedAt/5000, 10)).toEqual(date)
expect(parseInt(+users[1].deletedAt/5000)).toEqual(parseInt(+new Date()/5000)) expect(parseInt(+users[1].deletedAt/5000, 10)).toEqual(date)
done() done()
}) })
...@@ -912,7 +895,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -912,7 +895,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
}) })
}) // - destroy })
describe('special where conditions', function() { describe('special where conditions', function() {
before(function(done) { before(function(done) {
...@@ -1124,25 +1107,25 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1124,25 +1107,25 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
describe('find', function find() { describe('find', function() {
describe('general / basic function', function() {
before(function(done) { before(function(done) {
this.User.create({ var self = this
username: 'barfooz' this.User.create({username: 'barfooz'}).success(function(user) {
}).success(function(user) { self.UserPrimary = self.sequelize.define('UserPrimary', {
this.UserPrimary = this.sequelize.define('UserPrimary', {
specialKey: { specialKey: {
type: this.DataTypes.STRING, type: DataTypes.STRING,
primaryKey: true primaryKey: true
} }
}) })
this.UserPrimary.sync({force: true}).success(function(primary){ self.UserPrimary.sync({force: true}).success(function() {
this.UserPrimary.create({specialKey: 'a string'}).success(function(){ self.UserPrimary.create({specialKey: 'a string'}).success(function() {
this.user = user self.user = user
done() done()
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it('doesn\'t throw an error when entering in a non integer value for a specified primary field', function(done) { it('doesn\'t throw an error when entering in a non integer value for a specified primary field', function(done) {
...@@ -1160,21 +1143,23 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1160,21 +1143,23 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it('returns a single dao', function(done) { it('returns a single dao', function(done) {
var self = this
this.User.find(this.user.id).success(function(user) { this.User.find(this.user.id).success(function(user) {
expect(Array.isArray(user)).toBeFalsy() expect(Array.isArray(user)).toBeFalsy()
expect(user.id).toEqual(this.user.id) expect(user.id).toEqual(self.user.id)
expect(user.id).toEqual(1) expect(user.id).toEqual(1)
done() done()
}.bind(this)) })
}) })
it('returns a single dao given a string id', function(done) { it('returns a single dao given a string id', function(done) {
var self = this
this.User.find(this.user.id + '').success(function(user) { this.User.find(this.user.id + '').success(function(user) {
expect(Array.isArray(user)).toBeFalsy() expect(Array.isArray(user)).toBeFalsy()
expect(user.id).toEqual(this.user.id) expect(user.id).toEqual(self.user.id)
expect(user.id).toEqual(1) expect(user.id).toEqual(1)
done() done()
}.bind(this)) })
}) })
it("should make aliased attributes available", function(done) { it("should make aliased attributes available", function(done) {
...@@ -1187,16 +1172,15 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1187,16 +1172,15 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
it("should not try to convert boolean values if they are not selected", function (done) { it("should not try to convert boolean values if they are not selected", function(done) {
var UserWithBoolean = this.sequelize.define('user', { var UserWithBoolean = this.sequelize.define('UserBoolean', {
active: Sequelize.BOOLEAN active: Sequelize.BOOLEAN
}) })
this.sequelize.sync({force: true}).success(function () { UserWithBoolean.sync({force: true}).success(function () {
UserWithBoolean.create({ active: true }).success(function (user) { UserWithBoolean.create({ active: true }).success(function(user) {
UserWithBoolean.find({ where: { id: user.id }, attributes: [ 'id' ] }).success(function (user) { UserWithBoolean.find({ where: { id: user.id }, attributes: [ 'id' ] }).success(function(user) {
expect(user.active).not.toBeDefined() expect(user.active).not.toBeDefined()
done() done()
}) })
}) })
...@@ -1218,8 +1202,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1218,8 +1202,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it('allows sql logging', function(done) { it('allows sql logging', function(done) {
this.User.find({ where: { username: 'foo' } }) this.User.find({ where: { username: 'foo' } }).on('sql', function(sql) {
.on('sql', function(sql) {
expect(sql).toBeDefined() expect(sql).toBeDefined()
expect(sql.toUpperCase().indexOf("SELECT")).toBeGreaterThan(-1) expect(sql.toUpperCase().indexOf("SELECT")).toBeGreaterThan(-1)
done() done()
...@@ -1236,19 +1219,20 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1236,19 +1219,20 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it('finds entries via primary keys', function(done) { it('finds entries via primary keys', function(done) {
var User = this.sequelize.define('UserWithPrimaryKey', { var self = this
, UserPrimary = self.sequelize.define('UserWithPrimaryKey', {
identifier: {type: Sequelize.STRING, primaryKey: true}, identifier: {type: Sequelize.STRING, primaryKey: true},
name: Sequelize.STRING name: Sequelize.STRING
}) })
User.sync({ force: true }).success(function() { UserPrimary.sync({ force: true }).success(function() {
User.create({ UserPrimary.create({
identifier: 'an identifier', identifier: 'an identifier',
name: 'John' name: 'John'
}).success(function(u) { }).success(function(u) {
expect(u.id).not.toBeDefined() expect(u.id).not.toBeDefined()
User.find('an identifier').success(function(u2) { UserPrimary.find('an identifier').success(function(u2) {
expect(u2.identifier).toEqual('an identifier') expect(u2.identifier).toEqual('an identifier')
expect(u2.name).toEqual('John') expect(u2.name).toEqual('John')
done() done()
...@@ -1258,52 +1242,51 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1258,52 +1242,51 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it('returns the selected fields as instance.selectedValues', function(done) { it('returns the selected fields as instance.selectedValues', function(done) {
var self = this
this.User.create({ this.User.create({
username: 'JohnXOXOXO' username: 'JohnXOXOXO'
}).success(function() { }).success(function() {
this.User.find({ self.User.find({
where: { username: 'JohnXOXOXO' }, where: { username: 'JohnXOXOXO' },
attributes: ['username'] attributes: ['username']
}).success(function(user) { }).success(function(user) {
expect(user.selectedValues).toEqual({ username: 'JohnXOXOXO' }) expect(user.selectedValues).toEqual({ username: 'JohnXOXOXO' })
done() done()
}) })
}.bind(this)) })
}) })
it('returns the selected fields and all fields of the included table as instance.selectedValues', function(done) { it('returns the selected fields and all fields of the included table as instance.selectedValues', function(done) {
this.Mission = this.sequelize.define('Mission', { var self = this
self.Mission = self.sequelize.define('Mission', {
title: {type: Sequelize.STRING, defaultValue: 'a mission!!'}, title: {type: Sequelize.STRING, defaultValue: 'a mission!!'},
foo: {type: Sequelize.INTEGER, defaultValue: 2}, foo: {type: Sequelize.INTEGER, defaultValue: 2},
}) })
this.Mission.belongsTo(this.User) self.Mission.belongsTo(self.User)
this.User.hasMany(this.Mission) self.User.hasMany(self.Mission)
this.sequelize.sync({ force: true }).complete(function() { self.Mission.sync({ force: true }).success(function() {
this.Mission.create() self.Mission.create().success(function(mission) {
.success(function(mission) { self.User.create({username: 'John DOE'}).success(function(user) {
this.User.create({ mission.setUser(user).success(function() {
username: 'John DOE' self.User.find({
}).success(function(user) {
mission.setUser(user)
.success(function() {
this.User.find({
where: { username: 'John DOE' }, where: { username: 'John DOE' },
attributes: ['username'], attributes: ['username'],
include: [this.Mission] include: [self.Mission]
}).success(function(user) { }).success(function(user) {
expect(user.selectedValues).toEqual({ username: 'John DOE' }) expect(user.selectedValues).toEqual({ username: 'John DOE' })
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it('always honors ZERO as primary key', function(_done) { it('always honors ZERO as primary key', function(_done) {
var permutations = [ var self = this
, permutations = [
0, 0,
'0', '0',
{where: {id: 0}}, {where: {id: 0}},
...@@ -1311,10 +1294,9 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1311,10 +1294,9 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
] ]
, done = _.after(2 * permutations.length, _done); , done = _.after(2 * permutations.length, _done);
this.User.create({username: 'jack'}).success(function (jack) { this.User.bulkCreate([{username: 'jack'}, {username: 'jack'}]).success(function() {
this.User.create({username: 'jill'}).success(function (jill) {
permutations.forEach(function(perm) { permutations.forEach(function(perm) {
this.User.find(perm).done(function(err, user) { self.User.find(perm).done(function(err, user) {
expect(err).toBeNull(); expect(err).toBeNull();
expect(user).toBeNull(); expect(user).toBeNull();
done(); done();
...@@ -1322,88 +1304,99 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1322,88 +1304,99 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(s.indexOf(0)).not.toEqual(-1); expect(s.indexOf(0)).not.toEqual(-1);
done(); done();
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
describe('eager loading', function() { describe('eager loading', function() {
before(function() { before(function(done) {
this.Task = this.sequelize.define('Task', { title: Sequelize.STRING }) var self = this
this.Worker = this.sequelize.define('Worker', { name: Sequelize.STRING }) self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
this.init = function(callback) { this.init = function(callback) {
this.sequelize.sync({ force: true }).complete(function() { self.Task.sync({ force: true }).success(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) { self.Worker.sync({ force: true }).success(function() {
this.Task.create({ title: 'homework' }).success(function(task) { self.Worker.create({ name: 'worker' }).success(function(worker) {
this.worker = worker self.Task.create({ title: 'homework' }).success(function(task) {
this.task = task self.worker = worker
self.task = task
callback() callback()
}.bind(this))
}.bind(this))
}.bind(this))
}.bind(this)
}) })
})
describe('belongsTo', function() { })
before(function(done) { })
this.Task.belongsTo(this.Worker) }
this.init(function() { done()
this.task.setWorker(this.worker).success(done)
}.bind(this))
}) })
it('throws an error about unexpected input if include contains a non-object', function() { describe('belongsTo', function() {
Helpers.assertException(function() { describe('generic', function() {
this.Worker.find({ include: [ 1 ] }) it('throws an error about unexpected input if include contains a non-object', function(done) {
}.bind(this), 'Include unexpected. Element has to be either an instance of DAOFactory or an object.') var self = this
expect(function() {
self.Worker.find({ include: [ 1 ] })
}).toThrow('Error', 'Include unexpected. Element has to be either an instance of DAOFactory or an object.')
done()
}) })
it('throws an error about missing attributes if include contains an object with daoFactory', function() { it('throws an error about missing attributes if include contains an object with daoFactory', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.find({ include: [ { daoFactory: this.Worker } ] }) expect(function() {
}.bind(this), 'Include malformed. Expected attributes: daoFactory, as!') self.Worker.find({ include: [ { daoFactory: self.Worker } ] })
}).toThrow('Error', 'Include malformed. Expected attributes: daoFactory, as!')
done()
}) })
it('throws an error if included DaoFactory is not associated', function() { it('throws an error if included DaoFactory is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.find({ include: [ this.Task ] }) expect(function() {
}.bind(this), 'Task is not associated to Worker!') self.Worker.find({ include: [ self.Task ] })
}).toThrow('Error', 'Task is not associated to Worker!')
done()
}) })
it('returns the associated worker via task.worker', function(done) { it('returns the associated worker via task.worker', function(done) {
this.Task.find({ var self = this
this.Task.belongsTo(this.Worker)
this.init(function() {
self.task.setWorker(self.worker).success(function() {
self.Task.find({
where: { title: 'homework' }, where: { title: 'homework' },
include: [ this.Worker ] include: [ self.Worker ]
}).complete(function(err, task) { }).complete(function(err, task) {
expect(err).toBeNull() expect(err).toBeNull()
expect(task).toBeDefined() expect(task).toBeDefined()
expect(task.worker).toBeDefined() expect(task.worker).toBeDefined()
expect(task.worker.name).toEqual('worker') expect(task.worker.name).toEqual('worker')
done() done()
}.bind(this)) })
})
})
})
}) })
it('returns the private and public ip', function(done) { it('returns the private and public ip', function(done) {
var Domain = this.sequelize.define('Domain', { ip: Sequelize.STRING }) var self = Object.create(this)
var Environment = this.sequelize.define('Environment', { name: Sequelize.STRING }) self.Domain = self.sequelize.define('Domain', { ip: Sequelize.STRING })
self.Environment = self.sequelize.define('Environment', { name: Sequelize.STRING })
Environment self.Environment
.belongsTo(Domain, { as: 'PrivateDomain', foreignKey: 'privateDomainId' }) .belongsTo(self.Domain, { as: 'PrivateDomain', foreignKey: 'privateDomainId' })
.belongsTo(Domain, { as: 'PublicDomain', foreignKey: 'publicDomainId' }) .belongsTo(self.Domain, { as: 'PublicDomain', foreignKey: 'publicDomainId' })
this.sequelize.sync({ force: true }).complete(function() { self.Domain.sync({ force: true }).success(function() {
Domain.create({ ip: '192.168.0.1' }).success(function(privateIp) { self.Environment.sync({ force: true }).success(function() {
Domain.create({ ip: '91.65.189.19' }).success(function(publicIp) { self.Domain.create({ ip: '192.168.0.1' }).success(function(privateIp) {
Environment.create({ name: 'environment' }).success(function(env) { self.Domain.create({ ip: '91.65.189.19' }).success(function(publicIp) {
self.Environment.create({ name: 'environment' }).success(function(env) {
env.setPrivateDomain(privateIp).success(function() { env.setPrivateDomain(privateIp).success(function() {
env.setPublicDomain(publicIp).success(function() { env.setPublicDomain(publicIp).success(function() {
Environment.find({ self.Environment.find({
where: { name: 'environment' }, where: { name: 'environment' },
include: [ include: [
{ daoFactory: Domain, as: 'PrivateDomain' }, { daoFactory: self.Domain, as: 'PrivateDomain' },
{ daoFactory: Domain, as: 'PublicDomain' } { daoFactory: self.Domain, as: 'PublicDomain' }
] ]
}).complete(function(err, environment) { }).complete(function(err, environment) {
expect(err).toBeNull() expect(err).toBeNull()
...@@ -1422,27 +1415,23 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1422,27 +1415,23 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
}) })
})
describe('hasOne', function() { describe('hasOne', function() {
before(function(done) { before(function(done) {
var self = this
this.Worker.hasOne(this.Task) this.Worker.hasOne(this.Task)
this.init(function() {
this.sequelize.sync({ force: true }).complete(function() { self.worker.setTask(self.task).success(done)
this.Worker.create({ name: 'worker' }).success(function(worker) { })
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.worker.setTask(this.task).success(done)
}.bind(this))
}.bind(this))
}.bind(this))
}) })
it('throws an error if included DaoFactory is not associated', function() { it('throws an error if included DaoFactory is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Task.find({ include: [ this.Worker ] }) expect(function() {
}.bind(this), 'Worker is not associated to Task!') self.Task.find({ include: [ self.Worker ] })
}).toThrow('Error', 'Worker is not associated to Task!')
done()
}) })
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
...@@ -1455,36 +1444,34 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1455,36 +1444,34 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(worker.task).toBeDefined() expect(worker.task).toBeDefined()
expect(worker.task.title).toEqual('homework') expect(worker.task.title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
}) })
describe('hasOne with alias', function() { describe('hasOne with alias', function() {
it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ self.Task ] })
}).toThrow('Error', 'Task is not associated to Worker!')
done()
})
describe('alias', function(done) {
before(function(done) { before(function(done) {
var self = this
this.Worker.hasOne(this.Task, { as: 'ToDo' }) this.Worker.hasOne(this.Task, { as: 'ToDo' })
this.init(function() {
this.sequelize.sync({ force: true }).complete(function() { self.worker.setToDo(self.task).success(done)
this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.worker.setToDo(this.task).success(done)
}.bind(this))
}.bind(this))
}.bind(this))
}) })
it('throws an error if included DaoFactory is not referenced by alias', function() {
Helpers.assertException(function() {
this.Worker.find({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
}) })
it('throws an error if alias is not associated', function() { it('throws an error if alias is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.find({ include: [ { daoFactory: this.Task, as: 'Work' } ] }) expect(function() {
}.bind(this), 'Task (Work) is not associated to Worker!') self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).toThrow('Error', 'Task (Work) is not associated to Worker!')
done()
}) })
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
...@@ -1497,7 +1484,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1497,7 +1484,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(worker.toDo).toBeDefined() expect(worker.toDo).toBeDefined()
expect(worker.toDo.title).toEqual('homework') expect(worker.toDo.title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) { it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
...@@ -1507,30 +1494,26 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1507,30 +1494,26 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}).complete(function(err, worker) { }).complete(function(err, worker) {
expect(worker.toDo.title).toEqual('homework') expect(worker.toDo.title).toEqual('homework')
done() done()
}.bind(this)) })
})
}) })
}) })
describe('hasMany', function() { describe('hasMany', function() {
before(function(done) { before(function(done) {
var self = this
this.Worker.hasMany(this.Task) this.Worker.hasMany(this.Task)
this.init(function() {
this.sequelize.sync({ force: true }).complete(function() { self.worker.setTasks([ self.task ]).success(done)
this.Worker.create({ name: 'worker' }).success(function(worker) { })
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.worker.setTasks([ this.task ]).success(done)
}.bind(this))
}.bind(this))
}.bind(this))
}) })
it('throws an error if included DaoFactory is not associated', function() { it('throws an error if included DaoFactory is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Task.find({ include: [ this.Worker ] }) expect(function() {
}.bind(this), 'Worker is not associated to Task!') self.Task.find({ include: [ self.Worker ] })
}).toThrow('Error', 'Worker is not associated to Task!')
done()
}) })
it('returns the associated tasks via worker.tasks', function(done) { it('returns the associated tasks via worker.tasks', function(done) {
...@@ -1543,36 +1526,34 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1543,36 +1526,34 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(worker.tasks).toBeDefined() expect(worker.tasks).toBeDefined()
expect(worker.tasks[0].title).toEqual('homework') expect(worker.tasks[0].title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
}) })
describe('hasMany with alias', function() { describe('hasMany with alias', function() {
it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ self.Task ] })
}).toThrow('Error', 'Task is not associated to Worker!')
done()
})
describe('alias', function() {
before(function(done) { before(function(done) {
var self = this
this.Worker.hasMany(this.Task, { as: 'ToDos' }) this.Worker.hasMany(this.Task, { as: 'ToDos' })
this.init(function() {
this.sequelize.sync({ force: true }).complete(function() { self.worker.setToDos([ self.task ]).success(done)
this.Worker.create({ name: 'worker' }).success(function(worker) {
this.Task.create({ title: 'homework' }).success(function(task) {
this.worker = worker
this.task = task
this.worker.setToDos([ this.task ]).success(done)
}.bind(this))
}.bind(this))
}.bind(this))
}) })
it('throws an error if included DaoFactory is not referenced by alias', function() {
Helpers.assertException(function() {
this.Worker.find({ include: [ this.Task ] })
}.bind(this), 'Task is not associated to Worker!')
}) })
it('throws an error if alias is not associated', function() { it('throws an error if alias is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.find({ include: [ { daoFactory: this.Task, as: 'Work' } ] }) expect(function() {
}.bind(this), 'Task (Work) is not associated to Worker!') self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).toThrow('Error', 'Task (Work) is not associated to Worker!')
done()
}) })
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
...@@ -1585,7 +1566,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1585,7 +1566,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(worker.toDos).toBeDefined() expect(worker.toDos).toBeDefined()
expect(worker.toDos[0].title).toEqual('homework') expect(worker.toDos[0].title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) { it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
...@@ -1595,87 +1576,95 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1595,87 +1576,95 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}).complete(function(err, worker) { }).complete(function(err, worker) {
expect(worker.toDos[0].title).toEqual('homework') expect(worker.toDos[0].title).toEqual('homework')
done() done()
}.bind(this)) })
})
}) })
}) })
}) })
describe('queryOptions', function() { describe('queryOptions', function() {
before(function(done) { before(function(done) {
var self = this
this.User.create({ this.User.create({
username: 'barfooz' username: 'barfooz'
}).success(function(user) { }).success(function(user) {
this.user = user self.user = user
done() done()
}.bind(this))
}) })
it("should return a DAO when queryOptions are not set", function (done) {
this.User.find({ where: { username: 'barfooz'}}).done(function (err, user) {
expect(user).toHavePrototype(this.User.DAO.prototype)
done();
}.bind(this))
}) })
it("should return a DAO when raw is false", function (done) { it("should return a DAO when queryOptions are not set", function(done) {
this.User.find({ where: { username: 'barfooz'}}, { raw: false }).done(function (err, user) { var self = this
expect(user).toHavePrototype(this.User.DAO.prototype) this.User.find({ where: { username: 'barfooz'}}).done(function(err, user) {
expect(user).toHavePrototype(self.User.DAO.prototype)
done()
})
})
done(); it("should return a DAO when raw is false", function(done) {
}.bind(this)) var self = this
this.User.find({ where: { username: 'barfooz'}}, { raw: false }).done(function(err, user) {
expect(user).toHavePrototype(self.User.DAO.prototype)
done()
})
}) })
it("should return raw data when raw is true", function (done) { it("should return raw data when raw is true", function(done) {
this.User.find({ where: { username: 'barfooz'}}, { raw: true }).done(function (err, user) { var self = this
expect(user).not.toHavePrototype(this.User.DAO.prototype) this.User.find({ where: { username: 'barfooz'}}, { raw: true }).done(function(err, user) {
expect(user).not.toHavePrototype(self.User.DAO.prototype)
expect(user).toBeObject() expect(user).toBeObject()
done()
done(); })
}.bind(this)) })
}) })
}) // - describe: queryOptions
}) //- describe: find
describe('findAll', function findAll() {
describe('eager loading', function() {
before(function() {
this.Task = this.sequelize.define('Task', { title: Sequelize.STRING })
this.Worker = this.sequelize.define('Worker', { name: Sequelize.STRING })
}) })
describe('findAll', function() {
describe('eager loading', function() {
describe('belongsTo', function() { describe('belongsTo', function() {
before(function(done) { before(function(done) {
this.Task.belongsTo(this.Worker) var self = this
self.Task = self.sequelize.define('TaskBelongsTo', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Task.belongsTo(self.Worker)
this.sequelize.sync({ force: true }).complete(function() { self.Worker.sync({ force: true }).success(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) { self.Task.sync({ force: true }).success(function() {
this.Task.create({ title: 'homework' }).success(function(task) { self.Worker.create({ name: 'worker' }).success(function(worker) {
this.worker = worker self.Task.create({ title: 'homework' }).success(function(task) {
this.task = task self.worker = worker
self.task = task
this.task.setWorker(this.worker).success(done) self.task.setWorker(self.worker).success(done)
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
}) })
it('throws an error about unexpected input if include contains a non-object', function() { it('throws an error about unexpected input if include contains a non-object', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ 1 ] }) expect(function() {
}.bind(this), 'Include unexpected. Element has to be either an instance of DAOFactory or an object.') self.Worker.findAll({ include: [ 1 ] })
}).toThrow('Error', 'Include unexpected. Element has to be either an instance of DAOFactory or an object.')
done()
}) })
it('throws an error about missing attributes if include contains an object with daoFactory', function() { it('throws an error about missing attributes if include contains an object with daoFactory', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ { daoFactory: this.Worker } ] }) expect(function() {
}.bind(this), 'Include malformed. Expected attributes: daoFactory, as!') self.Worker.findAll({ include: [ { daoFactory: self.Worker } ] })
}).toThrow('Error', 'Include malformed. Expected attributes: daoFactory, as!')
done()
}) })
it('throws an error if included DaoFactory is not associated', function() { it('throws an error if included DaoFactory is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ this.Task ] }) expect(function() {
}.bind(this), 'Task is not associated to Worker!') self.Worker.findAll({ include: [ self.Task ] })
}).toThrow('Error', 'Task is not associated to Worker!')
done()
}) })
it('returns the associated worker via task.worker', function(done) { it('returns the associated worker via task.worker', function(done) {
...@@ -1688,30 +1677,36 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1688,30 +1677,36 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(tasks[0].worker).toBeDefined() expect(tasks[0].worker).toBeDefined()
expect(tasks[0].worker.name).toEqual('worker') expect(tasks[0].worker.name).toEqual('worker')
done() done()
}.bind(this)) })
}) })
}) })
describe('hasOne', function() { describe('hasOne', function() {
before(function(done) { before(function(done) {
this.Worker.hasOne(this.Task) var self = this
self.Task = self.sequelize.define('TaskHasOne', { title: Sequelize.STRING })
this.sequelize.sync({ force: true }).complete(function() { self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
this.Worker.create({ name: 'worker' }).success(function(worker) { self.Worker.hasOne(self.Task)
this.Task.create({ title: 'homework' }).success(function(task) { self.Worker.sync({ force: true }).success(function() {
this.worker = worker self.Task.sync({ force: true }).success(function() {
this.task = task self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
this.worker.setTask(this.task).success(done) self.worker.setTaskHasOne(self.task).success(done)
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
}) })
it('throws an error if included DaoFactory is not associated', function() { it('throws an error if included DaoFactory is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Task.findAll({ include: [ this.Worker ] }) expect(function() {
}.bind(this), 'Worker is not associated to Task!') self.Task.findAll({ include: [ self.Worker ] })
}).toThrow('Error', 'Worker is not associated to Task!')
done()
}) })
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
...@@ -1721,39 +1716,48 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1721,39 +1716,48 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}).complete(function(err, workers) { }).complete(function(err, workers) {
expect(err).toBeNull() expect(err).toBeNull()
expect(workers).toBeDefined() expect(workers).toBeDefined()
expect(workers[0].task).toBeDefined() expect(workers[0].taskHasOne).toBeDefined()
expect(workers[0].task.title).toEqual('homework') expect(workers[0].taskHasOne.title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
}) })
describe('hasOne with alias', function() { describe('hasOne with alias', function() {
before(function(done) { before(function(done) {
this.Worker.hasOne(this.Task, { as: 'ToDo' }) var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasOne(self.Task, { as: 'ToDo' })
this.sequelize.sync({ force: true }).complete(function() { self.Worker.sync({ force: true }).success(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) { self.Task.sync({ force: true }).success(function() {
this.Task.create({ title: 'homework' }).success(function(task) { self.Worker.create({ name: 'worker' }).success(function(worker) {
this.worker = worker self.Task.create({ title: 'homework' }).success(function(task) {
this.task = task self.worker = worker
self.task = task
this.worker.setToDo(this.task).success(done) self.worker.setToDo(self.task).success(done)
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
}) })
it('throws an error if included DaoFactory is not referenced by alias', function() { it('throws an error if included DaoFactory is not referenced by alias', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ this.Task ] }) expect(function() {
}.bind(this), 'Task is not associated to Worker!') self.Worker.findAll({ include: [ self.Task ] })
}).toThrow('Error', 'Task is not associated to Worker!')
done()
}) })
it('throws an error if alias is not associated', function() { it('throws an error if alias is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ { daoFactory: this.Task, as: 'Work' } ] }) expect(function() {
}.bind(this), 'Task (Work) is not associated to Worker!') self.Worker.findAll({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).toThrow('Error', 'Task (Work) is not associated to Worker!')
done()
}) })
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
...@@ -1766,7 +1770,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1766,7 +1770,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(workers[0].toDo).toBeDefined() expect(workers[0].toDo).toBeDefined()
expect(workers[0].toDo.title).toEqual('homework') expect(workers[0].toDo.title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) { it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
...@@ -1776,30 +1780,37 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1776,30 +1780,37 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}).complete(function(err, workers) { }).complete(function(err, workers) {
expect(workers[0].toDo.title).toEqual('homework') expect(workers[0].toDo.title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
}) })
describe('hasMany', function() { describe('hasMany', function() {
before(function(done) { before(function(done) {
this.Worker.hasMany(this.Task) var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasMany(self.Task)
this.sequelize.sync({ force: true }).complete(function() { self.Worker.sync({ force: true }).success(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) { self.Task.sync({ force: true }).success(function() {
this.Task.create({ title: 'homework' }).success(function(task) { self.Worker.create({ name: 'worker' }).success(function(worker) {
this.worker = worker self.Task.create({ title: 'homework' }).success(function(task) {
this.task = task self.worker = worker
self.task = task
this.worker.setTasks([ this.task ]).success(done) self.worker.setTasks([ self.task ]).success(done)
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
}) })
it('throws an error if included DaoFactory is not associated', function() { it('throws an error if included DaoFactory is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Task.findAll({ include: [ this.Worker ] }) expect(function() {
}.bind(this), 'Worker is not associated to Task!') self.Task.findAll({ include: [ self.Worker ] })
}).toThrow('Error', 'Worker is not associated to Task!')
done()
}) })
it('returns the associated tasks via worker.tasks', function(done) { it('returns the associated tasks via worker.tasks', function(done) {
...@@ -1812,36 +1823,45 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1812,36 +1823,45 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(workers[0].tasks).toBeDefined() expect(workers[0].tasks).toBeDefined()
expect(workers[0].tasks[0].title).toEqual('homework') expect(workers[0].tasks[0].title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
}) })
describe('hasMany with alias', function() { describe('hasMany with alias', function() {
before(function(done) { before(function(done) {
this.Worker.hasMany(this.Task, { as: 'ToDos' }) var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasMany(self.Task, { as: 'ToDos' })
this.sequelize.sync({ force: true }).complete(function() { self.Worker.sync({ force: true }).success(function() {
this.Worker.create({ name: 'worker' }).success(function(worker) { self.Task.sync({ force: true }).success(function() {
this.Task.create({ title: 'homework' }).success(function(task) { self.Worker.create({ name: 'worker' }).success(function(worker) {
this.worker = worker self.Task.create({ title: 'homework' }).success(function(task) {
this.task = task self.worker = worker
self.task = task
this.worker.setToDos([ this.task ]).success(done) self.worker.setToDos([ self.task ]).success(done)
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
})
}) })
it('throws an error if included DaoFactory is not referenced by alias', function() { it('throws an error if included DaoFactory is not referenced by alias', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ this.Task ] }) expect(function() {
}.bind(this), 'Task is not associated to Worker!') self.Worker.findAll({ include: [ self.Task ] })
}).toThrow('Error', 'Task is not associated to Worker!')
done()
}) })
it('throws an error if alias is not associated', function() { it('throws an error if alias is not associated', function(done) {
Helpers.assertException(function() { var self = this
this.Worker.findAll({ include: [ { daoFactory: this.Task, as: 'Work' } ] }) expect(function() {
}.bind(this), 'Task (Work) is not associated to Worker!') self.Worker.findAll({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).toThrow('Error', 'Task (Work) is not associated to Worker!')
done()
}) })
it('returns the associated task via worker.task', function(done) { it('returns the associated task via worker.task', function(done) {
...@@ -1854,7 +1874,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1854,7 +1874,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
expect(workers[0].toDos).toBeDefined() expect(workers[0].toDos).toBeDefined()
expect(workers[0].toDos[0].title).toEqual('homework') expect(workers[0].toDos[0].title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) { it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
...@@ -1864,56 +1884,56 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1864,56 +1884,56 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}).complete(function(err, workers) { }).complete(function(err, workers) {
expect(workers[0].toDos[0].title).toEqual('homework') expect(workers[0].toDos[0].title).toEqual('homework')
done() done()
}.bind(this)) })
}) })
}) })
describe('queryOptions', function() { describe('queryOptions', function() {
before(function(done) { before(function(done) {
var self = this
this.User.create({ this.User.create({
username: 'barfooz' username: 'barfooz'
}).success(function(user) { }).success(function(user) {
this.user = user self.user = user
done() done()
}.bind(this)) })
}) })
it("should return a DAO when queryOptions are not set", function (done) { it("should return a DAO when queryOptions are not set", function(done) {
this.User.findAll({ where: { username: 'barfooz'}}).done(function (err, users) { var self = this
this.User.findAll({ where: { username: 'barfooz'}}).done(function(err, users) {
users.forEach(function (user) { users.forEach(function (user) {
expect(user).toHavePrototype(this.User.DAO.prototype) expect(user).toHavePrototype(self.User.DAO.prototype)
}, this) })
done()
})
done();
}.bind(this))
}) })
it("should return a DAO when raw is false", function (done) { it("should return a DAO when raw is false", function(done) {
this.User.findAll({ where: { username: 'barfooz'}}, { raw: false }).done(function (err, users) { var self = this
this.User.findAll({ where: { username: 'barfooz'}}, { raw: false }).done(function(err, users) {
users.forEach(function (user) { users.forEach(function (user) {
expect(user).toHavePrototype(this.User.DAO.prototype) expect(user).toHavePrototype(self.User.DAO.prototype)
}, this) })
done()
done(); })
}.bind(this))
}) })
it("should return raw data when raw is true", function (done) { it("should return raw data when raw is true", function(done) {
this.User.findAll({ where: { username: 'barfooz'}}, { raw: true }).done(function (err, users) { var self = this
users.forEach(function (user) { this.User.findAll({ where: { username: 'barfooz'}}, { raw: true }).done(function(err, users) {
expect(user).not.toHavePrototype(this.User.DAO.prototype) users.forEach(function(user) {
expect(user).not.toHavePrototype(self.User.DAO.prototype)
expect(users[0]).toBeObject() expect(users[0]).toBeObject()
}, this)
done();
}.bind(this))
}) })
}) // - describe: queryOptions done()
})
})
})
}) })
describe('normal findAll', function() { describe('normal findAll', function() {
beforeEach(function(done) { before(function(done) {
var self = this var self = this
this.User.create({username: 'user', data: 'foobar', theDate: moment().toDate()}).success(function(user) { this.User.create({username: 'user', data: 'foobar', theDate: moment().toDate()}).success(function(user) {
self.User.create({username: 'user2', data: 'bar', theDate: moment().toDate()}).success(function(user2){ self.User.create({username: 'user2', data: 'bar', theDate: moment().toDate()}).success(function(user2){
...@@ -1924,7 +1944,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1924,7 +1944,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it("finds all entries", function(done) { it("finds all entries", function(done) {
this.User.findAll().on('success', function(users) { this.User.all().on('success', function(users) {
expect(users.length).toEqual(2) expect(users.length).toEqual(2)
done() done()
}) })
...@@ -1982,10 +2002,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -1982,10 +2002,10 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
}) })
}) })
}) //- describe: findAll })
describe('findAndCountAll', function() { describe('findAndCountAll', function() {
beforeEach(function(done) { before(function(done) {
var self = this var self = this
this.User.bulkCreate([ this.User.bulkCreate([
{username: 'user', data: 'foobar'}, {username: 'user', data: 'foobar'},
...@@ -2046,7 +2066,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2046,7 +2066,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
describe('all', function() { describe('all', function() {
beforeEach(function(done) { before(function(done) {
this.User.bulkCreate([ this.User.bulkCreate([
{username: 'user', data: 'foobar'}, {username: 'user', data: 'foobar'},
{username: 'user2', data: 'bar'} {username: 'user2', data: 'bar'}
...@@ -2079,7 +2099,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2079,7 +2099,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
bio: Sequelize.TEXT bio: Sequelize.TEXT
}) })
this.sequelize.sync({ force: true }).success(function() { userKeys.sync({ force: true }).success(function() {
userKeys.create({foo: '1', bar: '2', name: 'hallo', bio: 'welt'}).success(function(u) { userKeys.create({foo: '1', bar: '2', name: 'hallo', bio: 'welt'}).success(function(u) {
expect(u.equals(u)).toBeTruthy() expect(u.equals(u)).toBeTruthy()
done() done()
...@@ -2092,7 +2112,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2092,7 +2112,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
describe('equalsOneOf', function() { describe('equalsOneOf', function() {
// sqlite can't handle multiple primary keys // sqlite can't handle multiple primary keys
if (dialect !== "sqlite") { if (dialect !== "sqlite") {
beforeEach(function(done) { before(function(done) {
this.userKey = this.sequelize.define('userKeys', { this.userKey = this.sequelize.define('userKeys', {
foo: {type: Sequelize.STRING, primaryKey: true}, foo: {type: Sequelize.STRING, primaryKey: true},
bar: {type: Sequelize.STRING, primaryKey: true}, bar: {type: Sequelize.STRING, primaryKey: true},
...@@ -2100,7 +2120,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2100,7 +2120,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
bio: Sequelize.TEXT bio: Sequelize.TEXT
}) })
this.sequelize.sync({ force: true }).success(done) this.userKey.sync({ force: true }).success(done)
}) })
it('determines equality if one is matching', function(done) { it('determines equality if one is matching', function(done) {
...@@ -2122,15 +2142,13 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2122,15 +2142,13 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
describe('count', function() { describe('count', function() {
it('counts all created objects', function(done) { it('counts all created objects', function(done) {
var self = this var self = this
this.User.create({username: 'user1'}).success(function() { this.User.bulkCreate([{username: 'user1'}, {username: 'user2'}]).success(function() {
self.User.create({username: 'user2'}).success(function() {
self.User.count().success(function(count) { self.User.count().success(function(count) {
expect(count).toEqual(2) expect(count).toEqual(2)
done() done()
}) })
}) })
}) })
})
it('allows sql logging', function(done) { it('allows sql logging', function(done) {
this.User.count().on('sql', function(sql) { this.User.count().on('sql', function(sql) {
...@@ -2155,6 +2173,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2155,6 +2173,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
describe('min', function() { describe('min', function() {
before(function(done) { before(function(done) {
var self = this
this.UserWithAge = this.sequelize.define('UserWithAge', { this.UserWithAge = this.sequelize.define('UserWithAge', {
age: Sequelize.INTEGER age: Sequelize.INTEGER
}) })
...@@ -2164,19 +2183,18 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2164,19 +2183,18 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
this.UserWithAge.sync({ force: true }).success(function(){ this.UserWithAge.sync({ force: true }).success(function(){
this.UserWithDec.sync({ force: true }).success(done) self.UserWithDec.sync({ force: true }).success(done)
}.bind(this)) })
}) })
it("should return the min value", function(done) { it("should return the min value", function(done) {
this.UserWithAge.create({ age: 2 }).success(function() { var self = this
this.UserWithAge.create({ age: 3 }).success(function() { this.UserWithAge.bulkCreate([{age: 3}, { age: 2 }]).success(function() {
this.UserWithAge.min('age').success(function(min) { self.UserWithAge.min('age').success(function(min) {
expect(min).toEqual(2) expect(min).toEqual(2)
done() done()
}) })
}.bind(this)) })
}.bind(this))
}) })
it('allows sql logging', function(done) { it('allows sql logging', function(done) {
...@@ -2188,19 +2206,19 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2188,19 +2206,19 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
it("should allow decimals in min", function(done){ it("should allow decimals in min", function(done){
this.UserWithDec.create({value: 3.5}).success(function(){ var self = this
this.UserWithDec.create({ value: 5.5 }).success(function(){ this.UserWithDec.bulkCreate([{value: 5.5}, {value: 3.5}]).success(function(){
this.UserWithDec.min('value').success(function(min){ self.UserWithDec.min('value').success(function(min){
expect(min).toEqual(3.5) expect(min).toEqual(3.5)
done() done()
}) })
}.bind(this))
}.bind(this))
}) })
}) //- describe: min })
})
describe('max', function() { describe('max', function() {
before(function(done) { before(function(done) {
var self = this
this.UserWithAge = this.sequelize.define('UserWithAge', { this.UserWithAge = this.sequelize.define('UserWithAge', {
age: Sequelize.INTEGER, age: Sequelize.INTEGER,
order: Sequelize.INTEGER order: Sequelize.INTEGER
...@@ -2211,39 +2229,38 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2211,39 +2229,38 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
}) })
this.UserWithAge.sync({ force: true }).success(function(){ this.UserWithAge.sync({ force: true }).success(function(){
this.UserWithDec.sync({ force: true }).success(done) self.UserWithDec.sync({ force: true }).success(done)
}.bind(this)) })
}) })
it("should return the max value for a field named the same as an SQL reserved keyword", function(done) { it("should return the max value for a field named the same as an SQL reserved keyword", function(done) {
this.UserWithAge.create({age: 3, order: 5}).success(function(){ var self = this
this.UserWithAge.max('order').success(function(max) { this.UserWithAge.bulkCreate([{age: 2, order: 3}, {age: 3, order: 5}]).success(function(){
self.UserWithAge.max('order').success(function(max) {
expect(max).toEqual(5) expect(max).toEqual(5)
done() done()
}) })
}.bind(this)) })
}) })
it("should return the max value", function(done) { it("should return the max value", function(done) {
this.UserWithAge.create({ age: 2 }).success(function() { var self = this
this.UserWithAge.create({ age: 3 }).success(function() { self.UserWithAge.bulkCreate([{age: 2}, {age: 3}]).success(function() {
this.UserWithAge.max('age').success(function(max) { self.UserWithAge.max('age').success(function(max) {
expect(max).toEqual(3) expect(max).toEqual(3)
done() done()
}) })
}.bind(this)) })
}.bind(this))
}) })
it("should allow decimals in max", function(done){ it("should allow decimals in max", function(done) {
this.UserWithDec.create({value: 3.5}).success(function(){ var self = this
this.UserWithDec.create({ value: 5.5 }).success(function(){ this.UserWithDec.bulkCreate([{value: 3.5}, {value: 5.5}]).success(function(){
this.UserWithDec.max('value').success(function(max){ self.UserWithDec.max('value').success(function(max){
expect(max).toEqual(5.5) expect(max).toEqual(5.5)
done() done()
}) })
}.bind(this)) })
}.bind(this))
}) })
it('allows sql logging', function(done) { it('allows sql logging', function(done) {
...@@ -2253,7 +2270,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2253,7 +2270,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
done() done()
}) })
}) })
}) //- describe: max })
describe('schematic support', function() { describe('schematic support', function() {
before(function(done){ before(function(done){
...@@ -2342,35 +2359,31 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2342,35 +2359,31 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
} }
done() done()
}) })
}.bind(this))
}.bind(this))
}.bind(this))
}) })
}) })
})
describe('references', function() { })
before(function() {
this.Author = this.sequelize.define('author', { firstName: Sequelize.STRING })
}) })
describe("use of existing dao factory", function() { describe('references', function() {
before(function() { it('uses an existing dao factory and references the author table', function(done) {
this.Post = this.sequelize.define('post', { var self = this
, Author = self.sequelize.define('author', { firstName: Sequelize.STRING })
, Post = self.sequelize.define('post', {
title: Sequelize.STRING, title: Sequelize.STRING,
authorId: { authorId: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
references: this.Author, references: Author,
referencesKey: "id" referencesKey: "id"
} }
}) })
this.Author.hasMany(this.Post) Author.hasMany(Post)
this.Post.belongsTo(this.Author) Post.belongsTo(Author)
})
it('references the author table', function(done) { Author.sync({ force: true }).success(function() {
this.Author.sync({ force: true }).success(function() { Post.sync({ force: true })
this.Post.sync({ force: true }).on('sql', function(sql) { .on('sql', function(sql) {
if (dialect === 'postgres') { if (dialect === 'postgres') {
expect(sql).toMatch(/"authorId" INTEGER REFERENCES "authors" \("id"\)/) expect(sql).toMatch(/"authorId" INTEGER REFERENCES "authors" \("id"\)/)
} else if (dialect === 'mysql') { } else if (dialect === 'mysql') {
...@@ -2383,13 +2396,14 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2383,13 +2396,14 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
done() done()
}) })
}.bind(this))
}) })
}) })
describe('use of table name as string', function() { it('uses a table name as a string and references the author table', function(done) {
before(function() { this.timeout = 2500
this.Post = this.sequelize.define('post', { var self = this
, Author = self.sequelize.define('author', { firstName: Sequelize.STRING })
, Post = self.sequelize.define('post', {
title: Sequelize.STRING, title: Sequelize.STRING,
authorId: { authorId: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
...@@ -2398,13 +2412,11 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2398,13 +2412,11 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
} }
}) })
this.Author.hasMany(this.Post) Author.hasMany(Post)
this.Post.belongsTo(this.Author) Post.belongsTo(Author)
})
it('references the author table', function(done) { Author.sync( {force: true }).success(function() {
this.Author.sync({ force: true }).success(function() { Post.sync({ force: true }).on('sql', function(sql) {
this.Post.sync({ force: true }).on('sql', function(sql) {
if (dialect === 'postgres') { if (dialect === 'postgres') {
expect(sql).toMatch(/"authorId" INTEGER REFERENCES "authors" \("id"\)/) expect(sql).toMatch(/"authorId" INTEGER REFERENCES "authors" \("id"\)/)
} else if (dialect === 'mysql') { } else if (dialect === 'mysql') {
...@@ -2417,13 +2429,14 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2417,13 +2429,14 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
done() done()
}) })
}.bind(this))
}) })
}) })
describe('use of invalid table name', function() { it("emits an error event as the referenced table name is invalid", function(done) {
before(function() { this.timeout = 2500
this.Post = this.sequelize.define('post', { var self = this
, Author = self.sequelize.define('author', { firstName: Sequelize.STRING })
, Post = self.sequelize.define('post', {
title: Sequelize.STRING, title: Sequelize.STRING,
authorId: { authorId: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
...@@ -2432,15 +2445,11 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2432,15 +2445,11 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
} }
}) })
this.Author.hasMany(this.Post) Author.hasMany(Post)
this.Post.belongsTo(this.Author) Post.belongsTo(Author)
})
it("emits the error event as the referenced table name is invalid", function(done) { Author.sync({ force: true }).success(function() {
this.Author.sync({ force: true }).success(function() { Post.sync({ force: true }).success(function() {
this.Post
.sync({ force: true })
.success(function() {
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
// sorry ... but sqlite is too stupid to understand whats going on ... // sorry ... but sqlite is too stupid to understand whats going on ...
expect(1).toEqual(1) expect(1).toEqual(1)
...@@ -2451,7 +2460,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2451,7 +2460,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
} }
}).error(function(err) { }).error(function(err) {
if (dialect === 'mysql') { if (dialect === 'mysql') {
expect(err.message).toMatch(/ER_CANT_CREATE_TABLE/) expect(err.message).toMatch(/ER_CANNOT_ADD_FOREIGN/)
} else if (dialect === 'sqlite') { } else if (dialect === 'sqlite') {
// the parser should not end up here ... see above // the parser should not end up here ... see above
expect(1).toEqual(2) expect(1).toEqual(2)
...@@ -2463,8 +2472,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() { ...@@ -2463,8 +2472,7 @@ describe(Helpers.getTestDialectTeaser("DAOFactory"), function() {
done() done()
}) })
}.bind(this))
}) })
}) })
}) //- describe: references })
}) })
if (typeof require === 'function') { /* jshint camelcase: false */
const buster = require("buster") var buster = require("buster")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, Sequelize = require("../index")
, config = require(__dirname + "/config/config") , config = require(__dirname + "/config/config")
, DataTypes = require(__dirname + "/../lib/data-types")
, _ = require('lodash') , _ = require('lodash')
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("DAO"), function() { describe(Helpers.getTestDialectTeaser("DAO"), function() {
before(function(done) { var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
var self = this , User = sequelize.define('User', {
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', {
username: { type: DataTypes.STRING }, username: { type: DataTypes.STRING },
touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }, touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
aNumber: { type: DataTypes.INTEGER }, aNumber: { type: DataTypes.INTEGER },
...@@ -41,34 +34,12 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -41,34 +34,12 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
} }
}) })
self.User2 = sequelize.define('User2', { before(function(done) {
username: DataTypes.STRING, var self = this
updatedAt: DataTypes.DATE self.sequelize = Object.create(sequelize)
}, { self.User = User
timestamps: false Helpers.clearDatabase(self.sequelize, function(){
}) self.User.sync({ force: true }).success(done)
self.HistoryLog = sequelize.define('HistoryLog', {
someText: { type: DataTypes.STRING },
aNumber: { type: DataTypes.INTEGER },
aRandomId: { type: DataTypes.INTEGER }
})
self.ParanoidUser = sequelize.define('ParanoidUser', {
username: { type: DataTypes.STRING }
}, {
paranoid: true
})
self.ParanoidUser.hasOne( self.ParanoidUser )
},
onComplete: function() {
self.User.sync({ force: true }).success(function(){
self.HistoryLog.sync({ force: true }).success(function(){
self.ParanoidUser.sync({force: true }).success(done)
})
})
}
}) })
}) })
...@@ -78,6 +49,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -78,6 +49,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
// But this causes sqlite to fail and exits the entire test suite immediately // But this causes sqlite to fail and exits the entire test suite immediately
var bio = dialect + "'\"\n" // Need to add the dialect here so in case of failure I know what DB it failed for var bio = dialect + "'\"\n" // Need to add the dialect here so in case of failure I know what DB it failed for
, self = this , self = this
this.User.create({ username: bio }).success(function(u1) { this.User.create({ username: bio }).success(function(u1) {
self.User.find(u1.id).success(function(u2) { self.User.find(u1.id).success(function(u2) {
expect(u2.username).toEqual(bio) expect(u2.username).toEqual(bio)
...@@ -122,14 +94,14 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -122,14 +94,14 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
it("returns false for objects found by findAll method", function(done) { it("returns false for objects found by findAll method", function(done) {
var chainer = new Sequelize.Utils.QueryChainer() var self = this
, self = this , users = []
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
chainer.add(self.User.create({ username: 'user' })) users[users.length] = {username: 'user'}
} }
chainer.run().success(function() { this.User.bulkCreate(users).success(function() {
self.User.findAll().success(function(users) { self.User.findAll().success(function(users) {
users.forEach(function(u) { users.forEach(function(u) {
expect(u.isNewRecord).toBeFalsy() expect(u.isNewRecord).toBeFalsy()
...@@ -141,226 +113,206 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -141,226 +113,206 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
describe('increment', function () { describe('increment', function () {
before(function (done) { before(function(done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done) this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
}); })
it('with array', function (done) {
var self = this;
// Select something it('with array', function(done) {
this.User.find(1).done(function (err, user1) { var self = this
user1.increment(['aNumber'], 2).done(function (err, user2) { this.User.find(1).done(function(err, user1) {
self.User.find(1).done(function (err, user3) { user1.increment(['aNumber'], 2).done(function() {
expect(user3.aNumber).toBe(2); self.User.find(1).done(function(err, user3) {
done(); expect(user3.aNumber).toBe(2)
}); done()
}); })
}); })
}); })
})
it('with single field', function (done) { it('with single field', function(done) {
var self = this; var self = this
this.User.find(1).done(function(err, user1) {
user1.increment('aNumber', 2).done(function() {
self.User.find(1).done(function(err, user3) {
expect(user3.aNumber).toBe(2)
done()
})
})
})
})
// Select something it('should still work right with other concurrent updates', function(done) {
this.User.find(1).done(function (err, user1) { var self = this
user1.increment('aNumber', 2).done(function (err, user2) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(2);
done();
});
});
});
});
it('should still work right with other concurrent updates', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) { this.User.find(1).done(function (err, user1) {
// Select the user again (simulating a concurrent query) // Select the user again (simulating a concurrent query)
self.User.find(1).done(function (err, user2) { self.User.find(1).done(function (err, user2) {
user2.updateAttributes({ user2.updateAttributes({
aNumber: user2.aNumber + 1 aNumber: user2.aNumber + 1
}).done(function (err, user3) { }).done(function () {
user1.increment(['aNumber'], 2).done(function (err, user4) { user1.increment(['aNumber'], 2).done(function() {
self.User.find(1).done(function (err, user5) { self.User.find(1).done(function(err, user5) {
expect(user5.aNumber).toBe(3); expect(user5.aNumber).toBe(3)
done(); done()
}); })
}); })
}); })
}); })
}); })
});
it('should still work right with other concurrent increments', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
var _done = _.after(3, function () {
self.User.find(1).done(function (err, user2) {
expect(user2.aNumber).toEqual(6);
done();
}) })
});
user1.increment(['aNumber'], 2).done(_done); it('should still work right with other concurrent increments', function(done) {
user1.increment(['aNumber'], 2).done(_done); var self = this
user1.increment(['aNumber'], 2).done(_done); this.User.find(1).done(function(err, user1) {
}); var _done = _.after(3, function() {
}); self.User.find(1).done(function(err, user2) {
expect(user2.aNumber).toEqual(6)
done()
})
})
it('with key value pair', function (done) { user1.increment(['aNumber'], 2).done(_done)
var self = this; user1.increment(['aNumber'], 2).done(_done)
user1.increment(['aNumber'], 2).done(_done)
})
})
// Select something it('with key value pair', function(done) {
this.User.find(1).done(function (err, user1) { var self = this
user1.increment({ 'aNumber': 1, 'bNumber': 2}).done(function (err, user2) { this.User.find(1).done(function(err, user1) {
user1.increment({ 'aNumber': 1, 'bNumber': 2}).done(function() {
self.User.find(1).done(function (err, user3) { self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(1); expect(user3.aNumber).toBe(1)
expect(user3.bNumber).toBe(2); expect(user3.bNumber).toBe(2)
done(); done()
}); })
}); })
}); })
}); })
}); })
describe('decrement', function () { describe('decrement', function () {
before(function (done) { before(function(done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done) this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
}); })
it('with array', function (done) {
var self = this;
// Select something it('with array', function(done) {
this.User.find(1).done(function (err, user1) { var self = this
user1.decrement(['aNumber'], 2).done(function (err, user2) { this.User.find(1).done(function(err, user1) {
self.User.find(1).done(function (err, user3) { user1.decrement(['aNumber'], 2).done(function() {
expect(user3.aNumber).toBe(-2); self.User.find(1).done(function(err, user3) {
done(); expect(user3.aNumber).toBe(-2)
}); done()
}); })
}); })
}); })
})
it('with single field', function (done) { it('with single field', function(done) {
var self = this; var self = this
this.User.find(1).done(function(err, user1) {
user1.decrement('aNumber', 2).done(function() {
self.User.find(1).done(function(err, user3) {
expect(user3.aNumber).toBe(-2)
done()
})
})
})
})
// Select something it('should still work right with other concurrent updates', function(done) {
this.User.find(1).done(function (err, user1) { var self = this
user1.decrement('aNumber', 2).done(function (err, user2) { this.User.find(1).done(function(err, user1) {
self.User.find(1).done(function (err, user3) {
expect(user3.aNumber).toBe(-2);
done();
});
});
});
});
it('should still work right with other concurrent updates', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
// Select the user again (simulating a concurrent query) // Select the user again (simulating a concurrent query)
self.User.find(1).done(function (err, user2) { self.User.find(1).done(function(err, user2) {
user2.updateAttributes({ user2.updateAttributes({
aNumber: user2.aNumber + 1 aNumber: user2.aNumber + 1
}).done(function (err, user3) { }).done(function () {
user1.decrement(['aNumber'], 2).done(function (err, user4) { user1.decrement(['aNumber'], 2).done(function() {
self.User.find(1).done(function (err, user5) { self.User.find(1).done(function(err, user5) {
expect(user5.aNumber).toBe(-1); expect(user5.aNumber).toBe(-1)
done(); done()
}); })
}); })
}); })
}); })
}); })
});
it('should still work right with other concurrent increments', function (done) {
var self = this;
// Select something
this.User.find(1).done(function (err, user1) {
var _done = _.after(3, function () {
self.User.find(1).done(function (err, user2) {
expect(user2.aNumber).toEqual(-6);
done();
}) })
});
user1.decrement(['aNumber'], 2).done(_done); it('should still work right with other concurrent increments', function(done) {
user1.decrement(['aNumber'], 2).done(_done); var self = this
user1.decrement(['aNumber'], 2).done(_done); this.User.find(1).done(function(err, user1) {
}); var _done = _.after(3, function() {
}); self.User.find(1).done(function (err, user2) {
expect(user2.aNumber).toEqual(-6)
done()
})
})
it('with key value pair', function (done) { user1.decrement(['aNumber'], 2).done(_done)
var self = this; user1.decrement(['aNumber'], 2).done(_done)
user1.decrement(['aNumber'], 2).done(_done)
})
})
// Select something it('with key value pair', function(done) {
this.User.find(1).done(function (err, user1) { var self = this
user1.decrement({ 'aNumber': 1, 'bNumber': 2}).done(function (err, user2) { this.User.find(1).done(function(err, user1) {
self.User.find(1).done(function (err, user3) { user1.decrement({ 'aNumber': 1, 'bNumber': 2}).done(function() {
expect(user3.aNumber).toBe(-1); self.User.find(1).done(function(err, user3) {
expect(user3.bNumber).toBe(-2); expect(user3.aNumber).toBe(-1)
done(); expect(user3.bNumber).toBe(-2)
}); done()
}); })
}); })
}); })
}); })
})
describe('reload', function () { describe('reload', function () {
it("should return a reference to the same DAO instead of creating a new one", function (done) { it("should return a reference to the same DAO instead of creating a new one", function(done) {
this.User.create({ username: 'John Doe' }).done(function (err, originalUser) { this.User.create({ username: 'John Doe' }).done(function(err, originalUser) {
originalUser.updateAttributes({ username: 'Doe John' }).done(function() {
originalUser.updateAttributes({ username: 'Doe John' }).done(function () {
originalUser.reload().done(function (err, updatedUser) { originalUser.reload().done(function (err, updatedUser) {
expect(originalUser === updatedUser).toBeTrue() expect(originalUser === updatedUser).toBeTrue()
done(); done()
}) })
}) })
}) })
}) })
it("should update the values on all references to the DAO", function (done) { it("should update the values on all references to the DAO", function(done) {
var self = this var self = this
this.User.create({ username: 'John Doe' }).done(function(err, originalUser) {
this.User.create({ username: 'John Doe' }).done(function (err, originalUser) { self.User.find(originalUser.id).done(function(err, updater) {
self.User.find(originalUser.id).done(function (err, updater) { updater.updateAttributes({ username: 'Doe John' }).done(function() {
updater.updateAttributes({ username: 'Doe John' }).done(function () {
// We used a different reference when calling updateAttributes, so originalUser is now out of sync // We used a different reference when calling updateAttributes, so originalUser is now out of sync
expect(originalUser.username).toEqual('John Doe') expect(originalUser.username).toEqual('John Doe')
originalUser.reload().done(function (err, updatedUser) { originalUser.reload().done(function(err, updatedUser) {
expect(originalUser.username).toEqual('Doe John') expect(originalUser.username).toEqual('Doe John')
expect(updatedUser.username).toEqual('Doe John') expect(updatedUser.username).toEqual('Doe John')
done()
done();
}) })
}) })
}) })
}) })
}) })
it("should update read only attributes as well (updatedAt)", function (done) { it("should update read only attributes as well (updatedAt)", function(done) {
var self = this var self = this
this.timeout = 2000; this.timeout = 2000
this.User.create({ username: 'John Doe' }).done(function (err, originalUser) { this.User.create({ username: 'John Doe' }).done(function(err, originalUser) {
var originallyUpdatedAt = originalUser.updatedAt var originallyUpdatedAt = originalUser.updatedAt
// Wait for a second, so updatedAt will actually be different // Wait for a second, so updatedAt will actually be different
setTimeout(function () { setTimeout(function () {
self.User.find(originalUser.id).done(function (err, updater) { self.User.find(originalUser.id).done(function(err, updater) {
updater.updateAttributes({ username: 'Doe John' }).done(function () { updater.updateAttributes({ username: 'Doe John' }).done(function () {
originalUser.reload().done(function (err, updatedUser) { originalUser.reload().done(function(err, updatedUser) {
expect(originalUser.updatedAt).toBeGreaterThan(originallyUpdatedAt) expect(originalUser.updatedAt).toBeGreaterThan(originallyUpdatedAt)
expect(updatedUser.updatedAt).toBeGreaterThan(originallyUpdatedAt) expect(updatedUser.updatedAt).toBeGreaterThan(originallyUpdatedAt)
done()
done();
}) })
}) })
}) })
...@@ -375,7 +327,8 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -375,7 +327,8 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
Book.hasMany(Page) Book.hasMany(Page)
Page.belongsTo(Book) Page.belongsTo(Book)
this.sequelize.sync({ force: true }).success(function() { Book.sync().success(function() {
Page.sync().success(function() {
Book.create({ title: 'A very old book' }).success(function(book) { Book.create({ title: 'A very old book' }).success(function(book) {
Page.create({ content: 'om nom nom' }).success(function(page) { Page.create({ content: 'om nom nom' }).success(function(page) {
book.setPages([ page ]).success(function() { book.setPages([ page ]).success(function() {
...@@ -390,36 +343,37 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -390,36 +343,37 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
leBook.reload().success(function(leBook) { leBook.reload().success(function(leBook) {
expect(leBook.pages[0].content).toEqual('something totally different') expect(leBook.pages[0].content).toEqual('something totally different')
expect(page.content).toEqual('something totally different') expect(page.content).toEqual('something totally different')
done() done()
}) })
}) })
}) })
}) })
}) })
}.bind(this))
}.bind(this))
}) })
}); })
})
})
})
describe('default values', function() { describe('default values', function() {
describe('current date', function() { describe('current date', function() {
it('should store a date in touchedAt', function() { it('should store a date in touchedAt', function(done) {
var user = this.User.build({ username: 'a user'}) var user = this.User.build({ username: 'a user'})
expect(user.touchedAt instanceof Date).toBeTrue() expect(user.touchedAt instanceof Date).toBeTrue()
done()
}) })
it("should store the current date in touchedAt", function() { it("should store the current date in touchedAt", function(done) {
this.useFakeTimers().tick(5000) this.useFakeTimers().tick(5000)
var user = this.User.build({ username: 'a user'}) var user = this.User.build({ username: 'a user'})
expect(+user.touchedAt).toBe(5000) expect(+user.touchedAt).toBe(5000)
done()
}) })
}) })
describe('allowNull date', function() { describe('allowNull date', function() {
it('should be just "null" and not Date with Invalid Date', function(done) { it('should be just "null" and not Date with Invalid Date', function(done) {
var self = this; var self = this
this.User.build({ username: 'a user'}).save().success(function() { this.User.build({ username: 'a user'}).save().success(function() {
self.User.find({where: {username: 'a user'}}).success(function(user) { self.User.find({where: {username: 'a user'}}).success(function(user) {
expect(user.dateAllowNullTrue).toBe(null) expect(user.dateAllowNullTrue).toBe(null)
...@@ -429,8 +383,8 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -429,8 +383,8 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
it('should be the same valid date when saving the date', function(done) { it('should be the same valid date when saving the date', function(done) {
var self = this; var self = this
var date = new Date(); var date = new Date()
this.User.build({ username: 'a user', dateAllowNullTrue: date}).save().success(function() { this.User.build({ username: 'a user', dateAllowNullTrue: date}).save().success(function() {
self.User.find({where: {username: 'a user'}}).success(function(user) { self.User.find({where: {username: 'a user'}}).success(function(user) {
expect(user.dateAllowNullTrue.toString()).toEqual(date.toString()) expect(user.dateAllowNullTrue.toString()).toEqual(date.toString())
...@@ -443,7 +397,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -443,7 +397,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
describe('complete', function() { describe('complete', function() {
it("gets triggered if an error occurs", function(done) { it("gets triggered if an error occurs", function(done) {
this.User.find({ where: "asdasdasd" }).complete(function(err, result) { this.User.find({ where: "asdasdasd" }).complete(function(err) {
expect(err).toBeDefined() expect(err).toBeDefined()
expect(err.message).toBeDefined() expect(err.message).toBeDefined()
done() done()
...@@ -507,7 +461,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -507,7 +461,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
it("updates the timestamps", function(done) { it("updates the timestamps", function(done) {
this.timeout = 1000 * 5; this.timeout = 1000 * 5
var now = Date.now() var now = Date.now()
, user = null , user = null
, updatedAt = null , updatedAt = null
...@@ -532,13 +486,19 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -532,13 +486,19 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
describe('without timestamps option', function() { describe('without timestamps option', function() {
it("doesn't update the updatedAt column", function(done) { it("doesn't update the updatedAt column", function(done) {
this.User2.create({ username: 'john doe' }).success(function(johnDoe) { var User2 = sequelize.define('User2', {
username: DataTypes.STRING,
updatedAt: DataTypes.DATE
}, { timestamps: false })
User2.sync().success(function() {
User2.create({ username: 'john doe' }).success(function(johnDoe) {
// sqlite and mysql return undefined, whereas postgres returns null // sqlite and mysql return undefined, whereas postgres returns null
expect([undefined, null].indexOf(johnDoe.updatedAt)).not.toBe(-1); expect([undefined, null].indexOf(johnDoe.updatedAt)).not.toBe(-1)
done() done()
}) })
}) })
}) })
})
it('should fail a validation upon creating', function(done){ it('should fail a validation upon creating', function(done){
this.User.create({aNumber: 0, validateTest: 'hello'}).error(function(err){ this.User.create({aNumber: 0, validateTest: 'hello'}).error(function(err){
...@@ -546,9 +506,9 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -546,9 +506,9 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
expect(err).toBeObject() expect(err).toBeObject()
expect(err.validateTest).toBeArray() expect(err.validateTest).toBeArray()
expect(err.validateTest[0]).toBeDefined() expect(err.validateTest[0]).toBeDefined()
expect(err.validateTest[0].indexOf('Invalid integer')).toBeGreaterThan(-1); expect(err.validateTest[0].indexOf('Invalid integer')).toBeGreaterThan(-1)
done(); done()
}); })
}) })
it('should fail a validation upon building', function(done){ it('should fail a validation upon building', function(done){
...@@ -586,90 +546,99 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -586,90 +546,99 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
it('saves a record with no primary key', function(done){ it('saves a record with no primary key', function(done){
this.HistoryLog.create({ someText: 'Some random text', aNumber: 3, aRandomId: 5 }).success(function(log) { var HistoryLog = sequelize.define('HistoryLog', {
someText: { type: DataTypes.STRING },
aNumber: { type: DataTypes.INTEGER },
aRandomId: { type: DataTypes.INTEGER }
})
HistoryLog.sync().success(function() {
HistoryLog.create({ someText: 'Some random text', aNumber: 3, aRandomId: 5 }).success(function(log) {
log.updateAttributes({ aNumber: 5 }).success(function(newLog){ log.updateAttributes({ aNumber: 5 }).success(function(newLog){
expect(newLog.aNumber).toEqual(5) expect(newLog.aNumber).toEqual(5)
done() done()
}) })
}) })
}) })
})
before(function(done) { before(function(done) {
var self = this
this.UserEager = this.sequelize.define('UserEagerLoadingSaves', { this.UserEager = this.sequelize.define('UserEagerLoadingSaves', {
username : Helpers.Sequelize.STRING, username: DataTypes.STRING,
age : Helpers.Sequelize.INTEGER age: DataTypes.INTEGER
}, { timestamps: false }) }, { timestamps: false })
this.ProjectEager = this.sequelize.define('ProjectEagerLoadingSaves', { this.ProjectEager = this.sequelize.define('ProjectEagerLoadingSaves', {
title : Helpers.Sequelize.STRING, title: DataTypes.STRING,
overdue_days: Helpers.Sequelize.INTEGER overdue_days: DataTypes.INTEGER
}, { timestamps: false }) }, { timestamps: false })
this.UserEager.hasMany(this.ProjectEager, { as: 'Projects' }) this.UserEager.hasMany(this.ProjectEager, { as: 'Projects' })
this.ProjectEager.belongsTo(this.UserEager, { as: 'Poobah' }) this.ProjectEager.belongsTo(this.UserEager, { as: 'Poobah' })
this.sequelize.sync({ force: true }).success(done) self.UserEager.sync({force: true}).success(function() {
self.ProjectEager.sync({force: true}).success(done)
})
}) })
it('saves one object that has a collection of eagerly loaded objects', function(done) { it('saves one object that has a collection of eagerly loaded objects', function(done) {
var self = this
this.UserEager.create({ username: 'joe', age: 1 }).success(function(user) { this.UserEager.create({ username: 'joe', age: 1 }).success(function(user) {
this.ProjectEager.create({ title: 'project-joe1', overdue_days: 0 }).success(function(project1) { self.ProjectEager.create({ title: 'project-joe1', overdue_days: 0 }).success(function(project1) {
this.ProjectEager.create({ title: 'project-joe2', overdue_days: 0 }).success(function(project2) { self.ProjectEager.create({ title: 'project-joe2', overdue_days: 0 }).success(function(project2) {
user.setProjects([project1, project2]).success(function() { user.setProjects([project1, project2]).success(function() {
self.UserEager.find({where: {age: 1}, include: [{model: self.ProjectEager, as: 'Projects'}]}).success(function(user) {
this.UserEager.find({where: {age: 1}, include: [{model: this.ProjectEager, as: 'Projects'}]}).success(function(user) {
expect(user.username).toEqual('joe') expect(user.username).toEqual('joe')
expect(user.age).toEqual(1) expect(user.age).toEqual(1)
expect(user.projects).toBeDefined() expect(user.projects).toBeDefined()
expect(user.projects.length).toEqual(2) expect(user.projects.length).toEqual(2)
user.age = user.age + 1; // happy birthday joe user.age = user.age + 1 // happy birthday joe
user.save().success(function(saveduser) { user.save().success(function() {
expect(user.username).toEqual('joe') expect(user.username).toEqual('joe')
expect(user.age).toEqual(2) expect(user.age).toEqual(2)
expect(user.projects).toBeDefined() expect(user.projects).toBeDefined()
expect(user.projects.length).toEqual(2) expect(user.projects.length).toEqual(2)
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it('saves many objects that each a have collection of eagerly loaded objects', function(done) { it('saves many objects that each a have collection of eagerly loaded objects', function(done) {
var self = this
this.UserEager.create({ username: 'bart', age: 20 }).success(function(bart) { this.UserEager.create({ username: 'bart', age: 20 }).success(function(bart) {
this.UserEager.create({ username: 'lisa', age: 20 }).success(function(lisa) { self.UserEager.create({ username: 'lisa', age: 20 }).success(function(lisa) {
self.ProjectEager.create({ title: 'detention1', overdue_days: 0 }).success(function(detention1) {
this.ProjectEager.create({ title: 'detention1', overdue_days: 0 }).success(function(detention1) { self.ProjectEager.create({ title: 'detention2', overdue_days: 0 }).success(function(detention2) {
this.ProjectEager.create({ title: 'detention2', overdue_days: 0 }).success(function(detention2) { self.ProjectEager.create({ title: 'exam1', overdue_days: 0 }).success(function(exam1) {
this.ProjectEager.create({ title: 'exam1', overdue_days: 0 }).success(function(exam1) { self.ProjectEager.create({ title: 'exam2', overdue_days: 0 }).success(function(exam2) {
this.ProjectEager.create({ title: 'exam2', overdue_days: 0 }).success(function(exam2) {
bart.setProjects([detention1, detention2]).success(function() { bart.setProjects([detention1, detention2]).success(function() {
lisa.setProjects([exam1, exam2]).success(function() { lisa.setProjects([exam1, exam2]).success(function() {
this.UserEager.findAll({where: {age: 20}, order: 'username ASC', include: [{model: this.ProjectEager, as: 'Projects'}]}).success(function(simpsons) { self.UserEager.findAll({where: {age: 20}, order: 'username ASC', include: [{model: self.ProjectEager, as: 'Projects'}]}).success(function(simpsons) {
var _bart, _lisa; var _bart, _lisa
expect(simpsons.length).toEqual(2) expect(simpsons.length).toEqual(2)
_bart = simpsons[0]; _bart = simpsons[0]
_lisa = simpsons[1]; _lisa = simpsons[1]
expect(_bart.projects).toBeDefined() expect(_bart.projects).toBeDefined()
expect(_lisa.projects).toBeDefined() expect(_lisa.projects).toBeDefined()
expect(_bart.projects.length).toEqual(2) expect(_bart.projects.length).toEqual(2)
expect(_lisa.projects.length).toEqual(2) expect(_lisa.projects.length).toEqual(2)
_bart.age = _bart.age + 1; // happy birthday bart - off to Moe's _bart.age = _bart.age + 1 // happy birthday bart - off to Moe's
_bart.save().success(function(savedbart) { _bart.save().success(function(savedbart) {
expect(savedbart.username).toEqual('bart') expect(savedbart.username).toEqual('bart')
expect(savedbart.age).toEqual(21) expect(savedbart.age).toEqual(21)
_lisa.username = 'lsimpson'; _lisa.username = 'lsimpson'
_lisa.save().success(function(savedlisa) { _lisa.save().success(function(savedlisa) {
expect(savedlisa.username).toEqual('lsimpson') expect(savedlisa.username).toEqual('lsimpson')
...@@ -679,22 +648,23 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -679,22 +648,23 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
}) })
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it('saves many objects that each has one eagerly loaded object (to which they belong)', function(done) { it('saves many objects that each has one eagerly loaded object (to which they belong)', function(done) {
var self = this
this.UserEager.create({ username: 'poobah', age: 18 }).success(function(user) { this.UserEager.create({ username: 'poobah', age: 18 }).success(function(user) {
this.ProjectEager.create({ title: 'homework', overdue_days: 10 }).success(function(homework) { self.ProjectEager.create({ title: 'homework', overdue_days: 10 }).success(function(homework) {
this.ProjectEager.create({ title: 'party', overdue_days: 2 }).success(function(party) { self.ProjectEager.create({ title: 'party', overdue_days: 2 }).success(function(party) {
user.setProjects([homework, party]).success(function() { user.setProjects([homework, party]).success(function() {
this.ProjectEager.findAll({include: [{model: this.UserEager, as: 'Poobah'}]}).success(function(projects) { self.ProjectEager.findAll({include: [{model: self.UserEager, as: 'Poobah'}]}).success(function(projects) {
expect(projects.length).toEqual(2) expect(projects.length).toEqual(2)
expect(projects[0].poobah).toBeDefined() expect(projects[0].poobah).toBeDefined()
...@@ -702,14 +672,14 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -702,14 +672,14 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
expect(projects[0].poobah.username).toEqual('poobah') expect(projects[0].poobah.username).toEqual('poobah')
expect(projects[1].poobah.username).toEqual('poobah') expect(projects[1].poobah.username).toEqual('poobah')
projects[0].title = 'partymore'; projects[0].title = 'partymore'
projects[1].title = 'partymore'; projects[1].title = 'partymore'
projects[0].overdue_days = 0; projects[0].overdue_days = 0
projects[1].overdue_days = 0; projects[1].overdue_days = 0
projects[0].save().success(function() { projects[0].save().success(function() {
projects[1].save().success(function() { projects[1].save().success(function() {
this.ProjectEager.findAll({where: {title: 'partymore', overdue_days: 0}, include: [{model: this.UserEager, as: 'Poobah'}]}).success(function(savedprojects) { self.ProjectEager.findAll({where: {title: 'partymore', overdue_days: 0}, include: [{model: self.UserEager, as: 'Poobah'}]}).success(function(savedprojects) {
expect(savedprojects.length).toEqual(2) expect(savedprojects.length).toEqual(2)
expect(savedprojects[0].poobah).toBeDefined() expect(savedprojects[0].poobah).toBeDefined()
...@@ -719,18 +689,19 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -719,18 +689,19 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) })
describe('toJSON', function toJSON() { describe('toJSON', function() {
before(function(done) { before(function(done) {
var self = this
this.User = this.sequelize.define('UserWithUsernameAndAgeAndIsAdmin', { this.User = this.sequelize.define('UserWithUsernameAndAgeAndIsAdmin', {
username: Helpers.Sequelize.STRING, username: Helpers.Sequelize.STRING,
age: Helpers.Sequelize.INTEGER, age: Helpers.Sequelize.INTEGER,
...@@ -742,35 +713,41 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -742,35 +713,41 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
this.User.hasMany(this.Project, { as: 'Projects' }) this.User.hasMany(this.Project, { as: 'Projects' })
this.Project.belongsTo(this.User, { as: 'LovelyUser' }) this.Project.belongsTo(this.User, { as: 'LovelyUser' })
this.sequelize.sync({ force: true }).success(done) this.User.sync({ force: true }).success(function() {
self.Project.sync({ force: true }).success(done)
})
}) })
it('returns an object containing all values', function() { it('returns an object containing all values', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true }) var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(user.toJSON()).toEqual({ username: 'test.user', age: 99, isAdmin: true, id: null }) expect(user.toJSON()).toEqual({ username: 'test.user', age: 99, isAdmin: true, id: null })
done()
}) })
it('returns a response that can be stringified', function() { it('returns a response that can be stringified', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true }) var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(JSON.stringify(user)).toEqual('{"username":"test.user","age":99,"isAdmin":true,"id":null}') expect(JSON.stringify(user)).toEqual('{"username":"test.user","age":99,"isAdmin":true,"id":null}')
done()
}) })
it('returns a response that can be stringified and then parsed', function() { it('returns a response that can be stringified and then parsed', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true }) var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(JSON.parse(JSON.stringify(user))).toEqual({ username: 'test.user', age: 99, isAdmin: true, id: null }) expect(JSON.parse(JSON.stringify(user))).toEqual({ username: 'test.user', age: 99, isAdmin: true, id: null })
done()
}) })
it('includes the eagerly loaded associations', function(done) { it('includes the eagerly loaded associations', function(done) {
var self = this
this.User.create({ username: 'fnord', age: 1, isAdmin: true }).success(function(user) { this.User.create({ username: 'fnord', age: 1, isAdmin: true }).success(function(user) {
this.Project.create({ title: 'fnord' }).success(function(project) { self.Project.create({ title: 'fnord' }).success(function(project) {
user.setProjects([ project ]).success(function() { user.setProjects([ project ]).success(function() {
this.User.findAll({include: [ { model: this.Project, as: 'Projects' } ]}).success(function(users) { self.User.findAll({include: [ { model: self.Project, as: 'Projects' } ]}).success(function(users) {
var _user = users[0] var _user = users[0]
expect(_user.projects).toBeDefined() expect(_user.projects).toBeDefined()
expect(JSON.parse(JSON.stringify(_user)).projects).toBeDefined() expect(JSON.parse(JSON.stringify(_user)).projects).toBeDefined()
this.Project.findAll({include: [ { model: this.User, as: 'LovelyUser' } ]}).success(function(projects) { self.Project.findAll({include: [ { model: self.User, as: 'LovelyUser' } ]}).success(function(projects) {
var _project = projects[0] var _project = projects[0]
expect(_project.lovelyUser).toBeDefined() expect(_project.lovelyUser).toBeDefined()
...@@ -778,14 +755,23 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -778,14 +755,23 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) })
describe('findAll', function findAll() { describe('findAll', function() {
before(function(done) {
this.ParanoidUser = sequelize.define('ParanoidUser', {
username: { type: DataTypes.STRING }
}, { paranoid: true })
this.ParanoidUser.hasOne(this.ParanoidUser)
this.ParanoidUser.sync({ force: true }).success(done)
})
it("escapes a single single quotes properly in where clauses", function(done) { it("escapes a single single quotes properly in where clauses", function(done) {
var self = this var self = this
...@@ -819,113 +805,120 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -819,113 +805,120 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
}) })
it("returns the timestamps if no attributes have been specified", function(done) { it("returns the timestamps if no attributes have been specified", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() { this.User.create({ username: 'fnord' }).success(function() {
this.User.findAll().success(function(users) { self.User.findAll().success(function(users) {
expect(users[0].createdAt).toBeDefined() expect(users[0].createdAt).toBeDefined()
done() done()
}.bind(this)) })
}.bind(this)) })
}) })
it("does not return the timestamps if the username attribute has been specified", function(done) { it("does not return the timestamps if the username attribute has been specified", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() { this.User.create({ username: 'fnord' }).success(function() {
this.User.findAll({ attributes: ['username'] }).success(function(users) { self.User.findAll({ attributes: ['username'] }).success(function(users) {
expect(users[0].createdAt).not.toBeDefined() expect(users[0].createdAt).not.toBeDefined()
expect(users[0].username).toBeDefined() expect(users[0].username).toBeDefined()
done() done()
}.bind(this)) })
}.bind(this)) })
}) })
it("creates the deletedAt property, when defining paranoid as true", function(done) { it("creates the deletedAt property, when defining paranoid as true", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() { this.ParanoidUser.create({ username: 'fnord' }).success(function() {
this.ParanoidUser.findAll().success(function(users) { self.ParanoidUser.findAll().success(function(users) {
expect(users[0].deletedAt).toBeDefined() expect(users[0].deletedAt).toBeDefined()
expect(users[0].deletedAt).toBe(null) expect(users[0].deletedAt).toBe(null)
done() done()
}.bind(this)) })
}.bind(this)) })
}) })
it("sets deletedAt property to a specific date when deleting an instance", function(done) { it("sets deletedAt property to a specific date when deleting an instance", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() { this.ParanoidUser.create({ username: 'fnord' }).success(function() {
this.ParanoidUser.findAll().success(function(users) { self.ParanoidUser.findAll().success(function(users) {
users[0].destroy().success(function(user) { users[0].destroy().success(function(user) {
expect(user.deletedAt.getMonth).toBeDefined() expect(user.deletedAt.getMonth).toBeDefined()
done() done()
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it("keeps the deletedAt-attribute with value null, when running updateAttributes", function(done) { it("keeps the deletedAt-attribute with value null, when running updateAttributes", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() { this.ParanoidUser.create({ username: 'fnord' }).success(function() {
this.ParanoidUser.findAll().success(function(users) { self.ParanoidUser.findAll().success(function(users) {
users[0].updateAttributes({username: 'newFnord'}).success(function(user) { users[0].updateAttributes({username: 'newFnord'}).success(function(user) {
expect(user.deletedAt).toBe(null) expect(user.deletedAt).toBe(null)
done() done()
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it("keeps the deletedAt-attribute with value null, when updating associations", function(done) { it("keeps the deletedAt-attribute with value null, when updating associations", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() { this.ParanoidUser.create({ username: 'fnord' }).success(function() {
this.ParanoidUser.findAll().success(function(users) { self.ParanoidUser.findAll().success(function(users) {
this.ParanoidUser.create({ username: 'linkedFnord' }).success(function( linkedUser ) { self.ParanoidUser.create({ username: 'linkedFnord' }).success(function(linkedUser) {
users[0].setParanoidUser( linkedUser ).success(function(user) { users[0].setParanoidUser( linkedUser ).success(function(user) {
expect(user.deletedAt).toBe(null) expect(user.deletedAt).toBe(null)
done() done()
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
it("can reuse query option objects", function(done) { it("can reuse query option objects", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() { this.User.create({ username: 'fnord' }).success(function() {
var query = { where: { username: 'fnord' }} var query = { where: { username: 'fnord' }}
this.User.findAll(query).success(function(users) { self.User.findAll(query).success(function(users) {
expect(users[0].username).toEqual('fnord') expect(users[0].username).toEqual('fnord')
self.User.findAll(query).success(function(users) {
this.User.findAll(query).success(function(users) {
expect(users[0].username).toEqual('fnord') expect(users[0].username).toEqual('fnord')
done() done()
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) })
describe('find', function find() { describe('find', function() {
it("can reuse query option objects", function(done) { it("can reuse query option objects", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() { this.User.create({ username: 'fnord' }).success(function() {
var query = { where: { username: 'fnord' }} var query = { where: { username: 'fnord' }}
this.User.find(query).success(function(user) { self.User.find(query).success(function(user) {
expect(user.username).toEqual('fnord') expect(user.username).toEqual('fnord')
this.User.find(query).success(function(user) { self.User.find(query).success(function(user) {
expect(user.username).toEqual('fnord') expect(user.username).toEqual('fnord')
done() done()
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) })
describe('equals', function find() { describe('equals', function() {
it("can compare records with Date field", function(done) { it("can compare records with Date field", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function(user1) { this.User.create({ username: 'fnord' }).success(function(user1) {
var query = { where: { username: 'fnord' }} var query = { where: { username: 'fnord' }}
this.User.find(query).success(function(user2) { self.User.find(query).success(function(user2) {
expect(user1.equals(user2)).toBeTrue() expect(user1.equals(user2)).toBeTrue()
done() done()
}.bind(this)) })
}.bind(this)) })
}) })
}) })
...@@ -935,7 +928,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -935,7 +928,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
username: Helpers.Sequelize.STRING username: Helpers.Sequelize.STRING
}, { timestamps: false, logging: false }) }, { timestamps: false, logging: false })
User.sync({ force: true }).success(function() { User.sync().success(function() {
var user = User.build({ username: 'foo' }) var user = User.build({ username: 'foo' })
expect(user.values).toEqual({ username: "foo", id: null }) expect(user.values).toEqual({ username: "foo", id: null })
done() done()
...@@ -999,14 +992,14 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -999,14 +992,14 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
identifier: {type: Helpers.Sequelize.STRING, primaryKey: true} identifier: {type: Helpers.Sequelize.STRING, primaryKey: true}
}) })
User.sync({ force:true }).success(function(){ User.sync({ force: true }).success(function(){
User.create({ User.create({
name: 'snafu', name: 'snafu',
identifier: 'identifier' identifier: 'identifier'
}).success(function(user) { }).success(function(user) {
var emitter = user.updateAttributes({name: 'foobar'}) var emitter = user.updateAttributes({name: 'foobar'})
emitter.success(function() { emitter.on('sql', function(sql) {
expect(emitter.query.sql).toMatch(/WHERE [`"]identifier[`"]..identifier./) expect(sql).toMatch(/WHERE [`"]identifier[`"]..identifier./)
done() done()
}) })
}) })
...@@ -1020,7 +1013,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() { ...@@ -1020,7 +1013,7 @@ describe(Helpers.getTestDialectTeaser("DAO"), function() {
finishedAt: Helpers.Sequelize.DATE finishedAt: Helpers.Sequelize.DATE
}) })
Download.sync({ force: true }).success(function() { Download.sync().success(function() {
Download.create({ Download.create({
startedAt: new Date() startedAt: new Date()
}).success(function(download) { }).success(function(download) {
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Sequelize = require("../index") , Sequelize = require("../index")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser('DataTypes'), function() { describe(Helpers.getTestDialectTeaser('DataTypes'), function() {
it('should return DECIMAL for the default decimal type', function() { it('should return DECIMAL for the default decimal type', function(done) {
expect(Sequelize.DECIMAL).toEqual('DECIMAL'); expect(Sequelize.DECIMAL).toEqual('DECIMAL')
}); done()
})
it('should return DECIMAL(10,2) for the default decimal type with arguments', function() { it('should return DECIMAL(10,2) for the default decimal type with arguments', function(done) {
expect(Sequelize.DECIMAL(10, 2)).toEqual('DECIMAL(10,2)'); expect(Sequelize.DECIMAL(10, 2)).toEqual('DECIMAL(10,2)')
}); done()
})
var tests = [ var tests = [
[Sequelize.STRING, 'STRING', 'VARCHAR(255)'], [Sequelize.STRING, 'STRING', 'VARCHAR(255)'],
...@@ -59,8 +60,9 @@ describe(Helpers.getTestDialectTeaser('DataTypes'), function() { ...@@ -59,8 +60,9 @@ describe(Helpers.getTestDialectTeaser('DataTypes'), function() {
] ]
tests.forEach(function(test) { tests.forEach(function(test) {
it('transforms "' + test[1] + '" to "' + test[2] + '"', function() { it('transforms "' + test[1] + '" to "' + test[2] + '"', function(done) {
expect(test[0]).toEqual(test[2]) expect(test[0]).toEqual(test[2])
done()
}) })
}) })
}) })
...@@ -12,7 +12,7 @@ describe(Helpers.getTestDialectTeaser("CustomEventEmitter"), function() { ...@@ -12,7 +12,7 @@ describe(Helpers.getTestDialectTeaser("CustomEventEmitter"), function() {
describe("proxy", function () { describe("proxy", function () {
/* Tests could _probably_ be run synchronously, but for future proofing we're basing it on the events */ /* Tests could _probably_ be run synchronously, but for future proofing we're basing it on the events */
it("should correctly work with success listeners", function (done) { it("should correctly work with success listeners", function(done) {
var emitter = new CustomEventEmitter() var emitter = new CustomEventEmitter()
, proxy = new CustomEventEmitter() , proxy = new CustomEventEmitter()
, success = this.spy() , success = this.spy()
...@@ -29,7 +29,7 @@ describe(Helpers.getTestDialectTeaser("CustomEventEmitter"), function() { ...@@ -29,7 +29,7 @@ describe(Helpers.getTestDialectTeaser("CustomEventEmitter"), function() {
proxy.emit('success') proxy.emit('success')
}) })
it("should correctly work with error listeners", function (done) { it("should correctly work with error listeners", function(done) {
var emitter = new CustomEventEmitter() var emitter = new CustomEventEmitter()
, proxy = new CustomEventEmitter() , proxy = new CustomEventEmitter()
, error = this.spy() , error = this.spy()
...@@ -46,7 +46,7 @@ describe(Helpers.getTestDialectTeaser("CustomEventEmitter"), function() { ...@@ -46,7 +46,7 @@ describe(Helpers.getTestDialectTeaser("CustomEventEmitter"), function() {
proxy.emit('error') proxy.emit('error')
}) })
it("should correctly work with complete/done listeners", function (done) { it("should correctly work with complete/done listeners", function(done) {
var emitter = new CustomEventEmitter() var emitter = new CustomEventEmitter()
, proxy = new CustomEventEmitter() , proxy = new CustomEventEmitter()
, complete = this.spy() , complete = this.spy()
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Sequelize = require("../index") , Sequelize = require("../index")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("Language Util"), function() { describe(Helpers.getTestDialectTeaser("Language Util"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
describe("Plural", function(){ describe("Plural", function(){
before(function(done) { before(function(done) {
Helpers.initTests({ var self = this
dialect: dialect, self.sequelize = Object.create(sequelize)
onComplete: function(sequelize) { self.sequelize.options.language = 'es'
this.sequelize = sequelize Helpers.clearDatabase(self.sequelize, done)
this.sequelize.options.language = 'es'
done()
}.bind(this)
})
}) })
it("should rename tables to their plural form...", function(done){ it("should rename tables to their plural form...", function(done){
var table = this.sequelize.define('arbol', {name: Sequelize.STRING}) var self = this
var table2 = this.sequelize.define('androide', {name: Sequelize.STRING}) , table = self.sequelize.define('arbol', {name: Sequelize.STRING})
, table2 = self.sequelize.define('androide', {name: Sequelize.STRING})
expect(table.tableName).toEqual('arboles') expect(table.tableName).toEqual('arboles')
expect(table2.tableName).toEqual('androides') expect(table2.tableName).toEqual('androides')
done() done()
}) })
it("should be able to pluralize/singularize associations...", function(done){ it("should be able to pluralize/singularize associations...", function(done){
var table = this.sequelize.define('arbol', {name: Sequelize.STRING}) var self = this
var table2 = this.sequelize.define('androide', {name: Sequelize.STRING}) , table = self.sequelize.define('arbol', {name: Sequelize.STRING})
var table3 = this.sequelize.define('hombre', {name: Sequelize.STRING}) , table2 = self.sequelize.define('androide', {name: Sequelize.STRING})
, table3 = self.sequelize.define('hombre', {name: Sequelize.STRING})
table.hasOne(table2) table.hasOne(table2)
table2.belongsTo(table) table2.belongsTo(table)
......
if(typeof require === 'function') {
const buster = require("buster")
, QueryChainer = require("../lib/query-chainer")
, CustomEventEmitter = require("../lib/emitters/custom-event-emitter")
, Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect()
, Migrator = require("../lib/migrator")
}
buster.spec.expose()
buster.testRunner.timeout = 10000
describe(Helpers.getTestDialectTeaser("Migrator"), function() {
before(function(done) {
this.init = function(options, callback) {
options = Helpers.Sequelize.Utils._.extend({
path: __dirname + '/assets/migrations',
logging: function(){}
}, options || {})
var migrator = new Migrator(this.sequelize, options)
migrator
.findOrCreateSequelizeMetaDAO({ force: true })
.success(function(SequelizeMeta) {
callback && callback(migrator, SequelizeMeta)
})
.error(function(err) { console.log(err) })
}.bind(this)
Helpers.initTests({ dialect: dialect, onComplete: done, context: this })
})
it("as", function() {
expect(1).toEqual(1)
})
describe('getUndoneMigrations', function() {
it("returns no files if timestamps are after the files timestamp", function(done) {
this.init({ from: 20120101010101 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).toBeNull()
expect(migrations.length).toEqual(0)
done()
}.bind(this))
}.bind(this))
})
it("returns only files between from and to", function(done) {
this.init({ from: 19700101000000, to: 20111117063700 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).toBeNull()
expect(migrations.length).toEqual(1)
expect(migrations[migrations.length - 1].filename).toEqual('20111117063700-createPerson.js')
done()
}.bind(this))
}.bind(this))
})
it("returns exactly the migration which is defined in from and to", function(done) {
this.init({ from: 20111117063700, to: 20111117063700 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).toBeNull()
expect(migrations.length).toEqual(1)
expect(migrations[migrations.length - 1].filename).toEqual('20111117063700-createPerson.js')
done()
}.bind(this))
}.bind(this))
})
it("returns also the file which is exactly options.from or options.to", function(done) {
this.init({ from: 20111117063700, to: 20111130161100 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).toBeNull()
expect(migrations.length).toEqual(2)
expect(migrations[0].filename).toEqual('20111117063700-createPerson.js')
expect(migrations[1].filename).toEqual('20111130161100-emptyMigration.js')
done()
}.bind(this))
}.bind(this))
})
it("returns all files to options.to if no options.from is defined", function(done) {
this.init({ to: 20111130161100 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).toBeNull()
expect(migrations.length).toEqual(2)
done()
}.bind(this))
}.bind(this))
})
it("returns all files from last migration id stored in database", function(done) {
this.init(undefined, function(migrator, SequelizeMeta) {
SequelizeMeta.create({ from: null, to: 20111117063700 }).success(function() {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).toBeNull()
expect(migrations.length).toEqual(6)
expect(migrations[0].filename).toEqual('20111130161100-emptyMigration.js')
done()
}.bind(this))
}.bind(this))
}.bind(this))
})
})
describe('migrations', function() {
before(function(done) {
this.init({ from: 20111117063700, to: 20111117063700 }, function(migrator) {
this.migrator = migrator
this.migrator.migrate().success(done)
}.bind(this))
})
describe('executions', function() {
it("executes migration #20111117063700 and correctly creates the table", function(done) {
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).toEqual([ 'Person' ])
done()
})
})
it("executes migration #20111117063700 and correctly adds isBetaMember", function(done) {
this.sequelize.getQueryInterface().describeTable('Person').success(function(data) {
var fields = Helpers.Sequelize.Utils._.keys(data).sort()
expect(fields).toEqual([ 'isBetaMember', 'name' ])
done()
})
})
it("executes migration #20111117063700 correctly up (createTable) and downwards (dropTable)", function(done) {
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).toEqual([ 'Person' ])
this.migrator.migrate({ method: 'down' }).success(function() {
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).toEqual([])
done()
}.bind(this))
}.bind(this))
}.bind(this))
})
it("executes the empty migration #20111130161100", function(done) {
this.init({ from: 20111130161100, to: 20111130161100 }, function(migrator) {
// this migration isn't actually testing anything but
// should not timeout
expect(1).toEqual(1)
migrator
.migrate()
.success(done)
.error(function(err) { console.log(err) })
})
})
})
describe('renameTable', function() {
before(function(done) {
this.init({ from: 20111117063700, to: 20111117063700 }, function(migrator) {
this.migrator = migrator
this.migrator.migrate().success(done)
}.bind(this))
})
it("executes migration #20111205064000 and renames a table", function(done) {
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).toContain('Person')
this.init({ from: 20111205064000, to: 20111205064000 }, function(migrator) {
migrator.migrate().success(function() {
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).toEqual([ 'User' ])
done()
})
}.bind(this))
}.bind(this))
}.bind(this))
})
})
describe('addColumn', function() {
it('adds a column to the user table', function(done) {
this.init({ from: 20111117063700, to: 20111205162700 }, function(migrator) {
migrator.migrate().complete(function(err) {
this.sequelize.getQueryInterface().describeTable('User').complete(function(err, data) {
var signature = data.signature
, isAdmin = data.isAdmin
, shopId = data.shopId
expect(signature.allowNull).toEqual(true)
expect(isAdmin.allowNull).toEqual(false)
expect(isAdmin.defaultValue).toEqual(false)
expect(shopId.allowNull).toEqual(true)
done()
})
}.bind(this))
}.bind(this))
})
})
describe('removeColumn', function() {
it('removes the shopId column from user', function(done) {
this.init({ to: 20111206061400 }, function(migrator) {
migrator.migrate().success(function(){
this.sequelize.getQueryInterface().describeTable('User').success(function(data) {
var signature = data.signature
, isAdmin = data.isAdmin
, shopId = data.shopId
expect(signature.allowNull).toEqual(true)
expect(isAdmin.allowNull).toEqual(false)
expect(isAdmin.defaultValue).toEqual(false)
expect(shopId).toBeFalsy()
done()
})
}.bind(this))
}.bind(this))
})
})
describe('changeColumn', function() {
it('changes the signature column from user to default "signature" + notNull', function(done) {
this.init({ to: 20111206063000 }, function(migrator) {
migrator.migrate().success(function() {
this.sequelize.getQueryInterface().describeTable('User').success(function(data) {
var signature = data.signature
if (dialect === 'postgres') {
expect(signature.type).toEqual('CHARACTER VARYING')
} else {
expect(signature.type).toEqual('VARCHAR(255)')
}
expect(signature.allowNull).toEqual(false)
expect(signature.defaultValue).toEqual('Signature')
done()
})
}.bind(this))
}.bind(this))
})
})
})
describe('renameColumn', function() {
it("renames the signature column from user to sig", function(done) {
this.init({ to: 20111206163300 }, function(migrator) {
migrator.migrate().success(function(){
this.sequelize.getQueryInterface().describeTable('User').success(function(data) {
var signature = data.signature
, sig = data.sig
expect(signature).toBeFalsy()
expect(sig).toBeTruthy()
done()
})
}.bind(this))
}.bind(this))
})
})
})
/* jshint camelcase: false */ /* jshint camelcase: false */
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, config = require('../config/config')
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect.match(/^mysql/)) { if (dialect.match(/^mysql/)) {
describe('[MYSQL] Associations', function() { describe('[MYSQL Specific] Associations', function() {
before(function(done) { before(function(done) {
var self = this this.sequelize = sequelize
Helpers.clearDatabase(this.sequelize, done)
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
},
onComplete: function() {
self.sequelize.sync({ force: true }).success(done)
}
})
}) })
describe('many-to-many', function() { describe('many-to-many', function() {
...@@ -34,12 +24,14 @@ if (dialect.match(/^mysql/)) { ...@@ -34,12 +24,14 @@ if (dialect.match(/^mysql/)) {
Table1.hasMany(Table2) Table1.hasMany(Table2)
Table2.hasMany(Table1) Table2.hasMany(Table1)
this.sequelize.sync({ force: true }).success(function() { Table1.sync({ force: true }).success(function() {
Table2.sync({ force: true }).success(function() {
expect(self.sequelize.daoFactoryManager.getDAO('wp_table1swp_table2s')).toBeDefined() expect(self.sequelize.daoFactoryManager.getDAO('wp_table1swp_table2s')).toBeDefined()
done() done()
}) })
}) })
}) })
})
describe('when join table name is specified', function() { describe('when join table name is specified', function() {
before(function(done){ before(function(done){
...@@ -48,17 +40,14 @@ if (dialect.match(/^mysql/)) { ...@@ -48,17 +40,14 @@ if (dialect.match(/^mysql/)) {
Table1.hasMany(Table2, {joinTableName: 'table1_to_table2'}) Table1.hasMany(Table2, {joinTableName: 'table1_to_table2'})
Table2.hasMany(Table1, {joinTableName: 'table1_to_table2'}) Table2.hasMany(Table1, {joinTableName: 'table1_to_table2'})
this.sequelize.sync({ force: true }).success(done) Table1.sync({ force: true }).success(function() {
Table2.sync({ force: true }).success(done)
}) })
it("should not use a combined name", function(done) {
expect(this.sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).not.toBeDefined()
done()
}) })
it("should use the specified name", function(done) { it("should not use only a specified name", function() {
expect(this.sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).not.toBeDefined()
expect(this.sequelize.daoFactoryManager.getDAO('table1_to_table2')).toBeDefined() expect(this.sequelize.daoFactoryManager.getDAO('table1_to_table2')).toBeDefined()
done()
}) })
}) })
}) })
...@@ -87,12 +76,14 @@ if (dialect.match(/^mysql/)) { ...@@ -87,12 +76,14 @@ if (dialect.match(/^mysql/)) {
tasks[tasks.length] = {name: 'Task' + Math.random()} tasks[tasks.length] = {name: 'Task' + Math.random()}
} }
this.sequelize.sync({ force: true }).success(function() { this.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.bulkCreate(users).success(function() { self.User.bulkCreate(users).success(function() {
self.Task.bulkCreate(tasks).success(done) self.Task.bulkCreate(tasks).success(done)
}) })
}) })
}) })
})
describe('addDAO / getDAO', function() { describe('addDAO / getDAO', function() {
before(function(done) { before(function(done) {
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect.match(/^mysql/)) { if (dialect.match(/^mysql/)) {
describe('[MYSQL] Connector Manager', function() { describe('[MYSQL Specific] Connector Manager', function() {
before(function(done) { before(function(done) {
var self = this this.sequelize = sequelize
Helpers.clearDatabase(this.sequelize, done)
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
},
onComplete: function() {
self.sequelize.sync({ force: true }).success(done)
}
})
}) })
it('works correctly after being idle', function(done) { it('works correctly after being idle', function(done) {
......
/* jshint camelcase: false */ /* jshint camelcase: false */
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, config = require('../config/config') , config = require('../config/config')
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect.match(/^mysql/)) { if (dialect.match(/^mysql/)) {
describe('[MYSQL] DAOFactory', function() { describe('[MYSQL Specific] DAOFactory', function() {
before(function(done) { before(function(done) {
var self = this this.sequelize = sequelize
Helpers.clearDatabase(this.sequelize, done)
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = self.sequelize.define('User', { age: DataTypes.INTEGER, name: DataTypes.STRING, bio: DataTypes.TEXT })
},
onComplete: function() {
self.sequelize.sync({ force: true }).success(done)
}
})
}) })
describe('constructor', function() { describe('constructor', function() {
......
/* jshint camelcase: false */ /* jshint camelcase: false */
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, config = require('../config/config')
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, QueryGenerator = require("../../lib/dialects/mysql/query-generator") , QueryGenerator = require("../../lib/dialects/mysql/query-generator")
, util = require("util") , util = require("util")
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect.match(/^mysql/)) { if (dialect.match(/^mysql/)) {
describe('[MYSQL] QueryGenerator', function() { describe('[MYSQL Specific] QueryGenerator', function() {
before(function(done) { before(function(done) {
var self = this this.sequelize = sequelize
Helpers.clearDatabase(this.sequelize, done)
Helpers.initTests({
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
},
onComplete: function() {
self.sequelize.sync({ force: true }).success(done)
}
})
}) })
var suites = { var suites = {
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 2000
if (dialect.match(/^postgres/)) { if (dialect.match(/^postgres/)) {
describe('[POSTGRES] associations', function() { describe('[POSTGRES Specific] associations', function() {
before(function(done) { var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
var self = this
Helpers.initTests({ before(function(done) {
dialect: dialect, this.sequelize = sequelize
beforeComplete: function(sequelize, DataTypes) { Helpers.clearDatabase(this.sequelize, done)
self.sequelize = sequelize
},
onComplete: function() {
self.sequelize.sync({ force: true }).success(done)
}
})
}) })
describe('many-to-many', function() { describe('many-to-many', function() {
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
} , DataTypes = require(__dirname + "/../../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000
if (dialect.match(/^postgres/)) { if (dialect.match(/^postgres/)) {
describe('[POSTGRES] DAO', function() { describe('[POSTGRES Specific] DAO', function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
var self = this var self = this
this.sequelize = sequelize
Helpers.initTests({ Helpers.clearDatabase(this.sequelize, function() {
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', { self.User = sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)}, email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'} document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
}) })
},
onComplete: function() {
self.User.sync({ force: true }).success(done) self.User.sync({ force: true }).success(done)
}
}) })
}) })
describe('model', function() { describe('model', function() {
it("create handles array correctly", function(done) { it("create handles array correctly", function(done) {
var self = this
this.User this.User
.create({ username: 'user', email: ['foo@bar.com', 'bar@baz.com'] }) .create({ username: 'user', email: ['foo@bar.com', 'bar@baz.com'] })
.success(function(oldUser) { .success(function(oldUser) {
...@@ -65,29 +58,23 @@ if (dialect.match(/^postgres/)) { ...@@ -65,29 +58,23 @@ if (dialect.match(/^postgres/)) {
.error(console.log) .error(console.log)
}) })
}) })
})
describe('[POSTGRES] Unquoted identifiers', function() { describe('[POSTGRES] Unquoted identifiers', function() {
before(function(done) { before(function(done) {
var self = this var self = this
this.sequelize.options.quoteIdentifiers = false
Helpers.initTests({ self.User = this.sequelize.define('User', {
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.sequelize.options.quoteIdentifiers = false
self.User = sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
fullName: DataTypes.STRING // Note mixed case fullName: DataTypes.STRING // Note mixed case
}) })
},
onComplete: function() {
// We can create a table with non-quoted identifiers
self.User.sync({ force: true }).success(done) self.User.sync({ force: true }).success(done)
}
}) })
after(function(done) {
this.sequelize.options.quoteIdentifiers = true
done()
}) })
it("can insert and select", function(done) { it("can insert and select", function(done) {
...@@ -113,12 +100,7 @@ if (dialect.match(/^postgres/)) { ...@@ -113,12 +100,7 @@ if (dialect.match(/^postgres/)) {
expect(user2.fullName).toEqual('John Smith') expect(user2.fullName).toEqual('John Smith')
done(); done();
}) })
.error(function(err) {
console.log(err)
})
}) })
.error(function(err) {
console.log(err)
}) })
}) })
}) })
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000
if (dialect.match(/^postgres/)) { if (dialect.match(/^postgres/)) {
describe('[POSTGRES] hstore', function() { describe('[POSTGRES Specific] hstore', function() {
const hstore = require('../../lib/dialects/postgres/hstore') var hstore = require('../../lib/dialects/postgres/hstore')
describe('stringifyPart', function() { describe('stringifyPart', function() {
it("handles undefined values correctly", function() { it("handles undefined values correctly", function(done) {
expect(hstore.stringifyPart(undefined)).toEqual('NULL') expect(hstore.stringifyPart(undefined)).toEqual('NULL')
done()
}) })
it("handles null values correctly", function() {
it("handles null values correctly", function(done) {
expect(hstore.stringifyPart(null)).toEqual('NULL') expect(hstore.stringifyPart(null)).toEqual('NULL')
done()
}) })
it("handles boolean values correctly", function() {
it("handles boolean values correctly", function(done) {
expect(hstore.stringifyPart(false)).toEqual('false') expect(hstore.stringifyPart(false)).toEqual('false')
expect(hstore.stringifyPart(true)).toEqual('true') expect(hstore.stringifyPart(true)).toEqual('true')
done()
}) })
it("handles strings correctly", function() {
it("handles strings correctly", function(done) {
expect(hstore.stringifyPart('foo')).toEqual('"foo"') expect(hstore.stringifyPart('foo')).toEqual('"foo"')
done()
}) })
it("handles strings with backslashes correctly", function() {
it("handles strings with backslashes correctly", function(done) {
expect(hstore.stringifyPart("\\'literally\\'")).toEqual('"\\\\\'literally\\\\\'"') expect(hstore.stringifyPart("\\'literally\\'")).toEqual('"\\\\\'literally\\\\\'"')
done()
}) })
it("handles arrays correctly", function() {
it("handles arrays correctly", function(done) {
expect(hstore.stringifyPart([1,['2'],'"3"'])).toEqual('"[1,[\\"2\\"],\\"\\\\\\"3\\\\\\"\\"]"') expect(hstore.stringifyPart([1,['2'],'"3"'])).toEqual('"[1,[\\"2\\"],\\"\\\\\\"3\\\\\\"\\"]"')
done()
}) })
it("handles simple objects correctly", function() {
it("handles simple objects correctly", function(done) {
expect(hstore.stringifyPart({ test: 'value' })).toEqual('"{\\"test\\":\\"value\\"}"') expect(hstore.stringifyPart({ test: 'value' })).toEqual('"{\\"test\\":\\"value\\"}"')
done()
}) })
it("handles nested objects correctly", function () {
it("handles nested objects correctly", function(done) {
expect(hstore.stringifyPart({ test: { nested: 'value' } })).toEqual('"{\\"test\\":{\\"nested\\":\\"value\\"}}"') expect(hstore.stringifyPart({ test: { nested: 'value' } })).toEqual('"{\\"test\\":{\\"nested\\":\\"value\\"}}"')
done()
}) })
it("handles objects correctly", function() {
it("handles objects correctly", function(done) {
expect(hstore.stringifyPart({test: {nested: {value: {including: '"string"'}}}})).toEqual('"{\\"test\\":{\\"nested\\":{\\"value\\":{\\"including\\":\\"\\\\\\"string\\\\\\"\\"}}}}"') expect(hstore.stringifyPart({test: {nested: {value: {including: '"string"'}}}})).toEqual('"{\\"test\\":{\\"nested\\":{\\"value\\":{\\"including\\":\\"\\\\\\"string\\\\\\"\\"}}}}"')
done()
}) })
}) })
describe('stringify', function() { describe('stringify', function() {
it('should handle empty objects correctly', function() { it('should handle empty objects correctly', function(done) {
expect(hstore.stringify({ })).toEqual('') expect(hstore.stringify({ })).toEqual('')
done()
}) })
it('should handle null values correctly', function () {
it('should handle null values correctly', function(done) {
expect(hstore.stringify({ null: null })).toEqual('"null"=>NULL') expect(hstore.stringify({ null: null })).toEqual('"null"=>NULL')
done()
}) })
it('should handle simple objects correctly', function() {
it('should handle simple objects correctly', function(done) {
expect(hstore.stringify({ test: 'value' })).toEqual('"test"=>"value"') expect(hstore.stringify({ test: 'value' })).toEqual('"test"=>"value"')
done()
}) })
it('should handle nested objects correctly', function() {
it('should handle nested objects correctly', function(done) {
expect(hstore.stringify({ test: { nested: 'value' } })).toEqual('"test"=>"{\\"nested\\":\\"value\\"}"') expect(hstore.stringify({ test: { nested: 'value' } })).toEqual('"test"=>"{\\"nested\\":\\"value\\"}"')
done()
}) })
it('should handle nested arrays correctly', function() {
it('should handle nested arrays correctly', function(done) {
expect(hstore.stringify({ test: [ 1, '2', [ '"3"' ] ] })).toEqual('"test"=>"[1,\\"2\\",[\\"\\\\\\"3\\\\\\"\\"]]"') expect(hstore.stringify({ test: [ 1, '2', [ '"3"' ] ] })).toEqual('"test"=>"[1,\\"2\\",[\\"\\\\\\"3\\\\\\"\\"]]"')
done()
}) })
it('should handle multiple keys with different types of values', function() {
it('should handle multiple keys with different types of values', function(done) {
expect(hstore.stringify({ true: true, false: false, null: null, undefined: undefined, integer: 1, array: [1,'2'], object: { object: 'value' }})).toEqual('"true"=>true,"false"=>false,"null"=>NULL,"undefined"=>NULL,"integer"=>1,"array"=>"[1,\\"2\\"]","object"=>"{\\"object\\":\\"value\\"}"') expect(hstore.stringify({ true: true, false: false, null: null, undefined: undefined, integer: 1, array: [1,'2'], object: { object: 'value' }})).toEqual('"true"=>true,"false"=>false,"null"=>NULL,"undefined"=>NULL,"integer"=>1,"array"=>"[1,\\"2\\"]","object"=>"{\\"object\\":\\"value\\"}"')
done()
}) })
}) })
describe('parse', function() { describe('parse', function() {
it('should handle empty objects correctly', function() { it('should handle empty objects correctly', function(done) {
expect(hstore.parse('')).toEqual({ }) expect(hstore.parse('')).toEqual({ })
done()
}) })
it('should handle simple objects correctly', function() {
it('should handle simple objects correctly', function(done) {
expect(hstore.parse('"test"=>"value"')).toEqual({ test: 'value' }) expect(hstore.parse('"test"=>"value"')).toEqual({ test: 'value' })
done()
}) })
it('should handle nested objects correctly', function() {
it('should handle nested objects correctly', function(done) {
expect(hstore.parse('"test"=>"{\\"nested\\":\\"value\\"}"')).toEqual({ test: { nested: 'value' } }) expect(hstore.parse('"test"=>"{\\"nested\\":\\"value\\"}"')).toEqual({ test: { nested: 'value' } })
done()
}) })
it('should handle nested arrays correctly', function() {
it('should handle nested arrays correctly', function(done) {
expect(hstore.parse('"test"=>"[1,\\"2\\",[\\"\\\\\\"3\\\\\\"\\"]]"')).toEqual({ test: [ 1, '2', [ '"3"' ] ] }) expect(hstore.parse('"test"=>"[1,\\"2\\",[\\"\\\\\\"3\\\\\\"\\"]]"')).toEqual({ test: [ 1, '2', [ '"3"' ] ] })
done()
}) })
it('should handle multiple keys with different types of values', function() {
it('should handle multiple keys with different types of values', function(done) {
expect(hstore.parse('"true"=>true,"false"=>false,"null"=>NULL,"undefined"=>NULL,"integer"=>1,"array"=>"[1,\\"2\\"]","object"=>"{\\"object\\":\\"value\\"}"')).toEqual({ true: true, false: false, null: null, undefined: null, integer: 1, array: [1,'2'], object: { object: 'value' }}) expect(hstore.parse('"true"=>true,"false"=>false,"null"=>NULL,"undefined"=>NULL,"integer"=>1,"array"=>"[1,\\"2\\"]","object"=>"{\\"object\\":\\"value\\"}"')).toEqual({ true: true, false: false, null: null, undefined: null, integer: 1, array: [1,'2'], object: { object: 'value' }})
done()
}) })
}) })
}) })
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, QueryGenerator = require("../../lib/dialects/postgres/query-generator") , QueryGenerator = require("../../lib/dialects/postgres/query-generator")
, util = require("util") , util = require("util")
, moment = require('moment') , moment = require('moment')
} , DataTypes = require(__dirname + "/../../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
if (dialect.match(/^postgres/)) { if (dialect.match(/^postgres/)) {
describe('[POSTGRES] QueryGenerator', function() { describe('[POSTGRES Specific] QueryGenerator', function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
var self = this var self = this
this.sequelize = sequelize
Helpers.initTests({ Helpers.clearDatabase(this.sequelize, function() {
dialect: dialect,
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', { self.User = sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)}, email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'} document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
}) })
},
onComplete: function() {
self.User.sync({ force: true }).success(done) self.User.sync({ force: true }).success(done)
}
}) })
}) })
......
if (typeof require === 'function') {
const buster = require("buster")
, Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect()
, _ = require('lodash')
}
buster.spec.expose()
describe(Helpers.getTestDialectTeaser("Promise"), function () {
before(function (done) {
var self = this
Helpers.initTests({
dialect: dialect,
beforeComplete: function (sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', {
username: { type: DataTypes.STRING },
touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
aNumber: { type: DataTypes.INTEGER },
bNumber: { type: DataTypes.INTEGER },
validateTest: {
type: DataTypes.INTEGER,
allowNull: true,
validate: {isInt: true}
},
validateCustom: {
type: DataTypes.STRING,
allowNull: true,
validate: {len: {msg: 'Length failed.', args: [1, 20]}}
},
dateAllowNullTrue: {
type: DataTypes.DATE,
allowNull: true
}
})
self.HistoryLog = sequelize.define('HistoryLog', {
someText: { type: DataTypes.STRING },
aNumber: { type: DataTypes.INTEGER },
aRandomId: { type: DataTypes.INTEGER }
})
self.ParanoidUser = sequelize.define('ParanoidUser', {
username: { type: DataTypes.STRING }
}, {
paranoid: true
})
self.ParanoidUser.hasOne(self.ParanoidUser)
},
onComplete: function () {
self.User.sync({ force: true }).then(function () {
return self.HistoryLog.sync({ force: true })
}).then(function () {
return self.ParanoidUser.sync({force: true })
})
.then(function () {done()}, done)
}
})
})
describe('increment', function () {
before(function (done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
});
it('with array', function (done) {
var self = this;
// Select something
this.User.find(1).then(function (user1) {
return user1.increment(['aNumber'], 2)
}).then(function (user2) {
return self.User.find(1)
}).then(function (user3) {
expect(user3.aNumber).toBe(2);
done();
}, done);
});
it('should still work right with other concurrent updates', function (done) {
var self = this;
// Select something
this.User.find(1).then(function (user1) {
// Select the user again (simulating a concurrent query)
return self.User.find(1).then(function (user2) {
return user2.updateAttributes({
aNumber: user2.aNumber + 1
}).then(function (user3) {
return user1.increment(['aNumber'], 2)
}).then(function (user4) {
return self.User.find(1)
}).then(function (user5) {
expect(user5.aNumber).toBe(3);
done();
}, done)
});
});
});
it('with key value pair', function (done) {
var self = this;
// Select something
this.User.find(1).then(function (user1) {
return user1.increment({ 'aNumber': 1, 'bNumber': 2})
}).then(function () {
return self.User.find(1)
}).then(function (user3) {
expect(user3.aNumber).toBe(1);
expect(user3.bNumber).toBe(2);
done();
}, done);
});
});
describe('decrement', function () {
before(function (done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
});
it('with array', function (done) {
var self = this;
// Select something
this.User.find(1).then(function (user1) {
return user1.decrement(['aNumber'], 2)
}).then(function () {
return self.User.find(1);
}).then(function (user3) {
expect(user3.aNumber).toBe(-2);
done();
}, done);
});
it('with single field', function (done) {
var self = this;
// Select something
this.User.find(1).then(function (user1) {
return user1.decrement(['aNumber'], 2)
}).then(function () {
return self.User.find(1);
}).then(function (user3) {
expect(user3.aNumber).toBe(-2);
done();
}, done);
});
it('should still work right with other concurrent decrements', function (done) {
var self = this;
// Select something
this.User.find(1).then(function (user1) {
var _done = _.after(3, function () {
self.User.find(1).then(function (user2) {
expect(user2.aNumber).toEqual(-6);
done();
})
});
user1.decrement(['aNumber'], 2).done(_done);
user1.decrement(['aNumber'], 2).done(_done);
user1.decrement(['aNumber'], 2).done(_done);
});
});
});
describe('reload', function () {
it("should return a reference to the same DAO instead of creating a new one", function (done) {
this.User.create({ username: 'John Doe' }).then(function (originalUser) {
return originalUser.updateAttributes({ username: 'Doe John' }).then(function () {
return originalUser.reload()
}).then(function (updatedUser) {
expect(originalUser === updatedUser).toBeTrue()
done();
}, done)
})
})
it("should update the values on all references to the DAO", function (done) {
var self = this
this.User.create({ username: 'John Doe' }).then(function (originalUser) {
return self.User.find(originalUser.id).then(function (updater) {
return updater.updateAttributes({ username: 'Doe John' })
}).then(function () {
// We used a different reference when calling updateAttributes, so originalUser is now out of sync
expect(originalUser.username).toEqual('John Doe')
return originalUser.reload()
}).then(function (updatedUser) {
expect(originalUser.username).toEqual('Doe John')
expect(updatedUser.username).toEqual('Doe John')
done();
}, done)
})
})
it("should update the associations as well", function (done) {
var Book = this.sequelize.define('Book', { title: Helpers.Sequelize.STRING })
, Page = this.sequelize.define('Page', { content: Helpers.Sequelize.TEXT })
Book.hasMany(Page)
Page.belongsTo(Book)
this.sequelize.sync({ force: true }).then(function () {
return Book.create({ title: 'A very old book' })
}).then(function (book) {
return Page.create({ content: 'om nom nom' }).then(function (page) {
return book.setPages([ page ]).then(function () {
return Book.find({
where: (dialect === 'postgres' ? '"Books"."id"=' : '`Books`.`id`=') + book.id,
include: [Page]
}).then(function (leBook) {
return page.updateAttributes({ content: 'something totally different' }).then(function (page) {
expect(leBook.pages[0].content).toEqual('om nom nom')
expect(page.content).toEqual('something totally different')
return leBook.reload().then(function (leBook) {
expect(leBook.pages[0].content).toEqual('something totally different')
expect(page.content).toEqual('something totally different')
done()
})
})
})
})
})
}, done)
})
});
describe('complete', function () {
it("gets triggered if an error occurs", function (done) {
this.User.find({ where: "asdasdasd" }).then(null, function (err) {
expect(err).toBeDefined()
expect(err.message).toBeDefined()
done()
})
})
it("gets triggered if everything was ok", function (done) {
this.User.count().then(function (result) {
expect(result).toBeDefined()
done()
})
})
})
describe('save', function () {
it('should fail a validation upon creating', function (done) {
this.User.create({aNumber: 0, validateTest: 'hello'}).then(null, function (err) {
expect(err).toBeDefined()
expect(err).toBeObject()
expect(err.validateTest).toBeArray()
expect(err.validateTest[0]).toBeDefined()
expect(err.validateTest[0].indexOf('Invalid integer')).toBeGreaterThan(-1);
done();
});
})
it('should fail a validation upon building', function (done) {
this.User.build({aNumber: 0, validateCustom: 'aaaaaaaaaaaaaaaaaaaaaaaaaa'}).save()
.then(null, function (err) {
expect(err).toBeDefined()
expect(err).toBeObject()
expect(err.validateCustom).toBeDefined()
expect(err.validateCustom).toBeArray()
expect(err.validateCustom[0]).toBeDefined()
expect(err.validateCustom[0]).toEqual('Length failed.')
done()
})
})
it('should fail a validation when updating', function (done) {
this.User.create({aNumber: 0}).then(function (user) {
return user.updateAttributes({validateTest: 'hello'})
}).then(null, function (err) {
expect(err).toBeDefined()
expect(err).toBeObject()
expect(err.validateTest).toBeDefined()
expect(err.validateTest).toBeArray()
expect(err.validateTest[0]).toBeDefined()
expect(err.validateTest[0].indexOf('Invalid integer:')).toBeGreaterThan(-1)
done()
})
})
})
})
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, QueryChainer = require("../lib/query-chainer") , QueryChainer = require("../lib/query-chainer")
, CustomEventEmitter = require("../lib/emitters/custom-event-emitter") , CustomEventEmitter = require("../lib/emitters/custom-event-emitter")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("QueryChainer"), function() { describe(Helpers.getTestDialectTeaser("QueryChainer"), function() {
before(function() { before(function(done) {
this.queryChainer = new QueryChainer() this.queryChainer = new QueryChainer()
done()
}) })
describe('add', function() { describe('add', function() {
it('adds a new serial item if method is passed', function() { it('adds a new serial item if method is passed', function(done) {
expect(this.queryChainer.serials.length).toEqual(0) expect(this.queryChainer.serials.length).toEqual(0)
this.queryChainer.add({}, 'foo') this.queryChainer.add({}, 'foo')
expect(this.queryChainer.serials.length).toEqual(1) expect(this.queryChainer.serials.length).toEqual(1)
done()
}) })
it('adds a new emitter if no method is passed', function() { it('adds a new emitter if no method is passed', function(done) {
expect(this.queryChainer.emitters.length).toEqual(0) expect(this.queryChainer.emitters.length).toEqual(0)
this.queryChainer.add(new CustomEventEmitter()) this.queryChainer.add(new CustomEventEmitter())
expect(this.queryChainer.emitters.length).toEqual(1) expect(this.queryChainer.emitters.length).toEqual(1)
done()
}) })
}) })
......
/* jshint multistr: true */ /* jshint multistr: true */
var buster = require("buster")
if (typeof require === 'function') {
var buster = require("buster")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
} , DataTypes = require(__dirname + "/../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 2000 buster.testRunner.timeout = 2000
describe(Helpers.getTestDialectTeaser("QueryGenerators"), function() { describe(Helpers.getTestDialectTeaser("QueryGenerators"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
Helpers.initTests({ var self = this
dialect: dialect, self.sequelize = Object.create(sequelize)
beforeComplete: function(sequelize, DataTypes) { self.interface = self.sequelize.getQueryInterface()
this.sequelize = sequelize
this.DataTypes = DataTypes
}.bind(this),
onComplete: function() {
this.interface = this.sequelize.getQueryInterface()
done() done()
}.bind(this)
})
}) })
describe("comments", function() { describe("comments", function() {
it("should create a comment for a column", function(done) { it("should create a comment for a column", function(done) {
var self = this var self = this
, User = this.sequelize.define('User', { , User = this.sequelize.define('User', {
username: {type: this.DataTypes.STRING, comment: 'Some lovely info for my DBA'} username: {type: DataTypes.STRING, comment: 'Some lovely info for my DBA'}
}) })
User.sync().success(function(){ User.sync({ force: true }).success(function(){
var sql = '' var sql = ''
if (dialect === "mysql") { if (dialect === "mysql") {
sql = 'SELECT COLUMN_COMMENT as cmt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = \'' + self.sequelize.config.database + '\' AND TABLE_NAME = \'Users\' AND COLUMN_NAME = \'username\''; sql = 'SELECT COLUMN_COMMENT as cmt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = \'' + self.sequelize.config.database + '\' AND TABLE_NAME = \'Users\' AND COLUMN_NAME = \'username\'';
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, CustomEventEmitter = require("../lib/emitters/custom-event-emitter")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("QueryInterface"), function() { describe(Helpers.getTestDialectTeaser("QueryInterface"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
Helpers.initTests({ var self = this
dialect: dialect, self.sequelize = Object.create(sequelize)
beforeComplete: function(sequelize) { self.interface = self.sequelize.getQueryInterface()
this.sequelize = sequelize Helpers.clearDatabase(self.sequelize, done)
}.bind(this),
onComplete: function() {
this.interface = this.sequelize.getQueryInterface()
done()
}.bind(this)
})
}) })
describe('dropAllTables', function() { describe('dropAllTables', function() {
it("should drop all tables", function(done) { it("should drop all tables", function(done) {
var self = this
this.interface.dropAllTables().complete(function(err) { this.interface.dropAllTables().complete(function(err) {
expect(err).toBeNull() expect(err).toBeNull()
this.interface.showAllTables().complete(function(err, tableNames) { self.interface.showAllTables().complete(function(err, tableNames) {
expect(err).toBeNull() expect(err).toBeNull()
expect(tableNames.length).toEqual(0) expect(tableNames.length).toEqual(0)
this.interface.createTable('table', { name: Helpers.Sequelize.STRING }).complete(function(err) { self.interface.createTable('table', { name: Helpers.Sequelize.STRING }).complete(function(err) {
expect(err).toBeNull() expect(err).toBeNull()
this.interface.showAllTables().complete(function(err, tableNames) { self.interface.showAllTables().complete(function(err, tableNames) {
expect(err).toBeNull() expect(err).toBeNull()
expect(tableNames.length).toEqual(1) expect(tableNames.length).toEqual(1)
this.interface.dropAllTables().complete(function(err) { self.interface.dropAllTables().complete(function(err) {
expect(err).toBeNull() expect(err).toBeNull()
this.interface.showAllTables().complete(function(err, tableNames) { self.interface.showAllTables().complete(function(err, tableNames) {
expect(err).toBeNull() expect(err).toBeNull()
expect(tableNames.length).toEqual(0) expect(tableNames.length).toEqual(0)
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) })
...@@ -63,19 +57,20 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() { ...@@ -63,19 +57,20 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() {
}) })
it('adds, reads and removes an index to the table', function(done) { it('adds, reads and removes an index to the table', function(done) {
var self = this
this.interface.addIndex('User', ['username', 'isAdmin']).complete(function(err) { this.interface.addIndex('User', ['username', 'isAdmin']).complete(function(err) {
expect(err).toBeNull() expect(err).toBeNull()
this.interface.showIndex('User').complete(function(err, indexes) { self.interface.showIndex('User').complete(function(err, indexes) {
expect(err).toBeNull() expect(err).toBeNull()
var indexColumns = Helpers.Sequelize.Utils._.uniq(indexes.map(function(index) { return index.name })) var indexColumns = Helpers.Sequelize.Utils._.uniq(indexes.map(function(index) { return index.name }))
expect(indexColumns).toEqual(['user_username_is_admin']) expect(indexColumns).toEqual(['user_username_is_admin'])
this.interface.removeIndex('User', ['username', 'isAdmin']).complete(function(err) { self.interface.removeIndex('User', ['username', 'isAdmin']).complete(function(err) {
expect(err).toBeNull() expect(err).toBeNull()
this.interface.showIndex('User').complete(function(err, indexes) { self.interface.showIndex('User').complete(function(err, indexes) {
expect(err).toBeNull() expect(err).toBeNull()
indexColumns = Helpers.Sequelize.Utils._.uniq(indexes.map(function(index) { return index.name })) indexColumns = Helpers.Sequelize.Utils._.uniq(indexes.map(function(index) { return index.name }))
...@@ -83,23 +78,23 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() { ...@@ -83,23 +78,23 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() {
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
}) })
describe('describeTable', function() { describe('describeTable', function() {
before(function(done) { it('reads the metadata of the table', function(done) {
this.interface.createTable('User', { var self = this
var Users = self.sequelize.define('User', {
username: Helpers.Sequelize.STRING, username: Helpers.Sequelize.STRING,
isAdmin: Helpers.Sequelize.BOOLEAN, isAdmin: Helpers.Sequelize.BOOLEAN,
enumVals: Helpers.Sequelize.ENUM('hello', 'world') enumVals: Helpers.Sequelize.ENUM('hello', 'world')
}).success(done) }, { freezeTableName: true })
})
it('reads the metadata of the table', function(done) { Users.sync({ force: true }).success(function() {
this.interface.describeTable('User').complete(function(err, metadata) { self.interface.describeTable('User').complete(function(err, metadata) {
expect(err).toBeNull() expect(err).toBeNull()
var username = metadata.username var username = metadata.username
...@@ -114,7 +109,7 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() { ...@@ -114,7 +109,7 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() {
expect(isAdmin.allowNull).toBeTrue() expect(isAdmin.allowNull).toBeTrue()
expect(isAdmin.defaultValue).toBeNull() expect(isAdmin.defaultValue).toBeNull()
if (dialect === 'postgres') { if (dialect === "postgres" || dialect === "postgres-native") {
expect(enumVals.special).toBeArray(); expect(enumVals.special).toBeArray();
expect(enumVals.special.length).toEqual(2); expect(enumVals.special.length).toEqual(2);
} }
...@@ -123,4 +118,5 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() { ...@@ -123,4 +118,5 @@ describe(Helpers.getTestDialectTeaser("QueryInterface"), function() {
}) })
}) })
}) })
})
}) })
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('./buster-helpers') , Helpers = require('./buster-helpers')
, config = require(__dirname + "/config/config") , config = require(__dirname + "/config/config")
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, moment = require('moment') , moment = require('moment')
}
var qq = function(str) { var qq = function(str) {
if (dialect == 'postgres' || dialect == 'sqlite') { if (dialect == 'postgres' || dialect == 'sqlite') {
...@@ -17,15 +15,15 @@ var qq = function(str) { ...@@ -17,15 +15,15 @@ var qq = function(str) {
} }
buster.spec.expose() buster.spec.expose()
buster.timeout = 1000 buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("Sequelize"), function() { describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
before(function(done) { before(function(done) {
Helpers.initTests({ var self = this
dialect: dialect, self.sequelize = Object.create(sequelize)
beforeComplete: function(sequelize) { this.sequelize = sequelize }.bind(this), Helpers.clearDatabase(self.sequelize, done)
onComplete: done
})
}) })
describe('constructor', function() { describe('constructor', function() {
...@@ -60,24 +58,19 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -60,24 +58,19 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
describe('query', function() { describe('query', function() {
before(function(done) { before(function(done) {
this.sequelize.options.quoteIdentifiers = true
this.User = this.sequelize.define('User', { this.User = this.sequelize.define('User', {
username: Helpers.Sequelize.STRING username: Helpers.Sequelize.STRING
}) })
this.insertQuery = "INSERT INTO " + qq(this.User.tableName) + " (username, " + qq("createdAt") + ", " + qq("updatedAt") + ") VALUES ('john', '2012-01-01 10:10:10', '2012-01-01 10:10:10')" this.insertQuery = "INSERT INTO " + qq(this.User.tableName) + " (username, " + qq("createdAt") + ", " + qq("updatedAt") + ") VALUES ('john', '2012-01-01 10:10:10', '2012-01-01 10:10:10')"
this.User.sync().success(done).error(function(err) { this.User.sync({ force: true }).success(done)
console.log(err)
done()
})
}) })
it('executes a query the internal way', function(done) { it('executes a query the internal way', function(done) {
this.sequelize.query(this.insertQuery, null, { raw: true }) this.sequelize.query(this.insertQuery, null, { raw: true })
.complete(function(err, result) { .complete(function(err, result) {
if (err) {
console.log(err)
}
expect(err).toBeNull() expect(err).toBeNull()
expect(result).toBeNull() expect(result).toBeNull()
done() done()
...@@ -87,9 +80,6 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -87,9 +80,6 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
it('executes a query if only the sql is passed', function(done) { it('executes a query if only the sql is passed', function(done) {
this.sequelize.query(this.insertQuery) this.sequelize.query(this.insertQuery)
.complete(function(err, result) { .complete(function(err, result) {
if (err) {
console.log(err)
}
expect(err).toBeNull() expect(err).toBeNull()
expect(result).not.toBeDefined() expect(result).not.toBeDefined()
done() done()
...@@ -97,98 +87,97 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -97,98 +87,97 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
}) })
it('executes select queries correctly', function(done) { it('executes select queries correctly', function(done) {
this.sequelize.query(this.insertQuery).success(function() { var self = this
this.sequelize sequelize.query(this.insertQuery).success(function() {
.query("select * from " + qq(this.User.tableName) + "") sequelize
.query("select * from " + qq(self.User.tableName) + "")
.complete(function(err, users) { .complete(function(err, users) {
if (err) {
console.log(err)
}
expect(err).toBeNull() expect(err).toBeNull()
expect(users.map(function(u){ return u.username })).toEqual(['john']) expect(users.map(function(u){ return u.username })).toEqual(['john'])
done() done()
}) })
}.bind(this)) })
}) })
it('executes select queries correctly when quoteIdentifiers is false', function(done) { it('executes select queries correctly when quoteIdentifiers is false', function(done) {
this.sequelize.options.quoteIdentifiers = false var self = this
this.sequelize.query(this.insertQuery).success(function() { , seq = Object.create(self.sequelize)
this.sequelize
.query("select * from " + qq(this.User.tableName) + "") seq.options.quoteIdentifiers = false
seq.query(this.insertQuery).success(function() {
seq.query("select * from " + qq(self.User.tableName) + "")
.complete(function(err, users) { .complete(function(err, users) {
if (err) {
console.log(err)
}
expect(err).toBeNull() expect(err).toBeNull()
expect(users.map(function(u){ return u.username })).toEqual(['john']) expect(users.map(function(u){ return u.username })).toEqual(['john'])
done() done()
}) })
}.bind(this)) })
}) })
it('executes select query and parses dot notation results', function(done) { it('executes select query and parses dot notation results', function(done) {
this.sequelize.query(this.insertQuery).success(function() { var self = this
this.sequelize sequelize.query('DELETE FROM ' + qq(self.User.tableName)).complete(function() {
.query("select username as " + qq("user.username") + " from " + qq(this.User.tableName) + "") sequelize.query(self.insertQuery).success(function() {
sequelize
.query("select username as " + qq("user.username") + " from " + qq(self.User.tableName) + "")
.complete(function(err, users) { .complete(function(err, users) {
if (err) {
console.log(err)
}
expect(err).toBeNull() expect(err).toBeNull()
expect(users.map(function(u){ return u.user })).toEqual([{'username':'john'}]) expect(users.map(function(u){ return u.user })).toEqual([{'username':'john'}])
done() done()
}) })
}.bind(this)) })
})
}) })
if (dialect == 'mysql') { if (dialect == 'mysql') {
it('executes stored procedures', function(done) { it('executes stored procedures', function(done) {
this.sequelize.query(this.insertQuery).success(function() { var self = this
this.sequelize.query('DROP PROCEDURE IF EXISTS foo').success(function() { sequelize.query(this.insertQuery).success(function() {
this.sequelize.query( sequelize.query('DROP PROCEDURE IF EXISTS foo').success(function() {
"CREATE PROCEDURE foo()\nSELECT * FROM " + this.User.tableName + ";" sequelize.query(
"CREATE PROCEDURE foo()\nSELECT * FROM " + self.User.tableName + ";"
).success(function() { ).success(function() {
this.sequelize.query('CALL foo()').success(function(users) { sequelize.query('CALL foo()').success(function(users) {
expect(users.map(function(u){ return u.username })).toEqual(['john']) expect(users.map(function(u){ return u.username })).toEqual(['john'])
done() done()
}) })
}.bind(this)) })
}.bind(this)) })
}.bind(this)) })
}) })
} else { } else {
console.log('FIXME: I want to be supported in this dialect as well :-(') console.log('FIXME: I want to be supported in this dialect as well :-(')
} }
it('uses the passed DAOFactory', function(done) { it('uses the passed DAOFactory', function(done) {
this.sequelize.query(this.insertQuery).success(function() { var self = this
this.sequelize.query("SELECT * FROM " + qq(this.User.tableName) + ";", this.User).success(function(users) { sequelize.query(this.insertQuery).success(function() {
expect(users[0].__factory).toEqual(this.User) sequelize.query("SELECT * FROM " + qq(self.User.tableName) + ";", self.User).success(function(users) {
expect(users[0].__factory).toEqual(self.User)
done() done()
}.bind(this)) })
}.bind(this)) })
}) })
it('destructs dot separated attributes when doing a raw query', function(done) { it('destructs dot separated attributes when doing a raw query', function(done) {
var tickChar = (dialect === 'postgres') ? '"' : '`' var tickChar = (dialect === 'postgres') ? '"' : '`'
, sql = "select 1 as " + Helpers.Sequelize.Utils.addTicks('foo.bar.baz', tickChar) , sql = "select 1 as " + Helpers.Sequelize.Utils.addTicks('foo.bar.baz', tickChar)
this.sequelize.query(sql, null, { raw: true }).success(function(result) { sequelize.query(sql, null, { raw: true }).success(function(result) {
expect(result).toEqual([ { foo: { bar: { baz: 1 } } } ]) expect(result).toEqual([ { foo: { bar: { baz: 1 } } } ])
done() done()
}) })
}) })
it('replaces token with the passed array', function(done) { it('replaces token with the passed array', function(done) {
this.sequelize.query('select ? as foo, ? as bar', null, { raw: true }, [ 1, 2 ]).success(function(result) { sequelize.query('select ? as foo, ? as bar', null, { raw: true }, [ 1, 2 ]).success(function(result) {
expect(result).toEqual([{ foo: 1, bar: 2 }]) expect(result).toEqual([{ foo: 1, bar: 2 }])
done() done()
}) })
}) })
it('handles AS in conjunction with functions just fine', function(done) { it('handles AS in conjunction with functions just fine', function(done) {
this.sequelize.query('SELECT ' + (dialect === "sqlite" ? 'date(\'now\')' : 'NOW()') + ' AS t').success(function(result) { sequelize.query('SELECT ' + (dialect === "sqlite" ? 'date(\'now\')' : 'NOW()') + ' AS t').success(function(result) {
expect(moment(result[0].t).isValid()).toBeTrue() expect(moment(result[0].t).isValid()).toBeTrue()
done() done()
}) })
...@@ -197,9 +186,9 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -197,9 +186,9 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
describe('define', function() { describe('define', function() {
it("adds a new dao to the dao manager", function(done) { it("adds a new dao to the dao manager", function(done) {
expect(this.sequelize.daoFactoryManager.all.length).toEqual(0) expect(sequelize.daoFactoryManager.all.length).toEqual(0)
this.sequelize.define('foo', { title: Helpers.Sequelize.STRING }) sequelize.define('foo', { title: Helpers.Sequelize.STRING })
expect(this.sequelize.daoFactoryManager.all.length).toEqual(1) expect(sequelize.daoFactoryManager.all.length).toEqual(1)
done() done()
}) })
...@@ -239,7 +228,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -239,7 +228,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
var self = this var self = this
, Photo = this.sequelize.define('Foto', { name: Helpers.Sequelize.STRING }, { tableName: 'photos' }) , Photo = this.sequelize.define('Foto', { name: Helpers.Sequelize.STRING }, { tableName: 'photos' })
Photo.sync({ force: true }).success(function() { Photo.sync({ force: true }).success(function() {
self.sequelize.getQueryInterface().showAllTables().success(function(tableNames) { sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
expect(tableNames).toContain('photos') expect(tableNames).toContain('photos')
done() done()
}) })
...@@ -252,7 +241,8 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -252,7 +241,8 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
var Project = this.sequelize.define('project' + config.rand(), { title: Helpers.Sequelize.STRING }) var Project = this.sequelize.define('project' + config.rand(), { title: Helpers.Sequelize.STRING })
var Task = this.sequelize.define('task' + config.rand(), { title: Helpers.Sequelize.STRING }) var Task = this.sequelize.define('task' + config.rand(), { title: Helpers.Sequelize.STRING })
this.sequelize.sync().success(function() { Project.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
Project.create({title: 'bla'}).success(function() { Project.create({title: 'bla'}).success(function() {
Task.create({title: 'bla'}).success(function(task){ Task.create({title: 'bla'}).success(function(task){
expect(task).toBeDefined() expect(task).toBeDefined()
...@@ -262,9 +252,10 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -262,9 +252,10 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
}) })
}) })
}) })
})
it('works with correct database credentials', function(done) { it('works with correct database credentials', function(done) {
var User = this.sequelize.define('User', { username: Helpers.Sequelize.STRING }) var User = sequelize.define('User', { username: Helpers.Sequelize.STRING })
User.sync().success(function() { User.sync().success(function() {
expect(true).toBeTrue() expect(true).toBeTrue()
done() done()
...@@ -284,7 +275,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -284,7 +275,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
describe('drop should work', function() { describe('drop should work', function() {
it('correctly succeeds', function(done) { it('correctly succeeds', function(done) {
var User = this.sequelize.define('Users', {username: Helpers.Sequelize.STRING }) var User = sequelize.define('Users', {username: Helpers.Sequelize.STRING })
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.drop().success(function() { User.drop().success(function() {
expect(true).toBeTrue() expect(true).toBeTrue()
...@@ -296,7 +287,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -296,7 +287,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
describe('import', function() { describe('import', function() {
it("imports a dao definition from a file", function(done) { it("imports a dao definition from a file", function(done) {
var Project = this.sequelize.import(__dirname + "/assets/project") var Project = sequelize.import(__dirname + "/assets/project")
expect(Project).toBeDefined() expect(Project).toBeDefined()
done() done()
}) })
...@@ -309,16 +300,17 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -309,16 +300,17 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
].forEach(function(status) { ].forEach(function(status) {
describe('enum', function() { describe('enum', function() {
before(function(done) { before(function(done) {
this.Review = this.sequelize.define('review', { status: status }) this.Review = sequelize.define('review', { status: status })
this.Review.sync({ force: true }).success(done) this.Review.sync({ force: true }).success(done)
}) })
it('raises an error if no values are defined', function() { it('raises an error if no values are defined', function(done) {
Helpers.assertException(function() { expect(function() {
this.sequelize.define('omnomnom', { sequelize.define('omnomnom', {
bla: { type: Helpers.Sequelize.ENUM } bla: { type: Helpers.Sequelize.ENUM }
}) })
}.bind(this), 'Values for ENUM haven\'t been defined.') }).toThrow('Error', 'Values for ENUM haven\'t been defined.')
done()
}) })
it('correctly stores values', function(done) { it('correctly stores values', function(done) {
...@@ -329,18 +321,21 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -329,18 +321,21 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
}) })
it('correctly loads values', function(done) { it('correctly loads values', function(done) {
var self = this
this.Review.create({ status: 'active' }).success(function() { this.Review.create({ status: 'active' }).success(function() {
this.Review.findAll().success(function(reviews) { self.Review.findAll().success(function(reviews) {
expect(reviews[0].status).toEqual('active') expect(reviews[0].status).toEqual('active')
done() done()
}) })
}.bind(this)) })
}) })
it("doesn't save an instance if value is not in the range of enums", function() { it("doesn't save an instance if value is not in the range of enums", function(done) {
Helpers.assertException(function() { var self = this
this.Review.create({ status: 'fnord' }) expect(function() {
}.bind(this), 'Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished') self.Review.create({ status: 'fnord' })
}).toThrow('Error', 'Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished')
done()
}) })
}) })
}) })
...@@ -353,7 +348,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() { ...@@ -353,7 +348,7 @@ describe(Helpers.getTestDialectTeaser("Sequelize"), function() {
].forEach(function(customAttributes) { ].forEach(function(customAttributes) {
it('should be able to override options on the default attributes', function(done) { it('should be able to override options on the default attributes', function(done) {
var Picture = this.sequelize.define('picture', Helpers.Sequelize.Utils._.cloneDeep(customAttributes)) var Picture = sequelize.define('picture', Helpers.Sequelize.Utils._.cloneDeep(customAttributes))
Picture.sync({ force: true }).success(function() { Picture.sync({ force: true }).success(function() {
Object.keys(customAttributes).forEach(function(attribute) { Object.keys(customAttributes).forEach(function(attribute) {
Object.keys(customAttributes[attribute]).forEach(function(option) { Object.keys(customAttributes[attribute]).forEach(function(option) {
......
/* jshint camelcase: false */ /* jshint camelcase: false */
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, dbFile = __dirname + '/test.sqlite' , dbFile = __dirname + '/test.sqlite'
, storages = [dbFile] , storages = [dbFile]
, DataTypes = require(__dirname + "/../../lib/data-types") , DataTypes = require(__dirname + "/../../lib/data-types")
}
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
describe('[SQLITE] DAOFactory', function() { describe('[SQLITE] DAOFactory', function() {
before(function(done) { before(function(done) {
var self = this var self = this
this.sequelize = sequelize
Helpers.initTests({ Helpers.clearDatabase(this.sequelize, function() {
dialect: 'sqlite',
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', { self.User = sequelize.define('User', {
age: DataTypes.INTEGER, age: DataTypes.INTEGER,
name: DataTypes.STRING, name: DataTypes.STRING,
bio: DataTypes.TEXT bio: DataTypes.TEXT
}) })
},
onComplete: function() {
self.User.sync({ force: true }).success(done) self.User.sync({ force: true }).success(done)
}
}) })
}) })
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
} , DataTypes = require(__dirname + "/../../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
describe('[SQLITE] DAO', function() { describe('[SQLITE] DAO', function() {
before(function(done) { before(function(done) {
var self = this var self = this
this.sequelize = sequelize
Helpers.initTests({ Helpers.clearDatabase(this.sequelize, function() {
dialect: 'sqlite',
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', { self.User = sequelize.define('User', {
username: DataTypes.STRING username: DataTypes.STRING
}) })
},
onComplete: function() {
self.User.sync({ force: true }).success(done) self.User.sync({ force: true }).success(done)
}
}) })
}) })
...@@ -32,8 +27,8 @@ if (dialect === 'sqlite') { ...@@ -32,8 +27,8 @@ if (dialect === 'sqlite') {
this.User this.User
.create({ username: 'user', createdAt: new Date(2011, 04, 04) }) .create({ username: 'user', createdAt: new Date(2011, 04, 04) })
.success(function(oldUser) { .success(function() {
self.User.create({ username: 'new user' }).success(function(newUser) { self.User.create({ username: 'new user' }).success(function() {
self.User.findAll({ self.User.findAll({
where: ['createdAt > ?', new Date(2012, 01, 01)] where: ['createdAt > ?', new Date(2012, 01, 01)]
}).success(function(users) { }).success(function(users) {
......
if(typeof require === 'function') { var buster = require("buster")
const buster = require("buster")
, Helpers = require('../buster-helpers') , Helpers = require('../buster-helpers')
, dialect = Helpers.getTestDialect() , dialect = Helpers.getTestDialect()
, QueryGenerator = require("../../lib/dialects/sqlite/query-generator") , QueryGenerator = require("../../lib/dialects/sqlite/query-generator")
, util = require("util"); , util = require("util")
} , DataTypes = require(__dirname + "/../../lib/data-types")
buster.spec.expose() buster.spec.expose()
buster.testRunner.timeout = 1000 buster.testRunner.timeout = 1000
var sequelize = Helpers.createSequelizeInstance({dialect: dialect})
if (dialect === 'sqlite') { if (dialect === 'sqlite') {
describe('[SQLITE] QueryGenerator', function() { describe('[SQLITE] QueryGenerator', function() {
before(function(done) { before(function(done) {
var self = this var self = this
this.sequelize = sequelize
Helpers.initTests({ Helpers.clearDatabase(this.sequelize, function() {
dialect: 'sqlite',
beforeComplete: function(sequelize, DataTypes) {
self.sequelize = sequelize
self.User = sequelize.define('User', { self.User = sequelize.define('User', {
username: DataTypes.STRING username: DataTypes.STRING
}) })
},
onComplete: function() {
self.User.sync({ force: true }).success(done) self.User.sync({ force: true }).success(done)
}
}) })
}) })
......
module.exports = {
up: function(migration, DataTypes, done) {
migration
.createTable('Person', {
name: DataTypes.STRING,
isBetaMember: {
type: DataTypes.BOOLEAN,
defaultValue: false,
allowNull: false
}
})
.complete(done)
},
down: function(migration, DataTypes, done) {
migration.dropTable('Person').complete(done)
}
}
module.exports = {
up: function(migration, DataTypes, done) { done() },
down: function(migration, DataTypes, done) { done() }
}
module.exports = {
up: function(migration, DataTypes, done) {
migration.renameTable('Person', 'User').complete(done)
},
down: function(migration, DataTypes, done) {
migration.renameTable('User', 'Person').complete(done)
}
}
module.exports = {
up: function(migration, DataTypes, done) {
migration
.addColumn('User', 'isAdmin', { type: DataTypes.BOOLEAN, defaultValue: false, allowNull: false })
.complete(function(err) {
if (err) {
done(err)
} else {
migration
.addColumn('User', 'signature', DataTypes.TEXT)
.complete(function(err) {
if (err) {
done(err)
} else {
migration.addColumn('User', 'shopId', { type: DataTypes.INTEGER, allowNull: true }).complete(done)
}
})
}
})
},
down: function(migration, DataTypes, done) {
migration.removeColumn('User', 'signature').complete(function(err) {
if (err) {
done(err)
} else {
migration.removeColumn('User', 'shopId').complete(function(err) {
if (err) {
done(err)
} else {
migration.removeColumn('User', 'isAdmin').complete(done)
}
})
}
})
}
}
module.exports = {
up: function(migration, DataTypes, done) {
migration.removeColumn('User', 'shopId').complete(done)
},
down: function(migration, DataTypes, done) {
migration.addColumn('User', 'shopId', { type: DataTypes.INTEGER, allowNull: true }).complete(done)
}
}
module.exports = {
up: function(migration, DataTypes, done) {
migration.changeColumn('User', 'signature', {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'Signature'
}).complete(done)
},
down: function(migration, DataTypes, done) { done() }
}
module.exports = {
up: function(migration, DataTypes, done) {
migration.renameColumn('User', 'signature', 'sig').complete(done)
},
down: function(migration, DataTypes, done) {
migration.renameColumn('User', 'sig', 'signature').complete(done)
}
}
module.exports = function(sequelize, DataTypes) {
return sequelize.define('Project' + parseInt(Math.random() * 9999999999999999), {
name: DataTypes.STRING
})
}
\ No newline at end of file
module.exports = {
username: "root",
password: null,
database: 'sequelize_test',
host: '127.0.0.1',
pool: { maxConnections: 5, maxIdleTime: 30000},
rand: function() {
return parseInt(Math.random() * 999, 10)
},
//make maxIdleTime small so that tests exit promptly
mysql: {
username: "root",
password: null,
database: 'sequelize_test',
host: '127.0.0.1',
port: 3306,
pool: { maxConnections: 5, maxIdleTime: 30}
},
sqlite: {
},
postgres: {
database: 'sequelize_test',
username: "postgres",
port: 5432,
pool: { maxConnections: 5, maxIdleTime: 3000}
}
}
var chai = require('chai')
, expect = chai.expect
, config = require(__dirname + "/config/config")
, Support = require(__dirname + '/support')
, dialect = Support.getTestDialect()
, Sequelize = require(__dirname + '/../index')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("Configuration"), function() {
describe('Connections problems should fail with a nice message', function() {
it("when we don't have the correct server details", function(done) {
// mysql is not properly supported due to the custom pooling system
if (dialect !== "postgres" && dialect !== "postgres-native") {
console.log('This dialect doesn\'t support me :(')
expect(true).to.be.true // Silence Buster
return done()
}
var seq = new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {storage: '/path/to/no/where/land', logging: false, host: '0.0.0.1', port: config[dialect].port, dialect: dialect})
seq.query('select 1 as hello').error(function(err) {
expect(err.message).to.match(/Failed to find (.*?) Please double check your settings\./)
done()
})
})
it('when we don\'t have the correct login information', function(done) {
if (dialect !== "postgres" && dialect !== "postgres-native") {
console.log('This dialect doesn\'t support me :(')
expect(true).to.be.true // Silence Buster
return done()
}
var seq = new Sequelize(config[dialect].database, config[dialect].username, 'fakepass123', {logging: false, host: config[dialect].host, port: 1, dialect: dialect})
seq.query('select 1 as hello').error(function(err) {
expect(err.message).to.match(/^Failed to authenticate/)
done()
})
})
it('when we don\'t have a valid dialect.', function(done) {
expect(function() {
new Sequelize(config[dialect].database, config[dialect].username, config[dialect].password, {host: '0.0.0.1', port: config[dialect].port, dialect: undefined})
}).to.throw(Error, 'The dialect undefined is not supported.')
done()
})
})
describe('Instantiation with a URL string', function() {
it('should accept username, password, host, port, and database', function() {
var sequelize = new Sequelize('mysql://user:pass@example.com:9821/dbname')
var config = sequelize.config
var options = sequelize.options
expect(options.dialect).to.equal('mysql')
expect(config.database).to.equal('dbname')
expect(config.host).to.equal('example.com')
expect(config.username).to.equal('user')
expect(config.password).to.equal('pass')
expect(config.port).to.equal('9821')
})
it('should work with no authentication options', function(done) {
var sequelize = new Sequelize('mysql://example.com:9821/dbname')
var config = sequelize.config
expect(config.username).to.not.be.ok
expect(config.password).to.be.null
done()
})
it('should use the default port when no other is specified', function(done) {
var sequelize = new Sequelize('mysql://example.com/dbname')
var config = sequelize.config
// The default port should be set
expect(config.port).to.equal(3306)
done()
})
})
describe('Intantiation with arguments', function() {
it('should accept two parameters (database, username)', function(done) {
var sequelize = new Sequelize('dbname', 'root')
var config = sequelize.config
expect(config.database).to.equal('dbname')
expect(config.username).to.equal('root')
done()
})
it('should accept three parameters (database, username, password)', function(done) {
var sequelize = new Sequelize('dbname', 'root', 'pass')
var config = sequelize.config
expect(config.database).to.equal('dbname')
expect(config.username).to.equal('root')
expect(config.password).to.equal('pass')
done()
})
it('should accept four parameters (database, username, password, options)', function(done) {
var sequelize = new Sequelize('dbname', 'root', 'pass', { port: 999 })
var config = sequelize.config
expect(config.database).to.equal('dbname')
expect(config.username).to.equal('root')
expect(config.password).to.equal('pass')
expect(config.port).to.equal(999)
done()
})
})
})
/* jshint camelcase: false */
var chai = require('chai')
, Sequelize = require('../index')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, config = require(__dirname + "/config/config")
, sinon = require('sinon')
, datetime = require('chai-datetime')
, _ = require('lodash')
, moment = require('moment')
chai.use(datetime)
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("DAOFactory"), function () {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
secretValue: DataTypes.STRING,
data: DataTypes.STRING,
intVal: DataTypes.INTEGER,
theDate: DataTypes.DATE
})
this.User.sync({ force: true }).success(function() {
done()
})
})
describe('constructor', function() {
it("uses the passed dao name as tablename if freezeTableName", function(done) {
var User = this.sequelize.define('FrozenUser', {}, { freezeTableName: true })
expect(User.tableName).to.equal('FrozenUser')
done()
})
it("uses the pluralized dao name as tablename unless freezeTableName", function(done) {
var User = this.sequelize.define('SuperUser', {}, { freezeTableName: false })
expect(User.tableName).to.equal('SuperUsers')
done()
})
it("uses checks to make sure dao factory isnt leaking on multiple define", function(done) {
this.sequelize.define('SuperUser', {}, { freezeTableName: false })
var factorySize = this.sequelize.daoFactoryManager.all.length
this.sequelize.define('SuperUser', {}, { freezeTableName: false })
var factorySize2 = this.sequelize.daoFactoryManager.all.length
expect(factorySize).to.equal(factorySize2)
done()
})
it("attaches class and instance methods", function(done) {
var User = this.sequelize.define('UserWithClassAndInstanceMethods', {}, {
classMethods: { doSmth: function(){ return 1 } },
instanceMethods: { makeItSo: function(){ return 2}}
})
expect(User.doSmth).to.exist
expect(User.doSmth()).to.equal(1)
expect(User.makeItSo).not.to.exist
expect(User.build().doSmth).not.to.exist
expect(User.build().makeItSo).to.exist
expect(User.build().makeItSo()).to.equal(2)
done()
})
it("throws an error if 2 autoIncrements are passed", function(done) {
var self = this
expect(function() {
self.sequelize.define('UserWithTwoAutoIncrements', {
userid: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
userscore: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true }
})
}).to.throw(Error, 'Invalid DAO definition. Only one autoincrement field allowed.')
done()
})
it('throws an error if a custom model-wide validation is not a function', function(done) {
var self = this
expect(function() {
self.sequelize.define('Foo', {
field: Sequelize.INTEGER
}, {
validate: {
notFunction: 33
}
})
}).to.throw(Error, 'Members of the validate option must be functions. Model: Foo, error with validate member notFunction')
done()
})
it('throws an error if a custom model-wide validation has the same name as a field', function(done) {
var self = this
expect(function() {
self.sequelize.define('Foo', {
field: Sequelize.INTEGER
}, {
validate: {
field: function() {}
}
})
}).to.throw(Error, 'A model validator function must not have the same name as a field. Model: Foo, field/validation name: field')
done()
})
})
describe('build', function() {
it("doesn't create database entries", function(done) {
this.User.build({ username: 'John Wayne' })
this.User.all().success(function(users) {
expect(users).to.have.length(0)
done()
})
})
it("fills the objects with default values", function(done) {
var Task = this.sequelize.define('TaskBuild', {
title: {type: Sequelize.STRING, defaultValue: 'a task!'},
foo: {type: Sequelize.INTEGER, defaultValue: 2},
bar: {type: Sequelize.DATE},
foobar: {type: Sequelize.TEXT, defaultValue: 'asd'},
flag: {type: Sequelize.BOOLEAN, defaultValue: false}
})
expect(Task.build().title).to.equal('a task!')
expect(Task.build().foo).to.equal(2)
expect(Task.build().bar).to.not.be.ok
expect(Task.build().foobar).to.equal('asd')
expect(Task.build().flag).to.be.false
done()
})
it("fills the objects with default values", function(done) {
var Task = this.sequelize.define('TaskBuild', {
title: {type: Sequelize.STRING, defaultValue: 'a task!'},
foo: {type: Sequelize.INTEGER, defaultValue: 2},
bar: {type: Sequelize.DATE},
foobar: {type: Sequelize.TEXT, defaultValue: 'asd'},
flag: {type: Sequelize.BOOLEAN, defaultValue: false}
}, { timestamps: false })
expect(Task.build().title).to.equal('a task!')
expect(Task.build().foo).to.equal(2)
expect(Task.build().bar).to.not.be.ok
expect(Task.build().foobar).to.equal('asd')
expect(Task.build().flag).to.be.false
done()
})
it("stores the the passed values in a special variable", function(done) {
var user = this.User.build({ username: 'John Wayne' })
expect(user.selectedValues).to.deep.equal({ username: 'John Wayne' })
done()
})
it("attaches getter and setter methods from attribute definition", function(done) {
var Product = this.sequelize.define('ProductWithSettersAndGetters1', {
price: {
type: Sequelize.INTEGER,
get : function() {
return 'answer = ' + this.getDataValue('price')
},
set : function(v) {
return this.setDataValue('price', v + 42)
}
}
})
expect(Product.build({price: 42}).price).to.equal('answer = 84')
var p = Product.build({price: 1})
expect(p.price).to.equal('answer = 43');
p.price = 0
expect(p.price).to.equal('answer = 42')
done()
})
it("attaches getter and setter methods from options", function(done) {
var Product = this.sequelize.define('ProductWithSettersAndGetters2', {
priceInCents: Sequelize.INTEGER
},{
setterMethods: {
price: function(value) {
this.dataValues.priceInCents = value * 100
}
},
getterMethods: {
price: function() {
return '$' + (this.getDataValue('priceInCents') / 100)
},
priceInCents: function() {
return this.dataValues.priceInCents
}
}
});
expect(Product.build({price: 20}).priceInCents).to.equal(20 * 100)
expect(Product.build({priceInCents: 30 * 100}).price).to.equal('$' + 30)
done()
})
it("attaches getter and setter methods from options only if not defined in attribute", function(done) {
var Product = this.sequelize.define('ProductWithSettersAndGetters3', {
price1: {
type: Sequelize.INTEGER,
set : function(v) { this.setDataValue('price1', v * 10) }
},
price2: {
type: Sequelize.INTEGER,
get : function() { return this.getDataValue('price2') * 10 }
}
},{
setterMethods: {
price1: function(v) { this.setDataValue('price1', v * 100) }
},
getterMethods: {
price2: function() { return '$' + this.getDataValue('price2') }
}
});
var p = Product.build({ price1: 1, price2: 2 })
expect(p.price1).to.equal(10)
expect(p.price2).to.equal(20)
done()
})
})
describe('findOrCreate', function () {
it("Returns instace if already existent. Single find field.", function(done) {
var self = this,
data = {
username: 'Username'
};
this.User.create(data).success(function (user) {
self.User.findOrCreate({
username: user.username
}).success(function (_user, created) {
expect(_user.id).to.equal(user.id)
expect(_user.username).to.equal('Username')
expect(created).to.be.false
done()
})
})
})
it("Returns instace if already existent. Multiple find fields.", function(done) {
var self = this,
data = {
username: 'Username',
data: 'ThisIsData'
};
this.User.create(data).success(function (user) {
self.User.findOrCreate(data).success(function (_user, created) {
expect(_user.id).to.equal(user.id)
expect(_user.username).to.equal('Username')
expect(_user.data).to.equal('ThisIsData')
expect(created).to.be.false
done()
})
})
})
it("creates new instance with default value.", function(done) {
var data = {
username: 'Username'
},
default_values = {
data: 'ThisIsData'
};
this.User.findOrCreate(data, default_values).success(function(user, created) {
expect(user.username).to.equal('Username')
expect(user.data).to.equal('ThisIsData')
expect(created).to.be.true
done()
})
})
})
describe('create', function() {
it("casts empty arrays correctly for postgresql", function(done) {
if (dialect !== "postgres" && dialect !== "postgresql-native") {
expect('').to.equal('')
return done()
}
var User = this.sequelize.define('UserWithArray', {
myvals: { type: Sequelize.ARRAY(Sequelize.INTEGER) },
mystr: { type: Sequelize.ARRAY(Sequelize.STRING) }
})
User.sync({force: true}).success(function() {
User.create({myvals: [], mystr: []}).on('sql', function(sql){
expect(sql.indexOf('ARRAY[]::INTEGER[]')).to.be.above(-1)
expect(sql.indexOf('ARRAY[]::VARCHAR[]')).to.be.above(-1)
done()
})
})
})
it("doesn't allow duplicated records with unique:true", function(done) {
var User = this.sequelize.define('UserWithUniqueUsername', {
username: { type: Sequelize.STRING, unique: true }
})
User.sync({ force: true }).success(function() {
User.create({ username:'foo' }).success(function() {
User.create({ username: 'foo' }).error(function(err) {
expect(err).to.exist
if (dialect === "sqlite") {
expect(err.message).to.match(/.*SQLITE_CONSTRAINT.*/)
}
else if (dialect === "mysql") {
expect(err.message).to.match(/.*Duplicate\ entry.*/)
} else {
expect(err.message).to.match(/.*duplicate\ key\ value.*/)
}
done()
})
})
})
})
it("raises an error if created object breaks definition contraints", function(done) {
var UserNull = this.sequelize.define('UserWithNonNullSmth', {
username: { type: Sequelize.STRING, unique: true },
smth: { type: Sequelize.STRING, allowNull: false }
})
UserNull.sync({ force: true }).success(function() {
UserNull.create({ username: 'foo', smth: null }).error(function(err) {
expect(err).to.exist
if (dialect === "mysql") {
// We need to allow two different errors for MySQL, see:
// http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_trans_tables
expect(err.message).to.match(/(Column 'smth' cannot be null|Field 'smth' doesn't have a default value)/)
}
else if (dialect === "sqlite") {
expect(err.message).to.match(/.*SQLITE_CONSTRAINT.*/)
} else {
expect(err.message).to.match(/.*column "smth" violates not-null.*/)
}
UserNull.create({ username: 'foo', smth: 'foo' }).success(function() {
UserNull.create({ username: 'foo', smth: 'bar' }).error(function(err) {
expect(err).to.exist
if (dialect === "sqlite") {
expect(err.message).to.match(/.*SQLITE_CONSTRAINT.*/)
}
else if (dialect === "mysql") {
expect(err.message).to.match(/Duplicate entry 'foo' for key 'username'/)
} else {
expect(err.message).to.match(/.*duplicate key value violates unique constraint.*/)
}
done()
})
})
})
})
})
it('raises an error if you mess up the datatype', function(done) {
var self = this
expect(function() {
self.sequelize.define('UserBadDataType', {
activity_date: Sequelize.DATe
})
}).to.throw(Error, 'Unrecognized data type for field activity_date')
expect(function() {
self.sequelize.define('UserBadDataType', {
activity_date: {type: Sequelize.DATe}
})
}).to.throw(Error, 'Unrecognized data type for field activity_date')
done()
})
it('sets a 64 bit int in bigint', function(done) {
var User = this.sequelize.define('UserWithBigIntFields', {
big: Sequelize.BIGINT
})
User.sync({ force: true }).success(function() {
User.create({ big: '9223372036854775807' }).on('success', function(user) {
expect(user.big).to.be.equal( '9223372036854775807' )
done()
})
})
})
it('sets auto increment fields', function(done) {
var User = this.sequelize.define('UserWithAutoIncrementField', {
userid: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true, allowNull: false }
})
User.sync({ force: true }).success(function() {
User.create({}).on('success', function(user) {
expect(user.userid).to.equal(1)
User.create({}).on('success', function(user) {
expect(user.userid).to.equal(2)
done()
})
})
})
})
it('allows the usage of options as attribute', function(done) {
var User = this.sequelize.define('UserWithNameAndOptions', {
name: Sequelize.STRING,
options: Sequelize.TEXT
})
var options = JSON.stringify({ foo: 'bar', bar: 'foo' })
User.sync({ force: true }).success(function() {
User
.create({ name: 'John Doe', options: options })
.success(function(user) {
expect(user.options).to.equal(options)
done()
})
})
})
it('allows sql logging', function(done) {
var User = this.sequelize.define('UserWithUniqueNameAndNonNullSmth', {
name: {type: Sequelize.STRING, unique: true},
smth: {type: Sequelize.STRING, allowNull: false}
})
User.sync({ force: true }).success(function() {
User
.create({ name: 'Fluffy Bunny', smth: 'else' })
.on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("INSERT")).to.be.above(-1)
done()
})
})
})
it('should only store the values passed in the whitelist', function(done) {
var self = this
, data = { username: 'Peter', secretValue: '42' }
this.User.create(data, ['username']).success(function(user) {
self.User.find(user.id).success(function(_user) {
expect(_user.username).to.equal(data.username)
expect(_user.secretValue).not.to.equal(data.secretValue)
expect(_user.secretValue).to.equal(null)
done()
})
})
})
it('should store all values if no whitelist is specified', function(done) {
var self = this
, data = { username: 'Peter', secretValue: '42' }
this.User.create(data).success(function(user) {
self.User.find(user.id).success(function(_user) {
expect(_user.username).to.equal(data.username)
expect(_user.secretValue).to.equal(data.secretValue)
done()
})
})
})
it('can omitt autoincremental columns', function(done) {
var self = this
, data = { title: 'Iliad' }
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT]
, chain = new Sequelize.Utils.QueryChainer()
, chain2 = new Sequelize.Utils.QueryChainer()
, books = []
dataTypes.forEach(function(dataType, index) {
books[index] = self.sequelize.define('Book'+index, {
id: { type: dataType, primaryKey: true, autoIncrement: true },
title: Sequelize.TEXT
})
})
books.forEach(function(b) {
chain.add(b.sync({ force: true }))
})
chain.run().success(function() {
books.forEach(function(b) {
chain2.add(b.create(data))
})
chain2.run().success(function(results) {
results.forEach(function(book, index) {
expect(book.title).to.equal(data.title)
expect(book.author).to.equal(data.author)
expect(books[index].rawAttributes.id.type.toString())
.to.equal(dataTypes[index].toString())
})
done()
})
})
})
it('saves data with single quote', function(done) {
var quote = "single'quote"
, self = this
this.User.create({ data: quote }).success(function(user) {
expect(user.data).to.equal(quote)
self.User.find({where: { id: user.id }}).success(function(user) {
expect(user.data).to.equal(quote)
done()
})
})
})
it('saves data with double quote', function(done) {
var quote = 'double"quote'
, self = this
this.User.create({ data: quote }).success(function(user) {
expect(user.data).to.equal(quote)
self.User.find({where: { id: user.id }}).success(function(user) {
expect(user.data).to.equal(quote)
done()
})
})
})
it('saves stringified JSON data', function(done) {
var json = JSON.stringify({ key: 'value' })
, self = this
this.User.create({ data: json }).success(function(user) {
expect(user.data).to.equal(json)
self.User.find({where: { id: user.id }}).success(function(user) {
expect(user.data).to.equal(json)
done()
})
})
})
it('stores the current date in createdAt', function(done) {
this.User.create({ username: 'foo' }).success(function(user) {
expect(parseInt(+user.createdAt/5000, 10)).to.be.closeTo(parseInt(+new Date()/5000, 10), 1.5)
done()
})
})
it('allows setting custom IDs', function(done) {
var self = this
this.User.create({ id: 42 }).success(function (user) {
expect(user.id).to.equal(42)
self.User.find(42).success(function (user) {
expect(user).to.exist
done()
})
})
})
describe('enums', function() {
it('correctly restores enum values', function(done) {
var self = this
, Item = self.sequelize.define('Item', {
state: { type: Sequelize.ENUM, values: ['available', 'in_cart', 'shipped'] }
})
Item.sync({ force: true }).success(function() {
Item.create({ state: 'available' }).success(function(_item) {
Item.find({ where: { state: 'available' }}).success(function(item) {
expect(item.id).to.equal(_item.id)
done()
})
})
})
})
})
})
describe('bulkCreate', function() {
it('properly handles disparate field lists', function(done) {
var self = this
, data = [{username: 'Peter', secretValue: '42' },
{username: 'Paul'},
{username: 'Steve'}]
this.User.bulkCreate(data).success(function() {
self.User.findAll({where: {username: 'Paul'}}).success(function(users) {
expect(users.length).to.equal(1)
expect(users[0].username).to.equal("Paul")
expect(users[0].secretValue).to.be.null
done()
})
})
})
it('inserts multiple values respecting the white list', function(done) {
var self = this
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '23'}]
this.User.bulkCreate(data, ['username']).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].username).to.equal("Peter")
expect(users[0].secretValue).to.be.null;
expect(users[1].username).to.equal("Paul")
expect(users[1].secretValue).to.be.null;
done()
})
})
})
it('should store all values if no whitelist is specified', function(done) {
var self = this
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '23'}]
this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].username).to.equal("Peter")
expect(users[0].secretValue).to.equal('42')
expect(users[1].username).to.equal("Paul")
expect(users[1].secretValue).to.equal('23')
done()
})
})
})
it('saves data with single quote', function(done) {
var self = this
, quote = "Single'Quote"
, data = [{ username: 'Peter', data: quote},
{ username: 'Paul', data: quote}]
this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].username).to.equal("Peter")
expect(users[0].data).to.equal(quote)
expect(users[1].username).to.equal("Paul")
expect(users[1].data).to.equal(quote)
done()
})
})
})
it('saves data with double quote', function(done) {
var self = this
, quote = 'Double"Quote'
, data = [{ username: 'Peter', data: quote},
{ username: 'Paul', data: quote}]
this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].username).to.equal("Peter")
expect(users[0].data).to.equal(quote)
expect(users[1].username).to.equal("Paul")
expect(users[1].data).to.equal(quote)
done()
})
})
})
it('saves stringified JSON data', function(done) {
var self = this
, json = JSON.stringify({ key: 'value' })
, data = [{ username: 'Peter', data: json},
{ username: 'Paul', data: json}]
this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].username).to.equal("Peter")
expect(users[0].data).to.equal(json)
expect(users[1].username).to.equal("Paul")
expect(users[1].data).to.equal(json)
done()
})
})
})
it('stores the current date in createdAt', function(done) {
var self = this
, data = [{ username: 'Peter'},
{ username: 'Paul'}]
this.User.bulkCreate(data).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].username).to.equal("Peter")
expect(parseInt(+users[0].createdAt/5000, 10)).to.equal(parseInt(+new Date()/5000, 10))
expect(users[1].username).to.equal("Paul")
expect(parseInt(+users[1].createdAt/5000, 10)).to.equal(parseInt(+new Date()/5000, 10))
done()
})
})
})
describe('enums', function() {
it('correctly restores enum values', function(done) {
var self = this
, Item = self.sequelize.define('Item', {
state: { type: Sequelize.ENUM, values: ['available', 'in_cart', 'shipped'] },
name: Sequelize.STRING
})
Item.sync({ force: true }).success(function() {
Item.bulkCreate([{state: 'in_cart', name: 'A'}, { state: 'available', name: 'B'}]).success(function() {
Item.find({ where: { state: 'available' }}).success(function(item) {
expect(item.name).to.equal('B')
done()
})
})
})
})
})
})
describe('update', function() {
it('allows sql logging of updated statements', function(done) {
var User = this.sequelize.define('User', {
name: Sequelize.STRING,
bio: Sequelize.TEXT
}, {
paranoid:true
})
User.sync({ force: true }).success(function() {
User.create({ name: 'meg', bio: 'none' }).success(function(u) {
expect(u).to.exist
expect(u).not.to.be.null
u.updateAttributes({name: 'brian'}).on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("UPDATE")).to.be.above(-1)
done()
})
})
})
})
it('updates only values that match filter', function(done) {
var self = this
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '42' },
{ username: 'Bob', secretValue: '43' }]
this.User.bulkCreate(data).success(function() {
self.User.update({username: 'Bill'}, {secretValue: '42'})
.success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(3)
users.forEach(function (user) {
if (user.secretValue == '42') {
expect(user.username).to.equal("Bill")
} else {
expect(user.username).to.equal("Bob")
}
})
done()
})
})
})
})
it('sets updatedAt to the current timestamp', function(done) {
var self = this
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '42' },
{ username: 'Bob', secretValue: '43' }]
this.User.bulkCreate(data).success(function() {
self.User.update({username: 'Bill'}, {secretValue: '42'}).success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(3)
expect(users[0].username).to.equal("Bill")
expect(users[1].username).to.equal("Bill")
expect(users[2].username).to.equal("Bob")
expect(parseInt(+users[0].updatedAt/5000, 10)).to.equal(parseInt(+new Date()/5000, 10))
expect(parseInt(+users[1].updatedAt/5000, 10)).to.equal(parseInt(+new Date()/5000, 10))
done()
})
})
})
})
})
describe('destroy', function() {
it('deletes a record from the database if dao is not paranoid', function(done) {
var UserDestroy = this.sequelize.define('UserDestory', {
name: Sequelize.STRING,
bio: Sequelize.TEXT
})
UserDestroy.sync({ force: true }).success(function() {
UserDestroy.create({name: 'hallo', bio: 'welt'}).success(function(u) {
UserDestroy.all().success(function(users) {
expect(users.length).to.equal(1)
u.destroy().success(function() {
UserDestroy.all().success(function(users) {
expect(users.length).to.equal(0)
done()
})
})
})
})
})
})
it('allows sql logging of delete statements', function(done) {
var UserDelete = this.sequelize.define('UserDelete', {
name: Sequelize.STRING,
bio: Sequelize.TEXT
})
UserDelete.sync({ force: true }).success(function() {
UserDelete.create({name: 'hallo', bio: 'welt'}).success(function(u) {
UserDelete.all().success(function(users) {
expect(users.length).to.equal(1)
u.destroy().on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("DELETE")).to.be.above(-1)
done()
})
})
})
})
})
it('deletes values that match filter', function(done) {
var self = this
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '42' },
{ username: 'Bob', secretValue: '43' }]
this.User.bulkCreate(data).success(function() {
self.User.destroy({secretValue: '42'})
.success(function() {
self.User.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(1)
expect(users[0].username).to.equal("Bob")
done()
})
})
})
})
it('sets deletedAt to the current timestamp if paranoid is true', function(done) {
var self = this
, ParanoidUser = self.sequelize.define('ParanoidUser', {
username: Sequelize.STRING,
secretValue: Sequelize.STRING,
data: Sequelize.STRING,
intVal: { type: Sequelize.INTEGER, defaultValue: 1}
}, {
paranoid: true
})
, data = [{ username: 'Peter', secretValue: '42' },
{ username: 'Paul', secretValue: '42' },
{ username: 'Bob', secretValue: '43' }]
ParanoidUser.sync({ force: true }).success(function() {
ParanoidUser.bulkCreate(data).success(function() {
var date = parseInt(+new Date()/5000, 10)
ParanoidUser.destroy({secretValue: '42'}).success(function() {
ParanoidUser.findAll({order: 'id'}).success(function(users) {
expect(users.length).to.equal(3)
expect(users[0].username).to.equal("Peter")
expect(users[1].username).to.equal("Paul")
expect(users[2].username).to.equal("Bob")
expect(parseInt(+users[0].deletedAt/5000, 10)).to.equal(date)
expect(parseInt(+users[1].deletedAt/5000, 10)).to.equal(date)
done()
})
})
})
})
})
})
describe('special where conditions/smartWhere object', function() {
beforeEach(function(done) {
var self = this
this.User.bulkCreate([
{username: 'boo', intVal: 5, theDate: '2013-01-01 12:00'},
{username: 'boo2', intVal: 10, theDate: '2013-01-10 12:00'}
]).success(function(user2){
done()
})
})
it('should be able to retun a record with primaryKey being null for new inserts', function(done) {
var Session = this.sequelize.define('Session', {
token: { type: DataTypes.TEXT, allowNull: false },
lastUpdate: { type: DataTypes.DATE, allowNull: false }
}, {
charset: 'utf8',
collate: 'utf8_general_ci',
omitNull: true
})
, User = this.sequelize.define('User', {
name: { type: DataTypes.STRING, allowNull: false, unique: true },
password: { type: DataTypes.STRING, allowNull: false },
isAdmin: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false }
}, {
charset: 'utf8',
collate: 'utf8_general_ci'
})
User.hasMany(Session, { as: 'Sessions' })
Session.belongsTo(User)
Session.sync({ force: true }).success(function() {
User.sync({ force: true }).success(function() {
User.create({name: 'Name1', password: '123', isAdmin: false}).success(function(user) {
var sess = Session.build({
lastUpdate: new Date(),
token: '123'
})
user.addSession(sess).success(function(u) {
expect(u.token).to.equal('123')
done()
})
})
})
})
})
it('should be able to find a row between a certain date', function(done) {
this.User.findAll({
where: {
theDate: {
between: ['2013-01-02', '2013-01-11']
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo2')
expect(users[0].intVal).to.equal(10)
done()
})
})
it('should be able to find a row between a certain date and an additional where clause', function(done) {
this.User.findAll({
where: {
theDate: {
between: ['2013-01-02', '2013-01-11']
},
intVal: 10
}
}).success(function(users) {
expect(users[0].username).to.equal('boo2')
expect(users[0].intVal).to.equal(10)
done()
})
})
it('should be able to find a row not between a certain integer', function(done) {
this.User.findAll({
where: {
intVal: {
nbetween: [8, 10]
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo')
expect(users[0].intVal).to.equal(5)
done()
})
})
it('should be able to find a row using not between and between logic', function(done) {
this.User.findAll({
where: {
theDate: {
between: ['2012-12-10', '2013-01-02'],
nbetween: ['2013-01-04', '2013-01-20']
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo')
expect(users[0].intVal).to.equal(5)
done()
})
})
it('should be able to find a row using not between and between logic with dates', function(done) {
this.User.findAll({
where: {
theDate: {
between: [new Date('2012-12-10'), new Date('2013-01-02')],
nbetween: [new Date('2013-01-04'), new Date('2013-01-20')]
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo')
expect(users[0].intVal).to.equal(5)
done()
})
})
it('should be able to find a row using greater than or equal to logic with dates', function(done) {
this.User.findAll({
where: {
theDate: {
gte: new Date('2013-01-09')
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo2')
expect(users[0].intVal).to.equal(10)
done()
})
})
it('should be able to find a row using greater than or equal to', function(done) {
this.User.find({
where: {
intVal: {
gte: 6
}
}
}).success(function(user) {
expect(user.username).to.equal('boo2')
expect(user.intVal).to.equal(10)
done()
})
})
it('should be able to find a row using greater than', function(done) {
this.User.find({
where: {
intVal: {
gt: 5
}
}
}).success(function(user) {
expect(user.username).to.equal('boo2')
expect(user.intVal).to.equal(10)
done()
})
})
it('should be able to find a row using lesser than or equal to', function(done) {
this.User.find({
where: {
intVal: {
lte: 5
}
}
}).success(function(user) {
expect(user.username).to.equal('boo')
expect(user.intVal).to.equal(5)
done()
})
})
it('should be able to find a row using lesser than', function(done) {
this.User.find({
where: {
intVal: {
lt: 6
}
}
}).success(function(user) {
expect(user.username).to.equal('boo')
expect(user.intVal).to.equal(5)
done()
})
})
it('should have no problem finding a row using lesser and greater than', function(done) {
this.User.findAll({
where: {
intVal: {
lt: 6,
gt: 4
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo')
expect(users[0].intVal).to.equal(5)
done()
})
})
it('should be able to find a row using not equal to logic', function(done) {
this.User.find({
where: {
intVal: {
ne: 10
}
}
}).success(function(user) {
expect(user.username).to.equal('boo')
expect(user.intVal).to.equal(5)
done()
})
})
it('should be able to find multiple users with any of the special where logic properties', function(done) {
this.User.findAll({
where: {
intVal: {
lte: 10
}
}
}).success(function(users) {
expect(users[0].username).to.equal('boo')
expect(users[0].intVal).to.equal(5)
expect(users[1].username).to.equal('boo2')
expect(users[1].intVal).to.equal(10)
done()
})
})
})
describe('find', function() {
describe('general / basic function', function() {
beforeEach(function(done) {
var self = this
this.User.create({username: 'barfooz'}).success(function(user) {
self.UserPrimary = self.sequelize.define('UserPrimary', {
specialKey: {
type: DataTypes.STRING,
primaryKey: true
}
})
self.UserPrimary.sync({force: true}).success(function() {
self.UserPrimary.create({specialKey: 'a string'}).success(function() {
self.user = user
done()
})
})
})
})
it('doesn\'t throw an error when entering in a non integer value for a specified primary field', function(done) {
this.UserPrimary.find('a string').success(function(user) {
expect(user.specialKey).to.equal('a string')
done()
})
})
it('doesn\'t throw an error when entering in a non integer value', function(done) {
this.User.find('a string value').success(function(user) {
expect(user).to.be.null
done()
})
})
it('returns a single dao', function(done) {
var self = this
this.User.find(this.user.id).success(function(user) {
expect(Array.isArray(user)).to.not.be.ok
expect(user.id).to.equal(self.user.id)
expect(user.id).to.equal(1)
done()
})
})
it('returns a single dao given a string id', function(done) {
var self = this
this.User.find(this.user.id + '').success(function(user) {
expect(Array.isArray(user)).to.not.be.ok
expect(user.id).to.equal(self.user.id)
expect(user.id).to.equal(1)
done()
})
})
it("should make aliased attributes available", function(done) {
this.User.find({
where: { id: 1 },
attributes: ['id', ['username', 'name']]
}).success(function(user) {
expect(user.name).to.equal('barfooz')
done()
})
})
it("should not try to convert boolean values if they are not selected", function(done) {
var UserWithBoolean = this.sequelize.define('UserBoolean', {
active: Sequelize.BOOLEAN
})
UserWithBoolean.sync({force: true}).success(function () {
UserWithBoolean.create({ active: true }).success(function(user) {
UserWithBoolean.find({ where: { id: user.id }, attributes: [ 'id' ] }).success(function(user) {
expect(user.active).not.to.exist
done()
})
})
})
})
it('finds a specific user via where option', function(done) {
this.User.find({ where: { username: 'barfooz' } }).success(function(user) {
expect(user.username).to.equal('barfooz')
done()
})
})
it("doesn't find a user if conditions are not matching", function(done) {
this.User.find({ where: { username: 'foo' } }).success(function(user) {
expect(user).to.be.null
done()
})
})
it('allows sql logging', function(done) {
this.User.find({ where: { username: 'foo' } }).on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("SELECT")).to.be.above(-1)
done()
})
})
it('ignores passed limit option', function(done) {
this.User.find({ limit: 10 }).success(function(user) {
// it returns an object instead of an array
expect(Array.isArray(user)).to.not.be.ok
expect(user.hasOwnProperty('username')).to.be.ok
done()
})
})
it('finds entries via primary keys', function(done) {
var self = this
, UserPrimary = self.sequelize.define('UserWithPrimaryKey', {
identifier: {type: Sequelize.STRING, primaryKey: true},
name: Sequelize.STRING
})
UserPrimary.sync({ force: true }).success(function() {
UserPrimary.create({
identifier: 'an identifier',
name: 'John'
}).success(function(u) {
expect(u.id).not.to.exist
UserPrimary.find('an identifier').success(function(u2) {
expect(u2.identifier).to.equal('an identifier')
expect(u2.name).to.equal('John')
done()
})
})
})
})
it('returns the selected fields as instance.selectedValues', function(done) {
var self = this
this.User.create({
username: 'JohnXOXOXO'
}).success(function() {
self.User.find({
where: { username: 'JohnXOXOXO' },
attributes: ['username']
}).success(function(user) {
expect(user.selectedValues).to.have.property('username', 'JohnXOXOXO')
done()
})
})
})
it('returns the selected fields and all fields of the included table as instance.selectedValues', function(done) {
var self = this
self.Mission = self.sequelize.define('Mission', {
title: {type: Sequelize.STRING, defaultValue: 'a mission!!'},
foo: {type: Sequelize.INTEGER, defaultValue: 2},
})
self.Mission.belongsTo(self.User)
self.User.hasMany(self.Mission)
self.Mission.sync({ force: true }).success(function() {
self.Mission.create().success(function(mission) {
self.User.create({username: 'John DOE'}).success(function(user) {
mission.setUser(user).success(function() {
self.User.find({
where: { username: 'John DOE' },
attributes: ['username'],
include: [self.Mission]
}).success(function(user) {
expect(user.selectedValues).to.deep.equal({ username: 'John DOE' })
done()
})
})
})
})
})
})
it('always honors ZERO as primary key', function(_done) {
var self = this
, permutations = [
0,
'0',
{where: {id: 0}},
{where: {id: '0'}}
]
, done = _.after(2 * permutations.length, _done);
this.User.bulkCreate([{username: 'jack'}, {username: 'jack'}]).success(function() {
permutations.forEach(function(perm) {
self.User.find(perm).done(function(err, user) {
expect(err).to.be.null;
expect(user).to.be.null;
done();
}).on('sql', function(s) {
expect(s.indexOf(0)).not.to.equal(-1);
done();
})
})
})
})
})
describe('eager loading', function() {
beforeEach(function(done) {
var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
this.init = function(callback) {
self.Task.sync({ force: true }).success(function() {
self.Worker.sync({ force: true }).success(function() {
self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
callback()
})
})
})
})
}
done()
})
describe('belongsTo', function() {
describe('generic', function() {
it('throws an error about unexpected input if include contains a non-object', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ 1 ] })
}).to.throw(Error, 'Include unexpected. Element has to be either an instance of DAOFactory or an object.')
done()
})
it('throws an error about missing attributes if include contains an object with daoFactory', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ { daoFactory: self.Worker } ] })
}).to.throw(Error, 'Include malformed. Expected attributes: daoFactory, as!')
done()
})
it('throws an error if included DaoFactory is not associated', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ self.Task ] })
}).to.throw(Error, 'Task is not associated to Worker!')
done()
})
it('returns the associated worker via task.worker', function(done) {
var self = this
this.Task.belongsTo(this.Worker)
this.init(function() {
self.task.setWorker(self.worker).success(function() {
self.Task.find({
where: { title: 'homework' },
include: [ self.Worker ]
}).complete(function(err, task) {
expect(err).to.be.null
expect(task).to.exist
expect(task.worker).to.exist
expect(task.worker.name).to.equal('worker')
done()
})
})
})
})
})
it('returns the private and public ip', function(done) {
var self = Object.create(this)
self.Domain = self.sequelize.define('Domain', { ip: Sequelize.STRING })
self.Environment = self.sequelize.define('Environment', { name: Sequelize.STRING })
self.Environment
.belongsTo(self.Domain, { as: 'PrivateDomain', foreignKey: 'privateDomainId' })
.belongsTo(self.Domain, { as: 'PublicDomain', foreignKey: 'publicDomainId' })
self.Domain.sync({ force: true }).success(function() {
self.Environment.sync({ force: true }).success(function() {
self.Domain.create({ ip: '192.168.0.1' }).success(function(privateIp) {
self.Domain.create({ ip: '91.65.189.19' }).success(function(publicIp) {
self.Environment.create({ name: 'environment' }).success(function(env) {
env.setPrivateDomain(privateIp).success(function() {
env.setPublicDomain(publicIp).success(function() {
self.Environment.find({
where: { name: 'environment' },
include: [
{ daoFactory: self.Domain, as: 'PrivateDomain' },
{ daoFactory: self.Domain, as: 'PublicDomain' }
]
}).complete(function(err, environment) {
expect(err).to.be.null
expect(environment).to.exist
expect(environment.privateDomain).to.exist
expect(environment.privateDomain.ip).to.equal('192.168.0.1')
expect(environment.publicDomain).to.exist
expect(environment.publicDomain.ip).to.equal('91.65.189.19')
done()
})
})
})
})
})
})
})
})
})
})
describe('hasOne', function() {
beforeEach(function(done) {
var self = this
this.Worker.hasOne(this.Task)
this.init(function() {
self.worker.setTask(self.task).success(function() {
done()
})
})
})
it('throws an error if included DaoFactory is not associated', function(done) {
var self = this
expect(function() {
self.Task.find({ include: [ self.Worker ] })
}).to.throw(Error, 'Worker is not associated to Task!')
done()
})
it('returns the associated task via worker.task', function(done) {
this.Worker.find({
where: { name: 'worker' },
include: [ this.Task ]
}).complete(function(err, worker) {
expect(err).to.be.null
expect(worker).to.exist
expect(worker.task).to.exist
expect(worker.task.title).to.equal('homework')
done()
})
})
})
describe('hasOne with alias', function() {
it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ self.Task ] })
}).to.throw(Error, 'Task is not associated to Worker!')
done()
})
describe('alias', function(done) {
beforeEach(function(done) {
var self = this
this.Worker.hasOne(this.Task, { as: 'ToDo' })
this.init(function() {
self.worker.setToDo(self.task).success(function() {
done()
})
})
})
it('throws an error if alias is not associated', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done()
})
it('returns the associated task via worker.task', function(done) {
this.Worker.find({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDo' } ]
}).complete(function(err, worker) {
expect(err).to.be.null
expect(worker).to.exist
expect(worker.toDo).to.exist
expect(worker.toDo.title).to.equal('homework')
done()
})
})
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
this.Worker.find({
where: { name: 'worker' },
include: [ { model: this.Task, as: 'ToDo' } ]
}).complete(function(err, worker) {
expect(worker.toDo.title).to.equal('homework')
done()
})
})
})
})
describe('hasMany', function() {
beforeEach(function(done) {
var self = this
this.Worker.hasMany(this.Task)
this.init(function() {
self.worker.setTasks([ self.task ]).success(function() {
done()
})
})
})
it('throws an error if included DaoFactory is not associated', function(done) {
var self = this
expect(function() {
self.Task.find({ include: [ self.Worker ] })
}).to.throw(Error, 'Worker is not associated to Task!')
done()
})
it('returns the associated tasks via worker.tasks', function(done) {
this.Worker.find({
where: { name: 'worker' },
include: [ this.Task ]
}).complete(function(err, worker) {
expect(err).to.be.null
expect(worker).to.exist
expect(worker.tasks).to.exist
expect(worker.tasks[0].title).to.equal('homework')
done()
})
})
})
describe('hasMany with alias', function() {
it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ self.Task ] })
}).to.throw(Error, 'Task is not associated to Worker!')
done()
})
describe('alias', function() {
beforeEach(function(done) {
var self = this
this.Worker.hasMany(this.Task, { as: 'ToDos' })
this.init(function() {
self.worker.setToDos([ self.task ]).success(function() {
done()
})
})
})
it('throws an error if alias is not associated', function(done) {
var self = this
expect(function() {
self.Worker.find({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done()
})
it('returns the associated task via worker.task', function(done) {
this.Worker.find({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDos' } ]
}).complete(function(err, worker) {
expect(err).to.be.null
expect(worker).to.exist
expect(worker.toDos).to.exist
expect(worker.toDos[0].title).to.equal('homework')
done()
})
})
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
this.Worker.find({
where: { name: 'worker' },
include: [ { model: this.Task, as: 'ToDos' } ]
}).complete(function(err, worker) {
expect(worker.toDos[0].title).to.equal('homework')
done()
})
})
})
})
})
describe('queryOptions', function() {
beforeEach(function(done) {
var self = this
this.User.create({username: 'barfooz'}).success(function(user) {
self.user = user
done()
})
})
it("should return a DAO when queryOptions are not set", function(done) {
var self = this
this.User.find({ where: { username: 'barfooz'}}).done(function(err, user) {
expect(user).to.be.instanceOf(self.User.DAO)
done()
})
})
it("should return a DAO when raw is false", function(done) {
var self = this
this.User.find({ where: { username: 'barfooz'}}, { raw: false }).done(function(err, user) {
expect(user).to.be.instanceOf(self.User.DAO)
done()
})
})
it("should return raw data when raw is true", function(done) {
var self = this
this.User.find({ where: { username: 'barfooz'}}, { raw: true }).done(function(err, user) {
expect(user).to.not.be.instanceOf(self.User.DAO)
expect(user).to.be.instanceOf(Object)
done()
})
})
})
})
describe('findAll', function() {
describe('eager loading', function() {
describe('belongsTo', function() {
beforeEach(function(done) {
var self = this
self.Task = self.sequelize.define('TaskBelongsTo', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Task.belongsTo(self.Worker)
self.Worker.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
self.task.setWorker(self.worker).success(function() {
done()
})
})
})
})
})
})
it('throws an error about unexpected input if include contains a non-object', function(done) {
var self = this
expect(function() {
self.Worker.all({ include: [ 1 ] })
}).to.throw(Error, 'Include unexpected. Element has to be either an instance of DAOFactory or an object.')
done()
})
it('throws an error about missing attributes if include contains an object with daoFactory', function(done) {
var self = this
expect(function() {
self.Worker.all({ include: [ { daoFactory: self.Worker } ] })
}).to.throw(Error, 'Include malformed. Expected attributes: daoFactory, as!')
done()
})
it('throws an error if included DaoFactory is not associated', function(done) {
var self = this
expect(function() {
self.Worker.all({ include: [ self.Task ] })
}).to.throw(Error, 'TaskBelongsTo is not associated to Worker!')
done()
})
it('returns the associated worker via task.worker', function(done) {
this.Task.all({
where: { title: 'homework' },
include: [ this.Worker ]
}).complete(function(err, tasks) {
expect(err).to.be.null
expect(tasks).to.exist
expect(tasks[0].worker).to.exist
expect(tasks[0].worker.name).to.equal('worker')
done()
})
})
})
describe('hasOne', function() {
beforeEach(function(done) {
var self = this
self.Task = self.sequelize.define('TaskHasOne', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasOne(self.Task)
self.Worker.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
self.worker.setTaskHasOne(self.task).success(function() {
done()
})
})
})
})
})
})
it('throws an error if included DaoFactory is not associated', function(done) {
var self = this
expect(function() {
self.Task.all({ include: [ self.Worker ] })
}).to.throw(Error, 'Worker is not associated to TaskHasOne!')
done()
})
it('returns the associated task via worker.task', function(done) {
this.Worker.all({
where: { name: 'worker' },
include: [ this.Task ]
}).complete(function(err, workers) {
expect(err).to.be.null
expect(workers).to.exist
expect(workers[0].taskHasOne).to.exist
expect(workers[0].taskHasOne.title).to.equal('homework')
done()
})
})
})
describe('hasOne with alias', function() {
beforeEach(function(done) {
var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasOne(self.Task, { as: 'ToDo' })
self.Worker.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
self.worker.setToDo(self.task).success(function() {
done()
})
})
})
})
})
})
it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this
expect(function() {
self.Worker.all({ include: [ self.Task ] })
}).to.throw(Error, 'Task is not associated to Worker!')
done()
})
it('throws an error if alias is not associated', function(done) {
var self = this
expect(function() {
self.Worker.all({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done()
})
it('returns the associated task via worker.task', function(done) {
this.Worker.all({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDo' } ]
}).complete(function(err, workers) {
expect(err).to.be.null
expect(workers).to.exist
expect(workers[0].toDo).to.exist
expect(workers[0].toDo.title).to.equal('homework')
done()
})
})
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
this.Worker.all({
where: { name: 'worker' },
include: [ { model: this.Task, as: 'ToDo' } ]
}).complete(function(err, workers) {
expect(workers[0].toDo.title).to.equal('homework')
done()
})
})
})
describe('hasMany', function() {
beforeEach(function(done) {
var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasMany(self.Task)
self.Worker.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
self.worker.setTasks([ self.task ]).success(function() {
done()
})
})
})
})
})
})
it('throws an error if included DaoFactory is not associated', function(done) {
var self = this
expect(function() {
self.Task.findAll({ include: [ self.Worker ] })
}).to.throw(Error, 'Worker is not associated to Task!')
done()
})
it('returns the associated tasks via worker.tasks', function(done) {
this.Worker.findAll({
where: { name: 'worker' },
include: [ this.Task ]
}).complete(function(err, workers) {
expect(err).to.be.null
expect(workers).to.exist
expect(workers[0].tasks).to.exist
expect(workers[0].tasks[0].title).to.equal('homework')
done()
})
})
})
describe('hasMany with alias', function() {
beforeEach(function(done) {
var self = this
self.Task = self.sequelize.define('Task', { title: Sequelize.STRING })
self.Worker = self.sequelize.define('Worker', { name: Sequelize.STRING })
self.Worker.hasMany(self.Task, { as: 'ToDos' })
self.Worker.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.Worker.create({ name: 'worker' }).success(function(worker) {
self.Task.create({ title: 'homework' }).success(function(task) {
self.worker = worker
self.task = task
self.worker.setToDos([ self.task ]).success(function() {
done()
})
})
})
})
})
})
it('throws an error if included DaoFactory is not referenced by alias', function(done) {
var self = this
expect(function() {
self.Worker.findAll({ include: [ self.Task ] })
}).to.throw(Error, 'Task is not associated to Worker!')
done()
})
it('throws an error if alias is not associated', function(done) {
var self = this
expect(function() {
self.Worker.findAll({ include: [ { daoFactory: self.Task, as: 'Work' } ] })
}).to.throw(Error, 'Task (Work) is not associated to Worker!')
done()
})
it('returns the associated task via worker.task', function(done) {
this.Worker.findAll({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDos' } ]
}).complete(function(err, workers) {
expect(err).to.be.null
expect(workers).to.exist
expect(workers[0].toDos).to.exist
expect(workers[0].toDos[0].title).to.equal('homework')
done()
})
})
it('returns the associated task via worker.task when daoFactory is aliased with model', function(done) {
this.Worker.findAll({
where: { name: 'worker' },
include: [ { daoFactory: this.Task, as: 'ToDos' } ]
}).complete(function(err, workers) {
expect(workers[0].toDos[0].title).to.equal('homework')
done()
})
})
})
describe('queryOptions', function() {
beforeEach(function(done) {
var self = this
this.User.create({username: 'barfooz'}).success(function(user) {
self.user = user
done()
})
})
it("should return a DAO when queryOptions are not set", function(done) {
var self = this
this.User.findAll({ where: { username: 'barfooz'}}).done(function(err, users) {
users.forEach(function (user) {
expect(user).to.be.instanceOf(self.User.DAO)
})
done()
})
})
it("should return a DAO when raw is false", function(done) {
var self = this
this.User.findAll({ where: { username: 'barfooz'}}, { raw: false }).done(function(err, users) {
users.forEach(function (user) {
expect(user).to.be.instanceOf(self.User.DAO)
})
done()
})
})
it("should return raw data when raw is true", function(done) {
var self = this
this.User.findAll({ where: { username: 'barfooz'}}, { raw: true }).done(function(err, users) {
users.forEach(function(user) {
expect(user).to.not.be.instanceOf(self.User.DAO)
expect(users[0]).to.be.instanceOf(Object)
})
done()
})
})
})
})
describe('normal findAll', function() {
beforeEach(function(done) {
var self = this
this.User.create({username: 'user', data: 'foobar', theDate: moment().toDate()}).success(function(user) {
self.User.create({username: 'user2', data: 'bar', theDate: moment().toDate()}).success(function(user2){
self.users = [user].concat(user2)
done()
})
})
})
it("finds all entries", function(done) {
this.User.all().on('success', function(users) {
expect(users.length).to.equal(2)
done()
})
})
it("finds all users matching the passed conditions", function(done) {
this.User.findAll({where: "id != " + this.users[1].id}).success(function(users) {
expect(users.length).to.equal(1)
done()
})
})
it("can also handle array notation", function(done) {
var self = this
this.User.findAll({where: ['id = ?', this.users[1].id]}).success(function(users) {
expect(users.length).to.equal(1)
expect(users[0].id).to.equal(self.users[1].id)
done()
})
})
it("sorts the results via id in ascending order", function(done) {
this.User.findAll().success(function(users) {
expect(users.length).to.equal(2);
expect(users[0].id).to.be.below(users[1].id)
done()
})
})
it("sorts the results via id in descending order", function(done) {
this.User.findAll({ order: "id DESC" }).success(function(users) {
expect(users[0].id).to.be.above(users[1].id)
done()
})
})
it("sorts the results via a date column", function(done) {
var self = this
self.User.create({username: 'user3', data: 'bar', theDate: moment().add('hours', 2).toDate()}).success(function(){
self.User.findAll({ order: 'theDate DESC' }).success(function(users) {
expect(users[0].id).to.be.above(users[2].id)
done()
})
})
})
it("handles offset and limit", function(done) {
var self = this
this.User.bulkCreate([{username: 'bobby'}, {username: 'tables'}]).success(function() {
self.User.findAll({ limit: 2, offset: 2 }).success(function(users) {
expect(users.length).to.equal(2)
expect(users[0].id).to.equal(3)
done()
})
})
})
})
})
describe('findAndCountAll', function() {
beforeEach(function(done) {
var self = this
this.User.bulkCreate([
{username: 'user', data: 'foobar'},
{username: 'user2', data: 'bar'},
{username: 'bobby', data: 'foo'}
]).success(function() {
self.User.all().success(function(users){
self.users = users
done()
})
})
})
it("handles where clause [only]", function(done) {
this.User.findAndCountAll({where: "id != " + this.users[0].id}).success(function(info) {
expect(info.count).to.equal(2)
expect(Array.isArray(info.rows)).to.be.ok
expect(info.rows.length).to.equal(2)
done()
})
})
it("handles where clause with ordering [only]", function(done) {
this.User.findAndCountAll({where: "id != " + this.users[0].id, order: 'id ASC'}).success(function(info) {
expect(info.count).to.equal(2)
expect(Array.isArray(info.rows)).to.be.ok
expect(info.rows.length).to.equal(2)
done()
})
})
it("handles offset", function(done) {
this.User.findAndCountAll({offset: 1}).success(function(info) {
expect(info.count).to.equal(3)
expect(Array.isArray(info.rows)).to.be.ok
expect(info.rows.length).to.equal(2)
done()
})
})
it("handles limit", function(done) {
this.User.findAndCountAll({limit: 1}).success(function(info) {
expect(info.count).to.equal(3)
expect(Array.isArray(info.rows)).to.be.ok
expect(info.rows.length).to.equal(1)
done()
})
})
it("handles offset and limit", function(done) {
this.User.findAndCountAll({offset: 1, limit: 1}).success(function(info) {
expect(info.count).to.equal(3)
expect(Array.isArray(info.rows)).to.be.ok
expect(info.rows.length).to.equal(1)
done()
})
})
})
describe('all', function() {
beforeEach(function(done) {
this.User.bulkCreate([
{username: 'user', data: 'foobar'},
{username: 'user2', data: 'bar'}
]).complete(function() {
done()
})
})
it("should return all users", function(done) {
this.User.all().on('success', function(users) {
expect(users.length).to.equal(2)
done()
})
})
})
describe('equals', function() {
it("correctly determines equality of objects", function(done) {
this.User.create({username: 'hallo', data: 'welt'}).success(function(u) {
expect(u.equals(u)).to.be.ok
done()
})
})
// sqlite can't handle multiple primary keys
if(dialect !== "sqlite") {
it("correctly determines equality with multiple primary keys", function(done) {
var userKeys = this.sequelize.define('userkeys', {
foo: {type: Sequelize.STRING, primaryKey: true},
bar: {type: Sequelize.STRING, primaryKey: true},
name: Sequelize.STRING,
bio: Sequelize.TEXT
})
userKeys.sync({ force: true }).success(function() {
userKeys.create({foo: '1', bar: '2', name: 'hallo', bio: 'welt'}).success(function(u) {
expect(u.equals(u)).to.be.ok
done()
})
})
})
}
})
describe('equalsOneOf', function() {
// sqlite can't handle multiple primary keys
if (dialect !== "sqlite") {
beforeEach(function(done) {
this.userKey = this.sequelize.define('userKeys', {
foo: {type: Sequelize.STRING, primaryKey: true},
bar: {type: Sequelize.STRING, primaryKey: true},
name: Sequelize.STRING,
bio: Sequelize.TEXT
})
this.userKey.sync({ force: true }).success(function(){
done()
})
})
it('determines equality if one is matching', function(done) {
this.userKey.create({foo: '1', bar: '2', name: 'hallo', bio: 'welt'}).success(function(u) {
expect(u.equalsOneOf([u, {a: 1}])).to.be.ok
done()
})
})
it("doesn't determine equality if none is matching", function(done) {
this.userKey.create({foo: '1', bar: '2', name: 'hallo', bio: 'welt'}).success(function(u) {
expect(u.equalsOneOf([{b: 2}, {a: 1}])).to.not.be.ok
done()
})
})
}
})
describe('count', function() {
it('counts all created objects', function(done) {
var self = this
this.User.bulkCreate([{username: 'user1'}, {username: 'user2'}]).success(function() {
self.User.count().success(function(count) {
expect(count).to.equal(2)
done()
})
})
})
it('allows sql logging', function(done) {
this.User.count().on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("SELECT")).to.be.above(-1)
done()
})
})
it('filters object', function(done) {
var self = this
this.User.create({username: 'user1'}).success(function() {
self.User.create({username: 'foo'}).success(function() {
self.User.count({where: "username LIKE '%us%'"}).success(function(count) {
expect(count).to.equal(1)
done()
})
})
})
})
})
describe('min', function() {
beforeEach(function(done) {
var self = this
this.UserWithAge = this.sequelize.define('UserWithAge', {
age: Sequelize.INTEGER
})
this.UserWithDec = this.sequelize.define('UserWithDec', {
value: Sequelize.DECIMAL(10, 3)
})
this.UserWithAge.sync({ force: true }).success(function() {
self.UserWithDec.sync({ force: true }).success(function() {
done()
})
})
})
it("should return the min value", function(done) {
var self = this
this.UserWithAge.bulkCreate([{age: 3}, { age: 2 }]).success(function() {
self.UserWithAge.min('age').success(function(min) {
expect(min).to.equal(2)
done()
})
})
})
it('allows sql logging', function(done) {
this.UserWithAge.min('age').on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("SELECT")).to.be.above(-1)
done()
})
})
it("should allow decimals in min", function(done){
var self = this
this.UserWithDec.bulkCreate([{value: 5.5}, {value: 3.5}]).success(function(){
self.UserWithDec.min('value').success(function(min){
expect(min).to.equal(3.5)
done()
})
})
})
})
describe('max', function() {
beforeEach(function(done) {
var self = this
this.UserWithAge = this.sequelize.define('UserWithAge', {
age: Sequelize.INTEGER,
order: Sequelize.INTEGER
})
this.UserWithDec = this.sequelize.define('UserWithDec', {
value: Sequelize.DECIMAL(10, 3)
})
this.UserWithAge.sync({ force: true }).success(function() {
self.UserWithDec.sync({ force: true }).success(function() {
done()
})
})
})
it("should return the max value for a field named the same as an SQL reserved keyword", function(done) {
var self = this
this.UserWithAge.bulkCreate([{age: 2, order: 3}, {age: 3, order: 5}]).success(function(){
self.UserWithAge.max('order').success(function(max) {
expect(max).to.equal(5)
done()
})
})
})
it("should return the max value", function(done) {
var self = this
self.UserWithAge.bulkCreate([{age: 2}, {age: 3}]).success(function() {
self.UserWithAge.max('age').success(function(max) {
expect(max).to.equal(3)
done()
})
})
})
it("should allow decimals in max", function(done) {
var self = this
this.UserWithDec.bulkCreate([{value: 3.5}, {value: 5.5}]).success(function(){
self.UserWithDec.max('value').success(function(max){
expect(max).to.equal(5.5)
done()
})
})
})
it('allows sql logging', function(done) {
this.UserWithAge.max('age').on('sql', function(sql) {
expect(sql).to.exist
expect(sql.toUpperCase().indexOf("SELECT")).to.be.above(-1)
done()
})
})
})
describe('schematic support', function() {
beforeEach(function(done){
var self = this;
this.UserPublic = this.sequelize.define('UserPublic', {
age: Sequelize.INTEGER
})
this.UserSpecial = this.sequelize.define('UserSpecial', {
age: Sequelize.INTEGER
})
self.sequelize.dropAllSchemas().success(function(){
self.sequelize.createSchema('schema_test').success(function(){
self.sequelize.createSchema('special').success(function(){
self.UserSpecial.schema('special').sync({force: true}).success(function(UserSpecialSync) {
self.UserSpecialSync = UserSpecialSync
done()
})
})
})
})
})
it("should be able to list schemas", function(done){
this.sequelize.showAllSchemas().success(function(schemas) {
expect(schemas).to.exist
expect(schemas[0]).to.be.instanceof(Array)
// sqlite & MySQL doesn't actually create schemas unless Model.sync() is called
// Postgres supports schemas natively
expect(schemas[0]).to.have.length((dialect === "postgres" || dialect === "postgres-native" ? 2 : 1))
done()
})
})
if (dialect === "mysql") {
it("should take schemaDelimiter into account if applicable", function(done){
var UserSpecialUnderscore = this.sequelize.define('UserSpecialUnderscore', {age: Sequelize.INTEGER}, {schema: 'hello', schemaDelimiter: '_'})
var UserSpecialDblUnderscore = this.sequelize.define('UserSpecialDblUnderscore', {age: Sequelize.INTEGER})
UserSpecialUnderscore.sync({force: true}).success(function(User){
UserSpecialDblUnderscore.schema('hello', '__').sync({force: true}).success(function(DblUser){
DblUser.create({age: 3}).on('sql', function(dblSql){
User.create({age: 3}).on('sql', function(sql){
expect(dblSql).to.exist
expect(dblSql.indexOf('INSERT INTO `hello__UserSpecialDblUnderscores`')).to.be.above(-1)
expect(sql).to.exist
expect(sql.indexOf('INSERT INTO `hello_UserSpecialUnderscores`')).to.be.above(-1)
done()
})
})
})
})
})
}
it("should be able to create and update records under any valid schematic", function(done){
var self = this
self.UserPublic.sync({ force: true }).success(function(UserPublicSync){
UserPublicSync.create({age: 3}).on('sql', function(UserPublic){
self.UserSpecialSync.schema('special').create({age: 3})
.on('sql', function(UserSpecial){
expect(UserSpecial).to.exist
expect(UserPublic).to.exist
if (dialect === "postgres") {
expect(self.UserSpecialSync.getTableName()).to.equal('"special"."UserSpecials"');
expect(UserSpecial.indexOf('INSERT INTO "special"."UserSpecials"')).to.be.above(-1)
expect(UserPublic.indexOf('INSERT INTO "UserPublics"')).to.be.above(-1)
} else if (dialect === "sqlite") {
expect(self.UserSpecialSync.getTableName()).to.equal('`special`.`UserSpecials`');
expect(UserSpecial.indexOf('INSERT INTO `special.UserSpecials`')).to.be.above(-1)
expect(UserPublic.indexOf('INSERT INTO `UserPublics`')).to.be.above(-1)
} else {
expect(self.UserSpecialSync.getTableName()).to.equal('`special.UserSpecials`');
expect(UserSpecial.indexOf('INSERT INTO `special.UserSpecials`')).to.be.above(-1)
expect(UserPublic.indexOf('INSERT INTO `UserPublics`')).to.be.above(-1)
}
})
.success(function(UserSpecial){
UserSpecial.updateAttributes({age: 5})
.on('sql', function(user){
expect(user).to.exist
if (dialect === "postgres") {
expect(user.indexOf('UPDATE "special"."UserSpecials"')).to.be.above(-1)
} else {
expect(user.indexOf('UPDATE `special.UserSpecials`')).to.be.above(-1)
}
done()
})
})
})
})
})
})
describe('references', function() {
this.timeout(3000)
beforeEach(function(done) {
var self = this
self.Author = self.sequelize.define('author', { firstName: Sequelize.STRING })
self.Author.sync({ force: true }).success(function() {
done()
})
})
afterEach(function(done) {
var self = this
self.sequelize.getQueryInterface().dropTable('posts', { force: true }).success(function() {
self.sequelize.getQueryInterface().dropTable('authors', { force: true }).success(function() {
done()
})
})
})
it('uses an existing dao factory and references the author table', function(done) {
var self = this
, Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: this.Author,
referencesKey: "id"
}
})
this.Author.hasMany(Post)
Post.belongsTo(this.Author)
Post.sync().on('sql', function(sql) {
if (dialect === 'postgres') {
expect(sql).to.match(/"authorId" INTEGER REFERENCES "authors" \("id"\)/)
}
else if (dialect === 'mysql') {
expect(sql).to.match(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/)
}
else if (dialect === 'sqlite') {
expect(sql).to.match(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/)
} else {
throw new Error('Undefined dialect!')
}
done()
})
})
it('uses a table name as a string and references the author table', function(done) {
var self = this
, Post = self.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: 'authors',
referencesKey: "id"
}
})
this.Author.hasMany(Post)
Post.belongsTo(this.Author)
Post.sync().on('sql', function(sql) {
if (dialect === 'postgres') {
expect(sql).to.match(/"authorId" INTEGER REFERENCES "authors" \("id"\)/)
}
else if (dialect === 'mysql') {
expect(sql).to.match(/FOREIGN KEY \(`authorId`\) REFERENCES `authors` \(`id`\)/)
}
else if (dialect === 'sqlite') {
expect(sql).to.match(/`authorId` INTEGER REFERENCES `authors` \(`id`\)/)
} else {
throw new Error('Undefined dialect!')
}
done()
})
})
it("emits an error event as the referenced table name is invalid", function(done) {
var self = this
, Post = this.sequelize.define('post', {
title: Sequelize.STRING,
authorId: {
type: Sequelize.INTEGER,
references: '4uth0r5',
referencesKey: "id"
}
})
this.Author.hasMany(Post)
Post.belongsTo(this.Author)
Post.sync().success(function() {
if (dialect === 'sqlite') {
// sorry ... but sqlite is too stupid to understand whats going on ...
expect(1).to.equal(1)
done()
} else {
// the parser should not end up here ...
expect(2).to.equal(1)
done()
}
}).error(function(err) {
if (dialect === 'mysql') {
expect(err.message).to.match(/ER_CANNOT_ADD_FOREIGN|ER_CANT_CREATE_TABLE/)
}
else if (dialect === 'sqlite') {
// the parser should not end up here ... see above
expect(1).to.equal(2)
}
else if (dialect === 'postgres') {
expect(err.message).to.match(/relation "4uth0r5" does not exist/)
} else {
throw new Error('Undefined dialect!')
}
done()
})
})
})
})
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, config = require(__dirname + "/config/config")
, sinon = require('sinon')
, datetime = require('chai-datetime')
, _ = require('lodash')
chai.use(datetime)
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("DAO"), function () {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: { type: DataTypes.STRING },
touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
aNumber: { type: DataTypes.INTEGER },
bNumber: { type: DataTypes.INTEGER },
validateTest: {
type: DataTypes.INTEGER,
allowNull: true,
validate: {isInt: true}
},
validateCustom: {
type: DataTypes.STRING,
allowNull: true,
validate: {len: {msg: 'Length failed.', args: [1,20]}}
},
dateAllowNullTrue: {
type: DataTypes.DATE,
allowNull: true
}
})
this.User.sync({ force: true }).success(function() {
done()
})
})
describe('Escaping', function() {
it('is done properly for special characters', function(done) {
// Ideally we should test more: "\0\n\r\b\t\\\'\"\x1a"
// But this causes sqlite to fail and exits the entire test suite immediately
var bio = dialect + "'\"\n" // Need to add the dialect here so in case of failure I know what DB it failed for
, self = this
this.User.create({ username: bio }).success(function(u1) {
self.User.find(u1.id).success(function(u2) {
expect(u2.username).to.equal(bio)
done()
})
})
})
})
describe('isNewRecord', function() {
it('returns true for non-saved objects', function(done) {
var user = this.User.build({ username: 'user' })
expect(user.id).to.be.null
expect(user.isNewRecord).to.be.ok
done()
})
it("returns false for saved objects", function(done) {
this.User.build({ username: 'user' }).save().success(function(user) {
expect(user.isNewRecord).to.not.be.ok
done()
})
})
it("returns false for created objects", function(done) {
this.User.create({ username: 'user' }).success(function(user) {
expect(user.isNewRecord).to.not.be.ok
done()
})
})
it("returns false for objects found by find method", function(done) {
var self = this
this.User.create({ username: 'user' }).success(function() {
self.User.create({ username: 'user' }).success(function(user) {
self.User.find(user.id).success(function(user) {
expect(user.isNewRecord).to.not.be.ok
done()
})
})
})
})
it("returns false for objects found by findAll method", function(done) {
var self = this
, users = []
for (var i = 0; i < 10; i++) {
users[users.length] = {username: 'user'}
}
this.User.bulkCreate(users).success(function() {
self.User.findAll().success(function(users) {
users.forEach(function(u) {
expect(u.isNewRecord).to.not.be.ok
})
done()
})
})
})
})
describe('increment', function () {
beforeEach(function(done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).complete(function(){
done()
})
})
it('with array', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
user1.increment(['aNumber'], 2).complete(function() {
self.User.find(1).complete(function(err, user3) {
expect(user3.aNumber).to.be.equal(2)
done()
})
})
})
})
it('with single field', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
user1.increment('aNumber', 2).complete(function() {
self.User.find(1).complete(function(err, user3) {
expect(user3.aNumber).to.be.equal(2)
done()
})
})
})
})
it('should still work right with other concurrent updates', function(done) {
var self = this
this.User.find(1).complete(function (err, user1) {
// Select the user again (simulating a concurrent query)
self.User.find(1).complete(function (err, user2) {
user2.updateAttributes({
aNumber: user2.aNumber + 1
}).complete(function () {
user1.increment(['aNumber'], 2).complete(function() {
self.User.find(1).complete(function(err, user5) {
expect(user5.aNumber).to.be.equal(3)
done()
})
})
})
})
})
})
it('should still work right with other concurrent increments', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
var _done = _.after(3, function() {
self.User.find(1).complete(function(err, user2) {
expect(user2.aNumber).to.equal(6)
done()
})
})
user1.increment(['aNumber'], 2).complete(_done)
user1.increment(['aNumber'], 2).complete(_done)
user1.increment(['aNumber'], 2).complete(_done)
})
})
it('with key value pair', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
user1.increment({ 'aNumber': 1, 'bNumber': 2}).success(function() {
self.User.find(1).complete(function (err, user3) {
expect(user3.aNumber).to.be.equal(1)
expect(user3.bNumber).to.be.equal(2)
done()
})
})
})
})
})
describe('decrement', function () {
beforeEach(function(done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).complete(done)
})
it('with array', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
user1.decrement(['aNumber'], 2).complete(function() {
self.User.find(1).complete(function(err, user3) {
expect(user3.aNumber).to.be.equal(-2)
done()
})
})
})
})
it('with single field', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
user1.decrement('aNumber', 2).complete(function() {
self.User.find(1).complete(function(err, user3) {
expect(user3.aNumber).to.be.equal(-2)
done()
})
})
})
})
it('should still work right with other concurrent updates', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
// Select the user again (simulating a concurrent query)
self.User.find(1).complete(function(err, user2) {
user2.updateAttributes({
aNumber: user2.aNumber + 1
}).complete(function () {
user1.decrement(['aNumber'], 2).complete(function() {
self.User.find(1).complete(function(err, user5) {
expect(user5.aNumber).to.be.equal(-1)
done()
})
})
})
})
})
})
it('should still work right with other concurrent increments', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
var _done = _.after(3, function() {
self.User.find(1).complete(function (err, user2) {
expect(user2.aNumber).to.equal(-6)
done()
})
})
user1.decrement(['aNumber'], 2).complete(_done)
user1.decrement(['aNumber'], 2).complete(_done)
user1.decrement(['aNumber'], 2).complete(_done)
})
})
it('with key value pair', function(done) {
var self = this
this.User.find(1).complete(function(err, user1) {
user1.decrement({ 'aNumber': 1, 'bNumber': 2}).complete(function() {
self.User.find(1).complete(function(err, user3) {
expect(user3.aNumber).to.be.equal(-1)
expect(user3.bNumber).to.be.equal(-2)
done()
})
})
})
})
})
describe('reload', function () {
it("should return a reference to the same DAO instead of creating a new one", function(done) {
this.User.create({ username: 'John Doe' }).complete(function(err, originalUser) {
originalUser.updateAttributes({ username: 'Doe John' }).complete(function() {
originalUser.reload().complete(function (err, updatedUser) {
expect(originalUser === updatedUser).to.be.true
done()
})
})
})
})
it("should update the values on all references to the DAO", function(done) {
var self = this
this.User.create({ username: 'John Doe' }).complete(function(err, originalUser) {
self.User.find(originalUser.id).complete(function(err, updater) {
updater.updateAttributes({ username: 'Doe John' }).complete(function() {
// We used a different reference when calling updateAttributes, so originalUser is now out of sync
expect(originalUser.username).to.equal('John Doe')
originalUser.reload().complete(function(err, updatedUser) {
expect(originalUser.username).to.equal('Doe John')
expect(updatedUser.username).to.equal('Doe John')
done()
})
})
})
})
})
it("should update read only attributes as well (updatedAt)", function(done) {
var self = this
this.timeout = 2000
this.User.create({ username: 'John Doe' }).complete(function(err, originalUser) {
var originallyUpdatedAt = originalUser.updatedAt
// Wait for a second, so updatedAt will actually be different
setTimeout(function () {
self.User.find(originalUser.id).complete(function(err, updater) {
updater.updateAttributes({ username: 'Doe John' }).complete(function () {
originalUser.reload().complete(function(err, updatedUser) {
expect(originalUser.updatedAt).to.be.above(originallyUpdatedAt)
expect(updatedUser.updatedAt).to.be.above(originallyUpdatedAt)
done()
})
})
})
}, 1000)
})
})
it("should update the associations as well", function(done) {
var Book = this.sequelize.define('Book', { title: DataTypes.STRING })
, Page = this.sequelize.define('Page', { content: DataTypes.TEXT })
Book.hasMany(Page)
Page.belongsTo(Book)
Book.sync().success(function() {
Page.sync().success(function() {
Book.create({ title: 'A very old book' }).success(function(book) {
Page.create({ content: 'om nom nom' }).success(function(page) {
book.setPages([ page ]).success(function() {
Book.find({
where: (dialect === 'postgres' ? '"Books"."id"=' : '`Books`.`id`=') + book.id,
include: [Page]
}).success(function(leBook) {
page.updateAttributes({ content: 'something totally different' }).success(function(page) {
expect(leBook.pages[0].content).to.equal('om nom nom')
expect(page.content).to.equal('something totally different')
leBook.reload().success(function(leBook) {
expect(leBook.pages[0].content).to.equal('something totally different')
expect(page.content).to.equal('something totally different')
done()
})
})
})
})
})
})
})
})
})
})
describe('default values', function() {
describe('current date', function() {
it('should store a date in touchedAt', function(done) {
var user = this.User.build({ username: 'a user'})
expect(user.touchedAt).to.be.instanceof(Date)
done()
})
it("should store the current date in touchedAt", function(done) {
var clock = sinon.useFakeTimers()
clock.tick(5000)
var user = this.User.build({ username: 'a user'})
clock.restore()
expect(+user.touchedAt).to.be.equal(5000)
done()
})
})
describe('allowNull date', function() {
it('should be just "null" and not Date with Invalid Date', function(done) {
var self = this
this.User.build({ username: 'a user'}).save().success(function() {
self.User.find({where: {username: 'a user'}}).success(function(user) {
expect(user.dateAllowNullTrue).to.be.null
done()
})
})
})
it('should be the same valid date when saving the date', function(done) {
var self = this
var date = new Date()
this.User.build({ username: 'a user', dateAllowNullTrue: date}).save().success(function() {
self.User.find({where: {username: 'a user'}}).success(function(user) {
expect(user.dateAllowNullTrue.toString()).to.equal(date.toString())
done()
})
})
})
})
})
describe('complete', function() {
it("gets triggered if an error occurs", function(done) {
this.User.find({ where: "asdasdasd" }).complete(function(err) {
expect(err).to.exist
expect(err.message).to.exist
done()
})
})
it("gets triggered if everything was ok", function(done) {
this.User.count().complete(function(err, result) {
expect(err).to.be.null
expect(result).to.exist
done()
})
})
})
describe('save', function() {
this.timeout(3000) // for update timestamp
it('only updates fields in passed array', function(done) {
var self = this
, userId = null
, date = new Date(1990, 01, 01)
this.User.create({
username: 'foo',
touchedAt: new Date()
}).success(function(user) {
user.username = 'fizz'
user.touchedAt = date
user.save(['username']).success(function(){
// re-select user
self.User.find(user.id).success(function(user2) {
// name should have changed
expect(user2.username).to.equal('fizz')
// bio should be unchanged
expect(user2.birthDate).not.to.equal(date)
done()
})
})
})
})
it("stores an entry in the database", function(done) {
var username = 'user'
, User = this.User
, user = this.User.build({
username: username,
touchedAt: new Date(1984, 8, 23)
})
User.all().success(function(users) {
expect(users).to.have.length(0)
user.save().success(function(){
User.all().success(function(users) {
expect(users).to.have.length(1)
expect(users[0].username).to.equal(username)
expect(users[0].touchedAt).to.be.instanceof(Date)
expect(users[0].touchedAt).to.equalDate(new Date(1984, 8, 23))
done()
})
})
})
})
it("updates the timestamps", function(done) {
var now = Date.now()
, user = null
, updatedAt = null
, User = this.User
// timeout is needed, in order to check the update of the timestamp
var build = function(callback) {
user = User.build({ username: 'user' })
updatedAt = user.updatedAt
expect(updatedAt.getTime()).to.be.above(now)
setTimeout(function() {
user.save().success(function() {
expect(updatedAt.getTime()).to.be.below(user.updatedAt.getTime())
callback()
})
}, 1000)
}
// closures are fun :)
setTimeout(function() {
build(function() {
done()
})
}, 1000)
})
describe('without timestamps option', function() {
it("doesn't update the updatedAt column", function(done) {
var User2 = this.sequelize.define('User2', {
username: DataTypes.STRING,
updatedAt: DataTypes.DATE
}, { timestamps: false })
User2.sync().success(function() {
User2.create({ username: 'john doe' }).success(function(johnDoe) {
// sqlite and mysql return undefined, whereas postgres returns null
expect([undefined, null].indexOf(johnDoe.updatedAt)).not.to.be.equal(-1)
done()
})
})
})
})
it('should fail a validation upon creating', function(done){
this.User.create({aNumber: 0, validateTest: 'hello'}).error(function(err){
expect(err).to.exist
expect(err).to.be.instanceof(Object)
expect(err.validateTest).to.be.instanceof(Array)
expect(err.validateTest[0]).to.exist
expect(err.validateTest[0].indexOf('Invalid integer')).to.be.above(-1)
done()
})
})
it('should fail a validation upon building', function(done){
this.User.build({aNumber: 0, validateCustom: 'aaaaaaaaaaaaaaaaaaaaaaaaaa'}).save()
.error(function(err){
expect(err).to.exist
expect(err).to.be.instanceof(Object)
expect(err.validateCustom).to.exist
expect(err.validateCustom).to.be.instanceof(Array)
expect(err.validateCustom[0]).to.exist
expect(err.validateCustom[0]).to.equal('Length failed.')
done()
})
})
it('should fail a validation when updating', function(done){
this.User.create({aNumber: 0}).success(function(user){
user.updateAttributes({validateTest: 'hello'}).error(function(err){
expect(err).to.exist
expect(err).to.be.instanceof(Object)
expect(err.validateTest).to.exist
expect(err.validateTest).to.be.instanceof(Array)
expect(err.validateTest[0]).to.exist
expect(err.validateTest[0].indexOf('Invalid integer:')).to.be.above(-1)
done()
})
})
})
it('takes zero into account', function(done) {
this.User.build({ aNumber: 0 }).save([ 'aNumber' ]).success(function(user) {
expect(user.aNumber).to.equal(0)
done()
})
})
it('saves a record with no primary key', function(done){
var HistoryLog = this.sequelize.define('HistoryLog', {
someText: { type: DataTypes.STRING },
aNumber: { type: DataTypes.INTEGER },
aRandomId: { type: DataTypes.INTEGER }
})
HistoryLog.sync().success(function() {
HistoryLog.create({ someText: 'Some random text', aNumber: 3, aRandomId: 5 }).success(function(log) {
log.updateAttributes({ aNumber: 5 }).success(function(newLog){
expect(newLog.aNumber).to.equal(5)
done()
})
})
})
})
describe('eagerly loaded objects', function() {
beforeEach(function(done) {
var self = this
this.UserEager = this.sequelize.define('UserEagerLoadingSaves', {
username: DataTypes.STRING,
age: DataTypes.INTEGER
}, { timestamps: false })
this.ProjectEager = this.sequelize.define('ProjectEagerLoadingSaves', {
title: DataTypes.STRING,
overdue_days: DataTypes.INTEGER
}, { timestamps: false })
this.UserEager.hasMany(this.ProjectEager, { as: 'Projects' })
this.ProjectEager.belongsTo(this.UserEager, { as: 'Poobah' })
self.UserEager.sync({force: true}).success(function() {
self.ProjectEager.sync({force: true}).success(function() {
done()
})
})
})
it('saves one object that has a collection of eagerly loaded objects', function(done) {
var self = this
this.UserEager.create({ username: 'joe', age: 1 }).success(function(user) {
self.ProjectEager.create({ title: 'project-joe1', overdue_days: 0 }).success(function(project1) {
self.ProjectEager.create({ title: 'project-joe2', overdue_days: 0 }).success(function(project2) {
user.setProjects([project1, project2]).success(function() {
self.UserEager.find({where: {age: 1}, include: [{model: self.ProjectEager, as: 'Projects'}]}).success(function(user) {
expect(user.username).to.equal('joe')
expect(user.age).to.equal(1)
expect(user.projects).to.exist
expect(user.projects.length).to.equal(2)
user.age = user.age + 1 // happy birthday joe
user.save().success(function() {
expect(user.username).to.equal('joe')
expect(user.age).to.equal(2)
expect(user.projects).to.exist
expect(user.projects.length).to.equal(2)
done()
})
})
})
})
})
})
})
it('saves many objects that each a have collection of eagerly loaded objects', function(done) {
var self = this
this.UserEager.create({ username: 'bart', age: 20 }).success(function(bart) {
self.UserEager.create({ username: 'lisa', age: 20 }).success(function(lisa) {
self.ProjectEager.create({ title: 'detention1', overdue_days: 0 }).success(function(detention1) {
self.ProjectEager.create({ title: 'detention2', overdue_days: 0 }).success(function(detention2) {
self.ProjectEager.create({ title: 'exam1', overdue_days: 0 }).success(function(exam1) {
self.ProjectEager.create({ title: 'exam2', overdue_days: 0 }).success(function(exam2) {
bart.setProjects([detention1, detention2]).success(function() {
lisa.setProjects([exam1, exam2]).success(function() {
self.UserEager.findAll({where: {age: 20}, order: 'username ASC', include: [{model: self.ProjectEager, as: 'Projects'}]}).success(function(simpsons) {
var _bart, _lisa
expect(simpsons.length).to.equal(2)
_bart = simpsons[0]
_lisa = simpsons[1]
expect(_bart.projects).to.exist
expect(_lisa.projects).to.exist
expect(_bart.projects.length).to.equal(2)
expect(_lisa.projects.length).to.equal(2)
_bart.age = _bart.age + 1 // happy birthday bart - off to Moe's
_bart.save().success(function(savedbart) {
expect(savedbart.username).to.equal('bart')
expect(savedbart.age).to.equal(21)
_lisa.username = 'lsimpson'
_lisa.save().success(function(savedlisa) {
expect(savedlisa.username).to.equal('lsimpson')
expect(savedlisa.age).to.equal(20)
done()
})
})
})
})
})
})
})
})
})
})
})
})
it('saves many objects that each has one eagerly loaded object (to which they belong)', function(done) {
var self = this
this.UserEager.create({ username: 'poobah', age: 18 }).success(function(user) {
self.ProjectEager.create({ title: 'homework', overdue_days: 10 }).success(function(homework) {
self.ProjectEager.create({ title: 'party', overdue_days: 2 }).success(function(party) {
user.setProjects([homework, party]).success(function() {
self.ProjectEager.findAll({include: [{model: self.UserEager, as: 'Poobah'}]}).success(function(projects) {
expect(projects.length).to.equal(2)
expect(projects[0].poobah).to.exist
expect(projects[1].poobah).to.exist
expect(projects[0].poobah.username).to.equal('poobah')
expect(projects[1].poobah.username).to.equal('poobah')
projects[0].title = 'partymore'
projects[1].title = 'partymore'
projects[0].overdue_days = 0
projects[1].overdue_days = 0
projects[0].save().success(function() {
projects[1].save().success(function() {
self.ProjectEager.findAll({where: {title: 'partymore', overdue_days: 0}, include: [{model: self.UserEager, as: 'Poobah'}]}).success(function(savedprojects) {
expect(savedprojects.length).to.equal(2)
expect(savedprojects[0].poobah).to.exist
expect(savedprojects[1].poobah).to.exist
expect(savedprojects[0].poobah.username).to.equal('poobah')
expect(savedprojects[1].poobah.username).to.equal('poobah')
done()
})
})
})
})
})
})
})
})
})
})
})
describe('toJSON', function() {
beforeEach(function(done) {
var self = this
this.User = this.sequelize.define('UserWithUsernameAndAgeAndIsAdmin', {
username: DataTypes.STRING,
age: DataTypes.INTEGER,
isAdmin: DataTypes.BOOLEAN
}, { timestamps: false })
this.Project = this.sequelize.define('NiceProject', { title: DataTypes.STRING }, { timestamps: false })
this.User.hasMany(this.Project, { as: 'Projects' })
this.Project.belongsTo(this.User, { as: 'LovelyUser' })
this.User.sync({ force: true }).success(function() {
self.Project.sync({ force: true }).success(function() {
done()
})
})
})
it('returns an object containing all values', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(user.toJSON()).to.deep.equal({ username: 'test.user', age: 99, isAdmin: true, id: null })
done()
})
it('returns a response that can be stringified', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(JSON.stringify(user)).to.deep.equal('{"username":"test.user","age":99,"isAdmin":true,"id":null}')
done()
})
it('returns a response that can be stringified and then parsed', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(JSON.parse(JSON.stringify(user))).to.deep.equal({ username: 'test.user', age: 99, isAdmin: true, id: null })
done()
})
it('includes the eagerly loaded associations', function(done) {
var self = this
this.User.create({ username: 'fnord', age: 1, isAdmin: true }).success(function(user) {
self.Project.create({ title: 'fnord' }).success(function(project) {
user.setProjects([ project ]).success(function() {
self.User.findAll({include: [ { model: self.Project, as: 'Projects' } ]}).success(function(users) {
var _user = users[0]
expect(_user.projects).to.exist
expect(JSON.parse(JSON.stringify(_user)).projects).to.exist
self.Project.findAll({include: [ { model: self.User, as: 'LovelyUser' } ]}).success(function(projects) {
var _project = projects[0]
expect(_project.lovelyUser).to.exist
expect(JSON.parse(JSON.stringify(_project)).lovelyUser).to.exist
done()
})
})
})
})
})
})
})
describe('findAll', function() {
beforeEach(function(done) {
this.ParanoidUser = this.sequelize.define('ParanoidUser', {
username: { type: DataTypes.STRING }
}, { paranoid: true })
this.ParanoidUser.hasOne(this.ParanoidUser)
this.ParanoidUser.sync({ force: true }).success(function() {
done()
})
})
it("escapes a single single quotes properly in where clauses", function(done) {
var self = this
this.User
.create({ username: "user'name" })
.success(function() {
self.User.findAll({
where: { username: "user'name" }
}).success(function(users) {
expect(users.length).to.equal(1)
expect(users[0].username).to.equal("user'name")
done()
})
})
})
it("escapes two single quotes properly in where clauses", function(done) {
var self = this
this.User
.create({ username: "user''name" })
.success(function() {
self.User.findAll({
where: { username: "user''name" }
}).success(function(users) {
expect(users.length).to.equal(1)
expect(users[0].username).to.equal("user''name")
done()
})
})
})
it("returns the timestamps if no attributes have been specified", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() {
self.User.findAll().success(function(users) {
expect(users[0].createdAt).to.exist
done()
})
})
})
it("does not return the timestamps if the username attribute has been specified", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() {
self.User.findAll({ attributes: ['username'] }).success(function(users) {
expect(users[0].createdAt).not.to.exist
expect(users[0].username).to.exist
done()
})
})
})
it("creates the deletedAt property, when defining paranoid as true", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() {
self.ParanoidUser.findAll().success(function(users) {
expect(users[0].deletedAt).to.be.null
done()
})
})
})
it("sets deletedAt property to a specific date when deleting an instance", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() {
self.ParanoidUser.findAll().success(function(users) {
users[0].destroy().success(function(user) {
expect(user.deletedAt.getMonth).to.exist
done()
})
})
})
})
it("keeps the deletedAt-attribute with value null, when running updateAttributes", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() {
self.ParanoidUser.findAll().success(function(users) {
users[0].updateAttributes({username: 'newFnord'}).success(function(user) {
expect(user.deletedAt).to.be.null
done()
})
})
})
})
it("keeps the deletedAt-attribute with value null, when updating associations", function(done) {
var self = this
this.ParanoidUser.create({ username: 'fnord' }).success(function() {
self.ParanoidUser.findAll().success(function(users) {
self.ParanoidUser.create({ username: 'linkedFnord' }).success(function(linkedUser) {
users[0].setParanoidUser( linkedUser ).success(function(user) {
expect(user.deletedAt).to.be.null
done()
})
})
})
})
})
it("can reuse query option objects", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() {
var query = { where: { username: 'fnord' }}
self.User.findAll(query).success(function(users) {
expect(users[0].username).to.equal('fnord')
self.User.findAll(query).success(function(users) {
expect(users[0].username).to.equal('fnord')
done()
})
})
})
})
})
describe('find', function() {
it("can reuse query option objects", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function() {
var query = { where: { username: 'fnord' }}
self.User.find(query).success(function(user) {
expect(user.username).to.equal('fnord')
self.User.find(query).success(function(user) {
expect(user.username).to.equal('fnord')
done()
})
})
})
})
})
describe('equals', function() {
it("can compare records with Date field", function(done) {
var self = this
this.User.create({ username: 'fnord' }).success(function(user1) {
var query = { where: { username: 'fnord' }}
self.User.find(query).success(function(user2) {
expect(user1.equals(user2)).to.be.true
done()
})
})
})
})
describe('values', function() {
it('returns all values', function(done) {
var User = this.sequelize.define('UserHelper', {
username: DataTypes.STRING
}, { timestamps: false, logging: false })
User.sync().success(function() {
var user = User.build({ username: 'foo' })
expect(user.values).to.deep.equal({ username: "foo", id: null })
done()
})
})
})
describe('updateAttributes', function() {
it("updates attributes in the database", function(done) {
this.User.create({ username: 'user' }).success(function(user) {
expect(user.username).to.equal('user')
user.updateAttributes({ username: 'person' }).success(function(user) {
expect(user.username).to.equal('person')
done()
})
})
})
it("ignores unknown attributes", function(done) {
this.User.create({ username: 'user' }).success(function(user) {
user.updateAttributes({ username: 'person', foo: 'bar'}).success(function(user) {
expect(user.username).to.equal('person')
expect(user.foo).not.to.exist
done()
})
})
})
it("doesn't update primary keys or timestamps", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
name: DataTypes.STRING,
bio: DataTypes.TEXT,
identifier: {type: DataTypes.STRING, primaryKey: true}
})
User.sync({ force: true }).success(function(){
User.create({
name: 'snafu',
identifier: 'identifier'
}).success(function(user) {
var oldCreatedAt = user.createdAt
, oldIdentifier = user.identifier
user.updateAttributes({
name: 'foobar',
createdAt: new Date(2000, 1, 1),
identifier: 'another identifier'
}).success(function(user) {
expect((new Date(user.createdAt)).getTime()).to.equal((new Date(oldCreatedAt)).getTime())
expect(user.identifier).to.equal(oldIdentifier)
done()
})
})
})
})
it("uses primary keys in where clause", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
name: DataTypes.STRING,
bio: DataTypes.TEXT,
identifier: {type: DataTypes.STRING, primaryKey: true}
})
User.sync({ force: true }).success(function(){
User.create({
name: 'snafu',
identifier: 'identifier'
}).success(function(user) {
var emitter = user.updateAttributes({name: 'foobar'})
emitter.on('sql', function(sql) {
expect(sql).to.match(/WHERE [`"]identifier[`"]..identifier./)
done()
})
})
})
})
it('stores and restores null values', function(done) {
var Download = this.sequelize.define('download', {
startedAt: DataTypes.DATE,
canceledAt: DataTypes.DATE,
finishedAt: DataTypes.DATE
})
Download.sync().success(function() {
Download.create({
startedAt: new Date()
}).success(function(download) {
expect(download.startedAt instanceof Date).to.be.true
expect(download.canceledAt).to.not.be.ok
expect(download.finishedAt).to.not.be.ok
download.updateAttributes({
canceledAt: new Date()
}).success(function(download) {
expect(download.startedAt instanceof Date).to.be.true
expect(download.canceledAt instanceof Date).to.be.true
expect(download.finishedAt).to.not.be.ok
Download.all({
where: (dialect === 'postgres' ? '"finishedAt" IS NULL' : "`finishedAt` IS NULL")
}).success(function(downloads) {
downloads.forEach(function(download) {
expect(download.startedAt instanceof Date).to.be.true
expect(download.canceledAt instanceof Date).to.be.true
expect(download.finishedAt).to.not.be.ok
done()
})
})
})
})
})
})
})
})
if(typeof require === 'function') { var chai = require('chai')
const buster = require("buster") , expect = chai.expect
, Sequelize = require("../index") , Sequelize = require(__dirname + '/../index')
, Helpers = require('./buster-helpers') , Support = require(__dirname + '/support')
, dialect = Helpers.getTestDialect() , config = require(__dirname + '/config/config')
}
buster.spec.expose() chai.Assertion.includeStack = true
buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { describe(Support.getTestDialectTeaser("DaoValidator"), function() {
describe('validations', function() { describe('validations', function() {
before(function(done) {
Helpers.initTests({
dialect: dialect,
onComplete: function(sequelize) {
this.sequelize = sequelize
done()
}.bind(this)
})
}) //- before
var checks = { var checks = {
is: { is: {
spec: { args: ["[a-z]",'i'] }, spec: { args: ["[a-z]",'i'] },
...@@ -116,72 +104,72 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -116,72 +104,72 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
fail: "a", fail: "a",
pass: "0" pass: "0"
} }
, len : { , len: {
spec: { args: [2,4] }, spec: { args: [2,4] },
fail: ["1", "12345"], fail: ["1", "12345"],
pass: ["12", "123", "1234"], pass: ["12", "123", "1234"],
raw: true raw: true
} }
, len: { , len$: {
spec: [2,4], spec: [2,4],
fail: ["1", "12345"], fail: ["1", "12345"],
pass: ["12", "123", "1234"], pass: ["12", "123", "1234"],
raw: true raw: true
} }
, isUUID : { , isUUID: {
spec: { args: 4 }, spec: { args: 4 },
fail: "f47ac10b-58cc-3372-a567-0e02b2c3d479", fail: "f47ac10b-58cc-3372-a567-0e02b2c3d479",
pass: "f47ac10b-58cc-4372-a567-0e02b2c3d479" pass: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
} }
, isDate : { , isDate: {
fail: "not a date", fail: "not a date",
pass: "2011-02-04" pass: "2011-02-04"
} }
, isAfter : { , isAfter: {
spec: { args: "2011-11-05" }, spec: { args: "2011-11-05" },
fail: "2011-11-04", fail: "2011-11-04",
pass: "2011-11-05" pass: "2011-11-05"
} }
, isBefore : { , isBefore: {
spec: { args: "2011-11-05" }, spec: { args: "2011-11-05" },
fail: "2011-11-06", fail: "2011-11-06",
pass: "2011-11-05" pass: "2011-11-05"
} }
, isIn : { , isIn: {
spec: { args: "abcdefghijk" }, spec: { args: "abcdefghijk" },
fail: "ghik", fail: "ghik",
pass: "ghij" pass: "ghij"
} }
, notIn : { , notIn: {
spec: { args: "abcdefghijk" }, spec: { args: "abcdefghijk" },
fail: "ghij", fail: "ghij",
pass: "ghik" pass: "ghik"
} }
, max : { , max: {
spec: { args: 23 }, spec: { args: 23 },
fail: "24", fail: "24",
pass: "23" pass: "23"
} }
, max : { , max$: {
spec: 23, spec: 23,
fail: "24", fail: "24",
pass: "23" pass: "23"
} }
, min : { , min: {
spec: { args: 23 }, spec: { args: 23 },
fail: "22", fail: "22",
pass: "23" pass: "23"
} }
, min : { , min$: {
spec: 23, spec: 23,
fail: "22", fail: "22",
pass: "23" pass: "23"
} }
, isArray : { , isArray: {
fail: 22, fail: 22,
pass: [22] pass: [22]
} }
, isCreditCard : { , isCreditCard: {
fail: "401288888888188f", fail: "401288888888188f",
pass: "4012888888881881" pass: "4012888888881881"
} }
...@@ -189,6 +177,8 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -189,6 +177,8 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
for (var validator in checks) { for (var validator in checks) {
if (checks.hasOwnProperty(validator)) { if (checks.hasOwnProperty(validator)) {
validator = validator.replace(/\$$/, '')
var validatorDetails = checks[validator] var validatorDetails = checks[validator]
if (!validatorDetails.hasOwnProperty("raw")) { if (!validatorDetails.hasOwnProperty("raw")) {
...@@ -202,7 +192,7 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -202,7 +192,7 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
for (var i = 0; i < validatorDetails.fail.length; i++) { for (var i = 0; i < validatorDetails.fail.length; i++) {
var failingValue = validatorDetails.fail[i] var failingValue = validatorDetails.fail[i]
it('correctly specifies an instance as invalid using a value of "' + failingValue + '" for the validation "' + validator + '"', function() { it('correctly specifies an instance as invalid using a value of "' + failingValue + '" for the validation "' + validator + '"', function(done) {
var validations = {} var validations = {}
, message = validator + "(" + failingValue + ")" , message = validator + "(" + failingValue + ")"
...@@ -214,7 +204,7 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -214,7 +204,7 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
validations[validator].msg = message validations[validator].msg = message
var UserFail = this.sequelize.define('User' + Math.random(), { var UserFail = this.sequelize.define('User' + config.rand(), {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: validations validate: validations
...@@ -224,18 +214,20 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -224,18 +214,20 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
var failingUser = UserFail.build({ name : failingValue }) var failingUser = UserFail.build({ name : failingValue })
, errors = failingUser.validate() , errors = failingUser.validate()
expect(errors).not.toBeNull() expect(errors).not.to.be.null
expect(errors).toEqual({ name : [message] }) expect(errors).to.eql({ name : [message] })
done()
}) })
} }
//////////////////////////// ////////////////////////////
// test the success cases // // test the success cases //
//////////////////////////// ////////////////////////////
for (var j = 0; j < validatorDetails.pass.length; j++) { for (var j = 0; j < validatorDetails.pass.length; j++) {
var succeedingValue = validatorDetails.pass[j] var succeedingValue = validatorDetails.pass[j]
it('correctly specifies an instance as valid using a value of "' + succeedingValue + '" for the validation "' + validator + '"', function() { it('correctly specifies an instance as valid using a value of "' + succeedingValue + '" for the validation "' + validator + '"', function(done) {
var validations = {} var validations = {}
if (validatorDetails.hasOwnProperty('spec')) { if (validatorDetails.hasOwnProperty('spec')) {
...@@ -246,7 +238,7 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -246,7 +238,7 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
validations[validator].msg = validator + "(" + succeedingValue + ")" validations[validator].msg = validator + "(" + succeedingValue + ")"
var UserSuccess = this.sequelize.define('User' + Math.random(), { var UserSuccess = this.sequelize.define('User' + config.rand(), {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: validations validate: validations
...@@ -254,14 +246,15 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -254,14 +246,15 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
}) })
var successfulUser = UserSuccess.build({ name: succeedingValue }) var successfulUser = UserSuccess.build({ name: succeedingValue })
expect(successfulUser.validate()).toBeNull() expect(successfulUser.validate()).to.be.null
done()
}) })
} }
} }
} }
it('correctly validates using custom validation methods', function() { it('correctly validates using custom validation methods', function(done) {
var User = this.sequelize.define('User' + Math.random(), { var User = this.sequelize.define('User' + config.rand(), {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: { validate: {
...@@ -277,15 +270,17 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -277,15 +270,17 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
var failingUser = User.build({ name : "3" }) var failingUser = User.build({ name : "3" })
, errors = failingUser.validate() , errors = failingUser.validate()
expect(errors).not.toBeNull(null) expect(errors).not.to.be.null
expect(errors).toEqual({ name: ["name should equal '2'"] }) expect(errors).to.eql({ name: ["name should equal '2'"] })
var successfulUser = User.build({ name : "2" }) var successfulUser = User.build({ name : "2" })
expect(successfulUser.validate()).toBeNull() expect(successfulUser.validate()).to.be.null
done()
}) })
it('skips other validations if allowNull is true and the value is null', function() { it('skips other validations if allowNull is true and the value is null', function(done) {
var User = this.sequelize.define('User' + Math.random(), { var User = this.sequelize.define('User' + config.rand(), {
age: { age: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
allowNull: true, allowNull: true,
...@@ -298,18 +293,20 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -298,18 +293,20 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
var failingUser = User.build({ age: -1 }) var failingUser = User.build({ age: -1 })
, errors = failingUser.validate() , errors = failingUser.validate()
expect(errors).not.toBeNull(null) expect(errors).not.to.be.null
expect(errors).toEqual({ age: ['must be positive'] }) expect(errors).to.eql({ age: ['must be positive'] })
var successfulUser1 = User.build({ age: null }) var successfulUser1 = User.build({ age: null })
expect(successfulUser1.validate()).toBeNull() expect(successfulUser1.validate()).to.be.null
var successfulUser2 = User.build({ age: 1 }) var successfulUser2 = User.build({ age: 1 })
expect(successfulUser2.validate()).toBeNull() expect(successfulUser2.validate()).to.be.null
done()
}) })
it('validates a model with custom model-wide validation methods', function() { it('validates a model with custom model-wide validation methods', function(done) {
var Foo = this.sequelize.define('Foo' + Math.random(), { var Foo = this.sequelize.define('Foo' + config.rand(), {
field1: { field1: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
allowNull: true allowNull: true
...@@ -331,11 +328,12 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() { ...@@ -331,11 +328,12 @@ describe(Helpers.getTestDialectTeaser("DaoValidator"), function() {
var failingFoo = Foo.build({ field1: null, field2: null }) var failingFoo = Foo.build({ field1: null, field2: null })
, errors = failingFoo.validate() , errors = failingFoo.validate()
expect(errors).not.toBeNull() expect(errors).not.to.be.null
expect(errors).toEqual({ 'xnor': ['xnor failed'] }) expect(errors).to.eql({ 'xnor': ['xnor failed'] })
var successfulFoo = Foo.build({ field1: 33, field2: null }) var successfulFoo = Foo.build({ field1: 33, field2: null })
expect(successfulFoo.validate()).toBeNull() expect(successfulFoo.validate()).to.be.null
done()
}) })
}) })
}) })
var chai = require('chai')
, expect = chai.expect
, Sequelize = require(__dirname + '/../index')
, Support = require(__dirname + '/support')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser('DataTypes'), function() {
it('should return DECIMAL for the default decimal type', function(done) {
expect(Sequelize.DECIMAL.toString()).to.equal('DECIMAL')
done()
})
it('should return DECIMAL(10,2) for the default decimal type with arguments', function(done) {
expect(Sequelize.DECIMAL(10, 2)).to.equal('DECIMAL(10,2)')
done()
})
var tests = [
[Sequelize.STRING, 'STRING', 'VARCHAR(255)'],
[Sequelize.STRING(1234), 'STRING(1234)', 'VARCHAR(1234)'],
[Sequelize.STRING(1234).BINARY, 'STRING(1234).BINARY', 'VARCHAR(1234) BINARY'],
[Sequelize.STRING.BINARY, 'STRING.BINARY', 'VARCHAR(255) BINARY'],
[Sequelize.TEXT, 'TEXT', 'TEXT'],
[Sequelize.DATE, 'DATE', 'DATETIME'],
[Sequelize.NOW, 'NOW', 'NOW'],
[Sequelize.BOOLEAN, 'BOOLEAN', 'TINYINT(1)'],
[Sequelize.INTEGER, 'INTEGER', 'INTEGER'],
[Sequelize.INTEGER.UNSIGNED, 'INTEGER.UNSIGNED', 'INTEGER UNSIGNED'],
[Sequelize.INTEGER(11), 'INTEGER(11)','INTEGER(11)'],
[Sequelize.INTEGER(11).UNSIGNED, 'INTEGER(11).UNSIGNED', 'INTEGER(11) UNSIGNED'],
[Sequelize.INTEGER(11).UNSIGNED.ZEROFILL,'INTEGER(11).UNSIGNED.ZEROFILL','INTEGER(11) UNSIGNED ZEROFILL'],
[Sequelize.INTEGER(11).ZEROFILL,'INTEGER(11).ZEROFILL', 'INTEGER(11) ZEROFILL'],
[Sequelize.INTEGER(11).ZEROFILL.UNSIGNED,'INTEGER(11).ZEROFILL.UNSIGNED', 'INTEGER(11) UNSIGNED ZEROFILL'],
[Sequelize.BIGINT, 'BIGINT', 'BIGINT'],
[Sequelize.BIGINT.UNSIGNED, 'BIGINT.UNSIGNED', 'BIGINT UNSIGNED'],
[Sequelize.BIGINT(11), 'BIGINT(11)','BIGINT(11)'],
[Sequelize.BIGINT(11).UNSIGNED, 'BIGINT(11).UNSIGNED', 'BIGINT(11) UNSIGNED'],
[Sequelize.BIGINT(11).UNSIGNED.ZEROFILL, 'BIGINT(11).UNSIGNED.ZEROFILL','BIGINT(11) UNSIGNED ZEROFILL'],
[Sequelize.BIGINT(11).ZEROFILL, 'BIGINT(11).ZEROFILL', 'BIGINT(11) ZEROFILL'],
[Sequelize.BIGINT(11).ZEROFILL.UNSIGNED, 'BIGINT(11).ZEROFILL.UNSIGNED', 'BIGINT(11) UNSIGNED ZEROFILL'],
[Sequelize.FLOAT, 'FLOAT', 'FLOAT'],
[Sequelize.FLOAT.UNSIGNED, 'FLOAT.UNSIGNED', 'FLOAT UNSIGNED'],
[Sequelize.FLOAT(11), 'FLOAT(11)','FLOAT(11)'],
[Sequelize.FLOAT(11).UNSIGNED, 'FLOAT(11).UNSIGNED', 'FLOAT(11) UNSIGNED'],
[Sequelize.FLOAT(11).UNSIGNED.ZEROFILL,'FLOAT(11).UNSIGNED.ZEROFILL','FLOAT(11) UNSIGNED ZEROFILL'],
[Sequelize.FLOAT(11).ZEROFILL,'FLOAT(11).ZEROFILL', 'FLOAT(11) ZEROFILL'],
[Sequelize.FLOAT(11).ZEROFILL.UNSIGNED,'FLOAT(11).ZEROFILL.UNSIGNED', 'FLOAT(11) UNSIGNED ZEROFILL'],
[Sequelize.FLOAT(11, 12), 'FLOAT(11,12)','FLOAT(11,12)'],
[Sequelize.FLOAT(11, 12).UNSIGNED, 'FLOAT(11,12).UNSIGNED', 'FLOAT(11,12) UNSIGNED'],
[Sequelize.FLOAT(11, 12).UNSIGNED.ZEROFILL,'FLOAT(11,12).UNSIGNED.ZEROFILL','FLOAT(11,12) UNSIGNED ZEROFILL'],
[Sequelize.FLOAT(11, 12).ZEROFILL,'FLOAT(11,12).ZEROFILL', 'FLOAT(11,12) ZEROFILL'],
[Sequelize.FLOAT(11, 12).ZEROFILL.UNSIGNED,'FLOAT(11,12).ZEROFILL.UNSIGNED', 'FLOAT(11,12) UNSIGNED ZEROFILL']
]
tests.forEach(function(test) {
it('transforms "' + test[1] + '" to "' + test[2] + '"', function(done) {
expect(test[0].toString()).to.equal(test[2])
done()
})
})
})
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, sinon = require('sinon')
, CustomEventEmitter = require("../../lib/emitters/custom-event-emitter")
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("CustomEventEmitter"), function () {
describe("proxy", function () {
it("should correctly work with success listeners", function(done) {
var emitter = new CustomEventEmitter()
, proxy = new CustomEventEmitter()
, success = sinon.spy()
emitter.success(success)
proxy.success(function () {
process.nextTick(function () {
expect(success.called).to.be.true
done()
})
})
proxy.proxy(emitter)
proxy.emit('success')
})
it("should correctly work with error listeners", function(done) {
var emitter = new CustomEventEmitter()
, proxy = new CustomEventEmitter()
, error = sinon.spy()
emitter.error(error)
proxy.error(function() {
process.nextTick(function() {
expect(error.called).to.be.true
done()
})
})
proxy.proxy(emitter)
proxy.emit('error')
})
it("should correctly work with complete/done listeners", function(done) {
var emitter = new CustomEventEmitter()
, proxy = new CustomEventEmitter()
, complete = sinon.spy()
emitter.complete(complete)
proxy.complete(function() {
process.nextTick(function() {
expect(complete.called).to.be.true
done()
})
})
proxy.proxy(emitter)
proxy.emit('success')
})
})
})
var chai = require('chai')
, expect = chai.expect
, Sequelize = require(__dirname + '/../index')
, Support = require(__dirname + '/support')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("Language Util"), function() {
before(function(done) {
this.sequelize.options.language = 'es'
done()
})
after(function(done) {
this.sequelize.options.language = 'en'
done()
})
describe("Plural", function(){
it("should rename tables to their plural form...", function(done){
var self = this
, table = self.sequelize.define('arbol', {name: Sequelize.STRING})
, table2 = self.sequelize.define('androide', {name: Sequelize.STRING})
expect(table.tableName).to.equal('arboles')
expect(table2.tableName).to.equal('androides')
done()
})
it("should be able to pluralize/singularize associations...", function(done){
var self = this
, table = self.sequelize.define('arbol', {name: Sequelize.STRING})
, table2 = self.sequelize.define('androide', {name: Sequelize.STRING})
, table3 = self.sequelize.define('hombre', {name: Sequelize.STRING})
table.hasOne(table2)
table2.belongsTo(table)
table3.hasMany(table2)
expect(table.associations.androides.identifier).to.equal('arbolId')
expect(table2.associations.arboles).to.exist
expect(table3.associations.androideshombres).to.exist
done()
})
})
})
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, QueryChainer = require("../lib/query-chainer")
, Migrator = require("../lib/migrator")
, dialect = Support.getTestDialect()
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("Migrator"), function() {
beforeEach(function() {
this.init = function(options, callback) {
options = Support.Sequelize.Utils._.extend({
path: __dirname + '/assets/migrations',
logging: function(){}
}, options || {})
var migrator = new Migrator(this.sequelize, options)
migrator
.findOrCreateSequelizeMetaDAO({ force: true })
.success(function(SequelizeMeta) {
callback && callback(migrator, SequelizeMeta)
})
.error(function(err) { console.log(err) })
}.bind(this)
})
describe('getUndoneMigrations', function() {
it("returns no files if timestamps are after the files timestamp", function(done) {
this.init({ from: 20120101010101 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).to.be.null
expect(migrations.length).to.equal(0)
done()
})
})
})
it("returns only files between from and to", function(done) {
this.init({ from: 19700101000000, to: 20111117063700 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).to.be.null
expect(migrations.length).to.equal(1)
expect(migrations[migrations.length - 1].filename).to.equal('20111117063700-createPerson.js')
done()
})
})
})
it("returns exactly the migration which is defined in from and to", function(done) {
this.init({ from: 20111117063700, to: 20111117063700 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).to.be.null
expect(migrations.length).to.equal(1)
expect(migrations[migrations.length - 1].filename).to.equal('20111117063700-createPerson.js')
done()
})
})
})
it("returns also the file which is exactly options.from or options.to", function(done) {
this.init({ from: 20111117063700, to: 20111130161100 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).to.be.null
expect(migrations).to.have.length(2)
expect(migrations[0].filename).to.equal('20111117063700-createPerson.js')
expect(migrations[1].filename).to.equal('20111130161100-emptyMigration.js')
done()
})
})
})
it("returns all files to options.to if no options.from is defined", function(done) {
this.init({ to: 20111130161100 }, function(migrator) {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).to.be.null
expect(migrations).to.have.length(2)
done()
})
})
})
it("returns all files from last migration id stored in database", function(done) {
this.init(undefined, function(migrator, SequelizeMeta) {
SequelizeMeta.create({ from: null, to: 20111117063700 }).success(function() {
migrator.getUndoneMigrations(function(err, migrations) {
expect(err).to.be.null
expect(migrations).to.have.length(6)
expect(migrations[0].filename).to.equal('20111130161100-emptyMigration.js')
done()
})
})
})
})
})
describe('migrations', function() {
beforeEach(function(done) {
var self = this
this.init({ from: 20111117063700, to: 20111117063700 }, function(migrator) {
self.migrator = migrator
self.migrator.migrate().success(done)
})
})
describe('executions', function() {
it("executes migration #20111117063700 and correctly creates the table", function(done) {
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).to.eql([ 'Person' ])
done()
})
})
it("executes migration #20111117063700 and correctly adds isBetaMember", function(done) {
this.sequelize.getQueryInterface().describeTable('Person').success(function(data) {
var fields = Object.keys(data).sort()
expect(fields).to.eql([ 'isBetaMember', 'name' ])
done()
})
})
it("executes migration #20111117063700 correctly up (createTable) and downwards (dropTable)", function(done) {
var self = this
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).to.eql([ 'Person' ])
self.migrator.migrate({ method: 'down' }).success(function() {
self.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).to.eql([])
done()
})
})
})
})
it("executes the empty migration #20111130161100", function(done) {
this.init({ from: 20111130161100, to: 20111130161100 }, function(migrator) {
// this migration isn't actually testing anything but
// should not timeout
// expect(1).to.equal(1)
migrator
.migrate()
.success(done)
.error(function(err) { console.log(err) })
})
})
})
describe('renameTable', function() {
beforeEach(function(done) {
var self = this
this.init({ from: 20111117063700, to: 20111117063700 }, function(migrator) {
self.migrator = migrator
self.migrator.migrate().success(done)
})
})
it("executes migration #20111205064000 and renames a table", function(done) {
var self = this
this.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e) { return e != 'SequelizeMeta' })
expect(tableNames).to.include('Person')
self.init({ from: 20111205064000, to: 20111205064000 }, function(migrator) {
migrator.migrate().success(function() {
self.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
tableNames = tableNames.filter(function(e){ return e != 'SequelizeMeta' })
expect(tableNames).to.eql([ 'User' ])
done()
})
})
})
})
})
})
describe('addColumn', function() {
it('adds a column to the user table', function(done) {
var self = this
this.init({ from: 20111117063700, to: 20111205162700 }, function(migrator) {
migrator.migrate().complete(function(err) {
self.sequelize.getQueryInterface().describeTable('User').complete(function(err, data) {
var signature = data.signature
, isAdmin = data.isAdmin
, shopId = data.shopId
expect(signature.allowNull).to.be.true
expect(isAdmin.allowNull).to.be.false
if (dialect === "postgres" || dialect === "postgres-native" || dialect === "sqlite") {
expect(isAdmin.defaultValue).to.be.false
} else {
expect(isAdmin.defaultValue).to.equal("0")
}
expect(shopId.allowNull).to.be.true
done()
})
})
})
})
})
describe('removeColumn', function() {
it('removes the shopId column from user', function(done) {
var self = this
this.init({ to: 20111206061400 }, function(migrator) {
migrator.migrate().success(function(){
self.sequelize.getQueryInterface().describeTable('User').success(function(data) {
var signature = data.signature
, isAdmin = data.isAdmin
, shopId = data.shopId
expect(signature.allowNull).to.be.true
expect(isAdmin.allowNull).to.be.false
if (dialect === "postgres" || dialect === "postgres-native" || dialect === "sqlite") {
expect(isAdmin.defaultValue).to.be.false
} else {
expect(isAdmin.defaultValue).to.equal("0")
}
expect(shopId).to.be.not.ok
done()
})
})
})
})
})
describe('changeColumn', function() {
it('changes the signature column from user to default "signature" + notNull', function(done) {
var self = this
this.init({ to: 20111206063000 }, function(migrator) {
migrator.migrate().success(function() {
self.sequelize.getQueryInterface().describeTable('User').success(function(data) {
var signature = data.signature
if (dialect === 'postgres') {
expect(signature.type).to.equal('CHARACTER VARYING')
} else {
expect(signature.type).to.equal('VARCHAR(255)')
}
expect(signature.allowNull).to.equal(false)
expect(signature.defaultValue).to.equal('Signature')
done()
})
})
})
})
})
})
describe('renameColumn', function() {
it("renames the signature column from user to sig", function(done) {
var self = this
this.init({ to: 20111206163300 }, function(migrator) {
migrator.migrate().success(function(){
self.sequelize.getQueryInterface().describeTable('User').success(function(data) {
var signature = data.signature
, sig = data.sig
expect(signature).to.not.be.ok
expect(sig).to.be.ok
done()
})
})
})
})
})
})
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, sinon = require('sinon')
, DataTypes = require(__dirname + "/../../lib/data-types")
chai.Assertion.includeStack = true
if (dialect.match(/^mysql/)) {
describe('[MYSQL Specific] Associations', function() {
describe('many-to-many', function() {
describe('where tables have the same prefix', function() {
it("should create a table wp_table1wp_table2s", function(done) {
var Table2 = this.sequelize.define('wp_table2', {foo: DataTypes.STRING})
, Table1 = this.sequelize.define('wp_table1', {foo: DataTypes.STRING})
, self = this
Table1.hasMany(Table2)
Table2.hasMany(Table1)
Table1.sync({ force: true }).success(function() {
Table2.sync({ force: true }).success(function() {
expect(self.sequelize.daoFactoryManager.getDAO('wp_table1swp_table2s')).to.exist
done()
})
})
})
})
describe('when join table name is specified', function() {
beforeEach(function(done){
var Table2 = this.sequelize.define('ms_table1', {foo: DataTypes.STRING})
, Table1 = this.sequelize.define('ms_table2', {foo: DataTypes.STRING})
Table1.hasMany(Table2, {joinTableName: 'table1_to_table2'})
Table2.hasMany(Table1, {joinTableName: 'table1_to_table2'})
Table1.sync({ force: true }).success(function() {
Table2.sync({ force: true }).success(function() {
done()
})
})
})
it("should not use only a specified name", function() {
expect(this.sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).not.to.exist
expect(this.sequelize.daoFactoryManager.getDAO('table1_to_table2')).to.exist
})
})
})
describe('HasMany', function() {
beforeEach(function(done) {
//prevent periods from occurring in the table name since they are used to delimit (table.column)
this.User = this.sequelize.define('User' + Math.ceil(Math.random()*10000000), { name: DataTypes.STRING })
this.Task = this.sequelize.define('Task' + Math.ceil(Math.random()*10000000), { name: DataTypes.STRING })
this.users = null
this.tasks = null
this.User.hasMany(this.Task, {as:'Tasks'})
this.Task.hasMany(this.User, {as:'Users'})
var self = this
, users = []
, tasks = []
for (var i = 0; i < 5; ++i) {
users[users.length] = {name: 'User' + Math.random()}
}
for (var x = 0; x < 5; ++x) {
tasks[tasks.length] = {name: 'Task' + Math.random()}
}
this.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.bulkCreate(users).success(function() {
self.Task.bulkCreate(tasks).success(function() {
done()
})
})
})
})
})
describe('addDAO / getDAO', function() {
beforeEach(function(done) {
var self = this
self.user = null
self.task = null
self.User.all().success(function(_users) {
self.Task.all().success(function(_tasks) {
self.user = _users[0]
self.task = _tasks[0]
done()
})
})
})
it('should correctly add an association to the dao', function(done) {
var self = this
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).to.equal(0)
self.user.addTask(self.task).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).to.equal(1)
done()
})
})
})
})
})
describe('removeDAO', function() {
beforeEach(function(done) {
var self = this
self.user = null
self.tasks = null
self.User.all().success(function(_users) {
self.Task.all().success(function(_tasks) {
self.user = _users[0]
self.tasks = _tasks
done()
})
})
})
it("should correctly remove associated objects", function(done) {
var self = this
self.user.getTasks().on('success', function(__tasks) {
expect(__tasks.length).to.equal(0)
self.user.setTasks(self.tasks).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).to.equal(self.tasks.length)
self.user.removeTask(self.tasks[0]).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks.length).to.equal(self.tasks.length - 1)
done()
})
})
})
})
})
})
})
})
})
}
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, sinon = require('sinon')
, DataTypes = require(__dirname + "/../../lib/data-types")
chai.Assertion.includeStack = true
if (dialect.match(/^mysql/)) {
describe('[MYSQL Specific] Connector Manager', function() {
this.timeout(10000)
it('works correctly after being idle', function(done) {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, spy = sinon.spy()
User.sync({force: true}).on('success', function() {
User.create({username: 'user1'}).on('success', function() {
User.count().on('success', function(count) {
expect(count).to.equal(1)
spy()
setTimeout(function() {
User.count().on('success', function(count) {
expect(count).to.equal(1)
spy()
if (spy.calledTwice) {
done()
}
})
}, 1000)
})
})
})
})
})
}
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Support.getTestDialect()
, config = require(__dirname + "/../config/config")
chai.Assertion.includeStack = true
if (dialect.match(/^mysql/)) {
describe("[MYSQL Specific] DAOFactory", function () {
describe('constructor', function() {
it("handles extended attributes (unique)", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
username: { type: DataTypes.STRING, unique: true }
}, { timestamps: false })
expect(User.attributes).to.deep.equal({username:"VARCHAR(255) UNIQUE",id:"INTEGER NOT NULL auto_increment PRIMARY KEY"})
done()
})
it("handles extended attributes (default)", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, defaultValue: 'foo'}
}, { timestamps: false })
expect(User.attributes).to.deep.equal({username:"VARCHAR(255) DEFAULT 'foo'",id:"INTEGER NOT NULL auto_increment PRIMARY KEY"})
done()
})
it("handles extended attributes (null)", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, allowNull: false}
}, { timestamps: false })
expect(User.attributes).to.deep.equal({username:"VARCHAR(255) NOT NULL",id:"INTEGER NOT NULL auto_increment PRIMARY KEY"})
done()
})
it("handles extended attributes (comment)", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, comment: 'This be\'s a comment'}
}, { timestamps: false })
expect(User.attributes).to.deep.equal({username:"VARCHAR(255) COMMENT 'This be\\'s a comment'",id:"INTEGER NOT NULL auto_increment PRIMARY KEY"})
done()
})
it("handles extended attributes (primaryKey)", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
username: {type: DataTypes.STRING, primaryKey: true}
}, { timestamps: false })
expect(User.attributes).to.deep.equal({username:"VARCHAR(255) PRIMARY KEY"})
done()
})
it("adds timestamps", function(done) {
var User1 = this.sequelize.define('User' + config.rand(), {})
var User2 = this.sequelize.define('User' + config.rand(), {}, { timestamps: true })
expect(User1.attributes).to.deep.equal({id:"INTEGER NOT NULL auto_increment PRIMARY KEY", updatedAt:"DATETIME NOT NULL", createdAt:"DATETIME NOT NULL"})
expect(User2.attributes).to.deep.equal({id:"INTEGER NOT NULL auto_increment PRIMARY KEY", updatedAt:"DATETIME NOT NULL", createdAt:"DATETIME NOT NULL"})
done()
})
it("adds deletedAt if paranoid", function(done) {
var User = this.sequelize.define('User' + config.rand(), {}, { paranoid: true })
expect(User.attributes).to.deep.equal({id:"INTEGER NOT NULL auto_increment PRIMARY KEY", deletedAt:"DATETIME", updatedAt:"DATETIME NOT NULL", createdAt:"DATETIME NOT NULL"})
done()
})
it("underscores timestamps if underscored", function(done) {
var User = this.sequelize.define('User' + config.rand(), {}, { paranoid: true, underscored: true })
expect(User.attributes).to.deep.equal({id:"INTEGER NOT NULL auto_increment PRIMARY KEY", deleted_at:"DATETIME", updated_at:"DATETIME NOT NULL", created_at:"DATETIME NOT NULL"})
done()
})
})
describe('primaryKeys', function() {
it("determines the correct primaryKeys", function(done) {
var User = this.sequelize.define('User' + config.rand(), {
foo: {type: DataTypes.STRING, primaryKey: true},
bar: DataTypes.STRING
})
expect(User.primaryKeys).to.deep.equal({"foo":"VARCHAR(255) PRIMARY KEY"})
done()
})
})
})
}
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, util = require("util")
, _ = require('lodash')
, QueryGenerator = require("../../lib/dialects/mysql/query-generator")
chai.Assertion.includeStack = true
if (dialect.match(/^mysql/)) {
describe("[MYSQL Specific] QueryGenerator", function () {
var suites = {
attributesToSQL: [
{
arguments: [{id: 'INTEGER'}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: 'INTEGER', foo: 'VARCHAR(255)'}],
expectation: {id: 'INTEGER', foo: 'VARCHAR(255)'}
},
{
arguments: [{id: {type: 'INTEGER'}}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false}}],
expectation: {id: 'INTEGER NOT NULL'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: true}}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: {type: 'INTEGER', primaryKey: true, autoIncrement: true}}],
expectation: {id: 'INTEGER auto_increment PRIMARY KEY'}
},
{
arguments: [{id: {type: 'INTEGER', defaultValue: 0}}],
expectation: {id: 'INTEGER DEFAULT 0'}
},
{
arguments: [{id: {type: 'INTEGER', unique: true}}],
expectation: {id: 'INTEGER UNIQUE'}
},
{
arguments: [{id: {type: 'INTEGER', comment: "I'm a comment!" }}],
expectation: {id: "INTEGER COMMENT 'I\\'m a comment!'" }
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`pk`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON DELETE CASCADE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON UPDATE RESTRICT'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, autoIncrement: true, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL auto_increment DEFAULT 1 REFERENCES `Bar` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT'}
},
],
createTableQuery: [
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255)) ENGINE=InnoDB;"
},
{
arguments: ['myTable', {title: "INTEGER COMMENT 'I\\'m a comment!'"}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` INTEGER COMMENT 'I\\'m a comment!') ENGINE=InnoDB;"
},
{
arguments: ['myTable', {title: "INTEGER"}, {comment: "I'm a comment!"}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` INTEGER) COMMENT 'I\\'m a comment!' ENGINE=InnoDB;"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}, {engine: 'MyISAM'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255)) ENGINE=MyISAM;"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}, {charset: 'utf8', collate: 'utf8_unicode_ci'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}, {charset: 'latin1'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"
},
{
arguments: ['myTable', {title: 'ENUM("A", "B", "C")', name: 'VARCHAR(255)'}, {charset: 'latin1'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` ENUM(\"A\", \"B\", \"C\"), `name` VARCHAR(255)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', id: 'INTEGER PRIMARY KEY'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255), `id` INTEGER , PRIMARY KEY (`id`)) ENGINE=InnoDB;"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', otherId: 'INTEGER REFERENCES `otherTable` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255), `otherId` INTEGER, FOREIGN KEY (`otherId`) REFERENCES `otherTable` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION) ENGINE=InnoDB;"
}
],
dropTableQuery: [
{
arguments: ['myTable'],
expectation: "DROP TABLE IF EXISTS `myTable`;"
}
],
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', {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: ["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, 18440000000000000000;",
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'}],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('foo');"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('foo\\';DROP TABLE myTable;');"
}, {
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');"
}, {
arguments: ['myTable', {name: 'foo', foo: 1}],
expectation: "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);"
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: null}],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);"
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: null}],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: null}],
expectation: "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);",
context: {options: {omitNull: true}}
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: undefined}],
expectation: "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);",
context: {options: {omitNull: true}}
}, {
arguments: ['myTable', {foo: false}],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (false);"
}, {
arguments: ['myTable', {foo: true}],
expectation: "INSERT INTO `myTable` (`foo`) VALUES (true);"
}
],
bulkInsertQuery: [
{
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('foo'),('bar');"
}, {
arguments: ['myTable', [{name: "foo';DROP TABLE myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('foo\\';DROP TABLE myTable;'),('bar');"
}, {
arguments: ['myTable', [{name: 'foo', birthday: new Date(Date.UTC(2011, 2, 27, 10, 1, 55))}, {name: 'bar', birthday: new Date(Date.UTC(2012, 2, 27, 10, 1, 55))}]],
expectation: "INSERT INTO `myTable` (`name`,`birthday`) VALUES ('foo','2011-03-27 10:01:55'),('bar','2012-03-27 10:01:55');"
}, {
arguments: ['myTable', [{name: 'foo', foo: 1}, {name: 'bar', foo: 2}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1),('bar',2);"
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',NULL);"
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', foo: 2, nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', foo: 2, nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);",
context: {options: {omitNull: true}} // Note: We don't honour this because it makes little sense when some rows may have nulls and others not
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: undefined}, {name: 'bar', foo: 2, undefinedValue: undefined}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);",
context: {options: {omitNull: true}} // Note: As above
}, {
arguments: ['myTable', [{name: "foo", value: true}, {name: 'bar', value: false}]],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',true),('bar',false);"
}
],
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' 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' 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'"
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=2,`nullValue`=NULL WHERE `name`='foo'"
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=2,`nullValue`=NULL WHERE `name`='foo'",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=2 WHERE `name`='foo'",
context: {options: {omitNull: true}}
}, {
arguments: ['myTable', {bar: false}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=false WHERE `name`='foo'"
}, {
arguments: ['myTable', {bar: true}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=true WHERE `name`='foo'"
}
],
deleteQuery: [
{
arguments: ['myTable', {name: 'foo'}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo' LIMIT 1"
}, {
arguments: ['myTable', 1],
expectation: "DELETE FROM `myTable` WHERE `id`=1 LIMIT 1"
},{
arguments: ['myTable', undefined, {truncate: true}],
expectation: "TRUNCATE `myTable`"
},{
arguments: ['myTable', 1, {limit: 10, truncate: true}],
expectation: "TRUNCATE `myTable`"
}, {
arguments: ['myTable', 1, {limit: 10}],
expectation: "DELETE FROM `myTable` WHERE `id`=1 LIMIT 10"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {limit: 10}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo\\';DROP TABLE myTable;' LIMIT 10"
}, {
arguments: ['myTable', {name: 'foo'}, {limit: null}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo'"
}
],
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'], { parser: 'foo', indicesType: 'FULLTEXT', indexName: 'bar'}
],
expectation: "CREATE FULLTEXT INDEX bar ON User (username, isAdmin) WITH PARSER foo"
}
],
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 user_foo_bar ON User"
}, {
arguments: ['User', ['foo', 'bar']],
expectation: "DROP INDEX user_foo_bar ON User"
}
],
hashToWhereConditions: [
{
arguments: [{ id: [1,2,3] }],
expectation: "`id` IN (1,2,3)"
},
{
arguments: [{ id: [] }],
expectation: "`id` IN (NULL)"
},
{
arguments: [{ maple: false, bacon: true }],
expectation: "`maple`=false AND `bacon`=true"
},
{
arguments: [{ beaver: [false, true] }],
expectation: "`beaver` IN (false,true)"
},
{
arguments: [{birthday: new Date(Date.UTC(2011, 6, 1, 10, 1, 55))}],
expectation: "`birthday`='2011-07-01 10:01:55'"
},
{
arguments: [{ birthday: new Date(Date.UTC(2011, 6, 1, 10, 1, 55)),
otherday: new Date(Date.UTC(2013, 6, 2, 10, 1, 22)) }],
expectation: "`birthday`='2011-07-01 10:01:55' AND `otherday`='2013-07-02 10:01:22'"
},
{
arguments: [{ birthday: [new Date(Date.UTC(2011, 6, 1, 10, 1, 55)), new Date(Date.UTC(2013, 6, 2, 10, 1, 22))] }],
expectation: "`birthday` IN ('2011-07-01 10:01:55','2013-07-02 10:01:22')"
}
]
}
_.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() {
tests.forEach(function(test) {
var title = test.title || 'MySQL correctly returns ' + test.expectation + ' for ' + util.inspect(test.arguments)
it(title, function(done) {
// 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: {}};
QueryGenerator.options = context.options
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation)
done()
})
})
})
})
})
}
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, config = require(__dirname + '/../config/config')
, DataTypes = require(__dirname + "/../../lib/data-types")
chai.Assertion.includeStack = true
if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] associations', function() {
beforeEach(function(done) {
this.sequelize.options.quoteIdentifier = true
done()
})
describe('many-to-many', function() {
describe('where tables have the same prefix', function() {
it("should create a table wp_table1wp_table2s", function(done) {
var Table2 = this.sequelize.define('wp_table2', {foo: DataTypes.STRING})
, Table1 = this.sequelize.define('wp_table1', {foo: DataTypes.STRING})
Table1.hasMany(Table2)
Table2.hasMany(Table1)
expect(this.sequelize.daoFactoryManager.getDAO('wp_table1swp_table2s')).to.exist
done()
})
})
describe('when join table name is specified', function() {
beforeEach(function(done){
var Table2 = this.sequelize.define('ms_table1', {foo: DataTypes.STRING})
, Table1 = this.sequelize.define('ms_table2', {foo: DataTypes.STRING})
Table1.hasMany(Table2, {joinTableName: 'table1_to_table2'})
Table2.hasMany(Table1, {joinTableName: 'table1_to_table2'})
done()
})
it("should not use a combined name", function(done) {
expect(this.sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).not.to.exist
done()
})
it("should use the specified name", function(done) {
expect(this.sequelize.daoFactoryManager.getDAO('table1_to_table2')).to.exist
done()
})
})
})
describe('HasMany', function() {
describe('addDAO / getDAO', function() {
beforeEach(function(done) {
var self = this
//prevent periods from occurring in the table name since they are used to delimit (table.column)
this.User = this.sequelize.define('User' + config.rand(), { name: DataTypes.STRING })
this.Task = this.sequelize.define('Task' + config.rand(), { name: DataTypes.STRING })
this.users = null
this.tasks = null
this.User.hasMany(this.Task, {as:'Tasks'})
this.Task.hasMany(this.User, {as:'Users'})
var self = this
, users = []
, tasks = []
for (var i = 0; i < 5; ++i) {
users[users.length] = {name: 'User' + Math.random()}
}
for (var x = 0; x < 5; ++x) {
tasks[tasks.length] = {name: 'Task' + Math.random()}
}
self.sequelize.getQueryInterface().dropAllTables().success(function() {
self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.bulkCreate(users).success(function() {
self.Task.bulkCreate(tasks).success(function() {
self.User.all().success(function(_users) {
self.Task.all().success(function(_tasks) {
self.user = _users[0]
self.task = _tasks[0]
done()
})
})
})
})
})
})
})
})
it('should correctly add an association to the dao', function(done) {
var self = this
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(0)
self.user.addTask(self.task).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(1)
done()
})
})
})
})
})
describe('removeDAO', function() {
it("should correctly remove associated objects", function(done) {
var self = this
, users = []
, tasks = []
//prevent periods from occurring in the table name since they are used to delimit (table.column)
this.User = this.sequelize.define('User' + config.rand(), { name: DataTypes.STRING })
this.Task = this.sequelize.define('Task' + config.rand(), { name: DataTypes.STRING })
this.users = null
this.tasks = null
this.User.hasMany(this.Task, {as:'Tasks'})
this.Task.hasMany(this.User, {as:'Users'})
for (var i = 0; i < 5; ++i) {
users[users.length] = {id: i, name: 'User' + Math.random()}
}
for (var x = 0; x < 5; ++x) {
tasks[tasks.length] = {id: i, name: 'Task' + Math.random()}
}
self.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
self.User.bulkCreate(users).success(function() {
self.Task.bulkCreate(tasks).success(function() {
self.User.all().success(function(_users) {
self.Task.all().success(function(_tasks) {
self.user = _users[0]
self.task = _tasks[0]
self.users = _users
self.tasks = _tasks
self.user.getTasks().on('success', function(__tasks) {
expect(__tasks).to.have.length(0)
self.user.setTasks(self.tasks).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(self.tasks.length)
self.user.removeTask(self.tasks[0]).on('success', function() {
self.user.getTasks().on('success', function(_tasks) {
expect(_tasks).to.have.length(self.tasks.length - 1)
done()
})
})
})
})
})
})
})
})
})
})
})
})
})
})
})
}
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, config = require(__dirname + '/../config/config')
, DataTypes = require(__dirname + "/../../lib/data-types")
chai.Assertion.includeStack = true
if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] DAO', function() {
beforeEach(function(done) {
this.sequelize.options.quoteIdentifiers = true
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
})
this.User.sync({ force: true }).success(function() {
done()
})
})
afterEach(function(done) {
this.sequelize.options.quoteIdentifiers = true
done()
})
describe('model', function() {
it("create handles array correctly", function(done) {
this.User
.create({ username: 'user', email: ['foo@bar.com', 'bar@baz.com'] })
.success(function(oldUser) {
expect(oldUser.email).to.contain.members(['foo@bar.com', 'bar@baz.com'])
done()
})
.error(function(err) {
console.log(err)
})
})
it("should handle hstore correctly", function(done) {
var self = this
this.User
.create({ username: 'user', email: ['foo@bar.com'], document: { created: { test: '"value"' }}})
.success(function(newUser) {
expect(newUser.document).to.deep.equal({ created: { test: '"value"' }})
// Check to see if updating an hstore field works
newUser.updateAttributes({document: {should: 'update', to: 'this', first: 'place'}}).success(function(oldUser){
// Postgres always returns keys in alphabetical order (ascending)
expect(oldUser.document).to.deep.equal({first: 'place', should: 'update', to: 'this'})
// Check to see if the default value for an hstore field works
self.User.create({ username: 'user2', email: ['bar@baz.com']}).success(function(defaultUser){
expect(defaultUser.document).to.deep.equal({default: 'value'})
done()
})
})
})
.error(console.log)
})
})
describe('[POSTGRES] Unquoted identifiers', function() {
it("can insert and select", function(done) {
var self = this
this.sequelize.options.quoteIdentifiers = false
this.sequelize.getQueryInterface().QueryGenerator.options.quoteIdentifiers = false
this.User = this.sequelize.define('Userxs', {
username: DataTypes.STRING,
fullName: DataTypes.STRING // Note mixed case
}, {
quoteIdentifiers: false
})
this.User.sync({ force: true }).success(function() {
self.User
.create({ username: 'user', fullName: "John Smith" })
.success(function(user) {
// We can insert into a table with non-quoted identifiers
expect(user.id).to.exist
expect(user.id).not.to.be.null
expect(user.username).to.equal('user')
expect(user.fullName).to.equal('John Smith')
// We can query by non-quoted identifiers
self.User.find({
where: {fullName: "John Smith"}
})
.success(function(user2) {
self.sequelize.options.quoteIndentifiers = true
self.sequelize.getQueryInterface().QueryGenerator.options.quoteIdentifiers = true
self.sequelize.options.logging = false
// We can map values back to non-quoted identifiers
expect(user2.id).to.equal(user.id)
expect(user2.username).to.equal('user')
expect(user2.fullName).to.equal('John Smith')
done()
})
})
})
})
})
})
}
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, hstore = require(__dirname + '/../../lib/dialects/postgres/hstore')
chai.Assertion.includeStack = true
if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] hstore', function() {
describe('stringifyPart', function() {
it("handles undefined values correctly", function(done) {
expect(hstore.stringifyPart(undefined)).to.equal('NULL')
done()
})
it("handles null values correctly", function(done) {
expect(hstore.stringifyPart(null)).to.equal('NULL')
done()
})
it("handles boolean values correctly", function(done) {
expect(hstore.stringifyPart(false)).to.equal('false')
expect(hstore.stringifyPart(true)).to.equal('true')
done()
})
it("handles strings correctly", function(done) {
expect(hstore.stringifyPart('foo')).to.equal('"foo"')
done()
})
it("handles strings with backslashes correctly", function(done) {
expect(hstore.stringifyPart("\\'literally\\'")).to.equal('"\\\\\'literally\\\\\'"')
done()
})
it("handles arrays correctly", function(done) {
expect(hstore.stringifyPart([1,['2'],'"3"'])).to.equal('"[1,[\\"2\\"],\\"\\\\\\"3\\\\\\"\\"]"')
done()
})
it("handles simple objects correctly", function(done) {
expect(hstore.stringifyPart({ test: 'value' })).to.equal('"{\\"test\\":\\"value\\"}"')
done()
})
it("handles nested objects correctly", function(done) {
expect(hstore.stringifyPart({ test: { nested: 'value' } })).to.equal('"{\\"test\\":{\\"nested\\":\\"value\\"}}"')
done()
})
it("handles objects correctly", function(done) {
expect(hstore.stringifyPart({test: {nested: {value: {including: '"string"'}}}})).to.equal('"{\\"test\\":{\\"nested\\":{\\"value\\":{\\"including\\":\\"\\\\\\"string\\\\\\"\\"}}}}"')
done()
})
})
describe('stringify', function() {
it('should handle empty objects correctly', function(done) {
expect(hstore.stringify({ })).to.equal('')
done()
})
it('should handle null values correctly', function(done) {
expect(hstore.stringify({ null: null })).to.equal('"null"=>NULL')
done()
})
it('should handle simple objects correctly', function(done) {
expect(hstore.stringify({ test: 'value' })).to.equal('"test"=>"value"')
done()
})
it('should handle nested objects correctly', function(done) {
expect(hstore.stringify({ test: { nested: 'value' } })).to.equal('"test"=>"{\\"nested\\":\\"value\\"}"')
done()
})
it('should handle nested arrays correctly', function(done) {
expect(hstore.stringify({ test: [ 1, '2', [ '"3"' ] ] })).to.equal('"test"=>"[1,\\"2\\",[\\"\\\\\\"3\\\\\\"\\"]]"')
done()
})
it('should handle multiple keys with different types of values', function(done) {
expect(hstore.stringify({ true: true, false: false, null: null, undefined: undefined, integer: 1, array: [1,'2'], object: { object: 'value' }})).to.equal('"true"=>true,"false"=>false,"null"=>NULL,"undefined"=>NULL,"integer"=>1,"array"=>"[1,\\"2\\"]","object"=>"{\\"object\\":\\"value\\"}"')
done()
})
})
describe('parse', function() {
it('should handle empty objects correctly', function(done) {
expect(hstore.parse('')).to.deep.equal({ })
done()
})
it('should handle simple objects correctly', function(done) {
expect(hstore.parse('"test"=>"value"')).to.deep.equal({ test: 'value' })
done()
})
it('should handle nested objects correctly', function(done) {
expect(hstore.parse('"test"=>"{\\"nested\\":\\"value\\"}"')).to.deep.equal({ test: { nested: 'value' } })
done()
})
it('should handle nested arrays correctly', function(done) {
expect(hstore.parse('"test"=>"[1,\\"2\\",[\\"\\\\\\"3\\\\\\"\\"]]"')).to.deep.equal({ test: [ 1, '2', [ '"3"' ] ] })
done()
})
it('should handle multiple keys with different types of values', function(done) {
expect(hstore.parse('"true"=>true,"false"=>false,"null"=>NULL,"undefined"=>NULL,"integer"=>1,"array"=>"[1,\\"2\\"]","object"=>"{\\"object\\":\\"value\\"}"')).to.deep.equal({ true: true, false: false, null: null, undefined: null, integer: "1", array: [1,'2'], object: { object: 'value' }})
done()
})
})
})
}
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, QueryGenerator = require("../../lib/dialects/postgres/query-generator")
, Support = require(__dirname + '/../support')
, dialect = Support.getTestDialect()
, DataTypes = require(__dirname + "/../../lib/data-types")
, moment = require('moment')
, util = require("util")
, _ = require('lodash')
chai.Assertion.includeStack = true
if (dialect.match(/^postgres/)) {
describe('[POSTGRES Specific] QueryGenerator', function() {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)},
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'}
})
this.User.sync({ force: true }).success(function() {
done()
})
})
var suites = {
attributesToSQL: [
{
arguments: [{id: 'INTEGER'}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: 'INTEGER', foo: 'VARCHAR(255)'}],
expectation: {id: 'INTEGER', foo: 'VARCHAR(255)'}
},
{
arguments: [{id: {type: 'INTEGER'}}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false}}],
expectation: {id: 'INTEGER NOT NULL'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: true}}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: {type: 'INTEGER', primaryKey: true, autoIncrement: true}}],
expectation: {id: 'INTEGER SERIAL PRIMARY KEY'}
},
{
arguments: [{id: {type: 'INTEGER', defaultValue: 0}}],
expectation: {id: 'INTEGER DEFAULT 0'}
},
{
arguments: [{id: {type: 'INTEGER', unique: true}}],
expectation: {id: 'INTEGER UNIQUE'}
},
{
arguments: [{id: {type: 'INTEGER', comment: "I'm a comment!" }}],
expectation: {id: "INTEGER COMMENT ON COLUMN <%= table %>.\"id\" IS 'I''m a comment!'" }
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id")'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("pk")'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id") ON DELETE CASCADE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES "Bar" ("id") ON UPDATE RESTRICT'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES "Bar" ("id") ON DELETE CASCADE ON UPDATE RESTRICT'}
},
// Variants when quoteIdentifiers is false
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES Bar (id)'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES Bar (pk)'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES Bar (id) ON DELETE CASCADE'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES Bar (id) ON UPDATE RESTRICT'},
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES Bar (id) ON DELETE CASCADE ON UPDATE RESTRICT'},
context: {options: {quoteIdentifiers: false}}
},
],
createTableQuery: [
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" VARCHAR(255), \"name\" VARCHAR(255));",
},
{
arguments: ['myTable', {title: "INTEGER COMMENT ON COLUMN <%= table %>.\"title\" IS 'I''m a comment!'"}],
expectation: "CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" INTEGER ); COMMENT ON COLUMN \"myTable\".\"title\" IS 'I''m a comment!';",
},
{
arguments: ['myTable', {title: "INTEGER"}, {comment: "I'm a comment!"}],
expectation: "CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" INTEGER); COMMENT ON TABLE \"myTable\" IS 'I''m a comment!';",
},
{
arguments: ['mySchema.myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS \"mySchema\".\"myTable\" (\"title\" VARCHAR(255), \"name\" VARCHAR(255));"
},
{
arguments: ['myTable', {title: 'ENUM("A", "B", "C")', name: 'VARCHAR(255)'}],
expectation: "DROP TYPE IF EXISTS \"enum_myTable_title\"; CREATE TYPE \"enum_myTable_title\" AS ENUM(\"A\", \"B\", \"C\"); CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" \"enum_myTable_title\", \"name\" VARCHAR(255));"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', id: 'INTEGER PRIMARY KEY'}],
expectation: "CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" VARCHAR(255), \"name\" VARCHAR(255), \"id\" INTEGER , PRIMARY KEY (\"id\"));"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', otherId: 'INTEGER REFERENCES "otherTable" ("id") ON DELETE CASCADE ON UPDATE NO ACTION'}],
expectation: "CREATE TABLE IF NOT EXISTS \"myTable\" (\"title\" VARCHAR(255), \"name\" VARCHAR(255), \"otherId\" INTEGER REFERENCES \"otherTable\" (\"id\") ON DELETE CASCADE ON UPDATE NO ACTION);"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS myTable (title VARCHAR(255), name VARCHAR(255));",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['mySchema.myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS mySchema.myTable (title VARCHAR(255), name VARCHAR(255));",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['myTable', {title: 'ENUM("A", "B", "C")', name: 'VARCHAR(255)'}],
expectation: "DROP TYPE IF EXISTS enum_myTable_title; CREATE TYPE enum_myTable_title AS ENUM(\"A\", \"B\", \"C\"); CREATE TABLE IF NOT EXISTS myTable (title enum_myTable_title, name VARCHAR(255));",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', id: 'INTEGER PRIMARY KEY'}],
expectation: "CREATE TABLE IF NOT EXISTS myTable (title VARCHAR(255), name VARCHAR(255), id INTEGER , PRIMARY KEY (id));",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', otherId: 'INTEGER REFERENCES otherTable (id) ON DELETE CASCADE ON UPDATE NO ACTION'}],
expectation: "CREATE TABLE IF NOT EXISTS myTable (title VARCHAR(255), name VARCHAR(255), otherId INTEGER REFERENCES otherTable (id) ON DELETE CASCADE ON UPDATE NO ACTION);",
context: {options: {quoteIdentifiers: false}}
}
],
dropTableQuery: [
{
arguments: ['myTable'],
expectation: "DROP TABLE IF EXISTS \"myTable\";"
},
{
arguments: ['mySchema.myTable'],
expectation: "DROP TABLE IF EXISTS \"mySchema\".\"myTable\";"
},
{
arguments: ['myTable', {cascade: true}],
expectation: "DROP TABLE IF EXISTS \"myTable\" CASCADE;"
},
{
arguments: ['mySchema.myTable', {cascade: true}],
expectation: "DROP TABLE IF EXISTS \"mySchema\".\"myTable\" CASCADE;"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable'],
expectation: "DROP TABLE IF EXISTS myTable;",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['mySchema.myTable'],
expectation: "DROP TABLE IF EXISTS mySchema.myTable;",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['myTable', {cascade: true}],
expectation: "DROP TABLE IF EXISTS myTable CASCADE;",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: ['mySchema.myTable', {cascade: true}],
expectation: "DROP TABLE IF EXISTS mySchema.myTable CASCADE;",
context: {options: {quoteIdentifiers: false}}
}
],
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 \"myTable\".\"id\"=2;"
}, {
arguments: ['myTable', {where: {name: 'foo'}}],
expectation: "SELECT * FROM \"myTable\" WHERE \"myTable\".\"name\"='foo';"
}, {
arguments: ['myTable', {where: {name: "foo';DROP TABLE myTable;"}}],
expectation: "SELECT * FROM \"myTable\" WHERE \"myTable\".\"name\"='foo'';DROP TABLE myTable;';"
}, {
arguments: ['myTable', {where: 2}],
expectation: "SELECT * FROM \"myTable\" WHERE \"myTable\".\"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', {group: ["name"]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\";"
}, {
arguments: ['myTable', {group: ["name","title"]}],
expectation: "SELECT * FROM \"myTable\" GROUP BY \"name\", \"title\";"
}, {
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;"
}, {
arguments: ['mySchema.myTable'],
expectation: "SELECT * FROM \"mySchema\".\"myTable\";"
}, {
arguments: ['mySchema.myTable', {where: {name: "foo';DROP TABLE mySchema.myTable;"}}],
expectation: "SELECT * FROM \"mySchema\".\"myTable\" WHERE \"mySchema\".\"myTable\".\"name\"='foo'';DROP TABLE mySchema.myTable;';"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable'],
expectation: "SELECT * FROM myTable;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {attributes: ['id', 'name']}],
expectation: "SELECT id, name FROM myTable;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {where: {id: 2}}],
expectation: "SELECT * FROM myTable WHERE myTable.id=2;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {where: {name: 'foo'}}],
expectation: "SELECT * FROM myTable WHERE myTable.name='foo';",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {where: {name: "foo';DROP TABLE myTable;"}}],
expectation: "SELECT * FROM myTable WHERE myTable.name='foo'';DROP TABLE myTable;';",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {where: 2}],
expectation: "SELECT * FROM myTable WHERE myTable.id=2;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['foo', { attributes: [['count(*)', 'count']] }],
expectation: 'SELECT count(*) as count FROM foo;',
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {where: "foo='bar'"}],
expectation: "SELECT * FROM myTable WHERE foo='bar';",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {order: "id DESC"}],
expectation: "SELECT * FROM myTable ORDER BY id DESC;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {group: "name"}],
expectation: "SELECT * FROM myTable GROUP BY name;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {group: ["name"]}],
expectation: "SELECT * FROM myTable GROUP BY name;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {group: ["name","title"]}],
expectation: "SELECT * FROM myTable GROUP BY name, title;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {limit: 10}],
expectation: "SELECT * FROM myTable LIMIT 10;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {limit: 10, offset: 2}],
expectation: "SELECT * FROM myTable LIMIT 10 OFFSET 2;",
context: {options: {quoteIdentifiers: false}}
}, {
title: 'uses offset even if no limit was passed',
arguments: ['myTable', {offset: 2}],
expectation: "SELECT * FROM myTable OFFSET 2;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable'],
expectation: "SELECT * FROM mySchema.myTable;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {where: {name: "foo';DROP TABLE mySchema.myTable;"}}],
expectation: "SELECT * FROM mySchema.myTable WHERE mySchema.myTable.name='foo'';DROP TABLE mySchema.myTable;';",
context: {options: {quoteIdentifiers: false}}
}
],
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: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.000 +00:00') RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', foo: 1}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1) RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', nullValue: null}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL) RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo', nullValue: null}],
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL) RETURNING *;",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', {name: 'foo', nullValue: null}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;",
context: {options: {omitNull: true}}
}, {
arguments: ['myTable', {name: 'foo', nullValue: undefined}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;",
context: {options: {omitNull: true}}
}, {
arguments: ['mySchema.myTable', {name: 'foo'}],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo') RETURNING *;"
}, {
arguments: ['mySchema.myTable', {name: JSON.stringify({info: 'Look ma a " quote'})}],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}') RETURNING *;"
}, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;') RETURNING *;"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable', {name: 'foo'}],
expectation: "INSERT INTO myTable (name) VALUES ('foo') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}],
expectation: "INSERT INTO myTable (name) VALUES ('foo'';DROP TABLE myTable;') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}],
expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', foo: 1}],
expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1) RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', nullValue: null}],
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL) RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', nullValue: null}],
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL) RETURNING *;",
context: {options: {omitNull: false, quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', nullValue: null}],
expectation: "INSERT INTO myTable (name) VALUES ('foo') RETURNING *;",
context: {options: {omitNull: true, quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', nullValue: undefined}],
expectation: "INSERT INTO myTable (name) VALUES ('foo') RETURNING *;",
context: {options: {omitNull: true, quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {name: 'foo'}],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {name: JSON.stringify({info: 'Look ma a " quote'})}],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}
],
bulkInsertQuery: [
{
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;"
}, {
arguments: ['myTable', [{name: "foo';DROP TABLE myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;'),('bar') RETURNING *;"
}, {
arguments: ['myTable', [{name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {name: 'bar', birthday: moment("2012-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}]],
expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.000 +00:00'),('bar','2012-03-27 10:01:55.000 +00:00') RETURNING *;"
}, {
arguments: ['myTable', [{name: 'foo', foo: 1}, {name: 'bar', foo: 2}]],
expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1),('bar',2) RETURNING *;"
}, {
arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;"
}, {
arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: true}} // Note: We don't honour this because it makes little sense when some rows may have nulls and others not
}, {
arguments: ['myTable', [{name: 'foo', nullValue: undefined}, {name: 'bar', nullValue: undefined}]],
expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: true}} // Note: As above
}, {
arguments: ['mySchema.myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;"
}, {
arguments: ['mySchema.myTable', [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;"
}, {
arguments: ['mySchema.myTable', [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO myTable (name) VALUES ('foo'),('bar') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', [{name: "foo';DROP TABLE myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO myTable (name) VALUES ('foo'';DROP TABLE myTable;'),('bar') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', [{name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {name: 'bar', birthday: moment("2012-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}]],
expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00'),('bar','2012-03-27 10:01:55.000 +00:00') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', [{name: 'foo', foo: 1}, {name: 'bar', foo: 2}]],
expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1),('bar',2) RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {quoteIdentifiers: false, omitNull: false}},
}, {
arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]],
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: true, quoteIdentifiers: false}} // Note: We don't honour this because it makes little sense when some rows may have nulls and others not
}, {
arguments: ['myTable', [{name: 'foo', nullValue: undefined}, {name: 'bar', nullValue: undefined}]],
expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;",
context: {options: {omitNull: true, quoteIdentifiers: false}} // Note: As above
}, {
arguments: ['mySchema.myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'),('bar') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;",
context: {options: {quoteIdentifiers: false}}
}
],
updateQuery: [
{
arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}],
expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2 RETURNING *"
}, {
arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, 2],
expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2 RETURNING *"
}, {
arguments: ['myTable', {bar: 2}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"name\"='foo'';DROP TABLE myTable;' WHERE \"name\"='foo' RETURNING *"
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2,\"nullValue\"=NULL WHERE \"name\"='foo' RETURNING *"
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2,\"nullValue\"=NULL WHERE \"name\"='foo' RETURNING *",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *",
context: {options: {omitNull: true}}
}, {
arguments: ['myTable', {bar: 2, nullValue: undefined}, {name: 'foo'}],
expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *",
context: {options: {omitNull: true}}
}, {
arguments: ['mySchema.myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}],
expectation: "UPDATE \"mySchema\".\"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2 RETURNING *"
}, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'foo'}],
expectation: "UPDATE \"mySchema\".\"myTable\" SET \"name\"='foo'';DROP TABLE mySchema.myTable;' WHERE \"name\"='foo' RETURNING *"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}],
expectation: "UPDATE myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, 2],
expectation: "UPDATE myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {bar: 2}, {name: 'foo'}],
expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}],
expectation: "UPDATE myTable SET name='foo'';DROP TABLE myTable;' WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE myTable SET bar=2,nullValue=NULL WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE myTable SET bar=2,nullValue=NULL WHERE name='foo' RETURNING *",
context: {options: {omitNull: false, quoteIdentifiers: false}},
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *",
context: {options: {omitNull: true, quoteIdentifiers: false}},
}, {
arguments: ['myTable', {bar: 2, nullValue: undefined}, {name: 'foo'}],
expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *",
context: {options: {omitNull: true, quoteIdentifiers: false}},
}, {
arguments: ['mySchema.myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}],
expectation: "UPDATE mySchema.myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'foo'}],
expectation: "UPDATE mySchema.myTable SET name='foo'';DROP TABLE mySchema.myTable;' WHERE name='foo' RETURNING *",
context: {options: {quoteIdentifiers: false}}
}
],
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', undefined, {truncate: true}],
expectation: "TRUNCATE \"myTable\""
}, {
arguments: ['myTable', 1, {limit: 10, truncate: true}],
expectation: "TRUNCATE \"myTable\""
}, {
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)"
}, {
arguments: ['mySchema.myTable', {name: 'foo'}],
expectation: "DELETE FROM \"mySchema\".\"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"mySchema\".\"myTable\" WHERE \"name\"='foo' LIMIT 1)"
}, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}, {limit: 10}],
expectation: "DELETE FROM \"mySchema\".\"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"mySchema\".\"myTable\" WHERE \"name\"='foo'';DROP TABLE mySchema.myTable;' LIMIT 10)"
}, {
arguments: ['myTable', {name: 'foo'}, {limit: null}],
expectation: "DELETE FROM \"myTable\" WHERE \"id\" IN (SELECT \"id\" FROM \"myTable\" WHERE \"name\"='foo')"
},
// Variants when quoteIdentifiers is false
{
arguments: ['myTable', {name: 'foo'}],
expectation: "DELETE FROM myTable WHERE id IN (SELECT id FROM myTable WHERE name='foo' LIMIT 1)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', 1],
expectation: "DELETE FROM myTable WHERE id IN (SELECT id FROM myTable WHERE id=1 LIMIT 1)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', 1, {limit: 10}],
expectation: "DELETE FROM myTable WHERE id IN (SELECT id FROM myTable WHERE id=1 LIMIT 10)",
context: {options: {quoteIdentifiers: false}}
}, {
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)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {name: 'foo'}],
expectation: "DELETE FROM mySchema.myTable WHERE id IN (SELECT id FROM mySchema.myTable WHERE name='foo' LIMIT 1)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.myTable', {name: "foo';DROP TABLE mySchema.myTable;"}, {limit: 10}],
expectation: "DELETE FROM mySchema.myTable WHERE id IN (SELECT id FROM mySchema.myTable WHERE name='foo'';DROP TABLE mySchema.myTable;' LIMIT 10)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['myTable', {name: 'foo'}, {limit: null}],
expectation: "DELETE FROM myTable WHERE id IN (SELECT id FROM myTable WHERE name='foo')",
context: {options: {quoteIdentifiers: false}}
}
],
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\")"
}, {
arguments: ['mySchema.User', ['username', 'isAdmin']],
expectation: 'CREATE INDEX \"user_username_is_admin\" ON \"mySchema\".\"User\" (\"username\", \"isAdmin\")'
},
// Variants when quoteIdentifiers is false
{
arguments: ['User', ['username', 'isAdmin']],
expectation: 'CREATE INDEX user_username_is_admin ON User (username, isAdmin)',
context: {options: {quoteIdentifiers: false}}
}, {
arguments: [
'User', [
{ attribute: 'username', length: 10, order: 'ASC'},
'isAdmin'
]
],
expectation: "CREATE INDEX user_username_is_admin ON User (username(10) ASC, isAdmin)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: [
'User', ['username', 'isAdmin'], { indicesType: 'FULLTEXT', indexName: 'bar'}
],
expectation: "CREATE FULLTEXT INDEX bar ON User (username, isAdmin)",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['mySchema.User', ['username', 'isAdmin']],
expectation: 'CREATE INDEX user_username_is_admin ON mySchema.User (username, isAdmin)',
context: {options: {quoteIdentifiers: false}}
}
],
// 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\""
}, {
arguments: ['User', 'mySchema.user_foo_bar'],
expectation: "DROP INDEX IF EXISTS \"mySchema\".\"user_foo_bar\""
},
// Variants when quoteIdentifiers is false
{
arguments: ['User', 'user_foo_bar'],
expectation: "DROP INDEX IF EXISTS user_foo_bar",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['User', ['foo', 'bar']],
expectation: "DROP INDEX IF EXISTS user_foo_bar",
context: {options: {quoteIdentifiers: false}}
}, {
arguments: ['User', 'mySchema.user_foo_bar'],
expectation: "DROP INDEX IF EXISTS mySchema.user_foo_bar",
context: {options: {quoteIdentifiers: false}}
}
],
hashToWhereConditions: [
{
arguments: [{ id: [1,2,3] }],
expectation: "\"id\" IN (1,2,3)"
},
{
arguments: [{ id: [] }],
expectation: "\"id\" IN (NULL)"
},
// Variants when quoteIdentifiers is false
{
arguments: [{ id: [1,2,3] }],
expectation: "id IN (1,2,3)",
context: {options: {quoteIdentifiers: false}}
},
{
arguments: [{ id: [] }],
expectation: "id IN (NULL)",
context: {options: {quoteIdentifiers: false}}
},
]
}
_.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() {
afterEach(function(done) {
this.sequelize.options.quoteIdentifiers = true
QueryGenerator.options.quoteIdentifiers = true
done()
})
tests.forEach(function(test) {
var title = test.title || 'Postgres correctly returns ' + test.expectation + ' for ' + util.inspect(test.arguments)
it(title, function(done) {
// 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: {}};
QueryGenerator.options = context.options
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation)
done()
})
})
})
})
})
}
\ No newline at end of file
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, _ = require('lodash')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("Promise"), function () {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: { type: DataTypes.STRING },
touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
aNumber: { type: DataTypes.INTEGER },
bNumber: { type: DataTypes.INTEGER },
validateTest: {
type: DataTypes.INTEGER,
allowNull: true,
validate: {isInt: true}
},
validateCustom: {
type: DataTypes.STRING,
allowNull: true,
validate: {len: {msg: 'Length failed.', args: [1, 20]}}
},
dateAllowNullTrue: {
type: DataTypes.DATE,
allowNull: true
}
})
this.User.sync({ force: true }).then(function() { done() })
})
describe('increment', function () {
beforeEach(function(done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
})
it('with array', function(done) {
var self = this
this.User
.find(1)
.then(function(user) {
expect(user.id).to.equal(1)
return user.increment(['aNumber'], 2)
})
.then(function(user) {
// The following assertion would rock hard, but it's not implemented :(
// expect(user.aNumber).to.equal(2)
return self.User.find(1)
})
.then(function(user) {
expect(user.aNumber).to.equal(2)
done()
})
});
it('should still work right with other concurrent updates', function(done) {
var self = this
// Select something
this.User
.find(1)
.then(function (user1) {
// Select the user again (simulating a concurrent query)
return self.User.find(1)
.then(function (user2) {
return user2
.updateAttributes({ aNumber: user2.aNumber + 1 })
.then(function() { return user1.increment(['aNumber'], 2) })
.then(function() { return self.User.find(1) })
.then(function(user5) {
expect(user5.aNumber).to.equal(3)
done()
})
})
})
})
it('with key value pair', function(done) {
var self = this
this.User
.find(1)
.then(function(user1) {
return user1.increment({ 'aNumber': 1, 'bNumber': 2})
})
.then(function () {
return self.User.find(1)
})
.then(function (user3) {
expect(user3.aNumber).to.equal(1)
expect(user3.bNumber).to.equal(2)
done()
})
})
})
describe('decrement', function () {
beforeEach(function (done) {
this.User.create({ id: 1, aNumber: 0, bNumber: 0 }).done(done)
})
it('with array', function(done) {
var self = this
this.User
.find(1)
.then(function(user1) {
return user1.decrement(['aNumber'], 2)
})
.then(function(user2) {
return self.User.find(1)
})
.then(function(user3) {
expect(user3.aNumber).to.equal(-2)
done()
})
})
it('with single field', function(done) {
var self = this
this.User
.find(1)
.then(function(user1) {
return user1.decrement(['aNumber'], 2)
})
.then(function(user3) {
return self.User.find(1)
})
.then(function (user3) {
expect(user3.aNumber).to.equal(-2)
done()
})
})
it('should still work right with other concurrent decrements', function(done) {
var self = this
this.User
.find(1)
.then(function(user1) {
var _done = _.after(3, function() {
self.User
.find(1)
.then(function(user2) {
expect(user2.aNumber).to.equal(-6)
done()
})
})
user1.decrement(['aNumber'], 2).done(_done)
user1.decrement(['aNumber'], 2).done(_done)
user1.decrement(['aNumber'], 2).done(_done)
})
})
})
describe('reload', function () {
it("should return a reference to the same DAO instead of creating a new one", function(done) {
this.User
.create({ username: 'John Doe' })
.then(function(originalUser) {
return originalUser
.updateAttributes({ username: 'Doe John' })
.then(function () {
return originalUser.reload()
})
.then(function(updatedUser) {
expect(originalUser === updatedUser).to.be.true
done()
})
})
})
it("should update the values on all references to the DAO", function(done) {
var self = this
this.User
.create({ username: 'John Doe' })
.then(function(originalUser) {
return self.User
.find(originalUser.id)
.then(function(updater) {
return updater.updateAttributes({ username: 'Doe John' })
})
.then(function () {
// We used a different reference when calling updateAttributes, so originalUser is now out of sync
expect(originalUser.username).to.equal('John Doe')
return originalUser.reload()
}).then(function(updatedUser) {
expect(originalUser.username).to.equal('Doe John')
expect(updatedUser.username).to.equal('Doe John')
done()
})
})
})
it("should update the associations as well", function (done) {
var Book = this.sequelize.define('Book', { title: DataTypes.STRING })
, Page = this.sequelize.define('Page', { content: DataTypes.TEXT })
Book.hasMany(Page)
Page.belongsTo(Book)
Book
.sync({ force: true })
.then(function() {
Page
.sync({ force: true })
.then(function() {
return Book.create({ title: 'A very old book' })
})
.then(function (book) {
return Page
.create({ content: 'om nom nom' })
.then(function(page) {
return book
.setPages([ page ])
.then(function() {
return Book
.find({
where: (dialect === 'postgres' ? '"Books"."id"=' : '`Books`.`id`=') + book.id,
include: [Page]
})
.then(function (leBook) {
return page
.updateAttributes({ content: 'something totally different' })
.then(function (page) {
expect(leBook.pages[0].content).to.equal('om nom nom')
expect(page.content).to.equal('something totally different')
return leBook
.reload()
.then(function (leBook) {
expect(leBook.pages[0].content).to.equal('something totally different')
expect(page.content).to.equal('something totally different')
done()
})
})
})
})
})
}, done)
})
})
})
describe('complete', function () {
it("gets triggered if an error occurs", function(done) {
this.User.find({ where: "asdasdasd" }).then(null, function(err) {
expect(err).to.be.ok
expect(err.message).to.be.ok
done()
})
})
it("gets triggered if everything was ok", function(done) {
this.User.count().then(function(result) {
expect(result).to.not.be.undefined
done()
})
})
})
describe('save', function () {
it('should fail a validation upon creating', function(done) {
this.User.create({aNumber: 0, validateTest: 'hello'}).then(null, function(err) {
expect(err).to.be.ok
expect(err).to.be.an("object")
expect(err.validateTest).to.be.an("array")
expect(err.validateTest[0]).to.be.ok
expect(err.validateTest[0].indexOf('Invalid integer')).to.be.greaterThan(-1)
done()
});
})
it('should fail a validation upon building', function(done) {
this.User.build({aNumber: 0, validateCustom: 'aaaaaaaaaaaaaaaaaaaaaaaaaa'}).save()
.then(null, function(err) {
expect(err).to.be.ok
expect(err).to.be.an("object")
expect(err.validateCustom).to.be.ok
expect(err.validateCustom).to.be.an("array")
expect(err.validateCustom[0]).to.be.ok
expect(err.validateCustom[0]).to.equal('Length failed.')
done()
})
})
it('should fail a validation when updating', function(done) {
this.User.create({aNumber: 0}).then(function (user) {
return user.updateAttributes({validateTest: 'hello'})
}).then(null, function(err) {
expect(err).to.be.ok
expect(err).to.be.an("object")
expect(err.validateTest).to.be.ok
expect(err.validateTest).to.be.an("array")
expect(err.validateTest[0]).to.be.ok
expect(err.validateTest[0].indexOf('Invalid integer:')).to.be.greaterThan(-1)
done()
})
})
})
})
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, QueryChainer = require("../lib/query-chainer")
, CustomEventEmitter = require("../lib/emitters/custom-event-emitter")
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("QueryChainer"), function () {
beforeEach(function(done) {
this.queryChainer = new QueryChainer()
done()
})
describe('add', function() {
it('adds a new serial item if method is passed', function(done) {
expect(this.queryChainer.serials.length).to.equal(0)
this.queryChainer.add({}, 'foo')
expect(this.queryChainer.serials.length).to.equal(1)
done()
})
it('adds a new emitter if no method is passed', function(done) {
expect(this.queryChainer.emitters.length).to.equal(0)
this.queryChainer.add(new CustomEventEmitter())
expect(this.queryChainer.emitters.length).to.equal(1)
done()
})
})
describe('run', function() {
it('finishes when all emitters are finished', function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success') })
var emitter2 = new CustomEventEmitter(function(e) { e.emit('success') })
this.queryChainer.add(emitter1)
this.queryChainer.add(emitter2)
this.queryChainer.run().success(function() {
expect(true).to.be.true
done()
}).error(function(err) {
console.log(err)
})
emitter1.run()
setTimeout(function() { emitter2.run() }, 100)
})
it("returns the result of the passed emitters", function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success', 1) })
this.queryChainer.add(emitter1)
this.queryChainer.run().success(function(results) {
expect(results).to.exist
expect(results).to.have.length(1)
expect(results[0]).to.equal(1)
done()
})
emitter1.run()
})
it("returns the result of the passed emitters in the order of the occurrence of adding the emitters", function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success', 1) })
, emitter2 = new CustomEventEmitter(function(e) { e.emit('success', 2) })
, emitter3 = new CustomEventEmitter(function(e) { e.emit('success', 3) })
this.queryChainer.add(emitter1)
this.queryChainer.add(emitter2)
this.queryChainer.add(emitter3)
this.queryChainer.run().success(function(results) {
expect(results).to.have.length(3)
expect(results).to.include.members([1,2,3])
done()
})
emitter2.run()
emitter1.run()
emitter3.run()
})
it("returns the result as an array and each result as part of the callback signature", function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success', 1) })
, emitter2 = new CustomEventEmitter(function(e) { e.emit('success', 2) })
this.queryChainer.add(emitter1)
this.queryChainer.add(emitter2)
this.queryChainer.run().success(function(results, result1, result2) {
expect(result1).to.exist
expect(result2).to.exist
expect(result1).to.equal(1)
expect(result2).to.equal(2)
done()
})
emitter2.run()
emitter1.run()
})
})
describe('runSerially', function() {
it('finishes when all emitters are finished', function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success') })
var emitter2 = new CustomEventEmitter(function(e) { e.emit('success') })
this.queryChainer.add(emitter1, 'run')
this.queryChainer.add(emitter2, 'run')
this.queryChainer.runSerially().success(function() {
expect(true).to.be.true
done()
})
})
it("returns the result of the passed emitters", function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success', 1) })
this.queryChainer.add(emitter1, 'run')
this.queryChainer.runSerially().success(function(results) {
expect(results).to.exist
expect(results).to.have.length(1)
expect(results[0]).to.equal(1)
done()
})
})
it("returns the result of the passed emitters in the order of the occurrence of adding the emitters", function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success', 1) })
, emitter2 = new CustomEventEmitter(function(e) { setTimeout(function() { e.emit('success', 2) }, 100) })
, emitter3 = new CustomEventEmitter(function(e) { e.emit('success', 3) })
this.queryChainer.add(emitter1, 'run')
this.queryChainer.add(emitter2, 'run')
this.queryChainer.add(emitter3, 'run')
this.queryChainer.runSerially().success(function(results) {
expect(results).to.have.length(3)
expect(results).to.contain.members([1,2,3])
done()
})
})
it("returns the result as an array and each result as part of the callback signature", function(done) {
var emitter1 = new CustomEventEmitter(function(e) { e.emit('success', 1) })
, emitter2 = new CustomEventEmitter(function(e) { e.emit('success', 2) })
this.queryChainer.add(emitter1, 'run')
this.queryChainer.add(emitter2, 'run')
this.queryChainer.runSerially().success(function(results, result1, result2) {
expect(result1).to.exist
expect(result2).to.exist
expect(result1).to.equal(1)
expect(result2).to.equal(2)
done()
})
})
})
})
/* jshint multistr: true */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, _ = require('lodash')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("QueryGenerators"), function () {
describe("comments", function() {
it("should create a comment for a column", function(done) {
var self = this
, User = this.sequelize.define('User', {
username: {type: DataTypes.STRING, comment: 'Some lovely info for my DBA'}
})
User.sync({ force: true }).success(function() {
var sql = ''
if (dialect === "mysql") {
sql = 'SELECT COLUMN_COMMENT as cmt FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = \'' + self.sequelize.config.database + '\' AND TABLE_NAME = \'Users\' AND COLUMN_NAME = \'username\'';
}
else if (dialect === "postgres" || dialect === "postgres-native") {
sql = 'SELECT com.description as cmt FROM pg_attribute a JOIN pg_class pgc ON pgc.oid = a.attrelid \
LEFT JOIN pg_index i ON (pgc.oid = i.indrelid AND i.indkey[0] = a.attnum) \
LEFT JOIN pg_description com on (pgc.oid = com.objoid AND a.attnum = com.objsubid) \
WHERE a.attnum > 0 AND pgc.oid = a.attrelid AND pg_table_is_visible(pgc.oid) \
AND NOT a.attisdropped AND pgc.relname = \'Users\' AND a.attname = \'username\'';
}
else if (dialect === "sqlite") {
// sqlite doesn't support comments except for explicit comments in the file
expect(true).to.be.true
return done()
} else {
console.log('FIXME: This dialect is not supported :(');
expect(true).to.be.true
return done()
}
self.sequelize.query(sql, null, {raw: true}).success(function(result) {
expect(result[0].cmt).to.equal('Some lovely info for my DBA');
done()
})
})
})
})
})
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, _ = require('lodash')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("QueryInterface"), function () {
beforeEach(function(done) {
this.sequelize.options.quoteIdenifiers = true
this.queryInterface = this.sequelize.getQueryInterface()
done()
})
describe('dropAllTables', function() {
it("should drop all tables", function(done) {
var self = this
this.queryInterface.dropAllTables().complete(function(err) {
expect(err).to.be.null
self.queryInterface.showAllTables().complete(function(err, tableNames) {
expect(err).to.be.null
expect(tableNames).to.be.empty
self.queryInterface.createTable('table', { name: DataTypes.STRING }).complete(function(err) {
expect(err).to.be.null
self.queryInterface.showAllTables().complete(function(err, tableNames) {
expect(err).to.be.null
expect(tableNames).to.have.length(1)
self.queryInterface.dropAllTables().complete(function(err) {
expect(err).to.be.null
self.queryInterface.showAllTables().complete(function(err, tableNames) {
expect(err).to.be.null
expect(tableNames).to.be.empty
done()
})
})
})
})
})
})
})
})
describe('indexes', function() {
before(function(done) {
var self = this
this.queryInterface.dropTable('Users').success(function() {
self.queryInterface.createTable('Users', {
username: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN
}).success(function() {
done()
})
})
})
it('adds, reads and removes an index to the table', function(done) {
var self = this
this.queryInterface.addIndex('Users', ['username', 'isAdmin']).complete(function(err) {
expect(err).to.be.null
self.queryInterface.showIndex('Users').complete(function(err, indexes) {
expect(err).to.be.null
var indexColumns = _.uniq(indexes.map(function(index) { return index.name }))
expect(indexColumns).to.include('users_username_is_admin')
self.queryInterface.removeIndex('Users', ['username', 'isAdmin']).complete(function(err) {
expect(err).to.be.null
self.queryInterface.showIndex('Users').complete(function(err, indexes) {
expect(err).to.be.null
indexColumns = _.uniq(indexes.map(function(index) { return index.name }))
expect(indexColumns).to.be.empty
done()
})
})
})
})
})
})
describe('describeTable', function() {
it('reads the metadata of the table', function(done) {
var self = this
var Users = self.sequelize.define('_Users', {
username: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN,
enumVals: DataTypes.ENUM('hello', 'world')
}, { freezeTableName: true })
Users.sync({ force: true }).success(function() {
self.queryInterface.describeTable('_Users').complete(function(err, metadata) {
expect(err).to.be.null
var username = metadata.username
var isAdmin = metadata.isAdmin
var enumVals = metadata.enumVals
expect(username.type).to.equal(dialect === 'postgres' ? 'CHARACTER VARYING' : 'VARCHAR(255)')
expect(username.allowNull).to.be.true
expect(username.defaultValue).to.be.null
expect(isAdmin.type).to.equal(dialect === 'postgres' ? 'BOOLEAN' : 'TINYINT(1)')
expect(isAdmin.allowNull).to.be.true
expect(isAdmin.defaultValue).to.be.null
if (dialect === "postgres" || dialect === "postgres-native") {
expect(enumVals.special).to.be.instanceof(Array)
expect(enumVals.special).to.have.length(2);
}
done()
})
})
})
})
})
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/support')
, DataTypes = require(__dirname + "/../lib/data-types")
, dialect = Support.getTestDialect()
, _ = require('lodash')
, Sequelize = require(__dirname + '/../index')
, config = require(__dirname + "/config/config")
, moment = require('moment')
chai.Assertion.includeStack = true
var qq = function(str) {
if (dialect == 'postgres' || dialect == 'sqlite') {
return '"' + str + '"'
} else if (dialect == 'mysql') {
return '`' + str + '`'
} else {
return str
}
}
describe(Support.getTestDialectTeaser("Sequelize"), function () {
describe('constructor', function() {
it('should pass the global options correctly', function(done) {
var sequelize = Support.createSequelizeInstance({ logging: false, define: { underscored:true } })
, DAO = sequelize.define('dao', {name: DataTypes.STRING})
expect(DAO.options.underscored).to.be.ok
done()
})
it('should correctly set the host and the port', function(done) {
var sequelize = Support.createSequelizeInstance({ host: '127.0.0.1', port: 1234 })
expect(sequelize.config.port).to.equal(1234)
expect(sequelize.config.host).to.equal('127.0.0.1')
done()
})
})
describe('isDefined', function() {
it("returns false if the dao wasn't defined before", function() {
expect(this.sequelize.isDefined('Project')).to.be.false
})
it("returns true if the dao was defined before", function() {
this.sequelize.define('Project', {
name: DataTypes.STRING
})
expect(this.sequelize.isDefined('Project')).to.be.true
})
})
describe('query', function() {
afterEach(function(done) {
this.sequelize.options.quoteIdentifiers = true
done()
})
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING
})
this.insertQuery = "INSERT INTO " + qq(this.User.tableName) + " (username, " + qq("createdAt") + ", " + qq("updatedAt") + ") VALUES ('john', '2012-01-01 10:10:10', '2012-01-01 10:10:10')"
this.User.sync({ force: true }).success(function() {
done()
})
})
it('executes a query the internal way', function(done) {
this.sequelize.query(this.insertQuery, null, { raw: true })
.complete(function(err, result) {
expect(err).to.be.null
expect(result).to.be.null
done()
})
})
it('executes a query if only the sql is passed', function(done) {
this.sequelize.query(this.insertQuery)
.complete(function(err, result) {
expect(err).to.be.null
expect(result).to.not.exist
done()
})
})
it('executes select queries correctly', function(done) {
var self = this
self.sequelize.query(this.insertQuery).success(function() {
self.sequelize
.query("select * from " + qq(self.User.tableName) + "")
.complete(function(err, users) {
expect(err).to.be.null
expect(users.map(function(u){ return u.username })).to.include('john')
done()
})
})
})
it('executes select queries correctly when quoteIdentifiers is false', function(done) {
var self = this
, seq = Object.create(self.sequelize)
seq.options.quoteIdentifiers = false
seq.query(this.insertQuery).success(function() {
seq.query("select * from " + qq(self.User.tableName) + "")
.complete(function(err, users) {
expect(err).to.be.null
expect(users.map(function(u){ return u.username })).to.include('john')
done()
})
})
})
it('executes select query and parses dot notation results', function(done) {
var self = this
self.sequelize.query('DELETE FROM ' + qq(self.User.tableName)).complete(function() {
self.sequelize.query(self.insertQuery).success(function() {
self.sequelize
.query("select username as " + qq("user.username") + " from " + qq(self.User.tableName) + "")
.complete(function(err, users) {
expect(err).to.be.null
expect(users.map(function(u){ return u.user })).to.deep.equal([{'username':'john'}])
done()
})
})
})
})
if (dialect == 'mysql') {
it('executes stored procedures', function(done) {
var self = this
self.sequelize.query(this.insertQuery).success(function() {
self.sequelize.query('DROP PROCEDURE IF EXISTS foo').success(function() {
self.sequelize.query(
"CREATE PROCEDURE foo()\nSELECT * FROM " + self.User.tableName + ";"
).success(function() {
self.sequelize.query('CALL foo()').success(function(users) {
expect(users.map(function(u){ return u.username })).to.include('john')
done()
})
})
})
})
})
} else {
console.log('FIXME: I want to be supported in this dialect as well :-(')
}
it('uses the passed DAOFactory', function(done) {
var self = this
self.sequelize.query(this.insertQuery).success(function() {
self.sequelize.query("SELECT * FROM " + qq(self.User.tableName) + ";", self.User).success(function(users) {
expect(users[0].__factory).to.equal(self.User)
done()
})
})
})
it('destructs dot separated attributes when doing a raw query', function(done) {
var tickChar = (dialect === 'postgres') ? '"' : '`'
, sql = "select 1 as " + Sequelize.Utils.addTicks('foo.bar.baz', tickChar)
this.sequelize.query(sql, null, { raw: true }).success(function(result) {
expect(result).to.deep.equal([ { foo: { bar: { baz: 1 } } } ])
done()
})
})
it('replaces token with the passed array', function(done) {
this.sequelize.query('select ? as foo, ? as bar', null, { raw: true }, [ 1, 2 ]).success(function(result) {
expect(result).to.deep.equal([{ foo: 1, bar: 2 }])
done()
})
})
it('handles AS in conjunction with functions just fine', function(done) {
this.sequelize.query('SELECT ' + (dialect === "sqlite" ? 'date(\'now\')' : 'NOW()') + ' AS t').success(function(result) {
expect(moment(result[0].t).isValid()).to.be.true
done()
})
})
})
describe('define', function() {
it("adds a new dao to the dao manager", function(done) {
expect(this.sequelize.daoFactoryManager.all.length).to.equal(0)
this.sequelize.define('foo', { title: DataTypes.STRING })
expect(this.sequelize.daoFactoryManager.all.length).to.equal(1)
done()
})
it("overwrites global options", function(done) {
var sequelize = Support.createSequelizeInstance({ define: { collate: 'utf8_general_ci' } })
var DAO = sequelize.define('foo', {bar: DataTypes.STRING}, {collate: 'utf8_bin'})
expect(DAO.options.collate).to.equal('utf8_bin')
done()
})
it("inherits global collate option", function(done) {
var sequelize = Support.createSequelizeInstance({ define: { collate: 'utf8_general_ci' } })
var DAO = sequelize.define('foo', {bar: DataTypes.STRING})
expect(DAO.options.collate).to.equal('utf8_general_ci')
done()
})
it("inherits global classMethods and instanceMethods", function(done) {
var sequelize = Support.createSequelizeInstance({
define: {
classMethods : { globalClassMethod : function() {} },
instanceMethods : { globalInstanceMethod : function() {} }
}
})
var DAO = sequelize.define('foo', {bar: DataTypes.STRING}, {
classMethods : { localClassMethod : function() {} }
})
expect(typeof DAO.options.classMethods.globalClassMethod).to.equal('function')
expect(typeof DAO.options.classMethods.localClassMethod).to.equal('function')
expect(typeof DAO.options.instanceMethods.globalInstanceMethod).to.equal('function')
done()
})
it("uses the passed tableName", function(done) {
var self = this
, Photo = this.sequelize.define('Foto', { name: DataTypes.STRING }, { tableName: 'photos' })
Photo.sync({ force: true }).success(function() {
self.sequelize.getQueryInterface().showAllTables().success(function(tableNames) {
expect(tableNames).to.include('photos')
done()
})
})
})
})
describe('sync', function() {
it("synchronizes all daos", function(done) {
var Project = this.sequelize.define('project' + config.rand(), { title: DataTypes.STRING })
var Task = this.sequelize.define('task' + config.rand(), { title: DataTypes.STRING })
Project.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
Project.create({title: 'bla'}).success(function() {
Task.create({title: 'bla'}).success(function(task){
expect(task).to.exist
expect(task.title).to.equal('bla')
done()
})
})
})
})
})
it('works with correct database credentials', function(done) {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
User.sync().success(function() {
expect(true).to.be.true
done()
})
})
it("fails with incorrect database credentials", function(done) {
// sqlite doesn't have a concept of database credentials
if (dialect === "sqlite") {
expect(true).to.be.true
return done()
}
var sequelize2 = Support.getSequelizeInstance('foo', 'bar', null, { logging: false })
, User2 = sequelize2.define('User', { name: DataTypes.STRING, bio: DataTypes.TEXT })
User2.sync().error(function(err) {
if (dialect === "postgres" || dialect === "postgres-native") {
expect(err.message).to.equal('role "bar" does not exist')
} else {
expect(err.message.toString()).to.match(/.*Access\ denied.*/)
}
done()
})
})
})
describe('drop should work', function() {
it('correctly succeeds', function(done) {
var User = this.sequelize.define('Users', {username: DataTypes.STRING })
User.sync({ force: true }).success(function() {
User.drop().success(function() {
expect(true).to.be.true
done()
})
})
})
})
describe('import', function() {
it("imports a dao definition from a file", function(done) {
var Project = this.sequelize.import(__dirname + "/assets/project")
expect(Project).to.exist
done()
})
})
describe('define', function() {
[
{ type: DataTypes.ENUM, values: ['scheduled', 'active', 'finished']},
DataTypes.ENUM('scheduled', 'active', 'finished')
].forEach(function(status) {
describe('enum', function() {
beforeEach(function(done) {
this.Review = this.sequelize.define('review', { status: status })
this.Review.sync({ force: true }).success(function() {
done()
})
})
it('raises an error if no values are defined', function(done) {
var self = this
expect(function() {
self.sequelize.define('omnomnom', {
bla: { type: DataTypes.ENUM }
})
}).to.throw(Error, 'Values for ENUM haven\'t been defined.')
done()
})
it('correctly stores values', function(done) {
this.Review.create({ status: 'active' }).success(function(review) {
expect(review.status).to.equal('active')
done()
})
})
it('correctly loads values', function(done) {
var self = this
this.Review.create({ status: 'active' }).success(function() {
self.Review.findAll().success(function(reviews) {
expect(reviews[0].status).to.equal('active')
done()
})
})
})
it("doesn't save an instance if value is not in the range of enums", function(done) {
var self = this
expect(function() {
self.Review.create({ status: 'fnord' })
}).to.throw(Error, 'Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished')
done()
})
})
})
describe('table', function() {
[
{ id: { type: DataTypes.BIGINT } },
{ id: { type: DataTypes.STRING, allowNull: true } },
{ id: { type: DataTypes.BIGINT, allowNull: false, primaryKey: true, autoIncrement: true } }
].forEach(function(customAttributes) {
it('should be able to override options on the default attributes', function(done) {
var Picture = this.sequelize.define('picture', _.cloneDeep(customAttributes))
Picture.sync({ force: true }).success(function() {
Object.keys(customAttributes).forEach(function(attribute) {
Object.keys(customAttributes[attribute]).forEach(function(option) {
var optionValue = customAttributes[attribute][option];
expect(Picture.rawAttributes[attribute][option]).to.be.equal(optionValue)
})
})
done()
})
})
})
})
})
})
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Support.getTestDialect()
, dbFile = __dirname + '/test.sqlite'
, storages = [dbFile]
chai.Assertion.includeStack = true
if (dialect === 'sqlite') {
describe('[SQLITE Specific] DAOFactory', function() {
after(function(done) {
this.sequelize.options.storage = ':memory:'
done()
})
beforeEach(function(done) {
this.sequelize.options.storage = dbFile
this.User = this.sequelize.define('User', {
age: DataTypes.INTEGER,
name: DataTypes.STRING,
bio: DataTypes.TEXT
})
this.User.sync({ force: true }).success(function() {
done()
})
})
storages.forEach(function(storage) {
describe('with storage "' + storage + '"', function() {
after(function(done) {
if (storage === dbFile) {
require("fs").writeFile(dbFile, '', function() {
done()
})
}
})
describe('create', function() {
it('creates a table entry', function(done) {
var self = this
this.User.create({ age: 21, name: 'John Wayne', bio: 'noot noot' }).success(function(user) {
expect(user.age).to.equal(21)
expect(user.name).to.equal('John Wayne')
expect(user.bio).to.equal('noot noot')
self.User.all().success(function(users) {
var usernames = users.map(function(user) {
return user.name
})
expect(usernames).to.contain('John Wayne')
done()
})
})
})
it('should allow the creation of an object with options as attribute', function(done) {
var Person = this.sequelize.define('Person', {
name: DataTypes.STRING,
options: DataTypes.TEXT
})
Person.sync({ force: true }).success(function() {
var options = JSON.stringify({ foo: 'bar', bar: 'foo' })
Person.create({
name: 'John Doe',
options: options
}).success(function(people) {
expect(people.options).to.deep.equal(options)
done()
})
})
})
it('should allow the creation of an object with a boolean (true) as attribute', function(done) {
var Person = this.sequelize.define('Person', {
name: DataTypes.STRING,
has_swag: DataTypes.BOOLEAN
})
Person.sync({ force: true }).success(function() {
Person.create({
name: 'John Doe',
has_swag: true
}).success(function(people) {
expect(people.has_swag).to.be.ok
done()
})
})
})
it('should allow the creation of an object with a boolean (false) as attribute', function(done) {
var Person = this.sequelize.define('Person', {
name: DataTypes.STRING,
has_swag: DataTypes.BOOLEAN
})
Person.sync({ force: true }).success(function() {
Person.create({
name: 'John Doe',
has_swag: false
}).success(function(people) {
expect(people.has_swag).to.not.be.ok
done()
})
})
})
})
describe('.find', function() {
beforeEach(function(done) {
this.User.create({name: 'user', bio: 'footbar'}).success(function() {
done()
})
})
it("finds normal lookups", function(done) {
this.User.find({ where: { name:'user' } }).success(function(user) {
expect(user.name).to.equal('user')
done()
})
})
it("should make aliased attributes available", function(done) {
this.User.find({ where: { name:'user' }, attributes: ['id', ['name', 'username']] }).success(function(user) {
expect(user.username).to.equal('user')
done()
})
})
})
describe('.all', function() {
beforeEach(function(done) {
this.User.bulkCreate([
{name: 'user', bio: 'foobar'},
{name: 'user', bio: 'foobar'}
]).success(function() {
done()
})
})
it("should return all users", function(done) {
this.User.all().on('success', function(users) {
expect(users).to.have.length(2)
done()
})
})
})
describe('.min', function() {
it("should return the min value", function(done) {
var self = this
, users = []
for (var i = 2; i < 5; i++) {
users[users.length] = {age: i}
}
this.User.bulkCreate(users).success(function() {
self.User.min('age').on('success', function(min) {
expect(min).to.equal(2)
done()
})
})
})
})
describe('.max', function() {
it("should return the max value", function(done) {
var self = this
, users = []
for (var i = 2; i <= 5; i++) {
users[users.length] = {age: i}
}
this.User.bulkCreate(users).success(function() {
self.User.max('age').on('success', function(min) {
expect(min).to.equal(5)
done()
})
})
})
})
})
})
})
}
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Support.getTestDialect()
chai.Assertion.includeStack = true
if (dialect === 'sqlite') {
describe('[SQLITE Specific] DAO', function() {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING
})
this.User.sync({ force: true }).success(function() {
done()
})
})
describe('findAll', function() {
it("handles dates correctly", function(done) {
var self = this
this.User
.create({ username: 'user', createdAt: new Date(2011, 04, 04) })
.success(function() {
self.User.create({ username: 'new user' }).success(function() {
self.User.findAll({
where: ['createdAt > ?', new Date(2012, 01, 01)]
}).success(function(users) {
expect(users).to.have.length(1)
done()
})
})
})
})
})
})
}
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, dialect = Support.getTestDialect()
, util = require("util")
, _ = require('lodash')
, QueryGenerator = require("../../lib/dialects/sqlite/query-generator")
chai.Assertion.includeStack = true
if (dialect === 'sqlite') {
describe('[SQLITE Specific] QueryGenerator', function() {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
username: DataTypes.STRING
})
this.User.sync({ force: true }).success(function() {
done()
})
})
var suites = {
attributesToSQL: [
{
arguments: [{id: 'INTEGER'}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: 'INTEGER', foo: 'VARCHAR(255)'}],
expectation: {id: 'INTEGER', foo: 'VARCHAR(255)'}
},
{
arguments: [{id: {type: 'INTEGER'}}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false}}],
expectation: {id: 'INTEGER NOT NULL'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: true}}],
expectation: {id: 'INTEGER'}
},
{
arguments: [{id: {type: 'INTEGER', primaryKey: true, autoIncrement: true}}],
expectation: {id: 'INTEGER PRIMARY KEY AUTOINCREMENT'}
},
{
arguments: [{id: {type: 'INTEGER', defaultValue: 0}}],
expectation: {id: 'INTEGER DEFAULT 0'}
},
{
arguments: [{id: {type: 'INTEGER', unique: true}}],
expectation: {id: 'INTEGER UNIQUE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', referencesKey: 'pk'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`pk`)'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onDelete: 'CASCADE'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON DELETE CASCADE'}
},
{
arguments: [{id: {type: 'INTEGER', references: 'Bar', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER REFERENCES `Bar` (`id`) ON UPDATE RESTRICT'}
},
{
arguments: [{id: {type: 'INTEGER', allowNull: false, defaultValue: 1, references: 'Bar', onDelete: 'CASCADE', onUpdate: 'RESTRICT'}}],
expectation: {id: 'INTEGER NOT NULL DEFAULT 1 REFERENCES `Bar` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT'}
},
],
createTableQuery: [
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255));"
},
{
arguments: ['myTable', {title: 'ENUM("A", "B", "C")', name: 'VARCHAR(255)'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` ENUM(\"A\", \"B\", \"C\"), `name` VARCHAR(255));"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', id: 'INTEGER PRIMARY KEY'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255), `id` INTEGER PRIMARY KEY);"
},
{
arguments: ['myTable', {title: 'VARCHAR(255)', name: 'VARCHAR(255)', otherId: 'INTEGER REFERENCES `otherTable` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION'}],
expectation: "CREATE TABLE IF NOT EXISTS `myTable` (`title` VARCHAR(255), `name` VARCHAR(255), `otherId` INTEGER REFERENCES `otherTable` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION);"
}
],
insertQuery: [
{
arguments: ['myTable', { name: 'foo' }],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('foo');"
}, {
arguments: ['myTable', { name: "'bar'" }],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('''bar''');"
}, {
arguments: ['myTable', { name: "bar", value: null }],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('bar',NULL);"
}, {
arguments: ['myTable', { name: "bar", value: undefined }],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('bar',NULL);"
}, {
arguments: ['myTable', { name: "foo", value: true }],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',1);"
}, {
arguments: ['myTable', { name: "foo", value: false }],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',0);"
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: null}],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);"
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: null}],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL);",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: null}],
expectation: "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);",
context: {options: {omitNull: true}}
}, {
arguments: ['myTable', {name: 'foo', foo: 1, nullValue: undefined}],
expectation: "INSERT INTO `myTable` (`name`,`foo`) VALUES ('foo',1);",
context: {options: {omitNull: true}}
}
],
bulkInsertQuery: [
{
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('foo'),('bar');"
}, {
arguments: ['myTable', [{name: "'bar'"}, {name: 'foo'}]],
expectation: "INSERT INTO `myTable` (`name`) VALUES ('''bar'''),('foo');"
}, {
arguments: ['myTable', [{name: "bar", value: null}, {name: 'foo', value: 1}]],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('bar',NULL),('foo',1);"
}, {
arguments: ['myTable', [{name: "bar", value: undefined}, {name: 'bar', value: 2}]],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('bar',NULL),('bar',2);"
}, {
arguments: ['myTable', [{name: "foo", value: true}, {name: 'bar', value: false}]],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',1),('bar',0);"
}, {
arguments: ['myTable', [{name: "foo", value: false}, {name: 'bar', value: false}]],
expectation: "INSERT INTO `myTable` (`name`,`value`) VALUES ('foo',0),('bar',0);"
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', foo: 2, nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);"
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', foo: 2, nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', foo: 2, nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);",
context: {options: {omitNull: true}} // Note: We don't honour this because it makes little sense when some rows may have nulls and others not
}, {
arguments: ['myTable', [{name: 'foo', foo: 1, nullValue: null}, {name: 'bar', foo: 2, nullValue: null}]],
expectation: "INSERT INTO `myTable` (`name`,`foo`,`nullValue`) VALUES ('foo',1,NULL),('bar',2,NULL);",
context: {options: {omitNull: true}} // Note: As above
}
],
updateQuery: [
{
arguments: ['myTable', { name: 'foo' }, { id: 2 }],
expectation: "UPDATE `myTable` SET `name`='foo' WHERE `id`=2"
}, {
arguments: ['myTable', { name: "'bar'" }, { id: 2 }],
expectation: "UPDATE `myTable` SET `name`='''bar''' WHERE `id`=2"
}, {
arguments: ['myTable', { name: 'bar', value: null }, { id: 2 }],
expectation: "UPDATE `myTable` SET `name`='bar',`value`=NULL WHERE `id`=2"
}, {
arguments: ['myTable', { name: 'bar', value: undefined }, { id: 2 }],
expectation: "UPDATE `myTable` SET `name`='bar',`value`=NULL WHERE `id`=2"
}, {
arguments: ['myTable', { flag: true }, { id: 2 }],
expectation: "UPDATE `myTable` SET `flag`=1 WHERE `id`=2"
}, {
arguments: ['myTable', { flag: false }, { id: 2 }],
expectation: "UPDATE `myTable` SET `flag`=0 WHERE `id`=2"
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=2,`nullValue`=NULL WHERE `name`='foo'"
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=2,`nullValue`=NULL WHERE `name`='foo'",
context: {options: {omitNull: false}}
}, {
arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}],
expectation: "UPDATE `myTable` SET `bar`=2 WHERE `name`='foo'",
context: {options: {omitNull: true}}
}
],
deleteQuery: [
{
arguments: ['myTable', {name: 'foo'}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo'"
}, {
arguments: ['myTable', 1],
expectation: "DELETE FROM `myTable` WHERE `id`=1"
}, {
arguments: ['myTable', 1, {truncate: true}],
expectation: "DELETE FROM `myTable` WHERE `id`=1"
}, {
arguments: ['myTable', 1, {limit: 10}],
expectation: "DELETE FROM `myTable` WHERE `id`=1"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {limit: 10}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo'';DROP TABLE myTable;'"
}, {
arguments: ['myTable', {name: 'foo'}, {limit: null}],
expectation: "DELETE FROM `myTable` WHERE `name`='foo'"
}
]
}
_.each(suites, function(tests, suiteTitle) {
describe(suiteTitle, function() {
tests.forEach(function(test) {
var title = test.title || 'SQLite correctly returns ' + test.expectation + ' for ' + util.inspect(test.arguments)
it(title, function(done) {
// 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: {}};
QueryGenerator.options = context.options
var conditions = QueryGenerator[suiteTitle].apply(QueryGenerator, test.arguments)
expect(conditions).to.deep.equal(test.expectation)
done()
})
})
})
})
})
}
File mode changed
var fs = require('fs')
, Sequelize = require(__dirname + "/../index")
, DataTypes = require(__dirname + "/../lib/data-types")
, config = require(__dirname + "/config/config")
var Support = {
Sequelize: Sequelize,
initTests: function(options) {
var sequelize = this.createSequelizeInstance(options)
this.clearDatabase(sequelize, function() {
if (options.context) {
options.context.sequelize = sequelize
}
if (options.beforeComplete) {
options.beforeComplete(sequelize, DataTypes)
}
if (options.onComplete) {
options.onComplete(sequelize, DataTypes)
}
})
},
createSequelizeInstance: function(options) {
options = options || {}
options.dialect = options.dialect || 'mysql'
options.logging = (options.hasOwnProperty('logging') ? options.logging : false)
options.pool = options.pool || config.pool
var sequelizeOptions = {
logging: options.logging,
dialect: options.dialect,
port: options.port || process.env.SEQ_PORT || config[options.dialect].port,
pool: options.pool
}
if (!!options.host) {
sequelizeOptions.host = options.host
}
if (!!options.define) {
sequelizeOptions.define = options.define
}
if (process.env.DIALECT === 'postgres-native') {
sequelizeOptions.native = true
}
return this.getSequelizeInstance(
process.env.SEQ_DB || config[options.dialect].database,
process.env.SEQ_USER || process.env.SEQ_USERNAME || config[options.dialect].username,
process.env.SEQ_PW || process.env.SEQ_PASSWORD || config[options.dialect].password,
sequelizeOptions
)
},
getSequelizeInstance: function(db, user, pass, options) {
options = options || {};
options.dialect = options.dialect || this.getTestDialect()
return new Sequelize(db, user, pass, options)
},
clearDatabase: function(sequelize, callback) {
sequelize
.getQueryInterface()
.dropAllTables()
.success(function() {
sequelize.daoFactoryManager.daos = []
callback && callback()
})
.error(function(err) { console.log(err) })
},
getSupportedDialects: function() {
return fs.readdirSync(__dirname + '/../lib/dialects').filter(function(file) {
return ((file.indexOf('.js') === -1) && (file.indexOf('abstract') === -1))
})
},
checkMatchForDialects: function(dialect, value, expectations) {
if (!!expectations[dialect]) {
expect(value).to.match(expectations[dialect])
} else {
throw new Error('Undefined expectation for "' + dialect + '"!')
}
},
getTestDialect: function() {
var envDialect = process.env.DIALECT || 'mysql'
if (envDialect === 'postgres-native') {
envDialect = 'postgres'
}
if (this.getSupportedDialects().indexOf(envDialect) === -1) {
throw new Error('The dialect you have passed is unknown. Did you really mean: ' + envDialect)
}
return envDialect
},
getTestDialectTeaser: function(moduleName) {
var dialect = this.getTestDialect()
if (process.env.DIALECT === 'postgres-native') {
dialect = 'postgres-native'
}
return "[" + dialect.toUpperCase() + "] " + moduleName
}
}
var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() })
before(function(done) {
this.sequelize = sequelize
done()
})
afterEach(function(done) {
Support.clearDatabase(this.sequelize, function() {
done()
})
})
module.exports = Support
var buster = require("buster") var chai = require('chai')
, Utils = require('../lib/utils') , expect = chai.expect
, Helpers = require('./buster-helpers') , Utils = require(__dirname + '/../lib/utils')
, Support = require(__dirname + '/support')
buster.spec.expose() chai.Assertion.includeStack = true
buster.testRunner.timeout = 1000
describe(Helpers.getTestDialectTeaser("Utils"), function() { describe(Support.getTestDialectTeaser("Utils"), function() {
describe('removeCommentsFromFunctionString', function() { describe('removeCommentsFromFunctionString', function() {
it("removes line comments at the start of a line", function(done) { it("removes line comments at the start of a line", function(done) {
var functionWithLineComments = function() { var functionWithLineComments = function() {
// noot noot // noot noot
} }
var result = Utils.removeCommentsFromFunctionString(functionWithLineComments.toString()) var string = functionWithLineComments.toString()
expect(result).not.toMatch(/.*noot.*/) , result = Utils.removeCommentsFromFunctionString(string)
expect(result).not.to.match(/.*noot.*/)
done() done()
}) })
...@@ -22,8 +24,10 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -22,8 +24,10 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
alert(1) // noot noot alert(1) // noot noot
} }
var result = Utils.removeCommentsFromFunctionString(functionWithLineComments.toString()) var string = functionWithLineComments.toString()
expect(result).not.toMatch(/.*noot.*/) , result = Utils.removeCommentsFromFunctionString(string)
expect(result).not.to.match(/.*noot.*/)
done() done()
}) })
...@@ -38,31 +42,32 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -38,31 +42,32 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
}.toString() }.toString()
var result = Utils.removeCommentsFromFunctionString(s) var result = Utils.removeCommentsFromFunctionString(s)
expect(result).not.toMatch(/.*noot.*/)
expect(result).not.toMatch(/.*foo.*/) expect(result).not.to.match(/.*noot.*/)
expect(result).toMatch(/.*alert\(2\).*/) expect(result).not.to.match(/.*foo.*/)
expect(result).to.match(/.*alert\(2\).*/)
done() done()
}) })
}) })
describe('argsArePrimaryKeys', function() { describe('argsArePrimaryKeys', function() {
it("doesn't detect primary keys if primareyKeys and values have different lengths", function(done) { it("doesn't detect primary keys if primareyKeys and values have different lengths", function(done) {
expect(Utils.argsArePrimaryKeys([1,2,3], [1])).toBeFalsy() expect(Utils.argsArePrimaryKeys([1,2,3], [1])).to.be.false
done() done()
}) })
it("doesn't detect primary keys if primary keys are hashes or arrays", function(done) { it("doesn't detect primary keys if primary keys are hashes or arrays", function(done) {
expect(Utils.argsArePrimaryKeys([[]], [1])).toBeFalsy() expect(Utils.argsArePrimaryKeys([[]], [1])).to.be.false
done() done()
}) })
it('detects primary keys if length is correct and data types are matching', function(done) { it('detects primary keys if length is correct and data types are matching', function(done) {
expect(Utils.argsArePrimaryKeys([1,2,3], ["INTEGER", "INTEGER", "INTEGER"])).toBeTruthy() expect(Utils.argsArePrimaryKeys([1,2,3], ["INTEGER", "INTEGER", "INTEGER"])).to.be.true
done() done()
}) })
it("detects primary keys if primary keys are dates and lengths are matching", function(done) { it("detects primary keys if primary keys are dates and lengths are matching", function(done) {
expect(Utils.argsArePrimaryKeys([new Date()], ['foo'])).toBeTruthy() expect(Utils.argsArePrimaryKeys([new Date()], ['foo'])).to.be.true
done() done()
}) })
}) })
...@@ -70,34 +75,34 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -70,34 +75,34 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
describe('underscore', function() { describe('underscore', function() {
describe('underscoredIf', function() { describe('underscoredIf', function() {
it('is defined', function(done) { it('is defined', function(done) {
expect(Utils._.underscoredIf).toBeDefined() expect(Utils._.underscoredIf).to.be.ok
done() done()
}) })
it('underscores if second param is true', function(done) { it('underscores if second param is true', function(done) {
expect(Utils._.underscoredIf('fooBar', true)).toEqual('foo_bar') expect(Utils._.underscoredIf('fooBar', true)).to.equal('foo_bar')
done() done()
}) })
it("doesn't underscore if second param is false", function(done) { it("doesn't underscore if second param is false", function(done) {
expect(Utils._.underscoredIf('fooBar', false)).toEqual('fooBar') expect(Utils._.underscoredIf('fooBar', false)).to.equal('fooBar')
done() done()
}) })
}) })
describe('camelizeIf', function() { describe('camelizeIf', function() {
it('is defined', function(done) { it('is defined', function(done) {
expect(Utils._.camelizeIf).toBeDefined() expect(Utils._.camelizeIf).to.be.ok
done() done()
}) })
it('camelizes if second param is true', function(done) { it('camelizes if second param is true', function(done) {
expect(Utils._.camelizeIf('foo_bar', true)).toEqual('fooBar') expect(Utils._.camelizeIf('foo_bar', true)).to.equal('fooBar')
done() done()
}) })
it("doesn't camelize if second param is false", function(done) { it("doesn't camelize if second param is false", function(done) {
expect(Utils._.underscoredIf('fooBar', true)).toEqual('foo_bar') expect(Utils._.underscoredIf('fooBar', true)).to.equal('foo_bar')
done() done()
}) })
}) })
...@@ -105,12 +110,12 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -105,12 +110,12 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
describe('isHash', function() { describe('isHash', function() {
it('doesn\'t match arrays', function(done) { it('doesn\'t match arrays', function(done) {
expect(Utils.isHash([])).toBeFalsy() expect(Utils.isHash([])).to.be.false
done() done()
}) })
it('doesn\'t match null', function(done) { it('doesn\'t match null', function(done) {
expect(Utils.isHash(null)).toBeFalsy() expect(Utils.isHash(null)).to.be.false
done() done()
}) })
...@@ -121,7 +126,8 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -121,7 +126,8 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
'last': 'Bar' 'last': 'Bar'
} }
} }
expect(Utils.isHash(values)).toBeTruthy()
expect(Utils.isHash(values)).to.be.true
done() done()
}) })
...@@ -133,7 +139,8 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -133,7 +139,8 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
}, },
'length': 1 'length': 1
} }
expect(Utils.isHash(values)).toBeTruthy()
expect(Utils.isHash(values)).to.be.true
done() done()
}) })
}) })
...@@ -141,13 +148,13 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() { ...@@ -141,13 +148,13 @@ describe(Helpers.getTestDialectTeaser("Utils"), function() {
describe('format', function() { describe('format', function() {
it('should format where clause correctly when the value is truthy', function(done) { it('should format where clause correctly when the value is truthy', function(done) {
var where = ['foo = ?', 1] var where = ['foo = ?', 1]
expect(Utils.format(where)).toEqual('foo = 1') expect(Utils.format(where)).to.equal('foo = 1')
done() done()
}) })
it('should format where clause correctly when the value is falsy', function(done) { it('should format where clause correctly when the value is false', function(done) {
var where = ['foo = ?', 0] var where = ['foo = ?', 0]
expect(Utils.format(where)).toEqual('foo = 0') expect(Utils.format(where)).to.equal('foo = 0')
done() done()
}) })
}) })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!