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:
ssh24 2017-02-23 16:31:04 -05:00
parent 7f429e9a51
commit 12a279d248
1 changed files with 203 additions and 0 deletions

View File

@ -54,6 +54,209 @@ SQLConnector.prototype.invokeSuper = function(methodName) {
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
* Returns {String[]} The types for the connector