knex 2.4.1 → 2.4.2

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 (187) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +148 -148
  5. package/UPGRADING.md +233 -233
  6. package/bin/cli.js +473 -472
  7. package/bin/utils/cli-config-utils.js +210 -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/lib/builder-interface-augmenter.js +120 -120
  12. package/lib/client.js +475 -475
  13. package/lib/constants.js +61 -61
  14. package/lib/dialects/better-sqlite3/index.js +72 -72
  15. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  16. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  17. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  18. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  19. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  20. package/lib/dialects/cockroachdb/index.js +86 -86
  21. package/lib/dialects/mssql/index.js +495 -495
  22. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  23. package/lib/dialects/mssql/query/mssql-querycompiler.js +600 -600
  24. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  25. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  26. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  27. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  28. package/lib/dialects/mssql/transaction.js +176 -176
  29. package/lib/dialects/mysql/index.js +201 -201
  30. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  31. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  32. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  33. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  34. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  35. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  36. package/lib/dialects/mysql/transaction.js +46 -46
  37. package/lib/dialects/mysql2/index.js +33 -33
  38. package/lib/dialects/mysql2/transaction.js +44 -44
  39. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  40. package/lib/dialects/oracle/index.js +92 -92
  41. package/lib/dialects/oracle/query/oracle-querycompiler.js +342 -342
  42. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  43. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  44. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  45. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  46. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  47. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  48. package/lib/dialects/oracle/utils.js +87 -87
  49. package/lib/dialects/oracledb/index.js +327 -327
  50. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  51. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +55 -55
  52. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  53. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  54. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  55. package/lib/dialects/oracledb/transaction.js +98 -98
  56. package/lib/dialects/oracledb/utils.js +208 -208
  57. package/lib/dialects/pgnative/index.js +60 -60
  58. package/lib/dialects/postgres/execution/pg-transaction.js +12 -12
  59. package/lib/dialects/postgres/index.js +358 -358
  60. package/lib/dialects/postgres/query/pg-querybuilder.js +38 -38
  61. package/lib/dialects/postgres/query/pg-querycompiler.js +395 -395
  62. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  63. package/lib/dialects/postgres/schema/pg-compiler.js +138 -136
  64. package/lib/dialects/postgres/schema/pg-tablecompiler.js +299 -299
  65. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  66. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  67. package/lib/dialects/redshift/index.js +86 -86
  68. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  69. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  70. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  71. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  72. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  73. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  74. package/lib/dialects/redshift/transaction.js +25 -25
  75. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +18 -18
  76. package/lib/dialects/sqlite3/index.js +250 -250
  77. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  78. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  79. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  80. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  81. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  82. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  83. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  84. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  85. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  86. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  87. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  88. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  89. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  90. package/lib/execution/batch-insert.js +51 -51
  91. package/lib/execution/internal/delay.js +6 -6
  92. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  93. package/lib/execution/internal/query-executioner.js +62 -62
  94. package/lib/execution/runner.js +307 -307
  95. package/lib/execution/transaction.js +401 -401
  96. package/lib/formatter/formatterUtils.js +42 -42
  97. package/lib/formatter/rawFormatter.js +84 -84
  98. package/lib/formatter/wrappingFormatter.js +250 -250
  99. package/lib/formatter.js +25 -25
  100. package/lib/index.js +3 -3
  101. package/lib/knex-builder/FunctionHelper.js +54 -54
  102. package/lib/knex-builder/Knex.js +59 -59
  103. package/lib/knex-builder/internal/config-resolver.js +57 -57
  104. package/lib/knex-builder/internal/parse-connection.js +87 -87
  105. package/lib/knex-builder/make-knex.js +340 -340
  106. package/lib/logger.js +76 -76
  107. package/lib/migrations/common/MigrationsLoader.js +36 -36
  108. package/lib/migrations/migrate/MigrationGenerator.js +84 -82
  109. package/lib/migrations/migrate/Migrator.js +598 -598
  110. package/lib/migrations/migrate/migrate-stub.js +17 -17
  111. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  112. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  113. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  114. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  115. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  116. package/lib/migrations/migrate/stub/eg.stub +14 -14
  117. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  118. package/lib/migrations/migrate/stub/js.stub +22 -22
  119. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  120. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  121. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  122. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  123. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  124. package/lib/migrations/migrate/stub/ls.stub +14 -14
  125. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  126. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  127. package/lib/migrations/migrate/stub/ts.stub +21 -21
  128. package/lib/migrations/migrate/table-creator.js +77 -77
  129. package/lib/migrations/migrate/table-resolver.js +27 -27
  130. package/lib/migrations/seed/Seeder.js +137 -137
  131. package/lib/migrations/seed/seed-stub.js +13 -13
  132. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  133. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  134. package/lib/migrations/seed/stub/coffee.stub +9 -9
  135. package/lib/migrations/seed/stub/eg.stub +11 -11
  136. package/lib/migrations/seed/stub/js.stub +13 -13
  137. package/lib/migrations/seed/stub/ls.stub +11 -11
  138. package/lib/migrations/seed/stub/mjs.stub +12 -12
  139. package/lib/migrations/seed/stub/ts.stub +13 -13
  140. package/lib/migrations/util/fs.js +86 -86
  141. package/lib/migrations/util/import-file.js +12 -12
  142. package/lib/migrations/util/is-module-type.js +9 -9
  143. package/lib/migrations/util/template.js +52 -52
  144. package/lib/migrations/util/timestamp.js +14 -14
  145. package/lib/query/analytic.js +52 -52
  146. package/lib/query/constants.js +15 -15
  147. package/lib/query/joinclause.js +270 -270
  148. package/lib/query/method-constants.js +135 -135
  149. package/lib/query/querybuilder.js +1794 -1794
  150. package/lib/query/querycompiler.js +1580 -1580
  151. package/lib/raw.js +139 -139
  152. package/lib/ref.js +39 -39
  153. package/lib/schema/builder.js +115 -114
  154. package/lib/schema/columnbuilder.js +146 -145
  155. package/lib/schema/columncompiler.js +307 -307
  156. package/lib/schema/compiler.js +187 -187
  157. package/lib/schema/internal/helpers.js +55 -55
  158. package/lib/schema/tablebuilder.js +376 -375
  159. package/lib/schema/tablecompiler.js +433 -433
  160. package/lib/schema/viewbuilder.js +92 -93
  161. package/lib/schema/viewcompiler.js +138 -138
  162. package/lib/util/finally-mixin.js +13 -13
  163. package/lib/util/helpers.js +95 -95
  164. package/lib/util/is.js +32 -32
  165. package/lib/util/nanoid.js +40 -40
  166. package/lib/util/noop.js +1 -1
  167. package/lib/util/save-async-stack.js +14 -14
  168. package/lib/util/string.js +190 -190
  169. package/lib/util/timeout.js +29 -29
  170. package/package.json +8 -6
  171. package/scripts/build.js +125 -125
  172. package/scripts/clean.js +31 -29
  173. package/scripts/docker-compose.yml +152 -152
  174. package/scripts/next-release-howto.md +24 -24
  175. package/scripts/oracledb-install-driver-libs.sh +82 -82
  176. package/scripts/release.sh +34 -34
  177. package/scripts/runkit-example.js +34 -34
  178. package/scripts/stress-test/README.txt +18 -18
  179. package/scripts/stress-test/docker-compose.yml +57 -57
  180. package/scripts/stress-test/knex-stress-test.js +208 -208
  181. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  182. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  183. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  184. package/scripts/update_gitignore_for_tsc_output.js +90 -86
  185. package/types/index.d.ts +3233 -3233
  186. package/types/result.d.ts +27 -27
  187. 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;