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.
75 lines
2.5 KiB
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})
|
|
}
|
|
} |