Schema-Aenderungen als eigene Migration nachziehen
Die erste Migration wurde nachtraeglich mehrfach erweitert, statt Aenderungen anzuhaengen. Auf einer bestehenden Installation gilt sie als angewendet und wird uebersprungen - die seither hinzugekommenen Tabellen fehlten dort also schlicht, ohne dass beim Start etwas auffiel. Die Antragsseite lief dadurch in einen internen Fehler. Die neue Migration ergaenzt alles Fehlende und ist durchgehend mit IF NOT EXISTS geschrieben, weil bestehende Datenbanken je nach Zeitpunkt der Einrichtung unterschiedliche Staende haben. Geprueft gegen eine frische Datenbank, gegen eine auf altem Stand und auf mehrfaches Anwenden. Der Testharness wendet jetzt alle Migrationen der Reihe nach an statt nur der ersten - sonst faellt so etwas beim naechsten Mal wieder nicht auf. Ausserdem scheiterte das Buchen komplett, wenn eine Bestellung zwischenzeitlich ueber einen anderen Import gebucht worden war: die eindeutige Bestell-ID kippte die gesamte Transaktion. Solche Zeilen werden jetzt uebersprungen und gezaehlt, die uebrigen laufen durch. Dazu fehlten in der Oberflaeche die Wege zum Bearbeiten und Loeschen eines Spielers, obwohl es die Endpunkte gab. Beides ist jetzt auf der Spielerseite erreichbar; das Loeschen verlangt den Namen als Bestaetigung und benennt vorher, was mit verschwindet.
This commit is contained in:
+13
-3
@@ -1,11 +1,19 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { PGlite } from '@electric-sql/pglite';
|
||||
import { PGLiteSocketServer } from '@electric-sql/pglite-socket';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const MIGRATION = join(here, '..', 'prisma', 'migrations', '20250101000000_init', 'migration.sql');
|
||||
const MIGRATIONS_DIR = join(here, '..', 'prisma', 'migrations');
|
||||
|
||||
/** Alle Migrationen in der Reihenfolge, in der Prisma sie anwenden würde. */
|
||||
function migrationFiles(): string[] {
|
||||
return readdirSync(MIGRATIONS_DIR)
|
||||
.filter((entry) => /^\d/.test(entry))
|
||||
.sort()
|
||||
.map((entry) => join(MIGRATIONS_DIR, entry, 'migration.sql'));
|
||||
}
|
||||
|
||||
export interface TestDatabase {
|
||||
url: string;
|
||||
@@ -19,7 +27,9 @@ export interface TestDatabase {
|
||||
*/
|
||||
export async function startTestDatabase(port: number): Promise<TestDatabase> {
|
||||
const db = await PGlite.create();
|
||||
await db.exec(readFileSync(MIGRATION, 'utf8'));
|
||||
for (const file of migrationFiles()) {
|
||||
await db.exec(readFileSync(file, 'utf8'));
|
||||
}
|
||||
|
||||
const server = new PGLiteSocketServer({ db, port, host: '127.0.0.1' });
|
||||
await server.start();
|
||||
|
||||
@@ -201,3 +201,43 @@ describe('Vorschau und Buchung', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Kollisionen beim Buchen', () => {
|
||||
it('überspringt eine Bestellung, die inzwischen anderswo gebucht wurde', async () => {
|
||||
const csv = ['Bestellnummer;Steam-ID;Produkt', 'K-1;76561198000000077;CC-Paket'].join('\n');
|
||||
const mapping = {
|
||||
playerKey: 'Steam-ID',
|
||||
product: 'Produkt',
|
||||
orderId: 'Bestellnummer',
|
||||
createMissingPlayers: true,
|
||||
};
|
||||
|
||||
// Zwei Vorschauen mit derselben Bestellung - so entstanden durch mehrfachen Abgleich.
|
||||
const ersteVorschau = await imports.createImport(
|
||||
'erste.csv',
|
||||
imports.parseUpload('erste.csv', Buffer.from(csv, 'utf8')),
|
||||
ctx,
|
||||
);
|
||||
const zweiteVorschau = await imports.createImport(
|
||||
'zweite.csv',
|
||||
imports.parseUpload('zweite.csv', Buffer.from(csv, 'utf8')),
|
||||
ctx,
|
||||
);
|
||||
await imports.applyMapping(ersteVorschau, mapping, ctx);
|
||||
await imports.applyMapping(zweiteVorschau, mapping, ctx);
|
||||
|
||||
const erste = await imports.commitImport(ersteVorschau, ctx);
|
||||
assert.equal(erste.booked, 1);
|
||||
|
||||
// Früher scheiterte hier der gesamte Import an der eindeutigen Bestell-ID.
|
||||
const zweite = await imports.commitImport(zweiteVorschau, ctx);
|
||||
assert.equal(zweite.booked, 0);
|
||||
assert.equal(zweite.skipped, 1, 'die Zeile wird übersprungen, nicht der Import abgebrochen');
|
||||
|
||||
const player = await db.prisma.player.findUniqueOrThrow({
|
||||
where: { steamId: '76561198000000077' },
|
||||
});
|
||||
const balances = await credits.getBalances(player.id);
|
||||
assert.equal(balances.CC, 1, 'genau einmal gebucht, nicht doppelt');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user