You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
vore-rpg/src/database/index.ts

75 lines
2.5 KiB

import {QueryResult, QueryResultRow} from "pg"
import {UsersTable, UsersTableImpl} from "./users.js"
import {BattleTypeTables, BattleTypeTablesImpl} from "./battle_types";
import {GenderTables, GenderTablesImpl} from "./gender";
export interface PoolLike {
connect(): Promise<PoolClientLike>
}
export interface PoolClientLike extends Queryable {
release(err?: boolean): void
}
export function makeTransact(p: PoolLike): TransactType {
return async function transact({readonly=false, transaction}: {readonly?: boolean, transaction: (q: QueryType, attempts: number) => Promise<void>}): Promise<void> {
const client = await p.connect()
const query = client.query.bind(client)
let committed = false
let attempts = 0
while (!committed) {
try {
await client.query("BEGIN READ " + (readonly ? "ONLY" : "WRITE"))
} catch (err) {
client.release()
throw err
}
try {
await transaction(query, attempts)
} catch (err) {
try {
await client.query("ROLLBACK")
client.release()
} catch (err) {
client.release(true)
}
throw err
}
try {
await client.query("COMMIT")
committed = true
} catch (err) {
attempts += 1
}
}
client.release()
}
}
export interface Database {
readonly users: UsersTable
readonly gender: GenderTables
readonly battleTypes: BattleTypeTables
}
export interface Queryable {
query<RowT extends QueryResultRow>(queryText: string): Promise<QueryResult<RowT>>
query<RowT extends QueryResultRow, ParamT extends any[]>(queryText: string,
params: ParamT): Promise<QueryResult<RowT>>
}
export type QueryType = Queryable["query"]
export type TransactType = (config: {readonly?: boolean, transaction: (client: QueryType, attempts: number) => Promise<void>}) => Promise<void>
export class DatabaseImpl implements Database {
readonly users: UsersTableImpl
readonly gender: GenderTables
readonly battleTypes: BattleTypeTablesImpl
constructor({query, transact}: { query: QueryType, transact: TransactType }) {
this.users = new UsersTableImpl({query})
this.gender = new GenderTablesImpl({transact})
this.battleTypes = new BattleTypeTablesImpl({transact})
}
}