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

Commit 748c9bec by Sascha Depold

Merge branch 'milestones/2.0.0' of github.com:sequelize/sequelize into milestones/2.0.0

2 parents a5862835 cf637c52
......@@ -8,6 +8,8 @@ script:
notifications:
email:
- sascha@depold.com
hipchat:
- 40e8850aaba9854ac4c9963bd33f8b@253477
env:
- DB=mysql DIALECT=mysql
......
......@@ -30,6 +30,9 @@
- [BUG] Fixed BLOB/TEXT columns having a default value declared in MySQL [#793](https://github.com/sequelize/sequelize/pull/793). thanks to durango
- [BUG] You can now use .find() on any single integer primary key when throwing just a number as an argument [#796](https://github.com/sequelize/sequelize/pull/796). thanks to durango
- [BUG] Adding unique to a column for Postgres in the migrator should be fixed [#795](https://github.com/sequelize/sequelize/pull/795). thanks to durango
- [BUG] For MySQL users, if their collation allows case insensitivity then allow enums to be case insensitive as well [#794](https://github.com/sequelize/sequelize/pull/794). thanks to durango
- [BUG] Custom primary key (not keys, just singular) should no longer be a problem for models when using any of the data retrievals with just a number or through associations [#771](https://github.com/sequelize/sequelize/pull/771). thanks to sdephold & durango
- [BUG] Default schemas should now be utilized when describing tables [#812](https://github.com/sequelize/sequelize/pull/812). thanks to durango
- [FEATURE] Validate a model before it gets saved. [#601](https://github.com/sequelize/sequelize/pull/601). thanks to durango
- [FEATURE] Schematics. [#564](https://github.com/sequelize/sequelize/pull/564). thanks to durango
- [FEATURE] Foreign key constraints. [#595](https://github.com/sequelize/sequelize/pull/595). thanks to optilude
......
......@@ -37,15 +37,20 @@ module.exports = (function() {
BelongsTo.prototype.injectGetter = function(obj) {
var self = this
, accessor = Utils._.camelize('get_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language)))
, primaryKeys = Object.keys(self.target.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
obj[accessor] = function(params) {
var id = this[self.identifier]
, where = {}
where[primaryKey] = id
if (!Utils._.isUndefined(params)) {
if (!Utils._.isUndefined(params.where)) {
params.where = Utils._.extend({id:id}, params.where)
params.where = Utils._.extend(where, params.where)
} else {
params.where = {id: id}
params.where = where
}
} else {
params = id
......@@ -62,10 +67,13 @@ module.exports = (function() {
, accessor = Utils._.camelize('set_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language)))
obj[accessor] = function(associatedObject) {
this[self.identifier] = associatedObject ? associatedObject.id : null
var primaryKeys = !!associatedObject && !!associatedObject.daoFactory ? Object.keys(associatedObject.daoFactory.primaryKeys) : []
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
this[self.identifier] = associatedObject ? associatedObject[primaryKey] : null
// passes the changed field to save, so only that field get updated.
return this.save([ self.identifier ])
return this.save([ self.identifier ], {allowNull: [self.identifier]})
}
return this
......
......@@ -10,15 +10,21 @@ module.exports = (function() {
var self = this, _options = options
var customEventEmitter = new Utils.CustomEventEmitter(function() {
var where = {}, options = _options || {};
var where = {}, options = _options || {}
//fully qualify
where[self.__factory.connectorDAO.tableName+"."+self.__factory.identifier] = self.instance.id
var instancePrimaryKeys = Object.keys(self.instance.daoFactory.primaryKeys)
, instancePrimaryKey = instancePrimaryKeys.length > 0 ? instancePrimaryKeys[0] : 'id'
where[self.__factory.connectorDAO.tableName+"."+self.__factory.identifier] = self.instance[instancePrimaryKey]
var primaryKeys = Object.keys(self.__factory.connectorDAO.rawAttributes)
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0]
, foreignPrimary = Object.keys(self.__factory.target.primaryKeys)
foreignPrimary = foreignPrimary.length === 1 ? foreignPrimary[0] : 'id'
where[self.__factory.connectorDAO.tableName+"."+foreignKey] = {join: self.__factory.target.tableName+".id"}
where[self.__factory.connectorDAO.tableName+"."+foreignKey] = {join: self.__factory.target.tableName+"."+foreignPrimary}
if (options.where) {
if (Array.isArray(options.where)) {
......@@ -28,18 +34,11 @@ module.exports = (function() {
options.where = smart
}
} else {
Utils._.each(options.where, function(value, index) {
delete options.where[index];
smart = Utils.smartWhere(value, self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.__factory.target, smart)
smart = Utils.smartWhere([where, options.where], self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.__factory.target, smart, self.__factory.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) {
value = smart
options.where = smart
}
options.where[self.__factory.target.tableName+"."+index] = value;
});
options.where = Utils._.extend(options.where, where)
}
} else {
options.where = where;
......@@ -58,16 +57,17 @@ module.exports = (function() {
var self = this
, chainer = new Utils.QueryChainer()
, association = self.__factory.target.associations[self.__factory.associationAccessor]
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier
, obsoleteAssociations = oldAssociations.filter(function (old) {
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier;
var obsoleteAssociations = oldAssociations.filter(function (old) {
// Return only those old associations that are not found in new
return !Utils._.find(newAssociations, function (obj) {
return obj.id === old.id
return (!!obj[foreignIdentifier] && !!old[foreignIdentifier] ? obj[foreignIdentifier] === old[foreignIdentifier] : obj.id === old.id)
})
})
, unassociatedObjects = newAssociations.filter(function (obj) {
return !Utils._.find(oldAssociations, function (old) {
return obj.id === old.id
return (!!obj[foreignIdentifier] && !!old[foreignIdentifier] ? obj[foreignIdentifier] === old[foreignIdentifier] : obj.id === old.id)
})
})
......@@ -79,7 +79,7 @@ module.exports = (function() {
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0]
var where = {}
where[self.__factory.identifier] = self.instance.id
where[self.__factory.identifier] = self.instance[self.__factory.identifier] || self.instance.id
where[foreignKey] = foreignIds
chainer.add(self.__factory.connectorDAO.destroy(where))
......@@ -88,8 +88,8 @@ module.exports = (function() {
if (unassociatedObjects.length > 0) {
var bulk = unassociatedObjects.map(function(unassociatedObject) {
var attributes = {}
attributes[self.__factory.identifier] = self.instance.id
attributes[foreignIdentifier] = unassociatedObject.id
attributes[self.__factory.identifier] = self.instance[self.__factory.identifier] || self.instance.id
attributes[foreignIdentifier] = unassociatedObject[foreignIdentifier] || unassociatedObject.id
return attributes
})
......@@ -109,8 +109,8 @@ module.exports = (function() {
, association = this.__factory.target.associations[this.__factory.associationAccessor]
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier;
attributes[this.__factory.identifier] = this.instance.id
attributes[foreignIdentifier] = newAssociation.id
attributes[this.__factory.identifier] = this.instance[this.__factory.identifier] || this.instance.id
attributes[foreignIdentifier] = newAssociation[foreignIdentifier] || newAssociation.id
this.__factory.connectorDAO.create(attributes)
.success(function() { emitterProxy.emit('success', newAssociation) })
......
......@@ -7,14 +7,17 @@ module.exports = (function() {
}
HasManySingleLinked.prototype.injectGetter = function(options) {
var where = {}
var self = this
, where = {}
options = options || {}
where[this.__factory.identifier] = this.instance.id
var primaryKey = Object.keys(this.instance.rawAttributes).filter(function(k) { return self.instance.rawAttributes[k].primaryKey === true })
primaryKey = primaryKey.length === 1 ? primaryKey[0] : 'id'
where[this.__factory.identifier] = this.instance[primaryKey]
if (options.where) {
smart = Utils.smartWhere([where, options.where], this.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(this.__factory.target, smart)
smart = Utils.compileSmartWhere.call(this.__factory.target, smart, this.__factory.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) {
options.where = smart
}
......@@ -27,15 +30,17 @@ module.exports = (function() {
HasManySingleLinked.prototype.injectSetter = function(emitter, oldAssociations, newAssociations) {
var self = this
, associationKeys = Object.keys((oldAssociations[0] || newAssociations[0] || {}).daoFactory.primaryKeys || {})
, associationKey = associationKeys.length === 1 ? associationKeys[0] : 'id'
, chainer = new Utils.QueryChainer()
, obsoleteAssociations = oldAssociations.filter(function (old) {
return !Utils._.find(newAssociations, function (obj) {
return obj.id === old.id
return obj[associationKey] === old[associationKey]
})
})
, unassociatedObjects = newAssociations.filter(function (obj) {
return !Utils._.find(oldAssociations, function (old) {
return obj.id === old.id
return obj[associationKey] === old[associationKey]
})
})
, update
......@@ -44,24 +49,38 @@ module.exports = (function() {
// clear the old associations
var obsoleteIds = obsoleteAssociations.map(function(associatedObject) {
associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
return associatedObject.id
return associatedObject[associationKey]
})
update = {}
update[self.__factory.identifier] = null
chainer.add(this.__factory.target.update(update, { id: obsoleteIds }))
var primaryKeys = Object.keys(this.__factory.target.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
, updateWhere = {}
updateWhere[primaryKey] = obsoleteIds
chainer.add(this.__factory.target.update(update, updateWhere, {allowNull: [self.__factory.identifier]}))
}
if (unassociatedObjects.length > 0) {
// For the self.instance
var pkeys = Object.keys(self.instance.daoFactory.primaryKeys)
, pkey = pkeys.length === 1 ? pkeys[0] : 'id'
// For chainer
, primaryKeys = Object.keys(this.__factory.target.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
, updateWhere = {}
// set the new associations
var unassociatedIds = unassociatedObjects.map(function(associatedObject) {
associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
return associatedObject.id
associatedObject[self.__factory.identifier] = self.instance[pkey] || self.instance.id
return associatedObject[associationKey]
})
update = {}
update[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
chainer.add(this.__factory.target.update(update, { id: unassociatedIds }))
update[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance[pkey] || self.instance.id)
updateWhere[primaryKey] = unassociatedIds
chainer.add(this.__factory.target.update(update, updateWhere, {allowNull: [self.__factory.identifier]}))
}
chainer
......@@ -72,7 +91,10 @@ module.exports = (function() {
}
HasManySingleLinked.prototype.injectAdder = function(emitterProxy, newAssociation) {
newAssociation[this.__factory.identifier] = this.instance.id
var primaryKeys = Object.keys(this.instance.daoFactory.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
newAssociation[this.__factory.identifier] = this.instance[primaryKey]
newAssociation.save()
.success(function() { emitterProxy.emit('success', newAssociation) })
......
......@@ -155,8 +155,13 @@ module.exports = (function() {
obj[this.accessors.add] = function(newAssociatedObject) {
var instance = this
, primaryKeys = Object.keys(newAssociatedObject.daoFactory.primaryKeys || {})
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
, where = {}
where[newAssociatedObject.daoFactory.tableName+'.'+primaryKey] = newAssociatedObject[primaryKey]
return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]({ where: { id: newAssociatedObject.id }})
instance[self.accessors.get]({ where: where })
.error(function(err){ emitter.emit('error', err)})
.success(function(currentAssociatedObjects) {
if (currentAssociatedObjects.length === 0) {
......
......@@ -43,8 +43,10 @@ module.exports = (function() {
var self = this
obj[this.accessors.get] = function(params) {
var id = this.id
var primaryKeys = Object.keys(this.daoFactory.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
, where = {}
, id = this[primaryKey] || this.id
where[self.identifier] = id
......@@ -56,8 +58,8 @@ module.exports = (function() {
params = {where: where}
}
smart = Utils.smartWhere([where, params.where || []], self.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.target, smart)
smart = Utils.smartWhere(params.where || [], self.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.target, smart, self.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) {
params.where = smart
}
......@@ -73,13 +75,16 @@ module.exports = (function() {
obj[this.accessors.set] = function(associatedObject) {
var instance = this
, instanceKeys = Object.keys(instance.daoFactory.primaryKeys)
, instanceKey = instanceKeys.length === 1 ? instanceKeys[0] : 'id'
return new Utils.CustomEventEmitter(function(emitter) {
instance[self.accessors.get]().success(function(oldObj) {
if (oldObj) {
oldObj[self.identifier] = null
oldObj.save().success(function() {
oldObj.save([self.identifier], {allowNull: [self.identifier]}).success(function() {
if (associatedObject) {
associatedObject[self.identifier] = instance.id
associatedObject[self.identifier] = instance[instanceKey]
associatedObject
.save()
.success(function() { emitter.emit('success', associatedObject) })
......@@ -90,7 +95,7 @@ module.exports = (function() {
})
} else {
if (associatedObject) {
associatedObject[self.identifier] = instance.id
associatedObject[self.identifier] = instance[instanceKey]
associatedObject
.save()
.success(function() { emitter.emit('success', associatedObject) })
......
......@@ -62,6 +62,9 @@ module.exports = (function() {
get: function() { return this.QueryInterface.QueryGenerator }
})
// inject the node-sql methods to the dao factory in order to
// receive the syntax sugar ...
;(function() {
var instance = sql.define({ name: "dummy", columns: [] })
......@@ -192,7 +195,7 @@ module.exports = (function() {
}
DAOFactory.prototype.drop = function() {
return this.QueryInterface.dropTable(this.tableName)
return this.QueryInterface.dropTable(this.getTableName(this.tableName))
}
DAOFactory.prototype.dropSchema = function(schema) {
......@@ -571,16 +574,16 @@ module.exports = (function() {
* @param {Object} where Options to describe the scope of the search.
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`.
*/
DAOFactory.prototype.update = function(attrValueHash, where) {
DAOFactory.prototype.update = function(attrValueHash, where, options) {
if(this.options.timestamps) {
var attr = this.options.underscored ? 'updated_at' : 'updatedAt'
attrValueHash[attr] = Utils.now()
}
return this.QueryInterface.bulkUpdate(this.tableName, attrValueHash, where)
return this.QueryInterface.bulkUpdate(this.tableName, attrValueHash, where, options)
}
DAOFactory.prototype.describe = function() {
return this.QueryInterface.describeTable(this.tableName)
DAOFactory.prototype.describe = function(schema) {
return this.QueryInterface.describeTable(this.tableName, schema || this.options.schema || undefined)
}
DAOFactory.prototype.dataset = function() {
......
......@@ -96,7 +96,7 @@ module.exports = (function() {
// if an array with field names is passed to save()
// only those fields will be updated
DAO.prototype.save = function(fields) {
DAO.prototype.save = function(fields, options) {
var self = this
, values = fields ? {} : this.dataValues
, updatedAtAttr = this.__options.underscored ? 'updated_at' : 'updatedAt'
......@@ -179,7 +179,7 @@ module.exports = (function() {
this.isDirty = false
var tableName = this.QueryInterface.QueryGenerator.addSchema(this.__factory)
, query = this.QueryInterface.update(this, tableName, values, identifier)
, query = this.QueryInterface.update(this, tableName, values, identifier, options)
query.proxy(emitter)
}
......
......@@ -162,7 +162,7 @@ module.exports = (function() {
return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
},
selectQuery: function(tableName, options) {
selectQuery: function(tableName, options, factory) {
var table = null,
joinQuery = ""
......@@ -204,7 +204,7 @@ module.exports = (function() {
query += joinQuery
if (options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName)
options.where = this.getWhereConditions(options.where, tableName, factory)
query += " WHERE " + options.where
}
......@@ -266,8 +266,8 @@ module.exports = (function() {
return query
},
updateQuery: function(tableName, attrValueHash, where) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var values = []
......@@ -402,14 +402,24 @@ module.exports = (function() {
return Utils._.template(sql)({ tableName: tableName, indexName: indexName })
},
getWhereConditions: function(smth, tableName) {
getWhereConditions: function(smth, tableName, factory) {
var result = null
, where = {}
if (Utils.isHash(smth)) {
smth = Utils.prependTableNameToHash(tableName, smth)
result = this.hashToWhereConditions(smth)
} else if (typeof smth === 'number') {
smth = Utils.prependTableNameToHash(tableName, { id: smth })
var primaryKeys = !!factory ? Object.keys(factory.primaryKeys) : []
if (primaryKeys.length > 0) {
// Since we're just a number, assume only the first key
primaryKeys = primaryKeys[0]
} else {
primaryKeys = 'id'
}
where[primaryKeys] = smth
smth = Utils.prependTableNameToHash(tableName, where)
result = this.hashToWhereConditions(smth)
} else if (typeof smth === "string") {
result = smth
......
......@@ -36,6 +36,8 @@ module.exports = (function() {
ConnectorManager.prototype.endQuery = function() {
var self = this
self.pendingQueries--
if (!self.pooling && self.pendingQueries === 0) {
setTimeout(function() {
self.pendingQueries === 0 && self.disconnect.call(self)
......@@ -46,43 +48,31 @@ module.exports = (function() {
ConnectorManager.prototype.query = function(sql, callee, options) {
var self = this
// we really want pendingQueries to increment as fast as possible...
self.pendingQueries++
return new Utils.CustomEventEmitter(function(emitter) {
self.connect()
.on('error', function(err) {
// zero-out the previous increment
self.pendingQueries--
self.endQuery.call(self)
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) {
self.pendingQueries--
emitter.emit('success', results)
self.endQuery.call(self)
})
.error(function(err) {
self.pendingQueries--
emitter.emit('error', err)
self.endQuery.call(self)
})
.on('sql', function(sql) { emitter.emit('sql', sql) })
return query.run(sql, done)
.success(function(results) { self.endQuery.call(self) })
.error(function(err) { self.endQuery.call(self) })
.proxy(emitter)
})
}).run()
}
ConnectorManager.prototype.connect = function() {
ConnectorManager.prototype.connect = function(callback) {
var self = this
var emitter = new (require('events').EventEmitter)()
// in case database is slow to connect, prevent orphaning the client
if (this.isConnecting) {
if (this.isConnecting && !this.pooling) {
emitter.emit('success')
return emitter
}
......@@ -119,7 +109,7 @@ module.exports = (function() {
self.isConnected = true
self.client = client
emitter.emit('success', done)
});
})
} else {
self.client = null
emitter.emit('success', done)
......@@ -131,8 +121,8 @@ module.exports = (function() {
this.poolIdentifier = this.pg.pools.getOrCreate(this.sequelize.config)
this.poolIdentifier.connect(connectCallback)
} else {
if (this.client !== null) {
connectCallback(null, this.client)
if (!!this.client) {
connectCallback(null, this.client);
} else {
//create one-off client
this.client = new this.pg.Client(uri)
......
......@@ -92,8 +92,9 @@ module.exports = (function() {
dropTableQuery: function(tableName, options) {
options = options || {}
var query = "DROP TABLE IF EXISTS <%= table %><%= cascade %>;"
var query = "DROP TABLE IF EXISTS <%= schema %><%= table %><%= cascade %>;"
return Utils._.template(query)({
schema: options.schema ? this.quoteIdentifiers(options.schema) + '.' : '',
table: this.quoteIdentifiers(tableName),
cascade: options.cascade? " CASCADE" : ""
})
......@@ -111,10 +112,16 @@ module.exports = (function() {
return "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"
},
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 %>;'
describeTableQuery: function(tableName, schema) {
if (!schema) {
schema = 'public';
}
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 %> AND table_schema = <%= schema %>'
return Utils._.template(query)({
table: this.escape(tableName)
table: this.escape(tableName),
schema: this.escape(schema)
})
},
......@@ -226,7 +233,7 @@ module.exports = (function() {
})
},
selectQuery: function(tableName, options) {
selectQuery: function(tableName, options, factory) {
var query = "SELECT <%= attributes %> FROM <%= table %>",
table = null
......@@ -267,7 +274,7 @@ module.exports = (function() {
}
if(options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName)
options.where = this.getWhereConditions(options.where, tableName, factory)
query += " WHERE <%= where %>"
}
......@@ -354,8 +361,8 @@ module.exports = (function() {
return Utils._.template(query)(replacements)
},
updateQuery: function(tableName, attrValueHash, where) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %> RETURNING *"
, values = []
......@@ -492,18 +499,26 @@ module.exports = (function() {
})
},
getWhereConditions: function(smth, tableName) {
getWhereConditions: function(smth, tableName, factory) {
var result = null
, where = {}
if (Utils.isHash(smth)) {
smth = Utils.prependTableNameToHash(tableName, smth)
result = this.hashToWhereConditions(smth)
} else if (typeof smth === 'number') {
var primaryKeys = !!factory ? Object.keys(factory.primaryKeys) : []
if (primaryKeys.length > 0) {
// Since we're just a number, assume only the first key
primaryKeys = primaryKeys[0]
} else {
primaryKeys = 'id'
}
else if (typeof smth === "number") {
smth = Utils.prependTableNameToHash(tableName, { id: smth })
where[primaryKeys] = smth
smth = Utils.prependTableNameToHash(tableName, where)
result = this.hashToWhereConditions(smth)
}
else if (typeof smth === "string") {
} else if (typeof smth === "string") {
result = smth
}
else if (Array.isArray(smth)) {
......
......@@ -101,7 +101,7 @@ module.exports = (function() {
result[_result.Field].defaultValue = result[_result.Field].defaultValue.replace(/'/g, "")
if (result[_result.Field].defaultValue.indexOf('::') > -1) {
var split = result[_result.Field].defaultValue.split('::');
var split = result[_result.Field].defaultValue.split('::')
if (split[1].toLowerCase() !== "regclass)") {
result[_result.Field].defaultValue = split[0]
}
......
......@@ -16,7 +16,7 @@ module.exports = (function() {
addSchema: function(opts) {
var tableName = undefined
var schema = (!!opts && !!opts.options && !!opts.options.schema ? opts.options.schema : undefined)
var schemaPrefix = (!!opts && !!opts.options && !!opts.options.schemaPrefix ? opts.options.schemaPrefix : undefined)
var schemaDelimiter = (!!opts && !!opts.options && !!opts.options.schemaDelimiter ? opts.options.schemaDelimiter : undefined)
if (!!opts && !!opts.tableName) {
tableName = opts.tableName
......@@ -29,7 +29,7 @@ module.exports = (function() {
return tableName
}
return this.quoteIdentifier(schema) + (!schemaPrefix ? '.' : schemaPrefix) + this.quoteIdentifier(tableName)
return this.quoteIdentifier(schema) + (!schemaDelimiter ? '.' : schemaDelimiter) + this.quoteIdentifier(tableName)
},
createSchema: function() {
......@@ -144,7 +144,7 @@ module.exports = (function() {
return Utils._.template(query)(replacements)
},
selectQuery: function(tableName, options) {
selectQuery: function(tableName, options, factory) {
var table = null,
joinQuery = ""
......@@ -186,7 +186,7 @@ module.exports = (function() {
query += joinQuery
if (options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName)
options.where = this.getWhereConditions(options.where, tableName, factory)
query += " WHERE " + options.where
}
......@@ -218,8 +218,8 @@ module.exports = (function() {
return query
},
updateQuery: function(tableName, attrValueHash, where) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
, values = []
......@@ -398,9 +398,13 @@ module.exports = (function() {
return Utils._.template(sql, { tableName: tableName, indexName: indexName })
},
describeTableQuery: function(tableName) {
describeTableQuery: function(tableName, schema, schemaDelimiter) {
var options = {}
options.schema = schema || null
options.schemaDelimiter = schemaDelimiter || null
var sql = "PRAGMA TABLE_INFO('<%= tableName %>');"
return Utils._.template(sql, { tableName: tableName })
return Utils._.template(sql, { tableName: this.addSchema({tableName: tableName, options: options})})
},
renameTableQuery: function(before, after) {
......
......@@ -125,15 +125,15 @@ module.exports = (function() {
this.finished = true
if (this.emitters.length > 0) {
this.finished = (this.finishedEmits == this.emitters.length)
this.finished = (this.finishedEmits === this.emitters.length)
}
else if (this.serials.length > 0) {
this.finished = (this.finishedEmits == this.serials.length)
this.finished = (this.finishedEmits === this.serials.length)
}
if (this.finished && this.wasRunning) {
var status = (this.fails.length == 0 ? 'success' : 'error')
, result = (this.fails.length == 0 ? this[resultsName] : this.fails)
var status = (this.fails.length === 0 ? 'success' : 'error')
, result = (this.fails.length === 0 ? this[resultsName] : this.fails)
this.eventEmitter.emit.apply(this.eventEmitter, [status, result].concat(result))
}
......
......@@ -91,7 +91,6 @@ module.exports = (function() {
var chainer = new Utils.QueryChainer()
self.showAllTables().success(function(tableNames) {
chainer.add(self, 'disableForeignKeyConstraints', [])
tableNames.forEach(function(tableName) {
......@@ -110,6 +109,7 @@ module.exports = (function() {
self.emit('dropAllTables', err)
emitter.emit('error', err)
})
}).error(function(err) {
self.emit('dropAllTables', err)
emitter.emit('error', err)
......@@ -137,22 +137,34 @@ module.exports = (function() {
}).run()
}
QueryInterface.prototype.describeTable = function(tableName) {
QueryInterface.prototype.describeTable = function(tableName, options) {
var self = this
, schema = null
, schemaDelimiter = null
if (typeof options === "string") {
schema = options
}
else if (typeof options === "object") {
schema = options.schema || null
schemaDelimiter = options.schemaDelimiter || null
}
return new Utils.CustomEventEmitter(function(emitter) {
var sql;
if (self.QueryGenerator.describeTableQuery) {
sql = self.QueryGenerator.describeTableQuery(tableName)
sql = self.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter)
} else {
sql = 'DESCRIBE `' + tableName + '`;'
sql = 'DESCRIBE ' + self.QueryGenerator.addSchema({tableName: tableName, options: {schema: schema, schemaDelimiter: schemaDelimiter}}) + ';'
}
self.sequelize.query(sql, null, { raw: true }).success(function(data) {
emitter.emit('success', data)
}).error(function(err) {
emitter.emit('error', err)
}).on('sql', function(sql) {
emitter.emit('sql', sql)
})
}).run()
}
......@@ -265,10 +277,10 @@ module.exports = (function() {
return queryAndEmit.call(this, sql, 'bulkInsert')
}
QueryInterface.prototype.update = function(dao, tableName, values, identifier) {
QueryInterface.prototype.update = function(dao, tableName, values, identifier, options) {
var self = this
, restrict = false
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier)
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options)
// Check for a restrict field
if (!!dao.daoFactory && !!dao.daoFactory.associations) {
......@@ -305,9 +317,9 @@ module.exports = (function() {
}).run()
}
QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier) {
QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier, options) {
var self = this
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier)
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options)
return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer()
......@@ -393,7 +405,7 @@ module.exports = (function() {
QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) {
options = options || {}
var sql = this.QueryGenerator.selectQuery(tableName, options)
var sql = this.QueryGenerator.selectQuery(tableName, options, factory)
queryOptions = Utils._.extend({}, queryOptions, { include: options.include })
return queryAndEmit.call(this, [sql, factory, queryOptions], 'select')
}
......
......@@ -191,7 +191,6 @@ var Utils = module.exports = {
break
default: // lazy
text = text.concat(obj[column].lazy.conditions.map(function(val){ return columnName + ' ' + val }))
obj[column].lazy.bindings = obj[column].lazy.bindings.map(function(v) { return SqlString.escape(v, false, null, dialect) })
whereArgs = whereArgs.concat(obj[column].lazy.bindings)
}
})
......@@ -320,15 +319,18 @@ var Utils = module.exports = {
return hash
},
removeNullValuesFromHash: function(hash, omitNull) {
removeNullValuesFromHash: function(hash, omitNull, options) {
var result = hash
options = options || {}
options.allowNull = options.allowNull || []
if (omitNull) {
var _hash = {}
Utils._.each(hash, function(val, key) {
if (key.match(/Id$/) || ((val !== null) && (val !== undefined))) {
_hash[key] = val;
if (options.allowNull.indexOf(key) > -1 || key.match(/Id$/) || ((val !== null) && (val !== undefined))) {
_hash[key] = val
}
})
......
......@@ -39,7 +39,7 @@
"lodash": "~1.3.1",
"underscore.string": "~2.3.0",
"lingo": "~0.0.5",
"validator": "~1.3.0",
"validator": "~1.4.0",
"moment": "~2.1.0",
"commander": "~2.0.0",
"dottie": "0.0.8-0",
......@@ -51,8 +51,7 @@
"devDependencies": {
"sqlite3": "~2.1.12",
"mysql": "~2.0.0-alpha8",
"pg": "~2.2.0",
"buster": "~0.6.3",
"pg": "~2.3.1",
"watchr": "~2.4.3",
"yuidocjs": "~0.3.36",
"chai": "~1.7.2",
......
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("BelongsTo"), function() {
describe('setAssociation', function() {
it('can set the association with declared primary keys...', function(done) {
var User = this.sequelize.define('UserXYZ', { user_id: {type: DataTypes.INTEGER, primaryKey: true }, username: DataTypes.STRING })
, Task = this.sequelize.define('TaskXYZ', { task_id: {type: DataTypes.INTEGER, primaryKey: true }, title: DataTypes.STRING })
Task.belongsTo(User, { foreignKey: 'user_id' })
this.sequelize.sync({ force: true }).success(function() {
User.create({ user_id: 1, username: 'foo' }).success(function(user) {
Task.create({ task_id: 1, title: 'task' }).success(function(task) {
task.setUserXYZ(user).success(function() {
task.getUserXYZ().success(function(user) {
expect(user).not.to.be.null
task.setUserXYZ(null).success(function() {
task.getUserXYZ().success(function(user) {
expect(user).to.be.null
done()
})
})
})
})
})
})
})
})
it('clears the association if null is passed', function(done) {
var User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, Task = this.sequelize.define('TaskXYZ', { title: DataTypes.STRING })
Task.belongsTo(User)
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
task.setUserXYZ(user).success(function() {
task.getUserXYZ().success(function(user) {
expect(user).not.to.be.null
task.setUserXYZ(null).success(function() {
task.getUserXYZ().success(function(user) {
expect(user).to.be.null
done()
})
})
})
})
})
})
})
})
})
describe("Foreign key constraints", function() {
it("are not enabled by default", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User)
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
})
})
})
it("can cascade deletes", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User, {onDelete: 'cascade'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(0)
done()
})
})
})
})
})
})
})
it("can restrict deletes", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User, {onDelete: 'restrict'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() {
user.destroy().error(function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
})
})
})
it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User, {onUpdate: 'cascade'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).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).to.have.length(1)
expect(tasks[0].UserId).to.equal(999)
done()
})
})
})
})
})
})
})
it("can restrict updates", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.STRING })
Task.belongsTo(User, {onUpdate: 'restrict'})
this.sequelize.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).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).to.have.length(1)
done()
})
})
})
})
})
})
})
})
describe("Association options", function() {
it('can specify data type for autogenerated relational keys', function(done) {
var User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, dataTypes = [DataTypes.INTEGER, DataTypes.BIGINT, DataTypes.STRING]
, self = this
, Tasks = {}
dataTypes.forEach(function(dataType) {
var tableName = 'TaskXYZ_' + dataType.toString()
Tasks[dataType] = self.sequelize.define(tableName, { title: DataTypes.STRING })
Tasks[dataType].belongsTo(User, { foreignKey: 'userId', keyType: dataType })
})
self.sequelize.sync({ force: true })
.success(function() {
dataTypes.forEach(function(dataType, i) {
expect(Tasks[dataType].rawAttributes.userId.type.toString())
.to.equal(dataType.toString())
if ((i+1) === dataTypes.length) {
done()
}
})
})
})
})
})
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + "/../../lib/data-types")
, Sequelize = require('../../index')
, _ = require('lodash')
, moment = require('moment')
, sinon = require('sinon')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("HasMany"), function() {
describe('(1:N)', function() {
describe('hasSingle', function() {
beforeEach(function(done) {
var self = this
this.Article = this.sequelize.define('Article', {
'title': DataTypes.STRING
})
this.Label = this.sequelize.define('Label', {
'text': DataTypes.STRING
})
this.Article.hasMany(this.Label)
this.Label.sync({ force: true }).success(function() {
self.Article.sync({ force: true }).success(function() {
done()
})
})
})
it('does not have any labels assigned to it initially', function(done) {
var chainer = new Sequelize.Utils.QueryChainer([
this.Article.create({ title: 'Articl2e' }),
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
])
chainer.run().success(function(results, article, label1, label2) {
var chainer = new Sequelize.Utils.QueryChainer([
article.hasLabel(label1),
article.hasLabel(label2)
])
chainer.run().success(function(_, hasLabel1, hasLabel2) {
expect(hasLabel1).to.be.false
expect(hasLabel2).to.be.false
done()
})
})
})
it('answers true if the label has been assigned', function(done) {
var chainer = new Sequelize.Utils.QueryChainer([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
])
chainer.run().success(function(results, article, label1, label2) {
var chainer = new Sequelize.Utils.QueryChainer([
[ article, 'addLabel', [ label1 ]],
[ article, 'hasLabel', [ label1 ]],
[ article, 'hasLabel', [ label2 ]]
])
chainer.runSerially()
.success(function(_, label1, hasLabel1, hasLabel2) {
expect(hasLabel1).to.be.true
expect(hasLabel2).to.be.false
done()
})
})
})
})
describe('hasAll', function() {
beforeEach(function(done) {
var self = this
this.Article = this.sequelize.define('Article', {
'title': DataTypes.STRING
})
this.Label = this.sequelize.define('Label', {
'text': DataTypes.STRING
})
this.Article.hasMany(this.Label)
this.Label.sync({ force: true }).success(function() {
self.Article.sync({ force: true }).success(function() {
done()
})
})
})
it('answers false if only some labels have been assigned', function(done) {
var chainer = new Sequelize.Utils.QueryChainer([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
])
chainer.run().success(function(results, article, label1, label2) {
article.addLabel(label1).success(function() {
article.hasLabels([label1, label2]).success(function(result) {
expect(result).to.be.false
done()
})
})
})
})
it('answers true if all label have been assigned', function(done) {
var chainer = new Sequelize.Utils.QueryChainer([
this.Article.create({ title: 'Article' }),
this.Label.create({ text: 'Awesomeness' }),
this.Label.create({ text: 'Epicness' })
])
chainer.run().success(function(results, article, label1, label2) {
article.setLabels([label1, label2]).success(function() {
article.hasLabels([label1, label2]).success(function(result) {
expect(result).to.be.true
done()
})
})
})
})
})
describe('setAssociations', function() {
it("clears associations when passing null to the set-method", function(done) {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, Task = this.sequelize.define('Task', { title: DataTypes.STRING })
Task.hasMany(User)
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) {
task.setUsers([ user ]).success(function() {
task.getUsers().success(function(_users) {
expect(_users).to.have.length(1)
task.setUsers(null).success(function() {
task.getUsers().success(function(_users) {
expect(_users).to.have.length(0)
done()
})
})
})
})
})
})
})
})
})
})
it("clears associations when passing null to the set-method with omitNull set to true", function(done) {
this.sequelize.options.omitNull = true
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, Task = this.sequelize.define('Task', { title: DataTypes.STRING })
Task.hasMany(User)
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) {
task.setUsers([ user ]).success(function() {
task.getUsers().success(function(_users) {
expect(_users).to.have.length(1)
task.setUsers(null).success(function() {
task.getUsers().success(function(_users) {
expect(_users).to.have.length(0)
done()
})
})
})
})
})
})
})
})
})
describe("getting assocations with options", function() {
beforeEach(function(done) {
var self = this
this.User = this.sequelize.define('User', { username: DataTypes.STRING })
this.Task = this.sequelize.define('Task', { title: DataTypes.STRING, active: DataTypes.BOOLEAN })
this.User.hasMany(self.Task)
this.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
var chainer = new Sequelize.Utils.QueryChainer([
self.User.create({ username: 'John'}),
self.Task.create({ title: 'Get rich', active: true}),
self.Task.create({ title: 'Die trying', active: false})
])
chainer.run().success(function (results, john, task1, task2) {
john.setTasks([task1, task2]).success(function() {
done()
})
})
})
})
})
it('should treat the where object of associations as a first class citizen', function(done) {
var self = this
this.Article = this.sequelize.define('Article', {
'title': DataTypes.STRING
})
this.Label = this.sequelize.define('Label', {
'text': DataTypes.STRING,
'until': DataTypes.DATE
})
this.Article.hasMany(this.Label)
this.Label.sync({ force: true }).success(function() {
self.Article.sync({ force: true }).success(function() {
var chainer = new Sequelize.Utils.QueryChainer([
self.Article.create({ title: 'Article' }),
self.Label.create({ text: 'Awesomeness', until: '2014-01-01 01:00:00' }),
self.Label.create({ text: 'Epicness', until: '2014-01-03 01:00:00' })
])
chainer.run().success(function(results, article, label1, label2) {
article.setLabels([label1, label2]).success(function() {
article.getLabels({where: ['until > ?', moment('2014-01-02').toDate()]}).success(function(labels) {
expect(labels).to.be.instanceof(Array)
expect(labels).to.have.length(1)
expect(labels[0].text).to.equal('Epicness')
done()
})
})
})
})
})
})
it("gets all associated objects when no options are passed", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) {
john.getTasks().success(function (tasks) {
expect(tasks).to.have.length(2)
done()
})
})
})
it("only get objects that fulfill the options", function(done) {
this.User.find({ where: { username: 'John' } }).success(function (john) {
john.getTasks({ where: { active: true }, limit: 10, order: 'id DESC' }).success(function (tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
describe('optimizations using bulk create, destroy and update', function () {
beforeEach(function (done) {
var self = this
this.User = this.sequelize.define('User', { username: DataTypes.STRING }, {timestamps: false})
this.Task = this.sequelize.define('Task', { title: DataTypes.STRING }, {timestamps: false})
this.User.hasMany(this.Task)
this.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
done()
})
})
})
it('uses one UPDATE statement', function (done) {
var self = this
, spy = sinon.spy()
this.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task1' }).success(function(task1) {
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
expect(sql).to.have.string("UPDATE")
expect(sql).to.have.string("IN (1,2)")
})).success(function () {
expect(spy.calledTwice).to.be.ok // Once for SELECT, once for UPDATE
done()
})
})
})
})
})
it('uses one UPDATE statement', function (done) {
var self = this
, spy = sinon.spy()
this.User.create({ username: 'foo' }).success(function (user) {
self.Task.create({ title: 'task1' }).success(function (task1) {
self.Task.create({ title: 'task2' }).success(function (task2) {
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
expect(sql).to.have.string("UPDATE")
expect(sql).to.have.string("IN (1,2)")
})).success(function () {
expect(spy.calledTwice).to.be.ok // Once for SELECT, once for UPDATE
done()
})
})
})
})
})
})
}) // end optimization using bulk create, destroy and update
})
describe('(N:M)', function() {
describe("getting assocations with options", function() {
beforeEach(function(done) {
var self = this
this.User = this.sequelize.define('User', { username: DataTypes.STRING })
this.Task = this.sequelize.define('Task', { title: DataTypes.STRING, active: DataTypes.BOOLEAN })
self.User.hasMany(self.Task)
self.Task.hasMany(self.User)
this.User.sync({ force: true }).success(function() {
self.Task.sync({ force: true }).success(function() {
var chainer = new Sequelize.Utils.QueryChainer([
self.User.create({ username: 'John'}),
self.Task.create({ title: 'Get rich', active: true}),
self.Task.create({ title: 'Die trying', active: false})
])
chainer.run().success(function (results, john, task1, task2) {
john.setTasks([task1, task2]).success(function() {
done()
})
})
})
})
})
it("gets all associated objects when no options are passed", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) {
john.getTasks().success(function (tasks) {
expect(tasks).to.have.length(2)
done()
})
})
})
it("only get objects that fulfill the options", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) {
john.getTasks({where: {active: true}}).success(function (tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
it("only gets objects that fulfill options with a formatted value", function(done) {
this.User.find({where: {username: 'John'}}).success(function (john) {
john.getTasks({where: ['active = ?', true]}).success(function (tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
it("removes the reference id, which was added in the first place", function(done) {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, Task = this.sequelize.define('Task', { title: DataTypes.STRING })
User.hasMany(Task)
expect(Task.attributes.UserId).to.exist
Task.hasMany(User)
expect(Task.attributes.UserId).not.to.exist
done()
})
describe('setAssociations', function() {
it("clears associations when passing null to the set-method", function(done) {
var User = this.sequelize.define('User', { username: DataTypes.STRING })
, Task = this.sequelize.define('Task', { title: DataTypes.STRING })
User.hasMany(Task)
Task.hasMany(User)
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) {
task.setUsers([ user ]).success(function() {
task.getUsers().success(function(_users) {
expect(_users).to.have.length(1)
task.setUsers(null).success(function() {
task.getUsers().success(function(_users) {
expect(_users).to.have.length(0)
done()
})
})
})
})
})
})
})
})
})
it("joins an association with custom primary keys", function(done) {
var Group = this.sequelize.define('group', {
group_id: {type: DataTypes.INTEGER, primaryKey: true},
name: DataTypes.STRING(64)
})
, Member = this.sequelize.define('member', {
member_id: {type: DataTypes.INTEGER, primaryKey: true},
email: DataTypes.STRING(64)
})
Group.hasMany(Member, {joinTableName: 'group_members', foreignKey: 'group_id'})
Member.hasMany(Group, {joinTableName: 'group_members', foreignKey: 'member_id'})
Group.sync({ force: true }).success(function() {
Member.sync({ force: true }).success(function() {
Group.create({group_id: 1, name: 'Group1'}).success(function(){
Member.create({member_id: 10, email: 'team@sequelizejs.com'}).success(function() {
Group.find(1).success(function(group) {
Member.find(10).success(function(member) {
group.addMember(member).success(function() {
group.getMembers().success(function(members) {
expect(members).to.be.instanceof(Array)
expect(members).to.have.length(1)
expect(members[0].member_id).to.equal(10)
expect(members[0].email).to.equal('team@sequelizejs.com')
done()
})
})
})
})
})
})
})
})
})
})
describe('optimizations using bulk create, destroy and update', function () {
beforeEach(function (done) {
var self = this
this.User = this.sequelize.define('User', { username: DataTypes.STRING }, {timestamps: false})
this.Task = this.sequelize.define('Task', { title: DataTypes.STRING }, {timestamps: false})
this.User.hasMany(this.Task)
this.Task.hasMany(this.User)
this.User.sync({ force: true }).success(function() {
self.Task.sync({force: true}).success(function() {
done()
})
})
})
it('uses one insert into statement', function (done) {
var self = this
, spy = sinon.spy()
this.User.create({ username: 'foo' }).success(function(user) {
self.Task.create({ title: 'task1' }).success(function(task1) {
self.Task.create({ title: 'task2' }).success(function(task2) {
user.setTasks([task1, task2]).on('sql', spy).on('sql', _.after(2, function (sql) {
expect(sql).to.have.string("INSERT INTO")
expect(sql).to.have.string("VALUES (1,1),(2,1)")
})).success(function () {
expect(spy.calledTwice).to.be.ok
done()
})
})
})
})
})
it('uses one delete from statement', function (done) {
var self = this
, spy = sinon.spy()
this.User.create({ username: 'foo' }).success(function (user) {
self.Task.create({ title: 'task1' }).success(function (task1) {
self.Task.create({ title: 'task2' }).success(function (task2) {
user.setTasks([task1, task2]).success(function () {
user.setTasks(null).on('sql', spy).on('sql', _.after(2, function (sql) {
expect(sql).to.have.string("DELETE FROM")
expect(sql).to.have.string("IN (1,2)")
})).success(function () {
expect(spy.calledTwice).to.be.ok // Once for SELECT, once for DELETE
done()
})
})
})
})
})
})
}) // end optimization using bulk create, destroy and update
describe('join table creation', function () {
beforeEach(function (done) {
var self = this
this.User = this.sequelize.define('User',
{ username: DataTypes.STRING },
{ tableName: 'users'}
)
this.Task = this.sequelize.define('Task',
{ title: DataTypes.STRING },
{ tableName: 'tasks' }
)
this.User.hasMany(this.Task,
{ joinTableName: 'user_has_tasks' }
)
this.Task.hasMany(this.User)
this.User.sync({ force: true }).success(function() {
self.Task.sync({force: true}).success(function() {
done()
})
})
})
it('uses the specified joinTableName or a reasonable default', function(done) {
for (var associationName in this.User.associations) {
expect(associationName).not.to.equal(this.User.tableName)
expect(associationName).not.to.equal(this.Task.tableName)
var joinTableName = this.User.associations[associationName].options.joinTableName
if (typeof joinTableName !== 'undefined') {
expect(joinTableName).to.equal(associationName)
}
var tableName = this.User.associations[associationName].options.tableName
if (typeof tableName !== 'undefined') {
expect(tableName).to.equal(associationName)
}
}
done()
})
})
})
describe("Foreign key constraints", function() {
it("are not enabled by default", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { username: DataTypes.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.setTasks([task]).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
})
})
})
})
it("can cascade deletes", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { 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.setTasks([task]).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(0)
done()
})
})
})
})
})
})
})
})
it("can restrict deletes", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { 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.setTasks([task]).success(function() {
user.destroy().error(function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1)
done()
})
})
})
})
})
})
})
})
it("can cascade updates", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { 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.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).to.have.length(1)
expect(tasks[0].UserId).to.equal(999)
done()
})
})
})
})
})
})
})
})
it("can restrict updates", function(done) {
var Task = this.sequelize.define('Task', { title: DataTypes.STRING })
, User = this.sequelize.define('User', { 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.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).to.have.length(1)
done()
})
})
})
})
})
})
})
})
})
describe("Association options", function() {
it('can specify data type for autogenerated relational keys', function(done) {
var User = this.sequelize.define('UserXYZ', { username: DataTypes.STRING })
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING]
, self = this
, Tasks = {}
dataTypes.forEach(function(dataType) {
var tableName = 'TaskXYZ_' + dataType.toString()
Tasks[dataType] = self.sequelize.define(tableName, { title: DataTypes.STRING })
User.hasMany(Tasks[dataType], { foreignKey: 'userId', keyType: dataType })
Tasks[dataType].sync({ force: true }).success(function() {
expect(Tasks[dataType].rawAttributes.userId.type.toString())
.to.equal(dataType.toString())
dataTypes.splice(dataTypes.indexOf(dataType), 1)
if (!dataTypes.length) {
done()
}
})
})
})
})
})
\ No newline at end of file
/* jshint camelcase: false */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, Sequelize = require('../../index')
chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("HasOne"), function() {
describe('getAssocation', function() {
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 })
, Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING, status: Sequelize.STRING })
User.hasOne(Task)
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({ username: 'foo' }).success(function(user) {
Task.create({ title: 'task', status: 'inactive' }).success(function(task) {
user.setTaskXYZ(task).success(function() {
user.getTaskXYZ({where: ['status = ?', 'active']}).success(function(task) {
expect(task).to.equal(null)
done()
})
})
})
})
})
})
})
})
describe('setAssociation', function() {
it('can set an association with predefined primary keys', function(done) {
var User = this.sequelize.define('UserXYZZ', { userCoolIdTag: { type: Sequelize.INTEGER, primaryKey: true }, username: Sequelize.STRING })
, Task = this.sequelize.define('TaskXYZZ', { taskOrSomething: { type: Sequelize.INTEGER, primaryKey: true }, title: Sequelize.STRING })
User.hasOne(Task, {foreignKey: 'userCoolIdTag'})
User.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
User.create({userCoolIdTag: 1, username: 'foo'}).success(function(user) {
Task.create({taskOrSomething: 1, title: 'bar'}).success(function(task) {
user.setTaskXYZZ(task).success(function() {
user.getTaskXYZZ().success(function(task) {
expect(task).not.to.be.null
user.setTaskXYZZ(null).success(function() {
user.getTaskXYZZ().success(function(_task) {
expect(_task).to.be.null
done()
})
})
})
})
})
})
})
})
})
it('clears the association if null is passed', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING })
, Task = this.sequelize.define('TaskXYZ', { title: Sequelize.STRING })
User.hasOne(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.setTaskXYZ(task).success(function() {
user.getTaskXYZ().success(function(task) {
expect(task).not.to.equal(null)
user.setTaskXYZ(null).success(function() {
user.getTaskXYZ().success(function(task) {
expect(task).to.equal(null)
done()
})
})
})
})
})
})
})
})
})
})
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.hasOne(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.setTask(task).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(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.hasOne(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.setTask(task).success(function() {
user.destroy().success(function() {
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(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.hasOne(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.setTask(task).success(function() {
user.destroy().error(function() {
// Should fail due to FK restriction
Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(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.hasOne(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.setTask(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).to.have.length(1)
expect(tasks[0].UserId).to.equal(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.hasOne(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.setTask(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).to.have.length(1)
done()
})
})
})
})
})
})
})
})
})
describe("Association options", function() {
it('can specify data type for autogenerated relational keys', function(done) {
var User = this.sequelize.define('UserXYZ', { username: Sequelize.STRING })
, dataTypes = [Sequelize.INTEGER, Sequelize.BIGINT, Sequelize.STRING]
, self = this
, Tasks = {}
dataTypes.forEach(function(dataType) {
var tableName = 'TaskXYZ_' + dataType.toString()
Tasks[dataType] = self.sequelize.define(tableName, { title: Sequelize.STRING })
User.hasOne(Tasks[dataType], { foreignKey: 'userId', keyType: dataType })
Tasks[dataType].sync({ force: true }).success(function() {
expect(Tasks[dataType].rawAttributes.userId.type.toString())
.to.equal(dataType.toString())
dataTypes.splice(dataTypes.indexOf(dataType), 1)
if (!dataTypes.length) {
done()
}
})
})
})
})
})
\ No newline at end of file
......@@ -336,8 +336,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
smth: { type: Sequelize.STRING, allowNull: false }
})
this.sequelize.options.omitNull = false
UserNull.sync({ force: true }).success(function() {
UserNull.create({ username: 'foo', smth: null }).error(function(err) {
UserNull.create({ username: 'foo2', smth: null }).error(function(err) {
expect(err).to.exist
if (dialect === "mysql") {
......@@ -2481,7 +2483,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
})
if (dialect === "mysql") {
if (dialect === "mysql" || dialect === "sqlite") {
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})
......@@ -2501,6 +2503,49 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
}
it("should describeTable using the default schema settings", function(done) {
var self = this
, UserPublic = this.sequelize.define('Public', {
username: Sequelize.STRING
})
var _done = _.after(2, function() {
done()
})
UserPublic.sync({ force: true }).success(function() {
UserPublic.schema('special').sync({ force: true }).success(function() {
self.sequelize.queryInterface.describeTable('Publics')
.on('sql', function(sql) {
if (dialect === "sqlite" || dialect === "mysql") {
expect(sql).to.not.contain('special')
_done()
}
})
.success(function(table) {
if (dialect === "postgres" || dialect === "postgres-native") {
expect(table.id.defaultValue).to.not.contain('special')
_done()
}
self.sequelize.queryInterface.describeTable('Publics', 'special')
.on('sql', function(sql) {
if (dialect === "sqlite" || dialect === "mysql") {
expect(sql).to.contain('special')
_done()
}
})
.success(function(table) {
if (dialect === "postgres" || dialect === "postgres-native") {
expect(table.id.defaultValue).to.contain('special')
_done()
}
})
})
})
})
})
it("should be able to create and update records under any valid schematic", function(done){
var self = this
......
......@@ -261,6 +261,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
}
describe('#create', function() {
describe('generic', function() {
beforeEach(function(done) {
var self = this
......@@ -291,6 +292,13 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
})
})
it('correctly throws an error using create method ', function(done) {
this.Project.create({name: 'nope'}).error(function(err) {
expect(err).to.have.ownProperty('name')
done()
})
})
it('correctly validates using create method ', function(done) {
var self = this
this.Project.create({}).success(function(project) {
......@@ -305,16 +313,71 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
})
})
})
})
it('correctly throws an error using create method ', function(done) {
var self = this
this.Project.create({name: 'nope'}).error(function(err) {
expect(err).to.have.ownProperty('name')
describe('explicitly validating id/primary/auto incremented columns', function() {
it('should emit an error when we try to enter in a string for the id key without validation arguments', function(done) {
var User = this.sequelize.define('UserId', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
validate: {
isInt: true
}
}
})
User.sync({ force: true }).success(function() {
User.create({id: 'helloworld'}).error(function(err) {
expect(err).to.deep.equal({id: ['Invalid integer']})
done()
})
})
})
it('should emit an error when we try to enter in a string for the id key with validation arguments', function(done) {
var User = this.sequelize.define('UserId', {
id: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
validate: {
isInt: { args: true, msg: 'ID must be an integer!' }
}
}
})
User.sync({ force: true }).success(function() {
User.create({id: 'helloworld'}).error(function(err) {
expect(err).to.deep.equal({id: ['ID must be an integer!']})
done()
})
})
})
it('should emit an error when we try to enter in a string for an auto increment key (not named id)', function(done) {
var User = this.sequelize.define('UserId', {
username: {
type: Sequelize.INTEGER,
autoIncrement: true,
primaryKey: true,
validate: {
isInt: { args: true, msg: 'Username must be an integer!' }
}
}
})
User.sync({ force: true }).success(function() {
User.create({username: 'helloworldhelloworld'}).error(function(err) {
expect(err).to.deep.equal({username: ['Username must be an integer!']})
done()
})
})
})
})
})
it('correctly validates using custom validation methods', function(done) {
var User = this.sequelize.define('User' + config.rand(), {
name: {
......
......@@ -26,6 +26,80 @@ if (dialect.match(/^postgres/)) {
done()
})
describe('integers', function() {
describe('integer', function() {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
aNumber: DataTypes.INTEGER
})
this.User.sync({ force: true }).success(function() {
done()
})
})
it('positive', function(done) {
var User = this.User
User.create({aNumber: 2147483647}).success(function(user) {
expect(user.aNumber).to.equal(2147483647)
User.find({where: {aNumber: 2147483647}}).success(function(_user) {
expect(_user.aNumber).to.equal(2147483647)
done()
})
})
})
it('negative', function(done) {
var User = this.User
User.create({aNumber: -2147483647}).success(function(user) {
expect(user.aNumber).to.equal(-2147483647)
User.find({where: {aNumber: -2147483647}}).success(function(_user) {
expect(_user.aNumber).to.equal(-2147483647)
done()
})
})
})
})
describe('bigint', function() {
beforeEach(function(done) {
this.User = this.sequelize.define('User', {
aNumber: DataTypes.BIGINT
})
this.User.sync({ force: true }).success(function() {
done()
})
})
it('positive', function(done) {
var User = this.User
User.create({aNumber: '9223372036854775807'}).success(function(user) {
expect(user.aNumber).to.equal('9223372036854775807')
User.find({where: {aNumber: '9223372036854775807'}}).success(function(_user) {
expect(_user.aNumber).to.equal('9223372036854775807')
done()
})
})
})
it('negative', function(done) {
var User = this.User
User.create({aNumber: '-9223372036854775807'}).success(function(user) {
expect(user.aNumber).to.equal('-9223372036854775807')
User.find({where: {aNumber: '-9223372036854775807'}}).success(function(_user) {
expect(_user.aNumber).to.equal('-9223372036854775807')
done()
})
})
})
})
})
describe('model', function() {
it("create handles array correctly", function(done) {
this.User
......
......@@ -116,12 +116,8 @@ var Support = {
var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() })
before(function(done) {
this.sequelize = sequelize
done()
})
beforeEach(function(done) {
this.sequelize = sequelize
Support.clearDatabase(this.sequelize, function() {
done()
})
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!