Fix bugs, improve schema gen
This commit is contained in:
+42
-4
@@ -1,3 +1,4 @@
|
||||
import { BUN_MARIADB_ForeignKeyRules, } from "../../types";
|
||||
import MariaDBQuoteGen from "./mariadb-quote-gen";
|
||||
export function defaultForeignKeyName(tableName, fieldName) {
|
||||
return `fk_${tableName}_${fieldName}`;
|
||||
@@ -6,15 +7,52 @@ export function resolveForeignKeyName(field, tableName) {
|
||||
const fieldName = field.fieldName || "column";
|
||||
return field.foreignKey?.foreignKeyName || defaultForeignKeyName(tableName, fieldName);
|
||||
}
|
||||
/**
|
||||
* Normalize a referential action as MariaDB reports it in
|
||||
* `information_schema.REFERENTIAL_CONSTRAINTS`. InnoDB treats `NO ACTION`
|
||||
* exactly like `RESTRICT`, so both compare as `RESTRICT`.
|
||||
*/
|
||||
export function normalizeForeignKeyRule(rule) {
|
||||
const normalized = String(rule || "RESTRICT")
|
||||
.trim()
|
||||
.toUpperCase()
|
||||
.replace(/[_\s]+/g, " ");
|
||||
if (normalized === "NO ACTION")
|
||||
return "RESTRICT";
|
||||
if (!BUN_MARIADB_ForeignKeyRules.includes(normalized)) {
|
||||
throw new Error(`Invalid foreign key rule \`${rule}\`. Expected one of: ${BUN_MARIADB_ForeignKeyRules.join(", ")}`);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
/**
|
||||
* Resolve the ON DELETE / ON UPDATE actions for a field's foreign key.
|
||||
* Precedence: `foreignKey.onDelete` > field `onDeleteLiteral` / `onDelete`
|
||||
* (legacy) > `cascadeDelete` > `RESTRICT`. Same for update, except the
|
||||
* field-level `onUpdate*` keys are column `ON UPDATE` clauses, not FK rules.
|
||||
*/
|
||||
export function resolveForeignKeyRules(field, tableName) {
|
||||
const fk = field.foreignKey || {};
|
||||
const onDelete = normalizeForeignKeyRule(fk.onDelete ||
|
||||
field.onDeleteLiteral ||
|
||||
field.onDelete ||
|
||||
(fk.cascadeDelete ? "CASCADE" : "RESTRICT"));
|
||||
const onUpdate = normalizeForeignKeyRule(fk.onUpdate || (fk.cascadeUpdate ? "CASCADE" : "RESTRICT"));
|
||||
if ((onDelete === "SET NULL" || onUpdate === "SET NULL") &&
|
||||
(field.notNullValue || field.primaryKey)) {
|
||||
throw new Error(`Foreign key on \`${tableName ? `${tableName}.` : ""}${field.fieldName}\` uses SET NULL but the column is NOT NULL`);
|
||||
}
|
||||
return { onDelete, onUpdate };
|
||||
}
|
||||
export default function buildForeignKeyConstraint(field, tableName) {
|
||||
const fk = field.foreignKey;
|
||||
const constraintName = resolveForeignKeyName(field, tableName);
|
||||
const { onDelete, onUpdate } = resolveForeignKeyRules(field, tableName);
|
||||
let constraint = `CONSTRAINT ${MariaDBQuoteGen(constraintName)} FOREIGN KEY (${MariaDBQuoteGen(field.fieldName)}) REFERENCES ${MariaDBQuoteGen(fk.destinationTableName)}(${MariaDBQuoteGen(fk.destinationTableColumnName)})`;
|
||||
if (fk.cascadeDelete) {
|
||||
constraint += " ON DELETE CASCADE";
|
||||
if (onDelete !== "RESTRICT") {
|
||||
constraint += ` ON DELETE ${onDelete}`;
|
||||
}
|
||||
if (fk.cascadeUpdate) {
|
||||
constraint += " ON UPDATE CASCADE";
|
||||
if (onUpdate !== "RESTRICT") {
|
||||
constraint += ` ON UPDATE ${onUpdate}`;
|
||||
}
|
||||
return constraint;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user