@juit/pgproxy-client 1.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.
- package/README.md +136 -0
- package/dist/assert.cjs +34 -0
- package/dist/assert.cjs.map +6 -0
- package/dist/assert.d.ts +2 -0
- package/dist/assert.mjs +9 -0
- package/dist/assert.mjs.map +6 -0
- package/dist/client.cjs +97 -0
- package/dist/client.cjs.map +6 -0
- package/dist/client.d.ts +67 -0
- package/dist/client.mjs +72 -0
- package/dist/client.mjs.map +6 -0
- package/dist/index.cjs +33 -0
- package/dist/index.cjs.map +6 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +6 -0
- package/dist/provider.cjs +59 -0
- package/dist/provider.cjs.map +6 -0
- package/dist/provider.d.ts +33 -0
- package/dist/provider.mjs +32 -0
- package/dist/provider.mjs.map +6 -0
- package/dist/result.cjs +59 -0
- package/dist/result.cjs.map +6 -0
- package/dist/result.d.ts +30 -0
- package/dist/result.mjs +34 -0
- package/dist/result.mjs.map +6 -0
- package/dist/websocket.cjs +184 -0
- package/dist/websocket.cjs.map +6 -0
- package/dist/websocket.d.ts +60 -0
- package/dist/websocket.mjs +159 -0
- package/dist/websocket.mjs.map +6 -0
- package/package.json +47 -0
- package/src/assert.ts +4 -0
- package/src/client.ts +172 -0
- package/src/index.ts +5 -0
- package/src/provider.ts +80 -0
- package/src/result.ts +83 -0
- package/src/websocket.ts +269 -0
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# PostgreSQL Proxy Client (Base Package)
|
|
2
|
+
|
|
3
|
+
This package provides the main entry point for clients to work with PGProxy
|
|
4
|
+
Servers. It acts both as an abstraction layer over the various client
|
|
5
|
+
implementations _and_ as a registry for them.
|
|
6
|
+
|
|
7
|
+
* [Connecting](#connecting)
|
|
8
|
+
* [Client](#client)
|
|
9
|
+
* [PGProxy](https://github.com/juitnow/juit-pgproxy/blob/main/README.md)
|
|
10
|
+
* [Copyright Notice](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
|
|
11
|
+
* [License](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
|
|
12
|
+
|
|
13
|
+
### Connecting
|
|
14
|
+
|
|
15
|
+
In the code, you can simply depend on the `PGClient` class:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { PGClient } from '@juit/pgproxy-client'
|
|
19
|
+
|
|
20
|
+
const client = new PGClient()
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The client can be constructed with a `url` as a parameter, indicating the
|
|
24
|
+
endpoint of the connection _and_ the specific client to be used. If no such
|
|
25
|
+
parameter is specified, the value of the `PGURL` environment variable will be
|
|
26
|
+
used.
|
|
27
|
+
|
|
28
|
+
Additionally if the URL specified at construction (or in the `PGURL` environment
|
|
29
|
+
variable) does not provide ANY authentication information, the `PGUSER` and
|
|
30
|
+
`PGPASSWORD` environment variables will be used to fill in those details.
|
|
31
|
+
|
|
32
|
+
Specific implementations are registered by simply importing their library:
|
|
33
|
+
|
|
34
|
+
* `@juit/pgproxy-client-node`: The HTTP client for NodeJS \
|
|
35
|
+
handles URLs like: `http(s)://secret@host:port/`
|
|
36
|
+
* `@juit/pgproxy-client-whatwg`: The HTTP client for WhatWG + WebCrypto \
|
|
37
|
+
handles URLs like: `http(s)://secret@host:port/`
|
|
38
|
+
* `@juit/pgproxy-client-psql`: The direct LibPQ-based client \
|
|
39
|
+
handles URLs like: `psql://usrname:password@host:port/database`
|
|
40
|
+
|
|
41
|
+
The ability to abstract client and connection details allows the code to be
|
|
42
|
+
as portable as possible. For example in an AWS Lambda Function:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// Entry point for AWS Lambda functions
|
|
46
|
+
|
|
47
|
+
// Import the _node_ client, the PGURL environment variable comes from the
|
|
48
|
+
// Lambda definitions and can be specified via the AWS console, it will have
|
|
49
|
+
// a format like: https://my-secret@my-ec2-instance:54321/
|
|
50
|
+
import '@pgproxy/client-node'
|
|
51
|
+
|
|
52
|
+
export const handler = async (event: LambdaEvent) => {
|
|
53
|
+
// ... use code that connects to the database using `new PGClient()`
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Similarly, when running a test requiring a connection to a _local_ database
|
|
58
|
+
(no need to spin up a whole PGProxy Server to test):
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// Entry point for tests
|
|
62
|
+
|
|
63
|
+
// Import the _psql_ client, which will be registered as a handler for the
|
|
64
|
+
// "psql" protocol in PGClient
|
|
65
|
+
import '@pgproxy/client-psql'
|
|
66
|
+
|
|
67
|
+
beforeAll(() => {
|
|
68
|
+
process.env.PGURL = "psql://username:password@localhost:5432/my-database"
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('should run tests connecting to the database', async () => {
|
|
72
|
+
// ... test the code using `new PGCLient()`
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Client
|
|
77
|
+
|
|
78
|
+
Simple queries can be executed on the database via the `query(...)` method:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const client = new PGClient()
|
|
82
|
+
const result = await client.query('SELECT * FROM test WHERE value = $1', [ 'theValue' ])
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
More complex queries (e.g. transactions) can be performed using the
|
|
86
|
+
`connect(...)` method:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const client = new PGClient()
|
|
90
|
+
// here "result" will be the value returned by the callback passed to "connect"
|
|
91
|
+
const result = await client.connect(async (connection) => {
|
|
92
|
+
await connection.begin()
|
|
93
|
+
|
|
94
|
+
await connection.query(...) // ... all transaction queries
|
|
95
|
+
|
|
96
|
+
await connection.commit()
|
|
97
|
+
return result // returned to whatever is awaiting on "connect"
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The `query(...)` method requires one parameter, the SQL query to run, and allows
|
|
102
|
+
parameters (as an array) to be declared as a second, optional parameter.
|
|
103
|
+
|
|
104
|
+
The object passed to the `connect(...)` callback provides the following methods:
|
|
105
|
+
|
|
106
|
+
* `query(...)`: as above
|
|
107
|
+
* `begin()`: issues the `BEGIN` SQL statement (starts a transaction)
|
|
108
|
+
* `commit()`: issues the `COMMIT` SQL statement (commits a transaction)
|
|
109
|
+
* `rollback()`: issues the `ROLLBACK` SQL statement (rolls back a transaction)
|
|
110
|
+
|
|
111
|
+
Uncommitted transactions will always be rolled back by the connection pool code.
|
|
112
|
+
|
|
113
|
+
### Result
|
|
114
|
+
|
|
115
|
+
The result returned by the `query(...)` method is a simple object containing:
|
|
116
|
+
|
|
117
|
+
* `command` (_string_): The SQL command that generated this result (e.g.
|
|
118
|
+
`SELECT`, `INSERT`, ...)
|
|
119
|
+
* `rowCount` (_number_): The number of rows affected by the query. \
|
|
120
|
+
This can be the number of lines returned in `rows` (for `SELECT`
|
|
121
|
+
statements, for example) or the number of lines _affected_ by the query
|
|
122
|
+
(the number of records inserted by an `INSERT` query).
|
|
123
|
+
* `rows` (_Record<string, any>[]_): The rows returned by the database query,
|
|
124
|
+
keyed by the column name.
|
|
125
|
+
* `tuples` (_any[][]_): The tuples returned by the database query, keyed by
|
|
126
|
+
the column index. */
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
### Types
|
|
130
|
+
|
|
131
|
+
Each client exposes its own _types registry_ in the `registry` field.
|
|
132
|
+
|
|
133
|
+
By manipulating the registry, one can tweak the conversion of PostgreSQL types
|
|
134
|
+
to JavaScript types.
|
|
135
|
+
|
|
136
|
+
For more informations see the `@juit/pgproxy-types` package.
|
package/dist/assert.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// assert.ts
|
|
21
|
+
var assert_exports = {};
|
|
22
|
+
__export(assert_exports, {
|
|
23
|
+
assert: () => assert
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(assert_exports);
|
|
26
|
+
function assert(what, message) {
|
|
27
|
+
if (!what)
|
|
28
|
+
throw new Error(message);
|
|
29
|
+
}
|
|
30
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
31
|
+
0 && (module.exports = {
|
|
32
|
+
assert
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=assert.cjs.map
|
package/dist/assert.d.ts
ADDED
package/dist/assert.mjs
ADDED
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// client.ts
|
|
21
|
+
var client_exports = {};
|
|
22
|
+
__export(client_exports, {
|
|
23
|
+
PGClient: () => PGClient
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(client_exports);
|
|
26
|
+
var import_pgproxy_types = require("@juit/pgproxy-types");
|
|
27
|
+
var import_assert = require("./assert.cjs");
|
|
28
|
+
var import_provider = require("./provider.cjs");
|
|
29
|
+
var import_result = require("./result.cjs");
|
|
30
|
+
function serializeParams(params) {
|
|
31
|
+
if (params.length == 0)
|
|
32
|
+
return [];
|
|
33
|
+
const result = new Array(params.length);
|
|
34
|
+
for (let i = 0; i < params.length; i++) {
|
|
35
|
+
result[i] = params[i] === void 0 ? null : params[i] === null ? null : (0, import_pgproxy_types.serialize)(params[i]);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
var PGClient = class PGClientImpl {
|
|
40
|
+
registry = new import_pgproxy_types.Registry();
|
|
41
|
+
_provider;
|
|
42
|
+
constructor(urlOrProvider) {
|
|
43
|
+
urlOrProvider = urlOrProvider || globalThis?.process?.env?.PGURL;
|
|
44
|
+
(0, import_assert.assert)(urlOrProvider, "No URL to connect to (PGURL environment variable missing?)");
|
|
45
|
+
if (typeof urlOrProvider === "string")
|
|
46
|
+
urlOrProvider = new URL(urlOrProvider, "psql:///");
|
|
47
|
+
(0, import_assert.assert)(urlOrProvider, "Missing URL or provider for client");
|
|
48
|
+
if (urlOrProvider instanceof URL) {
|
|
49
|
+
if (!(urlOrProvider.username || urlOrProvider.password)) {
|
|
50
|
+
const username = globalThis?.process?.env?.PGUSER || "";
|
|
51
|
+
const password = globalThis?.process?.env?.PGPASSWORD || "";
|
|
52
|
+
urlOrProvider.username = encodeURIComponent(username);
|
|
53
|
+
urlOrProvider.password = encodeURIComponent(password);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
this._provider = urlOrProvider instanceof URL ? (0, import_provider.createProvider)(urlOrProvider) : urlOrProvider;
|
|
57
|
+
}
|
|
58
|
+
async query(text, params = []) {
|
|
59
|
+
const result = await this._provider.query(text, serializeParams(params));
|
|
60
|
+
return new import_result.PGResult(result, this.registry);
|
|
61
|
+
}
|
|
62
|
+
async connect(consumer) {
|
|
63
|
+
const connection = await this._provider.acquire();
|
|
64
|
+
try {
|
|
65
|
+
const registry = this.registry;
|
|
66
|
+
const consumable = {
|
|
67
|
+
async query(text, params = []) {
|
|
68
|
+
const result = await connection.query(text, serializeParams(params));
|
|
69
|
+
return new import_result.PGResult(result, registry);
|
|
70
|
+
},
|
|
71
|
+
async begin() {
|
|
72
|
+
await this.query("BEGIN");
|
|
73
|
+
return this;
|
|
74
|
+
},
|
|
75
|
+
async commit() {
|
|
76
|
+
await this.query("COMMIT");
|
|
77
|
+
return this;
|
|
78
|
+
},
|
|
79
|
+
async rollback() {
|
|
80
|
+
await this.query("ROLLBACK");
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return await consumer(consumable);
|
|
85
|
+
} finally {
|
|
86
|
+
await this._provider.release(connection);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async destroy() {
|
|
90
|
+
return await this._provider.destroy();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
94
|
+
0 && (module.exports = {
|
|
95
|
+
PGClient
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/client.ts"],
|
|
4
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAoC;AAEpC,oBAAuB;AACvB,sBAA+B;AAC/B,oBAAyB;AAIzB,SAAS,gBAAgB,QAAkC;AACzD,MAAI,OAAO,UAAU;AAAG,WAAO,CAAC;AAEhC,QAAM,SAA4B,IAAI,MAAM,OAAO,MAAM;AACzD,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAM;AACvC,WAAO,CAAC,IACN,OAAO,CAAC,MAAM,SAAY,OAC1B,OAAO,CAAC,MAAM,OAAO,WACrB,gCAAU,OAAO,CAAC,CAAC;AAAA,EACvB;AAEA,SAAO;AACT;AA+EO,IAAM,WAAgC,MAAM,aAAiC;AAAA,EACzE,WAAqB,IAAI,8BAAS;AAAA,EAEnC;AAAA,EAIR,YAAY,eAAyD;AACnE,oBAAgB,iBAAiB,YAAY,SAAS,KAAK;AAC3D,8BAAO,eAAe,4DAA4D;AAClF,QAAI,OAAO,kBAAkB;AAAU,sBAAgB,IAAI,IAAI,eAAe,UAAU;AACxF,8BAAO,eAAe,oCAAoC;AAE1D,QAAI,yBAAyB,KAAK;AAChC,UAAI,EAAE,cAAc,YAAY,cAAc,WAAW;AACvD,cAAM,WAAW,YAAY,SAAS,KAAK,UAAU;AACrD,cAAM,WAAW,YAAY,SAAS,KAAK,cAAc;AACzD,sBAAc,WAAW,mBAAmB,QAAQ;AACpD,sBAAc,WAAW,mBAAmB,QAAQ;AAAA,MACtD;AAAA,IACF;AAEA,SAAK,YAAY,yBAAyB,UACtC,gCAAe,aAAa,IAC5B;AAAA,EACN;AAAA,EAEA,MAAM,MAGJ,MAAc,SAAgB,CAAC,GAAkC;AACjE,UAAM,SAAS,MAAM,KAAK,UAAU,MAAM,MAAM,gBAAgB,MAAM,CAAC;AACvE,WAAO,IAAI,uBAAqB,QAAQ,KAAK,QAAQ;AAAA,EACvD;AAAA,EAEA,MAAM,QAAW,UAAqC;AACpD,UAAM,aAAa,MAAM,KAAK,UAAU,QAAQ;AAEhD,QAAI;AACF,YAAM,WAAW,KAAK;AAEtB,YAAM,aAAgC;AAAA,QACpC,MAAM,MAGJ,MAAc,SAAgB,CAAC,GAAkC;AACjE,gBAAM,SAAS,MAAM,WAAW,MAAM,MAAM,gBAAgB,MAAM,CAAC;AACnE,iBAAO,IAAI,uBAAS,QAAQ,QAAQ;AAAA,QACtC;AAAA,QACA,MAAM,QAAoC;AACxC,gBAAM,KAAK,MAAM,OAAO;AACxB,iBAAO;AAAA,QACT;AAAA,QACA,MAAM,SAAqC;AACzC,gBAAM,KAAK,MAAM,QAAQ;AACzB,iBAAO;AAAA,QACT;AAAA,QACA,MAAM,WAAuC;AAC3C,gBAAM,KAAK,MAAM,UAAU;AAC3B,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,UAAE;AACA,YAAM,KAAK,UAAU,QAAQ,UAAU;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AACF;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Registry } from '@juit/pgproxy-types';
|
|
3
|
+
import { PGResult } from './result';
|
|
4
|
+
import type { PGConnection, PGProvider } from './provider';
|
|
5
|
+
/** An interface for an object that can execute queries on a database */
|
|
6
|
+
export interface PGQueryable {
|
|
7
|
+
/**
|
|
8
|
+
* Execute a query on the database
|
|
9
|
+
*
|
|
10
|
+
* @param text - The SQL query to execute optionally containing placeholders.
|
|
11
|
+
* @param params - Any parameter replacement for `$x` placeholders.
|
|
12
|
+
*/
|
|
13
|
+
query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(text: string, params?: any[]): Promise<PGResult<Row, Tuple>>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* An interface for an object that can execute queries _and transactions_
|
|
17
|
+
* on a database */
|
|
18
|
+
export interface PGTransactionable extends PGQueryable {
|
|
19
|
+
/** Start a transaction by issuing a `BEGIN` statement */
|
|
20
|
+
begin(): Promise<this>;
|
|
21
|
+
/** Commit a transaction by issuing a `COMMIT` statement */
|
|
22
|
+
commit(): Promise<this>;
|
|
23
|
+
/** Cancel a transaction by issuing a `ROLLBACK` statement */
|
|
24
|
+
rollback(): Promise<this>;
|
|
25
|
+
}
|
|
26
|
+
/** A consumer for a {@link PGTransactionable} connection */
|
|
27
|
+
export type PGConsumer<T> = (connection: PGTransactionable) => T | PromiseLike<T>;
|
|
28
|
+
/** The PostgreSQL client */
|
|
29
|
+
export interface PGClient extends PGQueryable {
|
|
30
|
+
/** The {@link @juit/pgproxy-types#Registry} used to parse results from PostgreSQL */
|
|
31
|
+
readonly registry: Registry;
|
|
32
|
+
/**
|
|
33
|
+
* Execute a _single_ query on the database.
|
|
34
|
+
*
|
|
35
|
+
* Invoking the `query` method on a {@link (PGClient:interface)} does NOT guarantee that
|
|
36
|
+
* the query will be executed on the same connection, therefore things like
|
|
37
|
+
* _transactions_ will be immediately rolled back after the query.
|
|
38
|
+
*
|
|
39
|
+
* @param text - The SQL query to execute optionally containing placeholders.
|
|
40
|
+
* @param params - Any parameter replacement for `$x` placeholders.
|
|
41
|
+
*/
|
|
42
|
+
query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(text: string, params?: any[]): Promise<PGResult<Row, Tuple>>;
|
|
43
|
+
/**
|
|
44
|
+
* Connect to the database to execute a number of different queries.
|
|
45
|
+
*
|
|
46
|
+
* The `consumer` will be passed a {@link PGTransactionable} instance backed
|
|
47
|
+
* by the _same_ connection to the database, therefore transactions can be
|
|
48
|
+
* safely executed in the context of the consumer function itself.
|
|
49
|
+
*/
|
|
50
|
+
connect<T>(consumer: PGConsumer<T>): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Destroy any resource and underlying connection associated with this
|
|
53
|
+
* instance's {@link PGProvider}.
|
|
54
|
+
*/
|
|
55
|
+
destroy(): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
/** A constructor for {@link (PGClient:interface)} instances */
|
|
58
|
+
export interface PGClientConstructor {
|
|
59
|
+
new (url?: string | URL): PGClient;
|
|
60
|
+
new (provider: PGProvider<PGConnection>): PGClient;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The PostgreSQL client
|
|
64
|
+
*
|
|
65
|
+
* @constructor
|
|
66
|
+
*/
|
|
67
|
+
export declare const PGClient: PGClientConstructor;
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// client.ts
|
|
2
|
+
import { Registry, serialize } from "@juit/pgproxy-types";
|
|
3
|
+
import { assert } from "./assert.mjs";
|
|
4
|
+
import { createProvider } from "./provider.mjs";
|
|
5
|
+
import { PGResult } from "./result.mjs";
|
|
6
|
+
function serializeParams(params) {
|
|
7
|
+
if (params.length == 0)
|
|
8
|
+
return [];
|
|
9
|
+
const result = new Array(params.length);
|
|
10
|
+
for (let i = 0; i < params.length; i++) {
|
|
11
|
+
result[i] = params[i] === void 0 ? null : params[i] === null ? null : serialize(params[i]);
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
var PGClient = class PGClientImpl {
|
|
16
|
+
registry = new Registry();
|
|
17
|
+
_provider;
|
|
18
|
+
constructor(urlOrProvider) {
|
|
19
|
+
urlOrProvider = urlOrProvider || globalThis?.process?.env?.PGURL;
|
|
20
|
+
assert(urlOrProvider, "No URL to connect to (PGURL environment variable missing?)");
|
|
21
|
+
if (typeof urlOrProvider === "string")
|
|
22
|
+
urlOrProvider = new URL(urlOrProvider, "psql:///");
|
|
23
|
+
assert(urlOrProvider, "Missing URL or provider for client");
|
|
24
|
+
if (urlOrProvider instanceof URL) {
|
|
25
|
+
if (!(urlOrProvider.username || urlOrProvider.password)) {
|
|
26
|
+
const username = globalThis?.process?.env?.PGUSER || "";
|
|
27
|
+
const password = globalThis?.process?.env?.PGPASSWORD || "";
|
|
28
|
+
urlOrProvider.username = encodeURIComponent(username);
|
|
29
|
+
urlOrProvider.password = encodeURIComponent(password);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
this._provider = urlOrProvider instanceof URL ? createProvider(urlOrProvider) : urlOrProvider;
|
|
33
|
+
}
|
|
34
|
+
async query(text, params = []) {
|
|
35
|
+
const result = await this._provider.query(text, serializeParams(params));
|
|
36
|
+
return new PGResult(result, this.registry);
|
|
37
|
+
}
|
|
38
|
+
async connect(consumer) {
|
|
39
|
+
const connection = await this._provider.acquire();
|
|
40
|
+
try {
|
|
41
|
+
const registry = this.registry;
|
|
42
|
+
const consumable = {
|
|
43
|
+
async query(text, params = []) {
|
|
44
|
+
const result = await connection.query(text, serializeParams(params));
|
|
45
|
+
return new PGResult(result, registry);
|
|
46
|
+
},
|
|
47
|
+
async begin() {
|
|
48
|
+
await this.query("BEGIN");
|
|
49
|
+
return this;
|
|
50
|
+
},
|
|
51
|
+
async commit() {
|
|
52
|
+
await this.query("COMMIT");
|
|
53
|
+
return this;
|
|
54
|
+
},
|
|
55
|
+
async rollback() {
|
|
56
|
+
await this.query("ROLLBACK");
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return await consumer(consumable);
|
|
61
|
+
} finally {
|
|
62
|
+
await this._provider.release(connection);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async destroy() {
|
|
66
|
+
return await this._provider.destroy();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
export {
|
|
70
|
+
PGClient
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=client.mjs.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/client.ts"],
|
|
4
|
+
"mappings": ";AAAA,SAAS,UAAU,iBAAiB;AAEpC,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AAIzB,SAAS,gBAAgB,QAAkC;AACzD,MAAI,OAAO,UAAU;AAAG,WAAO,CAAC;AAEhC,QAAM,SAA4B,IAAI,MAAM,OAAO,MAAM;AACzD,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAM;AACvC,WAAO,CAAC,IACN,OAAO,CAAC,MAAM,SAAY,OAC1B,OAAO,CAAC,MAAM,OAAO,OACrB,UAAU,OAAO,CAAC,CAAC;AAAA,EACvB;AAEA,SAAO;AACT;AA+EO,IAAM,WAAgC,MAAM,aAAiC;AAAA,EACzE,WAAqB,IAAI,SAAS;AAAA,EAEnC;AAAA,EAIR,YAAY,eAAyD;AACnE,oBAAgB,iBAAiB,YAAY,SAAS,KAAK;AAC3D,WAAO,eAAe,4DAA4D;AAClF,QAAI,OAAO,kBAAkB;AAAU,sBAAgB,IAAI,IAAI,eAAe,UAAU;AACxF,WAAO,eAAe,oCAAoC;AAE1D,QAAI,yBAAyB,KAAK;AAChC,UAAI,EAAE,cAAc,YAAY,cAAc,WAAW;AACvD,cAAM,WAAW,YAAY,SAAS,KAAK,UAAU;AACrD,cAAM,WAAW,YAAY,SAAS,KAAK,cAAc;AACzD,sBAAc,WAAW,mBAAmB,QAAQ;AACpD,sBAAc,WAAW,mBAAmB,QAAQ;AAAA,MACtD;AAAA,IACF;AAEA,SAAK,YAAY,yBAAyB,MACtC,eAAe,aAAa,IAC5B;AAAA,EACN;AAAA,EAEA,MAAM,MAGJ,MAAc,SAAgB,CAAC,GAAkC;AACjE,UAAM,SAAS,MAAM,KAAK,UAAU,MAAM,MAAM,gBAAgB,MAAM,CAAC;AACvE,WAAO,IAAI,SAAqB,QAAQ,KAAK,QAAQ;AAAA,EACvD;AAAA,EAEA,MAAM,QAAW,UAAqC;AACpD,UAAM,aAAa,MAAM,KAAK,UAAU,QAAQ;AAEhD,QAAI;AACF,YAAM,WAAW,KAAK;AAEtB,YAAM,aAAgC;AAAA,QACpC,MAAM,MAGJ,MAAc,SAAgB,CAAC,GAAkC;AACjE,gBAAM,SAAS,MAAM,WAAW,MAAM,MAAM,gBAAgB,MAAM,CAAC;AACnE,iBAAO,IAAI,SAAS,QAAQ,QAAQ;AAAA,QACtC;AAAA,QACA,MAAM,QAAoC;AACxC,gBAAM,KAAK,MAAM,OAAO;AACxB,iBAAO;AAAA,QACT;AAAA,QACA,MAAM,SAAqC;AACzC,gBAAM,KAAK,MAAM,QAAQ;AACzB,iBAAO;AAAA,QACT;AAAA,QACA,MAAM,WAAuC;AAC3C,gBAAM,KAAK,MAAM,UAAU;AAC3B,iBAAO;AAAA,QACT;AAAA,MACF;AAEA,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,UAAE;AACA,YAAM,KAAK,UAAU,QAAQ,UAAU;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AACF;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __copyProps = (to, from, except, desc) => {
|
|
7
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
+
for (let key of __getOwnPropNames(from))
|
|
9
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
+
}
|
|
12
|
+
return to;
|
|
13
|
+
};
|
|
14
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
15
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
16
|
+
|
|
17
|
+
// index.ts
|
|
18
|
+
var src_exports = {};
|
|
19
|
+
module.exports = __toCommonJS(src_exports);
|
|
20
|
+
__reExport(src_exports, require("./assert.cjs"), module.exports);
|
|
21
|
+
__reExport(src_exports, require("./client.cjs"), module.exports);
|
|
22
|
+
__reExport(src_exports, require("./provider.cjs"), module.exports);
|
|
23
|
+
__reExport(src_exports, require("./result.cjs"), module.exports);
|
|
24
|
+
__reExport(src_exports, require("./websocket.cjs"), module.exports);
|
|
25
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
26
|
+
0 && (module.exports = {
|
|
27
|
+
...require("./assert.cjs"),
|
|
28
|
+
...require("./client.cjs"),
|
|
29
|
+
...require("./provider.cjs"),
|
|
30
|
+
...require("./result.cjs"),
|
|
31
|
+
...require("./websocket.cjs")
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// provider.ts
|
|
21
|
+
var provider_exports = {};
|
|
22
|
+
__export(provider_exports, {
|
|
23
|
+
AbstractPGProvider: () => AbstractPGProvider,
|
|
24
|
+
createProvider: () => createProvider,
|
|
25
|
+
registerProvider: () => registerProvider
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(provider_exports);
|
|
28
|
+
var import_assert = require("./assert.cjs");
|
|
29
|
+
var AbstractPGProvider = class {
|
|
30
|
+
async query(text, params) {
|
|
31
|
+
const connection = await this.acquire();
|
|
32
|
+
try {
|
|
33
|
+
return await connection.query(text, params);
|
|
34
|
+
} finally {
|
|
35
|
+
await this.release(connection);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async destroy() {
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var providers = /* @__PURE__ */ new Map();
|
|
42
|
+
function registerProvider(protocol, constructor) {
|
|
43
|
+
protocol = `${protocol}:`;
|
|
44
|
+
(0, import_assert.assert)(!providers.has(protocol), `Connection provider for "${protocol}..." already registered`);
|
|
45
|
+
providers.set(protocol, constructor);
|
|
46
|
+
providers.set(protocol, constructor);
|
|
47
|
+
}
|
|
48
|
+
function createProvider(url) {
|
|
49
|
+
const Provider = providers.get(url.protocol);
|
|
50
|
+
(0, import_assert.assert)(Provider, `No connection provider registered for "${url.protocol}..."`);
|
|
51
|
+
return new Provider(url);
|
|
52
|
+
}
|
|
53
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
54
|
+
0 && (module.exports = {
|
|
55
|
+
AbstractPGProvider,
|
|
56
|
+
createProvider,
|
|
57
|
+
registerProvider
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=provider.cjs.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/provider.ts"],
|
|
4
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAuB;AAqChB,IAAe,qBAAf,MAC2B;AAAA,EAIhC,MAAM,MAAM,MAAc,QAA+C;AACvE,UAAM,aAAa,MAAM,KAAK,QAAQ;AACtC,QAAI;AACF,aAAO,MAAM,WAAW,MAAM,MAAM,MAAM;AAAA,IAC5C,UAAE;AACA,YAAM,KAAK,QAAQ,UAAU;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAAA,EAE/B;AACF;AAOA,IAAM,YAAY,oBAAI,IAAiD;AAGhE,SAAS,iBACZ,UACA,aACI;AACN,aAAW,GAAG,QAAQ;AACtB,4BAAO,CAAE,UAAU,IAAI,QAAQ,GAAG,4BAA4B,QAAQ,yBAAyB;AAC/F,YAAU,IAAI,UAAU,WAAW;AACnC,YAAU,IAAI,UAAU,WAAW;AACrC;AAGO,SAAS,eAAe,KAAoC;AACjE,QAAM,WAAW,UAAU,IAAI,IAAI,QAAQ;AAC3C,4BAAO,UAAU,0CAA0C,IAAI,QAAQ,MAAM;AAC7E,SAAO,IAAI,SAAS,GAAG;AACzB;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/** Describes the result of a query from a {@link PGProvider} */
|
|
3
|
+
export interface PGConnectionResult {
|
|
4
|
+
/** The SQL command that generated this result (`SELECT`, `INSERT`, ...) */
|
|
5
|
+
command: string;
|
|
6
|
+
/** Number of rows affected by this query (e.g. added rows in `INSERT`) */
|
|
7
|
+
rowCount: number;
|
|
8
|
+
/** Fields description with `name` (column name) and `oid` (type) */
|
|
9
|
+
fields: [name: string, oid: number][];
|
|
10
|
+
/** Result rows, as an array of unparsed `string` results from `libpq` */
|
|
11
|
+
rows: (string | null)[][];
|
|
12
|
+
}
|
|
13
|
+
export interface PGConnection {
|
|
14
|
+
query(text: string, params: (string | null)[]): Promise<PGConnectionResult>;
|
|
15
|
+
}
|
|
16
|
+
export interface PGProviderConstructor<Connection extends PGConnection> {
|
|
17
|
+
new (url: URL): PGProvider<Connection>;
|
|
18
|
+
}
|
|
19
|
+
export interface PGProvider<Connection extends PGConnection> extends PGConnection {
|
|
20
|
+
acquire(): Promise<Connection>;
|
|
21
|
+
release(connection: Connection): Promise<void>;
|
|
22
|
+
destroy(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export declare abstract class AbstractPGProvider<Connection extends PGConnection> implements PGProvider<Connection> {
|
|
25
|
+
abstract acquire(): Promise<Connection>;
|
|
26
|
+
abstract release(connection: PGConnection): Promise<void>;
|
|
27
|
+
query(text: string, params: string[]): Promise<PGConnectionResult>;
|
|
28
|
+
destroy(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/** Register a provider, associating it with the specified protocol */
|
|
31
|
+
export declare function registerProvider(protocol: string, constructor: PGProviderConstructor<PGConnection>): void;
|
|
32
|
+
/** Create a new {@link PGProvider} instance for the specified URL */
|
|
33
|
+
export declare function createProvider(url: URL): PGProvider<PGConnection>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// provider.ts
|
|
2
|
+
import { assert } from "./assert.mjs";
|
|
3
|
+
var AbstractPGProvider = class {
|
|
4
|
+
async query(text, params) {
|
|
5
|
+
const connection = await this.acquire();
|
|
6
|
+
try {
|
|
7
|
+
return await connection.query(text, params);
|
|
8
|
+
} finally {
|
|
9
|
+
await this.release(connection);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
async destroy() {
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var providers = /* @__PURE__ */ new Map();
|
|
16
|
+
function registerProvider(protocol, constructor) {
|
|
17
|
+
protocol = `${protocol}:`;
|
|
18
|
+
assert(!providers.has(protocol), `Connection provider for "${protocol}..." already registered`);
|
|
19
|
+
providers.set(protocol, constructor);
|
|
20
|
+
providers.set(protocol, constructor);
|
|
21
|
+
}
|
|
22
|
+
function createProvider(url) {
|
|
23
|
+
const Provider = providers.get(url.protocol);
|
|
24
|
+
assert(Provider, `No connection provider registered for "${url.protocol}..."`);
|
|
25
|
+
return new Provider(url);
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
AbstractPGProvider,
|
|
29
|
+
createProvider,
|
|
30
|
+
registerProvider
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=provider.mjs.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/provider.ts"],
|
|
4
|
+
"mappings": ";AAAA,SAAS,cAAc;AAqChB,IAAe,qBAAf,MAC2B;AAAA,EAIhC,MAAM,MAAM,MAAc,QAA+C;AACvE,UAAM,aAAa,MAAM,KAAK,QAAQ;AACtC,QAAI;AACF,aAAO,MAAM,WAAW,MAAM,MAAM,MAAM;AAAA,IAC5C,UAAE;AACA,YAAM,KAAK,QAAQ,UAAU;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAAA,EAE/B;AACF;AAOA,IAAM,YAAY,oBAAI,IAAiD;AAGhE,SAAS,iBACZ,UACA,aACI;AACN,aAAW,GAAG,QAAQ;AACtB,SAAO,CAAE,UAAU,IAAI,QAAQ,GAAG,4BAA4B,QAAQ,yBAAyB;AAC/F,YAAU,IAAI,UAAU,WAAW;AACnC,YAAU,IAAI,UAAU,WAAW;AACrC;AAGO,SAAS,eAAe,KAAoC;AACjE,QAAM,WAAW,UAAU,IAAI,IAAI,QAAQ;AAC3C,SAAO,UAAU,0CAA0C,IAAI,QAAQ,MAAM;AAC7E,SAAO,IAAI,SAAS,GAAG;AACzB;",
|
|
5
|
+
"names": []
|
|
6
|
+
}
|