45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
|
|
import mysql from 'mysql2/promise';
|
|||
|
|
import type { Pool, PoolConnection, RowDataPacket, ResultSetHeader } from 'mysql2/promise';
|
|||
|
|
import { config } from './config.js';
|
|||
|
|
|
|||
|
|
export const pool: Pool = mysql.createPool({
|
|||
|
|
...config.db,
|
|||
|
|
connectionLimit: 10,
|
|||
|
|
charset: 'utf8mb4',
|
|||
|
|
timezone: 'Z',
|
|||
|
|
dateStrings: false,
|
|||
|
|
namedPlaceholders: false,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Alle Zeiten in UTC, auch die DB-Defaults (CURRENT_TIMESTAMP) – sonst Versatz zur Serverzeit.
|
|||
|
|
(pool as unknown as { on(e: string, f: (c: { query(s: string): void }) => void): void }).on('connection', (c) => c.query("SET time_zone = '+00:00'"));
|
|||
|
|
|
|||
|
|
export type Row = RowDataPacket;
|
|||
|
|
type Exec = Pick<Pool | PoolConnection, 'execute'>;
|
|||
|
|
|
|||
|
|
export async function query<T extends Row = Row>(sql: string, params: unknown[] = [], c: Exec = pool): Promise<T[]> {
|
|||
|
|
const [rows] = await c.execute<T[]>(sql, params as never[]);
|
|||
|
|
return rows;
|
|||
|
|
}
|
|||
|
|
export async function one<T extends Row = Row>(sql: string, params: unknown[] = [], c: Exec = pool): Promise<T | undefined> {
|
|||
|
|
return (await query<T>(sql, params, c))[0];
|
|||
|
|
}
|
|||
|
|
export async function run(sql: string, params: unknown[] = [], c: Exec = pool): Promise<ResultSetHeader> {
|
|||
|
|
const [res] = await c.execute<ResultSetHeader>(sql, params as never[]);
|
|||
|
|
return res;
|
|||
|
|
}
|
|||
|
|
export async function tx<T>(fn: (c: PoolConnection) => Promise<T>): Promise<T> {
|
|||
|
|
const c = await pool.getConnection();
|
|||
|
|
try {
|
|||
|
|
await c.beginTransaction();
|
|||
|
|
const out = await fn(c);
|
|||
|
|
await c.commit();
|
|||
|
|
return out;
|
|||
|
|
} catch (e) {
|
|||
|
|
await c.rollback();
|
|||
|
|
throw e;
|
|||
|
|
} finally {
|
|||
|
|
c.release();
|
|||
|
|
}
|
|||
|
|
}
|