knex 3.2.2 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2447 -2441
- package/CONTRIBUTING.md +190 -190
- package/LICENSE +22 -22
- package/README.md +156 -156
- package/UPGRADING.md +245 -245
- package/bin/cli.js +516 -516
- package/bin/knexfile-runtime-error.js +27 -27
- package/bin/utils/cli-config-utils.js +217 -217
- package/bin/utils/constants.js +7 -7
- package/bin/utils/migrationsLister.js +37 -37
- package/knex.js +23 -23
- package/knex.mjs +11 -11
- package/lib/builder-interface-augmenter.js +120 -120
- package/lib/client.js +585 -585
- package/lib/constants.js +61 -61
- package/lib/dialects/better-sqlite3/index.js +101 -101
- package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
- package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
- package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
- package/lib/dialects/cockroachdb/crdb-tablecompiler.js +46 -46
- package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
- package/lib/dialects/cockroachdb/index.js +86 -86
- package/lib/dialects/index.js +34 -34
- package/lib/dialects/mssql/index.js +498 -498
- package/lib/dialects/mssql/mssql-formatter.js +34 -34
- package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
- package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
- package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
- package/lib/dialects/mssql/schema/mssql-tablecompiler.js +393 -393
- package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
- package/lib/dialects/mssql/transaction.js +176 -176
- package/lib/dialects/mysql/index.js +317 -317
- package/lib/dialects/mysql/query/mysql-querybuilder.js +14 -14
- package/lib/dialects/mysql/query/mysql-querycompiler.js +292 -292
- package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
- package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
- package/lib/dialects/mysql/schema/mysql-tablecompiler.js +426 -426
- package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
- package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
- package/lib/dialects/mysql/transaction.js +46 -46
- package/lib/dialects/mysql2/index.js +53 -53
- package/lib/dialects/mysql2/transaction.js +44 -44
- package/lib/dialects/oracle/DEAD_CODE.md +5 -5
- package/lib/dialects/oracle/index.js +92 -92
- package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
- package/lib/dialects/oracle/schema/internal/incrementUtils.js +22 -22
- package/lib/dialects/oracle/schema/internal/trigger.js +155 -155
- package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
- package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
- package/lib/dialects/oracle/schema/oracle-compiler.js +124 -124
- package/lib/dialects/oracle/schema/oracle-tablecompiler.js +210 -210
- package/lib/dialects/oracle/utils.js +107 -107
- package/lib/dialects/oracledb/index.js +381 -381
- package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
- package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
- package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
- package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
- package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
- package/lib/dialects/oracledb/transaction.js +98 -98
- package/lib/dialects/oracledb/utils.js +208 -208
- package/lib/dialects/pgnative/index.js +60 -60
- package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
- package/lib/dialects/postgres/index.js +373 -373
- package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
- package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
- package/lib/dialects/postgres/schema/pg-columncompiler.js +162 -162
- package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
- package/lib/dialects/postgres/schema/pg-tablecompiler.js +331 -331
- package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
- package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
- package/lib/dialects/redshift/index.js +86 -86
- package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
- package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
- package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
- package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
- package/lib/dialects/redshift/schema/redshift-tablecompiler.js +134 -134
- package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
- package/lib/dialects/redshift/transaction.js +32 -32
- package/lib/dialects/sqlite3/execution/sqlite-transaction.js +172 -172
- package/lib/dialects/sqlite3/index.js +263 -263
- package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
- package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +341 -341
- package/lib/dialects/sqlite3/schema/ddl.js +380 -380
- package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
- package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
- package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
- package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
- package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
- package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
- package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
- package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
- package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +364 -364
- package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
- package/lib/execution/batch-insert.js +51 -51
- package/lib/execution/internal/delay.js +6 -6
- package/lib/execution/internal/ensure-connection-callback.js +41 -41
- package/lib/execution/internal/query-executioner.js +62 -62
- package/lib/execution/runner.js +325 -325
- package/lib/execution/transaction.js +417 -417
- package/lib/formatter/formatterUtils.js +42 -42
- package/lib/formatter/rawFormatter.js +84 -84
- package/lib/formatter/wrappingFormatter.js +253 -253
- package/lib/formatter.js +25 -25
- package/lib/index.js +3 -3
- package/lib/knex-builder/FunctionHelper.js +80 -80
- package/lib/knex-builder/Knex.js +59 -59
- package/lib/knex-builder/internal/config-resolver.js +57 -57
- package/lib/knex-builder/internal/parse-connection.js +87 -87
- package/lib/knex-builder/make-knex.js +345 -345
- package/lib/logger.js +76 -76
- package/lib/migrations/common/MigrationsLoader.js +36 -36
- package/lib/migrations/migrate/MigrationGenerator.js +84 -84
- package/lib/migrations/migrate/Migrator.js +632 -632
- package/lib/migrations/migrate/migrate-stub.js +17 -17
- package/lib/migrations/migrate/migration-list-resolver.js +33 -33
- package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
- package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
- package/lib/migrations/migrate/stub/cjs.stub +15 -15
- package/lib/migrations/migrate/stub/coffee.stub +13 -13
- package/lib/migrations/migrate/stub/eg.stub +14 -14
- package/lib/migrations/migrate/stub/js-schema.stub +22 -22
- package/lib/migrations/migrate/stub/js.stub +22 -22
- package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
- package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
- package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
- package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
- package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
- package/lib/migrations/migrate/stub/ls.stub +14 -14
- package/lib/migrations/migrate/stub/mjs.stub +23 -23
- package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
- package/lib/migrations/migrate/stub/ts.stub +21 -21
- package/lib/migrations/migrate/table-creator.js +77 -77
- package/lib/migrations/migrate/table-resolver.js +27 -27
- package/lib/migrations/seed/Seeder.js +137 -137
- package/lib/migrations/seed/seed-stub.js +13 -13
- package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
- package/lib/migrations/seed/sources/fs-seeds.js +65 -65
- package/lib/migrations/seed/stub/coffee.stub +9 -9
- package/lib/migrations/seed/stub/eg.stub +11 -11
- package/lib/migrations/seed/stub/js.stub +13 -13
- package/lib/migrations/seed/stub/ls.stub +11 -11
- package/lib/migrations/seed/stub/mjs.stub +12 -12
- package/lib/migrations/seed/stub/ts.stub +13 -13
- package/lib/migrations/util/fs.js +86 -86
- package/lib/migrations/util/import-file.js +12 -12
- package/lib/migrations/util/is-module-type.js +9 -9
- package/lib/migrations/util/template.js +52 -52
- package/lib/migrations/util/timestamp.js +14 -14
- package/lib/query/analytic.js +52 -52
- package/lib/query/constants.js +15 -15
- package/lib/query/joinclause.js +270 -270
- package/lib/query/method-constants.js +136 -136
- package/lib/query/querybuilder.js +1793 -1793
- package/lib/query/querycompiler.js +1634 -1634
- package/lib/raw.js +139 -139
- package/lib/ref.js +39 -39
- package/lib/schema/builder.js +115 -115
- package/lib/schema/columnbuilder.js +146 -146
- package/lib/schema/columncompiler.js +307 -307
- package/lib/schema/compiler.js +187 -187
- package/lib/schema/internal/helpers.js +55 -55
- package/lib/schema/tablebuilder.js +379 -379
- package/lib/schema/tablecompiler.js +450 -450
- package/lib/schema/viewbuilder.js +92 -92
- package/lib/schema/viewcompiler.js +138 -138
- package/lib/util/finally-mixin.js +13 -13
- package/lib/util/helpers.js +95 -95
- package/lib/util/is.js +32 -32
- package/lib/util/nanoid.js +40 -40
- package/lib/util/noop.js +1 -1
- package/lib/util/save-async-stack.js +14 -14
- package/lib/util/security.js +32 -32
- package/lib/util/string.js +190 -190
- package/lib/util/timeout.js +29 -29
- package/package.json +294 -296
- package/scripts/act-testing/act.sh +19 -19
- package/scripts/act-testing/merged-no-label.json +11 -11
- package/scripts/act-testing/merged-patch-labeled.json +12 -12
- package/scripts/act-testing/merged-skip-labeled.json +12 -12
- package/scripts/act-testing/not-merged-patch-labeled.json +12 -12
- package/scripts/build-for-release.sh +121 -121
- package/scripts/build.js +125 -125
- package/scripts/clean.js +31 -31
- package/scripts/docker-compose.yml +150 -150
- package/scripts/format-changelog.js +55 -55
- package/scripts/next-release-howto.md +24 -24
- package/scripts/oracledb-install-driver-libs.sh +82 -82
- package/scripts/release.sh +36 -36
- package/scripts/runkit-example.js +35 -35
- package/scripts/stress-test/README.txt +18 -18
- package/scripts/stress-test/docker-compose.yml +55 -55
- package/scripts/stress-test/knex-stress-test.js +212 -212
- package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -149
- package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -101
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -188
- package/types/index.d.mts +11 -0
- package/types/index.d.ts +3321 -3321
- package/types/result.d.ts +27 -27
- package/types/tables.d.ts +4 -4
|
@@ -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;
|