Fix bugs, improve schema gen
This commit is contained in:
@@ -5,82 +5,63 @@ import type {
|
||||
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> {
|
||||
let new_db_schema = _.cloneDeep(db_schema);
|
||||
|
||||
const new_db_schema = _.cloneDeep(db_schema);
|
||||
const tables = new_db_schema.tables;
|
||||
|
||||
let new_tables_set = new Set<BUN_MARIADB_TableSchemaType>();
|
||||
let new_tables_start_set = new Set<BUN_MARIADB_TableSchemaType>();
|
||||
let new_tables_end_set = new Set<BUN_MARIADB_TableSchemaType>();
|
||||
const tables_by_name = new Map<string, BUN_MARIADB_TableSchemaType>();
|
||||
for (const table of tables) {
|
||||
if (table) tables_by_name.set(table.tableName, table);
|
||||
}
|
||||
|
||||
function setParentTable(table: BUN_MARIADB_TableSchemaType) {
|
||||
const fields = table.fields;
|
||||
let does_table_have_foreign_keys = false;
|
||||
const ordered: BUN_MARIADB_TableSchemaType[] = [];
|
||||
const visited = new Set<string>();
|
||||
const visiting = new Set<string>();
|
||||
|
||||
for (let f = 0; f < fields.length; f++) {
|
||||
const field = fields[f];
|
||||
if (!field) continue;
|
||||
function visit(table: BUN_MARIADB_TableSchemaType) {
|
||||
if (visited.has(table.tableName) || visiting.has(table.tableName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dst_table_name = field.foreignKey?.destinationTableName;
|
||||
visiting.add(table.tableName);
|
||||
|
||||
if (dst_table_name) {
|
||||
const fk_table = tables.find(
|
||||
(tb) => tb.tableName == dst_table_name,
|
||||
);
|
||||
for (const field of table.fields || []) {
|
||||
const dst_table_name = field?.foreignKey?.destinationTableName;
|
||||
|
||||
if (
|
||||
fk_table &&
|
||||
!new_tables_start_set.has(fk_table) &&
|
||||
!new_tables_end_set.has(fk_table)
|
||||
) {
|
||||
setParentTable(fk_table);
|
||||
}
|
||||
if (!dst_table_name || dst_table_name === table.tableName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
new_tables_end_set.add(table);
|
||||
const fk_table = tables_by_name.get(dst_table_name);
|
||||
|
||||
if (fk_table) {
|
||||
new_tables_start_set.add(fk_table);
|
||||
}
|
||||
|
||||
does_table_have_foreign_keys = true;
|
||||
if (fk_table) {
|
||||
visit(fk_table);
|
||||
}
|
||||
}
|
||||
|
||||
return { does_table_have_foreign_keys };
|
||||
visiting.delete(table.tableName);
|
||||
visited.add(table.tableName);
|
||||
ordered.push(table);
|
||||
}
|
||||
|
||||
for (let i = 0; i < tables.length; i++) {
|
||||
const table = tables[i];
|
||||
|
||||
if (!table) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let { does_table_have_foreign_keys } = setParentTable(table);
|
||||
|
||||
if (does_table_have_foreign_keys) {
|
||||
new_tables_end_set.add(table);
|
||||
} else {
|
||||
new_tables_start_set.add(table);
|
||||
}
|
||||
for (const table of tables) {
|
||||
if (table) visit(table);
|
||||
}
|
||||
|
||||
const parsed_tables = [
|
||||
...Array.from(new_tables_start_set),
|
||||
...Array.from(new_tables_end_set),
|
||||
];
|
||||
|
||||
for (let nt = 0; nt < parsed_tables.length; nt++) {
|
||||
const new_table = parsed_tables[nt];
|
||||
if (new_table) {
|
||||
new_tables_set.add(new_table);
|
||||
}
|
||||
}
|
||||
|
||||
new_db_schema.tables = Array.from(new_tables_set);
|
||||
new_db_schema.tables = ordered;
|
||||
|
||||
return new_db_schema;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user