68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
import _ from "lodash";
|
|
import type {
|
|
BUN_MARIADB_DatabaseSchemaType,
|
|
BUN_MARIADB_TableSchemaType,
|
|
CreateDBSchemaParams,
|
|
} from "../../types";
|
|
|
|
/**
|
|
* Topologically order tables so referenced (parent) tables come before the
|
|
* tables that reference them. Declaration order is kept wherever the FK
|
|
* graph allows it.
|
|
*
|
|
* - Self references (e.g. `comments.parent_comment_id`) are ignored.
|
|
* - References to tables outside the schema are ignored.
|
|
* - Cycles do not throw: a table already on the current path is skipped,
|
|
* so every table is still emitted exactly once. Foreign keys are created
|
|
* after all tables exist, so cycles are safe to sync.
|
|
*/
|
|
export default async function orderDBSchema({
|
|
db_schema,
|
|
}: CreateDBSchemaParams): Promise<BUN_MARIADB_DatabaseSchemaType> {
|
|
const new_db_schema = _.cloneDeep(db_schema);
|
|
const tables = new_db_schema.tables;
|
|
|
|
const tables_by_name = new Map<string, BUN_MARIADB_TableSchemaType>();
|
|
for (const table of tables) {
|
|
if (table) tables_by_name.set(table.tableName, table);
|
|
}
|
|
|
|
const ordered: BUN_MARIADB_TableSchemaType[] = [];
|
|
const visited = new Set<string>();
|
|
const visiting = new Set<string>();
|
|
|
|
function visit(table: BUN_MARIADB_TableSchemaType) {
|
|
if (visited.has(table.tableName) || visiting.has(table.tableName)) {
|
|
return;
|
|
}
|
|
|
|
visiting.add(table.tableName);
|
|
|
|
for (const field of table.fields || []) {
|
|
const dst_table_name = field?.foreignKey?.destinationTableName;
|
|
|
|
if (!dst_table_name || dst_table_name === table.tableName) {
|
|
continue;
|
|
}
|
|
|
|
const fk_table = tables_by_name.get(dst_table_name);
|
|
|
|
if (fk_table) {
|
|
visit(fk_table);
|
|
}
|
|
}
|
|
|
|
visiting.delete(table.tableName);
|
|
visited.add(table.tableName);
|
|
ordered.push(table);
|
|
}
|
|
|
|
for (const table of tables) {
|
|
if (table) visit(table);
|
|
}
|
|
|
|
new_db_schema.tables = ordered;
|
|
|
|
return new_db_schema;
|
|
}
|