@juit/pgproxy-client 1.0.34 → 1.1.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 CHANGED
@@ -6,6 +6,9 @@ implementations _and_ as a registry for them.
6
6
 
7
7
  * [Connecting](#connecting)
8
8
  * [Client](#client)
9
+ * [Result](#result)
10
+ * [Types](#types)
11
+ * [Template Literals](#template-literals)
9
12
  * [PGProxy](https://github.com/juitnow/juit-pgproxy/blob/main/README.md)
10
13
  * [Copyright Notice](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
11
14
  * [License](https://github.com/juitnow/juit-pgproxy/blob/main/NOTICE.md)
@@ -101,6 +104,11 @@ const result = await client.connect(async (connection) => {
101
104
  The `query(...)` method requires one parameter, the SQL query to run, and allows
102
105
  parameters (as an array) to be declared as a second, optional parameter.
103
106
 
107
+ A second form of the `query(...)` function accepts an object with two keys:
108
+
109
+ * `query`: the SQL query to execute optionally containing placeholders
110
+ * `params`: any parameter replacement for `$x` placeholders
111
+
104
112
  The object passed to the `connect(...)` callback provides the following methods:
105
113
 
106
114
  * `query(...)`: as above
@@ -134,3 +142,50 @@ By manipulating the registry, one can tweak the conversion of PostgreSQL types
134
142
  to JavaScript types.
135
143
 
136
144
  For more informations see the `@juit/pgproxy-types` package.
145
+
146
+
147
+ ### Template Literals
148
+
149
+ This client also exposes a `SQL` _template tagging function_, or * a function
150
+ capable of converting a template string into a query like structure.
151
+
152
+ For example:
153
+
154
+ ```typescript
155
+ const email = 'user@example.org'
156
+ const query = SQL `SELECT * FROM users WHERE email = ${email}`
157
+
158
+ // Here "query" will be something like:
159
+ // {
160
+ // query: 'SELECT * FROM users WHERE email = $1',
161
+ // params: [ 'user@example.org' ],
162
+ // }
163
+ ```
164
+
165
+ The `SQL` function can also be use with _concatenated_ template strings, for
166
+ example:
167
+
168
+ ```typescript
169
+ const email = 'user@example.org'
170
+ const hash = 'thePasswordHash'
171
+ const query = SQL
172
+ `SELECT * FROM users WHERE email = ${email}`
173
+ `AND password_hash = ${hash}`
174
+
175
+ // Here "query" will be something like:
176
+ // {
177
+ // query: 'SELECT * FROM users WHERE email = $1 AND password_hash = $2',
178
+ // params: [ 'user@example.org', 'thePasswordHash' ],
179
+ // }
180
+ ```
181
+
182
+ In this case, multiple template strings will be concatenated with a single
183
+ space character.
184
+
185
+ This function can be directly used with our query interface, as follows:
186
+
187
+ ```typescript
188
+ const client = new PGClient()
189
+ const email = 'user@example.org'
190
+ const result = await client.query(SQL `SELECT * FROM users WHERE email = ${email}`)
191
+ ```
package/dist/client.cjs CHANGED
@@ -53,7 +53,8 @@ var PGClient = class PGClientImpl {
53
53
  }
54
54
  this._provider = urlOrProvider instanceof URL ? (0, import_provider.createProvider)(urlOrProvider) : urlOrProvider;
55
55
  }
56
- async query(text, params = []) {
56
+ async query(textOrQuery, maybeParams = []) {
57
+ const [text, params = []] = typeof textOrQuery === "string" ? [textOrQuery, maybeParams] : [textOrQuery.query, textOrQuery.params];
57
58
  const result = await this._provider.query(text, serializeParams(params));
58
59
  return new import_result.PGResult(result, this.registry);
59
60
  }
@@ -63,7 +64,8 @@ var PGClient = class PGClientImpl {
63
64
  try {
64
65
  const registry = this.registry;
65
66
  const consumable = {
66
- async query(text, params = []) {
67
+ async query(textOrQuery, maybeParams = []) {
68
+ const [text, params = []] = typeof textOrQuery === "string" ? [textOrQuery, maybeParams] : [textOrQuery.query, textOrQuery.params];
67
69
  const result = await connection.query(text, serializeParams(params));
68
70
  return new import_result.PGResult(result, registry);
69
71
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
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,EAAG,QAAO,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;AAoFO,IAAM,WAAgC,MAAM,aAAiC;AAAA,EACzE,WAAqB,IAAI,8BAAS;AAAA,EAEnC;AAAA,EAIR,YAAY,eAAyD;AACnE,oBAAgB,iBAAmB,YAAoB,SAAS,KAAK;AACrE,8BAAO,eAAe,4DAA4D;AAClF,QAAI,OAAO,kBAAkB,SAAU,iBAAgB,IAAI,IAAI,eAAe,UAAU;AACxF,8BAAO,eAAe,oCAAoC;AAE1D,QAAI,yBAAyB,KAAK;AAChC,UAAI,EAAE,cAAc,YAAY,cAAc,WAAW;AACvD,cAAM,WAAa,YAAoB,SAAS,KAAK,UAAiC;AACtF,cAAM,WAAa,YAAoB,SAAS,KAAK,cAAqC;AAC1F,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;AAChD,QAAI,cAAc;AAElB,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,QAA0B;AAC9B,cAAI,YAAa,QAAO;AACxB,gBAAM,WAAW,MAAM,OAAO;AAC9B,iBAAO,cAAc;AAAA,QACvB;AAAA,QACA,MAAM,SAAwB;AAC5B,gBAAM,WAAW,MAAM,QAAQ;AAC/B,wBAAc;AAAA,QAChB;AAAA,QACA,MAAM,WAA0B;AAC9B,gBAAM,WAAW,MAAM,UAAU;AACjC,wBAAc;AAAA,QAChB;AAAA,MACF;AAEA,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,UAAE;AACA,UAAI,YAAa,OAAM,WAAW,MAAM,UAAU;AAClD,YAAM,KAAK,UAAU,QAAQ,UAAU;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AACF;",
4
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAoC;AAEpC,oBAAuB;AACvB,sBAA+B;AAC/B,oBAAyB;AAIzB,SAAS,gBAAgB,QAA2C;AAClE,MAAI,OAAO,UAAU,EAAG,QAAO,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;AAsHO,IAAM,WAAgC,MAAM,aAAiC;AAAA,EACzE,WAAqB,IAAI,8BAAS;AAAA,EAEnC;AAAA,EAIR,YAAY,eAAyD;AACnE,oBAAgB,iBAAmB,YAAoB,SAAS,KAAK;AACrE,8BAAO,eAAe,4DAA4D;AAClF,QAAI,OAAO,kBAAkB,SAAU,iBAAgB,IAAI,IAAI,eAAe,UAAU;AACxF,8BAAO,eAAe,oCAAoC;AAE1D,QAAI,yBAAyB,KAAK;AAChC,UAAI,EAAE,cAAc,YAAY,cAAc,WAAW;AACvD,cAAM,WAAa,YAAoB,SAAS,KAAK,UAAiC;AACtF,cAAM,WAAa,YAAoB,SAAS,KAAK,cAAqC;AAC1F,sBAAc,WAAW,mBAAmB,QAAQ;AACpD,sBAAc,WAAW,mBAAmB,QAAQ;AAAA,MACtD;AAAA,IACF;AAEA,SAAK,YAAY,yBAAyB,UACtC,gCAAe,aAAa,IAC5B;AAAA,EACN;AAAA,EAaA,MAAM,MAGJ,aAA+B,cAA8B,CAAC,GAAkC;AAChG,UAAM,CAAE,MAAM,SAAS,CAAC,CAAE,IAAI,OAAO,gBAAgB,WACnD,CAAE,aAAa,WAAY,IAAI,CAAE,YAAY,OAAO,YAAY,MAAO;AAGzE,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;AAChD,QAAI,cAAc;AAElB,QAAI;AACF,YAAM,WAAW,KAAK;AAEtB,YAAM,aAAgC;AAAA,QACpC,MAAM,MAGJ,aAA+B,cAA8B,CAAC,GAAkC;AAChG,gBAAM,CAAE,MAAM,SAAS,CAAC,CAAE,IAAI,OAAO,gBAAgB,WACjD,CAAE,aAAa,WAAY,IAAI,CAAE,YAAY,OAAO,YAAY,MAAO;AAE3E,gBAAM,SAAS,MAAM,WAAW,MAAM,MAAM,gBAAgB,MAAM,CAAC;AACnE,iBAAO,IAAI,uBAAS,QAAQ,QAAQ;AAAA,QACtC;AAAA,QACA,MAAM,QAA0B;AAC9B,cAAI,YAAa,QAAO;AACxB,gBAAM,WAAW,MAAM,OAAO;AAC9B,iBAAO,cAAc;AAAA,QACvB;AAAA,QACA,MAAM,SAAwB;AAC5B,gBAAM,WAAW,MAAM,QAAQ;AAC/B,wBAAc;AAAA,QAChB;AAAA,QACA,MAAM,WAA0B;AAC9B,gBAAM,WAAW,MAAM,UAAU;AACjC,wBAAc;AAAA,QAChB;AAAA,MACF;AAEA,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,UAAE;AACA,UAAI,YAAa,OAAM,WAAW,MAAM,UAAU;AAClD,YAAM,KAAK,UAAU,QAAQ,UAAU;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AACF;",
5
5
  "names": []
6
6
  }
package/dist/client.d.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import { Registry } from '@juit/pgproxy-types';
2
2
  import { PGResult } from './result';
3
3
  import type { PGConnection, PGProvider } from './provider';
4
+ /** An interface representing a SQL query to a database */
5
+ export interface PGQuery {
6
+ /** The SQL query to execute optionally containing placeholders. */
7
+ readonly query: string;
8
+ /** Any parameter replacement for `$x` placeholders. */
9
+ readonly params?: readonly any[];
10
+ }
4
11
  /** An interface for an object that can execute queries on a database */
5
12
  export interface PGQueryable {
6
13
  /**
@@ -9,7 +16,14 @@ export interface PGQueryable {
9
16
  * @param text - The SQL query to execute optionally containing placeholders.
10
17
  * @param params - Any parameter replacement for `$x` placeholders.
11
18
  */
12
- query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(text: string, params?: any[]): Promise<PGResult<Row, Tuple>>;
19
+ query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(text: string, params?: readonly any[]): Promise<PGResult<Row, Tuple>>;
20
+ /**
21
+ * Execute a query on the database
22
+ *
23
+ * @param query - An object containing the query (both the SQL string and its
24
+ * related parameters) to execute
25
+ */
26
+ query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(query: PGQuery): Promise<PGResult<Row, Tuple>>;
13
27
  }
14
28
  /**
15
29
  * An interface for an object that can execute queries _and transactions_
@@ -36,14 +50,25 @@ export interface PGClient extends PGQueryable {
36
50
  /**
37
51
  * Execute a _single_ query on the database.
38
52
  *
39
- * Invoking the `query` method on a {@link (PGClient:interface)} does NOT guarantee that
40
- * the query will be executed on the same connection, therefore things like
41
- * _transactions_ will be immediately rolled back after the query.
53
+ * Invoking the `query` method on a {@link (PGClient:interface)} does NOT
54
+ * guarantee that the query will be executed on the same connection, therefore
55
+ * things like _transactions_ will be immediately rolled back after the query.
42
56
  *
43
57
  * @param text - The SQL query to execute optionally containing placeholders.
44
58
  * @param params - Any parameter replacement for `$x` placeholders.
45
59
  */
46
- query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(text: string, params?: any[]): Promise<PGResult<Row, Tuple>>;
60
+ query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(text: string, params?: readonly any[]): Promise<PGResult<Row, Tuple>>;
61
+ /**
62
+ * Execute a _single_ query on the database.
63
+ *
64
+ * Invoking the `query` method on a {@link (PGClient:interface)} does NOT
65
+ * guarantee that the query will be executed on the same connection, therefore
66
+ * things like _transactions_ will be immediately rolled back after the query.
67
+ *
68
+ * @param query - An object containing the query (both the SQL string and its
69
+ * related parameters) to execute
70
+ */
71
+ query<Row extends Record<string, any> = Record<string, any>, Tuple extends readonly any[] = readonly any[]>(query: PGQuery): Promise<PGResult<Row, Tuple>>;
47
72
  /**
48
73
  * Connect to the database to execute a number of different queries.
49
74
  *
package/dist/client.mjs CHANGED
@@ -29,7 +29,8 @@ var PGClient = class PGClientImpl {
29
29
  }
30
30
  this._provider = urlOrProvider instanceof URL ? createProvider(urlOrProvider) : urlOrProvider;
31
31
  }
32
- async query(text, params = []) {
32
+ async query(textOrQuery, maybeParams = []) {
33
+ const [text, params = []] = typeof textOrQuery === "string" ? [textOrQuery, maybeParams] : [textOrQuery.query, textOrQuery.params];
33
34
  const result = await this._provider.query(text, serializeParams(params));
34
35
  return new PGResult(result, this.registry);
35
36
  }
@@ -39,7 +40,8 @@ var PGClient = class PGClientImpl {
39
40
  try {
40
41
  const registry = this.registry;
41
42
  const consumable = {
42
- async query(text, params = []) {
43
+ async query(textOrQuery, maybeParams = []) {
44
+ const [text, params = []] = typeof textOrQuery === "string" ? [textOrQuery, maybeParams] : [textOrQuery.query, textOrQuery.params];
43
45
  const result = await connection.query(text, serializeParams(params));
44
46
  return new PGResult(result, registry);
45
47
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
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,EAAG,QAAO,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;AAoFO,IAAM,WAAgC,MAAM,aAAiC;AAAA,EACzE,WAAqB,IAAI,SAAS;AAAA,EAEnC;AAAA,EAIR,YAAY,eAAyD;AACnE,oBAAgB,iBAAmB,YAAoB,SAAS,KAAK;AACrE,WAAO,eAAe,4DAA4D;AAClF,QAAI,OAAO,kBAAkB,SAAU,iBAAgB,IAAI,IAAI,eAAe,UAAU;AACxF,WAAO,eAAe,oCAAoC;AAE1D,QAAI,yBAAyB,KAAK;AAChC,UAAI,EAAE,cAAc,YAAY,cAAc,WAAW;AACvD,cAAM,WAAa,YAAoB,SAAS,KAAK,UAAiC;AACtF,cAAM,WAAa,YAAoB,SAAS,KAAK,cAAqC;AAC1F,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;AAChD,QAAI,cAAc;AAElB,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,QAA0B;AAC9B,cAAI,YAAa,QAAO;AACxB,gBAAM,WAAW,MAAM,OAAO;AAC9B,iBAAO,cAAc;AAAA,QACvB;AAAA,QACA,MAAM,SAAwB;AAC5B,gBAAM,WAAW,MAAM,QAAQ;AAC/B,wBAAc;AAAA,QAChB;AAAA,QACA,MAAM,WAA0B;AAC9B,gBAAM,WAAW,MAAM,UAAU;AACjC,wBAAc;AAAA,QAChB;AAAA,MACF;AAEA,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,UAAE;AACA,UAAI,YAAa,OAAM,WAAW,MAAM,UAAU;AAClD,YAAM,KAAK,UAAU,QAAQ,UAAU;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AACF;",
4
+ "mappings": ";AAAA,SAAS,UAAU,iBAAiB;AAEpC,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AAIzB,SAAS,gBAAgB,QAA2C;AAClE,MAAI,OAAO,UAAU,EAAG,QAAO,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;AAsHO,IAAM,WAAgC,MAAM,aAAiC;AAAA,EACzE,WAAqB,IAAI,SAAS;AAAA,EAEnC;AAAA,EAIR,YAAY,eAAyD;AACnE,oBAAgB,iBAAmB,YAAoB,SAAS,KAAK;AACrE,WAAO,eAAe,4DAA4D;AAClF,QAAI,OAAO,kBAAkB,SAAU,iBAAgB,IAAI,IAAI,eAAe,UAAU;AACxF,WAAO,eAAe,oCAAoC;AAE1D,QAAI,yBAAyB,KAAK;AAChC,UAAI,EAAE,cAAc,YAAY,cAAc,WAAW;AACvD,cAAM,WAAa,YAAoB,SAAS,KAAK,UAAiC;AACtF,cAAM,WAAa,YAAoB,SAAS,KAAK,cAAqC;AAC1F,sBAAc,WAAW,mBAAmB,QAAQ;AACpD,sBAAc,WAAW,mBAAmB,QAAQ;AAAA,MACtD;AAAA,IACF;AAEA,SAAK,YAAY,yBAAyB,MACtC,eAAe,aAAa,IAC5B;AAAA,EACN;AAAA,EAaA,MAAM,MAGJ,aAA+B,cAA8B,CAAC,GAAkC;AAChG,UAAM,CAAE,MAAM,SAAS,CAAC,CAAE,IAAI,OAAO,gBAAgB,WACnD,CAAE,aAAa,WAAY,IAAI,CAAE,YAAY,OAAO,YAAY,MAAO;AAGzE,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;AAChD,QAAI,cAAc;AAElB,QAAI;AACF,YAAM,WAAW,KAAK;AAEtB,YAAM,aAAgC;AAAA,QACpC,MAAM,MAGJ,aAA+B,cAA8B,CAAC,GAAkC;AAChG,gBAAM,CAAE,MAAM,SAAS,CAAC,CAAE,IAAI,OAAO,gBAAgB,WACjD,CAAE,aAAa,WAAY,IAAI,CAAE,YAAY,OAAO,YAAY,MAAO;AAE3E,gBAAM,SAAS,MAAM,WAAW,MAAM,MAAM,gBAAgB,MAAM,CAAC;AACnE,iBAAO,IAAI,SAAS,QAAQ,QAAQ;AAAA,QACtC;AAAA,QACA,MAAM,QAA0B;AAC9B,cAAI,YAAa,QAAO;AACxB,gBAAM,WAAW,MAAM,OAAO;AAC9B,iBAAO,cAAc;AAAA,QACvB;AAAA,QACA,MAAM,SAAwB;AAC5B,gBAAM,WAAW,MAAM,QAAQ;AAC/B,wBAAc;AAAA,QAChB;AAAA,QACA,MAAM,WAA0B;AAC9B,gBAAM,WAAW,MAAM,UAAU;AACjC,wBAAc;AAAA,QAChB;AAAA,MACF;AAEA,aAAO,MAAM,SAAS,UAAU;AAAA,IAClC,UAAE;AACA,UAAI,YAAa,OAAM,WAAW,MAAM,UAAU;AAClD,YAAM,KAAK,UAAU,QAAQ,UAAU;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,UAAyB;AAC7B,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACtC;AACF;",
5
5
  "names": []
6
6
  }
package/dist/index.cjs CHANGED
@@ -21,6 +21,7 @@ __reExport(src_exports, require("./assert.cjs"), module.exports);
21
21
  __reExport(src_exports, require("./client.cjs"), module.exports);
22
22
  __reExport(src_exports, require("./provider.cjs"), module.exports);
23
23
  __reExport(src_exports, require("./result.cjs"), module.exports);
24
+ __reExport(src_exports, require("./sql.cjs"), module.exports);
24
25
  __reExport(src_exports, require("./websocket.cjs"), module.exports);
25
26
  // Annotate the CommonJS export names for ESM import in node:
26
27
  0 && (module.exports = {
@@ -28,6 +29,7 @@ __reExport(src_exports, require("./websocket.cjs"), module.exports);
28
29
  ...require("./client.cjs"),
29
30
  ...require("./provider.cjs"),
30
31
  ...require("./result.cjs"),
32
+ ...require("./sql.cjs"),
31
33
  ...require("./websocket.cjs")
32
34
  });
33
35
  //# sourceMappingURL=index.cjs.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,wBAAc,yBAAd;AACA,wBAAc,yBADd;AAEA,wBAAc,2BAFd;AAGA,wBAAc,yBAHd;AAIA,wBAAc,4BAJd;",
4
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,wBAAc,yBAAd;AACA,wBAAc,yBADd;AAEA,wBAAc,2BAFd;AAGA,wBAAc,yBAHd;AAIA,wBAAc,sBAJd;AAKA,wBAAc,4BALd;",
5
5
  "names": []
6
6
  }
package/dist/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from './assert';
2
2
  export * from './client';
3
3
  export * from './provider';
4
4
  export * from './result';
5
+ export * from './sql';
5
6
  export * from './websocket';
package/dist/index.mjs CHANGED
@@ -3,5 +3,6 @@ export * from "./assert.mjs";
3
3
  export * from "./client.mjs";
4
4
  export * from "./provider.mjs";
5
5
  export * from "./result.mjs";
6
+ export * from "./sql.mjs";
6
7
  export * from "./websocket.mjs";
7
8
  //# sourceMappingURL=index.mjs.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "mappings": ";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "mappings": ";AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
5
5
  "names": []
6
6
  }
package/dist/sql.cjs ADDED
@@ -0,0 +1,49 @@
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
+ // sql.ts
21
+ var sql_exports = {};
22
+ __export(sql_exports, {
23
+ SQL: () => SQL
24
+ });
25
+ module.exports = __toCommonJS(sql_exports);
26
+ function makeSQL(parts, params, query = "", start = 0) {
27
+ const [first = "", ...rest] = parts;
28
+ if (query) query += " ";
29
+ query += rest.reduce((q, s, i) => `${q}$${i + start + 1}${s}`, first);
30
+ const sql = (strings, ...args) => {
31
+ return makeSQL(strings, [...params, ...args], query, params.length);
32
+ };
33
+ return Object.assign(sql, {
34
+ get query() {
35
+ return query;
36
+ },
37
+ get params() {
38
+ return [...params];
39
+ }
40
+ });
41
+ }
42
+ function SQL(strings, ...args) {
43
+ return makeSQL(strings, args);
44
+ }
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ SQL
48
+ });
49
+ //# sourceMappingURL=sql.cjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/sql.ts"],
4
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CA,SAAS,QACL,OACA,QACA,QAAgB,IAChB,QAAgB,GACb;AACL,QAAM,CAAE,QAAQ,IAAI,GAAG,IAAK,IAAI;AAEhC,MAAI,MAAO,UAAS;AACpB,WAAS,KAAK,OAAO,CAAC,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK;AAEpE,QAAM,MAAM,CAAC,YAA+B,SAA8B;AACxE,WAAO,QAAQ,SAAS,CAAE,GAAG,QAAQ,GAAG,IAAK,GAAG,OAAO,OAAO,MAAM;AAAA,EACtE;AAEA,SAAO,OAAO,OAAO,KAAK;AAAA,IACxB,IAAI,QAAgB;AAClB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,SAAyB;AAC3B,aAAO,CAAE,GAAG,MAAO;AAAA,IACrB;AAAA,EACF,CAAC;AACH;AAuCO,SAAS,IAAI,YAA+B,MAA2B;AAC5E,SAAO,QAAQ,SAAS,IAAI;AAC9B;",
5
+ "names": []
6
+ }
package/dist/sql.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ import type { PGQuery } from './client';
2
+ /**
3
+ * A _function_ capable of converting a template string into a {@link PGQuery}
4
+ * like structure (tagged template literals).
5
+ *
6
+ * For example:
7
+ *
8
+ * ```typescript
9
+ * const email = 'user@example.org'
10
+ * const query = SQL `SELECT * FROM users WHERE email = ${email}`
11
+ *
12
+ * // Here "query" will be something like:
13
+ * // {
14
+ * // query: 'SELECT * FROM users WHERE email = $1',
15
+ * // params: [ 'user@example.org' ],
16
+ * // }
17
+ * ```
18
+ *
19
+ * The `SQL` function can also be use with _concatenated_ template strings, for
20
+ * example:
21
+ *
22
+ * ```typescript
23
+ * const email = 'user@example.org'
24
+ * const hash = 'thePasswordHash'
25
+ * const query = SQL
26
+ * `SELECT * FROM users WHERE email = ${email}`
27
+ * `AND password_hash = ${hash}`
28
+ *
29
+ * // Here "query" will be something like:
30
+ * // {
31
+ * // query: 'SELECT * FROM users WHERE email = $1 AND password_hash = $2',
32
+ * // params: [ 'user@example.org', 'thePasswordHash' ],
33
+ * // }
34
+ * ```
35
+ *
36
+ * In this case, multiple template strings will be concatenated with a single
37
+ * space character.
38
+ */
39
+ export interface SQL extends Required<PGQuery> {
40
+ (strings: readonly string[], ...args: any[]): SQL;
41
+ }
42
+ /**
43
+ * A _function_ capable of converting a template string into a {@link PGQuery}
44
+ * like structure (tagged template literals).
45
+ *
46
+ * For example:
47
+ *
48
+ * ```typescript
49
+ * const email = 'user@example.org'
50
+ * const query = SQL `SELECT * FROM users WHERE email = ${email}`
51
+ *
52
+ * // Here "query" will be something like:
53
+ * // {
54
+ * // query: 'SELECT * FROM users WHERE email = $1',
55
+ * // params: [ 'user@example.org' ],
56
+ * // }
57
+ * ```
58
+ *
59
+ * The `SQL` function can also be use with _concatenated_ template strings, for
60
+ * example:
61
+ *
62
+ * ```typescript
63
+ * const email = 'user@example.org'
64
+ * const hash = 'thePasswordHash'
65
+ * const query = SQL
66
+ * `SELECT * FROM users WHERE email = ${email}`
67
+ * `AND password_hash = ${hash}`
68
+ *
69
+ * // Here "query" will be something like:
70
+ * // {
71
+ * // query: 'SELECT * FROM users WHERE email = $1 AND password_hash = $2',
72
+ * // params: [ 'user@example.org', 'thePasswordHash' ],
73
+ * // }
74
+ * ```
75
+ *
76
+ * In this case, multiple template strings will be concatenated with a single
77
+ * space character.
78
+ */
79
+ export declare function SQL(strings: readonly string[], ...args: readonly any[]): SQL;
package/dist/sql.mjs ADDED
@@ -0,0 +1,24 @@
1
+ // sql.ts
2
+ function makeSQL(parts, params, query = "", start = 0) {
3
+ const [first = "", ...rest] = parts;
4
+ if (query) query += " ";
5
+ query += rest.reduce((q, s, i) => `${q}$${i + start + 1}${s}`, first);
6
+ const sql = (strings, ...args) => {
7
+ return makeSQL(strings, [...params, ...args], query, params.length);
8
+ };
9
+ return Object.assign(sql, {
10
+ get query() {
11
+ return query;
12
+ },
13
+ get params() {
14
+ return [...params];
15
+ }
16
+ });
17
+ }
18
+ function SQL(strings, ...args) {
19
+ return makeSQL(strings, args);
20
+ }
21
+ export {
22
+ SQL
23
+ };
24
+ //# sourceMappingURL=sql.mjs.map
@@ -0,0 +1,6 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/sql.ts"],
4
+ "mappings": ";AA+CA,SAAS,QACL,OACA,QACA,QAAgB,IAChB,QAAgB,GACb;AACL,QAAM,CAAE,QAAQ,IAAI,GAAG,IAAK,IAAI;AAEhC,MAAI,MAAO,UAAS;AACpB,WAAS,KAAK,OAAO,CAAC,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK;AAEpE,QAAM,MAAM,CAAC,YAA+B,SAA8B;AACxE,WAAO,QAAQ,SAAS,CAAE,GAAG,QAAQ,GAAG,IAAK,GAAG,OAAO,OAAO,MAAM;AAAA,EACtE;AAEA,SAAO,OAAO,OAAO,KAAK;AAAA,IACxB,IAAI,QAAgB;AAClB,aAAO;AAAA,IACT;AAAA,IACA,IAAI,SAAyB;AAC3B,aAAO,CAAE,GAAG,MAAO;AAAA,IACrB;AAAA,EACF,CAAC;AACH;AAuCO,SAAS,IAAI,YAA+B,MAA2B;AAC5E,SAAO,QAAQ,SAAS,IAAI;AAC9B;",
5
+ "names": []
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juit/pgproxy-client",
3
- "version": "1.0.34",
3
+ "version": "1.1.0",
4
4
  "main": "./dist/index.cjs",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "homepage": "https://github.com/juitnow/juit-pgproxy#readme",
37
37
  "dependencies": {
38
- "@juit/pgproxy-types": "1.0.34"
38
+ "@juit/pgproxy-types": "1.1.0"
39
39
  },
40
40
  "directories": {
41
41
  "test": "test"
package/src/client.ts CHANGED
@@ -6,7 +6,7 @@ import { PGResult } from './result'
6
6
 
7
7
  import type { PGConnection, PGProvider } from './provider'
8
8
 
9
- function serializeParams(params: any[]): (string | null)[] {
9
+ function serializeParams(params: readonly any[]): (string | null)[] {
10
10
  if (params.length == 0) return []
11
11
 
12
12
  const result: (string | null)[] = new Array(params.length)
@@ -20,6 +20,14 @@ function serializeParams(params: any[]): (string | null)[] {
20
20
  return result
21
21
  }
22
22
 
23
+ /** An interface representing a SQL query to a database */
24
+ export interface PGQuery {
25
+ /** The SQL query to execute optionally containing placeholders. */
26
+ readonly query: string
27
+ /** Any parameter replacement for `$x` placeholders. */
28
+ readonly params?: readonly any[]
29
+ }
30
+
23
31
  /** An interface for an object that can execute queries on a database */
24
32
  export interface PGQueryable {
25
33
  /**
@@ -31,7 +39,18 @@ export interface PGQueryable {
31
39
  query<
32
40
  Row extends Record<string, any> = Record<string, any>,
33
41
  Tuple extends readonly any[] = readonly any [],
34
- >(text: string, params?: any[]): Promise<PGResult<Row, Tuple>>
42
+ >(text: string, params?: readonly any[]): Promise<PGResult<Row, Tuple>>
43
+
44
+ /**
45
+ * Execute a query on the database
46
+ *
47
+ * @param query - An object containing the query (both the SQL string and its
48
+ * related parameters) to execute
49
+ */
50
+ query<
51
+ Row extends Record<string, any> = Record<string, any>,
52
+ Tuple extends readonly any[] = readonly any [],
53
+ >(query: PGQuery): Promise<PGResult<Row, Tuple>>
35
54
  }
36
55
 
37
56
  /**
@@ -63,9 +82,9 @@ export interface PGClient extends PGQueryable {
63
82
  /**
64
83
  * Execute a _single_ query on the database.
65
84
  *
66
- * Invoking the `query` method on a {@link (PGClient:interface)} does NOT guarantee that
67
- * the query will be executed on the same connection, therefore things like
68
- * _transactions_ will be immediately rolled back after the query.
85
+ * Invoking the `query` method on a {@link (PGClient:interface)} does NOT
86
+ * guarantee that the query will be executed on the same connection, therefore
87
+ * things like _transactions_ will be immediately rolled back after the query.
69
88
  *
70
89
  * @param text - The SQL query to execute optionally containing placeholders.
71
90
  * @param params - Any parameter replacement for `$x` placeholders.
@@ -73,7 +92,22 @@ export interface PGClient extends PGQueryable {
73
92
  query<
74
93
  Row extends Record<string, any> = Record<string, any>,
75
94
  Tuple extends readonly any[] = readonly any [],
76
- >(text: string, params?: any[]): Promise<PGResult<Row, Tuple>>
95
+ >(text: string, params?: readonly any[]): Promise<PGResult<Row, Tuple>>
96
+
97
+ /**
98
+ * Execute a _single_ query on the database.
99
+ *
100
+ * Invoking the `query` method on a {@link (PGClient:interface)} does NOT
101
+ * guarantee that the query will be executed on the same connection, therefore
102
+ * things like _transactions_ will be immediately rolled back after the query.
103
+ *
104
+ * @param query - An object containing the query (both the SQL string and its
105
+ * related parameters) to execute
106
+ */
107
+ query<
108
+ Row extends Record<string, any> = Record<string, any>,
109
+ Tuple extends readonly any[] = readonly any [],
110
+ >(query: PGQuery): Promise<PGResult<Row, Tuple>>
77
111
 
78
112
  /**
79
113
  * Connect to the database to execute a number of different queries.
@@ -132,7 +166,22 @@ export const PGClient: PGClientConstructor = class PGClientImpl implements PGCli
132
166
  async query<
133
167
  Row extends Record<string, any> = Record<string, any>,
134
168
  Tuple extends readonly any[] = readonly any [],
135
- >(text: string, params: any[] = []): Promise<PGResult<Row, Tuple>> {
169
+ >(text: string, params?: readonly any[]): Promise<PGResult<Row, Tuple>>
170
+
171
+ async query<
172
+ Row extends Record<string, any> = Record<string, any>,
173
+ Tuple extends readonly any[] = readonly any [],
174
+ >(query: PGQuery): Promise<PGResult<Row, Tuple>>
175
+
176
+
177
+ async query<
178
+ Row extends Record<string, any> = Record<string, any>,
179
+ Tuple extends readonly any[] = readonly any [],
180
+ >(textOrQuery: string | PGQuery, maybeParams: readonly any[] = []): Promise<PGResult<Row, Tuple>> {
181
+ const [ text, params = [] ] = typeof textOrQuery === 'string' ?
182
+ [ textOrQuery, maybeParams ] : [ textOrQuery.query, textOrQuery.params ]
183
+
184
+
136
185
  const result = await this._provider.query(text, serializeParams(params))
137
186
  return new PGResult<Row, Tuple>(result, this.registry)
138
187
  }
@@ -148,7 +197,10 @@ export const PGClient: PGClientConstructor = class PGClientImpl implements PGCli
148
197
  async query<
149
198
  Row extends Record<string, any> = Record<string, any>,
150
199
  Tuple extends readonly any[] = readonly any [],
151
- >(text: string, params: any[] = []): Promise<PGResult<Row, Tuple>> {
200
+ >(textOrQuery: string | PGQuery, maybeParams: readonly any[] = []): Promise<PGResult<Row, Tuple>> {
201
+ const [ text, params = [] ] = typeof textOrQuery === 'string' ?
202
+ [ textOrQuery, maybeParams ] : [ textOrQuery.query, textOrQuery.params ]
203
+
152
204
  const result = await connection.query(text, serializeParams(params))
153
205
  return new PGResult(result, registry)
154
206
  },
package/src/index.ts CHANGED
@@ -2,4 +2,5 @@ export * from './assert'
2
2
  export * from './client'
3
3
  export * from './provider'
4
4
  export * from './result'
5
+ export * from './sql'
5
6
  export * from './websocket'
package/src/sql.ts ADDED
@@ -0,0 +1,112 @@
1
+ import type { PGQuery } from './client'
2
+
3
+ /**
4
+ * A _function_ capable of converting a template string into a {@link PGQuery}
5
+ * like structure (tagged template literals).
6
+ *
7
+ * For example:
8
+ *
9
+ * ```typescript
10
+ * const email = 'user@example.org'
11
+ * const query = SQL `SELECT * FROM users WHERE email = ${email}`
12
+ *
13
+ * // Here "query" will be something like:
14
+ * // {
15
+ * // query: 'SELECT * FROM users WHERE email = $1',
16
+ * // params: [ 'user@example.org' ],
17
+ * // }
18
+ * ```
19
+ *
20
+ * The `SQL` function can also be use with _concatenated_ template strings, for
21
+ * example:
22
+ *
23
+ * ```typescript
24
+ * const email = 'user@example.org'
25
+ * const hash = 'thePasswordHash'
26
+ * const query = SQL
27
+ * `SELECT * FROM users WHERE email = ${email}`
28
+ * `AND password_hash = ${hash}`
29
+ *
30
+ * // Here "query" will be something like:
31
+ * // {
32
+ * // query: 'SELECT * FROM users WHERE email = $1 AND password_hash = $2',
33
+ * // params: [ 'user@example.org', 'thePasswordHash' ],
34
+ * // }
35
+ * ```
36
+ *
37
+ * In this case, multiple template strings will be concatenated with a single
38
+ * space character.
39
+ */
40
+ export interface SQL extends Required<PGQuery> {
41
+ (strings: readonly string [], ...args: any[]): SQL,
42
+ }
43
+
44
+ /**
45
+ * Entry point to parse a template string, optionally concatenating it to a
46
+ * previously parsed template (already converted into a `SQL` function)
47
+ */
48
+ function makeSQL(
49
+ parts: readonly string [],
50
+ params: readonly any[],
51
+ query: string = '',
52
+ start: number = 0,
53
+ ): SQL {
54
+ const [ first = '', ...rest ] = parts
55
+
56
+ if (query) query += ' '
57
+ query += rest.reduce((q, s, i) => `${q}$${i + start + 1}${s}`, first)
58
+
59
+ const sql = (strings: readonly string[], ...args: readonly any[]): SQL => {
60
+ return makeSQL(strings, [ ...params, ...args ], query, params.length)
61
+ }
62
+
63
+ return Object.assign(sql, {
64
+ get query(): string {
65
+ return query
66
+ },
67
+ get params(): readonly any[] {
68
+ return [ ...params ]
69
+ },
70
+ })
71
+ }
72
+
73
+ /**
74
+ * A _function_ capable of converting a template string into a {@link PGQuery}
75
+ * like structure (tagged template literals).
76
+ *
77
+ * For example:
78
+ *
79
+ * ```typescript
80
+ * const email = 'user@example.org'
81
+ * const query = SQL `SELECT * FROM users WHERE email = ${email}`
82
+ *
83
+ * // Here "query" will be something like:
84
+ * // {
85
+ * // query: 'SELECT * FROM users WHERE email = $1',
86
+ * // params: [ 'user@example.org' ],
87
+ * // }
88
+ * ```
89
+ *
90
+ * The `SQL` function can also be use with _concatenated_ template strings, for
91
+ * example:
92
+ *
93
+ * ```typescript
94
+ * const email = 'user@example.org'
95
+ * const hash = 'thePasswordHash'
96
+ * const query = SQL
97
+ * `SELECT * FROM users WHERE email = ${email}`
98
+ * `AND password_hash = ${hash}`
99
+ *
100
+ * // Here "query" will be something like:
101
+ * // {
102
+ * // query: 'SELECT * FROM users WHERE email = $1 AND password_hash = $2',
103
+ * // params: [ 'user@example.org', 'thePasswordHash' ],
104
+ * // }
105
+ * ```
106
+ *
107
+ * In this case, multiple template strings will be concatenated with a single
108
+ * space character.
109
+ */
110
+ export function SQL(strings: readonly string[], ...args: readonly any[]): SQL {
111
+ return makeSQL(strings, args)
112
+ }