@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/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 PGConnectionResult {
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 PGConnection {
21
- query(text: string, params?: (string | null)[]): Promise<PGConnectionResult>
20
+ export interface PGProviderConnection {
21
+ query(text: string, params?: (string | null)[]): Promise<PGProviderResult>
22
22
  }
23
23
 
24
- export interface PGProviderConstructor<Connection extends PGConnection> {
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 PGConnection> extends PGConnection {
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
- export abstract class AbstractPGProvider<Connection extends PGConnection>
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: PGConnection): Promise<void>
60
+ abstract release(connection: PGProviderConnection): Promise<void>
42
61
 
43
- async query(text: string, params: (string | null)[] = []): Promise<PGConnectionResult> {
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<PGConnection>>()
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<PGConnection>,
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<PGConnection> {
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 { PGConnectionResult } from './provider'
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: PGConnectionResult, registry: Registry): PGResult<Row, Tuple>
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: PGConnectionResult, registry: Registry) {
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 { PGConnection, PGConnectionResult, PGProvider } from './provider'
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 PGConnectionResult} promise */
58
+ /** A request, simply an unwrapped {@link PGProviderResult} promise */
58
59
  class WebSocketRequest {
59
- readonly promise: Promise<PGConnectionResult>
60
- readonly resolve!: (result: PGConnectionResult) => void
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<PGConnectionResult> {
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 PGConnection {
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<PGConnectionResult>
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