@m2k-5f/pgtx 1.4.12 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +225 -128
  2. package/dist/clauses/array.clause.js +1 -1
  3. package/dist/clauses/empty.clause.d.ts +1 -1
  4. package/dist/clauses/empty.clause.d.ts.map +1 -1
  5. package/dist/clauses/empty.clause.js +2 -2
  6. package/dist/clauses/fragment.clause.d.ts +1 -1
  7. package/dist/clauses/fragment.clause.d.ts.map +1 -1
  8. package/dist/clauses/fragment.clause.js +3 -5
  9. package/dist/clauses/iden.caluse.d.ts +1 -1
  10. package/dist/clauses/iden.caluse.d.ts.map +1 -1
  11. package/dist/clauses/index.d.ts +10 -0
  12. package/dist/clauses/index.d.ts.map +1 -0
  13. package/dist/clauses/index.js +25 -0
  14. package/dist/clauses/insert.clause.d.ts +1 -1
  15. package/dist/clauses/insert.clause.d.ts.map +1 -1
  16. package/dist/clauses/insert.clause.js +1 -1
  17. package/dist/clauses/literal.clause.d.ts +1 -1
  18. package/dist/clauses/literal.clause.d.ts.map +1 -1
  19. package/dist/clauses/update.clause.d.ts +1 -1
  20. package/dist/clauses/update.clause.d.ts.map +1 -1
  21. package/dist/clauses/update.clause.js +1 -1
  22. package/dist/clauses/where.clause.d.ts +1 -1
  23. package/dist/clauses/where.clause.d.ts.map +1 -1
  24. package/dist/clauses/where.clause.js +1 -1
  25. package/dist/connection.d.ts +135 -31
  26. package/dist/connection.d.ts.map +1 -1
  27. package/dist/connection.js +290 -59
  28. package/dist/index.d.ts +2 -10
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +10 -18
  31. package/dist/pool.d.ts +126 -32
  32. package/dist/pool.d.ts.map +1 -1
  33. package/dist/pool.js +203 -54
  34. package/dist/protocol/connection-request-writer.d.ts +38 -0
  35. package/dist/protocol/connection-request-writer.d.ts.map +1 -0
  36. package/dist/protocol/connection-request-writer.js +175 -0
  37. package/dist/protocol/connection-response-reader.d.ts +49 -0
  38. package/dist/protocol/connection-response-reader.d.ts.map +1 -0
  39. package/dist/protocol/connection-response-reader.js +185 -0
  40. package/dist/protocol/constants.d.ts +46 -0
  41. package/dist/protocol/constants.d.ts.map +1 -0
  42. package/dist/protocol/constants.js +43 -0
  43. package/dist/protocol/socket-authorization.d.ts +11 -0
  44. package/dist/protocol/socket-authorization.d.ts.map +1 -0
  45. package/dist/protocol/socket-authorization.js +95 -0
  46. package/dist/protocol/socket-connector.d.ts +17 -0
  47. package/dist/protocol/socket-connector.d.ts.map +1 -0
  48. package/dist/protocol/socket-connector.js +48 -0
  49. package/dist/queue.d.ts +10 -0
  50. package/dist/queue.d.ts.map +1 -0
  51. package/dist/queue.js +27 -0
  52. package/dist/security/md5.d.ts +2 -0
  53. package/dist/security/md5.d.ts.map +1 -0
  54. package/dist/security/md5.js +12 -0
  55. package/dist/security/sasl.d.ts +6 -0
  56. package/dist/security/sasl.d.ts.map +1 -0
  57. package/dist/security/sasl.js +29 -0
  58. package/dist/transaction.d.ts +1 -2
  59. package/dist/transaction.d.ts.map +1 -1
  60. package/dist/transaction.js +4 -4
  61. package/dist/types.d.ts +6 -8
  62. package/dist/types.d.ts.map +1 -1
  63. package/dist/utils/template-compiler.d.ts +3 -0
  64. package/dist/utils/template-compiler.d.ts.map +1 -0
  65. package/dist/utils/template-compiler.js +64 -0
  66. package/dist/utils/value-parser.d.ts +6 -0
  67. package/dist/utils/value-parser.d.ts.map +1 -0
  68. package/dist/utils/value-parser.js +101 -0
  69. package/package.json +8 -9
package/dist/index.js CHANGED
@@ -3,15 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Pool = exports.Transaction = exports.Connection = exports.sql = void 0;
4
4
  const pool_1 = require("./pool");
5
5
  Object.defineProperty(exports, "Pool", { enumerable: true, get: function () { return pool_1.Pool; } });
6
- const empty_clause_1 = require("./clauses/empty.clause");
7
- const where_clause_1 = require("./clauses/where.clause");
8
- const insert_clause_1 = require("./clauses/insert.clause");
9
- const update_clause_1 = require("./clauses/update.clause");
10
- const exclude_clause_1 = require("./clauses/exclude.clause");
11
- const iden_caluse_1 = require("./clauses/iden.caluse");
12
- const literal_clause_1 = require("./clauses/literal.clause");
13
- const fragment_clause_1 = require("./clauses/fragment.clause");
14
- const array_clause_1 = require("./clauses/array.clause");
6
+ const clauses_1 = require("./clauses");
15
7
  const connection_1 = require("./connection");
16
8
  Object.defineProperty(exports, "Connection", { enumerable: true, get: function () { return connection_1.Connection; } });
17
9
  const transaction_1 = require("./transaction");
@@ -33,7 +25,7 @@ exports.sql = {
33
25
  * sql.insert([{ id: 1 }, { id: 2 }])
34
26
  * // Result: (id) VALUES ($1), ($2)
35
27
  */
36
- insert: insert_clause_1.InsertClause.create,
28
+ insert: clauses_1.InsertClause.create,
37
29
  /**
38
30
  * Generates a SET clause for UPDATE queries from a JavaScript object.
39
31
  *
@@ -41,7 +33,7 @@ exports.sql = {
41
33
  * sql.update({ status: 'active', updated_at: new Date() })
42
34
  * // Result: status = $1, updated_at = $2
43
35
  */
44
- update: update_clause_1.UpdateClause.create,
36
+ update: clauses_1.UpdateClause.create,
45
37
  /**
46
38
  * Generates an assignment list for ON CONFLICT DO UPDATE using the EXCLUDED table.
47
39
  *
@@ -49,7 +41,7 @@ exports.sql = {
49
41
  * sql`INSERT INTO users ${sql.insert(data)} ON CONFLICT (id) DO UPDATE SET ${sql.excluded(['name', 'email'])}`
50
42
  * // Result: name = EXCLUDED.name, email = EXCLUDED.email
51
43
  */
52
- excluded: exclude_clause_1.ExcludeUpdateClause.create,
44
+ excluded: clauses_1.ExcludeUpdateClause.create,
53
45
  /**
54
46
  * Represents a safe empty SQL fragment.
55
47
  * Useful for dynamic query building when a condition or list might be optional.
@@ -59,7 +51,7 @@ exports.sql = {
59
51
  * sql`SELECT * FROM users ${filters.length ? sql.fragment`WHERE ...` : sql.empty}`
60
52
  * // Result: SELECT * FROM users
61
53
  */
62
- empty: empty_clause_1.emptyClause,
54
+ empty: clauses_1.emptyClause,
63
55
  /**
64
56
  * Generates a list of conditions for a WHERE clause from a JavaScript object.
65
57
  * Works similarly to sql.update, but uses ' AND ' as a separator instead of a comma.
@@ -72,7 +64,7 @@ exports.sql = {
72
64
  * sql`DELETE FROM tasks WHERE ${sql.where({ id: 10, user_id: 5 })}`
73
65
  * // Result: id = $1 AND user_id = $2
74
66
  */
75
- where: where_clause_1.WhereClause.create,
67
+ where: clauses_1.WhereClause.create,
76
68
  /**
77
69
  * Safely escapes SQL identifiers (table or column names) using double quotes.
78
70
  *
@@ -84,7 +76,7 @@ exports.sql = {
84
76
  * sql.ident('table.column')
85
77
  * // Result: "table.column"
86
78
  */
87
- ident: iden_caluse_1.IdentifierClause.create,
79
+ ident: clauses_1.IdentifierClause.create,
88
80
  /**
89
81
  * Injects raw, unescaped SQL strings.
90
82
  * ⚠️ Use with caution to prevent SQL injection!
@@ -93,7 +85,7 @@ exports.sql = {
93
85
  * sql.literal('DESC')
94
86
  * // Result: DESC
95
87
  */
96
- literal: literal_clause_1.LiteralClause.create,
88
+ literal: clauses_1.LiteralClause.create,
97
89
  /**
98
90
  * Creates a reusable, recursive SQL fragment.
99
91
  * Fragments can be nested within each other; argument numbering is handled automatically.
@@ -103,7 +95,7 @@ exports.sql = {
103
95
  * sql`SELECT * FROM users WHERE ${filter} AND status = ${'active'}`
104
96
  * // Result: SELECT * FROM users WHERE age > $1 AND status = $2
105
97
  */
106
- fragment: fragment_clause_1.FragmentClause.create,
98
+ fragment: clauses_1.FragmentClause.create,
107
99
  /**
108
100
  * Formats an array for dynamic lists (IN clauses, column lists, or joined conditions).
109
101
  * Supports recursive Clauses (fragments, idents) within the array.
@@ -124,5 +116,5 @@ exports.sql = {
124
116
  * sql`SELECT ${sql.array([sql.ident('id'), sql.ident('name')])}`
125
117
  * // Result: SELECT "id", "name"
126
118
  */
127
- array: array_clause_1.ArrayClause.create,
119
+ array: clauses_1.ArrayClause.create,
128
120
  };
package/dist/pool.d.ts CHANGED
@@ -1,60 +1,154 @@
1
- import { QueryResultRow } from "pg";
2
- import { PoolConfig, PreparedStatement } from "./types";
3
- import { Connection } from "./connection";
1
+ import { Connection, ConnectionParams } from "./connection";
4
2
  import { Transaction } from "./transaction";
3
+ type PoolParams = ConnectionParams & {
4
+ max?: number;
5
+ };
5
6
  /**
6
7
  * The main entry point for Pgtx.
7
8
  * Manages a connection pool and provides high-level API for queries and transactions.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const pool = new Pool({
13
+ * host: 'localhost',
14
+ * user: 'postgres',
15
+ * password: 'postgres',
16
+ * database: 'test',
17
+ * max: 10
18
+ * })
19
+ *
20
+ * // Simple query
21
+ * const users = await pool.query`SELECT * FROM users WHERE id = ${1}`
22
+ *
23
+ * // Transaction
24
+ * const result = await pool.begin(async tx => {
25
+ * await tx.query`INSERT INTO users ...`
26
+ * return 'success'
27
+ * })
28
+ *
29
+ * // Manual acquire/release
30
+ * const conn = await pool.acquire()
31
+ * try {
32
+ * await conn.query`SELECT 1`
33
+ * } finally {
34
+ * pool.release(conn)
35
+ * }
36
+ *
37
+ * // Clean up
38
+ * await pool.close()
39
+ * ```
8
40
  */
9
41
  export declare class Pool {
10
- private pool;
11
- private enableLogs;
12
- constructor(config: PoolConfig);
42
+ private _available;
43
+ private _config;
44
+ private _max;
45
+ private _total;
46
+ private _waiting;
47
+ private _isClosed;
48
+ private _checkClosed;
49
+ constructor(params: PoolParams);
13
50
  /**
14
- * Executes a one-off query.
15
- * Automatically acquires and releases a connection from the pool.
51
+ * Acquires a dedicated connection from the pool.
52
+ *
53
+ * **Note:** You must call `pool.release(conn)` manually when finished.
54
+ * For most cases, prefer using `pool.query()` or `pool.begin()` which handle this automatically.
55
+ *
56
+ * @returns A connection from the pool or a new one if available.
16
57
  *
17
58
  * @example
18
- * const users = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`;
59
+ * ```ts
60
+ * const conn = await pool.acquire()
61
+ * try {
62
+ * await conn.query`SELECT 1`
63
+ * } finally {
64
+ * pool.release(conn)
65
+ * }
66
+ * ```
19
67
  */
20
- query<T extends QueryResultRow>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>;
68
+ acquire(): Promise<Connection>;
21
69
  /**
22
- * Creates a reusable prepared statement.
23
- * When executed via `stmt.execute()`, it automatically manages its own connection.
24
- * Maps '?' placeholders to native PostgreSQL '$1, $2' indexes.
70
+ * Releases the connection back to the pool.
71
+ *
72
+ * If there are pending `acquire()` calls, the connection is passed directly to the next waiter.
73
+ * Otherwise, it's added to the available connections queue.
74
+ *
75
+ * @param conn - The connection to release.
25
76
  *
26
77
  * @example
27
- * const stmt = await pool.prepare<User, [string]>('get_user', 'SELECT * FROM users WHERE email = ?');
28
- * const users = await stmt.execute('test@example.com');
78
+ * ```ts
79
+ * const conn = await pool.acquire()
80
+ * try {
81
+ * await conn.query`SELECT 1`
82
+ * } finally {
83
+ * pool.release(conn)
84
+ * }
85
+ * ```
29
86
  */
30
- prepare<TResult extends QueryResultRow, TParams extends any[] = []>(name: string, sqlTemplate: string): Promise<PreparedStatement<TResult, TParams>>;
87
+ release(conn: Connection): void;
31
88
  /**
32
- * Acquires a dedicated connection from the pool.
33
- * **Note:** You must call `connection.release()` manually when finished.
89
+ * Starts a managed transaction.
90
+ *
91
+ * Automatically acquires a connection and handles `BEGIN`, `COMMIT`, and `ROLLBACK`.
92
+ * If the callback throws an error, the transaction is rolled back.
93
+ *
94
+ * @param txCallback - Async function that receives a `Transaction` instance.
95
+ * @returns The value returned from the callback.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const result = await pool.begin(async tx => {
100
+ * await tx.query`INSERT INTO accounts (id, balance) VALUES (1, 100)`
101
+ * await tx.query`UPDATE accounts SET balance = balance - 10 WHERE id = 1`
102
+ * return { success: true }
103
+ * })
104
+ * ```
34
105
  */
35
- acquire(): Promise<Connection>;
106
+ begin<T>(txCallback: (transaction: Transaction) => Promise<T>): Promise<T>;
36
107
  /**
37
- * Starts a managed transaction.
38
- * Automatically acquires a connection and handles BEGIN/COMMIT/ROLLBACK.
108
+ * Executes a one-off query using pipeline.
109
+ *
110
+ * Automatically acquires and releases a connection from the pool.
111
+ * For optimal performance, multiple queries can be pipelined through the same connection.
112
+ *
113
+ * @param templates - Tagged template string with SQL.
114
+ * @param args - Query parameters.
115
+ * @returns Array of rows with proper typing.
39
116
  *
40
117
  * @example
41
- * const result = await pool.begin(async (tx) => {
42
- * await tx.query`INSERT INTO accounts ...`;
43
- * return "success";
44
- * });
118
+ * ```ts
119
+ * // Simple query
120
+ * const users = await pool.query`SELECT * FROM users`
121
+ *
122
+ * // With parameters
123
+ * const user = await pool.query`SELECT * FROM users WHERE id = ${1}`
124
+ *
125
+ * // With typed result
126
+ * type User = { id: number, name: string }
127
+ * const users = await pool.query<User>`SELECT * FROM users`
128
+ * ```
129
+ */
130
+ query<T extends Record<string, unknown>>(templates: TemplateStringsArray, ...args: any[]): Promise<T[]>;
131
+ /**
132
+ * Number of available (idle) connections in the pool.
45
133
  */
46
- begin<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>;
134
+ get size(): number;
47
135
  /**
48
- * Returns current pool utilization statistics.
136
+ * Total number of connections currently managed by the pool
137
+ * (available + in use).
49
138
  */
50
- get stats(): {
51
- total: number;
52
- idle: number;
53
- waiting: number;
54
- };
139
+ get total(): number;
55
140
  /**
56
141
  * Shuts down the pool and closes all active connections.
142
+ *
143
+ * All pending `acquire()` calls will be rejected with an error.
144
+ * The pool cannot be used after calling `close()`.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * await pool.close()
149
+ * ```
57
150
  */
58
151
  close(): Promise<void>;
59
152
  }
153
+ export {};
60
154
  //# sourceMappingURL=pool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,cAAc,EAAC,MAAM,IAAI,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAG3C;;;GAGG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,UAAU,CAAS;gBAGvB,MAAM,EAAE,UAAU;IAMtB;;;;;;OAMG;IACU,KAAK,CAAC,CAAC,SAAS,cAAc,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAc5F;;;;;;;;OAQG;IACU,OAAO,CAAC,OAAO,SAAS,cAAc,EAAE,OAAO,SAAS,GAAG,EAAE,GAAG,EAAE,EAC3E,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAY/C;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAK3C;;;;;;;;;OASG;IACU,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAc5E;;OAEG;IACH,IAAW,KAAK;;;;MAMf;IAED;;OAEG;IACI,KAAK;CAGf"}
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAI3C,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AASD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,SAAS,CAAQ;IAEzB,OAAO,CAAC,YAAY;gBAIR,MAAM,EAAE,UAAU;IAM9B;;;;;;;;;;;;;;;;;OAiBG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IA6BpC;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,IAAI,EAAE,UAAU;IAoBxB;;;;;;;;;;;;;;;;;OAiBG;IACG,KAAK,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAYhF;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAmCvG;;OAEG;IACH,IAAI,IAAI,WAEP;IAGD;;;OAGG;IACH,IAAI,KAAK,WAER;IAGD;;;;;;;;;;OAUG;IACG,KAAK;CAed"}
package/dist/pool.js CHANGED
@@ -1,96 +1,245 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Pool = void 0;
4
- const pg_1 = require("pg");
5
4
  const connection_1 = require("./connection");
6
- const prepared_statement_1 = require("./prepared.statement");
5
+ const queue_1 = require("./queue");
7
6
  /**
8
7
  * The main entry point for Pgtx.
9
8
  * Manages a connection pool and provides high-level API for queries and transactions.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const pool = new Pool({
13
+ * host: 'localhost',
14
+ * user: 'postgres',
15
+ * password: 'postgres',
16
+ * database: 'test',
17
+ * max: 10
18
+ * })
19
+ *
20
+ * // Simple query
21
+ * const users = await pool.query`SELECT * FROM users WHERE id = ${1}`
22
+ *
23
+ * // Transaction
24
+ * const result = await pool.begin(async tx => {
25
+ * await tx.query`INSERT INTO users ...`
26
+ * return 'success'
27
+ * })
28
+ *
29
+ * // Manual acquire/release
30
+ * const conn = await pool.acquire()
31
+ * try {
32
+ * await conn.query`SELECT 1`
33
+ * } finally {
34
+ * pool.release(conn)
35
+ * }
36
+ *
37
+ * // Clean up
38
+ * await pool.close()
39
+ * ```
10
40
  */
11
41
  class Pool {
12
- constructor(config) {
13
- this.enableLogs = config.enableLogs ?? false;
14
- this.pool = new pg_1.Pool(config);
42
+ _checkClosed() {
43
+ if (this._isClosed)
44
+ throw new Error('Pool closed');
45
+ }
46
+ constructor(params) {
47
+ this._available = new queue_1.Queue();
48
+ this._total = 0;
49
+ this._waiting = new queue_1.Queue();
50
+ this._isClosed = false;
51
+ this._config = params;
52
+ this._max = params.max || 20;
15
53
  }
16
54
  /**
17
- * Executes a one-off query.
18
- * Automatically acquires and releases a connection from the pool.
55
+ * Acquires a dedicated connection from the pool.
56
+ *
57
+ * **Note:** You must call `pool.release(conn)` manually when finished.
58
+ * For most cases, prefer using `pool.query()` or `pool.begin()` which handle this automatically.
59
+ *
60
+ * @returns A connection from the pool or a new one if available.
19
61
  *
20
62
  * @example
21
- * const users = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`;
63
+ * ```ts
64
+ * const conn = await pool.acquire()
65
+ * try {
66
+ * await conn.query`SELECT 1`
67
+ * } finally {
68
+ * pool.release(conn)
69
+ * }
70
+ * ```
22
71
  */
23
- async query(strings, ...values) {
24
- const conn = await this.acquire();
25
- try {
26
- return await conn.query(strings, ...values);
72
+ async acquire() {
73
+ this._checkClosed();
74
+ while (!this._available.isFree) {
75
+ const conn = this._available.get();
76
+ this._available.next();
77
+ if (conn.isAlive) {
78
+ return conn;
79
+ }
80
+ this._total--;
27
81
  }
28
- catch (err) {
29
- throw err;
30
- }
31
- finally {
32
- conn.release();
82
+ if (this._total < this._max) {
83
+ this._total++;
84
+ try {
85
+ return await connection_1.Connection.new(this._config);
86
+ }
87
+ catch (err) {
88
+ this._total--;
89
+ throw err;
90
+ }
33
91
  }
92
+ return new Promise((resolve, reject) => {
93
+ this._waiting.push({ resolve, reject });
94
+ });
34
95
  }
35
96
  /**
36
- * Creates a reusable prepared statement.
37
- * When executed via `stmt.execute()`, it automatically manages its own connection.
38
- * Maps '?' placeholders to native PostgreSQL '$1, $2' indexes.
97
+ * Releases the connection back to the pool.
98
+ *
99
+ * If there are pending `acquire()` calls, the connection is passed directly to the next waiter.
100
+ * Otherwise, it's added to the available connections queue.
101
+ *
102
+ * @param conn - The connection to release.
39
103
  *
40
104
  * @example
41
- * const stmt = await pool.prepare<User, [string]>('get_user', 'SELECT * FROM users WHERE email = ?');
42
- * const users = await stmt.execute('test@example.com');
43
- */
44
- async prepare(name, sqlTemplate) {
45
- let index = 1;
46
- const text = sqlTemplate.replace(/\?/g, () => `$${index++}`);
47
- return new prepared_statement_1.PoolPreparedStatement(this.pool, text, name);
48
- }
49
- /**
50
- * Acquires a dedicated connection from the pool.
51
- * **Note:** You must call `connection.release()` manually when finished.
105
+ * ```ts
106
+ * const conn = await pool.acquire()
107
+ * try {
108
+ * await conn.query`SELECT 1`
109
+ * } finally {
110
+ * pool.release(conn)
111
+ * }
112
+ * ```
52
113
  */
53
- async acquire() {
54
- const client = await this.pool.connect();
55
- return new connection_1.Connection(client, this.enableLogs);
114
+ release(conn) {
115
+ this._checkClosed();
116
+ if (!conn.isAlive) {
117
+ this._total--;
118
+ return;
119
+ }
120
+ if (!this._waiting.isFree) {
121
+ const waiter = this._waiting.get();
122
+ this._waiting.next();
123
+ waiter.resolve(conn);
124
+ return;
125
+ }
126
+ this._available.push(conn);
56
127
  }
57
128
  /**
58
129
  * Starts a managed transaction.
59
- * Automatically acquires a connection and handles BEGIN/COMMIT/ROLLBACK.
130
+ *
131
+ * Automatically acquires a connection and handles `BEGIN`, `COMMIT`, and `ROLLBACK`.
132
+ * If the callback throws an error, the transaction is rolled back.
133
+ *
134
+ * @param txCallback - Async function that receives a `Transaction` instance.
135
+ * @returns The value returned from the callback.
60
136
  *
61
137
  * @example
62
- * const result = await pool.begin(async (tx) => {
63
- * await tx.query`INSERT INTO accounts ...`;
64
- * return "success";
65
- * });
138
+ * ```ts
139
+ * const result = await pool.begin(async tx => {
140
+ * await tx.query`INSERT INTO accounts (id, balance) VALUES (1, 100)`
141
+ * await tx.query`UPDATE accounts SET balance = balance - 10 WHERE id = 1`
142
+ * return { success: true }
143
+ * })
144
+ * ```
66
145
  */
67
- async begin(callback) {
146
+ async begin(txCallback) {
147
+ this._checkClosed();
68
148
  const conn = await this.acquire();
69
149
  try {
70
- return await conn.begin(callback);
71
- }
72
- catch (err) {
73
- throw err;
150
+ return conn.begin(txCallback);
74
151
  }
75
152
  finally {
76
- conn.release();
153
+ this.release(conn);
77
154
  }
78
155
  }
79
156
  /**
80
- * Returns current pool utilization statistics.
157
+ * Executes a one-off query using pipeline.
158
+ *
159
+ * Automatically acquires and releases a connection from the pool.
160
+ * For optimal performance, multiple queries can be pipelined through the same connection.
161
+ *
162
+ * @param templates - Tagged template string with SQL.
163
+ * @param args - Query parameters.
164
+ * @returns Array of rows with proper typing.
165
+ *
166
+ * @example
167
+ * ```ts
168
+ * // Simple query
169
+ * const users = await pool.query`SELECT * FROM users`
170
+ *
171
+ * // With parameters
172
+ * const user = await pool.query`SELECT * FROM users WHERE id = ${1}`
173
+ *
174
+ * // With typed result
175
+ * type User = { id: number, name: string }
176
+ * const users = await pool.query<User>`SELECT * FROM users`
177
+ * ```
81
178
  */
82
- get stats() {
83
- return {
84
- total: this.pool.totalCount,
85
- idle: this.pool.idleCount,
86
- waiting: this.pool.waitingCount
87
- };
179
+ query(templates, ...args) {
180
+ this._checkClosed();
181
+ while (!this._available.isFree) {
182
+ const conn = this._available.get();
183
+ if (conn.isAlive) {
184
+ return conn.query(templates, ...args);
185
+ }
186
+ this._available.next();
187
+ this._total--;
188
+ }
189
+ if (this._total < this._max) {
190
+ this._total++;
191
+ return connection_1.Connection.new(this._config)
192
+ .catch(err => {
193
+ this._total--;
194
+ throw err;
195
+ })
196
+ .then(conn => {
197
+ this.release(conn);
198
+ return conn.query(templates, ...args);
199
+ });
200
+ }
201
+ return this.acquire()
202
+ .then(conn => {
203
+ this.release(conn);
204
+ return conn.query(templates, ...args);
205
+ });
206
+ }
207
+ /**
208
+ * Number of available (idle) connections in the pool.
209
+ */
210
+ get size() {
211
+ return this._available.size;
212
+ }
213
+ /**
214
+ * Total number of connections currently managed by the pool
215
+ * (available + in use).
216
+ */
217
+ get total() {
218
+ return this._total;
88
219
  }
89
220
  /**
90
221
  * Shuts down the pool and closes all active connections.
222
+ *
223
+ * All pending `acquire()` calls will be rejected with an error.
224
+ * The pool cannot be used after calling `close()`.
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * await pool.close()
229
+ * ```
91
230
  */
92
- close() {
93
- return this.pool.end();
231
+ async close() {
232
+ while (!this._available.isFree) {
233
+ const conn = this._available.get();
234
+ this._available.next();
235
+ conn.close();
236
+ }
237
+ while (!this._waiting.isFree) {
238
+ const waiter = this._waiting.get();
239
+ this._waiting.next();
240
+ waiter.reject(new Error('Pool closed'));
241
+ }
242
+ this._total = 0;
94
243
  }
95
244
  }
96
245
  exports.Pool = Pool;
@@ -0,0 +1,38 @@
1
+ import { RequestType } from "./constants";
2
+ export declare class ConnectionRequestBuffer {
3
+ private buffer;
4
+ private offset;
5
+ private lastRequestLenByteOffset;
6
+ private constructor();
7
+ static new(capacity: number): ConnectionRequestBuffer;
8
+ private ensureCapacity;
9
+ writeCString(string: string): this;
10
+ writeString(string: string): this;
11
+ writeInt32(number: number): this;
12
+ writeInt16(number: number): this;
13
+ writeChar(char: string): this;
14
+ startRequest(requestType: RequestType): this;
15
+ startMessage(): this;
16
+ endRequest(): this;
17
+ asBuffer(): Buffer<ArrayBufferLike>;
18
+ clear(): void;
19
+ }
20
+ export declare class ConnectionRequestWriter {
21
+ private buffer;
22
+ private constructor();
23
+ static new(): ConnectionRequestWriter;
24
+ writeQuery(text: string): this;
25
+ writeParse(name: string | "", text: string): this;
26
+ writeDescribe(statementName: string | ""): this;
27
+ writeBind(portName: string | "", statementName: string | "", params: (string | null)[]): this;
28
+ writeClose(name: string): this;
29
+ writeStartup(user: string, database: string): this;
30
+ writeExecute(portName: string | ""): this;
31
+ writeSync(): this;
32
+ writePassword(password: string): this;
33
+ writeSaslInitial(mechanism: string, clientFirstMessage: string): this;
34
+ writeSaslResponse(clientFinalMessage: string): this;
35
+ asBuffer(): Buffer<ArrayBufferLike>;
36
+ clear(): this;
37
+ }
38
+ //# sourceMappingURL=connection-request-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-request-writer.d.ts","sourceRoot":"","sources":["../../src/protocol/connection-request-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAA;AAGvD,qBAAa,uBAAuB;IAE5B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,wBAAwB;IAHpC,OAAO;IAOP,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM;IAK3B,OAAO,CAAC,cAAc;IAmBtB,YAAY,CAAC,MAAM,EAAE,MAAM;IAY3B,WAAW,CAAC,MAAM,EAAE,MAAM;IAS1B,UAAU,CAAC,MAAM,EAAE,MAAM;IAUzB,UAAU,CAAC,MAAM,EAAE,MAAM;IAUzB,SAAS,CAAC,IAAI,EAAE,MAAM;IAStB,YAAY,CAAC,WAAW,EAAE,WAAW;IAQrC,YAAY;IAMZ,UAAU;IAUV,QAAQ;IAKR,KAAK;CAIR;AAGD,qBAAa,uBAAuB;IAE5B,OAAO,CAAC,MAAM;IADlB,OAAO;IAIP,MAAM,CAAC,GAAG;IAMV,UAAU,CAAC,IAAI,EAAE,MAAM;IASvB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM;IAW1C,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,EAAE;IAUxC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE,EAAE,aAAa,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE;IAmBtF,UAAU,CAAC,IAAI,EAAE,MAAM;IAUvB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAY3C,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,EAAE;IAUlC,SAAS;IAOT,aAAa,CAAC,QAAQ,EAAE,MAAM;IAS9B,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM;IAW9D,iBAAiB,CAAC,kBAAkB,EAAE,MAAM;IAS5C,QAAQ;IAKR,KAAK;CAKR"}