fix(db): desacopla configuracao administrativa das migrations
ci / lint, typecheck, testes e build (push) Canceled after 0s
ci / Postgres e Redis reais (push) Canceled after 0s
ci / imagem Docker Linux (push) Canceled after 0s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
camilafagundesandCursor committed 2026-10-24 01:14:00 -03:00
1 parent 93f280621b
commit 8cfeeb0464
7 files changed
+356 -29

No files matched your search

+38 -4
View File
@@ -29,12 +29,46 @@ export function isShimMigration(file: string): boolean {
export type PendingOptions = { applyIdentityShim?: boolean };
export type MigrationLedger = { state: "ausente" } | { state: "presente"; ids: string[] };
/** A leitura do histórico falhou. Não é o mesmo que tabela ausente. */
export class MigrationLedgerError extends Error {
readonly code = "historico_indisponivel";
constructor() {
super("historico_indisponivel");
this.name = "MigrationLedgerError";
}
}
/**
* Lê o histórico sem criá-lo. Tabela ausente é um estado explícito. Falha de
* permissão, conexão ou consulta interrompe: não vira lista vazia.
*/
export async function readMigrationLedger(db: Db): Promise<MigrationLedger> {
let presence: { name: string | null }[];
try {
presence = await db.withService((query) =>
query.query<{ name: string | null }>("select to_regclass('public.schema_migrations')::text as name"),
);
} catch {
throw new MigrationLedgerError();
}
if (!presence[0]?.name) return { state: "ausente" };
try {
const rows = await db.withService((query) =>
query.query<{ id: string }>("select id from public.schema_migrations order by id"),
);
return { state: "presente", ids: rows.map((row) => row.id) };
} catch {
throw new MigrationLedgerError();
}
}
/** Migrations esperadas que ainda não constam em `schema_migrations`. */
export async function pendingMigrations(db: Db, options: PendingOptions = {}): Promise<string[]> {
const applyShim = options.applyIdentityShim ?? identityShimEnabled();
const appliedRows = await db
.withService((query) => query.query<{ id: string }>("select id from public.schema_migrations"))
.catch(() => [] as { id: string }[]);
const applied = new Set(appliedRows.map((row) => row.id));
const ledger = await readMigrationLedger(db);
const applied = new Set(ledger.state === "presente" ? ledger.ids : []);
return EXPECTED_MIGRATIONS.filter((file) => !applied.has(file) && (applyShim || !isShimMigration(file)));
}