@juit/pgproxy-client 1.2.1 → 1.3.1
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 +23 -2
- package/dist/client.cjs +137 -39
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.ts +42 -6
- package/dist/client.mjs +138 -39
- package/dist/client.mjs.map +1 -1
- package/dist/provider.cjs +12 -0
- package/dist/provider.cjs.map +1 -1
- package/dist/provider.d.ts +14 -10
- package/dist/provider.mjs +12 -0
- package/dist/provider.mjs.map +1 -1
- package/dist/result.cjs.map +1 -1
- package/dist/result.d.ts +2 -2
- package/dist/result.mjs.map +1 -1
- package/dist/sql.cjs +7 -2
- package/dist/sql.cjs.map +1 -1
- package/dist/sql.d.ts +2 -0
- package/dist/sql.mjs +5 -1
- package/dist/sql.mjs.map +1 -1
- package/dist/websocket.cjs +2 -1
- package/dist/websocket.cjs.map +1 -1
- package/dist/websocket.d.ts +5 -4
- package/dist/websocket.mjs +2 -1
- package/dist/websocket.mjs.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +165 -61
- package/src/provider.ts +31 -11
- package/src/result.ts +3 -3
- package/src/sql.ts +5 -0
- package/src/websocket.ts +9 -8
package/src/provider.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { assert } from './assert'
|
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
8
|
/** Describes the result of a query from a {@link PGProvider} */
|
|
9
|
-
export interface
|
|
9
|
+
export interface PGProviderResult {
|
|
10
10
|
/** The SQL command that generated this result (`SELECT`, `INSERT`, ...) */
|
|
11
11
|
command: string
|
|
12
12
|
/** Number of rows affected by this query (e.g. added rows in `INSERT`) */
|
|
@@ -17,15 +17,18 @@ export interface PGConnectionResult {
|
|
|
17
17
|
rows: (string | null)[][]
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export interface
|
|
21
|
-
query(text: string, params?: (string | null)[]): Promise<
|
|
20
|
+
export interface PGProviderConnection {
|
|
21
|
+
query(text: string, params?: (string | null)[]): Promise<PGProviderResult>
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export interface PGProviderConstructor<Connection extends
|
|
24
|
+
export interface PGProviderConstructor<Connection extends PGProviderConnection = PGProviderConnection> {
|
|
25
25
|
new (url: URL): PGProvider<Connection>
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export interface PGProvider<Connection extends
|
|
28
|
+
export interface PGProvider<Connection extends PGProviderConnection = PGProviderConnection> extends PGProviderConnection {
|
|
29
|
+
/** The URL used to create this provider, devoid of any credentials */
|
|
30
|
+
readonly url: Readonly<URL>
|
|
31
|
+
|
|
29
32
|
acquire(): Promise<Connection>
|
|
30
33
|
release(connection: Connection): Promise<void>
|
|
31
34
|
destroy(): Promise<void>
|
|
@@ -35,12 +38,28 @@ export interface PGProvider<Connection extends PGConnection> extends PGConnectio
|
|
|
35
38
|
* ABSTRACT PROVIDER IMPLEMENTATION *
|
|
36
39
|
* ========================================================================== */
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+
/** Hide away URLs, without `#private` fields modifying our signatures */
|
|
42
|
+
const providerUrls = new WeakMap<AbstractPGProvider, URL>()
|
|
43
|
+
|
|
44
|
+
export abstract class AbstractPGProvider<Connection extends PGProviderConnection = PGProviderConnection>
|
|
39
45
|
implements PGProvider<Connection> {
|
|
46
|
+
constructor(url: URL | string) {
|
|
47
|
+
providerUrls.set(this, new URL(url)) // Defensive copy
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get url(): Readonly<URL> {
|
|
51
|
+
const url = providerUrls.get(this)
|
|
52
|
+
assert(url, 'Internal error: missing provider URL')
|
|
53
|
+
const sanitizedUrl = new URL(url)
|
|
54
|
+
sanitizedUrl.username = ''
|
|
55
|
+
sanitizedUrl.password = ''
|
|
56
|
+
return sanitizedUrl
|
|
57
|
+
}
|
|
58
|
+
|
|
40
59
|
abstract acquire(): Promise<Connection>
|
|
41
|
-
abstract release(connection:
|
|
60
|
+
abstract release(connection: PGProviderConnection): Promise<void>
|
|
42
61
|
|
|
43
|
-
async query(text: string, params: (string | null)[] = []): Promise<
|
|
62
|
+
async query(text: string, params: (string | null)[] = []): Promise<PGProviderResult> {
|
|
44
63
|
const connection = await this.acquire()
|
|
45
64
|
try {
|
|
46
65
|
return await connection.query(text, params)
|
|
@@ -54,17 +73,18 @@ implements PGProvider<Connection> {
|
|
|
54
73
|
}
|
|
55
74
|
}
|
|
56
75
|
|
|
76
|
+
|
|
57
77
|
/* ========================================================================== *
|
|
58
78
|
* PROVIDERS REGISTRATION *
|
|
59
79
|
* ========================================================================== */
|
|
60
80
|
|
|
61
81
|
/** All known providers, mapped by protocol */
|
|
62
|
-
const providers = new Map<string, PGProviderConstructor
|
|
82
|
+
const providers = new Map<string, PGProviderConstructor>()
|
|
63
83
|
|
|
64
84
|
/** Register a provider, associating it with the specified protocol */
|
|
65
85
|
export function registerProvider(
|
|
66
86
|
protocol: string,
|
|
67
|
-
constructor: PGProviderConstructor
|
|
87
|
+
constructor: PGProviderConstructor,
|
|
68
88
|
): void {
|
|
69
89
|
protocol = `${protocol}:` // URL always has protocol with _colon_
|
|
70
90
|
assert(! providers.has(protocol), `Connection provider for "${protocol}..." already registered`)
|
|
@@ -73,7 +93,7 @@ export function registerProvider(
|
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
/** Create a new {@link PGProvider} instance for the specified URL */
|
|
76
|
-
export function createProvider(url: URL): PGProvider
|
|
96
|
+
export function createProvider(url: URL): PGProvider {
|
|
77
97
|
const Provider = providers.get(url.protocol)
|
|
78
98
|
assert(Provider, `No connection provider registered for "${url.protocol}..."`)
|
|
79
99
|
return new Provider(url)
|
package/src/result.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Registry } from '@juit/pgproxy-types'
|
|
2
|
-
import type {
|
|
2
|
+
import type { PGProviderResult } from './provider'
|
|
3
3
|
|
|
4
4
|
/* ========================================================================== *
|
|
5
5
|
* EXPORTED TYPES *
|
|
@@ -33,7 +33,7 @@ export interface PGResultConstructor {
|
|
|
33
33
|
new <
|
|
34
34
|
Row extends Record<string, any> = Record<string, any>,
|
|
35
35
|
Tuple extends readonly any[] = readonly any [],
|
|
36
|
-
>(result:
|
|
36
|
+
>(result: PGProviderResult, registry: Registry): PGResult<Row, Tuple>
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/* ========================================================================== *
|
|
@@ -51,7 +51,7 @@ export const PGResult: PGResultConstructor = class PGResultImpl<
|
|
|
51
51
|
rows: Row[]
|
|
52
52
|
tuples: Tuple[]
|
|
53
53
|
|
|
54
|
-
constructor(result:
|
|
54
|
+
constructor(result: PGProviderResult, registry: Registry) {
|
|
55
55
|
this.rowCount = result.rowCount
|
|
56
56
|
this.command = result.command
|
|
57
57
|
this.fields = result.fields.map(([ name, oid ]) => ({ name, oid }))
|
package/src/sql.ts
CHANGED
|
@@ -110,3 +110,8 @@ function makeSQL(
|
|
|
110
110
|
export function SQL(strings: readonly string[], ...args: readonly any[]): SQL {
|
|
111
111
|
return makeSQL(strings, args)
|
|
112
112
|
}
|
|
113
|
+
|
|
114
|
+
/** Escape a PostgreSQL identifier (table, column, ... names) */
|
|
115
|
+
export function escape(str: string): string {
|
|
116
|
+
return `"${str.replaceAll('"', '""').trim()}"`
|
|
117
|
+
}
|
package/src/websocket.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { assert } from './assert'
|
|
2
|
+
import { AbstractPGProvider } from './provider'
|
|
2
3
|
|
|
3
4
|
import type { Request, Response } from '@juit/pgproxy-server'
|
|
4
|
-
import type {
|
|
5
|
+
import type { PGProvider, PGProviderConnection, PGProviderResult } from './provider'
|
|
5
6
|
|
|
6
7
|
/* ========================================================================== *
|
|
7
8
|
* WEBSOCKET TYPES: in order to work with both WHATWG WebSockets and NodeJS's *
|
|
@@ -54,10 +55,10 @@ function msg(message: string | null | undefined, defaultMessage: string): string
|
|
|
54
55
|
return message || defaultMessage
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
/** A request, simply an unwrapped {@link
|
|
58
|
+
/** A request, simply an unwrapped {@link PGProviderResult} promise */
|
|
58
59
|
class WebSocketRequest {
|
|
59
|
-
readonly promise: Promise<
|
|
60
|
-
readonly resolve!: (result:
|
|
60
|
+
readonly promise: Promise<PGProviderResult>
|
|
61
|
+
readonly resolve!: (result: PGProviderResult) => void
|
|
61
62
|
readonly reject!: (reason: any) => void
|
|
62
63
|
|
|
63
64
|
constructor(public id: string) {
|
|
@@ -148,7 +149,7 @@ class WebSocketConnectionImpl implements WebSocketConnection {
|
|
|
148
149
|
this._socket.close(1000, 'Normal termination')
|
|
149
150
|
}
|
|
150
151
|
|
|
151
|
-
query(query: string, params: (string | null)[] = []): Promise<
|
|
152
|
+
query(query: string, params: (string | null)[] = []): Promise<PGProviderResult> {
|
|
152
153
|
/* The error is set also when the websocket is closed, soooooo... */
|
|
153
154
|
if (this._error) return Promise.reject(this._error)
|
|
154
155
|
|
|
@@ -177,16 +178,16 @@ class WebSocketConnectionImpl implements WebSocketConnection {
|
|
|
177
178
|
* ========================================================================== */
|
|
178
179
|
|
|
179
180
|
/** A connection to the database backed by a `WebSocket` */
|
|
180
|
-
export interface WebSocketConnection extends
|
|
181
|
+
export interface WebSocketConnection extends PGProviderConnection {
|
|
181
182
|
/** Close this connection and the underlying `WebSocket` */
|
|
182
183
|
close(): void
|
|
183
184
|
}
|
|
184
185
|
|
|
185
186
|
/** An abstract provider implementing `connect(...)` via WHATWG WebSockets */
|
|
186
|
-
export abstract class WebSocketProvider implements PGProvider<WebSocketConnection> {
|
|
187
|
+
export abstract class WebSocketProvider extends AbstractPGProvider implements PGProvider<WebSocketConnection> {
|
|
187
188
|
private readonly _connections = new Set<WebSocketConnection>()
|
|
188
189
|
|
|
189
|
-
abstract query(text: string, params?: (string | null)[]): Promise<
|
|
190
|
+
abstract query(text: string, params?: (string | null)[]): Promise<PGProviderResult>
|
|
190
191
|
|
|
191
192
|
/** Return a unique request identifier to correlate responses */
|
|
192
193
|
protected abstract _getUniqueRequestId(): string
|