knex 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/CHANGELOG.md +78 -59
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +149 -147
  5. package/UPGRADING.md +245 -233
  6. package/bin/cli.js +475 -473
  7. package/bin/utils/cli-config-utils.js +212 -210
  8. package/bin/utils/constants.js +7 -7
  9. package/bin/utils/migrationsLister.js +37 -37
  10. package/knex.js +23 -23
  11. package/knex.mjs +11 -11
  12. package/lib/builder-interface-augmenter.js +120 -120
  13. package/lib/client.js +495 -495
  14. package/lib/constants.js +61 -61
  15. package/lib/dialects/better-sqlite3/index.js +77 -77
  16. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  17. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  18. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  19. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  20. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  21. package/lib/dialects/cockroachdb/index.js +86 -86
  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 +599 -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/stub/cjs.stub +15 -15
  116. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  117. package/lib/migrations/migrate/stub/eg.stub +14 -14
  118. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  119. package/lib/migrations/migrate/stub/js.stub +22 -22
  120. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  121. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  122. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  123. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  124. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  125. package/lib/migrations/migrate/stub/ls.stub +14 -14
  126. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  127. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  128. package/lib/migrations/migrate/stub/ts.stub +21 -21
  129. package/lib/migrations/migrate/table-creator.js +77 -77
  130. package/lib/migrations/migrate/table-resolver.js +27 -27
  131. package/lib/migrations/seed/Seeder.js +137 -137
  132. package/lib/migrations/seed/seed-stub.js +13 -13
  133. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  134. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  135. package/lib/migrations/seed/stub/coffee.stub +9 -9
  136. package/lib/migrations/seed/stub/eg.stub +11 -11
  137. package/lib/migrations/seed/stub/js.stub +13 -13
  138. package/lib/migrations/seed/stub/ls.stub +11 -11
  139. package/lib/migrations/seed/stub/mjs.stub +12 -12
  140. package/lib/migrations/seed/stub/ts.stub +13 -13
  141. package/lib/migrations/util/fs.js +86 -86
  142. package/lib/migrations/util/import-file.js +12 -12
  143. package/lib/migrations/util/is-module-type.js +9 -9
  144. package/lib/migrations/util/template.js +52 -52
  145. package/lib/migrations/util/timestamp.js +14 -14
  146. package/lib/query/analytic.js +52 -52
  147. package/lib/query/constants.js +15 -15
  148. package/lib/query/joinclause.js +270 -270
  149. package/lib/query/method-constants.js +136 -136
  150. package/lib/query/querybuilder.js +1793 -1793
  151. package/lib/query/querycompiler.js +1591 -1591
  152. package/lib/raw.js +139 -139
  153. package/lib/ref.js +39 -39
  154. package/lib/schema/builder.js +115 -115
  155. package/lib/schema/columnbuilder.js +146 -146
  156. package/lib/schema/columncompiler.js +307 -307
  157. package/lib/schema/compiler.js +187 -187
  158. package/lib/schema/internal/helpers.js +55 -55
  159. package/lib/schema/tablebuilder.js +376 -376
  160. package/lib/schema/tablecompiler.js +433 -433
  161. package/lib/schema/viewbuilder.js +92 -92
  162. package/lib/schema/viewcompiler.js +138 -138
  163. package/lib/util/finally-mixin.js +13 -13
  164. package/lib/util/helpers.js +95 -95
  165. package/lib/util/is.js +32 -32
  166. package/lib/util/nanoid.js +40 -40
  167. package/lib/util/noop.js +1 -1
  168. package/lib/util/save-async-stack.js +14 -14
  169. package/lib/util/security.js +26 -26
  170. package/lib/util/string.js +190 -190
  171. package/lib/util/timeout.js +29 -29
  172. package/package.json +13 -12
  173. package/scripts/build.js +125 -125
  174. package/scripts/clean.js +31 -31
  175. package/scripts/docker-compose.yml +152 -152
  176. package/scripts/next-release-howto.md +24 -24
  177. package/scripts/oracledb-install-driver-libs.sh +82 -82
  178. package/scripts/release.sh +36 -34
  179. package/scripts/runkit-example.js +35 -34
  180. package/scripts/stress-test/README.txt +18 -18
  181. package/scripts/stress-test/docker-compose.yml +57 -57
  182. package/scripts/stress-test/knex-stress-test.js +212 -208
  183. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -145
  184. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -100
  185. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -184
  186. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  187. package/types/index.d.ts +3272 -3273
  188. package/types/result.d.ts +27 -27
  189. package/types/tables.d.ts +4 -4
  190. package/lib/dialects/index.js +0 -34
@@ -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;