knex 2.5.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/CHANGELOG.md +64 -58
  2. package/CONTRIBUTING.md +194 -194
  3. package/README.md +149 -147
  4. package/UPGRADING.md +245 -233
  5. package/bin/cli.js +475 -473
  6. package/bin/utils/cli-config-utils.js +212 -210
  7. package/bin/utils/constants.js +7 -7
  8. package/bin/utils/migrationsLister.js +37 -37
  9. package/knex.js +23 -23
  10. package/knex.mjs +11 -11
  11. package/lib/builder-interface-augmenter.js +120 -120
  12. package/lib/client.js +495 -495
  13. package/lib/constants.js +61 -61
  14. package/lib/dialects/better-sqlite3/index.js +77 -77
  15. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  16. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  17. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  18. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  19. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  20. package/lib/dialects/cockroachdb/index.js +86 -86
  21. package/lib/dialects/index.js +20 -20
  22. package/lib/dialects/mssql/index.js +500 -500
  23. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  24. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
  25. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  26. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  27. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  28. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  29. package/lib/dialects/mssql/transaction.js +176 -176
  30. package/lib/dialects/mysql/index.js +201 -201
  31. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  32. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  33. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  34. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  35. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  36. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  37. package/lib/dialects/mysql/transaction.js +46 -46
  38. package/lib/dialects/mysql2/index.js +53 -53
  39. package/lib/dialects/mysql2/transaction.js +44 -44
  40. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  41. package/lib/dialects/oracle/index.js +92 -92
  42. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
  43. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  44. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  45. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  46. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  47. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  48. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  49. package/lib/dialects/oracle/utils.js +87 -87
  50. package/lib/dialects/oracledb/index.js +327 -327
  51. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  52. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
  53. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  54. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  55. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  56. package/lib/dialects/oracledb/transaction.js +98 -98
  57. package/lib/dialects/oracledb/utils.js +208 -208
  58. package/lib/dialects/pgnative/index.js +60 -60
  59. package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
  60. package/lib/dialects/postgres/index.js +358 -358
  61. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
  62. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
  63. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  64. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  65. package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -304
  66. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  67. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  68. package/lib/dialects/redshift/index.js +86 -86
  69. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  70. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  71. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  72. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  73. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  74. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  75. package/lib/dialects/redshift/transaction.js +32 -32
  76. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -25
  77. package/lib/dialects/sqlite3/index.js +250 -250
  78. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  79. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  80. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  81. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  82. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  83. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  84. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  85. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  86. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  87. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  88. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  89. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  90. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  91. package/lib/execution/batch-insert.js +51 -51
  92. package/lib/execution/internal/delay.js +6 -6
  93. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  94. package/lib/execution/internal/query-executioner.js +62 -62
  95. package/lib/execution/runner.js +325 -325
  96. package/lib/execution/transaction.js +409 -409
  97. package/lib/formatter/formatterUtils.js +42 -42
  98. package/lib/formatter/rawFormatter.js +84 -84
  99. package/lib/formatter/wrappingFormatter.js +250 -250
  100. package/lib/formatter.js +25 -25
  101. package/lib/index.js +3 -3
  102. package/lib/knex-builder/FunctionHelper.js +80 -80
  103. package/lib/knex-builder/Knex.js +59 -59
  104. package/lib/knex-builder/internal/config-resolver.js +57 -57
  105. package/lib/knex-builder/internal/parse-connection.js +87 -87
  106. package/lib/knex-builder/make-knex.js +345 -345
  107. package/lib/logger.js +76 -76
  108. package/lib/migrations/common/MigrationsLoader.js +36 -36
  109. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  110. package/lib/migrations/migrate/Migrator.js +598 -598
  111. package/lib/migrations/migrate/migrate-stub.js +17 -17
  112. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  113. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  114. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  115. package/lib/migrations/migrate/table-creator.js +77 -77
  116. package/lib/migrations/migrate/table-resolver.js +27 -27
  117. package/lib/migrations/seed/Seeder.js +137 -137
  118. package/lib/migrations/seed/seed-stub.js +13 -13
  119. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  120. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  121. package/lib/migrations/util/fs.js +86 -86
  122. package/lib/migrations/util/import-file.js +12 -12
  123. package/lib/migrations/util/is-module-type.js +9 -9
  124. package/lib/migrations/util/template.js +52 -52
  125. package/lib/migrations/util/timestamp.js +14 -14
  126. package/lib/query/analytic.js +52 -52
  127. package/lib/query/constants.js +15 -15
  128. package/lib/query/joinclause.js +270 -270
  129. package/lib/query/method-constants.js +136 -136
  130. package/lib/query/querybuilder.js +1793 -1793
  131. package/lib/query/querycompiler.js +1591 -1591
  132. package/lib/raw.js +139 -139
  133. package/lib/ref.js +39 -39
  134. package/lib/schema/builder.js +115 -115
  135. package/lib/schema/columnbuilder.js +146 -146
  136. package/lib/schema/columncompiler.js +307 -307
  137. package/lib/schema/compiler.js +187 -187
  138. package/lib/schema/internal/helpers.js +55 -55
  139. package/lib/schema/tablebuilder.js +376 -376
  140. package/lib/schema/tablecompiler.js +433 -433
  141. package/lib/schema/viewbuilder.js +92 -92
  142. package/lib/schema/viewcompiler.js +138 -138
  143. package/lib/util/finally-mixin.js +13 -13
  144. package/lib/util/helpers.js +95 -95
  145. package/lib/util/is.js +32 -32
  146. package/lib/util/nanoid.js +40 -40
  147. package/lib/util/noop.js +1 -1
  148. package/lib/util/save-async-stack.js +14 -14
  149. package/lib/util/security.js +26 -26
  150. package/lib/util/string.js +190 -190
  151. package/lib/util/timeout.js +29 -29
  152. package/package.json +11 -10
  153. package/scripts/build.js +125 -125
  154. package/scripts/clean.js +31 -31
  155. package/scripts/docker-compose.yml +152 -152
  156. package/scripts/next-release-howto.md +24 -24
  157. package/scripts/release.sh +2 -0
  158. package/scripts/runkit-example.js +35 -34
  159. package/scripts/stress-test/docker-compose.yml +57 -57
  160. package/scripts/stress-test/knex-stress-test.js +212 -208
  161. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -145
  162. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -100
  163. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -184
  164. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  165. package/types/index.d.ts +3274 -3273
  166. package/types/result.d.ts +27 -27
  167. package/types/tables.d.ts +4 -4
@@ -1,481 +1,481 @@
1
- const clone = require('lodash/clone');
2
- const each = require('lodash/each');
3
- const isEmpty = require('lodash/isEmpty');
4
- const isPlainObject = require('lodash/isPlainObject');
5
- const Oracle_Compiler = require('../../oracle/query/oracle-querycompiler');
6
- const ReturningHelper = require('../utils').ReturningHelper;
7
- const BlobHelper = require('../utils').BlobHelper;
8
- const { isString } = require('../../../util/is');
9
- const {
10
- columnize: columnize_,
11
- } = require('../../../formatter/wrappingFormatter');
12
-
13
- class Oracledb_Compiler extends Oracle_Compiler {
14
- // Compiles an "insert" query, allowing for multiple
15
- // inserts using a single query statement.
16
- insert() {
17
- const self = this;
18
- const outBindPrep = this._prepOutbindings(
19
- this.single.insert,
20
- this.single.returning
21
- );
22
- const outBinding = outBindPrep.outBinding;
23
- const returning = outBindPrep.returning;
24
- const insertValues = outBindPrep.values;
25
-
26
- if (
27
- Array.isArray(insertValues) &&
28
- insertValues.length === 1 &&
29
- isEmpty(insertValues[0])
30
- ) {
31
- const returningFragment = this.single.returning
32
- ? ' (' + this.formatter.wrap(this.single.returning) + ')'
33
- : '';
34
-
35
- return this._addReturningToSqlAndConvert(
36
- 'insert into ' +
37
- this.tableName +
38
- returningFragment +
39
- ' values (default)',
40
- outBinding[0],
41
- this.tableName,
42
- returning
43
- );
44
- }
45
-
46
- if (
47
- isEmpty(this.single.insert) &&
48
- typeof this.single.insert !== 'function'
49
- ) {
50
- return '';
51
- }
52
-
53
- const insertData = this._prepInsert(insertValues);
54
-
55
- const sql = {};
56
-
57
- if (isString(insertData)) {
58
- return this._addReturningToSqlAndConvert(
59
- 'insert into ' + this.tableName + ' ' + insertData,
60
- outBinding[0],
61
- this.tableName,
62
- returning
63
- );
64
- }
65
-
66
- if (insertData.values.length === 1) {
67
- return this._addReturningToSqlAndConvert(
68
- 'insert into ' +
69
- this.tableName +
70
- ' (' +
71
- this.formatter.columnize(insertData.columns) +
72
- ') values (' +
73
- this.client.parameterize(
74
- insertData.values[0],
75
- undefined,
76
- this.builder,
77
- this.bindingsHolder
78
- ) +
79
- ')',
80
- outBinding[0],
81
- this.tableName,
82
- returning
83
- );
84
- }
85
-
86
- const insertDefaultsOnly = insertData.columns.length === 0;
87
- sql.returning = returning;
88
- sql.sql =
89
- 'begin ' +
90
- insertData.values
91
- .map(function (value, index) {
92
- const parameterizedValues = !insertDefaultsOnly
93
- ? self.client.parameterize(
94
- value,
95
- self.client.valueForUndefined,
96
- self.builder,
97
- self.bindingsHolder
98
- )
99
- : '';
100
- let subSql = 'insert into ' + self.tableName;
101
-
102
- if (insertDefaultsOnly) {
103
- // No columns given so only the default value
104
- subSql +=
105
- ' (' +
106
- self.formatter.wrap(self.single.returning) +
107
- ') values (default)';
108
- } else {
109
- subSql +=
110
- ' (' +
111
- self.formatter.columnize(insertData.columns) +
112
- ') values (' +
113
- parameterizedValues +
114
- ')';
115
- }
116
-
117
- let returningClause = '';
118
- let intoClause = '';
119
- // ToDo review if this code is still needed or could be dropped
120
- // eslint-disable-next-line no-unused-vars
121
- let usingClause = '';
122
- let outClause = '';
123
-
124
- each(value, function (val) {
125
- if (!(val instanceof BlobHelper)) {
126
- usingClause += ' ?,';
127
- }
128
- });
129
- // eslint-disable-next-line no-unused-vars
130
- usingClause = usingClause.slice(0, -1);
131
-
132
- // Build returning and into clauses
133
- outBinding[index].forEach(function (ret) {
134
- const columnName = ret.columnName || ret;
135
- returningClause += self.formatter.wrap(columnName) + ',';
136
- intoClause += ' ?,';
137
- outClause += ' out ?,';
138
-
139
- // Add Helpers to bindings
140
- if (ret instanceof BlobHelper) {
141
- return self.formatter.bindings.push(ret);
142
- }
143
- self.formatter.bindings.push(new ReturningHelper(columnName));
144
- });
145
-
146
- // Strip last comma
147
- returningClause = returningClause.slice(0, -1);
148
- intoClause = intoClause.slice(0, -1);
149
- outClause = outClause.slice(0, -1);
150
-
151
- if (returningClause && intoClause) {
152
- subSql += ' returning ' + returningClause + ' into' + intoClause;
153
- }
154
-
155
- // Pre bind position because subSql is an execute immediate parameter
156
- // later position binding will only convert the ? params
157
- subSql = self.formatter.client.positionBindings(subSql);
158
- const parameterizedValuesWithoutDefaultAndBlob = parameterizedValues
159
- .replace(/DEFAULT, /g, '')
160
- .replace(/, DEFAULT/g, '')
161
- .replace('EMPTY_BLOB(), ', '')
162
- .replace(', EMPTY_BLOB()', '');
163
- return (
164
- "execute immediate '" +
165
- subSql.replace(/'/g, "''") +
166
- (parameterizedValuesWithoutDefaultAndBlob || value
167
- ? "' using "
168
- : '') +
169
- parameterizedValuesWithoutDefaultAndBlob +
170
- (parameterizedValuesWithoutDefaultAndBlob && outClause ? ',' : '') +
171
- outClause +
172
- ';'
173
- );
174
- })
175
- .join(' ') +
176
- 'end;';
177
-
178
- sql.outBinding = outBinding;
179
- if (returning[0] === '*') {
180
- // Generate select statement with special order by
181
- // to keep the order because 'in (..)' may change the order
182
- sql.returningSql = function () {
183
- return (
184
- 'select * from ' +
185
- self.tableName +
186
- ' where ROWID in (' +
187
- this.outBinding
188
- .map(function (v, i) {
189
- return ':' + (i + 1);
190
- })
191
- .join(', ') +
192
- ')' +
193
- ' order by case ROWID ' +
194
- this.outBinding
195
- .map(function (v, i) {
196
- return 'when CHARTOROWID(:' + (i + 1) + ') then ' + i;
197
- })
198
- .join(' ') +
199
- ' end'
200
- );
201
- };
202
- }
203
-
204
- return sql;
205
- }
206
-
207
- with() {
208
- // WITH RECURSIVE is a syntax error in Oracle SQL.
209
- // So mark all statements as non-recursive, generate the SQL, then restore.
210
- // This approach ensures any changes in base class with() get propagated here.
211
- const undoList = [];
212
- if (this.grouped.with) {
213
- for (const stmt of this.grouped.with) {
214
- if (stmt.recursive) {
215
- undoList.push(stmt);
216
- stmt.recursive = false;
217
- }
218
- }
219
- }
220
-
221
- const result = super.with();
222
-
223
- // Restore the recursive markings, in case this same query gets cloned and passed to other drivers.
224
- for (const stmt of undoList) {
225
- stmt.recursive = true;
226
- }
227
- return result;
228
- }
229
-
230
- _addReturningToSqlAndConvert(sql, outBinding, tableName, returning) {
231
- const self = this;
232
- const res = {
233
- sql: sql,
234
- };
235
-
236
- if (!outBinding) {
237
- return res;
238
- }
239
- const returningValues = Array.isArray(outBinding)
240
- ? outBinding
241
- : [outBinding];
242
- let returningClause = '';
243
- let intoClause = '';
244
- // Build returning and into clauses
245
- returningValues.forEach(function (ret) {
246
- const columnName = ret.columnName || ret;
247
- returningClause += self.formatter.wrap(columnName) + ',';
248
- intoClause += '?,';
249
-
250
- // Add Helpers to bindings
251
- if (ret instanceof BlobHelper) {
252
- return self.formatter.bindings.push(ret);
253
- }
254
- self.formatter.bindings.push(new ReturningHelper(columnName));
255
- });
256
- res.sql = sql;
257
-
258
- // Strip last comma
259
- returningClause = returningClause.slice(0, -1);
260
- intoClause = intoClause.slice(0, -1);
261
- if (returningClause && intoClause) {
262
- res.sql += ' returning ' + returningClause + ' into ' + intoClause;
263
- }
264
- res.outBinding = [outBinding];
265
- if (returning[0] === '*') {
266
- res.returningSql = function () {
267
- return 'select * from ' + self.tableName + ' where ROWID = :1';
268
- };
269
- }
270
- res.returning = returning;
271
-
272
- return res;
273
- }
274
-
275
- _prepOutbindings(paramValues, paramReturning) {
276
- const result = {};
277
- let params = paramValues || [];
278
- let returning = paramReturning || [];
279
- if (!Array.isArray(params) && isPlainObject(paramValues)) {
280
- params = [params];
281
- }
282
- // Always wrap returning argument in array
283
- if (returning && !Array.isArray(returning)) {
284
- returning = [returning];
285
- }
286
-
287
- const outBinding = [];
288
- // Handle Buffer value as Blob
289
- each(params, function (values, index) {
290
- if (returning[0] === '*') {
291
- outBinding[index] = ['ROWID'];
292
- } else {
293
- outBinding[index] = clone(returning);
294
- }
295
- each(values, function (value, key) {
296
- if (value instanceof Buffer) {
297
- values[key] = new BlobHelper(key, value);
298
-
299
- // Delete blob duplicate in returning
300
- const blobIndex = outBinding[index].indexOf(key);
301
- if (blobIndex >= 0) {
302
- outBinding[index].splice(blobIndex, 1);
303
- values[key].returning = true;
304
- }
305
- outBinding[index].push(values[key]);
306
- }
307
- if (value === undefined) {
308
- delete params[index][key];
309
- }
310
- });
311
- });
312
- result.returning = returning;
313
- result.outBinding = outBinding;
314
- result.values = params;
315
- return result;
316
- }
317
-
318
- _groupOrder(item, type) {
319
- return super._groupOrderNulls(item, type);
320
- }
321
-
322
- update() {
323
- const self = this;
324
- const sql = {};
325
- const outBindPrep = this._prepOutbindings(
326
- this.single.update || this.single.counter,
327
- this.single.returning
328
- );
329
- const outBinding = outBindPrep.outBinding;
330
- const returning = outBindPrep.returning;
331
-
332
- const updates = this._prepUpdate(this.single.update);
333
- const where = this.where();
334
-
335
- let returningClause = '';
336
- let intoClause = '';
337
-
338
- if (isEmpty(updates) && typeof this.single.update !== 'function') {
339
- return '';
340
- }
341
-
342
- // Build returning and into clauses
343
- outBinding.forEach(function (out) {
344
- out.forEach(function (ret) {
345
- const columnName = ret.columnName || ret;
346
- returningClause += self.formatter.wrap(columnName) + ',';
347
- intoClause += ' ?,';
348
-
349
- // Add Helpers to bindings
350
- if (ret instanceof BlobHelper) {
351
- return self.formatter.bindings.push(ret);
352
- }
353
- self.formatter.bindings.push(new ReturningHelper(columnName));
354
- });
355
- });
356
- // Strip last comma
357
- returningClause = returningClause.slice(0, -1);
358
- intoClause = intoClause.slice(0, -1);
359
-
360
- sql.outBinding = outBinding;
361
- sql.returning = returning;
362
- sql.sql =
363
- 'update ' +
364
- this.tableName +
365
- ' set ' +
366
- updates.join(', ') +
367
- (where ? ' ' + where : '');
368
- if (outBinding.length && !isEmpty(outBinding[0])) {
369
- sql.sql += ' returning ' + returningClause + ' into' + intoClause;
370
- }
371
- if (returning[0] === '*') {
372
- sql.returningSql = function () {
373
- let sql = 'select * from ' + self.tableName;
374
- const modifiedRowsCount = this.rowsAffected.length || this.rowsAffected;
375
- let returningSqlIn = ' where ROWID in (';
376
- let returningSqlOrderBy = ') order by case ROWID ';
377
-
378
- // Needs special order by because in(...) change result order
379
- for (let i = 0; i < modifiedRowsCount; i++) {
380
- if (this.returning[0] === '*') {
381
- returningSqlIn += ':' + (i + 1) + ', ';
382
- returningSqlOrderBy +=
383
- 'when CHARTOROWID(:' + (i + 1) + ') then ' + i + ' ';
384
- }
385
- }
386
- if (this.returning[0] === '*') {
387
- this.returning = this.returning.slice(0, -1);
388
- returningSqlIn = returningSqlIn.slice(0, -2);
389
- returningSqlOrderBy = returningSqlOrderBy.slice(0, -1);
390
- }
391
- return (sql += returningSqlIn + returningSqlOrderBy + ' end');
392
- };
393
- }
394
-
395
- return sql;
396
- }
397
-
398
- _jsonPathWrap(extraction) {
399
- return `'${extraction.path || extraction[1]}'`;
400
- }
401
-
402
- // Json functions
403
- jsonExtract(params) {
404
- return this._jsonExtract(
405
- params.singleValue ? 'json_value' : 'json_query',
406
- params
407
- );
408
- }
409
-
410
- jsonSet(params) {
411
- return `json_transform(${columnize_(
412
- params.column,
413
- this.builder,
414
- this.client,
415
- this.bindingsHolder
416
- )}, set ${this.client.parameter(
417
- params.path,
418
- this.builder,
419
- this.bindingsHolder
420
- )} = ${this.client.parameter(
421
- params.value,
422
- this.builder,
423
- this.bindingsHolder
424
- )})`;
425
- }
426
-
427
- jsonInsert(params) {
428
- return `json_transform(${columnize_(
429
- params.column,
430
- this.builder,
431
- this.client,
432
- this.bindingsHolder
433
- )}, insert ${this.client.parameter(
434
- params.path,
435
- this.builder,
436
- this.bindingsHolder
437
- )} = ${this.client.parameter(
438
- params.value,
439
- this.builder,
440
- this.bindingsHolder
441
- )})`;
442
- }
443
-
444
- jsonRemove(params) {
445
- const jsonCol = `json_transform(${columnize_(
446
- params.column,
447
- this.builder,
448
- this.client,
449
- this.bindingsHolder
450
- )}, remove ${this.client.parameter(
451
- params.path,
452
- this.builder,
453
- this.bindingsHolder
454
- )})`;
455
- return params.alias
456
- ? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
457
- : jsonCol;
458
- }
459
-
460
- whereJsonPath(statement) {
461
- return this._whereJsonPath('json_value', statement);
462
- }
463
-
464
- whereJsonSupersetOf(statement) {
465
- throw new Error(
466
- 'Json superset where clause not actually supported by Oracle'
467
- );
468
- }
469
-
470
- whereJsonSubsetOf(statement) {
471
- throw new Error(
472
- 'Json subset where clause not actually supported by Oracle'
473
- );
474
- }
475
-
476
- onJsonPathEquals(clause) {
477
- return this._onJsonPathEquals('json_value', clause);
478
- }
479
- }
480
-
481
- module.exports = Oracledb_Compiler;
1
+ const clone = require('lodash/clone');
2
+ const each = require('lodash/each');
3
+ const isEmpty = require('lodash/isEmpty');
4
+ const isPlainObject = require('lodash/isPlainObject');
5
+ const Oracle_Compiler = require('../../oracle/query/oracle-querycompiler');
6
+ const ReturningHelper = require('../utils').ReturningHelper;
7
+ const BlobHelper = require('../utils').BlobHelper;
8
+ const { isString } = require('../../../util/is');
9
+ const {
10
+ columnize: columnize_,
11
+ } = require('../../../formatter/wrappingFormatter');
12
+
13
+ class Oracledb_Compiler extends Oracle_Compiler {
14
+ // Compiles an "insert" query, allowing for multiple
15
+ // inserts using a single query statement.
16
+ insert() {
17
+ const self = this;
18
+ const outBindPrep = this._prepOutbindings(
19
+ this.single.insert,
20
+ this.single.returning
21
+ );
22
+ const outBinding = outBindPrep.outBinding;
23
+ const returning = outBindPrep.returning;
24
+ const insertValues = outBindPrep.values;
25
+
26
+ if (
27
+ Array.isArray(insertValues) &&
28
+ insertValues.length === 1 &&
29
+ isEmpty(insertValues[0])
30
+ ) {
31
+ const returningFragment = this.single.returning
32
+ ? ' (' + this.formatter.wrap(this.single.returning) + ')'
33
+ : '';
34
+
35
+ return this._addReturningToSqlAndConvert(
36
+ 'insert into ' +
37
+ this.tableName +
38
+ returningFragment +
39
+ ' values (default)',
40
+ outBinding[0],
41
+ this.tableName,
42
+ returning
43
+ );
44
+ }
45
+
46
+ if (
47
+ isEmpty(this.single.insert) &&
48
+ typeof this.single.insert !== 'function'
49
+ ) {
50
+ return '';
51
+ }
52
+
53
+ const insertData = this._prepInsert(insertValues);
54
+
55
+ const sql = {};
56
+
57
+ if (isString(insertData)) {
58
+ return this._addReturningToSqlAndConvert(
59
+ 'insert into ' + this.tableName + ' ' + insertData,
60
+ outBinding[0],
61
+ this.tableName,
62
+ returning
63
+ );
64
+ }
65
+
66
+ if (insertData.values.length === 1) {
67
+ return this._addReturningToSqlAndConvert(
68
+ 'insert into ' +
69
+ this.tableName +
70
+ ' (' +
71
+ this.formatter.columnize(insertData.columns) +
72
+ ') values (' +
73
+ this.client.parameterize(
74
+ insertData.values[0],
75
+ undefined,
76
+ this.builder,
77
+ this.bindingsHolder
78
+ ) +
79
+ ')',
80
+ outBinding[0],
81
+ this.tableName,
82
+ returning
83
+ );
84
+ }
85
+
86
+ const insertDefaultsOnly = insertData.columns.length === 0;
87
+ sql.returning = returning;
88
+ sql.sql =
89
+ 'begin ' +
90
+ insertData.values
91
+ .map(function (value, index) {
92
+ const parameterizedValues = !insertDefaultsOnly
93
+ ? self.client.parameterize(
94
+ value,
95
+ self.client.valueForUndefined,
96
+ self.builder,
97
+ self.bindingsHolder
98
+ )
99
+ : '';
100
+ let subSql = 'insert into ' + self.tableName;
101
+
102
+ if (insertDefaultsOnly) {
103
+ // No columns given so only the default value
104
+ subSql +=
105
+ ' (' +
106
+ self.formatter.wrap(self.single.returning) +
107
+ ') values (default)';
108
+ } else {
109
+ subSql +=
110
+ ' (' +
111
+ self.formatter.columnize(insertData.columns) +
112
+ ') values (' +
113
+ parameterizedValues +
114
+ ')';
115
+ }
116
+
117
+ let returningClause = '';
118
+ let intoClause = '';
119
+ // ToDo review if this code is still needed or could be dropped
120
+ // eslint-disable-next-line no-unused-vars
121
+ let usingClause = '';
122
+ let outClause = '';
123
+
124
+ each(value, function (val) {
125
+ if (!(val instanceof BlobHelper)) {
126
+ usingClause += ' ?,';
127
+ }
128
+ });
129
+ // eslint-disable-next-line no-unused-vars
130
+ usingClause = usingClause.slice(0, -1);
131
+
132
+ // Build returning and into clauses
133
+ outBinding[index].forEach(function (ret) {
134
+ const columnName = ret.columnName || ret;
135
+ returningClause += self.formatter.wrap(columnName) + ',';
136
+ intoClause += ' ?,';
137
+ outClause += ' out ?,';
138
+
139
+ // Add Helpers to bindings
140
+ if (ret instanceof BlobHelper) {
141
+ return self.formatter.bindings.push(ret);
142
+ }
143
+ self.formatter.bindings.push(new ReturningHelper(columnName));
144
+ });
145
+
146
+ // Strip last comma
147
+ returningClause = returningClause.slice(0, -1);
148
+ intoClause = intoClause.slice(0, -1);
149
+ outClause = outClause.slice(0, -1);
150
+
151
+ if (returningClause && intoClause) {
152
+ subSql += ' returning ' + returningClause + ' into' + intoClause;
153
+ }
154
+
155
+ // Pre bind position because subSql is an execute immediate parameter
156
+ // later position binding will only convert the ? params
157
+ subSql = self.formatter.client.positionBindings(subSql);
158
+ const parameterizedValuesWithoutDefaultAndBlob = parameterizedValues
159
+ .replace(/DEFAULT, /g, '')
160
+ .replace(/, DEFAULT/g, '')
161
+ .replace('EMPTY_BLOB(), ', '')
162
+ .replace(', EMPTY_BLOB()', '');
163
+ return (
164
+ "execute immediate '" +
165
+ subSql.replace(/'/g, "''") +
166
+ (parameterizedValuesWithoutDefaultAndBlob || value
167
+ ? "' using "
168
+ : '') +
169
+ parameterizedValuesWithoutDefaultAndBlob +
170
+ (parameterizedValuesWithoutDefaultAndBlob && outClause ? ',' : '') +
171
+ outClause +
172
+ ';'
173
+ );
174
+ })
175
+ .join(' ') +
176
+ 'end;';
177
+
178
+ sql.outBinding = outBinding;
179
+ if (returning[0] === '*') {
180
+ // Generate select statement with special order by
181
+ // to keep the order because 'in (..)' may change the order
182
+ sql.returningSql = function () {
183
+ return (
184
+ 'select * from ' +
185
+ self.tableName +
186
+ ' where ROWID in (' +
187
+ this.outBinding
188
+ .map(function (v, i) {
189
+ return ':' + (i + 1);
190
+ })
191
+ .join(', ') +
192
+ ')' +
193
+ ' order by case ROWID ' +
194
+ this.outBinding
195
+ .map(function (v, i) {
196
+ return 'when CHARTOROWID(:' + (i + 1) + ') then ' + i;
197
+ })
198
+ .join(' ') +
199
+ ' end'
200
+ );
201
+ };
202
+ }
203
+
204
+ return sql;
205
+ }
206
+
207
+ with() {
208
+ // WITH RECURSIVE is a syntax error in Oracle SQL.
209
+ // So mark all statements as non-recursive, generate the SQL, then restore.
210
+ // This approach ensures any changes in base class with() get propagated here.
211
+ const undoList = [];
212
+ if (this.grouped.with) {
213
+ for (const stmt of this.grouped.with) {
214
+ if (stmt.recursive) {
215
+ undoList.push(stmt);
216
+ stmt.recursive = false;
217
+ }
218
+ }
219
+ }
220
+
221
+ const result = super.with();
222
+
223
+ // Restore the recursive markings, in case this same query gets cloned and passed to other drivers.
224
+ for (const stmt of undoList) {
225
+ stmt.recursive = true;
226
+ }
227
+ return result;
228
+ }
229
+
230
+ _addReturningToSqlAndConvert(sql, outBinding, tableName, returning) {
231
+ const self = this;
232
+ const res = {
233
+ sql: sql,
234
+ };
235
+
236
+ if (!outBinding) {
237
+ return res;
238
+ }
239
+ const returningValues = Array.isArray(outBinding)
240
+ ? outBinding
241
+ : [outBinding];
242
+ let returningClause = '';
243
+ let intoClause = '';
244
+ // Build returning and into clauses
245
+ returningValues.forEach(function (ret) {
246
+ const columnName = ret.columnName || ret;
247
+ returningClause += self.formatter.wrap(columnName) + ',';
248
+ intoClause += '?,';
249
+
250
+ // Add Helpers to bindings
251
+ if (ret instanceof BlobHelper) {
252
+ return self.formatter.bindings.push(ret);
253
+ }
254
+ self.formatter.bindings.push(new ReturningHelper(columnName));
255
+ });
256
+ res.sql = sql;
257
+
258
+ // Strip last comma
259
+ returningClause = returningClause.slice(0, -1);
260
+ intoClause = intoClause.slice(0, -1);
261
+ if (returningClause && intoClause) {
262
+ res.sql += ' returning ' + returningClause + ' into ' + intoClause;
263
+ }
264
+ res.outBinding = [outBinding];
265
+ if (returning[0] === '*') {
266
+ res.returningSql = function () {
267
+ return 'select * from ' + self.tableName + ' where ROWID = :1';
268
+ };
269
+ }
270
+ res.returning = returning;
271
+
272
+ return res;
273
+ }
274
+
275
+ _prepOutbindings(paramValues, paramReturning) {
276
+ const result = {};
277
+ let params = paramValues || [];
278
+ let returning = paramReturning || [];
279
+ if (!Array.isArray(params) && isPlainObject(paramValues)) {
280
+ params = [params];
281
+ }
282
+ // Always wrap returning argument in array
283
+ if (returning && !Array.isArray(returning)) {
284
+ returning = [returning];
285
+ }
286
+
287
+ const outBinding = [];
288
+ // Handle Buffer value as Blob
289
+ each(params, function (values, index) {
290
+ if (returning[0] === '*') {
291
+ outBinding[index] = ['ROWID'];
292
+ } else {
293
+ outBinding[index] = clone(returning);
294
+ }
295
+ each(values, function (value, key) {
296
+ if (value instanceof Buffer) {
297
+ values[key] = new BlobHelper(key, value);
298
+
299
+ // Delete blob duplicate in returning
300
+ const blobIndex = outBinding[index].indexOf(key);
301
+ if (blobIndex >= 0) {
302
+ outBinding[index].splice(blobIndex, 1);
303
+ values[key].returning = true;
304
+ }
305
+ outBinding[index].push(values[key]);
306
+ }
307
+ if (value === undefined) {
308
+ delete params[index][key];
309
+ }
310
+ });
311
+ });
312
+ result.returning = returning;
313
+ result.outBinding = outBinding;
314
+ result.values = params;
315
+ return result;
316
+ }
317
+
318
+ _groupOrder(item, type) {
319
+ return super._groupOrderNulls(item, type);
320
+ }
321
+
322
+ update() {
323
+ const self = this;
324
+ const sql = {};
325
+ const outBindPrep = this._prepOutbindings(
326
+ this.single.update || this.single.counter,
327
+ this.single.returning
328
+ );
329
+ const outBinding = outBindPrep.outBinding;
330
+ const returning = outBindPrep.returning;
331
+
332
+ const updates = this._prepUpdate(this.single.update);
333
+ const where = this.where();
334
+
335
+ let returningClause = '';
336
+ let intoClause = '';
337
+
338
+ if (isEmpty(updates) && typeof this.single.update !== 'function') {
339
+ return '';
340
+ }
341
+
342
+ // Build returning and into clauses
343
+ outBinding.forEach(function (out) {
344
+ out.forEach(function (ret) {
345
+ const columnName = ret.columnName || ret;
346
+ returningClause += self.formatter.wrap(columnName) + ',';
347
+ intoClause += ' ?,';
348
+
349
+ // Add Helpers to bindings
350
+ if (ret instanceof BlobHelper) {
351
+ return self.formatter.bindings.push(ret);
352
+ }
353
+ self.formatter.bindings.push(new ReturningHelper(columnName));
354
+ });
355
+ });
356
+ // Strip last comma
357
+ returningClause = returningClause.slice(0, -1);
358
+ intoClause = intoClause.slice(0, -1);
359
+
360
+ sql.outBinding = outBinding;
361
+ sql.returning = returning;
362
+ sql.sql =
363
+ 'update ' +
364
+ this.tableName +
365
+ ' set ' +
366
+ updates.join(', ') +
367
+ (where ? ' ' + where : '');
368
+ if (outBinding.length && !isEmpty(outBinding[0])) {
369
+ sql.sql += ' returning ' + returningClause + ' into' + intoClause;
370
+ }
371
+ if (returning[0] === '*') {
372
+ sql.returningSql = function () {
373
+ let sql = 'select * from ' + self.tableName;
374
+ const modifiedRowsCount = this.rowsAffected.length || this.rowsAffected;
375
+ let returningSqlIn = ' where ROWID in (';
376
+ let returningSqlOrderBy = ') order by case ROWID ';
377
+
378
+ // Needs special order by because in(...) change result order
379
+ for (let i = 0; i < modifiedRowsCount; i++) {
380
+ if (this.returning[0] === '*') {
381
+ returningSqlIn += ':' + (i + 1) + ', ';
382
+ returningSqlOrderBy +=
383
+ 'when CHARTOROWID(:' + (i + 1) + ') then ' + i + ' ';
384
+ }
385
+ }
386
+ if (this.returning[0] === '*') {
387
+ this.returning = this.returning.slice(0, -1);
388
+ returningSqlIn = returningSqlIn.slice(0, -2);
389
+ returningSqlOrderBy = returningSqlOrderBy.slice(0, -1);
390
+ }
391
+ return (sql += returningSqlIn + returningSqlOrderBy + ' end');
392
+ };
393
+ }
394
+
395
+ return sql;
396
+ }
397
+
398
+ _jsonPathWrap(extraction) {
399
+ return `'${extraction.path || extraction[1]}'`;
400
+ }
401
+
402
+ // Json functions
403
+ jsonExtract(params) {
404
+ return this._jsonExtract(
405
+ params.singleValue ? 'json_value' : 'json_query',
406
+ params
407
+ );
408
+ }
409
+
410
+ jsonSet(params) {
411
+ return `json_transform(${columnize_(
412
+ params.column,
413
+ this.builder,
414
+ this.client,
415
+ this.bindingsHolder
416
+ )}, set ${this.client.parameter(
417
+ params.path,
418
+ this.builder,
419
+ this.bindingsHolder
420
+ )} = ${this.client.parameter(
421
+ params.value,
422
+ this.builder,
423
+ this.bindingsHolder
424
+ )})`;
425
+ }
426
+
427
+ jsonInsert(params) {
428
+ return `json_transform(${columnize_(
429
+ params.column,
430
+ this.builder,
431
+ this.client,
432
+ this.bindingsHolder
433
+ )}, insert ${this.client.parameter(
434
+ params.path,
435
+ this.builder,
436
+ this.bindingsHolder
437
+ )} = ${this.client.parameter(
438
+ params.value,
439
+ this.builder,
440
+ this.bindingsHolder
441
+ )})`;
442
+ }
443
+
444
+ jsonRemove(params) {
445
+ const jsonCol = `json_transform(${columnize_(
446
+ params.column,
447
+ this.builder,
448
+ this.client,
449
+ this.bindingsHolder
450
+ )}, remove ${this.client.parameter(
451
+ params.path,
452
+ this.builder,
453
+ this.bindingsHolder
454
+ )})`;
455
+ return params.alias
456
+ ? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
457
+ : jsonCol;
458
+ }
459
+
460
+ whereJsonPath(statement) {
461
+ return this._whereJsonPath('json_value', statement);
462
+ }
463
+
464
+ whereJsonSupersetOf(statement) {
465
+ throw new Error(
466
+ 'Json superset where clause not actually supported by Oracle'
467
+ );
468
+ }
469
+
470
+ whereJsonSubsetOf(statement) {
471
+ throw new Error(
472
+ 'Json subset where clause not actually supported by Oracle'
473
+ );
474
+ }
475
+
476
+ onJsonPathEquals(clause) {
477
+ return this._onJsonPathEquals('json_value', clause);
478
+ }
479
+ }
480
+
481
+ module.exports = Oracledb_Compiler;