Zwei Funde beim Nachsehen, warum `pnpm db:migrate` hängt.
**Der Befehl hing nicht, er fragte.** `prisma migrate dev` fand einen
Unterschied zwischen schema.prisma und den Migrationen und wartete auf einen
Namen für eine neue Migration. Deren Inhalt wäre gewesen, den GIN-Index über
den Suchvektor zu löschen: er stand nur in der Migration, weil
Unsupported("tsvector") dazu verleitet, den Index für nicht darstellbar zu
halten. Er ist darstellbar. Wer die Frage in Eile beantwortet hätte, hätte die
gestufte Volltextsuche verloren und es erst gemerkt, wenn die Suche leer
bleibt.
packages/db/tests/schema-drift.test.ts prüft das jetzt und nennt im Fehlerfall
das fehlende Stück. Gegengeprobt: ohne die Zeile im Schema schlägt der Test an.
Die Sperre, an der der zweite Versuch scheiterte (P1002), hielt eine verwaiste
Verbindung eines abgeschossenen migrate-dev. Wie man den Halter findet und
freigibt, steht jetzt in docs/11.
**Die Testdatenbank wird verworfen und neu angelegt.** Weil Akten nicht
löschbar sind, hatte sie 2487 angesammelt, und drei Zusicherungen auf eine auf
zehn Einträge begrenzte Liste fanden ihre eigene Akte nicht mehr darin. Das
sieht aus wie ein Fehler im Code und ist keiner. Neu aufsetzen kostet
dreieinhalb Sekunden; KEEP_TEST_DB=1 behält den Bestand.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { execFileSync } from 'node:child_process'
|
|
import path from 'node:path'
|
|
|
|
/**
|
|
* Schema und Migrationen dürfen nicht auseinanderlaufen.
|
|
*
|
|
* Der Anlass war handfest: ein von Hand angelegter GIN-Index über den
|
|
* Suchvektor stand in der Migration, aber nicht in `schema.prisma`. Prisma
|
|
* hielt das für einen Rückstand und fragte bei jedem `migrate dev` nach einem
|
|
* Namen für eine neue Migration — deren Inhalt gewesen wäre, **den Suchindex
|
|
* zu löschen**. Wer die Frage in Eile beantwortet, verliert die gestufte
|
|
* Volltextsuche und merkt es erst, wenn die Suche leer bleibt.
|
|
*
|
|
* Der Vergleich läuft gegen die Datenbank, auf die der Testlauf zeigt. Sie
|
|
* trägt alle Migrationen, also ist ein Unterschied zum Schema genau der
|
|
* Rückstand, den `migrate dev` sonst anbietet.
|
|
*
|
|
* `--exit-code`: 0 heisst kein Unterschied, 2 heisst Unterschied.
|
|
*/
|
|
const url = process.env.DIRECT_DATABASE_URL ?? process.env.DATABASE_URL
|
|
const suite = url ? describe : describe.skip
|
|
|
|
suite('Schema und Migrationen', () => {
|
|
it('haben keinen Unterschied, den migrate dev anbieten würde', () => {
|
|
const wurzel = path.resolve(__dirname, '..')
|
|
|
|
let ausgabe = ''
|
|
let code = 0
|
|
try {
|
|
ausgabe = execFileSync(
|
|
'node',
|
|
[
|
|
require.resolve('prisma/build/index.js', { paths: [wurzel] }),
|
|
'migrate',
|
|
'diff',
|
|
'--from-config-datasource',
|
|
'--to-schema',
|
|
path.join('prisma', 'schema.prisma'),
|
|
'--script',
|
|
'--exit-code',
|
|
],
|
|
{ cwd: wurzel, encoding: 'utf8', env: { ...process.env }, timeout: 120_000 },
|
|
)
|
|
} catch (error) {
|
|
const fehler = error as { status?: number; stdout?: string; stderr?: string }
|
|
code = fehler.status ?? 1
|
|
ausgabe = `${fehler.stdout ?? ''}${fehler.stderr ?? ''}`
|
|
}
|
|
|
|
// Die Meldung nennt das fehlende Stück, damit man nicht suchen muss.
|
|
expect(ausgabe.replace(/^Loaded Prisma config.*$/m, '').trim(), ausgabe).not.toMatch(
|
|
/^--\s*(Create|Drop|Alter|Add)/m,
|
|
)
|
|
expect(code, ausgabe).toBe(0)
|
|
}, 130_000)
|
|
})
|