metis-desk/modules/resources/src/api/infrastructure/persistence/resource-relational-sql.ts
2026-10-10 13:32:40 +02:00

59 lines
2.0 KiB
TypeScript

import type { Sequelize, Transaction } from "sequelize";
import { QueryTypes } from "sequelize";
/** Identificadores internos; los valores externos siempre se parametrizan. */
export function sqlIdentifier(value: string) {
return `\`${value.replaceAll("`", "``")}\``;
}
export async function writeResourceRow(
database: Sequelize,
table: string,
row: Record<string, string | number | boolean | null>,
transaction: Transaction
) {
const columns = Object.keys(row);
await database.query(
`INSERT INTO ${sqlIdentifier(table)} (${columns.map(sqlIdentifier).join(",")}) VALUES (${columns.map((key) => `:${key}`).join(",")}) ON DUPLICATE KEY UPDATE ${columns.map((key) => `${sqlIdentifier(key)}=VALUES(${sqlIdentifier(key)})`).join(",")}`,
{ replacements: row, transaction }
);
}
export async function readResourceRows<T extends object>(
database: Sequelize,
table: string,
column: string,
ids: readonly string[],
transaction: Transaction
) {
if (!ids.length) {
return [];
}
return database.query<T>(
`SELECT * FROM ${sqlIdentifier(table)} WHERE ${sqlIdentifier(column)} IN (:ids)`,
{ replacements: { ids }, type: QueryTypes.SELECT, transaction }
);
}
export async function removeResourceColumn(database: Sequelize, table: string, column: string) {
const columns = await database.getQueryInterface().describeTable(table);
if (!(column in columns)) {
return;
}
const constraints = await database.query<{ name: string }>(
"SELECT CONSTRAINT_NAME AS name FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=:table AND COLUMN_NAME=:column AND REFERENCED_TABLE_NAME IS NOT NULL",
{ replacements: { table, column }, type: QueryTypes.SELECT }
);
for (const { name } of constraints) {
await database.query(
`ALTER TABLE ${sqlIdentifier(table)} DROP FOREIGN KEY ${sqlIdentifier(name)}`
);
}
// Evita el fallo de QueryInterface.removeColumn con Sequelize 6 y mariadb 3.
await database.query(`ALTER TABLE ${sqlIdentifier(table)} DROP COLUMN ${sqlIdentifier(column)}`);
}