knex 3.2.3 → 3.2.5

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 (199) hide show
  1. package/CHANGELOG.md +2447 -2441
  2. package/CONTRIBUTING.md +190 -190
  3. package/LICENSE +22 -22
  4. package/README.md +177 -156
  5. package/UPGRADING.md +245 -245
  6. package/bin/cli.js +516 -516
  7. package/bin/knexfile-runtime-error.js +27 -27
  8. package/bin/utils/cli-config-utils.js +217 -217
  9. package/bin/utils/constants.js +7 -7
  10. package/bin/utils/migrationsLister.js +37 -37
  11. package/knex.js +23 -23
  12. package/knex.mjs +11 -11
  13. package/lib/builder-interface-augmenter.js +120 -120
  14. package/lib/client.js +585 -585
  15. package/lib/constants.js +61 -61
  16. package/lib/dialects/better-sqlite3/index.js +101 -101
  17. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  18. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  19. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  20. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +46 -46
  21. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  22. package/lib/dialects/cockroachdb/index.js +86 -86
  23. package/lib/dialects/index.js +34 -34
  24. package/lib/dialects/mssql/index.js +498 -498
  25. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  26. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
  27. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  28. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  29. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +393 -393
  30. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  31. package/lib/dialects/mssql/transaction.js +176 -176
  32. package/lib/dialects/mysql/index.js +317 -317
  33. package/lib/dialects/mysql/query/mysql-querybuilder.js +14 -14
  34. package/lib/dialects/mysql/query/mysql-querycompiler.js +292 -292
  35. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  36. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  37. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +426 -426
  38. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  39. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  40. package/lib/dialects/mysql/transaction.js +46 -46
  41. package/lib/dialects/mysql2/index.js +53 -53
  42. package/lib/dialects/mysql2/transaction.js +44 -44
  43. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  44. package/lib/dialects/oracle/index.js +92 -92
  45. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
  46. package/lib/dialects/oracle/schema/internal/incrementUtils.js +22 -22
  47. package/lib/dialects/oracle/schema/internal/trigger.js +155 -155
  48. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  49. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  50. package/lib/dialects/oracle/schema/oracle-compiler.js +124 -124
  51. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +210 -210
  52. package/lib/dialects/oracle/utils.js +107 -107
  53. package/lib/dialects/oracledb/index.js +381 -381
  54. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  55. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
  56. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  57. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  58. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  59. package/lib/dialects/oracledb/transaction.js +98 -98
  60. package/lib/dialects/oracledb/utils.js +208 -208
  61. package/lib/dialects/pgnative/index.js +60 -60
  62. package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
  63. package/lib/dialects/postgres/index.js +373 -373
  64. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
  65. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
  66. package/lib/dialects/postgres/schema/pg-columncompiler.js +162 -162
  67. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  68. package/lib/dialects/postgres/schema/pg-tablecompiler.js +331 -331
  69. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  70. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  71. package/lib/dialects/redshift/index.js +86 -86
  72. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  73. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  74. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  75. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  76. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +134 -134
  77. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  78. package/lib/dialects/redshift/transaction.js +32 -32
  79. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +172 -172
  80. package/lib/dialects/sqlite3/index.js +263 -263
  81. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  82. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +341 -341
  83. package/lib/dialects/sqlite3/schema/ddl.js +380 -380
  84. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  85. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  86. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  87. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  88. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  89. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  90. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  91. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  92. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +364 -364
  93. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  94. package/lib/execution/batch-insert.js +51 -51
  95. package/lib/execution/internal/delay.js +6 -6
  96. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  97. package/lib/execution/internal/query-executioner.js +62 -62
  98. package/lib/execution/runner.js +325 -325
  99. package/lib/execution/transaction.js +417 -417
  100. package/lib/formatter/formatterUtils.js +42 -42
  101. package/lib/formatter/rawFormatter.js +84 -84
  102. package/lib/formatter/wrappingFormatter.js +253 -253
  103. package/lib/formatter.js +25 -25
  104. package/lib/index.js +3 -3
  105. package/lib/knex-builder/FunctionHelper.js +80 -80
  106. package/lib/knex-builder/Knex.js +59 -59
  107. package/lib/knex-builder/internal/config-resolver.js +57 -57
  108. package/lib/knex-builder/internal/parse-connection.js +87 -87
  109. package/lib/knex-builder/make-knex.js +345 -345
  110. package/lib/logger.js +76 -76
  111. package/lib/migrations/common/MigrationsLoader.js +36 -36
  112. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  113. package/lib/migrations/migrate/Migrator.js +632 -632
  114. package/lib/migrations/migrate/migrate-stub.js +17 -17
  115. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  116. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  117. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  118. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  119. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  120. package/lib/migrations/migrate/stub/eg.stub +14 -14
  121. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  122. package/lib/migrations/migrate/stub/js.stub +22 -22
  123. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  124. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  125. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  126. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  127. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  128. package/lib/migrations/migrate/stub/ls.stub +14 -14
  129. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  130. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  131. package/lib/migrations/migrate/stub/ts.stub +21 -21
  132. package/lib/migrations/migrate/table-creator.js +77 -77
  133. package/lib/migrations/migrate/table-resolver.js +27 -27
  134. package/lib/migrations/seed/Seeder.js +137 -137
  135. package/lib/migrations/seed/seed-stub.js +13 -13
  136. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  137. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  138. package/lib/migrations/seed/stub/coffee.stub +9 -9
  139. package/lib/migrations/seed/stub/eg.stub +11 -11
  140. package/lib/migrations/seed/stub/js.stub +13 -13
  141. package/lib/migrations/seed/stub/ls.stub +11 -11
  142. package/lib/migrations/seed/stub/mjs.stub +12 -12
  143. package/lib/migrations/seed/stub/ts.stub +13 -13
  144. package/lib/migrations/util/fs.js +86 -86
  145. package/lib/migrations/util/import-file.js +12 -12
  146. package/lib/migrations/util/is-module-type.js +9 -9
  147. package/lib/migrations/util/template.js +52 -52
  148. package/lib/migrations/util/timestamp.js +14 -14
  149. package/lib/query/analytic.js +52 -52
  150. package/lib/query/constants.js +15 -15
  151. package/lib/query/joinclause.js +270 -270
  152. package/lib/query/method-constants.js +136 -136
  153. package/lib/query/querybuilder.js +1793 -1793
  154. package/lib/query/querycompiler.js +1634 -1634
  155. package/lib/raw.js +139 -139
  156. package/lib/ref.js +39 -39
  157. package/lib/schema/builder.js +115 -115
  158. package/lib/schema/columnbuilder.js +146 -146
  159. package/lib/schema/columncompiler.js +307 -307
  160. package/lib/schema/compiler.js +187 -187
  161. package/lib/schema/internal/helpers.js +55 -55
  162. package/lib/schema/tablebuilder.js +379 -379
  163. package/lib/schema/tablecompiler.js +450 -450
  164. package/lib/schema/viewbuilder.js +92 -92
  165. package/lib/schema/viewcompiler.js +138 -138
  166. package/lib/util/finally-mixin.js +13 -13
  167. package/lib/util/helpers.js +95 -95
  168. package/lib/util/is.js +32 -32
  169. package/lib/util/nanoid.js +40 -40
  170. package/lib/util/noop.js +1 -1
  171. package/lib/util/save-async-stack.js +14 -14
  172. package/lib/util/security.js +32 -32
  173. package/lib/util/string.js +190 -190
  174. package/lib/util/timeout.js +29 -29
  175. package/package.json +295 -293
  176. package/scripts/act-testing/act.sh +19 -19
  177. package/scripts/act-testing/merged-no-label.json +11 -11
  178. package/scripts/act-testing/merged-patch-labeled.json +12 -12
  179. package/scripts/act-testing/merged-skip-labeled.json +12 -12
  180. package/scripts/act-testing/not-merged-patch-labeled.json +12 -12
  181. package/scripts/build-for-release.sh +121 -121
  182. package/scripts/build.js +125 -125
  183. package/scripts/clean.js +31 -31
  184. package/scripts/docker-compose.yml +150 -150
  185. package/scripts/format-changelog.js +55 -55
  186. package/scripts/next-release-howto.md +24 -24
  187. package/scripts/oracledb-install-driver-libs.sh +82 -82
  188. package/scripts/release.sh +36 -36
  189. package/scripts/runkit-example.js +35 -35
  190. package/scripts/stress-test/README.txt +18 -18
  191. package/scripts/stress-test/docker-compose.yml +55 -55
  192. package/scripts/stress-test/knex-stress-test.js +212 -212
  193. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -149
  194. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -101
  195. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -188
  196. package/types/index.d.mts +14 -0
  197. package/types/index.d.ts +3321 -3321
  198. package/types/result.d.ts +27 -27
  199. package/types/tables.d.ts +4 -4
@@ -1,373 +1,373 @@
1
- // PostgreSQL
2
- // -------
3
- const extend = require('lodash/extend');
4
- const map = require('lodash/map');
5
- const { promisify } = require('util');
6
- const Client = require('../../client');
7
-
8
- const Transaction = require('./execution/pg-transaction');
9
- const QueryCompiler = require('./query/pg-querycompiler');
10
- const QueryBuilder = require('./query/pg-querybuilder');
11
- const ColumnCompiler = require('./schema/pg-columncompiler');
12
- const TableCompiler = require('./schema/pg-tablecompiler');
13
- const ViewCompiler = require('./schema/pg-viewcompiler');
14
- const ViewBuilder = require('./schema/pg-viewbuilder');
15
- const SchemaCompiler = require('./schema/pg-compiler');
16
- const { makeEscape } = require('../../util/string');
17
- const { isString } = require('../../util/is');
18
-
19
- class Client_PG extends Client {
20
- constructor(config) {
21
- super(config);
22
- if (config.returning) {
23
- this.defaultReturning = config.returning;
24
- }
25
-
26
- if (config.searchPath) {
27
- this.searchPath = config.searchPath;
28
- }
29
- }
30
- transaction() {
31
- return new Transaction(this, ...arguments);
32
- }
33
-
34
- queryBuilder() {
35
- return new QueryBuilder(this);
36
- }
37
-
38
- queryCompiler(builder, formatter) {
39
- return new QueryCompiler(this, builder, formatter);
40
- }
41
-
42
- columnCompiler() {
43
- return new ColumnCompiler(this, ...arguments);
44
- }
45
-
46
- schemaCompiler() {
47
- return new SchemaCompiler(this, ...arguments);
48
- }
49
-
50
- tableCompiler() {
51
- return new TableCompiler(this, ...arguments);
52
- }
53
-
54
- viewCompiler() {
55
- return new ViewCompiler(this, ...arguments);
56
- }
57
-
58
- viewBuilder() {
59
- return new ViewBuilder(this, ...arguments);
60
- }
61
-
62
- _driver() {
63
- return require('pg');
64
- }
65
-
66
- wrapIdentifierImpl(value) {
67
- if (value === '*') return value;
68
-
69
- let arrayAccessor = '';
70
- const arrayAccessorMatch = value.match(/(.*?)(\[[0-9]+\])/);
71
-
72
- if (arrayAccessorMatch) {
73
- value = arrayAccessorMatch[1];
74
- arrayAccessor = arrayAccessorMatch[2];
75
- }
76
-
77
- return `"${value.replace(/"/g, '""')}"${arrayAccessor}`;
78
- }
79
-
80
- _acquireOnlyConnection() {
81
- const connection = new this.driver.Client(this.connectionSettings);
82
-
83
- connection.on('error', (err) => {
84
- connection.__knex__disposed = err;
85
- });
86
-
87
- connection.on('end', (err) => {
88
- connection.__knex__disposed = err || 'Connection ended unexpectedly';
89
- });
90
-
91
- return connection.connect().then(() => connection);
92
- }
93
-
94
- // Get a raw connection, called by the `pool` whenever a new
95
- // connection needs to be added to the pool.
96
- acquireRawConnection() {
97
- const client = this;
98
-
99
- return this._acquireOnlyConnection()
100
- .then(function (connection) {
101
- if (!client.version) {
102
- return client.checkVersion(connection).then(function (version) {
103
- client.version = version;
104
- return connection;
105
- });
106
- }
107
-
108
- return connection;
109
- })
110
- .then(async function setSearchPath(connection) {
111
- await client.setSchemaSearchPath(connection);
112
- return connection;
113
- });
114
- }
115
-
116
- // Used to explicitly close a connection, called internally by the pool
117
- // when a connection times out or the pool is shutdown.
118
- async destroyRawConnection(connection) {
119
- const end = promisify((cb) => connection.end(cb));
120
- return end();
121
- }
122
-
123
- // In PostgreSQL, we need to do a version check to do some feature
124
- // checking on the database.
125
- checkVersion(connection) {
126
- return new Promise((resolve, reject) => {
127
- connection.query('select version();', (err, resp) => {
128
- if (err) return reject(err);
129
- resolve(this._parseVersion(resp.rows[0].version));
130
- });
131
- });
132
- }
133
-
134
- _parseVersion(versionString) {
135
- return /^PostgreSQL (.*?)( |$)/.exec(versionString)[1];
136
- }
137
-
138
- // Position the bindings for the query. The escape sequence for question mark
139
- // is \? (e.g. knex.raw("\\?") since javascript requires '\' to be escaped too...)
140
- positionBindings(sql) {
141
- let questionCount = 0;
142
- return sql.replace(/(\\*)(\?)/g, function (match, escapes) {
143
- if (escapes.length % 2) {
144
- return '?';
145
- } else {
146
- questionCount++;
147
- return `$${questionCount}`;
148
- }
149
- });
150
- }
151
-
152
- setSchemaSearchPath(connection, searchPath) {
153
- let path = searchPath || this.searchPath;
154
-
155
- if (!path) return Promise.resolve(true);
156
-
157
- if (!Array.isArray(path) && !isString(path)) {
158
- throw new TypeError(
159
- `knex: Expected searchPath to be Array/String, got: ${typeof path}`
160
- );
161
- }
162
-
163
- if (isString(path)) {
164
- if (path.includes(',')) {
165
- const parts = path.split(',');
166
- const arraySyntax = `[${parts
167
- .map((searchPath) => `'${searchPath}'`)
168
- .join(', ')}]`;
169
- this.logger.warn(
170
- `Detected comma in searchPath "${path}".` +
171
- `If you are trying to specify multiple schemas, use Array syntax: ${arraySyntax}`
172
- );
173
- }
174
- path = [path];
175
- }
176
-
177
- path = path.map((schemaName) => `"${schemaName}"`).join(',');
178
-
179
- return new Promise(function (resolver, rejecter) {
180
- connection.query(`set search_path to ${path}`, function (err) {
181
- if (err) return rejecter(err);
182
- resolver(true);
183
- });
184
- });
185
- }
186
-
187
- _stream(connection, obj, stream, options) {
188
- if (!obj.sql) throw new Error('The query is empty');
189
-
190
- let PGQueryStream;
191
- if (process.browser) {
192
- PGQueryStream = undefined;
193
- } else {
194
- try {
195
- PGQueryStream = require('pg-query-stream');
196
- } catch (e) {
197
- if (
198
- e instanceof Error &&
199
- e.code === 'MODULE_NOT_FOUND' &&
200
- e.message.includes('pg-query-stream')
201
- ) {
202
- throw new Error(
203
- "knex PostgreSQL query streaming requires the 'pg-query-stream' package. Please install it (e.g. `npm i pg-query-stream`)."
204
- );
205
- }
206
- throw e;
207
- }
208
- }
209
- const sql = obj.sql;
210
-
211
- return new Promise(function (resolver, rejecter) {
212
- const queryStream = connection.query(
213
- new PGQueryStream(sql, obj.bindings, options)
214
- );
215
-
216
- queryStream.on('error', function (error) {
217
- rejecter(error);
218
- stream.emit('error', error);
219
- });
220
-
221
- queryStream.on('end', resolver);
222
- queryStream.pipe(stream);
223
- });
224
- }
225
-
226
- // Runs the query on the specified connection, providing the bindings
227
- // and any other necessary prep work.
228
- _query(connection, obj) {
229
- if (!obj.sql) throw new Error('The query is empty');
230
-
231
- let queryConfig = {
232
- text: obj.sql,
233
- values: obj.bindings || [],
234
- };
235
-
236
- if (obj.options) {
237
- queryConfig = extend(queryConfig, obj.options);
238
- }
239
-
240
- return new Promise(function (resolver, rejecter) {
241
- connection.query(queryConfig, function (err, response) {
242
- if (err) return rejecter(err);
243
- obj.response = response;
244
- resolver(obj);
245
- });
246
- });
247
- }
248
-
249
- // Ensures the response is returned in the same format as other clients.
250
- processResponse(obj, runner) {
251
- const resp = obj.response;
252
- if (obj.output) return obj.output.call(runner, resp);
253
- if (obj.method === 'raw') return resp;
254
- const { returning } = obj;
255
- if (resp.command === 'SELECT') {
256
- if (obj.method === 'first') return resp.rows[0];
257
- if (obj.method === 'pluck') return map(resp.rows, obj.pluck);
258
- return resp.rows;
259
- }
260
- if (returning) {
261
- const returns = [];
262
- for (let i = 0, l = resp.rows.length; i < l; i++) {
263
- const row = resp.rows[i];
264
- returns[i] = row;
265
- }
266
- return returns;
267
- }
268
- if (resp.command === 'UPDATE' || resp.command === 'DELETE') {
269
- return resp.rowCount;
270
- }
271
- return resp;
272
- }
273
-
274
- async cancelQuery(connectionToKill) {
275
- const conn = await this.acquireRawConnection();
276
-
277
- try {
278
- return await this._wrappedCancelQueryCall(conn, connectionToKill);
279
- } finally {
280
- await this.destroyRawConnection(conn).catch((err) => {
281
- this.logger.warn(`Connection Error: ${err}`);
282
- });
283
- }
284
- }
285
- _wrappedCancelQueryCall(conn, connectionToKill) {
286
- return this._query(conn, {
287
- sql: 'SELECT pg_cancel_backend($1);',
288
- bindings: [connectionToKill.processID],
289
- options: {},
290
- });
291
- }
292
-
293
- toPathForJson(jsonPath) {
294
- const PG_PATH_REGEX = /^{.*}$/;
295
- if (jsonPath.match(PG_PATH_REGEX)) {
296
- return jsonPath;
297
- }
298
- return (
299
- '{' +
300
- jsonPath
301
- .replace(/^(\$\.)/, '') // remove the first dollar
302
- .replace('.', ',')
303
- .replace(/\[([0-9]+)]/, ',$1') + // transform [number] to ,number
304
- '}'
305
- );
306
- }
307
- }
308
-
309
- Object.assign(Client_PG.prototype, {
310
- dialect: 'postgresql',
311
-
312
- driverName: 'pg',
313
- canCancelQuery: true,
314
-
315
- _escapeBinding: makeEscape({
316
- escapeArray(val, esc) {
317
- return esc(arrayString(val, esc));
318
- },
319
- escapeString(str) {
320
- let hasBackslash = false;
321
- let escaped = "'";
322
- for (let i = 0; i < str.length; i++) {
323
- const c = str[i];
324
- if (c === "'") {
325
- escaped += c + c;
326
- } else if (c === '\\') {
327
- escaped += c + c;
328
- hasBackslash = true;
329
- } else {
330
- escaped += c;
331
- }
332
- }
333
- escaped += "'";
334
- if (hasBackslash === true) {
335
- escaped = 'E' + escaped;
336
- }
337
- return escaped;
338
- },
339
- escapeObject(val, prepareValue, timezone, seen = []) {
340
- if (val && typeof val.toPostgres === 'function') {
341
- seen = seen || [];
342
- if (seen.indexOf(val) !== -1) {
343
- throw new Error(
344
- `circular reference detected while preparing "${val}" for query`
345
- );
346
- }
347
- seen.push(val);
348
- return prepareValue(val.toPostgres(prepareValue), seen);
349
- }
350
- return JSON.stringify(val);
351
- },
352
- }),
353
- });
354
-
355
- function arrayString(arr, esc) {
356
- let result = '{';
357
- for (let i = 0; i < arr.length; i++) {
358
- if (i > 0) result += ',';
359
- const val = arr[i];
360
- if (val === null || typeof val === 'undefined') {
361
- result += 'NULL';
362
- } else if (Array.isArray(val)) {
363
- result += arrayString(val, esc);
364
- } else if (typeof val === 'number') {
365
- result += val;
366
- } else {
367
- result += JSON.stringify(typeof val === 'string' ? val : esc(val));
368
- }
369
- }
370
- return result + '}';
371
- }
372
-
373
- module.exports = Client_PG;
1
+ // PostgreSQL
2
+ // -------
3
+ const extend = require('lodash/extend');
4
+ const map = require('lodash/map');
5
+ const { promisify } = require('util');
6
+ const Client = require('../../client');
7
+
8
+ const Transaction = require('./execution/pg-transaction');
9
+ const QueryCompiler = require('./query/pg-querycompiler');
10
+ const QueryBuilder = require('./query/pg-querybuilder');
11
+ const ColumnCompiler = require('./schema/pg-columncompiler');
12
+ const TableCompiler = require('./schema/pg-tablecompiler');
13
+ const ViewCompiler = require('./schema/pg-viewcompiler');
14
+ const ViewBuilder = require('./schema/pg-viewbuilder');
15
+ const SchemaCompiler = require('./schema/pg-compiler');
16
+ const { makeEscape } = require('../../util/string');
17
+ const { isString } = require('../../util/is');
18
+
19
+ class Client_PG extends Client {
20
+ constructor(config) {
21
+ super(config);
22
+ if (config.returning) {
23
+ this.defaultReturning = config.returning;
24
+ }
25
+
26
+ if (config.searchPath) {
27
+ this.searchPath = config.searchPath;
28
+ }
29
+ }
30
+ transaction() {
31
+ return new Transaction(this, ...arguments);
32
+ }
33
+
34
+ queryBuilder() {
35
+ return new QueryBuilder(this);
36
+ }
37
+
38
+ queryCompiler(builder, formatter) {
39
+ return new QueryCompiler(this, builder, formatter);
40
+ }
41
+
42
+ columnCompiler() {
43
+ return new ColumnCompiler(this, ...arguments);
44
+ }
45
+
46
+ schemaCompiler() {
47
+ return new SchemaCompiler(this, ...arguments);
48
+ }
49
+
50
+ tableCompiler() {
51
+ return new TableCompiler(this, ...arguments);
52
+ }
53
+
54
+ viewCompiler() {
55
+ return new ViewCompiler(this, ...arguments);
56
+ }
57
+
58
+ viewBuilder() {
59
+ return new ViewBuilder(this, ...arguments);
60
+ }
61
+
62
+ _driver() {
63
+ return require('pg');
64
+ }
65
+
66
+ wrapIdentifierImpl(value) {
67
+ if (value === '*') return value;
68
+
69
+ let arrayAccessor = '';
70
+ const arrayAccessorMatch = value.match(/(.*?)(\[[0-9]+\])/);
71
+
72
+ if (arrayAccessorMatch) {
73
+ value = arrayAccessorMatch[1];
74
+ arrayAccessor = arrayAccessorMatch[2];
75
+ }
76
+
77
+ return `"${value.replace(/"/g, '""')}"${arrayAccessor}`;
78
+ }
79
+
80
+ _acquireOnlyConnection() {
81
+ const connection = new this.driver.Client(this.connectionSettings);
82
+
83
+ connection.on('error', (err) => {
84
+ connection.__knex__disposed = err;
85
+ });
86
+
87
+ connection.on('end', (err) => {
88
+ connection.__knex__disposed = err || 'Connection ended unexpectedly';
89
+ });
90
+
91
+ return connection.connect().then(() => connection);
92
+ }
93
+
94
+ // Get a raw connection, called by the `pool` whenever a new
95
+ // connection needs to be added to the pool.
96
+ acquireRawConnection() {
97
+ const client = this;
98
+
99
+ return this._acquireOnlyConnection()
100
+ .then(function (connection) {
101
+ if (!client.version) {
102
+ return client.checkVersion(connection).then(function (version) {
103
+ client.version = version;
104
+ return connection;
105
+ });
106
+ }
107
+
108
+ return connection;
109
+ })
110
+ .then(async function setSearchPath(connection) {
111
+ await client.setSchemaSearchPath(connection);
112
+ return connection;
113
+ });
114
+ }
115
+
116
+ // Used to explicitly close a connection, called internally by the pool
117
+ // when a connection times out or the pool is shutdown.
118
+ async destroyRawConnection(connection) {
119
+ const end = promisify((cb) => connection.end(cb));
120
+ return end();
121
+ }
122
+
123
+ // In PostgreSQL, we need to do a version check to do some feature
124
+ // checking on the database.
125
+ checkVersion(connection) {
126
+ return new Promise((resolve, reject) => {
127
+ connection.query('select version();', (err, resp) => {
128
+ if (err) return reject(err);
129
+ resolve(this._parseVersion(resp.rows[0].version));
130
+ });
131
+ });
132
+ }
133
+
134
+ _parseVersion(versionString) {
135
+ return /^PostgreSQL (.*?)( |$)/.exec(versionString)[1];
136
+ }
137
+
138
+ // Position the bindings for the query. The escape sequence for question mark
139
+ // is \? (e.g. knex.raw("\\?") since javascript requires '\' to be escaped too...)
140
+ positionBindings(sql) {
141
+ let questionCount = 0;
142
+ return sql.replace(/(\\*)(\?)/g, function (match, escapes) {
143
+ if (escapes.length % 2) {
144
+ return '?';
145
+ } else {
146
+ questionCount++;
147
+ return `$${questionCount}`;
148
+ }
149
+ });
150
+ }
151
+
152
+ setSchemaSearchPath(connection, searchPath) {
153
+ let path = searchPath || this.searchPath;
154
+
155
+ if (!path) return Promise.resolve(true);
156
+
157
+ if (!Array.isArray(path) && !isString(path)) {
158
+ throw new TypeError(
159
+ `knex: Expected searchPath to be Array/String, got: ${typeof path}`
160
+ );
161
+ }
162
+
163
+ if (isString(path)) {
164
+ if (path.includes(',')) {
165
+ const parts = path.split(',');
166
+ const arraySyntax = `[${parts
167
+ .map((searchPath) => `'${searchPath}'`)
168
+ .join(', ')}]`;
169
+ this.logger.warn(
170
+ `Detected comma in searchPath "${path}".` +
171
+ `If you are trying to specify multiple schemas, use Array syntax: ${arraySyntax}`
172
+ );
173
+ }
174
+ path = [path];
175
+ }
176
+
177
+ path = path.map((schemaName) => `"${schemaName}"`).join(',');
178
+
179
+ return new Promise(function (resolver, rejecter) {
180
+ connection.query(`set search_path to ${path}`, function (err) {
181
+ if (err) return rejecter(err);
182
+ resolver(true);
183
+ });
184
+ });
185
+ }
186
+
187
+ _stream(connection, obj, stream, options) {
188
+ if (!obj.sql) throw new Error('The query is empty');
189
+
190
+ let PGQueryStream;
191
+ if (process.browser) {
192
+ PGQueryStream = undefined;
193
+ } else {
194
+ try {
195
+ PGQueryStream = require('pg-query-stream');
196
+ } catch (e) {
197
+ if (
198
+ e instanceof Error &&
199
+ e.code === 'MODULE_NOT_FOUND' &&
200
+ e.message.includes('pg-query-stream')
201
+ ) {
202
+ throw new Error(
203
+ "knex PostgreSQL query streaming requires the 'pg-query-stream' package. Please install it (e.g. `npm i pg-query-stream`)."
204
+ );
205
+ }
206
+ throw e;
207
+ }
208
+ }
209
+ const sql = obj.sql;
210
+
211
+ return new Promise(function (resolver, rejecter) {
212
+ const queryStream = connection.query(
213
+ new PGQueryStream(sql, obj.bindings, options)
214
+ );
215
+
216
+ queryStream.on('error', function (error) {
217
+ rejecter(error);
218
+ stream.emit('error', error);
219
+ });
220
+
221
+ queryStream.on('end', resolver);
222
+ queryStream.pipe(stream);
223
+ });
224
+ }
225
+
226
+ // Runs the query on the specified connection, providing the bindings
227
+ // and any other necessary prep work.
228
+ _query(connection, obj) {
229
+ if (!obj.sql) throw new Error('The query is empty');
230
+
231
+ let queryConfig = {
232
+ text: obj.sql,
233
+ values: obj.bindings || [],
234
+ };
235
+
236
+ if (obj.options) {
237
+ queryConfig = extend(queryConfig, obj.options);
238
+ }
239
+
240
+ return new Promise(function (resolver, rejecter) {
241
+ connection.query(queryConfig, function (err, response) {
242
+ if (err) return rejecter(err);
243
+ obj.response = response;
244
+ resolver(obj);
245
+ });
246
+ });
247
+ }
248
+
249
+ // Ensures the response is returned in the same format as other clients.
250
+ processResponse(obj, runner) {
251
+ const resp = obj.response;
252
+ if (obj.output) return obj.output.call(runner, resp);
253
+ if (obj.method === 'raw') return resp;
254
+ const { returning } = obj;
255
+ if (resp.command === 'SELECT') {
256
+ if (obj.method === 'first') return resp.rows[0];
257
+ if (obj.method === 'pluck') return map(resp.rows, obj.pluck);
258
+ return resp.rows;
259
+ }
260
+ if (returning) {
261
+ const returns = [];
262
+ for (let i = 0, l = resp.rows.length; i < l; i++) {
263
+ const row = resp.rows[i];
264
+ returns[i] = row;
265
+ }
266
+ return returns;
267
+ }
268
+ if (resp.command === 'UPDATE' || resp.command === 'DELETE') {
269
+ return resp.rowCount;
270
+ }
271
+ return resp;
272
+ }
273
+
274
+ async cancelQuery(connectionToKill) {
275
+ const conn = await this.acquireRawConnection();
276
+
277
+ try {
278
+ return await this._wrappedCancelQueryCall(conn, connectionToKill);
279
+ } finally {
280
+ await this.destroyRawConnection(conn).catch((err) => {
281
+ this.logger.warn(`Connection Error: ${err}`);
282
+ });
283
+ }
284
+ }
285
+ _wrappedCancelQueryCall(conn, connectionToKill) {
286
+ return this._query(conn, {
287
+ sql: 'SELECT pg_cancel_backend($1);',
288
+ bindings: [connectionToKill.processID],
289
+ options: {},
290
+ });
291
+ }
292
+
293
+ toPathForJson(jsonPath) {
294
+ const PG_PATH_REGEX = /^{.*}$/;
295
+ if (jsonPath.match(PG_PATH_REGEX)) {
296
+ return jsonPath;
297
+ }
298
+ return (
299
+ '{' +
300
+ jsonPath
301
+ .replace(/^(\$\.)/, '') // remove the first dollar
302
+ .replace('.', ',')
303
+ .replace(/\[([0-9]+)]/, ',$1') + // transform [number] to ,number
304
+ '}'
305
+ );
306
+ }
307
+ }
308
+
309
+ Object.assign(Client_PG.prototype, {
310
+ dialect: 'postgresql',
311
+
312
+ driverName: 'pg',
313
+ canCancelQuery: true,
314
+
315
+ _escapeBinding: makeEscape({
316
+ escapeArray(val, esc) {
317
+ return esc(arrayString(val, esc));
318
+ },
319
+ escapeString(str) {
320
+ let hasBackslash = false;
321
+ let escaped = "'";
322
+ for (let i = 0; i < str.length; i++) {
323
+ const c = str[i];
324
+ if (c === "'") {
325
+ escaped += c + c;
326
+ } else if (c === '\\') {
327
+ escaped += c + c;
328
+ hasBackslash = true;
329
+ } else {
330
+ escaped += c;
331
+ }
332
+ }
333
+ escaped += "'";
334
+ if (hasBackslash === true) {
335
+ escaped = 'E' + escaped;
336
+ }
337
+ return escaped;
338
+ },
339
+ escapeObject(val, prepareValue, timezone, seen = []) {
340
+ if (val && typeof val.toPostgres === 'function') {
341
+ seen = seen || [];
342
+ if (seen.indexOf(val) !== -1) {
343
+ throw new Error(
344
+ `circular reference detected while preparing "${val}" for query`
345
+ );
346
+ }
347
+ seen.push(val);
348
+ return prepareValue(val.toPostgres(prepareValue), seen);
349
+ }
350
+ return JSON.stringify(val);
351
+ },
352
+ }),
353
+ });
354
+
355
+ function arrayString(arr, esc) {
356
+ let result = '{';
357
+ for (let i = 0; i < arr.length; i++) {
358
+ if (i > 0) result += ',';
359
+ const val = arr[i];
360
+ if (val === null || typeof val === 'undefined') {
361
+ result += 'NULL';
362
+ } else if (Array.isArray(val)) {
363
+ result += arrayString(val, esc);
364
+ } else if (typeof val === 'number') {
365
+ result += val;
366
+ } else {
367
+ result += JSON.stringify(typeof val === 'string' ? val : esc(val));
368
+ }
369
+ }
370
+ return result + '}';
371
+ }
372
+
373
+ module.exports = Client_PG;