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

Commit 9dae02d4 by Mick Hansen

feat(promises): fix a few more tests - and return this.then() rather than this f…

…rom done/success/error - i'm a dummy
1 parent 606cc844
......@@ -336,25 +336,17 @@ module.exports = (function() {
options = Utils._.extend({}, this.options, options || {})
var self = this
return new Utils.CustomEventEmitter(function(emitter) {
var doQuery = function() {
self
.QueryInterface
.createTable(self.getTableName(), self.attributes, options)
.proxy(emitter, {events: ['error', 'sql']})
.success(function() { emitter.emit('success', self) })
, doQuery = function() {
return self.QueryInterface.createTable(self.getTableName(), self.attributes, options);
}
if (options.force) {
self
.drop(options)
.proxy(emitter, {events: ['error', 'sql']})
.success(doQuery)
} else {
doQuery()
}
}).run()
if (options.force) {
return self.drop(options).then(function () {
return doQuery();
});
} else {
return doQuery().return(this)
}
}
/**
......
......@@ -166,27 +166,15 @@ DaoValidator.prototype.validate = function() {
DaoValidator.prototype.hookValidate = function() {
var self = this
return new Utils.CustomEventEmitter(function(emitter) {
self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance, function(err) {
if (!!err) {
return emitter.emit('error', err)
return self.modelInstance.Model.runHooks('beforeValidate', self.modelInstance).then(function () {
return self.validate().then(function (error) {
if (error) {
throw error
}
self.validate().success(function (error) {
if (!!error) {
return emitter.emit('error', error)
}
self.modelInstance.Model.runHooks('afterValidate', self.modelInstance, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
emitter.emit('success', self.modelInstance)
})
})
})
}).run()
});
}).then(function () {
return self.modelInstance.Model.runHooks('afterValidate', self.modelInstance);
}).return(self.modelInstance);
}
/**
......
......@@ -436,134 +436,119 @@ module.exports = (function() {
}
}
return new Utils.CustomEventEmitter(function(emitter) {
self.hookValidate({
skip: _.difference(Object.keys(self.rawAttributes), options.fields)
}).proxy(emitter, { events: ['error'] }).success(function() {
options.fields.forEach(function(field) {
if (self.dataValues[field] !== undefined) {
values[field] = self.dataValues[field]
}
})
return self.hookValidate({
skip: _.difference(Object.keys(self.rawAttributes), options.fields)
}).then(function () {
options.fields.forEach(function(field) {
if (self.dataValues[field] !== undefined) {
values[field] = self.dataValues[field]
}
})
for (var attrName in self.Model.rawAttributes) {
if (self.Model.rawAttributes.hasOwnProperty(attrName)) {
var definition = self.Model.rawAttributes[attrName]
, isEnum = !!definition.type && (definition.type.toString() === DataTypes.ENUM.toString())
, isMySQL = ['mysql', 'mariadb'].indexOf(self.Model.daoFactoryManager.sequelize.options.dialect) !== -1
, ciCollation = !!self.Model.options.collate && self.Model.options.collate.match(/_ci$/i)
, valueOutOfScope
// Unfortunately for MySQL CI collation we need to map/lowercase values again
if (isEnum && isMySQL && ciCollation && (attrName in values) && values[attrName]) {
var scopeIndex = (definition.values || []).map(function(d) { return d.toLowerCase() }).indexOf(values[attrName].toLowerCase())
valueOutOfScope = scopeIndex === -1
// We'll return what the actual case will be, since a simple SELECT query would do the same...
if (!valueOutOfScope) {
values[attrName] = definition.values[scopeIndex]
}
for (var attrName in self.Model.rawAttributes) {
if (self.Model.rawAttributes.hasOwnProperty(attrName)) {
var definition = self.Model.rawAttributes[attrName]
, isEnum = !!definition.type && (definition.type.toString() === DataTypes.ENUM.toString())
, isMySQL = ['mysql', 'mariadb'].indexOf(self.Model.daoFactoryManager.sequelize.options.dialect) !== -1
, ciCollation = !!self.Model.options.collate && self.Model.options.collate.match(/_ci$/i)
, valueOutOfScope
// Unfortunately for MySQL CI collation we need to map/lowercase values again
if (isEnum && isMySQL && ciCollation && (attrName in values) && values[attrName]) {
var scopeIndex = (definition.values || []).map(function(d) { return d.toLowerCase() }).indexOf(values[attrName].toLowerCase())
valueOutOfScope = scopeIndex === -1
// We'll return what the actual case will be, since a simple SELECT query would do the same...
if (!valueOutOfScope) {
values[attrName] = definition.values[scopeIndex]
}
}
}
}
if (updatedAtAttr) {
values[updatedAtAttr] = (
(
self.isNewRecord
&& !!self.Model.rawAttributes[updatedAtAttr]
&& !!self.Model.rawAttributes[updatedAtAttr].defaultValue
)
? self.Model.rawAttributes[updatedAtAttr].defaultValue
: Utils.now(self.sequelize.options.dialect))
if (updatedAtAttr) {
values[updatedAtAttr] = (
(
self.isNewRecord
&& !!self.Model.rawAttributes[updatedAtAttr]
&& !!self.Model.rawAttributes[updatedAtAttr].defaultValue
)
? self.Model.rawAttributes[updatedAtAttr].defaultValue
: Utils.now(self.sequelize.options.dialect))
}
if (self.isNewRecord && createdAtAttr && !values[createdAtAttr]) {
values[createdAtAttr] = (
(
!!self.Model.rawAttributes[createdAtAttr]
&& !!self.Model.rawAttributes[createdAtAttr].defaultValue
)
? self.Model.rawAttributes[createdAtAttr].defaultValue
: Utils.now(self.sequelize.options.dialect))
}
if (self.isNewRecord && createdAtAttr && !values[createdAtAttr]) {
values[createdAtAttr] = (
(
!!self.Model.rawAttributes[createdAtAttr]
&& !!self.Model.rawAttributes[createdAtAttr].defaultValue
)
? self.Model.rawAttributes[createdAtAttr].defaultValue
: Utils.now(self.sequelize.options.dialect))
}
var query = null
, args = []
, hook = ''
if (self.isNewRecord) {
query = 'insert'
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.Model), values, options]
hook = 'Create'
} else {
var identifier = self.primaryKeyValues
var query = null
, args = []
, hook = ''
if (identifier === null && self.__options.whereCollection !== null) {
identifier = self.__options.whereCollection;
}
if (self.isNewRecord) {
query = 'insert'
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.Model), values, options]
hook = 'Create'
} else {
var identifier = self.primaryKeyValues
query = 'update'
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.Model), values, identifier, options]
hook = 'Update'
if (identifier === null && self.__options.whereCollection !== null) {
identifier = self.__options.whereCollection;
}
// Add the values to the DAO
self.dataValues = _.extend(self.dataValues, values)
query = 'update'
args = [self, self.QueryInterface.QueryGenerator.addSchema(self.Model), values, identifier, options]
hook = 'Update'
}
// Add the values to the DAO
self.dataValues = _.extend(self.dataValues, values)
return self.Model.runHooks('before' + hook, self).then(function () {
// dataValues might have changed inside the hook, rebuild
// the values hash
values = {}
// Run the beforeCreate / beforeUpdate hook
self.Model.runHooks('before' + hook, self, function(err) {
if (!!err) {
return emitter.emit('error', err)
options.fields.forEach(function(field) {
if (self.dataValues[field] !== undefined) {
values[field] = self.dataValues[field]
}
})
args[2] = values
// dataValues might have changed inside the hook, rebuild
// the values hash
values = {}
return self.QueryInterface[query].apply(self.QueryInterface, args).catch(function(err) {
if (!!self.__options.uniqueKeys && err.code && self.QueryInterface.QueryGenerator.uniqueConstraintMapping.code === err.code) {
var fields = self.QueryInterface.QueryGenerator.uniqueConstraintMapping.map(err.toString())
options.fields.forEach(function(field) {
if (self.dataValues[field] !== undefined) {
values[field] = self.dataValues[field]
}
})
args[2] = values
self.QueryInterface[query].apply(self.QueryInterface, args)
.proxy(emitter, {events: ['sql']})
.error(function(err) {
if (!!self.__options.uniqueKeys && err.code && self.QueryInterface.QueryGenerator.uniqueConstraintMapping.code === err.code) {
var fields = self.QueryInterface.QueryGenerator.uniqueConstraintMapping.map(err.toString())
if (fields !== false) {
fields = fields.filter(function(f) { return f !== self.Model.tableName; })
Utils._.each(self.__options.uniqueKeys, function(value, key) {
if (Utils._.isEqual(value.fields, fields) && !!value.msg) {
err = new Error(value.msg)
}
})
if (fields !== false) {
fields = fields.filter(function(f) { return f !== self.Model.tableName; })
Utils._.each(self.__options.uniqueKeys, function(value) {
if (Utils._.isEqual(value.fields, fields) && !!value.msg) {
err = new Error(value.msg)
}
}
})
}
}
emitter.emit('error', err)
})
.success(function(result) {
// Transfer database generated values (defaults, autoincrement, etc)
values = _.extend(values, result.dataValues)
throw err
}).then(function(result) {
// Transfer database generated values (defaults, autoincrement, etc)
values = _.extend(values, result.dataValues)
// Ensure new values are on DAO, and reset previousDataValues
result.dataValues = _.extend(result.dataValues, values)
result._previousDataValues = _.clone(result.dataValues)
// Ensure new values are on DAO, and reset previousDataValues
result.dataValues = _.extend(result.dataValues, values)
result._previousDataValues = _.clone(result.dataValues)
self.Model.runHooks('after' + hook, result, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
emitter.emit('success', result)
})
})
return self.Model.runHooks('after' + hook, result).return(result)
})
})
}).run()
})
}
/*
......
var util = require("util")
, Promise = require("bluebird")
, Promise
, EventEmitter = require("events").EventEmitter
, proxyEventKeys = ['success', 'error', 'sql']
, Utils = require('./utils')
......@@ -33,9 +33,28 @@ var SequelizePromise = function(resolver) {
this.$sql = [];
};
Promise = require("bluebird")
util.inherits(SequelizePromise, Promise)
Utils._.extend(SequelizePromise, Promise)
SequelizePromise.all = function(promises) {
return SequelizePromise.resolve(Promise.all(promises));
};
// Need to hack resolve cause we can't hack all directrly
SequelizePromise.resolve = SequelizePromise.fulfilled = function(value) {
var ret = new SequelizePromise(INTERNAL);
if (ret._tryFollow(value)) {
return ret;
}
ret._cleanValues();
ret._setFulfilled();
ret._settledValue = value;
return ret;
};
// Need to hack _then to make sure our promise is chainable
SequelizePromise.prototype._then = function (
didFulfill,
......@@ -138,8 +157,7 @@ SequelizePromise.prototype.emit = function(evt) {
SequelizePromise.prototype.success =
SequelizePromise.prototype.ok = function(fct) {
this.then(fct);
return this;
return this.then(fct);
}
/**
......@@ -161,8 +179,7 @@ SequelizePromise.prototype.ok = function(fct) {
SequelizePromise.prototype.failure =
SequelizePromise.prototype.fail =
SequelizePromise.prototype.error = function(fct) {
this.then(null, fct);
return this;
return this.then(null, fct);
}
/**
......@@ -182,16 +199,14 @@ SequelizePromise.prototype.error = function(fct) {
SequelizePromise.prototype.done =
SequelizePromise.prototype.complete = function(fct) {
if (fct.length > 2) {
this.spread(function () {
return this.spread(function () {
fct.apply(null, [null].concat(Array.prototype.slice.call(arguments)));
}, fct);
} else {
this.then(function () {
return this.then(function () {
fct.apply(null, [null].concat(Array.prototype.slice.call(arguments)));
}, fct);
}
return this;
};
/*
......
......@@ -2,7 +2,7 @@ var Utils = require(__dirname + '/utils')
, DataTypes = require(__dirname + '/data-types')
, SQLiteQueryInterface = require(__dirname + '/dialects/sqlite/query-interface')
, Transaction = require(__dirname + '/transaction')
, Promise = require(__dirname + '/promise')
, Promise = require(__dirname + '/promise')
, QueryTypes = require('./query-types')
module.exports = (function() {
......@@ -88,78 +88,72 @@ module.exports = (function() {
logging: this.sequelize.options.logging
}, options || {})
return new Utils.CustomEventEmitter(function(emitter) {
// Postgres requires a special SQL command for enums
if (self.sequelize.options.dialect === "postgres") {
var chainer = new Utils.QueryChainer()
// For backwards-compatibility, public schemas don't need to
// explicitly state their schema when creating a new enum type
, getTableName = (!options || !options.schema || options.schema === "public" ? '' : options.schema + '_') + tableName
for (i = 0; i < keyLen; i++) {
if (attributes[keys[i]].toString().match(/^ENUM\(/) || attributes[keys[i]].toString() === "ENUM" || (attributes[keys[i]].type && attributes[keys[i]].type.toString() === "ENUM")) {
sql = self.QueryGenerator.pgListEnums(getTableName, keys[i], options)
chainer.add(self.sequelize.query(sql, null, { plain: true, raw: true, type: QueryTypes.SELECT, logging: options.logging }))
}
// Postgres requires a special SQL command for enums
if (self.sequelize.options.dialect === "postgres") {
var promises = []
// For backwards-compatibility, public schemas don't need to
// explicitly state their schema when creating a new enum type
, getTableName = (!options || !options.schema || options.schema === "public" ? '' : options.schema + '_') + tableName
for (i = 0; i < keyLen; i++) {
if (attributes[keys[i]].toString().match(/^ENUM\(/) || attributes[keys[i]].toString() === "ENUM" || (attributes[keys[i]].type && attributes[keys[i]].type.toString() === "ENUM")) {
sql = self.QueryGenerator.pgListEnums(getTableName, keys[i], options)
promises.push(self.sequelize.query(sql, null, { plain: true, raw: true, type: QueryTypes.SELECT, logging: options.logging }))
}
}
chainer.runSerially().success(function(results) {
var chainer2 = new Utils.QueryChainer()
// Find the table that we're trying to create throgh DAOFactoryManager
, daoTable = self.sequelize.daoFactoryManager.daos.filter(function(dao) { return dao.tableName === tableName })
, enumIdx = 0
return Promise.all(promises).then(function(results) {
var promises = []
// Find the table that we're trying to create throgh DAOFactoryManager
, daoTable = self.sequelize.daoFactoryManager.daos.filter(function(dao) { return dao.tableName === tableName })
, enumIdx = 0
daoTable = daoTable.length > 0 ? daoTable[0] : null
daoTable = daoTable.length > 0 ? daoTable[0] : null
for (i = 0; i < keyLen; i++) {
if (attributes[keys[i]].toString().match(/^ENUM\(/) || attributes[keys[i]].toString() === "ENUM" || (attributes[keys[i]].type && attributes[keys[i]].type.toString() === "ENUM")) {
// If the enum type doesn't exist then create it
if (!results[enumIdx]) {
sql = self.QueryGenerator.pgEnum(getTableName, keys[i], attributes[keys[i]], options)
chainer2.add(self.sequelize.query(sql, null, { raw: true, logging: options.logging }))
} else if (!!results[enumIdx] && !!daoTable) {
var enumVals = self.QueryGenerator.fromArray(results[enumIdx].enum_value)
, vals = daoTable.rawAttributes[keys[i]].values
vals.forEach(function(value, idx) {
// reset out after/before options since it's for every enum value
options.before = null
options.after = null
if (enumVals.indexOf(value) === -1) {
if (!!vals[idx+1]) {
options.before = vals[idx+1]
}
else if (!!vals[idx-1]) {
options.after = vals[idx-1]
}
chainer2.add(self.sequelize.query(self.QueryGenerator.pgEnumAdd(getTableName, keys[i], value, options)))
for (i = 0; i < keyLen; i++) {
if (attributes[keys[i]].toString().match(/^ENUM\(/) || attributes[keys[i]].toString() === "ENUM" || (attributes[keys[i]].type && attributes[keys[i]].type.toString() === "ENUM")) {
// If the enum type doesn't exist then create it
if (!results[enumIdx]) {
sql = self.QueryGenerator.pgEnum(getTableName, keys[i], attributes[keys[i]], options)
promises.push(self.sequelize.query(sql, null, { raw: true, logging: options.logging }))
} else if (!!results[enumIdx] && !!daoTable) {
var enumVals = self.QueryGenerator.fromArray(results[enumIdx].enum_value)
, vals = daoTable.rawAttributes[keys[i]].values
vals.forEach(function(value, idx) {
// reset out after/before options since it's for every enum value
options.before = null
options.after = null
if (enumVals.indexOf(value) === -1) {
if (!!vals[idx+1]) {
options.before = vals[idx+1]
}
})
enumIdx++
}
else if (!!vals[idx-1]) {
options.after = vals[idx-1]
}
promises.push(self.sequelize.query(self.QueryGenerator.pgEnumAdd(getTableName, keys[i], value, options)))
}
})
enumIdx++
}
}
}
attributes = self.QueryGenerator.attributesToSQL(attributeHashes)
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options)
chainer2.run().success(function() {
queryAndEmit
.call(self, sql, 'createTable', options)
.proxy(emitter, { events: ['success', 'error', 'sql']})
})
.proxy(emitter, { events: ['error', 'sql']})
})
} else {
attributes = self.QueryGenerator.attributesToSQL(attributeHashes)
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options)
queryAndEmit.call(self, sql, 'createTable', options)
.proxy(emitter, { events: ['success', 'error', 'sql']})
}
}).run()
return Promise.all(promises).then(function() {
return queryAndEmit.call(self, sql, 'createTable', options)
})
})
} else {
attributes = self.QueryGenerator.attributesToSQL(attributeHashes)
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options)
return queryAndEmit.call(self, sql, 'createTable', options)
}
}
QueryInterface.prototype.dropTable = function(tableName, options) {
......@@ -170,10 +164,8 @@ module.exports = (function() {
var sql = this.QueryGenerator.dropTableQuery(tableName, options)
, self = this
return new Utils.CustomEventEmitter(function(emitter) {
var chainer = new Utils.QueryChainer()
chainer.add(self, 'queryAndEmit', [sql, 'dropTable'], options)
return queryAndEmit.call(this, sql, 'dropTable', options).then(function () {
var promises = []
// Since postgres has a special case for enums, we should drop the related
// enum type within the table and attribute
......@@ -194,19 +186,16 @@ module.exports = (function() {
for (i = 0; i < keyLen; i++) {
if (daoTable.rawAttributes[keys[i]].type && daoTable.rawAttributes[keys[i]].type.toString() === "ENUM") {
chainer.add(self.sequelize, 'query', [self.QueryGenerator.pgEnumDrop(getTableName, keys[i]), null, {logging: options.logging, raw: true}])
promises.push(self.sequelize.query(self.QueryGenerator.pgEnumDrop(getTableName, keys[i]), null, {logging: options.logging, raw: true}))
}
}
}
}
chainer.runSerially()
.success(function(results) {
emitter.emit('success', results[0])
self.emit('dropTable', null)
})
.proxy(emitter, { events: ['error', 'sql']})
}).run()
return Promise.all(promises).then(function (results) {
return results[0];
});
})
}
QueryInterface.prototype.dropAllTables = function(options) {
......
......@@ -1554,28 +1554,25 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
})
describe('references', function() {
beforeEach(function(done) {
beforeEach(function() {
var self = this
this.sequelize.getQueryInterface().dropTable('posts', { force: true }).success(function() {
self.sequelize.getQueryInterface().dropTable('authors', { force: true }).success(function() {
self.Author = self.sequelize.define('author', { firstName: Sequelize.STRING })
self.Author.sync().success(function() {
done()
})
})
this.Author = this.sequelize.define('author', { firstName: Sequelize.STRING })
return this.sequelize.getQueryInterface().dropTable('posts', { force: true }).then(function() {
return self.sequelize.getQueryInterface().dropTable('authors', { force: true })
}).then(function() {
return self.Author.sync()
})
})
afterEach(function(done) {
/*afterEach(function() {
var self = this
this.sequelize.getQueryInterface().dropTable('posts', { force: true }).success(function() {
self.sequelize.getQueryInterface().dropTable('authors', { force: true }).success(function() {
done()
})
return this.sequelize.getQueryInterface().dropTable('posts', { force: true }).then(function() {
return self.sequelize.getQueryInterface().dropTable('authors', { force: true })
})
})
})*/
it('uses an existing dao factory and references the author table', function(done) {
var self = this
......@@ -1662,7 +1659,9 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
expect(2).to.equal(1)
done()
}
}).error(function(err) {
return;
}).catch(function(err) {
if (Support.dialectIsMySQL(true)) {
expect(err.message).to.match(/ER_CANNOT_ADD_FOREIGN|ER_CANT_CREATE_TABLE/)
} else if (dialect === 'mariadb') {
......
......@@ -8,6 +8,7 @@ var chai = require('chai')
, dialect = Support.getTestDialect()
, datetime = require('chai-datetime')
, _ = require('lodash')
, assert = require('assert')
chai.use(datetime)
chai.config.includeStack = true
......@@ -165,7 +166,9 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
expect(err).not.to.be.ok
User.create({email: 'hello@sequelize.com'}).done(function (err) {
expect(err).not.to.be.ok
User.create({email: 'hello@sequelize.com'}).done(function (err) {
User.create({email: 'hello@sequelize.com'}).then(function () {
assert(false)
}, function (err) {
expect(err).to.be.ok
expect(err).to.be.an.instanceof(Error)
done()
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!