Refactor SQL migration methods
Extract getTableStatus into a own function itself Have showFields, showIndexes and alterTable as a base function Add isActual as a base function Also include getAddModifyColumns and getDropColumns for the sake of CI Add getDropColumns as a base function Add searchForPropertyInActual to base connector Add addPropertyToActual to base connector Add propertyHasNotBeenDeleted to base Add applySqlChanges to base connector Add columnDataType as base function
This commit is contained in:
parent
7f429e9a51
commit
12a279d248
203
lib/sql.js
203
lib/sql.js
|
@ -54,6 +54,209 @@ SQLConnector.prototype.invokeSuper = function(methodName) {
|
||||||
return superMethod.apply(this, args);
|
return superMethod.apply(this, args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform autoupdate for the given models
|
||||||
|
* @param {String[]} [models] A model name or an array of model names.
|
||||||
|
* If not present, apply to all models
|
||||||
|
* @param {Function} [cb] The callback function
|
||||||
|
*/
|
||||||
|
SQLConnector.prototype.autoupdate = function(models, cb) {
|
||||||
|
var self = this;
|
||||||
|
if ((!cb) && ('function' === typeof models)) {
|
||||||
|
cb = models;
|
||||||
|
models = undefined;
|
||||||
|
}
|
||||||
|
// First argument is a model name
|
||||||
|
if ('string' === typeof models) {
|
||||||
|
models = [models];
|
||||||
|
}
|
||||||
|
|
||||||
|
models = models || Object.keys(this._models);
|
||||||
|
|
||||||
|
async.each(models, function(model, done) {
|
||||||
|
if (!(model in self._models)) {
|
||||||
|
return process.nextTick(function() {
|
||||||
|
done(new Error(g.f('Model not found: %s', model)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
self.getTableStatus(model, function(err, fields, indexes, FKs) {
|
||||||
|
if (!err && fields.length) {
|
||||||
|
self.alterTable(model, fields, indexes, done);
|
||||||
|
} else {
|
||||||
|
self.createTable(model, done);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the models exist
|
||||||
|
* @param {String[]} [models] A model name or an array of model names.
|
||||||
|
* If not present, apply to all models
|
||||||
|
* @param {Function} [cb] The callback function
|
||||||
|
*/
|
||||||
|
SQLConnector.prototype.isActual = function(models, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if ((!cb) && ('function' === typeof models)) {
|
||||||
|
cb = models;
|
||||||
|
models = undefined;
|
||||||
|
}
|
||||||
|
// First argument is a model name
|
||||||
|
if ('string' === typeof models) {
|
||||||
|
models = [models];
|
||||||
|
}
|
||||||
|
|
||||||
|
models = models || Object.keys(this._models);
|
||||||
|
|
||||||
|
var changes = [];
|
||||||
|
async.each(models, function(model, done) {
|
||||||
|
self.getTableStatus(model, function(err, fields) {
|
||||||
|
changes = changes.concat(self.getAddModifyColumns(model, fields));
|
||||||
|
changes = changes.concat(self.getDropColumns(model, fields));
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
}, function done(err) {
|
||||||
|
if (err) {
|
||||||
|
return cb && cb(err);
|
||||||
|
}
|
||||||
|
var actual = (changes.length === 0);
|
||||||
|
cb && cb(null, actual);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SQLConnector.prototype.getAddModifyColumns = function(model, fields) {
|
||||||
|
throw new Error(g.f('{{getAddModifyColumns()}} must be implemented by the connector'));
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.getDropColumns = function(model, fields) {
|
||||||
|
var sql = [];
|
||||||
|
var self = this;
|
||||||
|
sql = sql.concat(self.getColumnsToDrop(model, fields));
|
||||||
|
return sql;
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.getColumnsToDrop = function(model, fields) {
|
||||||
|
throw new Error(g.f('{{getColumnsToDrop()}} must be implemented by the connector'));
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.searchForPropertyInActual = function(model, propName,
|
||||||
|
actualFields) {
|
||||||
|
var self = this;
|
||||||
|
var found = false;
|
||||||
|
actualFields.forEach(function(f) {
|
||||||
|
if (f.column === self.column(model, propName)) {
|
||||||
|
found = f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.addPropertyToActual = function(model, propName) {
|
||||||
|
var self = this;
|
||||||
|
var sqlCommand = self.columnEscaped(model, propName) +
|
||||||
|
' ' + self.columnDataType(model, propName) +
|
||||||
|
(self.isNullable(self.getPropertyDefinition(model, propName)) ?
|
||||||
|
'' : ' NOT NULL');
|
||||||
|
return sqlCommand;
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.columnDataType = function(model, property) {
|
||||||
|
var columnMetadata = this.columnMetadata(model, property);
|
||||||
|
var colType = columnMetadata && columnMetadata.dataType;
|
||||||
|
if (colType) {
|
||||||
|
colType = colType.toUpperCase();
|
||||||
|
}
|
||||||
|
var prop = this.getModelDefinition(model).properties[property];
|
||||||
|
if (!prop) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var colLength = columnMetadata && columnMetadata.dataLength ||
|
||||||
|
prop.length || prop.limit;
|
||||||
|
if (colType && colLength) {
|
||||||
|
return colType + '(' + colLength + ')';
|
||||||
|
}
|
||||||
|
return this.buildColumnType(prop);
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.buildColumnType = function(property) {
|
||||||
|
throw new Error(g.f('{{buildColumnType()}} must be implemented by the connector'));
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.propertyHasNotBeenDeleted = function(model, propName) {
|
||||||
|
return !!this.getModelDefinition(model).properties[propName];
|
||||||
|
};
|
||||||
|
|
||||||
|
SQLConnector.prototype.applySqlChanges = function(model, pendingChanges, cb) {
|
||||||
|
var self = this;
|
||||||
|
if (pendingChanges.length) {
|
||||||
|
var thisQuery = 'ALTER TABLE ' + self.tableEscaped(model);
|
||||||
|
var ranOnce = false;
|
||||||
|
pendingChanges.forEach(function(change) {
|
||||||
|
if (ranOnce) {
|
||||||
|
thisQuery = thisQuery + ' ';
|
||||||
|
}
|
||||||
|
thisQuery = thisQuery + ' ' + change;
|
||||||
|
ranOnce = true;
|
||||||
|
});
|
||||||
|
self.execute(thisQuery, cb);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alters a table
|
||||||
|
* @param {String} model The model name
|
||||||
|
* @param {Object} fields Fields of the table
|
||||||
|
* @param {Object} indexes Indexes of the table
|
||||||
|
* @param {Function} cb The callback function
|
||||||
|
*/
|
||||||
|
SQLConnector.prototype.alterTable = function(model, fields, indexes, cb) {
|
||||||
|
throw new Error(g.f('{{alterTable()}} must be implemented by the connector'));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the status of a table
|
||||||
|
* @param {String} model The model name
|
||||||
|
* @param {Function} cb The callback function
|
||||||
|
*/
|
||||||
|
SQLConnector.prototype.getTableStatus = function(model, cb) {
|
||||||
|
var fields, indexes;
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.showFields(model, function(err, data) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
fields = data;
|
||||||
|
|
||||||
|
self.showIndexes(model, function(err, data) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
indexes = data;
|
||||||
|
|
||||||
|
if (fields && indexes)
|
||||||
|
return cb(null, fields, indexes);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get fields from a table
|
||||||
|
* @param {String} model The model name
|
||||||
|
* @param {Function} cb The callback function
|
||||||
|
*/
|
||||||
|
SQLConnector.prototype.showFields = function(model, cb) {
|
||||||
|
throw new Error(g.f('{{showFields()}} must be implemented by the connector'));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get indexes from a table
|
||||||
|
* @param {String} model The model name
|
||||||
|
* @param {Function} cb The callback function
|
||||||
|
*/
|
||||||
|
SQLConnector.prototype.showIndexes = function(model, cb) {
|
||||||
|
throw new Error(g.f('{{showIndexes()}} must be implemented by the connector'));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get types associated with the connector
|
* Get types associated with the connector
|
||||||
* Returns {String[]} The types for the connector
|
* Returns {String[]} The types for the connector
|
||||||
|
|
Loading…
Reference in New Issue