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/database.ts

71 lines
2.3 KiB

import {QueryResult, QueryResultRow} from "pg"
import {UsersTable, UsersTableImpl} from "./users.js"
import {CharacterCreationTable, CharacterCreationTableImpl} from "./character_creation.js"
export interface PoolLike {
connect(): Promise<PoolClientLike>
}
export interface PoolClientLike extends Queryable {
release(err?: boolean): void
}
export function makeTransactable(p: PoolLike): Transactable {
return async function transactable(callback: (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")
} catch (err) {
client.release()
throw err
}
try {
await callback(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 characterCreation: CharacterCreationTable
}
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 Transactable = (transaction: (client: QueryType, attempts: number) => Promise<void>) => Promise<void>
export class DatabaseImpl implements Database {
readonly users: UsersTableImpl
readonly characterCreation: CharacterCreationTableImpl
constructor({query, transactable}: { query: QueryType, transactable: Transactable }) {
this.users = new UsersTableImpl({query})
this.characterCreation = new CharacterCreationTableImpl({query, transactable})
}
}