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

Commit 99d02bd9 by Daniel Durante

Merge pull request #771 from durango/association-key

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. Closes #694
2 parents d5feb763 059bab9e
...@@ -37,15 +37,20 @@ module.exports = (function() { ...@@ -37,15 +37,20 @@ module.exports = (function() {
BelongsTo.prototype.injectGetter = function(obj) { BelongsTo.prototype.injectGetter = function(obj) {
var self = this var self = this
, accessor = Utils._.camelize('get_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language))) , 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) { obj[accessor] = function(params) {
var id = this[self.identifier] var id = this[self.identifier]
, where = {}
where[primaryKey] = id
if (!Utils._.isUndefined(params)) { if (!Utils._.isUndefined(params)) {
if (!Utils._.isUndefined(params.where)) { if (!Utils._.isUndefined(params.where)) {
params.where = Utils._.extend({id:id}, params.where) params.where = Utils._.extend(where, params.where)
} else { } else {
params.where = {id: id} params.where = where
} }
} else { } else {
params = id params = id
...@@ -62,10 +67,13 @@ module.exports = (function() { ...@@ -62,10 +67,13 @@ module.exports = (function() {
, accessor = Utils._.camelize('set_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language))) , accessor = Utils._.camelize('set_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language)))
obj[accessor] = function(associatedObject) { 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. // 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 return this
......
...@@ -10,15 +10,21 @@ module.exports = (function() { ...@@ -10,15 +10,21 @@ module.exports = (function() {
var self = this, _options = options var self = this, _options = options
var customEventEmitter = new Utils.CustomEventEmitter(function() { var customEventEmitter = new Utils.CustomEventEmitter(function() {
var where = {}, options = _options || {}; var where = {}, options = _options || {}
//fully qualify //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) var primaryKeys = Object.keys(self.__factory.connectorDAO.rawAttributes)
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0] , 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 (options.where) {
if (Array.isArray(options.where)) { if (Array.isArray(options.where)) {
...@@ -28,18 +34,11 @@ module.exports = (function() { ...@@ -28,18 +34,11 @@ module.exports = (function() {
options.where = smart options.where = smart
} }
} else { } else {
Utils._.each(options.where, function(value, index) { smart = Utils.smartWhere([where, options.where], self.__factory.target.daoFactoryManager.sequelize.options.dialect)
delete options.where[index]; smart = Utils.compileSmartWhere.call(self.__factory.target, smart, self.__factory.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.smartWhere(value, self.__factory.target.daoFactoryManager.sequelize.options.dialect) if (smart.length > 0) {
smart = Utils.compileSmartWhere.call(self.__factory.target, smart) options.where = smart
if (smart.length > 0) { }
value = smart
}
options.where[self.__factory.target.tableName+"."+index] = value;
});
options.where = Utils._.extend(options.where, where)
} }
} else { } else {
options.where = where; options.where = where;
...@@ -58,16 +57,17 @@ module.exports = (function() { ...@@ -58,16 +57,17 @@ module.exports = (function() {
var self = this var self = this
, chainer = new Utils.QueryChainer() , chainer = new Utils.QueryChainer()
, association = self.__factory.target.associations[self.__factory.associationAccessor] , association = self.__factory.target.associations[self.__factory.associationAccessor]
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier , foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier;
, obsoleteAssociations = oldAssociations.filter(function (old) {
var obsoleteAssociations = oldAssociations.filter(function (old) {
// Return only those old associations that are not found in new // Return only those old associations that are not found in new
return !Utils._.find(newAssociations, function (obj) { 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) { , unassociatedObjects = newAssociations.filter(function (obj) {
return !Utils._.find(oldAssociations, function (old) { 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() { ...@@ -79,7 +79,7 @@ module.exports = (function() {
, foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0] , foreignKey = primaryKeys.filter(function(pk) { return pk != self.__factory.identifier })[0]
var where = {} var where = {}
where[self.__factory.identifier] = self.instance.id where[self.__factory.identifier] = self.instance[self.__factory.identifier] || self.instance.id
where[foreignKey] = foreignIds where[foreignKey] = foreignIds
chainer.add(self.__factory.connectorDAO.destroy(where)) chainer.add(self.__factory.connectorDAO.destroy(where))
...@@ -88,8 +88,8 @@ module.exports = (function() { ...@@ -88,8 +88,8 @@ module.exports = (function() {
if (unassociatedObjects.length > 0) { if (unassociatedObjects.length > 0) {
var bulk = unassociatedObjects.map(function(unassociatedObject) { var bulk = unassociatedObjects.map(function(unassociatedObject) {
var attributes = {} var attributes = {}
attributes[self.__factory.identifier] = self.instance.id attributes[self.__factory.identifier] = self.instance[self.__factory.identifier] || self.instance.id
attributes[foreignIdentifier] = unassociatedObject.id attributes[foreignIdentifier] = unassociatedObject[foreignIdentifier] || unassociatedObject.id
return attributes return attributes
}) })
...@@ -109,8 +109,8 @@ module.exports = (function() { ...@@ -109,8 +109,8 @@ module.exports = (function() {
, association = this.__factory.target.associations[this.__factory.associationAccessor] , association = this.__factory.target.associations[this.__factory.associationAccessor]
, foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier; , foreignIdentifier = association.isSelfAssociation ? association.foreignIdentifier : association.identifier;
attributes[this.__factory.identifier] = this.instance.id attributes[this.__factory.identifier] = this.instance[this.__factory.identifier] || this.instance.id
attributes[foreignIdentifier] = newAssociation.id attributes[foreignIdentifier] = newAssociation[foreignIdentifier] || newAssociation.id
this.__factory.connectorDAO.create(attributes) this.__factory.connectorDAO.create(attributes)
.success(function() { emitterProxy.emit('success', newAssociation) }) .success(function() { emitterProxy.emit('success', newAssociation) })
......
...@@ -7,14 +7,17 @@ module.exports = (function() { ...@@ -7,14 +7,17 @@ module.exports = (function() {
} }
HasManySingleLinked.prototype.injectGetter = function(options) { HasManySingleLinked.prototype.injectGetter = function(options) {
var where = {} var self = this
, where = {}
options = options || {} 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) { if (options.where) {
smart = Utils.smartWhere([where, options.where], this.__factory.target.daoFactoryManager.sequelize.options.dialect) 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) { if (smart.length > 0) {
options.where = smart options.where = smart
} }
...@@ -27,15 +30,17 @@ module.exports = (function() { ...@@ -27,15 +30,17 @@ module.exports = (function() {
HasManySingleLinked.prototype.injectSetter = function(emitter, oldAssociations, newAssociations) { HasManySingleLinked.prototype.injectSetter = function(emitter, oldAssociations, newAssociations) {
var self = this var self = this
, associationKeys = Object.keys((oldAssociations[0] || newAssociations[0] || {}).daoFactory.primaryKeys || {})
, associationKey = associationKeys.length === 1 ? associationKeys[0] : 'id'
, chainer = new Utils.QueryChainer() , chainer = new Utils.QueryChainer()
, obsoleteAssociations = oldAssociations.filter(function (old) { , obsoleteAssociations = oldAssociations.filter(function (old) {
return !Utils._.find(newAssociations, function (obj) { return !Utils._.find(newAssociations, function (obj) {
return obj.id === old.id return obj[associationKey] === old[associationKey]
}) })
}) })
, unassociatedObjects = newAssociations.filter(function (obj) { , unassociatedObjects = newAssociations.filter(function (obj) {
return !Utils._.find(oldAssociations, function (old) { return !Utils._.find(oldAssociations, function (old) {
return obj.id === old.id return obj[associationKey] === old[associationKey]
}) })
}) })
, update , update
...@@ -44,24 +49,38 @@ module.exports = (function() { ...@@ -44,24 +49,38 @@ module.exports = (function() {
// clear the old associations // clear the old associations
var obsoleteIds = obsoleteAssociations.map(function(associatedObject) { var obsoleteIds = obsoleteAssociations.map(function(associatedObject) {
associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id) associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id)
return associatedObject.id return associatedObject[associationKey]
}) })
update = {} update = {}
update[self.__factory.identifier] = null 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) { 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 // set the new associations
var unassociatedIds = unassociatedObjects.map(function(associatedObject) { var unassociatedIds = unassociatedObjects.map(function(associatedObject) {
associatedObject[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id) associatedObject[self.__factory.identifier] = self.instance[pkey] || self.instance.id
return associatedObject.id return associatedObject[associationKey]
}) })
update = {} update = {}
update[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance.id) update[self.__factory.identifier] = (newAssociations.length < 1 ? null : self.instance[pkey] || self.instance.id)
chainer.add(this.__factory.target.update(update, { id: unassociatedIds })) updateWhere[primaryKey] = unassociatedIds
chainer.add(this.__factory.target.update(update, updateWhere, {allowNull: [self.__factory.identifier]}))
} }
chainer chainer
...@@ -72,7 +91,10 @@ module.exports = (function() { ...@@ -72,7 +91,10 @@ module.exports = (function() {
} }
HasManySingleLinked.prototype.injectAdder = function(emitterProxy, newAssociation) { 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() newAssociation.save()
.success(function() { emitterProxy.emit('success', newAssociation) }) .success(function() { emitterProxy.emit('success', newAssociation) })
......
...@@ -88,7 +88,7 @@ module.exports = (function() { ...@@ -88,7 +88,7 @@ module.exports = (function() {
} }
obj[this.accessors.hasAll] = function(objects) { obj[this.accessors.hasAll] = function(objects) {
var instance = this; var instance = this;
var customEventEmitter = new Utils.CustomEventEmitter(function() { var customEventEmitter = new Utils.CustomEventEmitter(function() {
instance[self.accessors.get]() instance[self.accessors.get]()
.error(function(err){ customEventEmitter.emit('error', err)}) .error(function(err){ customEventEmitter.emit('error', err)})
...@@ -108,7 +108,7 @@ module.exports = (function() { ...@@ -108,7 +108,7 @@ module.exports = (function() {
} }
obj[this.accessors.hasSingle] = function(o) { obj[this.accessors.hasSingle] = function(o) {
var instance = this; var instance = this;
var customEventEmitter = new Utils.CustomEventEmitter(function() { var customEventEmitter = new Utils.CustomEventEmitter(function() {
instance[self.accessors.get]() instance[self.accessors.get]()
.error(function(err){ customEventEmitter.emit('error', err)}) .error(function(err){ customEventEmitter.emit('error', err)})
...@@ -155,8 +155,13 @@ module.exports = (function() { ...@@ -155,8 +155,13 @@ module.exports = (function() {
obj[this.accessors.add] = function(newAssociatedObject) { obj[this.accessors.add] = function(newAssociatedObject) {
var instance = this 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) { 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)}) .error(function(err){ emitter.emit('error', err)})
.success(function(currentAssociatedObjects) { .success(function(currentAssociatedObjects) {
if (currentAssociatedObjects.length === 0) { if (currentAssociatedObjects.length === 0) {
......
...@@ -43,8 +43,10 @@ module.exports = (function() { ...@@ -43,8 +43,10 @@ module.exports = (function() {
var self = this var self = this
obj[this.accessors.get] = function(params) { 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 = {} , where = {}
, id = this[primaryKey] || this.id
where[self.identifier] = id where[self.identifier] = id
...@@ -56,8 +58,8 @@ module.exports = (function() { ...@@ -56,8 +58,8 @@ module.exports = (function() {
params = {where: where} params = {where: where}
} }
smart = Utils.smartWhere([where, params.where || []], self.target.daoFactoryManager.sequelize.options.dialect) smart = Utils.smartWhere(params.where || [], self.target.daoFactoryManager.sequelize.options.dialect)
smart = Utils.compileSmartWhere.call(self.target, smart) smart = Utils.compileSmartWhere.call(self.target, smart, self.target.daoFactoryManager.sequelize.options.dialect)
if (smart.length > 0) { if (smart.length > 0) {
params.where = smart params.where = smart
} }
...@@ -69,17 +71,20 @@ module.exports = (function() { ...@@ -69,17 +71,20 @@ module.exports = (function() {
} }
HasOne.prototype.injectSetter = function(obj) { HasOne.prototype.injectSetter = function(obj) {
var self = this var self = this
obj[this.accessors.set] = function(associatedObject) { obj[this.accessors.set] = function(associatedObject) {
var instance = this var instance = this
, instanceKeys = Object.keys(instance.daoFactory.primaryKeys)
, instanceKey = instanceKeys.length === 1 ? instanceKeys[0] : 'id'
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().success(function() { oldObj.save([self.identifier], {allowNull: [self.identifier]}).success(function() {
if (associatedObject) { if (associatedObject) {
associatedObject[self.identifier] = instance.id associatedObject[self.identifier] = instance[instanceKey]
associatedObject associatedObject
.save() .save()
.success(function() { emitter.emit('success', associatedObject) }) .success(function() { emitter.emit('success', associatedObject) })
...@@ -90,7 +95,7 @@ module.exports = (function() { ...@@ -90,7 +95,7 @@ module.exports = (function() {
}) })
} else { } else {
if (associatedObject) { if (associatedObject) {
associatedObject[self.identifier] = instance.id associatedObject[self.identifier] = instance[instanceKey]
associatedObject associatedObject
.save() .save()
.success(function() { emitter.emit('success', associatedObject) }) .success(function() { emitter.emit('success', associatedObject) })
......
...@@ -62,6 +62,9 @@ module.exports = (function() { ...@@ -62,6 +62,9 @@ module.exports = (function() {
get: function() { return this.QueryInterface.QueryGenerator } get: function() { return this.QueryInterface.QueryGenerator }
}) })
// inject the node-sql methods to the dao factory in order to
// receive the syntax sugar ...
;(function() { ;(function() {
var instance = sql.define({ name: "dummy", columns: [] }) var instance = sql.define({ name: "dummy", columns: [] })
...@@ -559,12 +562,12 @@ module.exports = (function() { ...@@ -559,12 +562,12 @@ module.exports = (function() {
* @param {Object} where Options to describe the scope of the search. * @param {Object} where Options to describe the scope of the search.
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`. * @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) { if(this.options.timestamps) {
var attr = this.options.underscored ? 'updated_at' : 'updatedAt' var attr = this.options.underscored ? 'updated_at' : 'updatedAt'
attrValueHash[attr] = Utils.now() 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() { DAOFactory.prototype.describe = function() {
......
...@@ -96,7 +96,7 @@ module.exports = (function() { ...@@ -96,7 +96,7 @@ module.exports = (function() {
// if an array with field names is passed to save() // if an array with field names is passed to save()
// only those fields will be updated // only those fields will be updated
DAO.prototype.save = function(fields) { DAO.prototype.save = function(fields, options) {
var self = this var self = this
, values = fields ? {} : this.dataValues , values = fields ? {} : this.dataValues
, updatedAtAttr = this.__options.underscored ? 'updated_at' : 'updatedAt' , updatedAtAttr = this.__options.underscored ? 'updated_at' : 'updatedAt'
...@@ -179,7 +179,7 @@ module.exports = (function() { ...@@ -179,7 +179,7 @@ module.exports = (function() {
this.isDirty = false this.isDirty = false
var tableName = this.QueryInterface.QueryGenerator.addSchema(this.__factory) 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)
return query return query
} }
......
...@@ -162,7 +162,7 @@ module.exports = (function() { ...@@ -162,7 +162,7 @@ module.exports = (function() {
return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') }) return Utils._.template(query)({ tableName: tableName, attributes: attrString.join(', ') })
}, },
selectQuery: function(tableName, options) { selectQuery: function(tableName, options, factory) {
var table = null, var table = null,
joinQuery = "" joinQuery = ""
...@@ -204,7 +204,7 @@ module.exports = (function() { ...@@ -204,7 +204,7 @@ module.exports = (function() {
query += joinQuery query += joinQuery
if (options.hasOwnProperty('where')) { if (options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName) options.where = this.getWhereConditions(options.where, tableName, factory)
query += " WHERE " + options.where query += " WHERE " + options.where
} }
...@@ -266,8 +266,8 @@ module.exports = (function() { ...@@ -266,8 +266,8 @@ module.exports = (function() {
return query return query
}, },
updateQuery: function(tableName, attrValueHash, where) { updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull) attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var values = [] var values = []
...@@ -402,14 +402,24 @@ module.exports = (function() { ...@@ -402,14 +402,24 @@ module.exports = (function() {
return Utils._.template(sql)({ tableName: tableName, indexName: indexName }) return Utils._.template(sql)({ tableName: tableName, indexName: indexName })
}, },
getWhereConditions: function(smth, tableName) { getWhereConditions: function(smth, tableName, factory) {
var result = null var result = null
, where = {}
if (Utils.isHash(smth)) { if (Utils.isHash(smth)) {
smth = Utils.prependTableNameToHash(tableName, smth) smth = Utils.prependTableNameToHash(tableName, smth)
result = this.hashToWhereConditions(smth) result = this.hashToWhereConditions(smth)
} else if (typeof smth === 'number') { } 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) result = this.hashToWhereConditions(smth)
} else if (typeof smth === "string") { } else if (typeof smth === "string") {
result = smth result = smth
......
...@@ -36,6 +36,8 @@ module.exports = (function() { ...@@ -36,6 +36,8 @@ module.exports = (function() {
ConnectorManager.prototype.endQuery = function() { ConnectorManager.prototype.endQuery = function() {
var self = this var self = this
self.pendingQueries--
if (!self.pooling && self.pendingQueries === 0) { if (!self.pooling && self.pendingQueries === 0) {
setTimeout(function() { setTimeout(function() {
self.pendingQueries === 0 && self.disconnect.call(self) self.pendingQueries === 0 && self.disconnect.call(self)
...@@ -46,43 +48,31 @@ module.exports = (function() { ...@@ -46,43 +48,31 @@ module.exports = (function() {
ConnectorManager.prototype.query = function(sql, callee, options) { ConnectorManager.prototype.query = function(sql, callee, options) {
var self = this var self = this
// we really want pendingQueries to increment as fast as possible...
self.pendingQueries++ self.pendingQueries++
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
self.connect() self.connect()
.on('error', function(err) { .on('error', function(err) {
// zero-out the previous increment
self.pendingQueries--
self.endQuery.call(self)
emitter.emit('error', err) emitter.emit('error', err)
}) })
.on('success', function(done) { .on('success', function(done) {
var query = new Query(self.client, self.sequelize, callee, options || {}) var query = new Query(self.client, self.sequelize, callee, options || {})
done = done || null done = done || null
query.run(sql, done) return query.run(sql, done)
.success(function(results) { .success(function(results) { self.endQuery.call(self) })
self.pendingQueries-- .error(function(err) { self.endQuery.call(self) })
emitter.emit('success', results) .proxy(emitter)
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) })
}) })
}).run() }).run()
} }
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 && !this.pooling) {
emitter.emit('success') emitter.emit('success')
return emitter return emitter
} }
...@@ -116,10 +106,10 @@ module.exports = (function() { ...@@ -116,10 +106,10 @@ module.exports = (function() {
} }
} else if (client) { } else if (client) {
client.query("SET TIME ZONE 'UTC'").on('end', function() { client.query("SET TIME ZONE 'UTC'").on('end', function() {
self.isConnected = true self.isConnected = true
self.client = client self.client = client
emitter.emit('success', done) emitter.emit('success', done)
}); })
} else { } else {
self.client = null self.client = null
emitter.emit('success', done) emitter.emit('success', done)
...@@ -131,8 +121,8 @@ module.exports = (function() { ...@@ -131,8 +121,8 @@ module.exports = (function() {
this.poolIdentifier = this.pg.pools.getOrCreate(this.sequelize.config) this.poolIdentifier = this.pg.pools.getOrCreate(this.sequelize.config)
this.poolIdentifier.connect(connectCallback) this.poolIdentifier.connect(connectCallback)
} else { } else {
if (this.client !== null) { if (!!this.client) {
connectCallback(null, this.client) connectCallback(null, this.client);
} else { } else {
//create one-off client //create one-off client
this.client = new this.pg.Client(uri) this.client = new this.pg.Client(uri)
...@@ -158,4 +148,4 @@ module.exports = (function() { ...@@ -158,4 +148,4 @@ module.exports = (function() {
} }
return ConnectorManager return ConnectorManager
})() })()
\ No newline at end of file
...@@ -226,7 +226,7 @@ module.exports = (function() { ...@@ -226,7 +226,7 @@ module.exports = (function() {
}) })
}, },
selectQuery: function(tableName, options) { selectQuery: function(tableName, options, factory) {
var query = "SELECT <%= attributes %> FROM <%= table %>", var query = "SELECT <%= attributes %> FROM <%= table %>",
table = null table = null
...@@ -267,7 +267,7 @@ module.exports = (function() { ...@@ -267,7 +267,7 @@ module.exports = (function() {
} }
if(options.hasOwnProperty('where')) { if(options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName) options.where = this.getWhereConditions(options.where, tableName, factory)
query += " WHERE <%= where %>" query += " WHERE <%= where %>"
} }
...@@ -354,8 +354,8 @@ module.exports = (function() { ...@@ -354,8 +354,8 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
updateQuery: function(tableName, attrValueHash, where) { updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull) attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %> RETURNING *" var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %> RETURNING *"
, values = [] , values = []
...@@ -492,18 +492,26 @@ module.exports = (function() { ...@@ -492,18 +492,26 @@ module.exports = (function() {
}) })
}, },
getWhereConditions: function(smth, tableName) { getWhereConditions: function(smth, tableName, factory) {
var result = null var result = null
, where = {}
if (Utils.isHash(smth)) { if (Utils.isHash(smth)) {
smth = Utils.prependTableNameToHash(tableName, smth) smth = Utils.prependTableNameToHash(tableName, smth)
result = this.hashToWhereConditions(smth) result = this.hashToWhereConditions(smth)
} } else if (typeof smth === 'number') {
else if (typeof smth === "number") { var primaryKeys = !!factory ? Object.keys(factory.primaryKeys) : []
smth = Utils.prependTableNameToHash(tableName, { id: smth }) 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) result = this.hashToWhereConditions(smth)
} } else if (typeof smth === "string") {
else if (typeof smth === "string") {
result = smth result = smth
} }
else if (Array.isArray(smth)) { else if (Array.isArray(smth)) {
......
...@@ -101,7 +101,7 @@ module.exports = (function() { ...@@ -101,7 +101,7 @@ module.exports = (function() {
result[_result.Field].defaultValue = result[_result.Field].defaultValue.replace(/'/g, "") result[_result.Field].defaultValue = result[_result.Field].defaultValue.replace(/'/g, "")
if (result[_result.Field].defaultValue.indexOf('::') > -1) { 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)") { if (split[1].toLowerCase() !== "regclass)") {
result[_result.Field].defaultValue = split[0] result[_result.Field].defaultValue = split[0]
} }
...@@ -163,4 +163,4 @@ module.exports = (function() { ...@@ -163,4 +163,4 @@ module.exports = (function() {
} }
return Query return Query
})() })()
\ No newline at end of file
...@@ -144,7 +144,7 @@ module.exports = (function() { ...@@ -144,7 +144,7 @@ module.exports = (function() {
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
selectQuery: function(tableName, options) { selectQuery: function(tableName, options, factory) {
var table = null, var table = null,
joinQuery = "" joinQuery = ""
...@@ -186,7 +186,7 @@ module.exports = (function() { ...@@ -186,7 +186,7 @@ module.exports = (function() {
query += joinQuery query += joinQuery
if (options.hasOwnProperty('where')) { if (options.hasOwnProperty('where')) {
options.where = this.getWhereConditions(options.where, tableName) options.where = this.getWhereConditions(options.where, tableName, factory)
query += " WHERE " + options.where query += " WHERE " + options.where
} }
...@@ -218,8 +218,8 @@ module.exports = (function() { ...@@ -218,8 +218,8 @@ module.exports = (function() {
return query return query
}, },
updateQuery: function(tableName, attrValueHash, where) { updateQuery: function(tableName, attrValueHash, where, options) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull) attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull, options)
var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>" var query = "UPDATE <%= table %> SET <%= values %> WHERE <%= where %>"
, values = [] , values = []
......
...@@ -125,15 +125,15 @@ module.exports = (function() { ...@@ -125,15 +125,15 @@ module.exports = (function() {
this.finished = true this.finished = true
if (this.emitters.length > 0) { 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) { 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) { if (this.finished && this.wasRunning) {
var status = (this.fails.length == 0 ? 'success' : 'error') var status = (this.fails.length === 0 ? 'success' : 'error')
, result = (this.fails.length == 0 ? this[resultsName] : this.fails) , result = (this.fails.length === 0 ? this[resultsName] : this.fails)
this.eventEmitter.emit.apply(this.eventEmitter, [status, result].concat(result)) this.eventEmitter.emit.apply(this.eventEmitter, [status, result].concat(result))
} }
......
...@@ -91,25 +91,25 @@ module.exports = (function() { ...@@ -91,25 +91,25 @@ module.exports = (function() {
var chainer = new Utils.QueryChainer() var chainer = new Utils.QueryChainer()
self.showAllTables().success(function(tableNames) { self.showAllTables().success(function(tableNames) {
chainer.add(self, 'disableForeignKeyConstraints', [])
chainer.add(self, 'disableForeignKeyConstraints', []) tableNames.forEach(function(tableName) {
chainer.add(self, 'dropTable', [tableName, {cascade: true}])
})
tableNames.forEach(function(tableName) { chainer.add(self, 'enableForeignKeyConstraints', [])
chainer.add(self, 'dropTable', [tableName, {cascade: true}])
})
chainer.add(self, 'enableForeignKeyConstraints', []) chainer
.runSerially()
.success(function() {
self.emit('dropAllTables', null)
emitter.emit('success', null)
})
.error(function(err) {
self.emit('dropAllTables', err)
emitter.emit('error', err)
})
chainer
.runSerially()
.success(function() {
self.emit('dropAllTables', null)
emitter.emit('success', null)
})
.error(function(err) {
self.emit('dropAllTables', err)
emitter.emit('error', err)
})
}).error(function(err) { }).error(function(err) {
self.emit('dropAllTables', err) self.emit('dropAllTables', err)
emitter.emit('error', err) emitter.emit('error', err)
...@@ -265,10 +265,10 @@ module.exports = (function() { ...@@ -265,10 +265,10 @@ module.exports = (function() {
return queryAndEmit.call(this, sql, 'bulkInsert') 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 var self = this
, restrict = false , restrict = false
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier) , sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options)
// Check for a restrict field // Check for a restrict field
if (!!dao.daoFactory && !!dao.daoFactory.associations) { if (!!dao.daoFactory && !!dao.daoFactory.associations) {
...@@ -285,8 +285,8 @@ module.exports = (function() { ...@@ -285,8 +285,8 @@ module.exports = (function() {
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer() var chainer = new Utils.QueryChainer()
chainer.add(self, 'enableForeignKeyConstraints', []) chainer.add(self, 'enableForeignKeyConstraints', [])
chainer.add(self, 'queryAndEmit', [[sql, dao], 'delete']) chainer.add(self, 'queryAndEmit', [[sql, dao], 'delete'])
chainer.runSerially() chainer.runSerially()
.success(function(results){ .success(function(results){
...@@ -305,9 +305,9 @@ module.exports = (function() { ...@@ -305,9 +305,9 @@ module.exports = (function() {
}).run() }).run()
} }
QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier) { QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier, options) {
var self = this var self = this
, sql = self.QueryGenerator.updateQuery(tableName, values, identifier) , sql = self.QueryGenerator.updateQuery(tableName, values, identifier, options)
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer() var chainer = new Utils.QueryChainer()
...@@ -393,7 +393,7 @@ module.exports = (function() { ...@@ -393,7 +393,7 @@ module.exports = (function() {
QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) { QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) {
options = options || {} options = options || {}
var sql = this.QueryGenerator.selectQuery(tableName, options) var sql = this.QueryGenerator.selectQuery(tableName, options, factory)
queryOptions = Utils._.extend({}, queryOptions, { include: options.include }) queryOptions = Utils._.extend({}, queryOptions, { include: options.include })
return queryAndEmit.call(this, [sql, factory, queryOptions], 'select') return queryAndEmit.call(this, [sql, factory, queryOptions], 'select')
} }
......
...@@ -191,7 +191,6 @@ var Utils = module.exports = { ...@@ -191,7 +191,6 @@ var Utils = module.exports = {
break break
default: // lazy default: // lazy
text = text.concat(obj[column].lazy.conditions.map(function(val){ return columnName + ' ' + val })) 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) whereArgs = whereArgs.concat(obj[column].lazy.bindings)
} }
}) })
...@@ -320,15 +319,18 @@ var Utils = module.exports = { ...@@ -320,15 +319,18 @@ var Utils = module.exports = {
return hash return hash
}, },
removeNullValuesFromHash: function(hash, omitNull) { removeNullValuesFromHash: function(hash, omitNull, options) {
var result = hash var result = hash
options = options || {}
options.allowNull = options.allowNull || []
if (omitNull) { if (omitNull) {
var _hash = {} var _hash = {}
Utils._.each(hash, function(val, key) { Utils._.each(hash, function(val, key) {
if (key.match(/Id$/) || ((val !== null) && (val !== undefined))) { if (options.allowNull.indexOf(key) > -1 || key.match(/Id$/) || ((val !== null) && (val !== undefined))) {
_hash[key] = val; _hash[key] = val
} }
}) })
......
/* 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')
, 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 () { ...@@ -336,8 +336,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
smth: { type: Sequelize.STRING, allowNull: false } smth: { type: Sequelize.STRING, allowNull: false }
}) })
this.sequelize.options.omitNull = false
UserNull.sync({ force: true }).success(function() { 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 expect(err).to.exist
if (dialect === "mysql") { if (dialect === "mysql") {
......
...@@ -116,12 +116,8 @@ var Support = { ...@@ -116,12 +116,8 @@ var Support = {
var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() }) var sequelize = Support.createSequelizeInstance({ dialect: Support.getTestDialect() })
before(function(done) {
this.sequelize = sequelize
done()
})
beforeEach(function(done) { beforeEach(function(done) {
this.sequelize = sequelize
Support.clearDatabase(this.sequelize, function() { Support.clearDatabase(this.sequelize, function() {
done() done()
}) })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!