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.
71 lines
2.3 KiB
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})
|
|
}
|
|
} |