forked from denodrivers/postgres
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pool.ts
112 lines (100 loc) · 2.94 KB
/
pool.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { PoolClient } from "./client.ts";
import { Connection } from "./connection.ts";
import {
ConnectionOptions,
ConnectionParams,
createParams,
} from "./connection_params.ts";
import { DeferredStack } from "./deferred.ts";
import { Query, QueryConfig, QueryResult } from "./query.ts";
export class Pool {
private _connectionParams: ConnectionParams;
private _connections!: Array<Connection>;
private _availableConnections!: DeferredStack<Connection>;
private _maxSize: number;
public ready: Promise<void>;
private _lazy: boolean;
constructor(
connectionParams: ConnectionOptions,
maxSize: number,
lazy?: boolean,
) {
this._connectionParams = createParams(connectionParams);
this._maxSize = maxSize;
this._lazy = !!lazy;
this.ready = this._startup();
}
private async _createConnection(): Promise<Connection> {
const connection = new Connection(this._connectionParams);
await connection.startup();
await connection.initSQL();
return connection;
}
/** pool max size */
get maxSize(): number {
return this._maxSize;
}
/** number of connections created */
get size(): number {
if (this._availableConnections == null) {
return 0;
}
return this._availableConnections.size;
}
/** number of available connections */
get available(): number {
if (this._availableConnections == null) {
return 0;
}
return this._availableConnections.available;
}
private async _startup(): Promise<void> {
const initSize = this._lazy ? 1 : this._maxSize;
const connecting = [...Array(initSize)].map(async () =>
await this._createConnection()
);
this._connections = await Promise.all(connecting);
this._availableConnections = new DeferredStack(
this._maxSize,
this._connections,
this._createConnection.bind(this),
);
}
private async _execute(query: Query): Promise<QueryResult> {
await this.ready;
const connection = await this._availableConnections.pop();
try {
const result = await connection.query(query);
return result;
} catch (error) {
throw error;
} finally {
this._availableConnections.push(connection);
}
}
async connect(): Promise<PoolClient> {
await this.ready;
const connection = await this._availableConnections.pop();
const release = () => this._availableConnections.push(connection);
return new PoolClient(connection, release);
}
// TODO: can we use more specific type for args?
async query(
text: string | QueryConfig,
// deno-lint-ignore no-explicit-any
...args: any[]
): Promise<QueryResult> {
const query = new Query(text, ...args);
return await this._execute(query);
}
async end(): Promise<void> {
await this.ready;
while (this.available > 0) {
const conn = await this._availableConnections.pop();
await conn.end();
}
}
// Support `using` module
_aenter = () => {};
_aexit = this.end;
}