knex 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/CHANGELOG.md +78 -59
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +149 -147
  5. package/UPGRADING.md +245 -233
  6. package/bin/cli.js +475 -473
  7. package/bin/utils/cli-config-utils.js +212 -210
  8. package/bin/utils/constants.js +7 -7
  9. package/bin/utils/migrationsLister.js +37 -37
  10. package/knex.js +23 -23
  11. package/knex.mjs +11 -11
  12. package/lib/builder-interface-augmenter.js +120 -120
  13. package/lib/client.js +495 -495
  14. package/lib/constants.js +61 -61
  15. package/lib/dialects/better-sqlite3/index.js +77 -77
  16. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  17. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  18. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  19. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  20. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  21. package/lib/dialects/cockroachdb/index.js +86 -86
  22. package/lib/dialects/mssql/index.js +500 -500
  23. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  24. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
  25. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  26. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  27. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  28. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  29. package/lib/dialects/mssql/transaction.js +176 -176
  30. package/lib/dialects/mysql/index.js +201 -201
  31. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  32. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  33. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  34. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  35. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  36. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  37. package/lib/dialects/mysql/transaction.js +46 -46
  38. package/lib/dialects/mysql2/index.js +53 -53
  39. package/lib/dialects/mysql2/transaction.js +44 -44
  40. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  41. package/lib/dialects/oracle/index.js +92 -92
  42. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
  43. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  44. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  45. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  46. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  47. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  48. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  49. package/lib/dialects/oracle/utils.js +87 -87
  50. package/lib/dialects/oracledb/index.js +327 -327
  51. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  52. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
  53. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  54. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  55. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  56. package/lib/dialects/oracledb/transaction.js +98 -98
  57. package/lib/dialects/oracledb/utils.js +208 -208
  58. package/lib/dialects/pgnative/index.js +60 -60
  59. package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
  60. package/lib/dialects/postgres/index.js +358 -358
  61. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
  62. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
  63. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  64. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  65. package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -304
  66. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  67. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  68. package/lib/dialects/redshift/index.js +86 -86
  69. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  70. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  71. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  72. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  73. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  74. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  75. package/lib/dialects/redshift/transaction.js +32 -32
  76. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -25
  77. package/lib/dialects/sqlite3/index.js +250 -250
  78. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  79. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  80. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  81. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  82. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  83. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  84. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  85. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  86. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  87. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  88. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  89. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  90. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  91. package/lib/execution/batch-insert.js +51 -51
  92. package/lib/execution/internal/delay.js +6 -6
  93. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  94. package/lib/execution/internal/query-executioner.js +62 -62
  95. package/lib/execution/runner.js +325 -325
  96. package/lib/execution/transaction.js +409 -409
  97. package/lib/formatter/formatterUtils.js +42 -42
  98. package/lib/formatter/rawFormatter.js +84 -84
  99. package/lib/formatter/wrappingFormatter.js +250 -250
  100. package/lib/formatter.js +25 -25
  101. package/lib/index.js +3 -3
  102. package/lib/knex-builder/FunctionHelper.js +80 -80
  103. package/lib/knex-builder/Knex.js +59 -59
  104. package/lib/knex-builder/internal/config-resolver.js +57 -57
  105. package/lib/knex-builder/internal/parse-connection.js +87 -87
  106. package/lib/knex-builder/make-knex.js +345 -345
  107. package/lib/logger.js +76 -76
  108. package/lib/migrations/common/MigrationsLoader.js +36 -36
  109. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  110. package/lib/migrations/migrate/Migrator.js +599 -598
  111. package/lib/migrations/migrate/migrate-stub.js +17 -17
  112. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  113. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  114. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  115. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  116. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  117. package/lib/migrations/migrate/stub/eg.stub +14 -14
  118. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  119. package/lib/migrations/migrate/stub/js.stub +22 -22
  120. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  121. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  122. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  123. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  124. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  125. package/lib/migrations/migrate/stub/ls.stub +14 -14
  126. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  127. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  128. package/lib/migrations/migrate/stub/ts.stub +21 -21
  129. package/lib/migrations/migrate/table-creator.js +77 -77
  130. package/lib/migrations/migrate/table-resolver.js +27 -27
  131. package/lib/migrations/seed/Seeder.js +137 -137
  132. package/lib/migrations/seed/seed-stub.js +13 -13
  133. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  134. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  135. package/lib/migrations/seed/stub/coffee.stub +9 -9
  136. package/lib/migrations/seed/stub/eg.stub +11 -11
  137. package/lib/migrations/seed/stub/js.stub +13 -13
  138. package/lib/migrations/seed/stub/ls.stub +11 -11
  139. package/lib/migrations/seed/stub/mjs.stub +12 -12
  140. package/lib/migrations/seed/stub/ts.stub +13 -13
  141. package/lib/migrations/util/fs.js +86 -86
  142. package/lib/migrations/util/import-file.js +12 -12
  143. package/lib/migrations/util/is-module-type.js +9 -9
  144. package/lib/migrations/util/template.js +52 -52
  145. package/lib/migrations/util/timestamp.js +14 -14
  146. package/lib/query/analytic.js +52 -52
  147. package/lib/query/constants.js +15 -15
  148. package/lib/query/joinclause.js +270 -270
  149. package/lib/query/method-constants.js +136 -136
  150. package/lib/query/querybuilder.js +1793 -1793
  151. package/lib/query/querycompiler.js +1591 -1591
  152. package/lib/raw.js +139 -139
  153. package/lib/ref.js +39 -39
  154. package/lib/schema/builder.js +115 -115
  155. package/lib/schema/columnbuilder.js +146 -146
  156. package/lib/schema/columncompiler.js +307 -307
  157. package/lib/schema/compiler.js +187 -187
  158. package/lib/schema/internal/helpers.js +55 -55
  159. package/lib/schema/tablebuilder.js +376 -376
  160. package/lib/schema/tablecompiler.js +433 -433
  161. package/lib/schema/viewbuilder.js +92 -92
  162. package/lib/schema/viewcompiler.js +138 -138
  163. package/lib/util/finally-mixin.js +13 -13
  164. package/lib/util/helpers.js +95 -95
  165. package/lib/util/is.js +32 -32
  166. package/lib/util/nanoid.js +40 -40
  167. package/lib/util/noop.js +1 -1
  168. package/lib/util/save-async-stack.js +14 -14
  169. package/lib/util/security.js +26 -26
  170. package/lib/util/string.js +190 -190
  171. package/lib/util/timeout.js +29 -29
  172. package/package.json +13 -12
  173. package/scripts/build.js +125 -125
  174. package/scripts/clean.js +31 -31
  175. package/scripts/docker-compose.yml +152 -152
  176. package/scripts/next-release-howto.md +24 -24
  177. package/scripts/oracledb-install-driver-libs.sh +82 -82
  178. package/scripts/release.sh +36 -34
  179. package/scripts/runkit-example.js +35 -34
  180. package/scripts/stress-test/README.txt +18 -18
  181. package/scripts/stress-test/docker-compose.yml +57 -57
  182. package/scripts/stress-test/knex-stress-test.js +212 -208
  183. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -145
  184. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -100
  185. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -184
  186. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  187. package/types/index.d.ts +3272 -3273
  188. package/types/result.d.ts +27 -27
  189. package/types/tables.d.ts +4 -4
  190. package/lib/dialects/index.js +0 -34
@@ -1,400 +1,400 @@
1
- // PostgreSQL Query Builder & Compiler
2
- // ------
3
- const identity = require('lodash/identity');
4
- const reduce = require('lodash/reduce');
5
-
6
- const QueryCompiler = require('../../../query/querycompiler');
7
- const {
8
- wrapString,
9
- columnize: columnize_,
10
- operator: operator_,
11
- wrap: wrap_,
12
- } = require('../../../formatter/wrappingFormatter');
13
-
14
- class QueryCompiler_PG extends QueryCompiler {
15
- constructor(client, builder, formatter) {
16
- super(client, builder, formatter);
17
- this._defaultInsertValue = 'default';
18
- }
19
-
20
- // Compiles a truncate query.
21
- truncate() {
22
- return `truncate ${this.tableName} restart identity`;
23
- }
24
-
25
- // is used if the an array with multiple empty values supplied
26
-
27
- // Compiles an `insert` query, allowing for multiple
28
- // inserts using a single query statement.
29
- insert() {
30
- let sql = super.insert();
31
- if (sql === '') return sql;
32
-
33
- const { returning, onConflict, ignore, merge, insert } = this.single;
34
- if (onConflict && ignore) sql += this._ignore(onConflict);
35
- if (onConflict && merge) {
36
- sql += this._merge(merge.updates, onConflict, insert);
37
- const wheres = this.where();
38
- if (wheres) sql += ` ${wheres}`;
39
- }
40
- if (returning) sql += this._returning(returning);
41
-
42
- return {
43
- sql,
44
- returning,
45
- };
46
- }
47
-
48
- // Compiles an `update` query, allowing for a return value.
49
- update() {
50
- const withSQL = this.with();
51
- const updateData = this._prepUpdate(this.single.update);
52
- const wheres = this.where();
53
- const { returning, updateFrom } = this.single;
54
- return {
55
- sql:
56
- withSQL +
57
- `update ${this.single.only ? 'only ' : ''}${this.tableName} ` +
58
- `set ${updateData.join(', ')}` +
59
- this._updateFrom(updateFrom) +
60
- (wheres ? ` ${wheres}` : '') +
61
- this._returning(returning),
62
- returning,
63
- };
64
- }
65
-
66
- using() {
67
- const usingTables = this.single.using;
68
- if (!usingTables) return;
69
- let sql = 'using ';
70
- if (Array.isArray(usingTables)) {
71
- sql += usingTables
72
- .map((table) => {
73
- return this.formatter.wrap(table);
74
- })
75
- .join(',');
76
- } else {
77
- sql += this.formatter.wrap(usingTables);
78
- }
79
- return sql;
80
- }
81
-
82
- // Compiles an `delete` query, allowing for a return value.
83
- del() {
84
- // Make sure tableName is processed by the formatter first.
85
- const { tableName } = this;
86
- const withSQL = this.with();
87
- let wheres = this.where() || '';
88
- let using = this.using() || '';
89
- const joins = this.grouped.join;
90
-
91
- const tableJoins = [];
92
- if (Array.isArray(joins)) {
93
- for (const join of joins) {
94
- tableJoins.push(
95
- wrap_(
96
- this._joinTable(join),
97
- undefined,
98
- this.builder,
99
- this.client,
100
- this.bindingsHolder
101
- )
102
- );
103
-
104
- const joinWheres = [];
105
- for (const clause of join.clauses) {
106
- joinWheres.push(
107
- this.whereBasic({
108
- column: clause.column,
109
- operator: '=',
110
- value: clause.value,
111
- asColumn: true,
112
- })
113
- );
114
- }
115
- if (joinWheres.length > 0) {
116
- wheres += (wheres ? ' and ' : 'where ') + joinWheres.join(' and ');
117
- }
118
- }
119
- if (tableJoins.length > 0) {
120
- using += (using ? ',' : 'using ') + tableJoins.join(',');
121
- }
122
- }
123
-
124
- // With 'using' syntax, no tablename between DELETE and FROM.
125
- const sql =
126
- withSQL +
127
- `delete from ${this.single.only ? 'only ' : ''}${tableName}` +
128
- (using ? ` ${using}` : '') +
129
- (wheres ? ` ${wheres}` : '');
130
- const { returning } = this.single;
131
- return {
132
- sql: sql + this._returning(returning),
133
- returning,
134
- };
135
- }
136
-
137
- aggregate(stmt) {
138
- return this._aggregate(stmt, { distinctParentheses: true });
139
- }
140
-
141
- _returning(value) {
142
- return value ? ` returning ${this.formatter.columnize(value)}` : '';
143
- }
144
-
145
- _updateFrom(name) {
146
- return name ? ` from ${this.formatter.wrap(name)}` : '';
147
- }
148
-
149
- _ignore(columns) {
150
- if (columns === true) {
151
- return ' on conflict do nothing';
152
- }
153
- return ` on conflict ${this._onConflictClause(columns)} do nothing`;
154
- }
155
-
156
- _merge(updates, columns, insert) {
157
- let sql = ` on conflict ${this._onConflictClause(columns)} do update set `;
158
- if (updates && Array.isArray(updates)) {
159
- sql += updates
160
- .map((column) =>
161
- wrapString(
162
- column.split('.').pop(),
163
- this.formatter.builder,
164
- this.client,
165
- this.formatter
166
- )
167
- )
168
- .map((column) => `${column} = excluded.${column}`)
169
- .join(', ');
170
-
171
- return sql;
172
- } else if (updates && typeof updates === 'object') {
173
- const updateData = this._prepUpdate(updates);
174
- if (typeof updateData === 'string') {
175
- sql += updateData;
176
- } else {
177
- sql += updateData.join(',');
178
- }
179
-
180
- return sql;
181
- } else {
182
- const insertData = this._prepInsert(insert);
183
- if (typeof insertData === 'string') {
184
- throw new Error(
185
- 'If using merge with a raw insert query, then updates must be provided'
186
- );
187
- }
188
-
189
- sql += insertData.columns
190
- .map((column) =>
191
- wrapString(column.split('.').pop(), this.builder, this.client)
192
- )
193
- .map((column) => `${column} = excluded.${column}`)
194
- .join(', ');
195
-
196
- return sql;
197
- }
198
- }
199
-
200
- // Join array of table names and apply default schema.
201
- _tableNames(tables) {
202
- const schemaName = this.single.schema;
203
- const sql = [];
204
-
205
- for (let i = 0; i < tables.length; i++) {
206
- let tableName = tables[i];
207
-
208
- if (tableName) {
209
- if (schemaName) {
210
- tableName = `${schemaName}.${tableName}`;
211
- }
212
- sql.push(this.formatter.wrap(tableName));
213
- }
214
- }
215
-
216
- return sql.join(', ');
217
- }
218
-
219
- _lockingClause(lockMode) {
220
- const tables = this.single.lockTables || [];
221
-
222
- return lockMode + (tables.length ? ' of ' + this._tableNames(tables) : '');
223
- }
224
-
225
- _groupOrder(item, type) {
226
- return super._groupOrderNulls(item, type);
227
- }
228
-
229
- forUpdate() {
230
- return this._lockingClause('for update');
231
- }
232
-
233
- forShare() {
234
- return this._lockingClause('for share');
235
- }
236
-
237
- forNoKeyUpdate() {
238
- return this._lockingClause('for no key update');
239
- }
240
-
241
- forKeyShare() {
242
- return this._lockingClause('for key share');
243
- }
244
-
245
- skipLocked() {
246
- return 'skip locked';
247
- }
248
-
249
- noWait() {
250
- return 'nowait';
251
- }
252
-
253
- // Compiles a columnInfo query
254
- columnInfo() {
255
- const column = this.single.columnInfo;
256
- let schema = this.single.schema;
257
-
258
- // The user may have specified a custom wrapIdentifier function in the config. We
259
- // need to run the identifiers through that function, but not format them as
260
- // identifiers otherwise.
261
- const table = this.client.customWrapIdentifier(this.single.table, identity);
262
-
263
- if (schema) {
264
- schema = this.client.customWrapIdentifier(schema, identity);
265
- }
266
-
267
- const sql =
268
- 'select * from information_schema.columns where table_name = ? and table_catalog = current_database()';
269
- const bindings = [table];
270
-
271
- return this._buildColumnInfoQuery(schema, sql, bindings, column);
272
- }
273
-
274
- _buildColumnInfoQuery(schema, sql, bindings, column) {
275
- if (schema) {
276
- sql += ' and table_schema = ?';
277
- bindings.push(schema);
278
- } else {
279
- sql += ' and table_schema = current_schema()';
280
- }
281
-
282
- return {
283
- sql,
284
- bindings,
285
- output(resp) {
286
- const out = reduce(
287
- resp.rows,
288
- function (columns, val) {
289
- columns[val.column_name] = {
290
- type: val.data_type,
291
- maxLength: val.character_maximum_length,
292
- nullable: val.is_nullable === 'YES',
293
- defaultValue: val.column_default,
294
- };
295
- return columns;
296
- },
297
- {}
298
- );
299
- return (column && out[column]) || out;
300
- },
301
- };
302
- }
303
-
304
- distinctOn(value) {
305
- return 'distinct on (' + this.formatter.columnize(value) + ') ';
306
- }
307
-
308
- // Json functions
309
- jsonExtract(params) {
310
- return this._jsonExtract('jsonb_path_query', params);
311
- }
312
-
313
- jsonSet(params) {
314
- return this._jsonSet(
315
- 'jsonb_set',
316
- Object.assign({}, params, {
317
- path: this.client.toPathForJson(params.path),
318
- })
319
- );
320
- }
321
-
322
- jsonInsert(params) {
323
- return this._jsonSet(
324
- 'jsonb_insert',
325
- Object.assign({}, params, {
326
- path: this.client.toPathForJson(params.path),
327
- })
328
- );
329
- }
330
-
331
- jsonRemove(params) {
332
- const jsonCol = `${columnize_(
333
- params.column,
334
- this.builder,
335
- this.client,
336
- this.bindingsHolder
337
- )} #- ${this.client.parameter(
338
- this.client.toPathForJson(params.path),
339
- this.builder,
340
- this.bindingsHolder
341
- )}`;
342
- return params.alias
343
- ? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
344
- : jsonCol;
345
- }
346
-
347
- whereJsonPath(statement) {
348
- let castValue = '';
349
- if (!isNaN(statement.value) && parseInt(statement.value)) {
350
- castValue = '::int';
351
- } else if (!isNaN(statement.value) && parseFloat(statement.value)) {
352
- castValue = '::float';
353
- } else {
354
- castValue = " #>> '{}'";
355
- }
356
- return `jsonb_path_query_first(${this._columnClause(
357
- statement
358
- )}, ${this.client.parameter(
359
- statement.jsonPath,
360
- this.builder,
361
- this.bindingsHolder
362
- )})${castValue} ${operator_(
363
- statement.operator,
364
- this.builder,
365
- this.client,
366
- this.bindingsHolder
367
- )} ${this._jsonValueClause(statement)}`;
368
- }
369
-
370
- whereJsonSupersetOf(statement) {
371
- return this._not(
372
- statement,
373
- `${wrap_(
374
- statement.column,
375
- undefined,
376
- this.builder,
377
- this.client,
378
- this.bindingsHolder
379
- )} @> ${this._jsonValueClause(statement)}`
380
- );
381
- }
382
-
383
- whereJsonSubsetOf(statement) {
384
- return this._not(
385
- statement,
386
- `${columnize_(
387
- statement.column,
388
- this.builder,
389
- this.client,
390
- this.bindingsHolder
391
- )} <@ ${this._jsonValueClause(statement)}`
392
- );
393
- }
394
-
395
- onJsonPathEquals(clause) {
396
- return this._onJsonPathEquals('jsonb_path_query_first', clause);
397
- }
398
- }
399
-
400
- module.exports = QueryCompiler_PG;
1
+ // PostgreSQL Query Builder & Compiler
2
+ // ------
3
+ const identity = require('lodash/identity');
4
+ const reduce = require('lodash/reduce');
5
+
6
+ const QueryCompiler = require('../../../query/querycompiler');
7
+ const {
8
+ wrapString,
9
+ columnize: columnize_,
10
+ operator: operator_,
11
+ wrap: wrap_,
12
+ } = require('../../../formatter/wrappingFormatter');
13
+
14
+ class QueryCompiler_PG extends QueryCompiler {
15
+ constructor(client, builder, formatter) {
16
+ super(client, builder, formatter);
17
+ this._defaultInsertValue = 'default';
18
+ }
19
+
20
+ // Compiles a truncate query.
21
+ truncate() {
22
+ return `truncate ${this.tableName} restart identity`;
23
+ }
24
+
25
+ // is used if the an array with multiple empty values supplied
26
+
27
+ // Compiles an `insert` query, allowing for multiple
28
+ // inserts using a single query statement.
29
+ insert() {
30
+ let sql = super.insert();
31
+ if (sql === '') return sql;
32
+
33
+ const { returning, onConflict, ignore, merge, insert } = this.single;
34
+ if (onConflict && ignore) sql += this._ignore(onConflict);
35
+ if (onConflict && merge) {
36
+ sql += this._merge(merge.updates, onConflict, insert);
37
+ const wheres = this.where();
38
+ if (wheres) sql += ` ${wheres}`;
39
+ }
40
+ if (returning) sql += this._returning(returning);
41
+
42
+ return {
43
+ sql,
44
+ returning,
45
+ };
46
+ }
47
+
48
+ // Compiles an `update` query, allowing for a return value.
49
+ update() {
50
+ const withSQL = this.with();
51
+ const updateData = this._prepUpdate(this.single.update);
52
+ const wheres = this.where();
53
+ const { returning, updateFrom } = this.single;
54
+ return {
55
+ sql:
56
+ withSQL +
57
+ `update ${this.single.only ? 'only ' : ''}${this.tableName} ` +
58
+ `set ${updateData.join(', ')}` +
59
+ this._updateFrom(updateFrom) +
60
+ (wheres ? ` ${wheres}` : '') +
61
+ this._returning(returning),
62
+ returning,
63
+ };
64
+ }
65
+
66
+ using() {
67
+ const usingTables = this.single.using;
68
+ if (!usingTables) return;
69
+ let sql = 'using ';
70
+ if (Array.isArray(usingTables)) {
71
+ sql += usingTables
72
+ .map((table) => {
73
+ return this.formatter.wrap(table);
74
+ })
75
+ .join(',');
76
+ } else {
77
+ sql += this.formatter.wrap(usingTables);
78
+ }
79
+ return sql;
80
+ }
81
+
82
+ // Compiles an `delete` query, allowing for a return value.
83
+ del() {
84
+ // Make sure tableName is processed by the formatter first.
85
+ const { tableName } = this;
86
+ const withSQL = this.with();
87
+ let wheres = this.where() || '';
88
+ let using = this.using() || '';
89
+ const joins = this.grouped.join;
90
+
91
+ const tableJoins = [];
92
+ if (Array.isArray(joins)) {
93
+ for (const join of joins) {
94
+ tableJoins.push(
95
+ wrap_(
96
+ this._joinTable(join),
97
+ undefined,
98
+ this.builder,
99
+ this.client,
100
+ this.bindingsHolder
101
+ )
102
+ );
103
+
104
+ const joinWheres = [];
105
+ for (const clause of join.clauses) {
106
+ joinWheres.push(
107
+ this.whereBasic({
108
+ column: clause.column,
109
+ operator: '=',
110
+ value: clause.value,
111
+ asColumn: true,
112
+ })
113
+ );
114
+ }
115
+ if (joinWheres.length > 0) {
116
+ wheres += (wheres ? ' and ' : 'where ') + joinWheres.join(' and ');
117
+ }
118
+ }
119
+ if (tableJoins.length > 0) {
120
+ using += (using ? ',' : 'using ') + tableJoins.join(',');
121
+ }
122
+ }
123
+
124
+ // With 'using' syntax, no tablename between DELETE and FROM.
125
+ const sql =
126
+ withSQL +
127
+ `delete from ${this.single.only ? 'only ' : ''}${tableName}` +
128
+ (using ? ` ${using}` : '') +
129
+ (wheres ? ` ${wheres}` : '');
130
+ const { returning } = this.single;
131
+ return {
132
+ sql: sql + this._returning(returning),
133
+ returning,
134
+ };
135
+ }
136
+
137
+ aggregate(stmt) {
138
+ return this._aggregate(stmt, { distinctParentheses: true });
139
+ }
140
+
141
+ _returning(value) {
142
+ return value ? ` returning ${this.formatter.columnize(value)}` : '';
143
+ }
144
+
145
+ _updateFrom(name) {
146
+ return name ? ` from ${this.formatter.wrap(name)}` : '';
147
+ }
148
+
149
+ _ignore(columns) {
150
+ if (columns === true) {
151
+ return ' on conflict do nothing';
152
+ }
153
+ return ` on conflict ${this._onConflictClause(columns)} do nothing`;
154
+ }
155
+
156
+ _merge(updates, columns, insert) {
157
+ let sql = ` on conflict ${this._onConflictClause(columns)} do update set `;
158
+ if (updates && Array.isArray(updates)) {
159
+ sql += updates
160
+ .map((column) =>
161
+ wrapString(
162
+ column.split('.').pop(),
163
+ this.formatter.builder,
164
+ this.client,
165
+ this.formatter
166
+ )
167
+ )
168
+ .map((column) => `${column} = excluded.${column}`)
169
+ .join(', ');
170
+
171
+ return sql;
172
+ } else if (updates && typeof updates === 'object') {
173
+ const updateData = this._prepUpdate(updates);
174
+ if (typeof updateData === 'string') {
175
+ sql += updateData;
176
+ } else {
177
+ sql += updateData.join(',');
178
+ }
179
+
180
+ return sql;
181
+ } else {
182
+ const insertData = this._prepInsert(insert);
183
+ if (typeof insertData === 'string') {
184
+ throw new Error(
185
+ 'If using merge with a raw insert query, then updates must be provided'
186
+ );
187
+ }
188
+
189
+ sql += insertData.columns
190
+ .map((column) =>
191
+ wrapString(column.split('.').pop(), this.builder, this.client)
192
+ )
193
+ .map((column) => `${column} = excluded.${column}`)
194
+ .join(', ');
195
+
196
+ return sql;
197
+ }
198
+ }
199
+
200
+ // Join array of table names and apply default schema.
201
+ _tableNames(tables) {
202
+ const schemaName = this.single.schema;
203
+ const sql = [];
204
+
205
+ for (let i = 0; i < tables.length; i++) {
206
+ let tableName = tables[i];
207
+
208
+ if (tableName) {
209
+ if (schemaName) {
210
+ tableName = `${schemaName}.${tableName}`;
211
+ }
212
+ sql.push(this.formatter.wrap(tableName));
213
+ }
214
+ }
215
+
216
+ return sql.join(', ');
217
+ }
218
+
219
+ _lockingClause(lockMode) {
220
+ const tables = this.single.lockTables || [];
221
+
222
+ return lockMode + (tables.length ? ' of ' + this._tableNames(tables) : '');
223
+ }
224
+
225
+ _groupOrder(item, type) {
226
+ return super._groupOrderNulls(item, type);
227
+ }
228
+
229
+ forUpdate() {
230
+ return this._lockingClause('for update');
231
+ }
232
+
233
+ forShare() {
234
+ return this._lockingClause('for share');
235
+ }
236
+
237
+ forNoKeyUpdate() {
238
+ return this._lockingClause('for no key update');
239
+ }
240
+
241
+ forKeyShare() {
242
+ return this._lockingClause('for key share');
243
+ }
244
+
245
+ skipLocked() {
246
+ return 'skip locked';
247
+ }
248
+
249
+ noWait() {
250
+ return 'nowait';
251
+ }
252
+
253
+ // Compiles a columnInfo query
254
+ columnInfo() {
255
+ const column = this.single.columnInfo;
256
+ let schema = this.single.schema;
257
+
258
+ // The user may have specified a custom wrapIdentifier function in the config. We
259
+ // need to run the identifiers through that function, but not format them as
260
+ // identifiers otherwise.
261
+ const table = this.client.customWrapIdentifier(this.single.table, identity);
262
+
263
+ if (schema) {
264
+ schema = this.client.customWrapIdentifier(schema, identity);
265
+ }
266
+
267
+ const sql =
268
+ 'select * from information_schema.columns where table_name = ? and table_catalog = current_database()';
269
+ const bindings = [table];
270
+
271
+ return this._buildColumnInfoQuery(schema, sql, bindings, column);
272
+ }
273
+
274
+ _buildColumnInfoQuery(schema, sql, bindings, column) {
275
+ if (schema) {
276
+ sql += ' and table_schema = ?';
277
+ bindings.push(schema);
278
+ } else {
279
+ sql += ' and table_schema = current_schema()';
280
+ }
281
+
282
+ return {
283
+ sql,
284
+ bindings,
285
+ output(resp) {
286
+ const out = reduce(
287
+ resp.rows,
288
+ function (columns, val) {
289
+ columns[val.column_name] = {
290
+ type: val.data_type,
291
+ maxLength: val.character_maximum_length,
292
+ nullable: val.is_nullable === 'YES',
293
+ defaultValue: val.column_default,
294
+ };
295
+ return columns;
296
+ },
297
+ {}
298
+ );
299
+ return (column && out[column]) || out;
300
+ },
301
+ };
302
+ }
303
+
304
+ distinctOn(value) {
305
+ return 'distinct on (' + this.formatter.columnize(value) + ') ';
306
+ }
307
+
308
+ // Json functions
309
+ jsonExtract(params) {
310
+ return this._jsonExtract('jsonb_path_query', params);
311
+ }
312
+
313
+ jsonSet(params) {
314
+ return this._jsonSet(
315
+ 'jsonb_set',
316
+ Object.assign({}, params, {
317
+ path: this.client.toPathForJson(params.path),
318
+ })
319
+ );
320
+ }
321
+
322
+ jsonInsert(params) {
323
+ return this._jsonSet(
324
+ 'jsonb_insert',
325
+ Object.assign({}, params, {
326
+ path: this.client.toPathForJson(params.path),
327
+ })
328
+ );
329
+ }
330
+
331
+ jsonRemove(params) {
332
+ const jsonCol = `${columnize_(
333
+ params.column,
334
+ this.builder,
335
+ this.client,
336
+ this.bindingsHolder
337
+ )} #- ${this.client.parameter(
338
+ this.client.toPathForJson(params.path),
339
+ this.builder,
340
+ this.bindingsHolder
341
+ )}`;
342
+ return params.alias
343
+ ? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
344
+ : jsonCol;
345
+ }
346
+
347
+ whereJsonPath(statement) {
348
+ let castValue = '';
349
+ if (!isNaN(statement.value) && parseInt(statement.value)) {
350
+ castValue = '::int';
351
+ } else if (!isNaN(statement.value) && parseFloat(statement.value)) {
352
+ castValue = '::float';
353
+ } else {
354
+ castValue = " #>> '{}'";
355
+ }
356
+ return `jsonb_path_query_first(${this._columnClause(
357
+ statement
358
+ )}, ${this.client.parameter(
359
+ statement.jsonPath,
360
+ this.builder,
361
+ this.bindingsHolder
362
+ )})${castValue} ${operator_(
363
+ statement.operator,
364
+ this.builder,
365
+ this.client,
366
+ this.bindingsHolder
367
+ )} ${this._jsonValueClause(statement)}`;
368
+ }
369
+
370
+ whereJsonSupersetOf(statement) {
371
+ return this._not(
372
+ statement,
373
+ `${wrap_(
374
+ statement.column,
375
+ undefined,
376
+ this.builder,
377
+ this.client,
378
+ this.bindingsHolder
379
+ )} @> ${this._jsonValueClause(statement)}`
380
+ );
381
+ }
382
+
383
+ whereJsonSubsetOf(statement) {
384
+ return this._not(
385
+ statement,
386
+ `${columnize_(
387
+ statement.column,
388
+ this.builder,
389
+ this.client,
390
+ this.bindingsHolder
391
+ )} <@ ${this._jsonValueClause(statement)}`
392
+ );
393
+ }
394
+
395
+ onJsonPathEquals(clause) {
396
+ return this._onJsonPathEquals('jsonb_path_query_first', clause);
397
+ }
398
+ }
399
+
400
+ module.exports = QueryCompiler_PG;