0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Added a foreign key in migration utils

no issue

- This makes it easy to add/remove foreign key in both mysql and sqlite
This commit is contained in:
Thibaut Patel 2021-02-24 22:07:16 +01:00 committed by Thibaut Patel
parent 68aa016264
commit c8af2d4a04

View file

@ -145,6 +145,96 @@ async function dropUnique(tableName, columns, transaction) {
}
}
/**
* Checks if a foreign key exists in a table over the given columns.
*
* @param {Object} configuration - contains all configuration for this function
* @param {string} configuration.fromTableName - name of the table to add the foreign key to
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
* @param {string} configuration.toTableName - name of the table to point the foreign key to
* @param {string} configuration.toColumn - column of the table to point the foreign key to
* @param {Object} configuration.transaction - connection object containing knex reference
* @param {Object} configuration.transaction.knex - knex instance
*/
async function hasForeign({fromTable, fromColumn, toTable, toColumn, transaction}) {
const knex = (transaction || db.knex);
const client = knex.client.config.client;
if (client === 'mysql') {
const dbName = knex.client.config.connection.database;
const [rawConstraints] = await knex.raw(`
SELECT i.TABLE_NAME, k.COLUMN_NAME, k.REFERENCED_TABLE_NAME, k.REFERENCED_COLUMN_NAME
FROM information_schema.TABLE_CONSTRAINTS i
INNER JOIN information_schema.KEY_COLUMN_USAGE k ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME
WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY'
AND i.CONSTRAINT_SCHEMA=:dbName
AND i.TABLE_NAME = :fromTable
AND k.COLUMN_NAME = :fromColumn
AND k.REFERENCED_TABLE_NAME = :toTable
AND k.REFERENCED_COLUMN_NAME = :toColumn`, {dbName, fromTable, fromColumn, toTable, toColumn});
return rawConstraints.length >= 1;
} else {
const foreignKeys = await knex.raw(`PRAGMA foreign_key_list('${fromTable}');`);
const hasForeignKey = foreignKeys.some(foreignKey => foreignKey.table === toTable && foreignKey.from === fromColumn && foreignKey.to === toColumn);
return hasForeignKey;
}
}
/**
* Adds a foreign key to a table.
*
* @param {Object} configuration - contains all configuration for this function
* @param {string} configuration.fromTableName - name of the table to add the foreign key to
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
* @param {string} configuration.toTableName - name of the table to point the foreign key to
* @param {string} configuration.toColumn - column of the table to point the foreign key to
* @param {Object} configuration.transaction - connection object containing knex reference
* @param {Object} configuration.transaction.knex - knex instance
*/
async function addForeign({fromTable, fromColumn, toTable, toColumn, cascade = false, transaction}) {
const hasForeignKey = await hasForeign({fromTable, fromColumn, toTable, toColumn, transaction});
if (!hasForeignKey) {
logging.info(`Adding foreign key for: ${fromColumn} in ${fromTable} to ${toColumn} in ${toTable}`);
return (transaction || db.knex).schema.table(fromTable, function (table) {
if (cascade) {
table.foreign(fromColumn).references(`${toTable}.${toColumn}`).onDelete('CASCADE');
} else {
table.foreign(fromColumn).references(`${toTable}.${toColumn}`);
}
});
} else {
logging.warn(`Skipped adding foreign key for ${fromColumn} in ${fromTable} to ${toColumn} in ${toTable} - foreign key already exists`);
}
}
/**
* Drops a foreign key from a table.
*
* @param {Object} configuration - contains all configuration for this function
* @param {string} configuration.fromTableName - name of the table to add the foreign key to
* @param {string} configuration.fromColumn - column of the table to add the foreign key to
* @param {string} configuration.toTableName - name of the table to point the foreign key to
* @param {string} configuration.toColumn - column of the table to point the foreign key to
* @param {Object} configuration.transaction - connection object containing knex reference
* @param {Object} configuration.transaction.knex - knex instance
*/
async function dropForeign({fromTable, fromColumn, toTable, toColumn, transaction}) {
const hasForeignKey = await hasForeign({fromTable, fromColumn, toTable, toColumn, transaction});
if (hasForeignKey) {
logging.info(`Dropping foreign key for: ${fromColumn} in ${fromTable} to ${toColumn} in ${toTable}`);
return (transaction || db.knex).schema.table(fromTable, function (table) {
table.dropForeign(fromColumn);
});
} else {
logging.warn(`Skipped dropping foreign key for ${fromColumn} in ${fromTable} to ${toColumn} in ${toTable} - foreign key does not exist`);
}
}
/**
* Checks if primary key index exists in a table over the given columns.
*
@ -302,6 +392,8 @@ module.exports = {
addUnique: addUnique,
dropUnique: dropUnique,
addPrimaryKey: addPrimaryKey,
addForeign: addForeign,
dropForeign: dropForeign,
addColumn: addColumn,
dropColumn: dropColumn,
getColumns: getColumns,