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

Commit 4b7c0e94 by Mick Hansen

Update 2.0.0 branch

2 parents 525760c2 8547ea1a
REPORTER ?= dot REPORTER ?= spec
TESTS = $(shell find ./test/* -name "*.test.js") TESTS = $(shell find ./test/* -name "*.test.js")
DIALECT ?= mysql DIALECT ?= mysql
......
...@@ -10,6 +10,8 @@ There is a parallel "branch" of the project, released as `2.0.0-alphaX` in NPM. ...@@ -10,6 +10,8 @@ There is a parallel "branch" of the project, released as `2.0.0-alphaX` in NPM.
and will get all the changes of the master. However, `2.0.0` will contain backwards compatibility breaking changes. Check the and will get all the changes of the master. However, `2.0.0` will contain backwards compatibility breaking changes. Check the
changelog of the branch: https://github.com/sequelize/sequelize/blob/milestones/2.0.0/changelog.md changelog of the branch: https://github.com/sequelize/sequelize/blob/milestones/2.0.0/changelog.md
##### 2.0.0 API should be considered unstable
### 1.6.0 ### ### 1.6.0 ###
- We changed the way timestamps are handled. From v1.6.0 on timestamps are stored and loaded as UTC. - We changed the way timestamps are handled. From v1.6.0 on timestamps are stored and loaded as UTC.
...@@ -37,11 +39,11 @@ changelog of the branch: https://github.com/sequelize/sequelize/blob/milestones/ ...@@ -37,11 +39,11 @@ changelog of the branch: https://github.com/sequelize/sequelize/blob/milestones/
## Documentation and Updates ## ## Documentation and Updates ##
You can find the documentation and announcements of updates on the [project's website](http://www.sequelizejs.com). You can find the documentation and announcements of updates on the [project's website](http://sequelizejs.com).
If you want to know about latest development and releases, follow me on [Twitter](http://twitter.com/sdepold). If you want to know about latest development and releases, follow me on [Twitter](http://twitter.com/sdepold).
Also make sure to take a look at the examples in the repository. The website will contain them soon, as well. Also make sure to take a look at the examples in the repository. The website will contain them soon, as well.
- [Documentation](http://www.sequelizejs.com) - [Documentation](http://sequelizejs.com)
- [Twitter](http://twitter.com/sdepold) - [Twitter](http://twitter.com/sdepold)
- [IRC](http://webchat.freenode.net?channels=sequelizejs) - [IRC](http://webchat.freenode.net?channels=sequelizejs)
- [Google Groups](https://groups.google.com/forum/#!forum/sequelize) - [Google Groups](https://groups.google.com/forum/#!forum/sequelize)
...@@ -105,7 +107,16 @@ a productive developer, I would recommend the latest v0.8. Also I usually recomm ...@@ -105,7 +107,16 @@ a productive developer, I would recommend the latest v0.8. Also I usually recomm
Once Node.JS is installed on your computer, you will also have access to the lovely Once Node.JS is installed on your computer, you will also have access to the lovely
Node Package Manager (NPM). Node Package Manager (NPM).
### 2. Database... Come to me! ### ### 2. Install the dependencies ###
Just "cd" into sequelize directory and run `npm install`, see an example below:
```console
$ cd path/to/sequelize
$ npm install
```
### 3. Database... Come to me! ###
First class citizen of Sequelize was MySQL. Over time, Sequelize began to First class citizen of Sequelize was MySQL. Over time, Sequelize began to
become compatible to SQLite and PostgreSQL. In order to provide a fully become compatible to SQLite and PostgreSQL. In order to provide a fully
...@@ -130,16 +141,32 @@ $ echo "CREATE DATABASE sequelize_test;" | mysql -uroot ...@@ -130,16 +141,32 @@ $ echo "CREATE DATABASE sequelize_test;" | mysql -uroot
**AND ONE LAST THING:** Once `npm install` worked for you (see below), you'll **AND ONE LAST THING:** Once `npm install` worked for you (see below), you'll
get SQLite tests for free :) get SQLite tests for free :)
#### 3a. Docker
If you don't feel like setting up databases and users, you can use our [docker](http://docker.io) [image](https://index.docker.io/u/mhansen/sequelize-contribution/) for sequelize contribution.
Getting the image:
```console
$ sudo docker pull mhansen/sequelize-contribution
```
### 3. Install the dependencies ### Start the container and save references to container id and ip:
```console
$ CONTAINER=$(sudo docker run -d -i -t mhansen/sequelize-contribution)
$ CONTAINER_IP=$(sudo docker inspect -format='{{.NetworkSettings.IPAddress}}' $CONTAINER)
```
Just "cd" into sequelize directory and run `npm install`, see an example below: Run tests:
```console
$ SEQ_HOST=$CONTAINER_IP SEQ_USER=sequelize_test make all
```
Stop the container:
```console ```console
$ cd path/to/sequelize $ sudo docker stop $CONTAINER
$ npm install
``` ```
When running tests repeatedly, you only need to redo step 3 if you haven't stopped the container.
### 4. Run the tests ### ### 4. Run the tests ###
Right now, the test base is split into the `test` folder (which contains the Right now, the test base is split into the `test` folder (which contains the
......
...@@ -22,6 +22,15 @@ var relativeConfigFile = function() { ...@@ -22,6 +22,15 @@ var relativeConfigFile = function() {
return path.relative(process.cwd(), configuration.configFile) return path.relative(process.cwd(), configuration.configFile)
} }
// Taken from
// http://stackoverflow.com/questions/15375544/how-can-i-robustly-detect-a-relative-path-in-node-js/17521358#17521358
var isRelativePath = function(p) {
var normal = path.normalize(p)
, absolute = path.resolve(p);
return normal != absolute;
}
var writeDefaultConfig = function(config) { var writeDefaultConfig = function(config) {
var configPath = path.dirname(configuration.configFile) var configPath = path.dirname(configuration.configFile)
...@@ -109,7 +118,11 @@ program ...@@ -109,7 +118,11 @@ program
.parse(process.argv) .parse(process.argv)
if(typeof program.config === 'string') { if(typeof program.config === 'string') {
if (isRelativePath(program.config)) {
configuration.configFile = path.join(process.cwd(), program.config);
} else {
configuration.configFile = program.config configuration.configFile = program.config
}
} }
if(typeof program.env === 'string') { if(typeof program.env === 'string') {
......
...@@ -3,22 +3,32 @@ var Utils = require("./../utils") ...@@ -3,22 +3,32 @@ var Utils = require("./../utils")
, Helpers = require('./helpers') , Helpers = require('./helpers')
module.exports = (function() { module.exports = (function() {
var BelongsTo = function(srcDAO, targetDAO, options) { var BelongsTo = function(source, target, options) {
this.associationType = 'BelongsTo' this.associationType = 'BelongsTo'
this.source = srcDAO this.source = source
this.target = targetDAO this.target = target
this.options = options this.options = options
this.isSingleAssociation = true
this.isSelfAssociation = (this.source.tableName == this.target.tableName) this.isSelfAssociation = (this.source.tableName == this.target.tableName)
if (this.isSelfAssociation && !this.options.foreignKey && !!this.options.as) { if (this.isSelfAssociation && !this.options.foreignKey && !!this.options.as) {
this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.options.as, this.source.options.language) + "Id", this.source.options.underscored) this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.options.as, this.source.options.language) + "Id", this.source.options.underscored)
} }
this.options.useHooks = options.useHooks if (!this.options.as) {
this.options.as = Utils.singularize(this.target.tableName, this.target.options.language)
}
this.associationAccessor = this.isSelfAssociation this.associationAccessor = this.isSelfAssociation
? Utils.combineTableNames(this.target.tableName, this.options.as || this.target.tableName) ? Utils.combineTableNames(this.target.tableName, this.options.as)
: this.options.as || this.target.tableName : this.options.as
this.options.useHooks = options.useHooks
this.accessors = {
get: Utils._.camelize('get_' + this.options.as),
set: Utils._.camelize('set_' + this.options.as)
}
} }
// the id is in the source table // the id is in the source table
...@@ -40,11 +50,10 @@ module.exports = (function() { ...@@ -40,11 +50,10 @@ 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)))
, primaryKeys = Object.keys(self.target.primaryKeys) , primaryKeys = Object.keys(self.target.primaryKeys)
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id' , primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
obj[accessor] = function(params) { obj[this.accessors.get] = function(params) {
var id = this[self.identifier] var id = this[self.identifier]
, where = {} , where = {}
, options = Utils._.pick(params || {}, 'transaction') , options = Utils._.pick(params || {}, 'transaction')
...@@ -69,9 +78,8 @@ module.exports = (function() { ...@@ -69,9 +78,8 @@ module.exports = (function() {
BelongsTo.prototype.injectSetter = function(obj) { BelongsTo.prototype.injectSetter = function(obj) {
var self = this var self = this
, accessor = Utils._.camelize('set_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language)))
obj[accessor] = function(associatedObject, options) { obj[this.accessors.set] = function(associatedObject, options) {
var primaryKeys = !!associatedObject && !!associatedObject.daoFactory ? Object.keys(associatedObject.daoFactory.primaryKeys) : [] var primaryKeys = !!associatedObject && !!associatedObject.daoFactory ? Object.keys(associatedObject.daoFactory.primaryKeys) : []
, primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id' , primaryKey = primaryKeys.length === 1 ? primaryKeys[0] : 'id'
......
...@@ -8,21 +8,26 @@ module.exports = (function() { ...@@ -8,21 +8,26 @@ module.exports = (function() {
this.source = srcDAO this.source = srcDAO
this.target = targetDAO this.target = targetDAO
this.options = options this.options = options
this.isSingleAssociation = true
this.isSelfAssociation = (this.source.tableName == this.target.tableName) this.isSelfAssociation = (this.source.tableName == this.target.tableName)
if (this.isSelfAssociation && !this.options.foreignKey && !!this.options.as) { if (this.isSelfAssociation && !this.options.foreignKey && !!this.options.as) {
this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.options.as, this.target.options.language) + "Id", this.options.underscored) this.options.foreignKey = Utils._.underscoredIf(Utils.singularize(this.options.as, this.target.options.language) + "Id", this.options.underscored)
} }
if (!this.options.as) {
this.options.as = Utils.singularize(this.target.tableName, this.target.options.language)
}
this.associationAccessor = this.isSelfAssociation this.associationAccessor = this.isSelfAssociation
? Utils.combineTableNames(this.target.tableName, this.options.as || this.target.tableName) ? Utils.combineTableNames(this.target.tableName, this.options.as)
: this.options.as || this.target.tableName : this.options.as
this.options.useHooks = options.useHooks this.options.useHooks = options.useHooks
this.accessors = { this.accessors = {
get: Utils._.camelize('get_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language))), get: Utils._.camelize('get_' + this.options.as),
set: Utils._.camelize('set_' + (this.options.as || Utils.singularize(this.target.tableName, this.target.options.language))) set: Utils._.camelize('set_' + this.options.as)
} }
} }
......
...@@ -6,14 +6,14 @@ var Utils = require("./../utils") ...@@ -6,14 +6,14 @@ var Utils = require("./../utils")
/* Defines Mixin for all models. */ /* Defines Mixin for all models. */
var Mixin = module.exports = function(){} var Mixin = module.exports = function(){}
Mixin.hasOne = function(associatedDAO, options) { Mixin.hasOne = function(associatedDAOFactory, options) {
// Since this is a mixin, we'll need a unique variable name for hooks (since DAOFactory will override our hooks option) // Since this is a mixin, we'll need a unique variable name for hooks (since DAOFactory will override our hooks option)
options = options || {} options = options || {}
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks) options.hooks = options.hooks === undefined ? false : Boolean(options.hooks)
options.useHooks = options.hooks options.useHooks = options.hooks
// the id is in the foreign table // the id is in the foreign table
var association = new HasOne(this, associatedDAO, Utils._.extend((options||{}), this.options)) var association = new HasOne(this, associatedDAOFactory, Utils._.extend((options||{}), this.options))
this.associations[association.associationAccessor] = association.injectAttributes() this.associations[association.associationAccessor] = association.injectAttributes()
association.injectGetter(this.DAO.prototype); association.injectGetter(this.DAO.prototype);
...@@ -22,14 +22,14 @@ Mixin.hasOne = function(associatedDAO, options) { ...@@ -22,14 +22,14 @@ Mixin.hasOne = function(associatedDAO, options) {
return this return this
} }
Mixin.belongsTo = function(associatedDAO, options) { Mixin.belongsTo = function(associatedDAOFactory, options) {
// Since this is a mixin, we'll need a unique variable name for hooks (since DAOFactory will override our hooks option) // Since this is a mixin, we'll need a unique variable name for hooks (since DAOFactory will override our hooks option)
options = options || {} options = options || {}
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks) options.hooks = options.hooks === undefined ? false : Boolean(options.hooks)
options.useHooks = options.hooks options.useHooks = options.hooks
// the id is in this table // the id is in this table
var association = new BelongsTo(this, associatedDAO, Utils._.extend(options, this.options)) var association = new BelongsTo(this, associatedDAOFactory, Utils._.extend(options, this.options))
this.associations[association.associationAccessor] = association.injectAttributes() this.associations[association.associationAccessor] = association.injectAttributes()
association.injectGetter(this.DAO.prototype) association.injectGetter(this.DAO.prototype)
...@@ -38,14 +38,14 @@ Mixin.belongsTo = function(associatedDAO, options) { ...@@ -38,14 +38,14 @@ Mixin.belongsTo = function(associatedDAO, options) {
return this return this
} }
Mixin.hasMany = function(associatedDAO, options) { Mixin.hasMany = function(associatedDAOFactory, options) {
// Since this is a mixin, we'll need a unique variable name for hooks (since DAOFactory will override our hooks option) // Since this is a mixin, we'll need a unique variable name for hooks (since DAOFactory will override our hooks option)
options = options || {} options = options || {}
options.hooks = options.hooks === undefined ? false : Boolean(options.hooks) options.hooks = options.hooks === undefined ? false : Boolean(options.hooks)
options.useHooks = options.hooks options.useHooks = options.hooks
// the id is in the foreign table or in a connecting table // the id is in the foreign table or in a connecting table
var association = new HasMany(this, associatedDAO, Utils._.extend((options||{}), this.options)) var association = new HasMany(this, associatedDAOFactory, Utils._.extend((options||{}), this.options))
this.associations[association.associationAccessor] = association.injectAttributes() this.associations[association.associationAccessor] = association.injectAttributes()
association.injectGetter(this.DAO.prototype) association.injectGetter(this.DAO.prototype)
......
...@@ -168,7 +168,10 @@ module.exports = (function() { ...@@ -168,7 +168,10 @@ module.exports = (function() {
}) })
this.DAO.prototype.__factory = this this.DAO.prototype.__factory = this
this.DAO.prototype.daoFactory = this
this.DAO.prototype.Model = this
this.DAO.prototype.hasDefaultValues = !Utils._.isEmpty(this.DAO.prototype.defaultValues) this.DAO.prototype.hasDefaultValues = !Utils._.isEmpty(this.DAO.prototype.defaultValues)
this.DAO.prototype.daoFactoryName = this.name
return this return this
} }
...@@ -555,13 +558,23 @@ module.exports = (function() { ...@@ -555,13 +558,23 @@ module.exports = (function() {
DAOFactory.prototype.build = function(values, options) { DAOFactory.prototype.build = function(values, options) {
options = options || { isNewRecord: true, isDirty: true } options = options || { isNewRecord: true, isDirty: true }
var self = this if (options.hasOwnProperty('include') && (!options.includeValidated || !options.includeNames)) {
, instance = new this.DAO(values, this.options, options.isNewRecord) options.includeNames = []
options.include = options.include.map(function(include) {
include = validateIncludedElement.call(this, include)
options.includeNames.push(include.as)
return include
}.bind(this))
}
instance.isNewRecord = options.isNewRecord if (options.includeNames) {
instance.daoFactoryName = this.name options.includeNames = options.includeNames.concat(options.includeNames.map(function (key) {
instance.daoFactory = this return key.slice(0,1).toLowerCase() + key.slice(1)
instance.isDirty = options.isDirty }))
}
var self = this
, instance = new this.DAO(values, options)
return instance return instance
} }
...@@ -843,6 +856,9 @@ module.exports = (function() { ...@@ -843,6 +856,9 @@ module.exports = (function() {
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`. * @return {Object} A promise which fires `success`, `error`, `complete` and `sql`.
*/ */
DAOFactory.prototype.destroy = function(where, options) { DAOFactory.prototype.destroy = function(where, options) {
options = options || {}
options.force = options.force === undefined ? false : Boolean(options.force)
var self = this var self = this
, query = null , query = null
, args = [] , args = []
...@@ -855,7 +871,7 @@ module.exports = (function() { ...@@ -855,7 +871,7 @@ module.exports = (function() {
where = newWhere || where where = newWhere || where
if (self.options.timestamps && self.options.paranoid) { if (self.options.timestamps && self.options.paranoid && options.force === false) {
var attr = Utils._.underscoredIf(self.options.deletedAt, self.options.underscored) var attr = Utils._.underscoredIf(self.options.deletedAt, self.options.underscored)
var attrValueHash = {} var attrValueHash = {}
attrValueHash[attr] = Utils.now() attrValueHash[attr] = Utils.now()
...@@ -1118,18 +1134,20 @@ module.exports = (function() { ...@@ -1118,18 +1134,20 @@ module.exports = (function() {
options = options || {} options = options || {}
options.where = options.where || {} options.where = options.where || {}
var deletedAtCol = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored)
// Don't overwrite our explicit deletedAt search value if we provide one // Don't overwrite our explicit deletedAt search value if we provide one
if (!!options.where[this.options.deletedAt]) { if (!!options.where[deletedAtCol]) {
return options return options
} }
if (typeof options.where === "string") { if (typeof options.where === "string") {
options.where += ' AND ' + this.QueryInterface.quoteIdentifier(this.options.deletedAt) + ' IS NULL ' options.where += ' AND ' + this.QueryInterface.quoteIdentifier(deletedAtCol) + ' IS NULL '
} }
else if (Array.isArray(options.where)) { else if (Array.isArray(options.where)) {
options.where[0] += ' AND ' + this.QueryInterface.quoteIdentifier(this.options.deletedAt) + ' IS NULL ' options.where[0] += ' AND ' + this.QueryInterface.quoteIdentifier(deletedAtCol) + ' IS NULL '
} else { } else {
options.where[this.options.deletedAt] = null options.where[deletedAtCol] = null
} }
} }
...@@ -1215,6 +1233,11 @@ module.exports = (function() { ...@@ -1215,6 +1233,11 @@ module.exports = (function() {
var usesAlias = (include.as !== include.daoFactory.tableName) var usesAlias = (include.as !== include.daoFactory.tableName)
, association = (usesAlias ? this.getAssociationByAlias(include.as) : this.getAssociation(include.daoFactory)) , association = (usesAlias ? this.getAssociationByAlias(include.as) : this.getAssociation(include.daoFactory))
// If single (1:1) association, we singularize the alias, so it will match the automatically generated alias of belongsTo/HasOne
if (association && !usesAlias && association.isSingleAssociation) {
include.as = Utils.singularize(include.daoFactory.tableName, include.daoFactory.options.language)
}
// check if the current daoFactory is actually associated with the passed daoFactory // check if the current daoFactory is actually associated with the passed daoFactory
if (!!association && (!association.options.as || (association.options.as === include.as))) { if (!!association && (!association.options.as || (association.options.as === include.as))) {
include.association = association include.association = association
......
...@@ -3,16 +3,22 @@ var Utils = require("./utils") ...@@ -3,16 +3,22 @@ var Utils = require("./utils")
, DaoValidator = require("./dao-validator") , DaoValidator = require("./dao-validator")
, DataTypes = require("./data-types") , DataTypes = require("./data-types")
, hstore = require('./dialects/postgres/hstore') , hstore = require('./dialects/postgres/hstore')
, _ = require('lodash')
module.exports = (function() { module.exports = (function() {
var DAO = function(values, options, isNewRecord) { var DAO = function(values, options) {
this.dataValues = {} this.dataValues = {}
this.__options = options this.__options = this.__factory.options
this.hasPrimaryKeys = options.hasPrimaryKeys this.options = options
this.selectedValues = values this.hasPrimaryKeys = this.__factory.options.hasPrimaryKeys
// What is selected values even used for?
this.selectedValues = options.include ? _.omit(values, options.includeNames) : values
this.__eagerlyLoadedAssociations = [] this.__eagerlyLoadedAssociations = []
this.isNewRecord = options.isNewRecord
initAttributes.call(this, values, isNewRecord) initAttributes.call(this, values, options)
this.isDirty = options.isDirty
} }
Utils._.extend(DAO.prototype, Mixin.prototype) Utils._.extend(DAO.prototype, Mixin.prototype)
...@@ -36,17 +42,7 @@ module.exports = (function() { ...@@ -36,17 +42,7 @@ module.exports = (function() {
Object.defineProperty(DAO.prototype, 'values', { Object.defineProperty(DAO.prototype, 'values', {
get: function() { get: function() {
var result = {} return this.dataValues
, self = this
this.attributes.concat(this.__eagerlyLoadedAssociations).forEach(function(attr) {
result[attr] = self.dataValues.hasOwnProperty(attr)
? self.dataValues[attr]
: self[attr]
;
})
return result
} }
}) })
...@@ -104,7 +100,7 @@ module.exports = (function() { ...@@ -104,7 +100,7 @@ module.exports = (function() {
options = Utils._.extend({}, options, fieldsOrOptions) options = Utils._.extend({}, options, fieldsOrOptions)
var self = this var self = this
, values = options.fields ? {} : this.dataValues , values = options.fields ? {} : (this.options.includeNames ? _.omit(this.dataValues, this.options.includeNames) : this.dataValues)
, updatedAtAttr = Utils._.underscoredIf(this.__options.updatedAt, this.__options.underscored) , updatedAtAttr = Utils._.underscoredIf(this.__options.updatedAt, this.__options.underscored)
, createdAtAttr = Utils._.underscoredIf(this.__options.createdAt, this.__options.underscored) , createdAtAttr = Utils._.underscoredIf(this.__options.createdAt, this.__options.underscored)
...@@ -215,7 +211,7 @@ module.exports = (function() { ...@@ -215,7 +211,7 @@ module.exports = (function() {
return emitter.emit('error', err) return emitter.emit('error', err)
} }
result.dataValues = newValues result.dataValues = _.extend(result.dataValues, newValues)
emitter.emit('success', result) emitter.emit('success', result)
}) })
}) })
...@@ -241,7 +237,7 @@ module.exports = (function() { ...@@ -241,7 +237,7 @@ module.exports = (function() {
this.__factory.find({ this.__factory.find({
where: where, where: where,
limit: 1, limit: 1,
include: this.__eagerlyLoadedOptions || [] include: this.options.include || []
}, options) }, options)
.on('sql', function(sql) { emitter.emit('sql', sql) }) .on('sql', function(sql) { emitter.emit('sql', sql) })
.on('error', function(error) { emitter.emit('error', error) }) .on('error', function(error) { emitter.emit('error', error) })
...@@ -327,6 +323,9 @@ module.exports = (function() { ...@@ -327,6 +323,9 @@ module.exports = (function() {
} }
DAO.prototype.destroy = function(options) { DAO.prototype.destroy = function(options) {
options = options || {}
options.force = options.force === undefined ? false : Boolean(options.force)
var self = this var self = this
, query = null , query = null
...@@ -336,7 +335,7 @@ module.exports = (function() { ...@@ -336,7 +335,7 @@ module.exports = (function() {
return emitter.emit('error', err) return emitter.emit('error', err)
} }
if (self.__options.timestamps && self.__options.paranoid) { if (self.__options.timestamps && self.__options.paranoid && options.force === false) {
var attr = Utils._.underscoredIf(self.__options.deletedAt, self.__options.underscored) var attr = Utils._.underscoredIf(self.__options.deletedAt, self.__options.underscored)
self.dataValues[attr] = new Date() self.dataValues[attr] = new Date()
query = self.save(options) query = self.save(options)
...@@ -469,25 +468,20 @@ module.exports = (function() { ...@@ -469,25 +468,20 @@ module.exports = (function() {
} }
DAO.prototype.toJSON = function() { DAO.prototype.toJSON = function() {
return this.values; return this.dataValues;
} }
// private // private
var initAttributes = function(values, isNewRecord) { var initAttributes = function(values, options) {
// set id to null if not passed as value, a newly created dao has no id // set id to null if not passed as value, a newly created dao has no id
var defaults = this.hasPrimaryKeys ? {} : { id: null }, var defaults = this.hasPrimaryKeys ? {} : { id: null },
attrs = {}, attrs = {},
key; key;
// add all passed values to the dao and store the attribute names in this.attributes // add all passed values to the dao and store the attribute names in this.attributes
for (key in values) {
if (values.hasOwnProperty(key)) {
this.addAttribute(key, values[key])
}
}
if (isNewRecord) { if (options.isNewRecord) {
if (this.hasDefaultValues) { if (this.hasDefaultValues) {
Utils._.each(this.defaultValues, function(valueFn, key) { Utils._.each(this.defaultValues, function(valueFn, key) {
if (!defaults.hasOwnProperty(key)) { if (!defaults.hasOwnProperty(key)) {
...@@ -532,22 +526,43 @@ module.exports = (function() { ...@@ -532,22 +526,43 @@ module.exports = (function() {
} }
for (key in attrs) { for (key in attrs) {
this.addAttribute(key, attrs[key]) if (options.include && options.includeNames.indexOf(key) !== -1) {
} if (!Array.isArray(attrs[key])) attrs[key] = [attrs[key]];
// this.addAttributes COMPLETELY destroys the structure of our DAO due to __defineGetter__ resetting the object var include = _.find(options.include, function (include) {
// so now we have to rebuild for bulkInserts, bulkUpdates, etc. return include.as === key || (include.as.slice(0,1).toLowerCase() + include.as.slice(1)) === key
var rebuild = {} })
var association = include.association
, self = this
// Get the correct map.... var accessor = Utils._.camelize(key)
Utils._.each(this.attributes, function(key) {
if (this.dataValues.hasOwnProperty(key)) { // downcase the first char
rebuild[key] = this.dataValues[key] accessor = accessor.slice(0,1).toLowerCase() + accessor.slice(1)
attrs[key].forEach(function(data) {
var daoInstance = include.daoFactory.build(data, { isNewRecord: false, isDirty: false })
, isEmpty = !Utils.firstValueOfHash(daoInstance.identifiers)
if (association.isSingleAssociation) {
accessor = Utils.singularize(accessor, self.sequelize.language)
self.dataValues[accessor] = isEmpty ? null : daoInstance
self[accessor] = self.dataValues[accessor]
} else {
if (!self.dataValues[accessor]) {
self.dataValues[accessor] = []
self[accessor] = self.dataValues[accessor]
} }
}.bind(this))
// This allows for aliases, etc. if (!isEmpty) {
this.dataValues = Utils._.extend(rebuild, this.dataValues) self.dataValues[accessor].push(daoInstance)
}
}
}.bind(this))
} else {
this.addAttribute(key, attrs[key])
}
}
} }
return DAO return DAO
......
...@@ -188,7 +188,7 @@ module.exports = { ...@@ -188,7 +188,7 @@ module.exports = {
FLOAT: FLOAT, FLOAT: FLOAT,
NOW: 'NOW', NOW: 'NOW',
BLOB: BLOB, BLOB: BLOB,
UUID: 'CHAR(36)', UUID: 'UUID',
UUIDV1: 'UUIDV1', UUIDV1: 'UUIDV1',
UUIDV4: 'UUIDV4', UUIDV4: 'UUIDV4',
......
...@@ -388,7 +388,7 @@ module.exports = (function() { ...@@ -388,7 +388,7 @@ module.exports = (function() {
var table = include.daoFactory.tableName var table = include.daoFactory.tableName
, as = include.as , as = include.as
if (!include.association.connectorDAO) { if (!(Object(include.association.through) === include.association.through)) {
var primaryKeysLeft = ((include.association.associationType === 'BelongsTo') ? Object.keys(include.association.target.primaryKeys) : Object.keys(include.association.source.primaryKeys)) var primaryKeysLeft = ((include.association.associationType === 'BelongsTo') ? Object.keys(include.association.target.primaryKeys) : Object.keys(include.association.source.primaryKeys))
, tableLeft = ((include.association.associationType === 'BelongsTo') ? include.as : tableName) , tableLeft = ((include.association.associationType === 'BelongsTo') ? include.as : tableName)
, attrLeft = ((primaryKeysLeft.length !== 1) ? 'id' : primaryKeysLeft[0]) , attrLeft = ((primaryKeysLeft.length !== 1) ? 'id' : primaryKeysLeft[0])
...@@ -407,7 +407,7 @@ module.exports = (function() { ...@@ -407,7 +407,7 @@ module.exports = (function() {
, identTarget = include.association.foreignIdentifier , identTarget = include.association.foreignIdentifier
, attrTarget = ((!include.association.target.hasPrimaryKeys || primaryKeysTarget.length !== 1) ? 'id' : primaryKeysTarget[0]) , attrTarget = ((!include.association.target.hasPrimaryKeys || primaryKeysTarget.length !== 1) ? 'id' : primaryKeysTarget[0])
var tableJunction = include.association.connectorDAO.tableName var tableJunction = include.association.through.tableName
joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(tableJunction) + " ON " + this.quoteIdentifier(tableSource) + "." + this.quoteIdentifier(attrSource) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identSource) joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(tableJunction) + " ON " + this.quoteIdentifier(tableSource) + "." + this.quoteIdentifier(attrSource) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identSource)
joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(table) + " AS " + this.quoteIdentifier(as) + " ON " + this.quoteIdentifier(tableTarget) + "." + this.quoteIdentifier(attrTarget) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identTarget) joinQuery += " LEFT OUTER JOIN " + this.quoteIdentifier(table) + " AS " + this.quoteIdentifier(as) + " ON " + this.quoteIdentifier(tableTarget) + "." + this.quoteIdentifier(attrTarget) + " = " + this.quoteIdentifier(tableJunction) + "." + this.quoteIdentifier(identTarget)
} }
...@@ -635,14 +635,14 @@ module.exports = (function() { ...@@ -635,14 +635,14 @@ module.exports = (function() {
joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName) joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName)
joins += ' ON ' + self.quoteIdentifiers(association.source.tableName + '.' + association.identifier) joins += ' ON ' + self.quoteIdentifiers(association.source.tableName + '.' + association.identifier)
joins += ' = ' + self.quoteIdentifiers(association.target.tableName + '.' + association.target.autoIncrementField) joins += ' = ' + self.quoteIdentifiers(association.target.tableName + '.' + association.target.autoIncrementField)
} else if (association.connectorDAO){ } else if (Object(association.through) === association.through) {
joinedTables[association.connectorDAO.tableName] = true; joinedTables[association.through.tableName] = true;
joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.connectorDAO.tableName) joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.through.tableName)
joins += ' ON ' + self.quoteIdentifiers(association.source.tableName + '.' + association.source.autoIncrementField) joins += ' ON ' + self.quoteIdentifiers(association.source.tableName + '.' + association.source.autoIncrementField)
joins += ' = ' + self.quoteIdentifiers(association.connectorDAO.tableName + '.' + association.identifier) joins += ' = ' + self.quoteIdentifiers(association.through.tableName + '.' + association.identifier)
joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName) joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName)
joins += ' ON ' + self.quoteIdentifiers(association.connectorDAO.tableName + '.' + association.foreignIdentifier) joins += ' ON ' + self.quoteIdentifiers(association.through.tableName + '.' + association.foreignIdentifier)
joins += ' = ' + self.quoteIdentifiers(association.target.tableName + '.' + association.target.autoIncrementField) joins += ' = ' + self.quoteIdentifiers(association.target.tableName + '.' + association.target.autoIncrementField)
} else { } else {
joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName) joins += ' LEFT JOIN ' + self.quoteIdentifiers(association.target.tableName)
...@@ -687,7 +687,7 @@ module.exports = (function() { ...@@ -687,7 +687,7 @@ module.exports = (function() {
if (Array.isArray(value)) { if (Array.isArray(value)) {
result.push(this.arrayValue(value, key, _key, dao)) result.push(this.arrayValue(value, key, _key, dao))
} else if ((value) && (typeof value == 'object') && !(value instanceof Date)) { } else if ((value) && (typeof value == 'object') && !(value instanceof Date) && !Buffer.isBuffer(value)) {
if (!!value.join) { if (!!value.join) {
//using as sentinel for join column => value //using as sentinel for join column => value
_value = this.quoteIdentifiers(value.join) _value = this.quoteIdentifiers(value.join)
......
var Utils = require('../../utils') var Utils = require('../../utils')
, CustomEventEmitter = require("../../emitters/custom-event-emitter") , CustomEventEmitter = require("../../emitters/custom-event-emitter")
, Dot = require('dottie') , Dot = require('dottie')
, _ = require('lodash')
module.exports = (function() { module.exports = (function() {
var AbstractQuery = function(database, sequelize, callee, options) {} var AbstractQuery = function(database, sequelize, callee, options) {}
...@@ -100,39 +101,6 @@ module.exports = (function() { ...@@ -100,39 +101,6 @@ module.exports = (function() {
} }
/** /**
Shortcut methods (success, ok) for listening for success events.
Params:
- fct: A function that gets executed once the *success* event was triggered.
Result:
The function returns the instance of the query.
*/
AbstractQuery.prototype.success =
AbstractQuery.prototype.ok =
function(fct) {
this.on('success', fct)
return this
}
/**
Shortcut methods (failure, fail, error) for listening for error events.
Params:
- fct: A function that gets executed once the *error* event was triggered.
Result:
The function returns the instance of the query.
*/
AbstractQuery.prototype.failure =
AbstractQuery.prototype.fail =
AbstractQuery.prototype.error =
function(fct) {
this.on('error', fct)
return this
}
/**
* This function is a wrapper for private methods. * This function is a wrapper for private methods.
* *
* @param {String} fctName The name of the private method. * @param {String} fctName The name of the private method.
...@@ -167,10 +135,13 @@ module.exports = (function() { ...@@ -167,10 +135,13 @@ module.exports = (function() {
if (!this.options.include) { if (!this.options.include) {
return null return null
} }
if (!this.options.includeNames) {
var tableNames = this.options.include.map(function(include) { this.options.includeNames = this.options.include.map(function(include) {
return include.as return include.as
}).filter(function(include) { })
}
var tableNames = this.options.includeNames.filter(function(include) {
return attribute.indexOf(include + '.') === 0 return attribute.indexOf(include + '.') === 0
}) })
...@@ -181,20 +152,6 @@ module.exports = (function() { ...@@ -181,20 +152,6 @@ module.exports = (function() {
} }
} }
var queryResultHasJoin = function(results) {
if (!!results[0]) {
var keys = Object.keys(results[0])
for (var i = 0; i < keys.length; i++) {
if (!!findTableNameInAttribute.call(this, keys[i])) {
return true
}
}
}
return false
}
var isInsertQuery = function(results, metaData) { var isInsertQuery = function(results, metaData) {
var result = true var result = true
...@@ -244,6 +201,7 @@ module.exports = (function() { ...@@ -244,6 +201,7 @@ module.exports = (function() {
var handleSelectQuery = function(results) { var handleSelectQuery = function(results) {
var result = null var result = null
// Raw queries
if (this.options.raw) { if (this.options.raw) {
result = results.map(function(result) { result = results.map(function(result) {
var o = {} var o = {}
...@@ -258,8 +216,22 @@ module.exports = (function() { ...@@ -258,8 +216,22 @@ module.exports = (function() {
}) })
result = result.map(Dot.transform) result = result.map(Dot.transform)
// Queries with include
} else if (this.options.hasJoin === true) { } else if (this.options.hasJoin === true) {
result = transformRowsWithEagerLoadingIntoDaos.call(this, results) this.options.includeNames = this.options.include.map(function (include) {
return include.as
})
results = groupJoinData.call(this, results)
result = results.map(function(result) {
return this.callee.build(result, {
isNewRecord: false,
isDirty: false,
include:this.options.include,
includeNames: this.options.includeNames,
includeValidated: true
})
}.bind(this))
} else if (this.options.hasJoinTableModel === true) { } else if (this.options.hasJoinTableModel === true) {
result = results.map(function(result) { result = results.map(function(result) {
result = Dot.transform(result) result = Dot.transform(result)
...@@ -275,6 +247,8 @@ module.exports = (function() { ...@@ -275,6 +247,8 @@ module.exports = (function() {
return mainDao return mainDao
}.bind(this)) }.bind(this))
// Regular queries
} else { } else {
result = results.map(function(result) { result = results.map(function(result) {
return this.callee.build(result, { isNewRecord: false, isDirty: false }) return this.callee.build(result, { isNewRecord: false, isDirty: false })
...@@ -289,75 +263,6 @@ module.exports = (function() { ...@@ -289,75 +263,6 @@ module.exports = (function() {
return result return result
} }
var transformRowsWithEagerLoadingIntoDaos = function(results) {
var result = []
result = prepareJoinData.call(this, results)
result = groupDataByCalleeFactory.call(this, result).map(function(result) {
return transformRowWithEagerLoadingIntoDao.call(this, result)
}.bind(this))
return result
}
var transformRowWithEagerLoadingIntoDao = function(result, dao) {
// let's build the actual dao instance first...
dao = dao || this.callee.build(result[this.callee.tableName], { isNewRecord: false, isDirty: false })
// ... and afterwards the prefetched associations
for (var tableName in result) {
if (result.hasOwnProperty(tableName) && (tableName !== this.callee.tableName)) {
buildAssociatedDaoInstances.call(this, tableName, result[tableName], dao)
}
}
return dao
}
var buildAssociatedDaoInstances = function(tableName, associationData, dao) {
var associatedDaoFactory = this.sequelize.daoFactoryManager.getDAO(tableName, { attribute: 'tableName' })
, association = null
, self = this
if (!!associatedDaoFactory) {
association = this.callee.getAssociation(associatedDaoFactory)
} else {
associatedDaoFactory = this.sequelize.daoFactoryManager.getDAO(Utils.pluralize(tableName, this.sequelize.language), { attribute: 'tableName' })
if (!!associatedDaoFactory) {
association = this.callee.getAssociation(associatedDaoFactory)
} else {
association = this.callee.getAssociationByAlias(tableName)
associatedDaoFactory = association.target
}
}
var accessor = Utils._.camelize(tableName)
// downcase the first char
accessor = accessor.slice(0,1).toLowerCase() + accessor.slice(1)
associationData.forEach(function(data) {
var daoInstance = associatedDaoFactory.build(data, { isNewRecord: false, isDirty: false })
, isEmpty = !Utils.firstValueOfHash(daoInstance.identifiers)
if (['BelongsTo', 'HasOne'].indexOf(association.associationType) > -1) {
accessor = Utils.singularize(accessor, self.sequelize.language)
dao[accessor] = isEmpty ? null : daoInstance
} else {
dao[accessor] = dao[accessor] || []
if (!isEmpty) {
dao[accessor].push(daoInstance)
}
}
// add the accessor to the eagerly loaded associations array
dao.__eagerlyLoadedAssociations = Utils._.uniq(dao.__eagerlyLoadedAssociations.concat([accessor]))
dao.__eagerlyLoadedOptions = (this.options && this.options.include) ? this.options.include : []
}.bind(this))
}
var isShowOrDescribeQuery = function() { var isShowOrDescribeQuery = function() {
var result = false var result = false
...@@ -381,15 +286,18 @@ module.exports = (function() { ...@@ -381,15 +286,18 @@ module.exports = (function() {
the associated data by the callee. the associated data by the callee.
Example: Example:
groupDataByCalleeFactory([ groupJoinData([
{ {
callee: { some: 'data', id: 1 }, some: 'data',
id: 1,
association: { foo: 'bar', id: 1 } association: { foo: 'bar', id: 1 }
}, { }, {
callee: { some: 'data', id: 1 }, some: 'data',
id: 1,
association: { foo: 'bar', id: 2 } association: { foo: 'bar', id: 2 }
}, { }, {
callee: { some: 'data', id: 1 }, some: 'data',
id: 1,
association: { foo: 'bar', id: 3 } association: { foo: 'bar', id: 3 }
} }
]) ])
...@@ -399,7 +307,8 @@ module.exports = (function() { ...@@ -399,7 +307,8 @@ module.exports = (function() {
[ [
{ {
callee: { some: 'data', id: 1 }, some: 'data',
id: 1,
association: [ association: [
{ foo: 'bar', id: 1 }, { foo: 'bar', id: 1 },
{ foo: 'bar', id: 2 }, { foo: 'bar', id: 2 },
...@@ -408,67 +317,38 @@ module.exports = (function() { ...@@ -408,67 +317,38 @@ module.exports = (function() {
} }
] ]
*/ */
var groupDataByCalleeFactory = function(data) {
var result = []
, calleeTableName = this.callee.tableName
data.forEach(function(row) { var groupJoinData = function(data) {
var calleeData = row[calleeTableName] var self = this
, existingEntry = result.filter(function(groupedRow) { , results = []
return Utils._.isEqual(groupedRow[calleeTableName], calleeData) , existingResult
})[0] , calleeData
data.forEach(function (row) {
row = Dot.transform(row)
calleeData = _.omit(row, self.options.includeNames)
if (!existingEntry) { existingResult = _.find(results, function (result) {
existingEntry = {} return Utils._.isEqual(_.omit(result, self.options.includeNames), calleeData)
result.push(existingEntry) })
existingEntry[calleeTableName] = calleeData
if (!existingResult) {
results.push(existingResult = calleeData)
} }
for (var attrName in row) { for (var attrName in row) {
if (row.hasOwnProperty(attrName) && (attrName !== calleeTableName)) { if (row.hasOwnProperty(attrName) && Object(row[attrName]) === row[attrName] && self.options.includeNames.indexOf(attrName) !== -1) {
existingEntry[attrName] = existingEntry[attrName] || [] existingResult[attrName] = existingResult[attrName] || []
var attrRowExists = existingEntry[attrName].some(function(attrRow) { var attrRowExists = existingResult[attrName].some(function(attrRow) {
return Utils._.isEqual(attrRow, row[attrName]) return Utils._.isEqual(attrRow, row[attrName])
}) })
if (!attrRowExists) { if (!attrRowExists) {
existingEntry[attrName].push(row[attrName]) existingResult[attrName].push(row[attrName])
} }
} }
} }
}) })
return results
return result
}
/**
* This function will prepare the result of select queries with joins.
*
* @param {Array} data This array contains objects.
* @return {Array} The array will have the needed format for groupDataByCalleeFactory.
*/
var prepareJoinData = function(data) {
var result = data.map(function(row) {
var nestedRow = {}
for (var key in row) {
if (row.hasOwnProperty(key)) {
var tableName = findTableNameInAttribute.call(this, key)
if (!!tableName) {
nestedRow[tableName] = nestedRow[tableName] || {}
nestedRow[tableName][key.replace(tableName + '.', '')] = row[key]
} else {
nestedRow[this.callee.tableName] = nestedRow[this.callee.tableName] || {}
nestedRow[this.callee.tableName][key] = row[key]
}
}
}
return nestedRow
}.bind(this))
return result
} }
return AbstractQuery return AbstractQuery
......
...@@ -88,6 +88,7 @@ module.exports = (function() { ...@@ -88,6 +88,7 @@ module.exports = (function() {
.on('error', function(err) { .on('error', function(err) {
errorDetected = true errorDetected = true
self.emit('sql', self.sql) self.emit('sql', self.sql)
err.sql = sql
self.emit('error', err, self.callee) self.emit('error', err, self.callee)
}) })
.on('end', function(info) { .on('end', function(info) {
......
...@@ -50,7 +50,7 @@ module.exports = (function() { ...@@ -50,7 +50,7 @@ module.exports = (function() {
for (var attr in attributes) { for (var attr in attributes) {
if (attributes.hasOwnProperty(attr)) { if (attributes.hasOwnProperty(attr)) {
var dataType = attributes[attr] var dataType = this.mysqlDataTypeMapping(tableName, attr, attributes[attr])
if (Utils._.includes(dataType, 'PRIMARY KEY')) { if (Utils._.includes(dataType, 'PRIMARY KEY')) {
primaryKeys.push(attr) primaryKeys.push(attr)
...@@ -117,7 +117,7 @@ module.exports = (function() { ...@@ -117,7 +117,7 @@ module.exports = (function() {
attrString.push(Utils._.template('`<%= attrName %>` <%= definition %>')({ attrString.push(Utils._.template('`<%= attrName %>` <%= definition %>')({
attrName: attrName, attrName: attrName,
definition: definition definition: this.mysqlDataTypeMapping(tableName, attrName, definition)
})) }))
} }
...@@ -496,6 +496,14 @@ module.exports = (function() { ...@@ -496,6 +496,14 @@ module.exports = (function() {
*/ */
dropForeignKeyQuery: function(tableName, foreignKey) { dropForeignKeyQuery: function(tableName, foreignKey) {
return 'ALTER TABLE ' + this.quoteIdentifier(tableName) + ' DROP FOREIGN KEY ' + this.quoteIdentifier(foreignKey) + ';' return 'ALTER TABLE ' + this.quoteIdentifier(tableName) + ' DROP FOREIGN KEY ' + this.quoteIdentifier(foreignKey) + ';'
},
mysqlDataTypeMapping: function(tableName, attr, dataType) {
if (Utils._.includes(dataType, 'UUID')) {
dataType = dataType.replace(/UUID/, 'CHAR(36) BINARY')
}
return dataType
} }
} }
......
...@@ -27,6 +27,7 @@ module.exports = (function() { ...@@ -27,6 +27,7 @@ module.exports = (function() {
this.emit('sql', this.sql) this.emit('sql', this.sql)
if (err) { if (err) {
err.sql = sql
this.emit('error', err, this.callee) this.emit('error', err, this.callee)
} else { } else {
this.emit('success', this.formatResults(results)) this.emit('success', this.formatResults(results))
......
...@@ -27,6 +27,7 @@ module.exports = (function() { ...@@ -27,6 +27,7 @@ module.exports = (function() {
this.disconnectTimeoutId = null this.disconnectTimeoutId = null
this.pendingQueries = 0 this.pendingQueries = 0
this.clientDrained = true
this.maxConcurrentQueries = (this.config.maxConcurrentQueries || 50) this.maxConcurrentQueries = (this.config.maxConcurrentQueries || 50)
process.on('exit', function() { process.on('exit', function() {
...@@ -51,6 +52,7 @@ module.exports = (function() { ...@@ -51,6 +52,7 @@ module.exports = (function() {
var self = this var self = this
self.pendingQueries++ self.pendingQueries++
self.clientDrained = false
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
self.connect() self.connect()
...@@ -64,8 +66,6 @@ module.exports = (function() { ...@@ -64,8 +66,6 @@ module.exports = (function() {
.complete(function(err) { .complete(function(err) {
self.endQuery.call(self) self.endQuery.call(self)
done && done(err) }) done && done(err) })
.success(function(results) { self.endQuery.call(self) })
.error(function(err) { self.endQuery.call(self) })
.proxy(emitter) .proxy(emitter)
}) })
}).run() }).run()
...@@ -152,6 +152,12 @@ module.exports = (function() { ...@@ -152,6 +152,12 @@ module.exports = (function() {
this.client.connect(function(err, client, done) { this.client.connect(function(err, client, done) {
connectCallback(err, client || self.client, done) connectCallback(err, client || self.client, done)
}) })
// Closes a client correctly even if we have backed up queries
// https://github.com/brianc/node-postgres/pull/346
this.client.on('drain', function() {
self.clientDrained = true
})
} }
} }
...@@ -168,9 +174,9 @@ module.exports = (function() { ...@@ -168,9 +174,9 @@ module.exports = (function() {
} }
if (this.client) { if (this.client) {
// Closes a client correctly even if we have backed up queries if (this.clientDrained) {
// https://github.com/brianc/node-postgres/pull/346 this.client.end()
this.client.on('drain', this.client.end.bind(this.client)) }
this.client = null this.client = null
} }
......
...@@ -256,9 +256,12 @@ module.exports = (function() { ...@@ -256,9 +256,12 @@ module.exports = (function() {
}, },
insertQuery: function(tableName, attrValueHash, attributes) { insertQuery: function(tableName, attrValueHash, attributes) {
var query
, valueQuery = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>) RETURNING *;"
, emptyQuery = "INSERT INTO <%= table %> DEFAULT VALUES RETURNING *;"
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull) attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>) RETURNING *;"
// Remove serials that are null or undefined, which causes an error in PG // Remove serials that are null or undefined, which causes an error in PG
Utils._.forEach(attrValueHash, function(value, key, hash) { Utils._.forEach(attrValueHash, function(value, key, hash) {
if (tables[tableName]) { if (tables[tableName]) {
...@@ -284,17 +287,32 @@ module.exports = (function() { ...@@ -284,17 +287,32 @@ module.exports = (function() {
, values: rowValues.join(",") , values: rowValues.join(",")
} }
query = replacements.attributes.length ? valueQuery : emptyQuery
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
bulkInsertQuery: function(tableName, attrValueHashes) { bulkInsertQuery: function(tableName, attrValueHashes) {
var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %> RETURNING *;" var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %> RETURNING *;"
, tuples = [] , tuples = []
, serials = []
Utils._.forEach(attrValueHashes, function(attrValueHash, i) {
if (i === 0) {
Utils._.forEach(attrValueHash, function(value, key, hash) {
if (tables[tableName] && tables[tableName][key]) {
if (['bigserial', 'serial'].indexOf(tables[tableName][key]) !== -1) {
serials.push(key)
}
}
})
}
Utils._.forEach(attrValueHashes, function(attrValueHash) {
removeSerialsFromHash(tableName, attrValueHash)
tuples.push("(" + tuples.push("(" +
Utils._.values(attrValueHash).map(function(value){ Utils._.map(attrValueHash, function(value, key){
if (serials.indexOf(key) !== -1) {
return 'DEFAULT';
}
return this.escape(value) return this.escape(value)
}.bind(this)).join(",") + }.bind(this)).join(",") +
")") ")")
...@@ -435,8 +453,8 @@ module.exports = (function() { ...@@ -435,8 +453,8 @@ module.exports = (function() {
return Utils._.compact([ return Utils._.compact([
"CREATE", options.indicesType, "INDEX", this.quoteIdentifiers(options.indexName), "CREATE", options.indicesType, "INDEX", this.quoteIdentifiers(options.indexName),
(options.indexType ? ('USING ' + options.indexType) : undefined), "ON", this.quoteIdentifiers(tableName), (options.indexType ? ('USING ' + options.indexType) : undefined),
"ON", this.quoteIdentifiers(tableName), '(' + transformedAttributes.join(', ') + ')' '(' + transformedAttributes.join(', ') + ')'
]).join(' ') ]).join(' ')
}, },
......
...@@ -36,6 +36,7 @@ module.exports = (function() { ...@@ -36,6 +36,7 @@ module.exports = (function() {
query.on('error', function(err) { query.on('error', function(err) {
receivedError = true receivedError = true
err.sql = sql
self.emit('error', err, self.callee) self.emit('error', err, self.callee)
}) })
......
...@@ -156,7 +156,9 @@ module.exports = (function() { ...@@ -156,7 +156,9 @@ module.exports = (function() {
insertQuery: function(tableName, attrValueHash) { insertQuery: function(tableName, attrValueHash) {
attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull) attrValueHash = Utils.removeNullValuesFromHash(attrValueHash, this.options.omitNull)
var query = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>);"; var query
, valueQuery = "INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>);"
, emptyQuery = "INSERT INTO <%= table %> DEFAULT VALUES;"
var replacements = { var replacements = {
table: this.quoteIdentifier(tableName), table: this.quoteIdentifier(tableName),
...@@ -166,6 +168,7 @@ module.exports = (function() { ...@@ -166,6 +168,7 @@ module.exports = (function() {
}.bind(this)).join(",") }.bind(this)).join(",")
} }
query = replacements.attributes.length ? valueQuery : emptyQuery
return Utils._.template(query)(replacements) return Utils._.template(query)(replacements)
}, },
......
...@@ -44,6 +44,7 @@ module.exports = (function() { ...@@ -44,6 +44,7 @@ module.exports = (function() {
self.emit('sql', self.sql) self.emit('sql', self.sql)
if (err) { if (err) {
err.sql = self.sql
onFailure.call(self, err) onFailure.call(self, err)
} else { } else {
this.columnTypes = columnTypes this.columnTypes = columnTypes
......
...@@ -28,6 +28,15 @@ module.exports = (function() { ...@@ -28,6 +28,15 @@ module.exports = (function() {
return this return this
} }
/**
Shortcut methods (success, ok) for listening for success events.
Params:
- fct: A function that gets executed once the *success* event was triggered.
Result:
The function returns the instance of the query.
*/
CustomEventEmitter.prototype.success = CustomEventEmitter.prototype.success =
CustomEventEmitter.prototype.ok = CustomEventEmitter.prototype.ok =
function(fct) { function(fct) {
...@@ -35,6 +44,15 @@ module.exports = (function() { ...@@ -35,6 +44,15 @@ module.exports = (function() {
return this return this
} }
/**
Shortcut methods (failure, fail, error) for listening for error events.
Params:
- fct: A function that gets executed once the *error* event was triggered.
Result:
The function returns the instance of the query.
*/
CustomEventEmitter.prototype.failure = CustomEventEmitter.prototype.failure =
CustomEventEmitter.prototype.fail = CustomEventEmitter.prototype.fail =
CustomEventEmitter.prototype.error = CustomEventEmitter.prototype.error =
......
...@@ -660,6 +660,7 @@ module.exports = (function() { ...@@ -660,6 +660,7 @@ module.exports = (function() {
var sql = this.QueryGenerator.selectQuery(tableName, options, factory) 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')
} }
......
...@@ -79,7 +79,7 @@ module.exports = (function() { ...@@ -79,7 +79,7 @@ module.exports = (function() {
define: {}, define: {},
query: {}, query: {},
sync: {}, sync: {},
logging: console.log, logging: false,
omitNull: false, omitNull: false,
queue: true, queue: true,
native: false, native: false,
......
Utils = require('./utils') var Utils = require('./utils')
var TransactionManager = module.exports = function(sequelize) { var TransactionManager = module.exports = function(sequelize) {
this.sequelize = sequelize this.sequelize = sequelize
......
var cJSON = require('circular-json') var cJSON = require('circular-json')
, _ = require('lodash') // Don't require Utils here, as it creates a circular dependency
var ParameterValidator = module.exports = { var ParameterValidator = module.exports = {
check: function(value, expectation, options) { check: function(value, expectation, options) {
options = Utils._.extend({ options = _.extend({
throwError: true, throwError: true,
deprecated: false, deprecated: false,
deprecationWarning: generateDeprecationWarning(value, expectation, options), deprecationWarning: generateDeprecationWarning(value, expectation, options),
......
...@@ -64,7 +64,8 @@ ...@@ -64,7 +64,8 @@
"chai-spies": "~0.5.1", "chai-spies": "~0.5.1",
"lcov-result-merger": "0.0.2", "lcov-result-merger": "0.0.2",
"istanbul": "~0.1.45", "istanbul": "~0.1.45",
"coveralls": "~2.5.0" "coveralls": "~2.5.0",
"async": "~0.2.9"
}, },
"keywords": [ "keywords": [
"mysql", "mysql",
......
...@@ -16,7 +16,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -16,7 +16,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
Group.belongsTo(User, { foreignKey: 'primaryGroupId', as: 'primaryUsers' }) Group.belongsTo(User, { foreignKey: 'primaryGroupId', as: 'primaryUsers' })
Group.belongsTo(User, { foreignKey: 'secondaryGroupId', as: 'secondaryUsers' }) Group.belongsTo(User, { foreignKey: 'secondaryGroupId', as: 'secondaryUsers' })
expect(Object.keys(Group.associations)).to.deep.equal(['Users', 'primaryUsers', 'secondaryUsers']) expect(Object.keys(Group.associations)).to.deep.equal(['User', 'primaryUsers', 'secondaryUsers'])
}) })
}) })
......
...@@ -676,10 +676,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -676,10 +676,8 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
{ tableName: 'tasks' } { tableName: 'tasks' }
) )
this.User.hasMany(this.Task, this.User.hasMany(this.Task, { joinTableName: 'user_has_tasks' })
{ joinTableName: 'user_has_tasks' } this.Task.hasMany(this.User, { joinTableName: 'user_has_tasks' })
)
this.Task.hasMany(this.User)
this.User.sync({ force: true }).success(function() { this.User.sync({ force: true }).success(function() {
self.Task.sync({force: true}).success(function() { self.Task.sync({force: true}).success(function() {
...@@ -693,16 +691,18 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -693,16 +691,18 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
expect(associationName).not.to.equal(this.User.tableName) expect(associationName).not.to.equal(this.User.tableName)
expect(associationName).not.to.equal(this.Task.tableName) expect(associationName).not.to.equal(this.Task.tableName)
var joinTableName = this.User.associations[associationName].options.joinTableName var through = this.User.associations[associationName].through
if (typeof joinTableName !== 'undefined') { if (typeof through !== 'undefined') {
expect(joinTableName).to.equal(associationName) expect(through.tableName).to.equal(associationName)
} }
var tableName = this.User.associations[associationName].options.tableName var tableName = this.User.associations[associationName].options.tableName
if (typeof tableName !== 'undefined') { if (typeof tableName !== 'undefined') {
expect(tableName).to.equal(associationName) expect(tableName).to.equal(associationName)
} }
} }
setTimeout(function () {
done() done()
}, 50)
}) })
}) })
...@@ -766,8 +766,6 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -766,8 +766,6 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}) })
describe('inserting in join table', function () { describe('inserting in join table', function () {
describe('add', function () { describe('add', function () {
it('should insert data provided on the object into the join table', function (done) { it('should insert data provided on the object into the join table', function (done) {
var self = this var self = this
...@@ -800,6 +798,32 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -800,6 +798,32 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
it('should be able to add twice (second call result in UPDATE call) without any attributes (and timestamps off) on the through model', function (done) {
var Worker = this.sequelize.define('Worker', {}, {timestamps: false})
, Task = this.sequelize.define('Task', {}, {timestamps: false})
, WorkerTasks = this.sequelize.define('WorkerTasks', {}, {timestamps: false})
Worker.hasMany(Task, { through: WorkerTasks })
Task.hasMany(Worker, { through: WorkerTasks })
this.sequelize.sync().done(function(err) {
expect(err).not.to.be.ok
Worker.create().done(function (err, worker) {
expect(err).not.to.be.ok
Task.create().done(function (err, task) {
expect(err).not.to.be.ok
worker.addTask(task).done(function (err) {
expect(err).not.to.be.ok
worker.addTask(task).done(function (err) {
expect(err).not.to.be.ok
done()
})
})
})
})
})
})
}) })
describe('set', function () { describe('set', function () {
...@@ -832,6 +856,68 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -832,6 +856,68 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
it('should be able to set twice (second call result in UPDATE calls) without any attributes (and timestamps off) on the through model', function (done) {
var Worker = this.sequelize.define('Worker', {}, {timestamps: false})
, Task = this.sequelize.define('Task', {}, {timestamps: false})
, WorkerTasks = this.sequelize.define('WorkerTasks', {}, {timestamps: false})
Worker.hasMany(Task, { through: WorkerTasks })
Task.hasMany(Worker, { through: WorkerTasks })
this.sequelize.sync().done(function(err) {
expect(err).not.to.be.ok
Worker.create().done(function (err, worker) {
expect(err).not.to.be.ok
Task.bulkCreate([{}, {}]).done(function (err) {
expect(err).not.to.be.ok
Task.findAll().done(function (err, tasks) {
expect(err).not.to.be.ok
worker.setTasks(tasks).done(function (err) {
worker.setTasks(tasks).done(function (err) {
expect(err).not.to.be.ok
done()
})
})
})
})
})
})
})
})
})
describe('removing from the join table', function () {
it('should remove a single entry without any attributes (and timestamps off) on the through model', function (done) {
var Worker = this.sequelize.define('Worker', {}, {timestamps: false})
, Task = this.sequelize.define('Task', {}, {timestamps: false})
, WorkerTasks = this.sequelize.define('WorkerTasks', {}, {timestamps: false})
Worker.hasMany(Task, { through: WorkerTasks })
Task.hasMany(Worker, { through: WorkerTasks })
this.sequelize.sync().done(function(err) {
expect(err).not.to.be.ok
Worker.create({}).done(function (err, worker) {
expect(err).not.to.be.ok
Task.bulkCreate([{}, {}]).done(function (err) {
expect(err).not.to.be.ok
Task.findAll().done(function (err, tasks) {
expect(err).not.to.be.ok
worker.setTasks(tasks).done(function (err) {
worker.removeTask(tasks[0]).done(function (err) {
expect(err).not.to.be.ok
worker.getTasks().done(function (err, tasks) {
expect(tasks.length).to.equal(1)
done()
})
})
})
})
})
})
})
}) })
}) })
}) })
...@@ -900,6 +986,77 @@ describe(Support.getTestDialectTeaser("HasMany"), function() { ...@@ -900,6 +986,77 @@ describe(Support.getTestDialectTeaser("HasMany"), function() {
}) })
}) })
}) })
describe('alias', function () {
it("creates the join table when through is a string", function (done) {
var self = this
, User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {})
User.hasMany(Group, { as: 'MyGroups', through: 'group_user'})
Group.hasMany(User, { as: 'MyUsers', through: 'group_user'})
this.sequelize.sync({force:true}).success(function () {
self.sequelize.getQueryInterface().showAllTables().success(function (result) {
expect(result.indexOf('group_user')).not.to.equal(-1)
done()
})
})
})
it("creates the join table when through is a model", function (done) {
var self = this
, User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {})
, UserGroup = this.sequelize.define('GroupUser', {}, {tableName: 'user_groups'})
User.hasMany(Group, { as: 'MyGroups', through: UserGroup})
Group.hasMany(User, { as: 'MyUsers', through: UserGroup})
this.sequelize.sync({force:true}).success(function () {
self.sequelize.getQueryInterface().showAllTables().success(function (result) {
expect(result.indexOf('user_groups')).not.to.equal(-1)
done()
})
})
})
it("correctly identifies its counterpart when through is a string", function (done) {
var self = this
, User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {})
User.hasMany(Group, { as: 'MyGroups', through: 'group_user'})
Group.hasMany(User, { as: 'MyUsers', through: 'group_user'})
expect(Group.associations.MyUsers.through === User.associations.MyGroups.through);
expect(Group.associations.MyUsers.through.rawAttributes.UserId).to.exist;
expect(Group.associations.MyUsers.through.rawAttributes.GroupId).to.exist;
setTimeout(function () {
done()
}, 50)
})
it("correctly identifies its counterpart when through is a model", function (done) {
var self = this
, User = this.sequelize.define('User', {})
, Group = this.sequelize.define('Group', {})
, UserGroup = this.sequelize.define('GroupUser', {}, {tableName: 'user_groups'})
User.hasMany(Group, { as: 'MyGroups', through: UserGroup})
Group.hasMany(User, { as: 'MyUsers', through: UserGroup})
expect(Group.associations.MyUsers.through === User.associations.MyGroups.through);
expect(Group.associations.MyUsers.through.rawAttributes.UserId).to.exist;
expect(Group.associations.MyUsers.through.rawAttributes.GroupId).to.exist;
setTimeout(function () {
done()
}, 50)
})
})
}) })
describe("Foreign key constraints", function() { describe("Foreign key constraints", function() {
......
...@@ -16,7 +16,7 @@ describe(Support.getTestDialectTeaser("HasOne"), function() { ...@@ -16,7 +16,7 @@ describe(Support.getTestDialectTeaser("HasOne"), function() {
Group.hasOne(User, { foreignKey: 'primaryGroupId', as: 'primaryUsers' }) Group.hasOne(User, { foreignKey: 'primaryGroupId', as: 'primaryUsers' })
Group.hasOne(User, { foreignKey: 'secondaryGroupId', as: 'secondaryUsers' }) Group.hasOne(User, { foreignKey: 'secondaryGroupId', as: 'secondaryUsers' })
expect(Object.keys(Group.associations)).to.deep.equal(['Users', 'primaryUsers', 'secondaryUsers']) expect(Object.keys(Group.associations)).to.deep.equal(['User', 'primaryUsers', 'secondaryUsers'])
}) })
}) })
......
...@@ -944,7 +944,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -944,7 +944,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
user.age = user.age + 1 // happy birthday joe user.age = user.age + 1 // happy birthday joe
user.save().success(function() { user.save().done(function(err) {
expect(err).not.to.be.ok
expect(user.username).to.equal('joe') expect(user.username).to.equal('joe')
expect(user.age).to.equal(2) expect(user.age).to.equal(2)
expect(user.projects).to.exist expect(user.projects).to.exist
...@@ -1078,7 +1080,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -1078,7 +1080,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
it('returns a response that can be stringified', function(done) { it('returns a response that can be stringified', function(done) {
var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true }) var user = this.User.build({ username: 'test.user', age: 99, isAdmin: true })
expect(JSON.stringify(user)).to.deep.equal('{"username":"test.user","age":99,"isAdmin":true,"id":null}') expect(JSON.stringify(user)).to.deep.equal('{"id":null,"username":"test.user","age":99,"isAdmin":true}')
done() done()
}) })
......
...@@ -25,7 +25,7 @@ describe(Support.getTestDialectTeaser('DataTypes'), function() { ...@@ -25,7 +25,7 @@ describe(Support.getTestDialectTeaser('DataTypes'), function() {
[Sequelize.TEXT, 'TEXT', 'TEXT'], [Sequelize.TEXT, 'TEXT', 'TEXT'],
[Sequelize.DATE, 'DATE', 'DATETIME'], [Sequelize.DATE, 'DATE', 'DATETIME'],
[Sequelize.NOW, 'NOW', 'NOW'], [Sequelize.NOW, 'NOW', 'NOW'],
[Sequelize.UUID, 'UUID', 'CHAR(36)'], [Sequelize.UUID, 'UUID', 'UUID'],
[Sequelize.BOOLEAN, 'BOOLEAN', 'TINYINT(1)'], [Sequelize.BOOLEAN, 'BOOLEAN', 'TINYINT(1)'],
[Sequelize.BLOB, 'BLOB', 'BLOB'], [Sequelize.BLOB, 'BLOB', 'BLOB'],
......
...@@ -6,12 +6,12 @@ var chai = require('chai') ...@@ -6,12 +6,12 @@ var chai = require('chai')
chai.Assertion.includeStack = true chai.Assertion.includeStack = true
describe(Support.getTestDialectTeaser("Language Util"), function() { describe(Support.getTestDialectTeaser("Language Util"), function() {
before(function(done) { beforeEach(function(done) {
this.sequelize.options.language = 'es' this.sequelize.options.language = 'es'
done() done()
}) })
after(function(done) { afterEach(function(done) {
this.sequelize.options.language = 'en' this.sequelize.options.language = 'en'
done() done()
}) })
...@@ -37,8 +37,8 @@ describe(Support.getTestDialectTeaser("Language Util"), function() { ...@@ -37,8 +37,8 @@ describe(Support.getTestDialectTeaser("Language Util"), function() {
table2.belongsTo(table) table2.belongsTo(table)
table3.hasMany(table2) table3.hasMany(table2)
expect(table.associations.androides.identifier).to.equal('arbolId') expect(table.associations.androide.identifier).to.equal('arbolId')
expect(table2.associations.arboles).to.exist expect(table2.associations.arbol).to.exist
expect(table3.associations.androideshombres).to.exist expect(table3.associations.androideshombres).to.exist
done() done()
}) })
......
...@@ -268,6 +268,11 @@ if (Support.dialectIsMySQL()) { ...@@ -268,6 +268,11 @@ if (Support.dialectIsMySQL()) {
arguments: ['myTable', {where: null}], arguments: ['myTable', {where: null}],
expectation: "SELECT * FROM `myTable` WHERE 1=1;", expectation: "SELECT * FROM `myTable` WHERE 1=1;",
context: QueryGenerator context: QueryGenerator
}, {
title: 'buffer as where argument',
arguments: ['myTable', {where: { field: new Buffer("Sequelize")}}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`field`=X'53657175656c697a65';",
context: QueryGenerator
} }
], ],
......
...@@ -38,12 +38,16 @@ if (dialect.match(/^postgres/)) { ...@@ -38,12 +38,16 @@ if (dialect.match(/^postgres/)) {
it("should not use a combined name", function(done) { it("should not use a combined name", function(done) {
expect(this.sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).not.to.exist expect(this.sequelize.daoFactoryManager.getDAO('ms_table1sms_table2s')).not.to.exist
setTimeout(function () {
done() done()
}, 50)
}) })
it("should use the specified name", function(done) { it("should use the specified name", function(done) {
expect(this.sequelize.daoFactoryManager.getDAO('table1_to_table2')).to.exist expect(this.sequelize.daoFactoryManager.getDAO('table1_to_table2')).to.exist
setTimeout(function () {
done() done()
}, 50)
}) })
}) })
}) })
......
...@@ -333,6 +333,11 @@ if (dialect.match(/^postgres/)) { ...@@ -333,6 +333,11 @@ if (dialect.match(/^postgres/)) {
}, { }, {
arguments: ['mySchema.myTable', {where: {name: "foo';DROP TABLE mySchema.myTable;"}}], arguments: ['mySchema.myTable', {where: {name: "foo';DROP TABLE mySchema.myTable;"}}],
expectation: "SELECT * FROM \"mySchema\".\"myTable\" WHERE \"mySchema\".\"myTable\".\"name\"='foo'';DROP TABLE mySchema.myTable;';" expectation: "SELECT * FROM \"mySchema\".\"myTable\" WHERE \"mySchema\".\"myTable\".\"name\"='foo'';DROP TABLE mySchema.myTable;';"
}, {
title: 'buffer as where argument',
arguments: ['myTable', {where: { field: new Buffer("Sequelize")}}],
expectation: "SELECT * FROM \"myTable\" WHERE \"myTable\".\"field\"=E'\\\\x53657175656c697a65';",
context: QueryGenerator
}, },
// Variants when quoteIdentifiers is false // Variants when quoteIdentifiers is false
...@@ -410,6 +415,10 @@ if (dialect.match(/^postgres/)) { ...@@ -410,6 +415,10 @@ if (dialect.match(/^postgres/)) {
insertQuery: [ insertQuery: [
{ {
arguments: ['myTable', {}],
expectation: "INSERT INTO \"myTable\" DEFAULT VALUES RETURNING *;"
},
{
arguments: ['myTable', {name: 'foo'}], arguments: ['myTable', {name: 'foo'}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;" expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;"
}, { }, {
......
...@@ -255,6 +255,11 @@ if (dialect === 'sqlite') { ...@@ -255,6 +255,11 @@ if (dialect === 'sqlite') {
arguments: ['myTable', {where: null}], arguments: ['myTable', {where: null}],
expectation: "SELECT * FROM `myTable` WHERE 1=1;", expectation: "SELECT * FROM `myTable` WHERE 1=1;",
context: QueryGenerator context: QueryGenerator
}, {
title: 'buffer as where argument',
arguments: ['myTable', {where: { field: new Buffer("Sequelize")}}],
expectation: "SELECT * FROM `myTable` WHERE `myTable`.`field`=X'53657175656c697a65';",
context: QueryGenerator
} }
], ],
......
...@@ -48,6 +48,7 @@ var Support = { ...@@ -48,6 +48,7 @@ var Support = {
options.pool = options.pool || config.pool options.pool = options.pool || config.pool
var sequelizeOptions = { var sequelizeOptions = {
host: options.host || config.host,
logging: options.logging, logging: options.logging,
dialect: options.dialect, dialect: options.dialect,
port: options.port || process.env.SEQ_PORT || config.port, port: options.port || process.env.SEQ_PORT || config.port,
...@@ -55,10 +56,6 @@ var Support = { ...@@ -55,10 +56,6 @@ var Support = {
dialectOptions: options.dialectOptions || {} dialectOptions: options.dialectOptions || {}
} }
if (!!options.host) {
sequelizeOptions.host = options.host
}
if (!!options.define) { if (!!options.define) {
sequelizeOptions.define = options.define sequelizeOptions.define = options.define
} }
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!