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
При старте backend накатывает схему PostgreSQL 18 и, если база пустая, один раз импортирует mikrotik.db с тома. Повторный старт не копирует данные. Бэкап в UI идёт через pg_dump. Co-authored-by: Cursor <[email protected]>
72 lines
1.9 KiB
TypeScript
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()
|
|
}
|