Merge pull request #193 from matthewdickinson/foreign_key_migration
Foreign key migration
This commit is contained in:
commit
692c07bd51
196
lib/migration.js
196
lib/migration.js
|
@ -21,6 +21,7 @@ function mixinMigration(MySQL, mysql) {
|
||||||
*/
|
*/
|
||||||
MySQL.prototype.autoupdate = function(models, cb) {
|
MySQL.prototype.autoupdate = function(models, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var foreignKeyStatements = [];
|
||||||
|
|
||||||
if ((!cb) && ('function' === typeof models)) {
|
if ((!cb) && ('function' === typeof models)) {
|
||||||
cb = models;
|
cb = models;
|
||||||
|
@ -41,15 +42,55 @@ function mixinMigration(MySQL, mysql) {
|
||||||
}
|
}
|
||||||
var table = self.tableEscaped(model);
|
var table = self.tableEscaped(model);
|
||||||
self.execute('SHOW FIELDS FROM ' + table, function(err, fields) {
|
self.execute('SHOW FIELDS FROM ' + table, function(err, fields) {
|
||||||
|
if (err) console.log('Failed to discover "' + table + '" fields', err);
|
||||||
|
|
||||||
self.execute('SHOW INDEXES FROM ' + table, function(err, indexes) {
|
self.execute('SHOW INDEXES FROM ' + table, function(err, indexes) {
|
||||||
|
if (err) console.log('Failed to discover "' + table + '" indexes', err);
|
||||||
|
|
||||||
|
self.discoverForeignKeys(self.table(model), {}, function(err, foreignKeys) {
|
||||||
|
if (err) console.log('Failed to discover "' + table + '" foreign keys', err);
|
||||||
|
|
||||||
if (!err && fields && fields.length) {
|
if (!err && fields && fields.length) {
|
||||||
self.alterTable(model, fields, indexes, done);
|
//if we already have a definition, update this table
|
||||||
|
self.alterTable(model, fields, indexes, foreignKeys, function(err, changed, res) {
|
||||||
|
//check to see if there were any new foreign keys for this table.
|
||||||
|
//If so, we'll create them once all tables have been updated
|
||||||
|
if (!err && res && res.newFks && res.newFks.length) {
|
||||||
|
foreignKeyStatements.push(res.newFks);
|
||||||
|
}
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.createTable(model, done);
|
//if there is not yet a definition, create this table
|
||||||
|
var res = self.createTable(model, function(err) {
|
||||||
|
if (!err) {
|
||||||
|
//get a list of the alter statements needed to add the defined foreign keys
|
||||||
|
var newFks = self.getForeignKeySQL(model, foreignKeys);
|
||||||
|
|
||||||
|
//check to see if there were any new foreign keys for this table.
|
||||||
|
//If so, we'll create them once all tables have been updated
|
||||||
|
if (newFks && newFks.length) {
|
||||||
|
foreignKeyStatements.push(self.getAlterStatement(model, newFks));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, cb);
|
});
|
||||||
|
}, function(err) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
//add any new foreign keys
|
||||||
|
async.each(foreignKeyStatements, function(addFkStmt, execDone) {
|
||||||
|
self.execute(addFkStmt, execDone);
|
||||||
|
}, function(err) {
|
||||||
|
cb(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -92,8 +133,15 @@ function mixinMigration(MySQL, mysql) {
|
||||||
async.each(models, function(model, done) {
|
async.each(models, function(model, done) {
|
||||||
var table = self.tableEscaped(model);
|
var table = self.tableEscaped(model);
|
||||||
self.execute('SHOW FIELDS FROM ' + table, function(err, fields) {
|
self.execute('SHOW FIELDS FROM ' + table, function(err, fields) {
|
||||||
|
if (err) console.log('Failed to discover "' + table + '" fields', err);
|
||||||
|
|
||||||
self.execute('SHOW INDEXES FROM ' + table, function(err, indexes) {
|
self.execute('SHOW INDEXES FROM ' + table, function(err, indexes) {
|
||||||
self.alterTable(model, fields, indexes, function(err, needAlter) {
|
if (err) console.log('Failed to discover "' + table + '" indexes', err);
|
||||||
|
|
||||||
|
self.discoverForeignKeys(self.table(model), {}, function(err, foreignKeys) {
|
||||||
|
if (err) console.log('Failed to discover "' + table + '" foreign keys', err);
|
||||||
|
|
||||||
|
self.alterTable(model, fields, indexes, foreignKeys, function(err, needAlter) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,15 +151,44 @@ function mixinMigration(MySQL, mysql) {
|
||||||
}, true);
|
}, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
cb(err, !ok);
|
||||||
return err;
|
|
||||||
}
|
|
||||||
cb(null, !ok);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
MySQL.prototype.alterTable = function(model, actualFields, actualIndexes, done, checkOnly) {
|
MySQL.prototype.getForeignKeySQL = function(model, actualFks) {
|
||||||
|
var self = this;
|
||||||
|
var m = this.getModelDefinition(model);
|
||||||
|
var addFksSql = [];
|
||||||
|
var newFks = m.settings.foreignKeys || {};
|
||||||
|
var newFkNames = Object.keys(newFks).filter(function(name) {
|
||||||
|
return !!m.settings.foreignKeys[name];
|
||||||
|
});
|
||||||
|
|
||||||
|
//add new foreign keys
|
||||||
|
if (newFkNames.length) {
|
||||||
|
//narrow down our key names to only those that don't already exist
|
||||||
|
var oldKeyNames = actualFks.map(function(oldKey) { return oldKey.fkName; });
|
||||||
|
newFkNames.filter(function(key) { return !~oldKeyNames.indexOf(key); })
|
||||||
|
.forEach(function(key) {
|
||||||
|
var constraint = self.buildForeignKeyDefinition(model, key);
|
||||||
|
if (constraint) {
|
||||||
|
addFksSql.push('ADD ' + constraint);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return addFksSql;
|
||||||
|
};
|
||||||
|
|
||||||
|
MySQL.prototype.alterTable = function(model, actualFields, actualIndexes, actualFks, done, checkOnly) {
|
||||||
|
//if this is using an old signature, then grab the correct callback and check boolean
|
||||||
|
if ('function' == typeof actualFks && typeof done !== 'function') {
|
||||||
|
checkOnly = done || false;
|
||||||
|
done = actualFks;
|
||||||
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var m = this.getModelDefinition(model);
|
var m = this.getModelDefinition(model);
|
||||||
var propNames = Object.keys(m.properties).filter(function(name) {
|
var propNames = Object.keys(m.properties).filter(function(name) {
|
||||||
|
@ -121,6 +198,9 @@ function mixinMigration(MySQL, mysql) {
|
||||||
var indexNames = Object.keys(indexes).filter(function(name) {
|
var indexNames = Object.keys(indexes).filter(function(name) {
|
||||||
return !!m.settings.indexes[name];
|
return !!m.settings.indexes[name];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//add new foreign keys
|
||||||
|
var correctFks = m.settings.foreignKeys || {};
|
||||||
var sql = [];
|
var sql = [];
|
||||||
var ai = {};
|
var ai = {};
|
||||||
|
|
||||||
|
@ -159,6 +239,36 @@ function mixinMigration(MySQL, mysql) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//drop foreign keys for removed fields
|
||||||
|
if (actualFks) {
|
||||||
|
var removedFks = [];
|
||||||
|
actualFks.forEach(function(fk) {
|
||||||
|
var needsToDrop = false;
|
||||||
|
var newFk = correctFks[fk.fkName];
|
||||||
|
if (newFk) {
|
||||||
|
var fkCol = expectedColName(newFk.foreignKey);
|
||||||
|
var fkEntity = self.getModelDefinition(newFk.entity);
|
||||||
|
var fkRefKey = expectedColNameForModel(newFk.entityKey, fkEntity);
|
||||||
|
var fkRefTable = newFk.entity.name; //TODO check for mysql name
|
||||||
|
needsToDrop = fkCol != fk.fkColumnName ||
|
||||||
|
fkRefKey != fk.pkColumnName ||
|
||||||
|
fkRefTable != fk.pkTableName;
|
||||||
|
} else {
|
||||||
|
needsToDrop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsToDrop) {
|
||||||
|
sql.push('DROP FOREIGN KEY ' + fk.fkName);
|
||||||
|
removedFks.push(fk); //keep track that we removed these
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//update out list of existing keys by removing dropped keys
|
||||||
|
actualFks = actualFks.filter(function(k) {
|
||||||
|
return removedFks.indexOf(k) == -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// drop columns
|
// drop columns
|
||||||
if (actualFields) {
|
if (actualFields) {
|
||||||
actualFields.forEach(function(f) {
|
actualFields.forEach(function(f) {
|
||||||
|
@ -177,6 +287,8 @@ function mixinMigration(MySQL, mysql) {
|
||||||
aiNames.forEach(function(indexName) {
|
aiNames.forEach(function(indexName) {
|
||||||
if (indexName === 'PRIMARY' ||
|
if (indexName === 'PRIMARY' ||
|
||||||
(m.properties[indexName] && self.id(model, indexName))) return;
|
(m.properties[indexName] && self.id(model, indexName))) return;
|
||||||
|
|
||||||
|
if (Object.keys(actualFks).indexOf(indexName) > -1) return; //this index is from an FK
|
||||||
if (indexNames.indexOf(indexName) === -1 && !m.properties[indexName] ||
|
if (indexNames.indexOf(indexName) === -1 && !m.properties[indexName] ||
|
||||||
m.properties[indexName] && !m.properties[indexName].index) {
|
m.properties[indexName] && !m.properties[indexName].index) {
|
||||||
sql.push('DROP INDEX ' + self.client.escapeId(indexName));
|
sql.push('DROP INDEX ' + self.client.escapeId(indexName));
|
||||||
|
@ -293,13 +405,35 @@ function mixinMigration(MySQL, mysql) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sql.length) {
|
//since we're passing the actualFks list to this,
|
||||||
var query = 'ALTER TABLE ' + self.tableEscaped(model) + ' ' +
|
//this code has be called after foreign keys have been dropped
|
||||||
sql.join(',\n');
|
//(in case we're replacing FKs)
|
||||||
if (checkOnly) {
|
var addFksSql = this.getForeignKeySQL(model, actualFks);
|
||||||
done(null, true, {statements: sql, query: query});
|
|
||||||
|
//determine if there are column, index, or foreign keys changes (all require update)
|
||||||
|
if (sql.length || addFksSql.length) {
|
||||||
|
//get the required alter statements
|
||||||
|
var alterStmt = self.getAlterStatement(model, sql);
|
||||||
|
var newFksStatement = self.getAlterStatement(model, addFksSql);
|
||||||
|
var stmtList = [alterStmt, newFksStatement].filter(function(s) { return s.length; });
|
||||||
|
|
||||||
|
//set up an object to pass back all changes, changes that have been run,
|
||||||
|
//and foreign key statements that haven't been run
|
||||||
|
var retValues = {
|
||||||
|
statements: stmtList,
|
||||||
|
query: stmtList.join(';'),
|
||||||
|
newFks: newFksStatement,
|
||||||
|
};
|
||||||
|
|
||||||
|
//if we're running in read only mode OR if the only changes are foreign keys additions,
|
||||||
|
//then just return the object directly
|
||||||
|
if (checkOnly || !alterStmt.length) {
|
||||||
|
done(null, true, retValues);
|
||||||
} else {
|
} else {
|
||||||
this.execute(query, done);
|
//if there are changes in the alter statement, then execute them and return the object
|
||||||
|
self.execute(alterStmt, function(err) {
|
||||||
|
done(err, true, retValues);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
done();
|
done();
|
||||||
|
@ -336,7 +470,11 @@ function mixinMigration(MySQL, mysql) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectedColName(propName) {
|
function expectedColName(propName) {
|
||||||
var mysql = m.properties[propName].mysql;
|
return expectedColNameForModel(propName, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expectedColNameForModel(propName, modelToCheck) {
|
||||||
|
var mysql = modelToCheck.properties[propName].mysql;
|
||||||
if (typeof mysql === 'undefined') {
|
if (typeof mysql === 'undefined') {
|
||||||
return propName;
|
return propName;
|
||||||
}
|
}
|
||||||
|
@ -348,6 +486,31 @@ function mixinMigration(MySQL, mysql) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MySQL.prototype.getAlterStatement = function(model, statements) {
|
||||||
|
return statements.length ?
|
||||||
|
'ALTER TABLE ' + this.tableEscaped(model) + ' ' + statements.join(',\n') :
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
MySQL.prototype.buildForeignKeyDefinition = function(model, keyName) {
|
||||||
|
var definition = this.getModelDefinition(model);
|
||||||
|
|
||||||
|
var fk = definition.settings.foreignKeys[keyName];
|
||||||
|
if (fk) {
|
||||||
|
//get the definition of the referenced object
|
||||||
|
var fkEntityName = (typeof fk.entity === 'object') ? fk.entity.name : fk.entity;
|
||||||
|
|
||||||
|
//verify that the other model in the same DB
|
||||||
|
if (this._models[fkEntityName]) {
|
||||||
|
return ' CONSTRAINT ' + this.client.escapeId(fk.name) +
|
||||||
|
' FOREIGN KEY (' + fk.foreignKey + ')' +
|
||||||
|
' REFERENCES ' + this.tableEscaped(fkEntityName) +
|
||||||
|
'(' + this.client.escapeId(fk.entityKey) + ')';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
MySQL.prototype.buildColumnDefinitions =
|
MySQL.prototype.buildColumnDefinitions =
|
||||||
MySQL.prototype.propertiesSQL = function(model) {
|
MySQL.prototype.propertiesSQL = function(model) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -385,6 +548,7 @@ function mixinMigration(MySQL, mysql) {
|
||||||
indexes.forEach(function(i) {
|
indexes.forEach(function(i) {
|
||||||
sql.push(i);
|
sql.push(i);
|
||||||
});
|
});
|
||||||
|
|
||||||
return sql.join(',\n ');
|
return sql.join(',\n ');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -228,6 +228,252 @@ describe('MySQL connector', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should auto migrate/update foreign keys in tables', function(done) {
|
||||||
|
var customer2_schema =
|
||||||
|
{
|
||||||
|
'name': 'CustomerTest2',
|
||||||
|
'options': {
|
||||||
|
'idInjection': false,
|
||||||
|
'mysql': {
|
||||||
|
'schema': 'myapp_test',
|
||||||
|
'table': 'customer_test2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': false,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
'email': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': true,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
'age': {
|
||||||
|
'type': 'Number',
|
||||||
|
'required': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var customer3_schema =
|
||||||
|
{
|
||||||
|
'name': 'CustomerTest3',
|
||||||
|
'options': {
|
||||||
|
'idInjection': false,
|
||||||
|
'mysql': {
|
||||||
|
'schema': 'myapp_test',
|
||||||
|
'table': 'customer_test3',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'name': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': false,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
'email': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': true,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
'age': {
|
||||||
|
'type': 'Number',
|
||||||
|
'required': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var schema_v1 =
|
||||||
|
{
|
||||||
|
'name': 'OrderTest',
|
||||||
|
'options': {
|
||||||
|
'idInjection': false,
|
||||||
|
'mysql': {
|
||||||
|
'schema': 'myapp_test',
|
||||||
|
'table': 'order_test',
|
||||||
|
},
|
||||||
|
'foreignKeys': {
|
||||||
|
'fk_ordertest_customerId': {
|
||||||
|
'name': 'fk_ordertest_customerId',
|
||||||
|
'entity': 'CustomerTest3',
|
||||||
|
'entityKey': 'id',
|
||||||
|
'foreignKey': 'customerId',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'customerId': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': false,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var schema_v2 =
|
||||||
|
{
|
||||||
|
'name': 'OrderTest',
|
||||||
|
'options': {
|
||||||
|
'idInjection': false,
|
||||||
|
'mysql': {
|
||||||
|
'schema': 'myapp_test',
|
||||||
|
'table': 'order_test',
|
||||||
|
},
|
||||||
|
'foreignKeys': {
|
||||||
|
'fk_ordertest_customerId': {
|
||||||
|
'name': 'fk_ordertest_customerId',
|
||||||
|
'entity': 'CustomerTest2',
|
||||||
|
'entityKey': 'id',
|
||||||
|
'foreignKey': 'customerId',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'customerId': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': false,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var schema_v3 =
|
||||||
|
{
|
||||||
|
'name': 'OrderTest',
|
||||||
|
'options': {
|
||||||
|
'idInjection': false,
|
||||||
|
'mysql': {
|
||||||
|
'schema': 'myapp_test',
|
||||||
|
'table': 'order_test',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'properties': {
|
||||||
|
'id': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'customerId': {
|
||||||
|
'type': 'String',
|
||||||
|
'length': 20,
|
||||||
|
'id': 1,
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'String',
|
||||||
|
'required': false,
|
||||||
|
'length': 40,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var foreignKeySelect =
|
||||||
|
'SELECT COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME ' +
|
||||||
|
'FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE ' +
|
||||||
|
'WHERE REFERENCED_TABLE_SCHEMA = "myapp_test" ' +
|
||||||
|
'AND TABLE_NAME = "order_test"';
|
||||||
|
|
||||||
|
ds.createModel(customer2_schema.name, customer2_schema.properties, customer2_schema.options);
|
||||||
|
ds.createModel(customer3_schema.name, customer3_schema.properties, customer3_schema.options);
|
||||||
|
ds.createModel(schema_v1.name, schema_v1.properties, schema_v1.options);
|
||||||
|
|
||||||
|
//do initial update/creation of table
|
||||||
|
ds.autoupdate(function() {
|
||||||
|
ds.discoverModelProperties('order_test', function(err, props) {
|
||||||
|
//validate that we have the correct number of properties
|
||||||
|
assert.equal(props.length, 3);
|
||||||
|
|
||||||
|
//get the foreign keys for this table
|
||||||
|
ds.connector.execute(foreignKeySelect, function(err, foreignKeys) {
|
||||||
|
if (err) return done (err);
|
||||||
|
//validate that the foreign key exists and points to the right column
|
||||||
|
assert(foreignKeys);
|
||||||
|
assert(foreignKeys.length.should.be.equal(1));
|
||||||
|
assert.equal(foreignKeys[0].REFERENCED_TABLE_NAME, 'customer_test3');
|
||||||
|
assert.equal(foreignKeys[0].COLUMN_NAME, 'customerId');
|
||||||
|
assert.equal(foreignKeys[0].CONSTRAINT_NAME, 'fk_ordertest_customerId');
|
||||||
|
assert.equal(foreignKeys[0].REFERENCED_COLUMN_NAME, 'id');
|
||||||
|
|
||||||
|
//update our model (move foreign key) and run autoupdate to migrate
|
||||||
|
ds.createModel(schema_v2.name, schema_v2.properties, schema_v2.options);
|
||||||
|
ds.autoupdate(function(err, result) {
|
||||||
|
if (err) return done (err);
|
||||||
|
|
||||||
|
//get and validate the properties on this model
|
||||||
|
ds.discoverModelProperties('order_test', function(err, props) {
|
||||||
|
if (err) return done (err);
|
||||||
|
|
||||||
|
assert.equal(props.length, 3);
|
||||||
|
|
||||||
|
//get the foreign keys that exist after the migration
|
||||||
|
ds.connector.execute(foreignKeySelect, function(err, updatedForeignKeys) {
|
||||||
|
if (err) return done (err);
|
||||||
|
//validate that the foreign keys was moved to the new column
|
||||||
|
assert(updatedForeignKeys);
|
||||||
|
assert(updatedForeignKeys.length.should.be.equal(1));
|
||||||
|
assert.equal(updatedForeignKeys[0].REFERENCED_TABLE_NAME, 'customer_test2');
|
||||||
|
assert.equal(updatedForeignKeys[0].COLUMN_NAME, 'customerId');
|
||||||
|
assert.equal(updatedForeignKeys[0].CONSTRAINT_NAME, 'fk_ordertest_customerId');
|
||||||
|
assert.equal(updatedForeignKeys[0].REFERENCED_COLUMN_NAME, 'id');
|
||||||
|
|
||||||
|
//update model (to drop foreign key) and autoupdate
|
||||||
|
ds.createModel(schema_v3.name, schema_v3.properties, schema_v3.options);
|
||||||
|
ds.autoupdate(function(err, result) {
|
||||||
|
if (err) return done (err);
|
||||||
|
//validate the properties
|
||||||
|
ds.discoverModelProperties('order_test', function(err, props) {
|
||||||
|
if (err) return done (err);
|
||||||
|
|
||||||
|
assert.equal(props.length, 3);
|
||||||
|
|
||||||
|
//get the foreign keys and validate the foreign key has been dropped
|
||||||
|
ds.connector.execute(foreignKeySelect, function(err, thirdForeignKeys) {
|
||||||
|
if (err) return done (err);
|
||||||
|
assert(thirdForeignKeys);
|
||||||
|
assert(thirdForeignKeys.length.should.be.equal(0));
|
||||||
|
|
||||||
|
done(err, result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function setupAltColNameData() {
|
function setupAltColNameData() {
|
||||||
var schema = {
|
var schema = {
|
||||||
name: 'ColRenameTest',
|
name: 'ColRenameTest',
|
||||||
|
|
Loading…
Reference in New Issue