Files
MikrotikManager/backend/src/db/index.ts
T
DenozordecandCursor ec43591a99
Docker images / prepare-release (push) Successful in 12s
Docker images / backend-test (push) Successful in 4m9s
Docker images / frontend-image (push) Successful in 4m28s
Docker images / updater-image (push) Successful in 58s
Docker images / backend-image (push) Successful in 2m49s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s
feat(db): перевести хранилище с SQLite на PostgreSQL
При старте backend накатывает схему PostgreSQL 18 и, если база пустая, один раз импортирует mikrotik.db с тома. Повторный старт не копирует данные. Бэкап в UI идёт через pg_dump.

Co-authored-by: Cursor <[email protected]>
2026-09-08 01:36:48 +07:00

72 lines
1.9 KiB
TypeScript

import { isMainThread } from "node:worker_threads"
import pg from "pg"
import { drizzle } from "drizzle-orm/node-postgres"
import { env } from "../config.js"
import * as schema from "./schema.js"
import { bindSql } from "./sql-bind.js"
const INT8_OID = 20
const DATE_OID = 1082
pg.types.setTypeParser(INT8_OID, (val) => {
const n = Number(val)
return Number.isSafeInteger(n) ? n : val
})
pg.types.setTypeParser(DATE_OID, (val) => val)
export function createPool(max = 16): pg.Pool {
return new pg.Pool({
connectionString: env.DATABASE_URL,
max,
idleTimeoutMillis: 30_000,
connectionTimeoutMillis: 8_000,
statement_timeout: 120_000,
})
}
export const pool = createPool(isMainThread ? 16 : 4)
export const db = drizzle(pool, { schema })
export async function dbQuery<T extends pg.QueryResultRow = pg.QueryResultRow>(
text: string,
params?: unknown[] | Record<string, unknown>,
): Promise<pg.QueryResult<T>> {
const q = bindSql(text, params)
return pool.query<T>(q)
}
export async function dbAll<T extends pg.QueryResultRow = pg.QueryResultRow>(
text: string,
params?: unknown[] | Record<string, unknown>,
): Promise<T[]> {
const res = await dbQuery<T>(text, params)
return res.rows
}
export async function dbGet<T extends pg.QueryResultRow = pg.QueryResultRow>(
text: string,
params?: unknown[] | Record<string, unknown>,
): Promise<T | undefined> {
const rows = await dbAll<T>(text, params)
return rows[0]
}
export async function withAdvisoryLock<T>(key: number, fn: () => Promise<T>): Promise<T> {
const client = await pool.connect()
try {
await client.query("SELECT pg_advisory_lock($1)", [key])
return await fn()
} finally {
try {
await client.query("SELECT pg_advisory_unlock($1)", [key])
} catch {
/* ignore */
}
client.release()
}
}
export async function closePool(): Promise<void> {
await pool.end()
}