Permalink
Browse files

fix(project): shift foreign key policy to avoid bugs with circular re…

…fs and improve performance
  • Loading branch information...
RWOverdijk committed Jan 27, 2018
1 parent 0654f30 commit 5d50d5491db7995ae2a1fc2b40e17dfbc299af54
Showing with 144 additions and 139 deletions.
  1. +98 −56 src/SchemaBuilder.ts
  2. +46 −83 src/SnapshotManager.ts
@@ -176,6 +176,9 @@ export class SchemaBuilder {
let instructions = instructionSets[store];
let code = [];
// Drop foreign keys
useForeignKeys && this.buildDropForeignKeys(instructions.foreign.drop, code, spacing);
// Rename tables
if (Array.isArray(instructions.rename) && instructions.rename.length) {
instructions.rename.forEach(rename => {
@@ -185,24 +188,20 @@ export class SchemaBuilder {
code.push('');
}
this.buildTable(useForeignKeys, 'alter', false, instructions, code, spacing);
this.buildTable(useForeignKeys, 'create', true, instructions, code, spacing);
instructions.alter.forEach(alterData => {
let tableName = alterData.tableName;
if (useForeignKeys && alterData.info.foreign && alterData.info.foreign.length) {
let mockInstructions = {alter: [{tableName, info: {foreign: alterData.info.foreign}}]};
// Alter tables.
this.buildTable('alter', false, instructions, code, spacing);
this.buildTable(useForeignKeys, 'alter', true, mockInstructions, code, spacing);
}
});
// Create new tables
this.buildTable('create', true, instructions, code, spacing);
// Drop tables
instructions.drop.forEach(drop => {
code.push(`\n${spacing()}builder.schema.dropTable('${drop}');`);
});
// Create foreign keys
useForeignKeys && this.buildCreateForeignKeys(instructions.foreign.create, code, spacing);
if (code.length) {
allCode.push(`${spacing()}let builder = migration.getBuilder(${`'${store}'` || ''});`);
@@ -216,26 +215,109 @@ export class SchemaBuilder {
return this;
}
private buildDropForeignKeys(drop, code, spacing) {
const tableNames = Reflect.ownKeys(drop);
if (!tableNames.length) {
return;
}
tableNames.forEach(tableName => {
const toDrop = drop[tableName];
code.push(`\n${spacing()}builder.schema.alterTable('${tableName}', table => {`);
spacing(2);
// Drop foreign keys
toDrop.forEach(key => code.push(`${spacing()}table.dropForeign('${key}');`));
spacing(-2);
code.push(`${spacing()}});`);
});
}
// @todo check typings in all my changes.
private buildCreateForeignKeys(create, code, spacing) {
const tableNames = Reflect.ownKeys(create);
if (!tableNames.length) {
return;
}
tableNames.forEach(tableName => {
const toCreate = create[tableName];
code.push(`\n${spacing()}builder.schema.alterTable('${tableName}', table => {`);
spacing(2);
// Create foreign keys.
toCreate.forEach(foreign => {
let foreignCode = spacing();
foreignCode += `table.foreign(${JSON.stringify(foreign.columns).replace(/"/g, "'")})`;
foreignCode += `.references('${foreign.references}').inTable('${foreign.inTable}')`;
if (foreign.onDelete) {
foreignCode += `.onDelete('${foreign.onDelete}')`;
}
if (foreign.onUpdate) {
foreignCode += `.onUpdate('${foreign.onUpdate}')`;
}
foreignCode += ';';
code.push(foreignCode);
});
spacing(-2);
code.push(`${spacing()}});`);
});
}
/**
* Create a foreign key.
*
* @param {{}} table
* @param {function} spacing
* @param {string[]} code
*/
private buildCreateForeigssnKeys(table: {foreign: Array<any>}, spacing: (change?: number) => string, code: Array<string>): void {
table.foreign.forEach(foreign => {
let foreignCode = spacing();
foreignCode += `table.foreign(${JSON.stringify(foreign.columns).replace(/"/g, "'")})`;
foreignCode += `.references('${foreign.references}').inTable('${foreign.inTable}')`;
if (foreign.onDelete) {
foreignCode += `.onDelete('${foreign.onDelete}')`;
}
if (foreign.onUpdate) {
foreignCode += `.onUpdate('${foreign.onUpdate}')`;
}
foreignCode += ';';
code.push(foreignCode);
});
}
/**
* Build table.
*
* @param {boolean} useForeign
* @param {string} action
* @param {boolean} createForeign
* @param {{}} instructions
* @param {string[]} code
* @param {function} spacing
*/
private buildTable(useForeign: boolean,
action: string,
private buildTable(action: string,
createForeign: boolean,
instructions: any,
code: Array<string>,
spacing: (change?: number)=>string) {
instructions[action].forEach(actionData => {
let tableName = actionData.tableName;
let table = actionData.info;
let hasDropForeign = Array.isArray(table.dropForeign) && table.dropForeign.length;
let hasDropColumns = Array.isArray(table.dropColumn) && table.dropColumn.length;
let pushedBuilder = false;
let ensureBuilder = () => {
@@ -261,17 +343,10 @@ export class SchemaBuilder {
pushedBuilder = true;
};
if (hasDropForeign || hasDropColumns) {
if (hasDropColumns) {
code.push(`\n${spacing()}builder.schema.${action}Table('${tableName}', table => {`);
spacing(2);
// Drop foreign
if (useForeign && hasDropForeign) {
table.dropForeign.forEach(dropForeign => {
code.push(`${spacing()}table.dropForeign('${dropForeign}');`);
});
}
// Drop columns
if (hasDropColumns) {
table.dropColumn.forEach(column => {
@@ -337,46 +412,13 @@ export class SchemaBuilder {
});
}
if (useForeign && createForeign && table.foreign && table.foreign.length) {
ensureBuilder();
this.createForeign(table, spacing, code);
}
if (pushedBuilder) {
spacing(-2);
code.push(`${spacing()}});`);
}
});
}
/**
* Create a foreign key.
*
* @param {{}} table
* @param {function} spacing
* @param {string[]} code
*/
private createForeign(table: {foreign: Array<any>}, spacing: (change?: number) => string, code: Array<string>): void {
table.foreign.forEach(foreign => {
let foreignCode = spacing();
foreignCode += `table.foreign(${JSON.stringify(foreign.columns).replace(/"/g, "'")})`;
foreignCode += `.references('${foreign.references}').inTable('${foreign.inTable}')`;
if (foreign.onDelete) {
foreignCode += `.onDelete('${foreign.onDelete}')`;
}
if (foreign.onUpdate) {
foreignCode += `.onUpdate('${foreign.onUpdate}')`;
}
foreignCode += ';';
code.push(foreignCode);
});
}
/**
* Compose a field.
*
Oops, something went wrong.

0 comments on commit 5d50d54

Please sign in to comment.