Merge pull request #78 from strongloop/refactor-migration
Refactor migration
This commit is contained in:
commit
bba29f88f2
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