knex 3.2.2 → 3.2.4

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 +156 -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 +294 -296
  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 +11 -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,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;