knex 3.1.0 → 3.2.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 (199) hide show
  1. package/CHANGELOG.md +2441 -2380
  2. package/CONTRIBUTING.md +190 -194
  3. package/LICENSE +22 -22
  4. package/README.md +156 -149
  5. package/UPGRADING.md +245 -245
  6. package/bin/cli.js +516 -475
  7. package/bin/knexfile-runtime-error.js +27 -0
  8. package/bin/utils/cli-config-utils.js +217 -212
  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 -495
  15. package/lib/constants.js +61 -61
  16. package/lib/dialects/better-sqlite3/index.js +101 -77
  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 -37
  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 -500
  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 -378
  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 -206
  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 -405
  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 -197
  52. package/lib/dialects/oracle/utils.js +107 -106
  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 -361
  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 -156
  67. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  68. package/lib/dialects/postgres/schema/pg-tablecompiler.js +331 -304
  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 -122
  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 -25
  80. package/lib/dialects/sqlite3/index.js +263 -250
  81. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  82. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +341 -334
  83. package/lib/dialects/sqlite3/schema/ddl.js +380 -400
  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 -347
  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 -413
  100. package/lib/formatter/formatterUtils.js +42 -42
  101. package/lib/formatter/rawFormatter.js +84 -84
  102. package/lib/formatter/wrappingFormatter.js +253 -250
  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 -599
  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 -1591
  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 -376
  163. package/lib/schema/tablecompiler.js +450 -439
  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 -26
  173. package/lib/util/string.js +190 -190
  174. package/lib/util/timeout.js +29 -29
  175. package/package.json +291 -267
  176. package/scripts/act-testing/act.sh +19 -0
  177. package/scripts/act-testing/merged-no-label.json +11 -0
  178. package/scripts/act-testing/merged-patch-labeled.json +12 -0
  179. package/scripts/act-testing/merged-skip-labeled.json +12 -0
  180. package/scripts/act-testing/not-merged-patch-labeled.json +12 -0
  181. package/scripts/build-for-release.sh +122 -0
  182. package/scripts/build.js +125 -125
  183. package/scripts/clean.js +31 -31
  184. package/scripts/docker-compose.yml +150 -152
  185. package/scripts/format-changelog.js +55 -0
  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 -57
  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.ts +3321 -3275
  197. package/types/result.d.ts +27 -27
  198. package/types/tables.d.ts +4 -4
  199. package/scripts/update_gitignore_for_tsc_output.js +0 -90
@@ -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;