var Utils = require("../../utils") /** Returns an object that treats SQLite's inabilities to do certain queries. @class QueryInterface @static */ var QueryInterface = module.exports = { /** A wrapper that fixes SQLite's inability to remove columns from existing tables. It will create a backup of the table, drop the table afterwards and create a new table with the same name but without the obsolete column. @method removeColumn @for QueryInterface @param {String} tableName The name of the table. @param {String} attributeName The name of the attribute that we want to remove. @param {CustomEventEmitter} emitter The EventEmitter from outside. @param {Function} queryAndEmit The function from outside that triggers some events to get triggered. @since 1.6.0 */ removeColumn: function(tableName, attributeName, emitter, queryAndEmit) { this.describeTable(tableName).complete(function(err, fields) { if (err) { emitter.emit('error', err) } else { delete fields[attributeName] var sql = this.QueryGenerator.removeColumnQuery(tableName, fields) , subQueries = sql.split(';').filter(function(q) { return q !== '' }) QueryInterface.execMultiQuery.call(this, subQueries, 'removeColumn', emitter, queryAndEmit) } }.bind(this)) }, /** A wrapper that fixes SQLite's inability to change columns from existing tables. It will create a backup of the table, drop the table afterwards and create a new table with the same name but with a modified version of the respective column. @method changeColumn @for QueryInterface @param {String} tableName The name of the table. @param {Object} attributes An object with the attribute's name as key and it's options as value object. @param {CustomEventEmitter} emitter The EventEmitter from outside. @param {Function} queryAndEmit The function from outside that triggers some events to get triggered. @since 1.6.0 */ changeColumn: function(tableName, attributes, emitter, queryAndEmit) { var attributeName = Utils._.keys(attributes)[0] this.describeTable(tableName).complete(function(err, fields) { if (err) { emitter.emit('error', err) } else { fields[attributeName] = attributes[attributeName] var sql = this.QueryGenerator.removeColumnQuery(tableName, fields) , subQueries = sql.split(';').filter(function(q) { return q !== '' }) QueryInterface.execMultiQuery.call(this, subQueries, 'changeColumn', emitter, queryAndEmit) } }.bind(this)) }, /** A wrapper that fixes SQLite's inability to rename columns from existing tables. It will create a backup of the table, drop the table afterwards and create a new table with the same name but with a renamed version of the respective column. @method renameColumn @for QueryInterface @param {String} tableName The name of the table. @param {String} attrNameBefore The name of the attribute before it was renamed. @param {String} attrNameAfter The name of the attribute after it was renamed. @param {CustomEventEmitter} emitter The EventEmitter from outside. @param {Function} queryAndEmit The function from outside that triggers some events to get triggered. @since 1.6.0 */ renameColumn: function(tableName, attrNameBefore, attrNameAfter, emitter, queryAndEmit) { this.describeTable(tableName).complete(function(err, fields) { if (err) { emitter.emit('error', err) } else { fields[attrNameAfter] = Utils._.clone(fields[attrNameBefore]) delete fields[attrNameBefore] var sql = this.QueryGenerator.renameColumnQuery(tableName, attrNameBefore, attrNameAfter, fields) , subQueries = sql.split(';').filter(function(q) { return q !== '' }) QueryInterface.execMultiQuery.call(this, subQueries, 'renameColumn', emitter, queryAndEmit) } }.bind(this)) }, 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)) chainer .runSerially() .complete(function(err) { if (err) { emitter.emit(methodName, err) emitter.emit('error', err) } else { 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() } }