knex 0.21.20 → 0.21.21

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 (141) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/CONTRIBUTING.md +184 -184
  3. package/LICENSE +22 -22
  4. package/README.md +95 -95
  5. package/bin/cli.js +414 -414
  6. package/bin/utils/cli-config-utils.js +151 -151
  7. package/bin/utils/constants.js +7 -7
  8. package/bin/utils/migrationsLister.js +37 -37
  9. package/knex.js +8 -8
  10. package/lib/client.js +413 -413
  11. package/lib/config-resolver.js +61 -61
  12. package/lib/constants.js +44 -44
  13. package/lib/dialects/mssql/index.js +390 -390
  14. package/lib/dialects/mssql/query/compiler.js +444 -444
  15. package/lib/dialects/mssql/schema/columncompiler.js +103 -103
  16. package/lib/dialects/mssql/schema/compiler.js +59 -59
  17. package/lib/dialects/mssql/schema/tablecompiler.js +245 -245
  18. package/lib/dialects/mssql/transaction.js +97 -97
  19. package/lib/dialects/mysql/index.js +191 -191
  20. package/lib/dialects/mysql/query/compiler.js +142 -142
  21. package/lib/dialects/mysql/schema/columncompiler.js +171 -171
  22. package/lib/dialects/mysql/schema/compiler.js +60 -60
  23. package/lib/dialects/mysql/schema/tablecompiler.js +262 -262
  24. package/lib/dialects/mysql/transaction.js +48 -48
  25. package/lib/dialects/mysql2/index.js +35 -35
  26. package/lib/dialects/mysql2/transaction.js +46 -46
  27. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  28. package/lib/dialects/oracle/formatter.js +20 -20
  29. package/lib/dialects/oracle/index.js +79 -79
  30. package/lib/dialects/oracle/query/compiler.js +327 -327
  31. package/lib/dialects/oracle/schema/columnbuilder.js +18 -18
  32. package/lib/dialects/oracle/schema/columncompiler.js +139 -139
  33. package/lib/dialects/oracle/schema/compiler.js +81 -81
  34. package/lib/dialects/oracle/schema/tablecompiler.js +165 -165
  35. package/lib/dialects/oracle/schema/trigger.js +126 -126
  36. package/lib/dialects/oracle/utils.js +86 -86
  37. package/lib/dialects/oracledb/index.js +489 -489
  38. package/lib/dialects/oracledb/query/compiler.js +363 -363
  39. package/lib/dialects/oracledb/schema/columncompiler.js +35 -35
  40. package/lib/dialects/oracledb/transaction.js +76 -76
  41. package/lib/dialects/oracledb/utils.js +14 -14
  42. package/lib/dialects/postgres/index.js +319 -319
  43. package/lib/dialects/postgres/query/compiler.js +206 -206
  44. package/lib/dialects/postgres/schema/columncompiler.js +125 -125
  45. package/lib/dialects/postgres/schema/compiler.js +109 -109
  46. package/lib/dialects/postgres/schema/tablecompiler.js +183 -183
  47. package/lib/dialects/redshift/index.js +73 -73
  48. package/lib/dialects/redshift/query/compiler.js +119 -119
  49. package/lib/dialects/redshift/schema/columnbuilder.js +20 -20
  50. package/lib/dialects/redshift/schema/columncompiler.js +60 -60
  51. package/lib/dialects/redshift/schema/compiler.js +14 -14
  52. package/lib/dialects/redshift/schema/tablecompiler.js +123 -123
  53. package/lib/dialects/redshift/transaction.js +18 -18
  54. package/lib/dialects/sqlite3/formatter.js +21 -21
  55. package/lib/dialects/sqlite3/index.js +169 -169
  56. package/lib/dialects/sqlite3/query/compiler.js +222 -222
  57. package/lib/dialects/sqlite3/schema/columncompiler.js +27 -27
  58. package/lib/dialects/sqlite3/schema/compiler.js +49 -49
  59. package/lib/dialects/sqlite3/schema/ddl.js +525 -525
  60. package/lib/dialects/sqlite3/schema/tablecompiler.js +238 -238
  61. package/lib/formatter.js +295 -295
  62. package/lib/functionhelper.js +14 -14
  63. package/lib/helpers.js +92 -92
  64. package/lib/index.js +3 -3
  65. package/lib/interface.js +115 -115
  66. package/lib/knex.js +42 -42
  67. package/lib/logger.js +76 -76
  68. package/lib/migrate/MigrationGenerator.js +82 -82
  69. package/lib/migrate/Migrator.js +611 -611
  70. package/lib/migrate/configuration-merger.js +60 -60
  71. package/lib/migrate/migrate-stub.js +17 -17
  72. package/lib/migrate/migration-list-resolver.js +36 -36
  73. package/lib/migrate/sources/fs-migrations.js +99 -99
  74. package/lib/migrate/stub/cjs.stub +15 -15
  75. package/lib/migrate/stub/coffee.stub +13 -13
  76. package/lib/migrate/stub/eg.stub +14 -14
  77. package/lib/migrate/stub/js.stub +15 -15
  78. package/lib/migrate/stub/knexfile-coffee.stub +34 -34
  79. package/lib/migrate/stub/knexfile-eg.stub +43 -43
  80. package/lib/migrate/stub/knexfile-js.stub +44 -44
  81. package/lib/migrate/stub/knexfile-ls.stub +35 -35
  82. package/lib/migrate/stub/knexfile-ts.stub +44 -44
  83. package/lib/migrate/stub/ls.stub +14 -14
  84. package/lib/migrate/stub/ts.stub +21 -21
  85. package/lib/migrate/table-creator.js +67 -67
  86. package/lib/migrate/table-resolver.js +27 -27
  87. package/lib/query/builder.js +1372 -1372
  88. package/lib/query/compiler.js +889 -889
  89. package/lib/query/constants.js +13 -13
  90. package/lib/query/joinclause.js +263 -263
  91. package/lib/query/methods.js +92 -92
  92. package/lib/query/string.js +190 -190
  93. package/lib/raw.js +188 -188
  94. package/lib/ref.js +39 -39
  95. package/lib/runner.js +285 -285
  96. package/lib/schema/builder.js +82 -82
  97. package/lib/schema/columnbuilder.js +117 -117
  98. package/lib/schema/columncompiler.js +177 -177
  99. package/lib/schema/compiler.js +101 -101
  100. package/lib/schema/helpers.js +51 -51
  101. package/lib/schema/tablebuilder.js +288 -288
  102. package/lib/schema/tablecompiler.js +296 -296
  103. package/lib/seed/Seeder.js +203 -203
  104. package/lib/seed/seed-stub.js +13 -13
  105. package/lib/seed/stub/coffee.stub +9 -9
  106. package/lib/seed/stub/eg.stub +11 -11
  107. package/lib/seed/stub/js.stub +13 -13
  108. package/lib/seed/stub/ls.stub +11 -11
  109. package/lib/seed/stub/ts.stub +13 -13
  110. package/lib/transaction.js +363 -363
  111. package/lib/util/batchInsert.js +59 -59
  112. package/lib/util/delay.js +6 -6
  113. package/lib/util/fake-client.js +9 -9
  114. package/lib/util/finally-mixin.js +13 -13
  115. package/lib/util/fs.js +76 -76
  116. package/lib/util/import-file.js +13 -13
  117. package/lib/util/is-module-type.js +14 -14
  118. package/lib/util/is.js +32 -32
  119. package/lib/util/make-knex.js +338 -338
  120. package/lib/util/nanoid.js +29 -29
  121. package/lib/util/noop.js +1 -1
  122. package/lib/util/parse-connection.js +66 -66
  123. package/lib/util/save-async-stack.js +14 -14
  124. package/lib/util/template.js +52 -52
  125. package/lib/util/timeout.js +29 -29
  126. package/lib/util/timestamp.js +16 -16
  127. package/package.json +1 -1
  128. package/scripts/build.js +125 -125
  129. package/scripts/docker-compose.yml +111 -111
  130. package/scripts/next-release-howto.md +24 -24
  131. package/scripts/release.sh +34 -34
  132. package/scripts/runkit-example.js +34 -34
  133. package/scripts/stress-test/README.txt +18 -18
  134. package/scripts/stress-test/docker-compose.yml +47 -47
  135. package/scripts/stress-test/knex-stress-test.js +196 -196
  136. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  137. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  138. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  139. package/types/index.d.ts +2249 -2249
  140. package/types/result.d.ts +27 -27
  141. package/types/tables.d.ts +4 -4
@@ -1,319 +1,319 @@
1
- // PostgreSQL
2
- // -------
3
- const extend = require('lodash/extend');
4
- const map = require('lodash/map');
5
- const { promisify, inherits } = require('util');
6
- const Client = require('../../client');
7
-
8
- const QueryCompiler = require('./query/compiler');
9
- const ColumnCompiler = require('./schema/columncompiler');
10
- const TableCompiler = require('./schema/tablecompiler');
11
- const SchemaCompiler = require('./schema/compiler');
12
- const { makeEscape } = require('../../query/string');
13
- const { isString } = require('../../util/is');
14
-
15
- function Client_PG(config) {
16
- Client.apply(this, arguments);
17
- if (config.returning) {
18
- this.defaultReturning = config.returning;
19
- }
20
-
21
- if (config.searchPath) {
22
- this.searchPath = config.searchPath;
23
- }
24
- }
25
- inherits(Client_PG, Client);
26
-
27
- Object.assign(Client_PG.prototype, {
28
- queryCompiler() {
29
- return new QueryCompiler(this, ...arguments);
30
- },
31
-
32
- columnCompiler() {
33
- return new ColumnCompiler(this, ...arguments);
34
- },
35
-
36
- schemaCompiler() {
37
- return new SchemaCompiler(this, ...arguments);
38
- },
39
-
40
- tableCompiler() {
41
- return new TableCompiler(this, ...arguments);
42
- },
43
-
44
- dialect: 'postgresql',
45
-
46
- driverName: 'pg',
47
-
48
- _driver() {
49
- return require('pg');
50
- },
51
-
52
- _escapeBinding: makeEscape({
53
- escapeArray(val, esc) {
54
- return esc(arrayString(val, esc));
55
- },
56
- escapeString(str) {
57
- let hasBackslash = false;
58
- let escaped = "'";
59
- for (let i = 0; i < str.length; i++) {
60
- const c = str[i];
61
- if (c === "'") {
62
- escaped += c + c;
63
- } else if (c === '\\') {
64
- escaped += c + c;
65
- hasBackslash = true;
66
- } else {
67
- escaped += c;
68
- }
69
- }
70
- escaped += "'";
71
- if (hasBackslash === true) {
72
- escaped = 'E' + escaped;
73
- }
74
- return escaped;
75
- },
76
- escapeObject(val, prepareValue, timezone, seen = []) {
77
- if (val && typeof val.toPostgres === 'function') {
78
- seen = seen || [];
79
- if (seen.indexOf(val) !== -1) {
80
- throw new Error(
81
- `circular reference detected while preparing "${val}" for query`
82
- );
83
- }
84
- seen.push(val);
85
- return prepareValue(val.toPostgres(prepareValue), seen);
86
- }
87
- return JSON.stringify(val);
88
- },
89
- }),
90
-
91
- wrapIdentifierImpl(value) {
92
- if (value === '*') return value;
93
-
94
- let arrayAccessor = '';
95
- const arrayAccessorMatch = value.match(/(.*?)(\[[0-9]+\])/);
96
-
97
- if (arrayAccessorMatch) {
98
- value = arrayAccessorMatch[1];
99
- arrayAccessor = arrayAccessorMatch[2];
100
- }
101
-
102
- return `"${value.replace(/"/g, '""')}"${arrayAccessor}`;
103
- },
104
-
105
- // Get a raw connection, called by the `pool` whenever a new
106
- // connection needs to be added to the pool.
107
- acquireRawConnection() {
108
- const client = this;
109
- return new Promise(function (resolver, rejecter) {
110
- const connection = new client.driver.Client(client.connectionSettings);
111
- connection.connect(function (err, connection) {
112
- if (err) {
113
- return rejecter(err);
114
- }
115
- connection.on('error', (err) => {
116
- connection.__knex__disposed = err;
117
- });
118
- connection.on('end', (err) => {
119
- connection.__knex__disposed = err || 'Connection ended unexpectedly';
120
- });
121
- if (!client.version) {
122
- return client.checkVersion(connection).then(function (version) {
123
- client.version = version;
124
- resolver(connection);
125
- });
126
- }
127
- resolver(connection);
128
- });
129
- }).then(function setSearchPath(connection) {
130
- client.setSchemaSearchPath(connection);
131
- return connection;
132
- });
133
- },
134
-
135
- // Used to explicitly close a connection, called internally by the pool
136
- // when a connection times out or the pool is shutdown.
137
- async destroyRawConnection(connection) {
138
- const end = promisify((cb) => connection.end(cb));
139
- return end();
140
- },
141
-
142
- // In PostgreSQL, we need to do a version check to do some feature
143
- // checking on the database.
144
- checkVersion(connection) {
145
- return new Promise(function (resolver, rejecter) {
146
- connection.query('select version();', function (err, resp) {
147
- if (err) return rejecter(err);
148
- resolver(/^PostgreSQL (.*?)( |$)/.exec(resp.rows[0].version)[1]);
149
- });
150
- });
151
- },
152
-
153
- // Position the bindings for the query. The escape sequence for question mark
154
- // is \? (e.g. knex.raw("\\?") since javascript requires '\' to be escaped too...)
155
- positionBindings(sql) {
156
- let questionCount = 0;
157
- return sql.replace(/(\\*)(\?)/g, function (match, escapes) {
158
- if (escapes.length % 2) {
159
- return '?';
160
- } else {
161
- questionCount++;
162
- return `$${questionCount}`;
163
- }
164
- });
165
- },
166
-
167
- setSchemaSearchPath(connection, searchPath) {
168
- let path = searchPath || this.searchPath;
169
-
170
- if (!path) return Promise.resolve(true);
171
-
172
- if (!Array.isArray(path) && !isString(path)) {
173
- throw new TypeError(
174
- `knex: Expected searchPath to be Array/String, got: ${typeof path}`
175
- );
176
- }
177
-
178
- if (isString(path)) {
179
- if (path.includes(',')) {
180
- const parts = path.split(',');
181
- const arraySyntax = `[${parts
182
- .map((searchPath) => `'${searchPath}'`)
183
- .join(', ')}]`;
184
- this.logger.warn(
185
- `Detected comma in searchPath "${path}".` +
186
- `If you are trying to specify multiple schemas, use Array syntax: ${arraySyntax}`
187
- );
188
- }
189
- path = [path];
190
- }
191
-
192
- path = path.map((schemaName) => `"${schemaName}"`).join(',');
193
-
194
- return new Promise(function (resolver, rejecter) {
195
- connection.query(`set search_path to ${path}`, function (err) {
196
- if (err) return rejecter(err);
197
- resolver(true);
198
- });
199
- });
200
- },
201
-
202
- _stream(connection, obj, stream, options) {
203
- const PGQueryStream = process.browser
204
- ? undefined
205
- : require('pg-query-stream');
206
- const sql = obj.sql;
207
-
208
- return new Promise(function (resolver, rejecter) {
209
- const queryStream = connection.query(
210
- new PGQueryStream(sql, obj.bindings, options)
211
- );
212
-
213
- queryStream.on('error', function (error) {
214
- rejecter(error);
215
- stream.emit('error', error);
216
- });
217
-
218
- // 'end' IS propagated by .pipe, by default
219
- stream.on('end', resolver);
220
- queryStream.pipe(stream);
221
- });
222
- },
223
-
224
- // Runs the query on the specified connection, providing the bindings
225
- // and any other necessary prep work.
226
- _query(connection, obj) {
227
- let queryConfig = {
228
- text: obj.sql,
229
- values: obj.bindings || [],
230
- };
231
-
232
- if (obj.options) {
233
- queryConfig = extend(queryConfig, obj.options);
234
- }
235
-
236
- return new Promise(function (resolver, rejecter) {
237
- connection.query(queryConfig, function (err, response) {
238
- if (err) return rejecter(err);
239
- obj.response = response;
240
- resolver(obj);
241
- });
242
- });
243
- },
244
-
245
- // Ensures the response is returned in the same format as other clients.
246
- processResponse(obj, runner) {
247
- const resp = obj.response;
248
- if (obj.output) return obj.output.call(runner, resp);
249
- if (obj.method === 'raw') return resp;
250
- const { returning } = obj;
251
- if (resp.command === 'SELECT') {
252
- if (obj.method === 'first') return resp.rows[0];
253
- if (obj.method === 'pluck') return map(resp.rows, obj.pluck);
254
- return resp.rows;
255
- }
256
- if (returning) {
257
- const returns = [];
258
- for (let i = 0, l = resp.rows.length; i < l; i++) {
259
- const row = resp.rows[i];
260
- if (returning === '*' || Array.isArray(returning)) {
261
- returns[i] = row;
262
- } else {
263
- // Pluck the only column in the row.
264
- returns[i] = row[Object.keys(row)[0]];
265
- }
266
- }
267
- return returns;
268
- }
269
- if (resp.command === 'UPDATE' || resp.command === 'DELETE') {
270
- return resp.rowCount;
271
- }
272
- return resp;
273
- },
274
-
275
- canCancelQuery: true,
276
- async cancelQuery(connectionToKill) {
277
- // Error out if we can't acquire connection in time.
278
- // Purposely not putting timeout on `pg_cancel_backend` execution because erroring
279
- // early there would release the `connectionToKill` back to the pool with
280
- // a `KILL QUERY` command yet to finish.
281
- const conn = await this.acquireConnection();
282
-
283
- try {
284
- return await this._wrappedCancelQueryCall(conn, connectionToKill);
285
- } finally {
286
- // NOT returning this promise because we want to release the connection
287
- // in a non-blocking fashion
288
- this.releaseConnection(conn);
289
- }
290
- },
291
- _wrappedCancelQueryCall(conn, connectionToKill) {
292
- return this.query(conn, {
293
- method: 'raw',
294
- sql: 'SELECT pg_cancel_backend(?);',
295
- bindings: [connectionToKill.processID],
296
- options: {},
297
- });
298
- },
299
- });
300
-
301
- function arrayString(arr, esc) {
302
- let result = '{';
303
- for (let i = 0; i < arr.length; i++) {
304
- if (i > 0) result += ',';
305
- const val = arr[i];
306
- if (val === null || typeof val === 'undefined') {
307
- result += 'NULL';
308
- } else if (Array.isArray(val)) {
309
- result += arrayString(val, esc);
310
- } else if (typeof val === 'number') {
311
- result += val;
312
- } else {
313
- result += JSON.stringify(typeof val === 'string' ? val : esc(val));
314
- }
315
- }
316
- return result + '}';
317
- }
318
-
319
- module.exports = Client_PG;
1
+ // PostgreSQL
2
+ // -------
3
+ const extend = require('lodash/extend');
4
+ const map = require('lodash/map');
5
+ const { promisify, inherits } = require('util');
6
+ const Client = require('../../client');
7
+
8
+ const QueryCompiler = require('./query/compiler');
9
+ const ColumnCompiler = require('./schema/columncompiler');
10
+ const TableCompiler = require('./schema/tablecompiler');
11
+ const SchemaCompiler = require('./schema/compiler');
12
+ const { makeEscape } = require('../../query/string');
13
+ const { isString } = require('../../util/is');
14
+
15
+ function Client_PG(config) {
16
+ Client.apply(this, arguments);
17
+ if (config.returning) {
18
+ this.defaultReturning = config.returning;
19
+ }
20
+
21
+ if (config.searchPath) {
22
+ this.searchPath = config.searchPath;
23
+ }
24
+ }
25
+ inherits(Client_PG, Client);
26
+
27
+ Object.assign(Client_PG.prototype, {
28
+ queryCompiler() {
29
+ return new QueryCompiler(this, ...arguments);
30
+ },
31
+
32
+ columnCompiler() {
33
+ return new ColumnCompiler(this, ...arguments);
34
+ },
35
+
36
+ schemaCompiler() {
37
+ return new SchemaCompiler(this, ...arguments);
38
+ },
39
+
40
+ tableCompiler() {
41
+ return new TableCompiler(this, ...arguments);
42
+ },
43
+
44
+ dialect: 'postgresql',
45
+
46
+ driverName: 'pg',
47
+
48
+ _driver() {
49
+ return require('pg');
50
+ },
51
+
52
+ _escapeBinding: makeEscape({
53
+ escapeArray(val, esc) {
54
+ return esc(arrayString(val, esc));
55
+ },
56
+ escapeString(str) {
57
+ let hasBackslash = false;
58
+ let escaped = "'";
59
+ for (let i = 0; i < str.length; i++) {
60
+ const c = str[i];
61
+ if (c === "'") {
62
+ escaped += c + c;
63
+ } else if (c === '\\') {
64
+ escaped += c + c;
65
+ hasBackslash = true;
66
+ } else {
67
+ escaped += c;
68
+ }
69
+ }
70
+ escaped += "'";
71
+ if (hasBackslash === true) {
72
+ escaped = 'E' + escaped;
73
+ }
74
+ return escaped;
75
+ },
76
+ escapeObject(val, prepareValue, timezone, seen = []) {
77
+ if (val && typeof val.toPostgres === 'function') {
78
+ seen = seen || [];
79
+ if (seen.indexOf(val) !== -1) {
80
+ throw new Error(
81
+ `circular reference detected while preparing "${val}" for query`
82
+ );
83
+ }
84
+ seen.push(val);
85
+ return prepareValue(val.toPostgres(prepareValue), seen);
86
+ }
87
+ return JSON.stringify(val);
88
+ },
89
+ }),
90
+
91
+ wrapIdentifierImpl(value) {
92
+ if (value === '*') return value;
93
+
94
+ let arrayAccessor = '';
95
+ const arrayAccessorMatch = value.match(/(.*?)(\[[0-9]+\])/);
96
+
97
+ if (arrayAccessorMatch) {
98
+ value = arrayAccessorMatch[1];
99
+ arrayAccessor = arrayAccessorMatch[2];
100
+ }
101
+
102
+ return `"${value.replace(/"/g, '""')}"${arrayAccessor}`;
103
+ },
104
+
105
+ // Get a raw connection, called by the `pool` whenever a new
106
+ // connection needs to be added to the pool.
107
+ acquireRawConnection() {
108
+ const client = this;
109
+ return new Promise(function (resolver, rejecter) {
110
+ const connection = new client.driver.Client(client.connectionSettings);
111
+ connection.connect(function (err, connection) {
112
+ if (err) {
113
+ return rejecter(err);
114
+ }
115
+ connection.on('error', (err) => {
116
+ connection.__knex__disposed = err;
117
+ });
118
+ connection.on('end', (err) => {
119
+ connection.__knex__disposed = err || 'Connection ended unexpectedly';
120
+ });
121
+ if (!client.version) {
122
+ return client.checkVersion(connection).then(function (version) {
123
+ client.version = version;
124
+ resolver(connection);
125
+ });
126
+ }
127
+ resolver(connection);
128
+ });
129
+ }).then(function setSearchPath(connection) {
130
+ client.setSchemaSearchPath(connection);
131
+ return connection;
132
+ });
133
+ },
134
+
135
+ // Used to explicitly close a connection, called internally by the pool
136
+ // when a connection times out or the pool is shutdown.
137
+ async destroyRawConnection(connection) {
138
+ const end = promisify((cb) => connection.end(cb));
139
+ return end();
140
+ },
141
+
142
+ // In PostgreSQL, we need to do a version check to do some feature
143
+ // checking on the database.
144
+ checkVersion(connection) {
145
+ return new Promise(function (resolver, rejecter) {
146
+ connection.query('select version();', function (err, resp) {
147
+ if (err) return rejecter(err);
148
+ resolver(/^PostgreSQL (.*?)( |$)/.exec(resp.rows[0].version)[1]);
149
+ });
150
+ });
151
+ },
152
+
153
+ // Position the bindings for the query. The escape sequence for question mark
154
+ // is \? (e.g. knex.raw("\\?") since javascript requires '\' to be escaped too...)
155
+ positionBindings(sql) {
156
+ let questionCount = 0;
157
+ return sql.replace(/(\\*)(\?)/g, function (match, escapes) {
158
+ if (escapes.length % 2) {
159
+ return '?';
160
+ } else {
161
+ questionCount++;
162
+ return `$${questionCount}`;
163
+ }
164
+ });
165
+ },
166
+
167
+ setSchemaSearchPath(connection, searchPath) {
168
+ let path = searchPath || this.searchPath;
169
+
170
+ if (!path) return Promise.resolve(true);
171
+
172
+ if (!Array.isArray(path) && !isString(path)) {
173
+ throw new TypeError(
174
+ `knex: Expected searchPath to be Array/String, got: ${typeof path}`
175
+ );
176
+ }
177
+
178
+ if (isString(path)) {
179
+ if (path.includes(',')) {
180
+ const parts = path.split(',');
181
+ const arraySyntax = `[${parts
182
+ .map((searchPath) => `'${searchPath}'`)
183
+ .join(', ')}]`;
184
+ this.logger.warn(
185
+ `Detected comma in searchPath "${path}".` +
186
+ `If you are trying to specify multiple schemas, use Array syntax: ${arraySyntax}`
187
+ );
188
+ }
189
+ path = [path];
190
+ }
191
+
192
+ path = path.map((schemaName) => `"${schemaName}"`).join(',');
193
+
194
+ return new Promise(function (resolver, rejecter) {
195
+ connection.query(`set search_path to ${path}`, function (err) {
196
+ if (err) return rejecter(err);
197
+ resolver(true);
198
+ });
199
+ });
200
+ },
201
+
202
+ _stream(connection, obj, stream, options) {
203
+ const PGQueryStream = process.browser
204
+ ? undefined
205
+ : require('pg-query-stream');
206
+ const sql = obj.sql;
207
+
208
+ return new Promise(function (resolver, rejecter) {
209
+ const queryStream = connection.query(
210
+ new PGQueryStream(sql, obj.bindings, options)
211
+ );
212
+
213
+ queryStream.on('error', function (error) {
214
+ rejecter(error);
215
+ stream.emit('error', error);
216
+ });
217
+
218
+ // 'end' IS propagated by .pipe, by default
219
+ stream.on('end', resolver);
220
+ queryStream.pipe(stream);
221
+ });
222
+ },
223
+
224
+ // Runs the query on the specified connection, providing the bindings
225
+ // and any other necessary prep work.
226
+ _query(connection, obj) {
227
+ let queryConfig = {
228
+ text: obj.sql,
229
+ values: obj.bindings || [],
230
+ };
231
+
232
+ if (obj.options) {
233
+ queryConfig = extend(queryConfig, obj.options);
234
+ }
235
+
236
+ return new Promise(function (resolver, rejecter) {
237
+ connection.query(queryConfig, function (err, response) {
238
+ if (err) return rejecter(err);
239
+ obj.response = response;
240
+ resolver(obj);
241
+ });
242
+ });
243
+ },
244
+
245
+ // Ensures the response is returned in the same format as other clients.
246
+ processResponse(obj, runner) {
247
+ const resp = obj.response;
248
+ if (obj.output) return obj.output.call(runner, resp);
249
+ if (obj.method === 'raw') return resp;
250
+ const { returning } = obj;
251
+ if (resp.command === 'SELECT') {
252
+ if (obj.method === 'first') return resp.rows[0];
253
+ if (obj.method === 'pluck') return map(resp.rows, obj.pluck);
254
+ return resp.rows;
255
+ }
256
+ if (returning) {
257
+ const returns = [];
258
+ for (let i = 0, l = resp.rows.length; i < l; i++) {
259
+ const row = resp.rows[i];
260
+ if (returning === '*' || Array.isArray(returning)) {
261
+ returns[i] = row;
262
+ } else {
263
+ // Pluck the only column in the row.
264
+ returns[i] = row[Object.keys(row)[0]];
265
+ }
266
+ }
267
+ return returns;
268
+ }
269
+ if (resp.command === 'UPDATE' || resp.command === 'DELETE') {
270
+ return resp.rowCount;
271
+ }
272
+ return resp;
273
+ },
274
+
275
+ canCancelQuery: true,
276
+ async cancelQuery(connectionToKill) {
277
+ // Error out if we can't acquire connection in time.
278
+ // Purposely not putting timeout on `pg_cancel_backend` execution because erroring
279
+ // early there would release the `connectionToKill` back to the pool with
280
+ // a `KILL QUERY` command yet to finish.
281
+ const conn = await this.acquireConnection();
282
+
283
+ try {
284
+ return await this._wrappedCancelQueryCall(conn, connectionToKill);
285
+ } finally {
286
+ // NOT returning this promise because we want to release the connection
287
+ // in a non-blocking fashion
288
+ this.releaseConnection(conn);
289
+ }
290
+ },
291
+ _wrappedCancelQueryCall(conn, connectionToKill) {
292
+ return this.query(conn, {
293
+ method: 'raw',
294
+ sql: 'SELECT pg_cancel_backend(?);',
295
+ bindings: [connectionToKill.processID],
296
+ options: {},
297
+ });
298
+ },
299
+ });
300
+
301
+ function arrayString(arr, esc) {
302
+ let result = '{';
303
+ for (let i = 0; i < arr.length; i++) {
304
+ if (i > 0) result += ',';
305
+ const val = arr[i];
306
+ if (val === null || typeof val === 'undefined') {
307
+ result += 'NULL';
308
+ } else if (Array.isArray(val)) {
309
+ result += arrayString(val, esc);
310
+ } else if (typeof val === 'number') {
311
+ result += val;
312
+ } else {
313
+ result += JSON.stringify(typeof val === 'string' ? val : esc(val));
314
+ }
315
+ }
316
+ return result + '}';
317
+ }
318
+
319
+ module.exports = Client_PG;