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

Commit bb40f280 by Mick Hansen

Merge pull request #1723 from sequelize/queryInterfacePromises

Query interface promises
2 parents c33046b9 a8f23bd8
...@@ -6,6 +6,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell ...@@ -6,6 +6,7 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
- Sequelize now returns promises instead of its custom event emitter from most calls. This affects methods that return multiple values (like `findOrCreate` or `findOrInitialize`). If your current callbacks do not accept the 2nd success parameter you might be seeing an array as the first param. Either use `.spread()` for these methods or add another argument to your callback: `.success(instance)` -> `.success(instance, created)`. - Sequelize now returns promises instead of its custom event emitter from most calls. This affects methods that return multiple values (like `findOrCreate` or `findOrInitialize`). If your current callbacks do not accept the 2nd success parameter you might be seeing an array as the first param. Either use `.spread()` for these methods or add another argument to your callback: `.success(instance)` -> `.success(instance, created)`.
- `.success()`/`.done()` and any other non promise methods are now deprecated (we will keep the codebase around for a few versions though). on('sql') persists for debugging purposes. - `.success()`/`.done()` and any other non promise methods are now deprecated (we will keep the codebase around for a few versions though). on('sql') persists for debugging purposes.
- Model association calls (belongsTo/hasOne/hasMany) are no longer chainable. (this is to support being able to pass association references to include rather than model/as combinations) - Model association calls (belongsTo/hasOne/hasMany) are no longer chainable. (this is to support being able to pass association references to include rather than model/as combinations)
- `QueryInterface` no longer emits global events. This means you can no longer do things like `QueryInterface.on('showAllSchemas', function ... `
- `define()` stores models in `sequelize.models` Object e.g. `sequelize.models.MyModel` - `define()` stores models in `sequelize.models` Object e.g. `sequelize.models.MyModel`
# v2.0.0-dev11 # v2.0.0-dev11
......
...@@ -39,6 +39,20 @@ module.exports = (function() { ...@@ -39,6 +39,20 @@ module.exports = (function() {
throwMethodUndefined('createTableQuery') throwMethodUndefined('createTableQuery')
}, },
describeTableQuery: function (tableName, schema, schemaDelimiter) {
var table = this.quoteTable(
this.addSchema({
tableName: tableName,
options: {
schema: schema,
schemaDelimiter: schemaDelimiter
}
})
)
return 'DESCRIBE ' + table + ';'
},
/* /*
Returns a query for dropping a table. Returns a query for dropping a table.
*/ */
......
...@@ -159,54 +159,88 @@ module.exports = (function() { ...@@ -159,54 +159,88 @@ module.exports = (function() {
Utils._.extend(ConnectorManager.prototype, require("../abstract/connector-manager").prototype) Utils._.extend(ConnectorManager.prototype, require("../abstract/connector-manager").prototype)
ConnectorManager.prototype.query = function(sql, callee, options) { ConnectorManager.prototype.query = function(sql, callee, options) {
if (!this.isConnected && !this.pool) { var self = this
this.connect()
} options = options || {}
if (this.useQueue) { if (this.useQueue) {
// If queueing we'll let the execQueueItem method handle connecting
var queueItem = { var queueItem = {
query: new Query(this.client, this.sequelize, callee, options || {}), query: new Query(null, this.sequelize, callee, options),
client: this.client,
sql: sql sql: sql
} };
queueItem.query.options.uuid = this.config.uuid
enqueue.call(this, queueItem, options) enqueue.call(this, queueItem, options)
return queueItem.query return queueItem.query.promise.finally(function () {
afterQuery.call(self, queueItem)
})
} }
var self = this var query = new Query(null, this.sequelize, callee, options);
, query = new Query(this.client, this.sequelize, callee, options || {}) this.pendingQueries++;
this.pendingQueries++
query.options.uuid = this.config.uuid
query.done(function() {
self.pendingQueries-- return this.getConnection(options).then(function (client) {
if (self.pool) { query.client = client
self.pool.release(query.client) return query.run(sql).finally(function () {
} else { self.pendingQueries--;
if (self.pendingQueries === 0) { if (self.pool) {
setTimeout(function() { self.pool.release(query.client);
self.pendingQueries === 0 && self.disconnect.call(self) } else {
}, 100) if (self.pendingQueries === 0) {
setTimeout(function() {
if (self.pendingQueries === 0){
self.disconnect.call(self);
}
}, 100);
}
} }
} });
}) })
};
ConnectorManager.prototype.getConnection = function(options) {
var self = this;
if (!this.pool) { options = options || {}
query.run(sql)
} else {
this.pool.acquire(function(err, client) {
if (err) {
return query.emit('error', err)
}
query.client = client return new Utils.Promise(function (resolve, reject) {
query.run(sql) if (!self.pool) {
return // Regular client caching
}, undefined, options.type) if (self.client) {
} return resolve(self.client);
} else {
// Cache for concurrent queries
if (self._getConnection) {
return resolve(self._getConnection)
}
return query // Set cache and acquire connection
} self._getConnection = this;
connect.call(self, function(err, client) {
if (err) {
return reject(err);
}
// Unset caching, should now be caught by the self.client check
self._getConnection = null;
self.client = client;
resolve(client);
});
}
} else {
// Acquire from pool
self.pool.acquire(function(err, client) {
if (err) {
return reject(err);
}
resolve(client);
}, options.priority, options.type);
}
})
};
ConnectorManager.prototype.connect = function() { ConnectorManager.prototype.connect = function() {
var self = this var self = this
...@@ -228,10 +262,12 @@ module.exports = (function() { ...@@ -228,10 +262,12 @@ module.exports = (function() {
return return
} }
// private // private
var disconnect = function(client) { var disconnect = function(client) {
if (!client) {
return // TODO possible orphaning of clients?
}
var self = this var self = this
if (!this.useQueue) { if (!this.useQueue) {
this.client = null this.client = null
...@@ -257,7 +293,7 @@ module.exports = (function() { ...@@ -257,7 +293,7 @@ module.exports = (function() {
var connect = function(done, config) { var connect = function(done, config) {
config = config || this.config config = config || this.config
var self = this var self = this
, client , client
...@@ -324,7 +360,7 @@ module.exports = (function() { ...@@ -324,7 +360,7 @@ module.exports = (function() {
var self = this var self = this
this.pool.acquire(function(err, client) { this.pool.acquire(function(err, client) {
if (err) { if (err) {
queueItem.query.emit('error', err) queueItem.query.reject(err)
return return
} }
//we set the client here, asynchronously, when getting a pooled connection //we set the client here, asynchronously, when getting a pooled connection
...@@ -367,12 +403,6 @@ module.exports = (function() { ...@@ -367,12 +403,6 @@ module.exports = (function() {
var execQueueItem = function(queueItem) { var execQueueItem = function(queueItem) {
var self = this
queueItem.query
.success(function(){ afterQuery.call(self, queueItem) })
.error(function(){ afterQuery.call(self, queueItem) })
queueItem.query.run(queueItem.sql, queueItem.client) queueItem.query.run(queueItem.sql, queueItem.client)
} }
......
...@@ -12,7 +12,12 @@ module.exports = (function() { ...@@ -12,7 +12,12 @@ module.exports = (function() {
raw: false raw: false
}, options || {}) }, options || {})
var self = this
this.checkLoggingOption() this.checkLoggingOption()
this.promise = new Utils.Promise(function (resolve, reject) {
self.resolve = resolve
self.reject = reject
})
} }
Utils.inherit(Query, AbstractQuery) Utils.inherit(Query, AbstractQuery)
...@@ -87,9 +92,9 @@ module.exports = (function() { ...@@ -87,9 +92,9 @@ module.exports = (function() {
}) })
.on('error', function(err) { .on('error', function(err) {
errorDetected = true errorDetected = true
self.emit('sql', self.sql) self.promise.emit('sql', self.sql)
err.sql = sql err.sql = sql
self.emit('error', err, self.callee) self.reject(err)
}) })
.on('end', function(info) { .on('end', function(info) {
if (alreadyEnded || errorDetected) { if (alreadyEnded || errorDetected) {
...@@ -97,19 +102,18 @@ module.exports = (function() { ...@@ -97,19 +102,18 @@ module.exports = (function() {
} }
alreadyEnded = true alreadyEnded = true
self.emit('sql', self.sql) self.promise.emit('sql', self.sql)
// we need to figure out whether to send the result set // we need to figure out whether to send the result set
// or info depending upon the type of query // or info depending upon the type of query
if (/^call/.test(self.sql.toLowerCase())) { if (/^call/.test(self.sql.toLowerCase())) {
self.emit('success', resultSet) self.resolve(resultSet)
} else if( /^show/.test(self.sql.toLowerCase()) || } else if( /^show/.test(self.sql.toLowerCase()) ||
/^select/.test(self.sql.toLowerCase()) || /^select/.test(self.sql.toLowerCase()) ||
/^describe/.test(self.sql.toLowerCase())) { /^describe/.test(self.sql.toLowerCase())) {
self.emit('success', self.formatResults(resultSet)) self.resolve(self.formatResults(resultSet))
} else { } else {
self.emit('success', self.formatResults(info)) self.resolve(self.formatResults(info))
} }
}) })
}) })
.on('error', function(err) { .on('error', function(err) {
...@@ -117,12 +121,12 @@ module.exports = (function() { ...@@ -117,12 +121,12 @@ module.exports = (function() {
return return
} }
errorDetected = true errorDetected = true
self.emit('sql', self.sql) self.promise.emit('sql', self.sql)
self.emit('error', err, self.callee) self.reject(err)
}) })
.setMaxListeners(100) .setMaxListeners(100)
return this return this.promise
} }
return Query return Query
......
...@@ -2,7 +2,7 @@ var mysql ...@@ -2,7 +2,7 @@ var mysql
, Pooling = require('generic-pool') , Pooling = require('generic-pool')
, Query = require("./query") , Query = require("./query")
, Utils = require("../../utils") , Utils = require("../../utils")
, without = function(arr, elem) { return arr.filter(function(e) { return e != elem }) } , without = function(arr, elem) { return arr.filter(function(e) { return e.query.uuid != elem.query.uuid }) }
module.exports = (function() { module.exports = (function() {
var ConnectorManager = function(sequelize, config) { var ConnectorManager = function(sequelize, config) {
...@@ -160,79 +160,75 @@ module.exports = (function() { ...@@ -160,79 +160,75 @@ module.exports = (function() {
Utils._.extend(ConnectorManager.prototype, require("../abstract/connector-manager").prototype); Utils._.extend(ConnectorManager.prototype, require("../abstract/connector-manager").prototype);
ConnectorManager.prototype.query = function(sql, callee, options) { ConnectorManager.prototype.query = function(sql, callee, options) {
var self = this
options = options || {}
if (this.useQueue) { if (this.useQueue) {
// If queueing we'll let the execQueueItem method handle connecting // If queueing we'll let the execQueueItem method handle connecting
var queueItem = { var queueItem = {
query: new Query(null, this.sequelize, callee, options || {}), query: new Query(null, this.sequelize, callee, options),
sql: sql sql: sql
}; };
queueItem.query.options.uuid = this.config.uuid queueItem.query.options.uuid = this.config.uuid
enqueue.call(this, queueItem, options); enqueue.call(this, queueItem, options)
return queueItem.query; return queueItem.query.promise.finally(function () {
afterQuery.call(self, queueItem)
})
} }
var self = this, query = new Query(null, this.sequelize, callee, options || {}); var query = new Query(null, this.sequelize, callee, options);
this.pendingQueries++; this.pendingQueries++;
query.options.uuid = this.config.uuid query.options.uuid = this.config.uuid
query.done(function() {
self.pendingQueries--;
if (self.pool) {
self.pool.release(query.client);
} else {
if (self.pendingQueries === 0) {
setTimeout(function() {
if (self.pendingQueries === 0){
self.disconnect.call(self);
}
}, 100);
}
}
});
this.getConnection(options, function (err, client) { return this.getConnection(options).then(function (client) {
if (err) {
return query.emit('error', err)
}
query.client = client query.client = client
query.run(sql) return query.run(sql).finally(function () {
}); self.pendingQueries--;
if (self.pool) {
return query; self.pool.release(query.client);
} else {
if (self.pendingQueries === 0) {
setTimeout(function() {
if (self.pendingQueries === 0){
self.disconnect.call(self);
}
}, 100);
}
}
});
})
}; };
ConnectorManager.prototype.getConnection = function(options, callback) { ConnectorManager.prototype.getConnection = function(options) {
var self = this; var self = this;
if (typeof options === "function") { options = options || {}
callback = options;
options = {};
}
return new Utils.CustomEventEmitter(function (emitter) { return new Utils.Promise(function (resolve, reject) {
if (!self.pool) { if (!self.pool) {
// Regular client caching // Regular client caching
if (self.client) { if (self.client) {
return emitter.emit('success', self.client); return resolve(self.client);
} else { } else {
// Cache for concurrent queries // Cache for concurrent queries
if (self._getConnection) { if (self._getConnection) {
self._getConnection.proxy(emitter); return resolve(self._getConnection)
return;
} }
// Set cache and acquire connection // Set cache and acquire connection
self._getConnection = emitter; self._getConnection = this;
connect.call(self, function(err, client) { connect.call(self, function(err, client) {
if (err) { if (err) {
return emitter.emit('error', err); return reject(err);
} }
// Unset caching, should now be caught by the self.client check // Unset caching, should now be caught by the self.client check
self._getConnection = null; self._getConnection = null;
self.client = client; self.client = client;
emitter.emit('success', client); resolve(client);
}); });
} }
} }
...@@ -240,12 +236,12 @@ module.exports = (function() { ...@@ -240,12 +236,12 @@ module.exports = (function() {
// Acquire from pool // Acquire from pool
self.pool.acquire(function(err, client) { self.pool.acquire(function(err, client) {
if (err) { if (err) {
return emitter.emit('error', err); return reject(err);
} }
emitter.emit('success', client); resolve(client);
}, options.priority, options.type); }, options.priority, options.type);
} }
}).run().done(callback); })
}; };
ConnectorManager.prototype.disconnect = function() { ConnectorManager.prototype.disconnect = function() {
...@@ -255,13 +251,15 @@ module.exports = (function() { ...@@ -255,13 +251,15 @@ module.exports = (function() {
return return
}; };
// private // private
var disconnect = function(client) { var disconnect = function(client) {
var self = this; var self = this;
this.client = null; this.client = null;
if (!client) {
return // TODO possible orphaning of clients?
}
client.end(function() { client.end(function() {
if (!self.useQueue) { if (!self.useQueue) {
return client.destroy(); return client.destroy();
...@@ -269,7 +267,6 @@ module.exports = (function() { ...@@ -269,7 +267,6 @@ module.exports = (function() {
var intervalObj = null var intervalObj = null
var cleanup = function () { var cleanup = function () {
var retryCt = 0
// make sure to let client finish before calling destroy // make sure to let client finish before calling destroy
if (client._queue && (client._queue.length > 0)) { if (client._queue && (client._queue.length > 0)) {
return return
...@@ -287,7 +284,6 @@ module.exports = (function() { ...@@ -287,7 +284,6 @@ module.exports = (function() {
var connect = function(done, config) { var connect = function(done, config) {
config = config || this.config config = config || this.config
var emitter = new (require('events').EventEmitter)()
var connectionConfig = { var connectionConfig = {
host: config.host, host: config.host,
port: config.port, port: config.port,
...@@ -309,22 +305,22 @@ module.exports = (function() { ...@@ -309,22 +305,22 @@ module.exports = (function() {
switch(err.code) { switch(err.code) {
case 'ECONNREFUSED': case 'ECONNREFUSED':
case 'ER_ACCESS_D2ENIED_ERROR': case 'ER_ACCESS_D2ENIED_ERROR':
emitter.emit('error', 'Failed to authenticate for MySQL. Please double check your settings.') done('Failed to authenticate for MySQL. Please double check your settings.')
break break
case 'ENOTFOUND': case 'ENOTFOUND':
case 'EHOSTUNREACH': case 'EHOSTUNREACH':
case 'EINVAL': case 'EINVAL':
emitter.emit('error', 'Failed to find MySQL server. Please double check your settings.') done('Failed to find MySQL server. Please double check your settings.')
break break
default: default:
emitter.emit('error', err); done(err);
break; break;
} }
return; return;
} }
emitter.emit('success', connection); done(null, connection);
}) })
connection.query("SET time_zone = '+0:00'"); connection.query("SET time_zone = '+0:00'");
...@@ -333,13 +329,6 @@ module.exports = (function() { ...@@ -333,13 +329,6 @@ module.exports = (function() {
if (config.pool !== null && config.pool.handleDisconnects) { if (config.pool !== null && config.pool.handleDisconnects) {
handleDisconnect(this.pool, connection) handleDisconnect(this.pool, connection)
} }
emitter.on('error', function (err) {
done(err);
});
emitter.on('success', function (connection) {
done(null, connection);
});
} }
var handleDisconnect = function(pool, client) { var handleDisconnect = function(pool, client) {
...@@ -388,26 +377,17 @@ module.exports = (function() { ...@@ -388,26 +377,17 @@ module.exports = (function() {
disconnectIfNoConnections.call(this) disconnectIfNoConnections.call(this)
} }
var execQueueItem = function(queueItem) { var execQueueItem = function(queueItem) {
var self = this this.getConnection({
self.getConnection({
priority: queueItem.query.options.priority, priority: queueItem.query.options.priority,
type: queueItem.query.options.type type: queueItem.query.options.type
}, function (err, connection) { }).then(function (connection) {
if (err) {
queueItem.query.emit('error', err)
return
}
queueItem.query.client = connection queueItem.query.client = connection
queueItem.client = connection queueItem.client = connection
queueItem.query
.success(function(){ afterQuery.call(self, queueItem) })
.error(function(){ afterQuery.call(self, queueItem) })
queueItem.query.run(queueItem.sql, queueItem.client) queueItem.query.run(queueItem.sql)
}, function (err) {
queueItem.query.reject(err)
}) })
} }
...@@ -421,7 +401,7 @@ module.exports = (function() { ...@@ -421,7 +401,7 @@ module.exports = (function() {
}) })
ConnectorManager.prototype.__defineGetter__('isConnected', function() { ConnectorManager.prototype.__defineGetter__('isConnected', function() {
return this.client != null return this.client !== null
}) })
var disconnectIfNoConnections = function() { var disconnectIfNoConnections = function() {
......
var Utils = require("../../utils") var Utils = require("../../utils")
, AbstractQuery = require('../abstract/query') , AbstractQuery = require('../abstract/query')
, uuid = require('node-uuid')
module.exports = (function() { module.exports = (function() {
var Query = function(client, sequelize, callee, options) { var Query = function(client, sequelize, callee, options) {
this.client = client this.client = client
this.callee = callee this.callee = callee
this.sequelize = sequelize this.sequelize = sequelize
this.uuid = uuid.v4()
this.options = Utils._.extend({ this.options = Utils._.extend({
logging: console.log, logging: console.log,
plain: false, plain: false,
raw: false raw: false
}, options || {}) }, options || {})
var self = this
this.checkLoggingOption() this.checkLoggingOption()
this.promise = new Utils.Promise(function (resolve, reject) {
self.resolve = resolve
self.reject = reject
})
} }
Utils.inherit(Query, AbstractQuery) Utils.inherit(Query, AbstractQuery)
Query.prototype.run = function(sql) { Query.prototype.run = function(sql) {
var self = this
this.sql = sql this.sql = sql
if (this.options.logging !== false) { if (this.options.logging !== false) {
this.sequelize.log('Executing (' + this.options.uuid + '): ' + this.sql) this.sequelize.log('Executing (' + this.options.uuid + '): ' + this.sql)
} }
this.client.query(this.sql, function(err, results, fields) { self.client.query(self.sql, function(err, results, fields) {
this.emit('sql', this.sql, this.options.uuid) self.promise.emit('sql', self.sql, self.options.uuid)
if (err) { if (err) {
err.sql = sql err.sql = sql
this.emit('error', err)
self.reject(err)
} else { } else {
this.emit('success', this.formatResults(results)) self.resolve(self.formatResults(results))
} }
}.bind(this)).setMaxListeners(100) }).setMaxListeners(100)
return this
return this.promise
} }
return Query return Query
......
...@@ -22,15 +22,19 @@ var QueryInterface = module.exports = { ...@@ -22,15 +22,19 @@ var QueryInterface = module.exports = {
@since 1.6.0 @since 1.6.0
*/ */
removeColumn: function(tableName, attributeName, emitter, queryAndEmit) { removeColumn: function(tableName, attributeName) {
var self = this
return this.describeTable(tableName).then(function(fields) { return this.describeTable(tableName).then(function(fields) {
delete fields[attributeName] delete fields[attributeName]
var sql = this.QueryGenerator.removeColumnQuery(tableName, fields) var sql = self.QueryGenerator.removeColumnQuery(tableName, fields)
, subQueries = sql.split(';').filter(function(q) { return q !== '' }) , subQueries = sql.split(';').filter(function(q) { return q !== '' })
return QueryInterface.execMultiQuery.call(this, subQueries, 'removeColumn', null, queryAndEmit) subQueries.unshift(null)
}.bind(this)) return Utils.Promise.reduce(subQueries, function (total, subQuery) {
return self.sequelize.query(subQuery + ';', null, { raw: true})
})
})
}, },
/** /**
...@@ -48,17 +52,21 @@ var QueryInterface = module.exports = { ...@@ -48,17 +52,21 @@ var QueryInterface = module.exports = {
@since 1.6.0 @since 1.6.0
*/ */
changeColumn: function(tableName, attributes, emitter, queryAndEmit) { changeColumn: function(tableName, attributes) {
var attributeName = Utils._.keys(attributes)[0] var attributeName = Utils._.keys(attributes)[0]
, self = this
return this.describeTable(tableName).then(function(fields) { return this.describeTable(tableName).then(function(fields) {
fields[attributeName] = attributes[attributeName] fields[attributeName] = attributes[attributeName]
var sql = this.QueryGenerator.removeColumnQuery(tableName, fields) var sql = self.QueryGenerator.removeColumnQuery(tableName, fields)
, subQueries = sql.split(';').filter(function(q) { return q !== '' }) , subQueries = sql.split(';').filter(function(q) { return q !== '' })
return QueryInterface.execMultiQuery.call(this, subQueries, 'changeColumn', emitter, queryAndEmit) subQueries.unshift(null)
}.bind(this)) return Utils.Promise.reduce(subQueries, function (total, subQuery) {
return self.sequelize.query(subQuery + ';', null, { raw: true})
})
})
}, },
/** /**
...@@ -77,93 +85,19 @@ var QueryInterface = module.exports = { ...@@ -77,93 +85,19 @@ var QueryInterface = module.exports = {
@since 1.6.0 @since 1.6.0
*/ */
renameColumn: function(tableName, attrNameBefore, attrNameAfter, emitter, queryAndEmit) { renameColumn: function(tableName, attrNameBefore, attrNameAfter) {
var self = this
return this.describeTable(tableName).then(function(fields) { return this.describeTable(tableName).then(function(fields) {
fields[attrNameAfter] = Utils._.clone(fields[attrNameBefore]) fields[attrNameAfter] = Utils._.clone(fields[attrNameBefore])
delete fields[attrNameBefore] delete fields[attrNameBefore]
var sql = this.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields) var sql = self.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields)
, subQueries = sql.split(';').filter(function(q) { return q !== '' }) , subQueries = sql.split(';').filter(function(q) { return q !== '' })
return QueryInterface.execMultiQuery.call(this, subQueries, 'renameColumn', emitter, queryAndEmit) subQueries.unshift(null)
}.bind(this)) return Utils.Promise.reduce(subQueries, function (total, subQuery) {
return self.sequelize.query(subQuery + ';', null, { raw: true})
})
})
}, },
execMultiQuery: function(queries, methodName, emitter, queryAndEmit) {
var chainer = new Utils.QueryChainer()
queries.splice(0, queries.length - 1).forEach(function(query) {
chainer.add(this.sequelize, 'query', [query + ";", null, { raw: true }])
}.bind(this))
return chainer
.runSerially()
.then(function() {
return queryAndEmit.call(this, queries.splice(queries.length - 1)[0], methodName, {}, emitter)
}.bind(this))
},
dropAllTables: function(options) {
var self = this
if (!options) {
options = {}
}
var skip = options.skip || [];
return new Utils.CustomEventEmitter(function(dropAllTablesEmitter) {
var events = []
, chainer = new Utils.QueryChainer()
, onError = function(err) {
self.emit('dropAllTables', err)
dropAllTablesEmitter.emit('error', err)
}
self
.showAllTables()
.error(onError)
.success(function(tableNames) {
self
.sequelize
.query('PRAGMA foreign_keys;')
.proxy(dropAllTablesEmitter, { events: ['sql'] })
.error(onError)
.success(function(result) {
var foreignKeysAreEnabled = result.foreign_keys === 1
if (foreignKeysAreEnabled) {
var queries = []
queries.push('PRAGMA foreign_keys = OFF')
tableNames.forEach(function(tableName) {
// if tableName is not in the Array of tables names then dont drop it
if (skip.indexOf(tableName) === -1) {
queries.push(self.QueryGenerator.dropTableQuery(tableName).replace(';', ''))
}
})
queries.push('PRAGMA foreign_keys = ON')
QueryInterface.execMultiQuery.call(self, queries, 'dropAllTables', dropAllTablesEmitter, self.queryAndEmit)
} else {
// add the table removal query to the chainer
tableNames.forEach(function(tableName) {
chainer.add(self, 'dropTable', [ tableName, { cascade: true } ])
})
chainer
.runSerially()
.proxy(dropAllTablesEmitter, { events: ['sql'] })
.error(onError)
.success(function() {
self.emit('dropAllTables', null)
dropAllTablesEmitter.emit('success', null)
})
}
})
})
}).run()
}
} }
...@@ -23,6 +23,7 @@ module.exports = (function() { ...@@ -23,6 +23,7 @@ module.exports = (function() {
Query.prototype.run = function(sql) { Query.prototype.run = function(sql) {
var self = this var self = this
, promise
this.sql = sql this.sql = sql
...@@ -30,70 +31,145 @@ module.exports = (function() { ...@@ -30,70 +31,145 @@ module.exports = (function() {
this.sequelize.log('Executing (' + this.options.uuid + '): ' + this.sql) this.sequelize.log('Executing (' + this.options.uuid + '): ' + this.sql)
} }
var columnTypes = {} return new Utils.Promise(function (resolve) {
this.database.serialize(function() { var columnTypes = {}
var executeSql = function() { promise = this
if (self.sql.indexOf('-- ') === 0) {
// the sql query starts with a comment. don't bother the server with that ... self.database.serialize(function() {
Utils.tick(function() { var executeSql = function() {
self.emit('sql', self.sql, self.options.uuid) if (self.sql.indexOf('-- ') === 0) {
self.emit('success', null) // the sql query starts with a comment. don't bother the server with that ...
}) promise.emit('sql', self.sql, self.options.uuid)
} else { return resolve()
self.database[getDatabaseMethod.call(self)](self.sql, function(err, results) { } else {
// allow clients to listen to sql to do their own logging or whatnot resolve(new Utils.Promise(function (resolve, reject) {
self.emit('sql', self.sql, self.options.uuid) self.database[getDatabaseMethod.call(self)](self.sql, function(err, results) {
// allow clients to listen to sql to do their own logging or whatnot
if (err) { promise.emit('sql', self.sql, self.options.uuid)
err.sql = self.sql
onFailure.call(self, err) if (err) {
} else { err.sql = self.sql
this.columnTypes = columnTypes reject(err)
onSuccess.call(self, results, this) } else {
} var metaData = this
}) metaData.columnTypes = columnTypes
}
} var result = self.callee
if ((getDatabaseMethod.call(self) === 'all')) { // add the inserted row id to the instance
var tableNames = [] if (self.send('isInsertQuery', results, metaData)) {
if (self.options && self.options.tableNames) { self.send('handleInsertQuery', results, metaData)
tableNames = self.options.tableNames }
} else if (/FROM `(.*?)`/i.exec(self.sql)) {
tableNames.push(/FROM `(.*?)`/i.exec(self.sql)[1])
}
if (!tableNames.length) { if (self.sql.indexOf('sqlite_master') !== -1) {
executeSql() result = results.map(function(resultSet) { return resultSet.name })
} else { } else if (self.send('isSelectQuery')) {
var execute = Utils._.after(tableNames.length, executeSql) if(!self.options.raw) {
results = results.map(function(result) {
tableNames.forEach(function (tableName) { for (var name in result) {
if (tableName !== 'sqlite_master') { if (result.hasOwnProperty(name) && metaData.columnTypes[name]) {
// get the column types if (metaData.columnTypes[name] === 'DATETIME') {
self.database.all("PRAGMA table_info(" + tableName + ")", function(err, results) { // we need to convert the timestamps into actual date objects
if (!err) { var val = result[name]
for (var i=0, l=results.length; i<l; i++) { if (val !== null) {
columnTypes[tableName + '.' + results[i].name] = columnTypes[results[i].name] = results[i].type result[name] = new Date(val+'Z') // Z means UTC
}
} else if (metaData.columnTypes[name].lastIndexOf('BLOB') !== -1) {
if (result[name]) {
result[name] = new Buffer(result[name])
}
}
}
}
return result
})
}
result = self.send('handleSelectQuery', results)
} else if (self.send('isShowOrDescribeQuery')) {
result = results
} else if (self.sql.indexOf('PRAGMA INDEX_LIST') !== -1) {
// this is the sqlite way of getting the indexes of a table
result = results.map(function(result) {
return {
name: result.name,
tableName: result.name.split('_')[0],
unique: (result.unique === 0)
}
})
} else if (self.sql.indexOf('PRAGMA TABLE_INFO') !== -1) {
// this is the sqlite way of getting the metadata of a table
result = {}
results.forEach(function(_result) {
result[_result.name] = {
type: _result.type,
allowNull: (_result.notnull === 0),
defaultValue: _result.dflt_value
}
if (result[_result.name].type === 'TINYINT(1)') {
result[_result.name].defaultValue = { '0': false, '1': true }[result[_result.name].defaultValue]
}
if (result[_result.name].defaultValue === undefined) {
result[_result.name].defaultValue = null
}
if (typeof result[_result.name].defaultValue === 'string') {
result[_result.name].defaultValue = result[_result.name].defaultValue.replace(/'/g, "")
}
})
} else if (self.sql.indexOf('PRAGMA foreign_keys;') !== -1) {
result = results[0]
} else if (self.sql.indexOf('PRAGMA foreign_keys') !== -1) {
result = results
} else if ([QueryTypes.BULKUPDATE, QueryTypes.BULKDELETE].indexOf(self.options.type) !== -1) {
result = metaData.changes
} }
resolve(result)
} }
execute() })
}); }))
} else { }
execute()
}
})
} }
} else {
executeSql()
}
})
return this if ((getDatabaseMethod.call(self) === 'all')) {
var tableNames = []
if (self.options && self.options.tableNames) {
tableNames = self.options.tableNames
} else if (/FROM `(.*?)`/i.exec(self.sql)) {
tableNames.push(/FROM `(.*?)`/i.exec(self.sql)[1])
}
if (!tableNames.length) {
return executeSql()
} else {
return Utils.Promise.map(tableNames, function (tableName) {
if (tableName !== 'sqlite_master') {
return new Utils.Promise(function (resolve) {
// get the column types
self.database.all("PRAGMA table_info(" + tableName + ")", function(err, results) {
if (!err) {
for (var i=0, l=results.length; i<l; i++) {
columnTypes[tableName + '.' + results[i].name] = columnTypes[results[i].name] = results[i].type
}
}
resolve()
});
})
}
}).then(executeSql)
}
} else {
return executeSql()
}
})
})
} }
//private //private
var getDatabaseMethod = function() { var getDatabaseMethod = function() {
if (this.send('isInsertQuery') || this.send('isUpdateQuery') || (this.sql.toLowerCase().indexOf('CREATE TEMPORARY TABLE'.toLowerCase()) !== -1) || this.options.type === QueryTypes.BULKDELETE) { if (this.send('isInsertQuery') || this.send('isUpdateQuery') || (this.sql.toLowerCase().indexOf('CREATE TEMPORARY TABLE'.toLowerCase()) !== -1) || this.options.type === QueryTypes.BULKDELETE) {
return 'run' return 'run'
...@@ -102,87 +178,5 @@ module.exports = (function() { ...@@ -102,87 +178,5 @@ module.exports = (function() {
} }
} }
var onSuccess = function(results, metaData) {
var result = this.callee
// add the inserted row id to the instance
if (this.send('isInsertQuery', results, metaData)) {
this.send('handleInsertQuery', results, metaData)
}
if (this.sql.indexOf('sqlite_master') !== -1) {
result = results.map(function(resultSet) { return resultSet.name })
} else if (this.send('isSelectQuery')) {
if(!this.options.raw) {
results = results.map(function(result) {
for (var name in result) {
if (result.hasOwnProperty(name) && metaData.columnTypes[name]) {
if (metaData.columnTypes[name] === 'DATETIME') {
// we need to convert the timestamps into actual date objects
var val = result[name]
if (val !== null) {
result[name] = new Date(val+'Z') // Z means UTC
}
} else if (metaData.columnTypes[name].lastIndexOf('BLOB') !== -1) {
if (result[name]) {
result[name] = new Buffer(result[name])
}
}
}
}
return result
})
}
result = this.send('handleSelectQuery', results)
} else if (this.send('isShowOrDescribeQuery')) {
result = results
} else if (this.sql.indexOf('PRAGMA INDEX_LIST') !== -1) {
// this is the sqlite way of getting the indexes of a table
result = results.map(function(result) {
return {
name: result.name,
tableName: result.name.split('_')[0],
unique: (result.unique === 0)
}
})
} else if (this.sql.indexOf('PRAGMA TABLE_INFO') !== -1) {
// this is the sqlite way of getting the metadata of a table
result = {}
results.forEach(function(_result) {
result[_result.name] = {
type: _result.type,
allowNull: (_result.notnull === 0),
defaultValue: _result.dflt_value
}
if (result[_result.name].type === 'TINYINT(1)') {
result[_result.name].defaultValue = { '0': false, '1': true }[result[_result.name].defaultValue]
}
if (result[_result.name].defaultValue === undefined) {
result[_result.name].defaultValue = null
}
if (typeof result[_result.name].defaultValue === 'string') {
result[_result.name].defaultValue = result[_result.name].defaultValue.replace(/'/g, "")
}
})
} else if (this.sql.indexOf('PRAGMA foreign_keys;') !== -1) {
result = results[0]
} else if (this.sql.indexOf('PRAGMA foreign_keys') !== -1) {
result = results
} else if ([QueryTypes.BULKUPDATE, QueryTypes.BULKDELETE].indexOf(this.options.type) !== -1) {
result = metaData.changes
}
this.emit('success', result)
}
var onFailure = function(err) {
this.emit('error', err, this.callee)
}
return Query return Query
})() })()
...@@ -112,7 +112,7 @@ Hooks.runHooks = function() { ...@@ -112,7 +112,7 @@ Hooks.runHooks = function() {
}) })
if (fn) { if (fn) {
promise.spread(function () { promise = promise.spread(function () {
fn.apply(self, [null].concat(Array.prototype.slice.apply(arguments))); fn.apply(self, [null].concat(Array.prototype.slice.apply(arguments)));
}, fn); }, fn);
} }
......
...@@ -648,17 +648,15 @@ module.exports = (function() { ...@@ -648,17 +648,15 @@ module.exports = (function() {
// This semi awkward syntax where we can't return the chain directly but have to return the last .then() call is to allow sql proxying // This semi awkward syntax where we can't return the chain directly but have to return the last .then() call is to allow sql proxying
return self.Model.runHooks(self.Model.options.hooks.beforeDestroy, self).then(function () { return self.Model.runHooks(self.Model.options.hooks.beforeDestroy, self).then(function () {
var query var identifier
, identifier
if (self.Model._timestampAttributes.deletedAt && options.force === false) { if (self.Model._timestampAttributes.deletedAt && options.force === false) {
self.dataValues[self.Model._timestampAttributes.deletedAt] = new Date() self.dataValues[self.Model._timestampAttributes.deletedAt] = new Date()
query = self.save(options) return self.save(options)
} else { } else {
identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id }; identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id };
query = self.QueryInterface.delete(self, self.QueryInterface.QueryGenerator.addSchema(self.Model), identifier, options) return self.QueryInterface.delete(self, self.QueryInterface.QueryGenerator.addSchema(self.Model), identifier, options)
} }
return query;
}).then(function (results) { }).then(function (results) {
return self.Model.runHooks(self.Model.options.hooks.afterDestroy, self).return(results); return self.Model.runHooks(self.Model.options.hooks.afterDestroy, self).return(results);
}); });
......
...@@ -170,7 +170,7 @@ module.exports = (function() { ...@@ -170,7 +170,7 @@ module.exports = (function() {
type: QueryTypes.SELECT type: QueryTypes.SELECT
}, options || {}) }, options || {})
return self.QueryInterface.queryAndEmit([result.toSql(), self, options], 'snafu') return self.sequelize.query(result.toSql(), self, options)
} }
return result return result
...@@ -393,7 +393,7 @@ module.exports = (function() { ...@@ -393,7 +393,7 @@ module.exports = (function() {
if (options.force) { if (options.force) {
return self.drop(options).then(function () { return self.drop(options).then(function () {
return doQuery().return(self); return doQuery().return(self)
}); });
} else { } else {
return doQuery().return(this) return doQuery().return(this)
...@@ -1143,7 +1143,7 @@ module.exports = (function() { ...@@ -1143,7 +1143,7 @@ module.exports = (function() {
} }
if(this.sequelize.options.dialect === 'postgres' && options.ignoreDuplicates) { if(this.sequelize.options.dialect === 'postgres' && options.ignoreDuplicates) {
return this.sequelize.Promise.reject(new Error('Postgres does not support the \'ignoreDuplicates\' option.')) return Utils.Promise.reject(new Error('Postgres does not support the \'ignoreDuplicates\' option.'))
} }
var self = this var self = this
......
...@@ -127,10 +127,6 @@ module.exports = (function() { ...@@ -127,10 +127,6 @@ module.exports = (function() {
if (options.skipOnError && (self.fails.length > 0)) { if (options.skipOnError && (self.fails.length > 0)) {
onError('Skipped due to earlier error!') onError('Skipped due to earlier error!')
} else { } else {
if (typeof serial.options === "object" && Object.keys(serial.options).length > 0 && serial.method === "queryAndEmit") {
serial.params.push(serial.options)
}
var emitter = serial.klass[serial.method].apply(serial.klass, serial.params) var emitter = serial.klass[serial.method].apply(serial.klass, serial.params)
emitter.success(function(result) { emitter.success(function(result) {
......
...@@ -17,16 +17,15 @@ module.exports = (function() { ...@@ -17,16 +17,15 @@ module.exports = (function() {
this.QueryGenerator._dialect = this.sequelize.dialect this.QueryGenerator._dialect = this.sequelize.dialect
this.QueryGenerator.sequelize = this.sequelize this.QueryGenerator.sequelize = this.sequelize
} }
Utils.addEventEmitter(QueryInterface)
QueryInterface.prototype.createSchema = function(schema) { QueryInterface.prototype.createSchema = function(schema) {
var sql = this.QueryGenerator.createSchema(schema) var sql = this.QueryGenerator.createSchema(schema)
return queryAndEmit.call(this, sql, 'createSchema') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.dropSchema = function(schema) { QueryInterface.prototype.dropSchema = function(schema) {
var sql = this.QueryGenerator.dropSchema(schema) var sql = this.QueryGenerator.dropSchema(schema)
return queryAndEmit.call(this, sql, 'dropSchema') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.dropAllSchemas = function() { QueryInterface.prototype.dropAllSchemas = function() {
...@@ -35,15 +34,9 @@ module.exports = (function() { ...@@ -35,15 +34,9 @@ module.exports = (function() {
if (!this.QueryGenerator._dialect.supports.schemas) { if (!this.QueryGenerator._dialect.supports.schemas) {
return this.sequelize.drop() return this.sequelize.drop()
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return this.showAllSchemas().map(function (schemaName, index, length) {
self.showAllSchemas().success(function(schemaNames) { return self.dropSchema(schemaName)
var chainer = new Utils.QueryChainer() })
schemaNames.forEach(function(schemaName) {
chainer.add(self.dropSchema(schemaName))
})
chainer.run().proxy(emitter)
}).proxy(emitter, {events: ['sql', 'error']})
}).run()
} }
} }
...@@ -55,16 +48,15 @@ module.exports = (function() { ...@@ -55,16 +48,15 @@ module.exports = (function() {
raw: true raw: true
}, options || {}) }, options || {})
return new Utils.CustomEventEmitter(function(emitter) { var showSchemasSql = self.QueryGenerator.showSchemasQuery()
var showSchemasSql = self.QueryGenerator.showSchemasQuery()
self.sequelize.query(showSchemasSql, null, options).success(function(schemaNames) { return this.sequelize.query(showSchemasSql, null, options).then(function (schemaNames) {
self.emit('showAllSchemas', null) return Utils._.flatten(
emitter.emit('success', Utils._.flatten(Utils._.map(schemaNames, function(value){ return (!!value.schema_name ? value.schema_name : value) }))) Utils._.map(schemaNames, function(value){
}).error(function(err) { return (!!value.schema_name ? value.schema_name : value)
self.emit('showAllSchemas', err) })
emitter.emit('error', err) )
}) })
}).run()
} }
QueryInterface.prototype.createTable = function(tableName, attributes, options) { QueryInterface.prototype.createTable = function(tableName, attributes, options) {
...@@ -145,14 +137,14 @@ module.exports = (function() { ...@@ -145,14 +137,14 @@ module.exports = (function() {
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options) sql = self.QueryGenerator.createTableQuery(tableName, attributes, options)
return Promise.all(promises).then(function() { return Promise.all(promises).then(function() {
return queryAndEmit.call(self, sql, 'createTable', options) return self.sequelize.query(sql, null, options)
}) })
}) })
} else { } else {
attributes = self.QueryGenerator.attributesToSQL(attributeHashes) attributes = self.QueryGenerator.attributesToSQL(attributeHashes)
sql = self.QueryGenerator.createTableQuery(tableName, attributes, options) sql = self.QueryGenerator.createTableQuery(tableName, attributes, options)
return queryAndEmit.call(self, sql, 'createTable', options) return self.sequelize.query(sql, null, options)
} }
} }
...@@ -164,19 +156,15 @@ module.exports = (function() { ...@@ -164,19 +156,15 @@ module.exports = (function() {
var sql = this.QueryGenerator.dropTableQuery(tableName, options) var sql = this.QueryGenerator.dropTableQuery(tableName, options)
, self = this , self = this
return queryAndEmit.call(this, sql, 'dropTable', options).then(function () { return this.sequelize.query(sql, null, options).then(function () {
var promises = [] var promises = []
// Since postgres has a special case for enums, we should drop the related // Since postgres has a special case for enums, we should drop the related
// enum type within the table and attribute // enum type within the table and attribute
if (self.sequelize.options.dialect === "postgres") { if (self.sequelize.options.dialect === "postgres") {
// Find the table that we're trying to drop // Find the table that we're trying to drop
daoTable = self.sequelize.daoFactoryManager.daos.filter(function(dao) { var daoTable = self.sequelize.daoFactoryManager.getDAO(tableName, 'tableName')
return dao.tableName === tableName
})
// Just in case if we're trying to drop a non-existing table
daoTable = daoTable.length > 0 ? daoTable[0] : null
if (!!daoTable) { if (!!daoTable) {
var getTableName = (!options || !options.schema || options.schema === "public" ? '' : options.schema + '_') + tableName var getTableName = (!options || !options.schema || options.schema === "public" ? '' : options.schema + '_') + tableName
...@@ -192,93 +180,83 @@ module.exports = (function() { ...@@ -192,93 +180,83 @@ module.exports = (function() {
} }
} }
return Promise.all(promises).then(function (results) { return Promise.all(promises).get(0);
return results[0];
});
}) })
} }
QueryInterface.prototype.dropAllTables = function(options) { QueryInterface.prototype.dropAllTables = function(options) {
var self = this var self = this
if (!options) { options = options || {}
options = {}
var dropAllTables = function(tableNames) {
tableNames.unshift(null)
return Utils.Promise.reduce(tableNames, function (total, tableName) {
// if tableName is not in the Array of tables names then dont drop it
if (skip.indexOf(tableName) === -1) {
return self.dropTable(tableName, { cascade: true })
}
})
} }
var skip = options.skip || []; var skip = options.skip || [];
if (this.sequelize.options.dialect === 'sqlite') { return self.showAllTables().then(function(tableNames) {
// sqlite needs some special treatment as it cannot drop a column if (self.sequelize.options.dialect === 'sqlite') {
return SQLiteQueryInterface.dropAllTables.call(this, options) return self.sequelize.query('PRAGMA foreign_keys;').then(function (result) {
} else { var foreignKeysAreEnabled = result.foreign_keys === 1
return new Utils.CustomEventEmitter(function(dropAllTablesEmitter) {
var events = [] if (foreignKeysAreEnabled) {
, chainer = new Utils.QueryChainer() return self.sequelize.query('PRAGMA foreign_keys = OFF').then(function () {
, onError = function(err) { return dropAllTables(tableNames).then(function (){
self.emit('dropAllTables', err) return self.sequelize.query('PRAGMA foreign_keys = ON')
dropAllTablesEmitter.emit('error', err)
}
self.showAllTables().success(function(tableNames) {
self.getForeignKeysForTables(tableNames).success(function(foreignKeys) {
// add the foreign key removal query to the chainer
Object.keys(foreignKeys).forEach(function(tableName) {
foreignKeys[tableName].forEach(function(foreignKey) {
var sql = self.QueryGenerator.dropForeignKeyQuery(tableName, foreignKey)
chainer.add(self.sequelize, 'query', [ sql ])
}) })
}) })
} else {
return dropAllTables(tableNames)
}
})
} else {
return self.getForeignKeysForTables(tableNames).then(function(foreignKeys) {
var promises = []
// add the table removal query to the chainer tableNames.forEach(function (tableName) {
tableNames.forEach(function(tableName) { foreignKeys[tableName].forEach(function (foreignKey) {
// if tableName is not in the Array of tables names then dont drop it var sql = self.QueryGenerator.dropForeignKeyQuery(tableName, foreignKey)
if (skip.indexOf(tableName) === -1) { promises.push(self.sequelize.query(sql))
chainer.add(self, 'dropTable', [ tableName, { cascade: true } ])
}
}) })
})
chainer return Utils.Promise.all(promises).then(function () {
.runSerially() return dropAllTables(tableNames)
.proxy(dropAllTablesEmitter, { proxy: ['success', 'error', 'sql']}) })
}).error(onError) })
}).error(onError) }
}).run() })
}
} }
QueryInterface.prototype.dropAllEnums = function(options) { QueryInterface.prototype.dropAllEnums = function(options) {
if (this.sequelize.getDialect() !== 'postgres') { if (this.sequelize.getDialect() !== 'postgres') {
return new Utils.CustomEventEmitter(function (emitter) { return Utils.Promise.resolve()
emitter.emit('success')
}).run()
} }
options = options || {} options = options || {}
var self = this var self = this
, emitter = new Utils.CustomEventEmitter()
, chainer = new Utils.QueryChainer()
, sql = this.QueryGenerator.pgListEnums() , sql = this.QueryGenerator.pgListEnums()
this.sequelize.query(sql, null, { plain: false, raw: true, type: QueryTypes.SELECT, logging: options.logging }) return this.sequelize.query(sql, null, { plain: false, raw: true, type: QueryTypes.SELECT, logging: options.logging }).map(function (result) {
.proxy(emitter, {events: ['sql', 'error']}) return self.sequelize.query(
.success(function (results) { self.QueryGenerator.pgEnumDrop(null, null, self.QueryGenerator.pgEscapeAndQuote(result.enum_name)),
results.forEach(function (result) { null,
chainer.add(self.sequelize.query( {logging: options.logging, raw: true}
self.QueryGenerator.pgEnumDrop(null, null, self.QueryGenerator.pgEscapeAndQuote(result.enum_name)), )
null, })
{logging: options.logging, raw: true}
))
})
chainer.run().proxy(emitter)
})
return emitter
} }
QueryInterface.prototype.renameTable = function(before, after) { QueryInterface.prototype.renameTable = function(before, after) {
var sql = this.QueryGenerator.renameTableQuery(before, after) var sql = this.QueryGenerator.renameTableQuery(before, after)
return queryAndEmit.call(this, sql, 'renameTable') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.showAllTables = function(options) { QueryInterface.prototype.showAllTables = function(options) {
...@@ -301,30 +279,12 @@ module.exports = (function() { ...@@ -301,30 +279,12 @@ module.exports = (function() {
if (typeof options === "string") { if (typeof options === "string") {
schema = options schema = options
} } else if (typeof options === "object") {
else if (typeof options === "object") {
schema = options.schema || null schema = options.schema || null
schemaDelimiter = options.schemaDelimiter || null schemaDelimiter = options.schemaDelimiter || null
} }
var sql; var sql = this.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter)
if (this.QueryGenerator.describeTableQuery) {
sql = this.QueryGenerator.describeTableQuery(tableName, schema, schemaDelimiter)
} else {
// TODO move this to abstract query gen.
var table = this.QueryGenerator.quoteTable(
this.QueryGenerator.addSchema({
tableName: tableName,
options: {
schema: schema,
schemaDelimiter:
schemaDelimiter
}
})
)
sql = 'DESCRIBE ' + table + ';'
}
return this.sequelize.query(sql, null, { raw: true }) return this.sequelize.query(sql, null, { raw: true })
} }
...@@ -341,16 +301,16 @@ module.exports = (function() { ...@@ -341,16 +301,16 @@ module.exports = (function() {
var options = this.QueryGenerator.attributesToSQL(attributes) var options = this.QueryGenerator.attributesToSQL(attributes)
, sql = this.QueryGenerator.addColumnQuery(tableName, options) , sql = this.QueryGenerator.addColumnQuery(tableName, options)
return queryAndEmit.call(this, sql, 'addColumn') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.removeColumn = function(tableName, attributeName) { QueryInterface.prototype.removeColumn = function(tableName, attributeName) {
if (this.sequelize.options.dialect === 'sqlite') { if (this.sequelize.options.dialect === 'sqlite') {
// sqlite needs some special treatment as it cannot drop a column // sqlite needs some special treatment as it cannot drop a column
return SQLiteQueryInterface.removeColumn.call(this, tableName, attributeName, null, queryAndEmit) return SQLiteQueryInterface.removeColumn.call(this, tableName, attributeName)
} else { } else {
var sql = this.QueryGenerator.removeColumnQuery(tableName, attributeName) var sql = this.QueryGenerator.removeColumnQuery(tableName, attributeName)
return queryAndEmit.call(this, sql, 'removeColumn') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
} }
...@@ -365,12 +325,12 @@ module.exports = (function() { ...@@ -365,12 +325,12 @@ module.exports = (function() {
if (this.sequelize.options.dialect === 'sqlite') { if (this.sequelize.options.dialect === 'sqlite') {
// sqlite needs some special treatment as it cannot change a column // sqlite needs some special treatment as it cannot change a column
return SQLiteQueryInterface.changeColumn.call(this, tableName, attributes, null, queryAndEmit) return SQLiteQueryInterface.changeColumn.call(this, tableName, attributes)
} else { } else {
var options = this.QueryGenerator.attributesToSQL(attributes) var options = this.QueryGenerator.attributesToSQL(attributes)
, sql = this.QueryGenerator.changeColumnQuery(tableName, options) , sql = this.QueryGenerator.changeColumnQuery(tableName, options)
return queryAndEmit.call(this, sql, 'changeColumn') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
} }
...@@ -394,65 +354,59 @@ module.exports = (function() { ...@@ -394,65 +354,59 @@ module.exports = (function() {
if (this.sequelize.options.dialect === 'sqlite') { if (this.sequelize.options.dialect === 'sqlite') {
// sqlite needs some special treatment as it cannot rename a column // sqlite needs some special treatment as it cannot rename a column
return SQLiteQueryInterface.renameColumn.call(this, tableName, attrNameBefore, attrNameAfter, null, queryAndEmit) return SQLiteQueryInterface.renameColumn.call(this, tableName, attrNameBefore, attrNameAfter)
} else { } else {
var sql = this.QueryGenerator.renameColumnQuery(tableName, var sql = this.QueryGenerator.renameColumnQuery(
tableName,
attrNameBefore, attrNameBefore,
this.QueryGenerator.attributesToSQL(options) this.QueryGenerator.attributesToSQL(options)
) )
return queryAndEmit.call(this, sql, 'renameColumn', {}) return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
}.bind(this)); }.bind(this));
} }
QueryInterface.prototype.addIndex = function(tableName, attributes, options) { QueryInterface.prototype.addIndex = function(tableName, attributes, options) {
var sql = this.QueryGenerator.addIndexQuery(tableName, attributes, options) var sql = this.QueryGenerator.addIndexQuery(tableName, attributes, options)
return queryAndEmit.call(this, sql, 'addIndex') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.showIndex = function(tableName, options) { QueryInterface.prototype.showIndex = function(tableName, options) {
var sql = this.QueryGenerator.showIndexQuery(tableName, options) var sql = this.QueryGenerator.showIndexQuery(tableName, options)
return queryAndEmit.call(this, sql, 'showIndex') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.getForeignKeysForTables = function(tableNames) { QueryInterface.prototype.getForeignKeysForTables = function(tableNames) {
var self = this var self = this
return new Utils.CustomEventEmitter(function(emitter) { if (tableNames.length === 0) {
if (tableNames.length === 0) { return Utils.Promise.resolve({})
emitter.emit('success', {}) }
} else {
var chainer = new Utils.QueryChainer()
tableNames.forEach(function(tableName) {
var sql = self.QueryGenerator.getForeignKeysQuery(tableName, self.sequelize.config.database)
chainer.add(self.sequelize, 'query', [sql])
})
chainer.runSerially().proxy(emitter, {
skipEvents: ['success']
}).success(function(results) {
var result = {}
tableNames.forEach(function(tableName, i) { return Utils.Promise.map(tableNames, function (tableName) {
result[tableName] = Utils._.compact(results[i]).map(function(r) { return r.constraint_name }) return self.sequelize.query(self.QueryGenerator.getForeignKeysQuery(tableName, self.sequelize.config.database))
}) }).then(function (results) {
var result = {}
emitter.emit('success', result) tableNames.forEach(function(tableName, i) {
result[tableName] = Utils._.compact(results[i]).map(function(r) {
return r.constraint_name
}) })
} })
}).run()
return result
})
} }
QueryInterface.prototype.removeIndex = function(tableName, indexNameOrAttributes) { QueryInterface.prototype.removeIndex = function(tableName, indexNameOrAttributes) {
var sql = this.QueryGenerator.removeIndexQuery(tableName, indexNameOrAttributes) var sql = this.QueryGenerator.removeIndexQuery(tableName, indexNameOrAttributes)
return queryAndEmit.call(this, sql, "removeIndex") return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} }
QueryInterface.prototype.insert = function(dao, tableName, values, options) { QueryInterface.prototype.insert = function(dao, tableName, values, options) {
var sql = this.QueryGenerator.insertQuery(tableName, values, dao.Model.rawAttributes); var sql = this.QueryGenerator.insertQuery(tableName, values, dao.Model.rawAttributes);
return queryAndEmit.call(this, [sql, dao, options], 'insert').then(function (result) { return this.sequelize.query(sql, dao, options).then(function (result) {
result.isNewRecord = false; result.isNewRecord = false;
return result; return result;
}); });
...@@ -460,7 +414,7 @@ module.exports = (function() { ...@@ -460,7 +414,7 @@ module.exports = (function() {
QueryInterface.prototype.bulkInsert = function(tableName, records, options, Model) { QueryInterface.prototype.bulkInsert = function(tableName, records, options, Model) {
var sql = this.QueryGenerator.bulkInsertQuery(tableName, records, options, Model.rawAttributes) var sql = this.QueryGenerator.bulkInsertQuery(tableName, records, options, Model.rawAttributes)
return queryAndEmit.call(this, [sql, null, options], 'bulkInsert') return this.sequelize.query(sql, null, options)
} }
QueryInterface.prototype.update = function(dao, tableName, values, identifier, options) { QueryInterface.prototype.update = function(dao, tableName, values, identifier, options) {
...@@ -480,13 +434,13 @@ module.exports = (function() { ...@@ -480,13 +434,13 @@ module.exports = (function() {
} }
} }
return this.queryAndEmit([sql, dao, options], 'update') return this.sequelize.query(sql, dao, options)
} }
QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier, options, attributes) { QueryInterface.prototype.bulkUpdate = function(tableName, values, identifier, options, attributes) {
var sql = this.QueryGenerator.updateQuery(tableName, values, identifier, options, attributes) var sql = this.QueryGenerator.updateQuery(tableName, values, identifier, options, attributes)
return this.queryAndEmit([sql, null, options], 'bulkUpdate') return this.sequelize.query(sql, null, options)
} }
QueryInterface.prototype.delete = function(dao, tableName, identifier, options) { QueryInterface.prototype.delete = function(dao, tableName, identifier, options) {
...@@ -512,7 +466,7 @@ module.exports = (function() { ...@@ -512,7 +466,7 @@ module.exports = (function() {
} }
} }
return new Promise(function (resolve, reject) { return new Utils.Promise(function (resolve, reject) {
var tick = 0 var tick = 0
var iterate = function(err, i) { var iterate = function(err, i) {
if (err) { if (err) {
...@@ -561,14 +515,13 @@ module.exports = (function() { ...@@ -561,14 +515,13 @@ module.exports = (function() {
resolve(); resolve();
} }
}).then(function () { }).then(function () {
return self.queryAndEmit([sql, dao, options], 'delete'); return self.sequelize.query(sql, dao, options)
}); });
} }
QueryInterface.prototype.bulkDelete = function(tableName, identifier, options, model) { QueryInterface.prototype.bulkDelete = function(tableName, identifier, options, model) {
var sql = this.QueryGenerator.deleteQuery(tableName, identifier, Utils._.defaults(options || {}, {limit: null}), model) var sql = this.QueryGenerator.deleteQuery(tableName, identifier, Utils._.defaults(options || {}, {limit: null}), model)
return this.sequelize.query(sql, null, options)
return this.queryAndEmit([sql, null, options], 'bulkDelete', options)
} }
QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) { QueryInterface.prototype.select = function(factory, tableName, options, queryOptions) {
...@@ -601,12 +554,12 @@ module.exports = (function() { ...@@ -601,12 +554,12 @@ module.exports = (function() {
originalAttributes: options.originalAttributes originalAttributes: options.originalAttributes
}) })
return queryAndEmit.call(this, [sql, factory, queryOptions], 'select') return this.sequelize.query(sql, factory, queryOptions)
} }
QueryInterface.prototype.increment = function(dao, tableName, values, identifier, options) { QueryInterface.prototype.increment = function(dao, tableName, values, identifier, options) {
var sql = this.QueryGenerator.incrementQuery(tableName, values, identifier, options.attributes) var sql = this.QueryGenerator.incrementQuery(tableName, values, identifier, options.attributes)
return queryAndEmit.call(this, [sql, dao, options], 'increment') return this.sequelize.query(sql, dao, options)
} }
QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector, Model) { QueryInterface.prototype.rawSelect = function(tableName, options, attributeSelector, Model) {
...@@ -640,75 +593,57 @@ module.exports = (function() { ...@@ -640,75 +593,57 @@ module.exports = (function() {
QueryInterface.prototype.createTrigger = function(tableName, triggerName, timingType, fireOnArray, QueryInterface.prototype.createTrigger = function(tableName, triggerName, timingType, fireOnArray,
functionName, functionParams, optionsArray) { functionName, functionParams, optionsArray) {
var sql = this.QueryGenerator.createTrigger(tableName, triggerName, timingType, fireOnArray, functionName var sql = this.QueryGenerator.createTrigger(tableName, triggerName, timingType, fireOnArray, functionName
, functionParams, optionsArray) , functionParams, optionsArray)
if (sql){ if (sql){
return queryAndEmit.call(this, sql, 'createTrigger') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve()
this.emit('createTrigger', null)
emitter.emit('success')
}).run()
} }
} }
QueryInterface.prototype.dropTrigger = function(tableName, triggerName) { QueryInterface.prototype.dropTrigger = function(tableName, triggerName) {
var sql = this.QueryGenerator.dropTrigger(tableName, triggerName) var sql = this.QueryGenerator.dropTrigger(tableName, triggerName)
if (sql){ if (sql){
return queryAndEmit.call(this, sql, 'dropTrigger') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve()
this.emit('dropTrigger', null)
emitter.emit('success')
}).run()
} }
} }
QueryInterface.prototype.renameTrigger = function(tableName, oldTriggerName, newTriggerName) { QueryInterface.prototype.renameTrigger = function(tableName, oldTriggerName, newTriggerName) {
var sql = this.QueryGenerator.renameTrigger(tableName, oldTriggerName, newTriggerName) var sql = this.QueryGenerator.renameTrigger(tableName, oldTriggerName, newTriggerName)
if (sql){ if (sql){
return queryAndEmit.call(this, sql, 'renameTrigger') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve()
this.emit('renameTrigger', null)
emitter.emit('success')
}).run()
} }
} }
QueryInterface.prototype.createFunction = function(functionName, params, returnType, language, body, options) { QueryInterface.prototype.createFunction = function(functionName, params, returnType, language, body, options) {
var sql = this.QueryGenerator.createFunction(functionName, params, returnType, language, body, options) var sql = this.QueryGenerator.createFunction(functionName, params, returnType, language, body, options)
if (sql){ if (sql){
return queryAndEmit.call(this, sql, 'createFunction') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve()
this.emit('createFunction', null)
emitter.emit('success')
}).run()
} }
} }
QueryInterface.prototype.dropFunction = function(functionName, params) { QueryInterface.prototype.dropFunction = function(functionName, params) {
var sql = this.QueryGenerator.dropFunction(functionName, params) var sql = this.QueryGenerator.dropFunction(functionName, params)
if (sql){ if (sql){
return queryAndEmit.call(this, sql, 'dropFunction') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve()
this.emit('dropFunction', null)
emitter.emit('success')
}).run()
} }
} }
QueryInterface.prototype.renameFunction = function(oldFunctionName, params, newFunctionName) { QueryInterface.prototype.renameFunction = function(oldFunctionName, params, newFunctionName) {
var sql = this.QueryGenerator.renameFunction(oldFunctionName, params, newFunctionName) var sql = this.QueryGenerator.renameFunction(oldFunctionName, params, newFunctionName)
if (sql){ if (sql){
return queryAndEmit.call(this, sql, 'renameFunction') return this.sequelize.query(sql, null, {logging: this.sequelize.options.logging})
} else { } else {
return new Utils.CustomEventEmitter(function(emitter) { return Utils.Promise.resolve()
this.emit('renameFunction', null)
emitter.emit('success')
}).run()
} }
} }
...@@ -727,7 +662,6 @@ module.exports = (function() { ...@@ -727,7 +662,6 @@ module.exports = (function() {
return this.QueryGenerator.quoteTable(identifier) return this.QueryGenerator.quoteTable(identifier)
} }
/** /**
* Split an identifier into .-separated tokens and quote each part. * Split an identifier into .-separated tokens and quote each part.
* If force is true, the identifier will be quoted even if the * If force is true, the identifier will be quoted even if the
...@@ -750,7 +684,7 @@ module.exports = (function() { ...@@ -750,7 +684,7 @@ module.exports = (function() {
} }
var sql = this.QueryGenerator.setAutocommitQuery(value) var sql = this.QueryGenerator.setAutocommitQuery(value)
return this.queryAndEmit([sql, null, { transaction: transaction }], 'setAutocommit') return this.sequelize.query(sql, null, { transaction: transaction})
} }
QueryInterface.prototype.setIsolationLevel = function(transaction, value) { QueryInterface.prototype.setIsolationLevel = function(transaction, value) {
...@@ -759,7 +693,7 @@ module.exports = (function() { ...@@ -759,7 +693,7 @@ module.exports = (function() {
} }
var sql = this.QueryGenerator.setIsolationLevelQuery(value) var sql = this.QueryGenerator.setIsolationLevelQuery(value)
return this.queryAndEmit([sql, null, { transaction: transaction }], 'setIsolationLevel') return this.sequelize.query(sql, null, { transaction: transaction })
} }
QueryInterface.prototype.startTransaction = function(transaction, options) { QueryInterface.prototype.startTransaction = function(transaction, options) {
...@@ -772,7 +706,7 @@ module.exports = (function() { ...@@ -772,7 +706,7 @@ module.exports = (function() {
}, options || {}) }, options || {})
var sql = this.QueryGenerator.startTransactionQuery(options) var sql = this.QueryGenerator.startTransactionQuery(options)
return this.queryAndEmit([sql, null, options], 'startTransaction') return this.sequelize.query(sql, null, options)
} }
QueryInterface.prototype.commitTransaction = function(transaction, options) { QueryInterface.prototype.commitTransaction = function(transaction, options) {
...@@ -785,7 +719,7 @@ module.exports = (function() { ...@@ -785,7 +719,7 @@ module.exports = (function() {
}, options || {}) }, options || {})
var sql = this.QueryGenerator.commitTransactionQuery(options) var sql = this.QueryGenerator.commitTransactionQuery(options)
return this.queryAndEmit([sql, null, options], 'commitTransaction') return this.sequelize.query(sql, null, options)
} }
QueryInterface.prototype.rollbackTransaction = function(transaction, options) { QueryInterface.prototype.rollbackTransaction = function(transaction, options) {
...@@ -798,7 +732,7 @@ module.exports = (function() { ...@@ -798,7 +732,7 @@ module.exports = (function() {
}, options || {}) }, options || {})
var sql = this.QueryGenerator.rollbackTransactionQuery(options) var sql = this.QueryGenerator.rollbackTransactionQuery(options)
return this.queryAndEmit([sql, null, options], 'rollbackTransaction') return this.sequelize.query(sql, null, options)
} }
// private // private
...@@ -812,68 +746,5 @@ module.exports = (function() { ...@@ -812,68 +746,5 @@ module.exports = (function() {
return {limit: this.scopeObj.limit || null, offset: this.scopeObj.offset || null, where: smart, order: (this.scopeObj.order || []).join(', ')} return {limit: this.scopeObj.limit || null, offset: this.scopeObj.offset || null, where: smart, order: (this.scopeObj.order || []).join(', ')}
} }
var queryAndEmit = QueryInterface.prototype.queryAndEmit = function(sqlOrQueryParams, methodName, options, emitter) {
options = Utils._.extend({
success: function(){},
error: function(){},
transaction: null,
logging: this.sequelize.options.logging
}, options || {})
var execQuery = function(emitter) {
var query;
if (Array.isArray(sqlOrQueryParams)) {
if (sqlOrQueryParams.length === 1) {
sqlOrQueryParams.push(null)
}
if (sqlOrQueryParams.length === 2) {
sqlOrQueryParams.push(typeof options === "object" ? options : {})
}
query = this.sequelize.query.apply(this.sequelize, sqlOrQueryParams)
} else {
query = this.sequelize.query(sqlOrQueryParams, null, options)
}
if (!emitter) {
return query.then(function (result) {
if (options.success) options.success(result);
return result;
}/*, function (err) {
if (options.error) options.error(err);
}*/);
}
emitter.query = query;
emitter
.query
.success(function(obj) {
if (options.success) {
options.success(obj)
}
this.emit(methodName, null)
emitter.emit('success', obj)
}.bind(this))
.error(function(err) {
if (options.error) {
options.error(err)
}
this.emit(methodName, err)
emitter.emit('error', err)
}.bind(this))
.proxy(emitter, { events: ['sql'] })
return emitter;
}.bind(this)
if (!!emitter) {
execQuery(emitter)
} else {
return execQuery();
}
}
return QueryInterface return QueryInterface
})() })()
...@@ -52,9 +52,6 @@ var Utils = module.exports = { ...@@ -52,9 +52,6 @@ var Utils = module.exports = {
return _ return _
})(), })(),
addEventEmitter: function(_class) {
util.inherits(_class, require('events').EventEmitter)
},
format: function(arr, dialect) { format: function(arr, dialect) {
var timeZone = null; var timeZone = null;
// Make a clone of the array beacuse format modifies the passed args // Make a clone of the array beacuse format modifies the passed args
......
...@@ -361,9 +361,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() { ...@@ -361,9 +361,7 @@ describe(Support.getTestDialectTeaser("BelongsTo"), function() {
Task.create({ title: 'task' }).success(function(task) { Task.create({ title: 'task' }).success(function(task) {
task.setUser(user).success(function() { task.setUser(user).success(function() {
// Should fail due to FK restriction // Should fail due to FK restriction
user.destroy().then(function () { user.destroy().catch(function(err) {
assert(false);
}, function(err) {
expect(err).to.be.ok; expect(err).to.be.ok;
Task.findAll().success(function(tasks) { Task.findAll().success(function(tasks) {
expect(tasks).to.have.length(1) expect(tasks).to.have.length(1)
......
...@@ -98,10 +98,10 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () { ...@@ -98,10 +98,10 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
if (dialect === 'mariadb') { if (dialect === 'mariadb') {
expect(err.message).to.match(/Access denied for user/) expect(err.message).to.match(/Access denied for user/)
} else if (dialect === 'postgres') { } else if (dialect === 'postgres') {
// When the test is run with only it produces: // When the test is run with only it produces:
// Error: Error: Failed to authenticate for PostgresSQL. Please double check your settings. // Error: Error: Failed to authenticate for PostgresSQL. Please double check your settings.
// When its run with all the other tests it produces: // When its run with all the other tests it produces:
// Error: invalid port number: "99999" // Error: invalid port number: "99999"
expect(err.message).to.match(/invalid port number/) expect(err.message).to.match(/invalid port number/)
} else { } else {
expect(err.message).to.match(/Failed to authenticate/) expect(err.message).to.match(/Failed to authenticate/)
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!