diff --git a/scripts/check-schema-types.mjs b/scripts/check-schema-types.mjs index e22f561..6d65099 100644 --- a/scripts/check-schema-types.mjs +++ b/scripts/check-schema-types.mjs @@ -80,16 +80,51 @@ function parseMigrations() { tables.set(name, columns); } - for (const m of sql.matchAll(/alter table (?:if exists )?(\w+)\s+add column (?:if not exists )?(\w+)/gi)) { - tables.get(m[1])?.add(m[2].toLowerCase()); - } - for (const m of sql.matchAll(/alter table (?:if exists )?(\w+)\s+drop column (?:if exists )?(\w+)/gi)) { - tables.get(m[1])?.delete(m[2].toLowerCase()); - } - for (const m of sql.matchAll(/alter table (?:if exists )?(\w+)\s+rename column (\w+) to (\w+)/gi)) { - const t = tables.get(m[1]); - if (t?.delete(m[2].toLowerCase())) t.add(m[3].toLowerCase()); + // ── ALTER TABLE, vollständig ──────────────────────────────────── + // + // Eine Anweisung kann mehrere Klauseln tragen, durch Komma getrennt: + // + // alter table employees + // drop column if exists division_id, + // drop column if exists team_id, + // drop column if exists manager_id; + // + // Wer nur nach `alter table … drop column …` als **einem** Muster sucht, + // findet davon genau die erste. Die übrigen bleiben im Modell stehen, und der + // Abgleich meldet Spalten als vorhanden, die es seit einem Jahr nicht + // mehr gibt — genau die vier aus dem OM-Umbau. Umgekehrt fehlten drei + // später ergänzte Spalten, weil sie jeweils die zweite Klausel eines + // `add column` waren. + // + // Deshalb wird hier erst die ganze Anweisung bis zum Semikolon + // aufgesammelt und dann jede Klausel darin ausgewertet. Klammern zählen + // mit, damit ein Semikolon in einer Prüfbedingung die Anweisung nicht + // vorzeitig beendet. + for (const kopf of sql.matchAll(/alter table (?:if exists )?(\w+)/gi)) { + const tabelle = tables.get(kopf[1]); + if (!tabelle) continue; + + let tiefe = 0; + let ende = kopf.index + kopf[0].length; + for (; ende < sql.length; ende++) { + const c = sql[ende]; + if (c === "(") tiefe++; + else if (c === ")") tiefe--; + else if (c === ";" && tiefe === 0) break; + } + const anweisung = sql.slice(kopf.index + kopf[0].length, ende); + + for (const m of anweisung.matchAll(/\badd column (?:if not exists )?(\w+)/gi)) { + tabelle.add(m[1].toLowerCase()); + } + for (const m of anweisung.matchAll(/\bdrop column (?:if exists )?(\w+)/gi)) { + tabelle.delete(m[1].toLowerCase()); + } + for (const m of anweisung.matchAll(/\brename column (\w+) to (\w+)/gi)) { + if (tabelle.delete(m[1].toLowerCase())) tabelle.add(m[2].toLowerCase()); + } } + for (const m of sql.matchAll(/drop table (?:if exists )?(\w+)/gi)) { tables.delete(m[1]); }