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,1634 +1,1634 @@
|
|
|
1
|
-
// Query Compiler
|
|
2
|
-
// -------
|
|
3
|
-
const helpers = require('../util/helpers');
|
|
4
|
-
const { hasOwn } = require('../util/security');
|
|
5
|
-
const Raw = require('../raw');
|
|
6
|
-
const QueryBuilder = require('./querybuilder');
|
|
7
|
-
const JoinClause = require('./joinclause');
|
|
8
|
-
const debug = require('debug');
|
|
9
|
-
|
|
10
|
-
const assign = require('lodash/assign');
|
|
11
|
-
const compact = require('lodash/compact');
|
|
12
|
-
const groupBy = require('lodash/groupBy');
|
|
13
|
-
const has = require('lodash/has');
|
|
14
|
-
const isEmpty = require('lodash/isEmpty');
|
|
15
|
-
const map = require('lodash/map');
|
|
16
|
-
const omitBy = require('lodash/omitBy');
|
|
17
|
-
const reduce = require('lodash/reduce');
|
|
18
|
-
const { nanoid } = require('../util/nanoid');
|
|
19
|
-
const { isString, isUndefined } = require('../util/is');
|
|
20
|
-
const {
|
|
21
|
-
columnize: columnize_,
|
|
22
|
-
direction: direction_,
|
|
23
|
-
operator: operator_,
|
|
24
|
-
wrap: wrap_,
|
|
25
|
-
unwrapRaw: unwrapRaw_,
|
|
26
|
-
rawOrFn: rawOrFn_,
|
|
27
|
-
} = require('../formatter/wrappingFormatter');
|
|
28
|
-
|
|
29
|
-
const debugBindings = debug('knex:bindings');
|
|
30
|
-
|
|
31
|
-
const components = [
|
|
32
|
-
'comments',
|
|
33
|
-
'columns',
|
|
34
|
-
'join',
|
|
35
|
-
'where',
|
|
36
|
-
'union',
|
|
37
|
-
'group',
|
|
38
|
-
'having',
|
|
39
|
-
'order',
|
|
40
|
-
'limit',
|
|
41
|
-
'offset',
|
|
42
|
-
'lock',
|
|
43
|
-
'waitMode',
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
const methodAliases = {
|
|
47
|
-
del: 'delete',
|
|
48
|
-
first: 'select',
|
|
49
|
-
pluck: 'select',
|
|
50
|
-
};
|
|
51
|
-
const invalidClauses = {
|
|
52
|
-
delete: ['having', 'limit'],
|
|
53
|
-
truncate: ['where', 'having', 'limit'],
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
// The "QueryCompiler" takes all of the query statements which
|
|
57
|
-
// have been gathered in the "QueryBuilder" and turns them into a
|
|
58
|
-
// properly formatted / bound query string.
|
|
59
|
-
class QueryCompiler {
|
|
60
|
-
constructor(client, builder, bindings) {
|
|
61
|
-
this.client = client;
|
|
62
|
-
this.method = builder._method || 'select';
|
|
63
|
-
this.options = builder._options;
|
|
64
|
-
this.single = builder._single;
|
|
65
|
-
this.queryComments = builder._comments;
|
|
66
|
-
this.timeout = builder._timeout || false;
|
|
67
|
-
this.cancelOnTimeout = builder._cancelOnTimeout || false;
|
|
68
|
-
this.grouped = groupBy(builder._statements, 'grouping');
|
|
69
|
-
this.formatter = client.formatter(builder);
|
|
70
|
-
// Used when the insert call is empty.
|
|
71
|
-
this._emptyInsertValue = 'default values';
|
|
72
|
-
this.first = this.select;
|
|
73
|
-
|
|
74
|
-
this.bindings = bindings || [];
|
|
75
|
-
this.formatter.bindings = this.bindings;
|
|
76
|
-
this.bindingsHolder = this;
|
|
77
|
-
this.builder = this.formatter.builder;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Categorically refuse to execute certain queries that have defined certain clause groups
|
|
81
|
-
// For example, if a "having" clause is defined but we're executing a "delete" query, that
|
|
82
|
-
// is never valid in any of the supported dialects.
|
|
83
|
-
_preValidate() {
|
|
84
|
-
// Query builders don't really store the SQL verb they expect to generate; this would
|
|
85
|
-
// be nicer if we could avoid the fanout of "call an arbitrary method on one of a dozen
|
|
86
|
-
// classes". Instead, we keep an alias list to derive the expected intent from the
|
|
87
|
-
// methods used by the codebase for now.
|
|
88
|
-
const method = this.method;
|
|
89
|
-
const verb = hasOwn(methodAliases, method) ? methodAliases[method] : method;
|
|
90
|
-
if (!hasOwn(invalidClauses, verb)) return;
|
|
91
|
-
|
|
92
|
-
// For certain verbs, certain clauses just don't exist / aren't supported. The list
|
|
93
|
-
// here is intentionally not complete; it's just checking the things that allow users
|
|
94
|
-
// to make dangerous errors.
|
|
95
|
-
const invalid = invalidClauses[verb];
|
|
96
|
-
for (let i = 0; i < invalid.length; i++) {
|
|
97
|
-
const clause = invalid[i];
|
|
98
|
-
|
|
99
|
-
const hasNonEmptyGrouped =
|
|
100
|
-
hasOwn(this.grouped, clause) && this.grouped[clause].length > 0;
|
|
101
|
-
const hasNonEmptySingle =
|
|
102
|
-
hasOwn(this.single, clause) && this.single[clause] != null;
|
|
103
|
-
|
|
104
|
-
if (hasNonEmptyGrouped || hasNonEmptySingle) {
|
|
105
|
-
throw new Error(
|
|
106
|
-
`Aborted query compilation: \`${clause}\` has no effect on a \`${verb}\` statement`
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Collapse the builder into a single object
|
|
113
|
-
toSQL(method, tz) {
|
|
114
|
-
this._preValidate();
|
|
115
|
-
|
|
116
|
-
this._undefinedInWhereClause = false;
|
|
117
|
-
this.undefinedBindingsInfo = [];
|
|
118
|
-
|
|
119
|
-
method = method || this.method;
|
|
120
|
-
const val = this[method]() || '';
|
|
121
|
-
|
|
122
|
-
const query = {
|
|
123
|
-
method,
|
|
124
|
-
options: reduce(this.options, assign, {}),
|
|
125
|
-
timeout: this.timeout,
|
|
126
|
-
cancelOnTimeout: this.cancelOnTimeout,
|
|
127
|
-
bindings: this.bindingsHolder.bindings || [],
|
|
128
|
-
__knexQueryUid: nanoid(),
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
Object.defineProperties(query, {
|
|
132
|
-
toNative: {
|
|
133
|
-
value: () => {
|
|
134
|
-
return {
|
|
135
|
-
sql: this.client.positionBindings(query.sql),
|
|
136
|
-
bindings: this.client.prepBindings(query.bindings),
|
|
137
|
-
};
|
|
138
|
-
},
|
|
139
|
-
enumerable: false,
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
if (isString(val)) {
|
|
144
|
-
query.sql = val;
|
|
145
|
-
} else {
|
|
146
|
-
assign(query, val);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (method === 'select' || method === 'first') {
|
|
150
|
-
if (this.single.as) {
|
|
151
|
-
query.as = this.single.as;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (this._undefinedInWhereClause) {
|
|
156
|
-
debugBindings(query.bindings);
|
|
157
|
-
throw new Error(
|
|
158
|
-
`Undefined binding(s) detected when compiling ` +
|
|
159
|
-
`${method.toUpperCase()}. Undefined column(s): [${this.undefinedBindingsInfo.join(
|
|
160
|
-
', '
|
|
161
|
-
)}] query: ${query.sql}`
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return query;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Compiles the `select` statement, or nested sub-selects by calling each of
|
|
169
|
-
// the component compilers, trimming out the empties, and returning a
|
|
170
|
-
// generated query string.
|
|
171
|
-
select() {
|
|
172
|
-
let sql = this.with();
|
|
173
|
-
|
|
174
|
-
let unionStatement = '';
|
|
175
|
-
|
|
176
|
-
const firstStatements = [];
|
|
177
|
-
const endStatements = [];
|
|
178
|
-
|
|
179
|
-
components.forEach((component) => {
|
|
180
|
-
const statement = this[component](this);
|
|
181
|
-
// We store the 'union' statement to append it at the end.
|
|
182
|
-
// We still need to call the component sequentially because of
|
|
183
|
-
// order of bindings.
|
|
184
|
-
switch (component) {
|
|
185
|
-
case 'union':
|
|
186
|
-
unionStatement = statement;
|
|
187
|
-
break;
|
|
188
|
-
case 'comments':
|
|
189
|
-
case 'columns':
|
|
190
|
-
case 'join':
|
|
191
|
-
case 'where':
|
|
192
|
-
firstStatements.push(statement);
|
|
193
|
-
break;
|
|
194
|
-
default:
|
|
195
|
-
endStatements.push(statement);
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// Check if we need to wrap the main query.
|
|
201
|
-
// We need to wrap main query if one of union have wrap options to true
|
|
202
|
-
// to avoid error syntax (in PostgreSQL for example).
|
|
203
|
-
const wrapMainQuery =
|
|
204
|
-
this.grouped.union &&
|
|
205
|
-
this.grouped.union.map((u) => u.wrap).some((u) => u);
|
|
206
|
-
|
|
207
|
-
if (this.onlyUnions()) {
|
|
208
|
-
const statements = compact(firstStatements.concat(endStatements)).join(
|
|
209
|
-
' '
|
|
210
|
-
);
|
|
211
|
-
sql += unionStatement + (statements ? ' ' + statements : '');
|
|
212
|
-
} else {
|
|
213
|
-
const allStatements =
|
|
214
|
-
(wrapMainQuery ? '(' : '') +
|
|
215
|
-
compact(firstStatements).join(' ') +
|
|
216
|
-
(wrapMainQuery ? ')' : '');
|
|
217
|
-
const endStat = compact(endStatements).join(' ');
|
|
218
|
-
sql +=
|
|
219
|
-
allStatements +
|
|
220
|
-
(unionStatement ? ' ' + unionStatement : '') +
|
|
221
|
-
(endStat ? ' ' + endStat : endStat);
|
|
222
|
-
}
|
|
223
|
-
return sql;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
pluck() {
|
|
227
|
-
let toPluck = this.single.pluck;
|
|
228
|
-
if (toPluck.indexOf('.') !== -1) {
|
|
229
|
-
toPluck = toPluck.split('.').slice(-1)[0];
|
|
230
|
-
}
|
|
231
|
-
return {
|
|
232
|
-
sql: this.select(),
|
|
233
|
-
pluck: toPluck,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Compiles an "insert" query, allowing for multiple
|
|
238
|
-
// inserts using a single query statement.
|
|
239
|
-
insert() {
|
|
240
|
-
const insertValues = this.single.insert || [];
|
|
241
|
-
const sql = this.with() + `insert into ${this.tableName} `;
|
|
242
|
-
const body = this._insertBody(insertValues);
|
|
243
|
-
return body === '' ? '' : sql + body;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
_onConflictClause(columns) {
|
|
247
|
-
return columns instanceof Raw
|
|
248
|
-
? this.formatter.wrap(columns)
|
|
249
|
-
: `(${this.formatter.columnize(columns)})`;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
_buildInsertValues(insertData) {
|
|
253
|
-
let sql = '';
|
|
254
|
-
let i = -1;
|
|
255
|
-
while (++i < insertData.values.length) {
|
|
256
|
-
if (i !== 0) sql += '), (';
|
|
257
|
-
sql += this.client.parameterize(
|
|
258
|
-
insertData.values[i],
|
|
259
|
-
this.client.valueForUndefined,
|
|
260
|
-
this.builder,
|
|
261
|
-
this.bindingsHolder
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
return sql;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
_insertBody(insertValues) {
|
|
268
|
-
let sql = '';
|
|
269
|
-
if (Array.isArray(insertValues)) {
|
|
270
|
-
if (insertValues.length === 0) {
|
|
271
|
-
return '';
|
|
272
|
-
}
|
|
273
|
-
} else if (typeof insertValues === 'object' && isEmpty(insertValues)) {
|
|
274
|
-
return sql + this._emptyInsertValue;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
const insertData = this._prepInsert(insertValues);
|
|
278
|
-
if (typeof insertData === 'string') {
|
|
279
|
-
sql += insertData;
|
|
280
|
-
} else {
|
|
281
|
-
if (insertData.columns.length) {
|
|
282
|
-
sql += `(${columnize_(
|
|
283
|
-
insertData.columns,
|
|
284
|
-
this.builder,
|
|
285
|
-
this.client,
|
|
286
|
-
this.bindingsHolder
|
|
287
|
-
)}`;
|
|
288
|
-
sql += ') values (' + this._buildInsertValues(insertData) + ')';
|
|
289
|
-
} else if (insertValues.length === 1 && insertValues[0]) {
|
|
290
|
-
sql += this._emptyInsertValue;
|
|
291
|
-
} else {
|
|
292
|
-
sql = '';
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
return sql;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Compiles the "update" query.
|
|
299
|
-
update() {
|
|
300
|
-
// Make sure tableName is processed by the formatter first.
|
|
301
|
-
const withSQL = this.with();
|
|
302
|
-
const { tableName } = this;
|
|
303
|
-
const updateData = this._prepUpdate(this.single.update);
|
|
304
|
-
const wheres = this.where();
|
|
305
|
-
return (
|
|
306
|
-
withSQL +
|
|
307
|
-
`update ${this.single.only ? 'only ' : ''}${tableName}` +
|
|
308
|
-
' set ' +
|
|
309
|
-
updateData.join(', ') +
|
|
310
|
-
(wheres ? ` ${wheres}` : '')
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
_hintComments() {
|
|
315
|
-
let hints = this.grouped.hintComments || [];
|
|
316
|
-
hints = hints.map((hint) => compact(hint.value).join(' '));
|
|
317
|
-
hints = compact(hints).join(' ');
|
|
318
|
-
return hints ? `/*+ ${hints} */ ` : '';
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Compiles the columns in the query, specifying if an item was distinct.
|
|
322
|
-
columns() {
|
|
323
|
-
let distinctClause = '';
|
|
324
|
-
if (this.onlyUnions()) return '';
|
|
325
|
-
const hints = this._hintComments();
|
|
326
|
-
const columns = this.grouped.columns || [];
|
|
327
|
-
let i = -1,
|
|
328
|
-
sql = [];
|
|
329
|
-
if (columns) {
|
|
330
|
-
while (++i < columns.length) {
|
|
331
|
-
const stmt = columns[i];
|
|
332
|
-
if (stmt.distinct) distinctClause = 'distinct ';
|
|
333
|
-
if (stmt.distinctOn) {
|
|
334
|
-
distinctClause = this.distinctOn(stmt.value);
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
if (stmt.type === 'aggregate') {
|
|
338
|
-
sql.push(...this.aggregate(stmt));
|
|
339
|
-
} else if (stmt.type === 'aggregateRaw') {
|
|
340
|
-
sql.push(this.aggregateRaw(stmt));
|
|
341
|
-
} else if (stmt.type === 'analytic') {
|
|
342
|
-
sql.push(this.analytic(stmt));
|
|
343
|
-
} else if (stmt.type === 'json') {
|
|
344
|
-
sql.push(this.json(stmt));
|
|
345
|
-
} else if (stmt.value && stmt.value.length > 0) {
|
|
346
|
-
sql.push(
|
|
347
|
-
columnize_(
|
|
348
|
-
stmt.value,
|
|
349
|
-
this.builder,
|
|
350
|
-
this.client,
|
|
351
|
-
this.bindingsHolder
|
|
352
|
-
)
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
if (sql.length === 0) sql = ['*'];
|
|
358
|
-
const select = this.onlyJson() ? '' : 'select ';
|
|
359
|
-
return (
|
|
360
|
-
`${select}${hints}${distinctClause}` +
|
|
361
|
-
sql.join(', ') +
|
|
362
|
-
(this.tableName
|
|
363
|
-
? ` from ${this.single.only ? 'only ' : ''}${this.tableName}`
|
|
364
|
-
: '')
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Add comments to the query
|
|
369
|
-
comments() {
|
|
370
|
-
if (!this.queryComments.length) return '';
|
|
371
|
-
return this.queryComments
|
|
372
|
-
.map((comment) => `/* ${comment.comment} */`)
|
|
373
|
-
.join(' ');
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
_aggregate(stmt, { aliasSeparator = ' as ', distinctParentheses } = {}) {
|
|
377
|
-
const value = stmt.value;
|
|
378
|
-
const method = stmt.method;
|
|
379
|
-
const distinct = stmt.aggregateDistinct ? 'distinct ' : '';
|
|
380
|
-
const wrap = (identifier) =>
|
|
381
|
-
wrap_(
|
|
382
|
-
identifier,
|
|
383
|
-
undefined,
|
|
384
|
-
this.builder,
|
|
385
|
-
this.client,
|
|
386
|
-
this.bindingsHolder
|
|
387
|
-
);
|
|
388
|
-
const addAlias = (value, alias) => {
|
|
389
|
-
if (alias) {
|
|
390
|
-
return value + aliasSeparator + wrap(alias);
|
|
391
|
-
}
|
|
392
|
-
return value;
|
|
393
|
-
};
|
|
394
|
-
const aggregateArray = (value, alias) => {
|
|
395
|
-
let columns = value.map(wrap).join(', ');
|
|
396
|
-
if (distinct) {
|
|
397
|
-
const openParen = distinctParentheses ? '(' : ' ';
|
|
398
|
-
const closeParen = distinctParentheses ? ')' : '';
|
|
399
|
-
columns = distinct.trim() + openParen + columns + closeParen;
|
|
400
|
-
}
|
|
401
|
-
const aggregated = `${method}(${columns})`;
|
|
402
|
-
return addAlias(aggregated, alias);
|
|
403
|
-
};
|
|
404
|
-
const aggregateString = (value, alias) => {
|
|
405
|
-
const aggregated = `${method}(${distinct + wrap(value)})`;
|
|
406
|
-
return addAlias(aggregated, alias);
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
if (Array.isArray(value)) {
|
|
410
|
-
return [aggregateArray(value)];
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (typeof value === 'object') {
|
|
414
|
-
if (stmt.alias) {
|
|
415
|
-
throw new Error('When using an object explicit alias can not be used');
|
|
416
|
-
}
|
|
417
|
-
return Object.entries(value).map(([alias, column]) => {
|
|
418
|
-
if (Array.isArray(column)) {
|
|
419
|
-
return aggregateArray(column, alias);
|
|
420
|
-
}
|
|
421
|
-
return aggregateString(column, alias);
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// Allows us to speciy an alias for the aggregate types.
|
|
426
|
-
const splitOn = value.toLowerCase().indexOf(' as ');
|
|
427
|
-
let column = value;
|
|
428
|
-
let { alias } = stmt;
|
|
429
|
-
if (splitOn !== -1) {
|
|
430
|
-
column = value.slice(0, splitOn);
|
|
431
|
-
if (alias) {
|
|
432
|
-
throw new Error(`Found multiple aliases for same column: ${column}`);
|
|
433
|
-
}
|
|
434
|
-
alias = value.slice(splitOn + 4);
|
|
435
|
-
}
|
|
436
|
-
return [aggregateString(column, alias)];
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
aggregate(stmt) {
|
|
440
|
-
return this._aggregate(stmt);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
aggregateRaw(stmt) {
|
|
444
|
-
const distinct = stmt.aggregateDistinct ? 'distinct ' : '';
|
|
445
|
-
return `${stmt.method}(${
|
|
446
|
-
distinct +
|
|
447
|
-
unwrapRaw_(
|
|
448
|
-
stmt.value,
|
|
449
|
-
undefined,
|
|
450
|
-
this.builder,
|
|
451
|
-
this.client,
|
|
452
|
-
this.bindingsHolder
|
|
453
|
-
)
|
|
454
|
-
})`;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
_joinTable(join) {
|
|
458
|
-
return join.schema && !(join.table instanceof Raw)
|
|
459
|
-
? `${join.schema}.${join.table}`
|
|
460
|
-
: join.table;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Compiles all each of the `join` clauses on the query,
|
|
464
|
-
// including any nested join queries.
|
|
465
|
-
join() {
|
|
466
|
-
let sql = '';
|
|
467
|
-
let i = -1;
|
|
468
|
-
const joins = this.grouped.join;
|
|
469
|
-
if (!joins) return '';
|
|
470
|
-
while (++i < joins.length) {
|
|
471
|
-
const join = joins[i];
|
|
472
|
-
const table = this._joinTable(join);
|
|
473
|
-
if (i > 0) sql += ' ';
|
|
474
|
-
if (join.joinType === 'raw') {
|
|
475
|
-
sql += unwrapRaw_(
|
|
476
|
-
join.table,
|
|
477
|
-
undefined,
|
|
478
|
-
this.builder,
|
|
479
|
-
this.client,
|
|
480
|
-
this.bindingsHolder
|
|
481
|
-
);
|
|
482
|
-
} else {
|
|
483
|
-
sql +=
|
|
484
|
-
join.joinType +
|
|
485
|
-
' join ' +
|
|
486
|
-
wrap_(
|
|
487
|
-
table,
|
|
488
|
-
undefined,
|
|
489
|
-
this.builder,
|
|
490
|
-
this.client,
|
|
491
|
-
this.bindingsHolder
|
|
492
|
-
);
|
|
493
|
-
let ii = -1;
|
|
494
|
-
while (++ii < join.clauses.length) {
|
|
495
|
-
const clause = join.clauses[ii];
|
|
496
|
-
if (ii > 0) {
|
|
497
|
-
sql += ` ${clause.bool} `;
|
|
498
|
-
} else {
|
|
499
|
-
sql += ` ${clause.type === 'onUsing' ? 'using' : 'on'} `;
|
|
500
|
-
}
|
|
501
|
-
const val = this[clause.type](clause);
|
|
502
|
-
if (val) {
|
|
503
|
-
sql += val;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return sql;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
onBetween(statement) {
|
|
512
|
-
return (
|
|
513
|
-
wrap_(
|
|
514
|
-
statement.column,
|
|
515
|
-
undefined,
|
|
516
|
-
this.builder,
|
|
517
|
-
this.client,
|
|
518
|
-
this.bindingsHolder
|
|
519
|
-
) +
|
|
520
|
-
' ' +
|
|
521
|
-
this._not(statement, 'between') +
|
|
522
|
-
' ' +
|
|
523
|
-
statement.value
|
|
524
|
-
.map((value) =>
|
|
525
|
-
this.client.parameter(value, this.builder, this.bindingsHolder)
|
|
526
|
-
)
|
|
527
|
-
.join(' and ')
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
onNull(statement) {
|
|
532
|
-
return (
|
|
533
|
-
wrap_(
|
|
534
|
-
statement.column,
|
|
535
|
-
undefined,
|
|
536
|
-
this.builder,
|
|
537
|
-
this.client,
|
|
538
|
-
this.bindingsHolder
|
|
539
|
-
) +
|
|
540
|
-
' is ' +
|
|
541
|
-
this._not(statement, 'null')
|
|
542
|
-
);
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
onExists(statement) {
|
|
546
|
-
return (
|
|
547
|
-
this._not(statement, 'exists') +
|
|
548
|
-
' (' +
|
|
549
|
-
rawOrFn_(
|
|
550
|
-
statement.value,
|
|
551
|
-
undefined,
|
|
552
|
-
this.builder,
|
|
553
|
-
this.client,
|
|
554
|
-
this.bindingsHolder
|
|
555
|
-
) +
|
|
556
|
-
')'
|
|
557
|
-
);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
onIn(statement) {
|
|
561
|
-
if (Array.isArray(statement.column)) return this.multiOnIn(statement);
|
|
562
|
-
|
|
563
|
-
let values;
|
|
564
|
-
if (statement.value instanceof Raw) {
|
|
565
|
-
values = this.client.parameter(
|
|
566
|
-
statement.value,
|
|
567
|
-
this.builder,
|
|
568
|
-
this.formatter
|
|
569
|
-
);
|
|
570
|
-
} else {
|
|
571
|
-
values = this.client.parameterize(
|
|
572
|
-
statement.value,
|
|
573
|
-
undefined,
|
|
574
|
-
this.builder,
|
|
575
|
-
this.bindingsHolder
|
|
576
|
-
);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
return (
|
|
580
|
-
wrap_(
|
|
581
|
-
statement.column,
|
|
582
|
-
undefined,
|
|
583
|
-
this.builder,
|
|
584
|
-
this.client,
|
|
585
|
-
this.bindingsHolder
|
|
586
|
-
) +
|
|
587
|
-
' ' +
|
|
588
|
-
this._not(statement, 'in ') +
|
|
589
|
-
this.wrap(values)
|
|
590
|
-
);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
multiOnIn(statement) {
|
|
594
|
-
let i = -1,
|
|
595
|
-
sql = `(${columnize_(
|
|
596
|
-
statement.column,
|
|
597
|
-
this.builder,
|
|
598
|
-
this.client,
|
|
599
|
-
this.bindingsHolder
|
|
600
|
-
)}) `;
|
|
601
|
-
sql += this._not(statement, 'in ') + '((';
|
|
602
|
-
while (++i < statement.value.length) {
|
|
603
|
-
if (i !== 0) sql += '),(';
|
|
604
|
-
sql += this.client.parameterize(
|
|
605
|
-
statement.value[i],
|
|
606
|
-
undefined,
|
|
607
|
-
this.builder,
|
|
608
|
-
this.bindingsHolder
|
|
609
|
-
);
|
|
610
|
-
}
|
|
611
|
-
return sql + '))';
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// Compiles all `where` statements on the query.
|
|
615
|
-
where() {
|
|
616
|
-
const wheres = this.grouped.where;
|
|
617
|
-
if (!wheres) return;
|
|
618
|
-
const sql = [];
|
|
619
|
-
let i = -1;
|
|
620
|
-
while (++i < wheres.length) {
|
|
621
|
-
const stmt = wheres[i];
|
|
622
|
-
if (
|
|
623
|
-
Object.prototype.hasOwnProperty.call(stmt, 'value') &&
|
|
624
|
-
helpers.containsUndefined(stmt.value)
|
|
625
|
-
) {
|
|
626
|
-
this.undefinedBindingsInfo.push(stmt.column);
|
|
627
|
-
this._undefinedInWhereClause = true;
|
|
628
|
-
}
|
|
629
|
-
const val = this[stmt.type](stmt);
|
|
630
|
-
if (val) {
|
|
631
|
-
if (sql.length === 0) {
|
|
632
|
-
sql[0] = 'where';
|
|
633
|
-
} else {
|
|
634
|
-
sql.push(stmt.bool);
|
|
635
|
-
}
|
|
636
|
-
sql.push(val);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
return sql.length > 1 ? sql.join(' ') : '';
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
group() {
|
|
643
|
-
return this._groupsOrders('group');
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
order() {
|
|
647
|
-
return this._groupsOrders('order');
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// Compiles the `having` statements.
|
|
651
|
-
having() {
|
|
652
|
-
const havings = this.grouped.having;
|
|
653
|
-
if (!havings) return '';
|
|
654
|
-
const sql = ['having'];
|
|
655
|
-
for (let i = 0, l = havings.length; i < l; i++) {
|
|
656
|
-
const s = havings[i];
|
|
657
|
-
const val = this[s.type](s);
|
|
658
|
-
if (val) {
|
|
659
|
-
if (sql.length === 0) {
|
|
660
|
-
sql[0] = 'where';
|
|
661
|
-
}
|
|
662
|
-
if (sql.length > 1 || (sql.length === 1 && sql[0] !== 'having')) {
|
|
663
|
-
sql.push(s.bool);
|
|
664
|
-
}
|
|
665
|
-
sql.push(val);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
return sql.length > 1 ? sql.join(' ') : '';
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
havingRaw(statement) {
|
|
672
|
-
return (
|
|
673
|
-
this._not(statement, '') +
|
|
674
|
-
unwrapRaw_(
|
|
675
|
-
statement.value,
|
|
676
|
-
undefined,
|
|
677
|
-
this.builder,
|
|
678
|
-
this.client,
|
|
679
|
-
this.bindingsHolder
|
|
680
|
-
)
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
havingWrapped(statement) {
|
|
685
|
-
const val = rawOrFn_(
|
|
686
|
-
statement.value,
|
|
687
|
-
'where',
|
|
688
|
-
this.builder,
|
|
689
|
-
this.client,
|
|
690
|
-
this.bindingsHolder
|
|
691
|
-
);
|
|
692
|
-
return (val && this._not(statement, '') + '(' + val.slice(6) + ')') || '';
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
havingBasic(statement) {
|
|
696
|
-
return (
|
|
697
|
-
this._not(statement, '') +
|
|
698
|
-
wrap_(
|
|
699
|
-
statement.column,
|
|
700
|
-
undefined,
|
|
701
|
-
this.builder,
|
|
702
|
-
this.client,
|
|
703
|
-
this.bindingsHolder
|
|
704
|
-
) +
|
|
705
|
-
' ' +
|
|
706
|
-
operator_(
|
|
707
|
-
statement.operator,
|
|
708
|
-
this.builder,
|
|
709
|
-
this.client,
|
|
710
|
-
this.bindingsHolder
|
|
711
|
-
) +
|
|
712
|
-
' ' +
|
|
713
|
-
this.client.parameter(statement.value, this.builder, this.bindingsHolder)
|
|
714
|
-
);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
havingNull(statement) {
|
|
718
|
-
return (
|
|
719
|
-
wrap_(
|
|
720
|
-
statement.column,
|
|
721
|
-
undefined,
|
|
722
|
-
this.builder,
|
|
723
|
-
this.client,
|
|
724
|
-
this.bindingsHolder
|
|
725
|
-
) +
|
|
726
|
-
' is ' +
|
|
727
|
-
this._not(statement, 'null')
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
havingExists(statement) {
|
|
732
|
-
return (
|
|
733
|
-
this._not(statement, 'exists') +
|
|
734
|
-
' (' +
|
|
735
|
-
rawOrFn_(
|
|
736
|
-
statement.value,
|
|
737
|
-
undefined,
|
|
738
|
-
this.builder,
|
|
739
|
-
this.client,
|
|
740
|
-
this.bindingsHolder
|
|
741
|
-
) +
|
|
742
|
-
')'
|
|
743
|
-
);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
havingBetween(statement) {
|
|
747
|
-
return (
|
|
748
|
-
wrap_(
|
|
749
|
-
statement.column,
|
|
750
|
-
undefined,
|
|
751
|
-
this.builder,
|
|
752
|
-
this.client,
|
|
753
|
-
this.bindingsHolder
|
|
754
|
-
) +
|
|
755
|
-
' ' +
|
|
756
|
-
this._not(statement, 'between') +
|
|
757
|
-
' ' +
|
|
758
|
-
statement.value
|
|
759
|
-
.map((value) =>
|
|
760
|
-
this.client.parameter(value, this.builder, this.bindingsHolder)
|
|
761
|
-
)
|
|
762
|
-
.join(' and ')
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
havingIn(statement) {
|
|
767
|
-
if (Array.isArray(statement.column)) return this.multiHavingIn(statement);
|
|
768
|
-
return (
|
|
769
|
-
wrap_(
|
|
770
|
-
statement.column,
|
|
771
|
-
undefined,
|
|
772
|
-
this.builder,
|
|
773
|
-
this.client,
|
|
774
|
-
this.bindingsHolder
|
|
775
|
-
) +
|
|
776
|
-
' ' +
|
|
777
|
-
this._not(statement, 'in ') +
|
|
778
|
-
this.wrap(
|
|
779
|
-
this.client.parameterize(
|
|
780
|
-
statement.value,
|
|
781
|
-
undefined,
|
|
782
|
-
this.builder,
|
|
783
|
-
this.bindingsHolder
|
|
784
|
-
)
|
|
785
|
-
)
|
|
786
|
-
);
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
multiHavingIn(statement) {
|
|
790
|
-
return this.multiOnIn(statement);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// Compile the "union" queries attached to the main query.
|
|
794
|
-
union() {
|
|
795
|
-
const onlyUnions = this.onlyUnions();
|
|
796
|
-
const unions = this.grouped.union;
|
|
797
|
-
if (!unions) return '';
|
|
798
|
-
let sql = '';
|
|
799
|
-
for (let i = 0, l = unions.length; i < l; i++) {
|
|
800
|
-
const union = unions[i];
|
|
801
|
-
if (i > 0) sql += ' ';
|
|
802
|
-
if (i > 0 || !onlyUnions) sql += union.clause + ' ';
|
|
803
|
-
const statement = rawOrFn_(
|
|
804
|
-
union.value,
|
|
805
|
-
undefined,
|
|
806
|
-
this.builder,
|
|
807
|
-
this.client,
|
|
808
|
-
this.bindingsHolder
|
|
809
|
-
);
|
|
810
|
-
if (statement) {
|
|
811
|
-
const wrap = union.wrap;
|
|
812
|
-
if (wrap) sql += '(';
|
|
813
|
-
sql += statement;
|
|
814
|
-
if (wrap) sql += ')';
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
return sql;
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
// If we haven't specified any columns or a `tableName`, we're assuming this
|
|
821
|
-
// is only being used for unions.
|
|
822
|
-
onlyUnions() {
|
|
823
|
-
return (
|
|
824
|
-
(!this.grouped.columns || !!this.grouped.columns[0].value) &&
|
|
825
|
-
this.grouped.union &&
|
|
826
|
-
!this.tableName
|
|
827
|
-
);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
_getValueOrParameterFromAttribute(attribute, rawValue) {
|
|
831
|
-
if (this.single.skipBinding[attribute] === true) {
|
|
832
|
-
return rawValue !== undefined && rawValue !== null
|
|
833
|
-
? rawValue
|
|
834
|
-
: this.single[attribute];
|
|
835
|
-
}
|
|
836
|
-
return this.client.parameter(
|
|
837
|
-
this.single[attribute],
|
|
838
|
-
this.builder,
|
|
839
|
-
this.bindingsHolder
|
|
840
|
-
);
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
onlyJson() {
|
|
844
|
-
return (
|
|
845
|
-
!this.tableName &&
|
|
846
|
-
this.grouped.columns &&
|
|
847
|
-
this.grouped.columns.length === 1 &&
|
|
848
|
-
this.grouped.columns[0].type === 'json'
|
|
849
|
-
);
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
limit() {
|
|
853
|
-
const noLimit = !this.single.limit && this.single.limit !== 0;
|
|
854
|
-
if (noLimit) return '';
|
|
855
|
-
return `limit ${this._getValueOrParameterFromAttribute('limit')}`;
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
offset() {
|
|
859
|
-
if (!this.single.offset) return '';
|
|
860
|
-
return `offset ${this._getValueOrParameterFromAttribute('offset')}`;
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
// Compiles a `delete` query.
|
|
864
|
-
del() {
|
|
865
|
-
// Make sure tableName is processed by the formatter first.
|
|
866
|
-
const { tableName } = this;
|
|
867
|
-
const withSQL = this.with();
|
|
868
|
-
const wheres = this.where();
|
|
869
|
-
const joins = this.join();
|
|
870
|
-
// When using joins, delete the "from" table values as a default
|
|
871
|
-
const deleteSelector = joins ? tableName + ' ' : '';
|
|
872
|
-
return (
|
|
873
|
-
withSQL +
|
|
874
|
-
`delete ${deleteSelector}from ${
|
|
875
|
-
this.single.only ? 'only ' : ''
|
|
876
|
-
}${tableName}` +
|
|
877
|
-
(joins ? ` ${joins}` : '') +
|
|
878
|
-
(wheres ? ` ${wheres}` : '')
|
|
879
|
-
);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// Compiles a `truncate` query.
|
|
883
|
-
truncate() {
|
|
884
|
-
return `truncate ${this.tableName}`;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
// Compiles the "locks".
|
|
888
|
-
lock() {
|
|
889
|
-
if (this.single.lock) {
|
|
890
|
-
return this[this.single.lock]();
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
// Compiles the wait mode on the locks.
|
|
895
|
-
waitMode() {
|
|
896
|
-
if (this.single.waitMode) {
|
|
897
|
-
return this[this.single.waitMode]();
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
// Fail on unsupported databases
|
|
902
|
-
skipLocked() {
|
|
903
|
-
throw new Error(
|
|
904
|
-
'.skipLocked() is currently only supported on MySQL 8.0+ and PostgreSQL 9.5+'
|
|
905
|
-
);
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// Fail on unsupported databases
|
|
909
|
-
noWait() {
|
|
910
|
-
throw new Error(
|
|
911
|
-
'.noWait() is currently only supported on MySQL 8.0+, MariaDB 10.3.0+ and PostgreSQL 9.5+'
|
|
912
|
-
);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
distinctOn(value) {
|
|
916
|
-
throw new Error('.distinctOn() is currently only supported on PostgreSQL');
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// On Clause
|
|
920
|
-
// ------
|
|
921
|
-
|
|
922
|
-
onWrapped(clause) {
|
|
923
|
-
const self = this;
|
|
924
|
-
|
|
925
|
-
const wrapJoin = new JoinClause();
|
|
926
|
-
clause.value.call(wrapJoin, wrapJoin);
|
|
927
|
-
|
|
928
|
-
let sql = '';
|
|
929
|
-
|
|
930
|
-
for (let ii = 0; ii < wrapJoin.clauses.length; ii++) {
|
|
931
|
-
const wrapClause = wrapJoin.clauses[ii];
|
|
932
|
-
if (ii > 0) {
|
|
933
|
-
sql += ` ${wrapClause.bool} `;
|
|
934
|
-
}
|
|
935
|
-
const val = self[wrapClause.type](wrapClause);
|
|
936
|
-
if (val) {
|
|
937
|
-
sql += val;
|
|
938
|
-
}
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
if (sql.length) {
|
|
942
|
-
return `(${sql})`;
|
|
943
|
-
}
|
|
944
|
-
return '';
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
onBasic(clause) {
|
|
948
|
-
const toWrap = clause.value instanceof QueryBuilder;
|
|
949
|
-
return (
|
|
950
|
-
wrap_(
|
|
951
|
-
clause.column,
|
|
952
|
-
undefined,
|
|
953
|
-
this.builder,
|
|
954
|
-
this.client,
|
|
955
|
-
this.bindingsHolder
|
|
956
|
-
) +
|
|
957
|
-
' ' +
|
|
958
|
-
operator_(
|
|
959
|
-
clause.operator,
|
|
960
|
-
this.builder,
|
|
961
|
-
this.client,
|
|
962
|
-
this.bindingsHolder
|
|
963
|
-
) +
|
|
964
|
-
' ' +
|
|
965
|
-
(toWrap ? '(' : '') +
|
|
966
|
-
wrap_(
|
|
967
|
-
clause.value,
|
|
968
|
-
undefined,
|
|
969
|
-
this.builder,
|
|
970
|
-
this.client,
|
|
971
|
-
this.bindingsHolder
|
|
972
|
-
) +
|
|
973
|
-
(toWrap ? ')' : '')
|
|
974
|
-
);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
onVal(clause) {
|
|
978
|
-
return (
|
|
979
|
-
wrap_(
|
|
980
|
-
clause.column,
|
|
981
|
-
undefined,
|
|
982
|
-
this.builder,
|
|
983
|
-
this.client,
|
|
984
|
-
this.bindingsHolder
|
|
985
|
-
) +
|
|
986
|
-
' ' +
|
|
987
|
-
operator_(
|
|
988
|
-
clause.operator,
|
|
989
|
-
this.builder,
|
|
990
|
-
this.client,
|
|
991
|
-
this.bindingsHolder
|
|
992
|
-
) +
|
|
993
|
-
' ' +
|
|
994
|
-
this.client.parameter(clause.value, this.builder, this.bindingsHolder)
|
|
995
|
-
);
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
onRaw(clause) {
|
|
999
|
-
return unwrapRaw_(
|
|
1000
|
-
clause.value,
|
|
1001
|
-
undefined,
|
|
1002
|
-
this.builder,
|
|
1003
|
-
this.client,
|
|
1004
|
-
this.bindingsHolder
|
|
1005
|
-
);
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
onUsing(clause) {
|
|
1009
|
-
return (
|
|
1010
|
-
'(' +
|
|
1011
|
-
columnize_(
|
|
1012
|
-
clause.column,
|
|
1013
|
-
this.builder,
|
|
1014
|
-
this.client,
|
|
1015
|
-
this.bindingsHolder
|
|
1016
|
-
) +
|
|
1017
|
-
')'
|
|
1018
|
-
);
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// Where Clause
|
|
1022
|
-
// ------
|
|
1023
|
-
|
|
1024
|
-
_valueClause(statement) {
|
|
1025
|
-
return statement.asColumn
|
|
1026
|
-
? wrap_(
|
|
1027
|
-
statement.value,
|
|
1028
|
-
undefined,
|
|
1029
|
-
this.builder,
|
|
1030
|
-
this.client,
|
|
1031
|
-
this.bindingsHolder
|
|
1032
|
-
)
|
|
1033
|
-
: this.client.parameter(
|
|
1034
|
-
statement.value,
|
|
1035
|
-
this.builder,
|
|
1036
|
-
this.bindingsHolder
|
|
1037
|
-
);
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
_columnClause(statement) {
|
|
1041
|
-
let columns;
|
|
1042
|
-
if (Array.isArray(statement.column)) {
|
|
1043
|
-
columns = `(${columnize_(
|
|
1044
|
-
statement.column,
|
|
1045
|
-
this.builder,
|
|
1046
|
-
this.client,
|
|
1047
|
-
this.bindingsHolder
|
|
1048
|
-
)})`;
|
|
1049
|
-
} else {
|
|
1050
|
-
columns = wrap_(
|
|
1051
|
-
statement.column,
|
|
1052
|
-
undefined,
|
|
1053
|
-
this.builder,
|
|
1054
|
-
this.client,
|
|
1055
|
-
this.bindingsHolder
|
|
1056
|
-
);
|
|
1057
|
-
}
|
|
1058
|
-
return columns;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
whereIn(statement) {
|
|
1062
|
-
const columns = this._columnClause(statement);
|
|
1063
|
-
const values = this.client.values(
|
|
1064
|
-
statement.value,
|
|
1065
|
-
this.builder,
|
|
1066
|
-
this.bindingsHolder
|
|
1067
|
-
);
|
|
1068
|
-
return `${columns} ${this._not(statement, 'in ')}${values}`;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
whereLike(statement) {
|
|
1072
|
-
return `${this._columnClause(statement)} ${this._not(
|
|
1073
|
-
statement,
|
|
1074
|
-
'like '
|
|
1075
|
-
)}${this._valueClause(statement)}`;
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
whereILike(statement) {
|
|
1079
|
-
return `${this._columnClause(statement)} ${this._not(
|
|
1080
|
-
statement,
|
|
1081
|
-
'ilike '
|
|
1082
|
-
)}${this._valueClause(statement)}`;
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
whereNull(statement) {
|
|
1086
|
-
return (
|
|
1087
|
-
wrap_(
|
|
1088
|
-
statement.column,
|
|
1089
|
-
undefined,
|
|
1090
|
-
this.builder,
|
|
1091
|
-
this.client,
|
|
1092
|
-
this.bindingsHolder
|
|
1093
|
-
) +
|
|
1094
|
-
' is ' +
|
|
1095
|
-
this._not(statement, 'null')
|
|
1096
|
-
);
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
// Compiles a basic "where" clause.
|
|
1100
|
-
whereBasic(statement) {
|
|
1101
|
-
return (
|
|
1102
|
-
this._not(statement, '') +
|
|
1103
|
-
wrap_(
|
|
1104
|
-
statement.column,
|
|
1105
|
-
undefined,
|
|
1106
|
-
this.builder,
|
|
1107
|
-
this.client,
|
|
1108
|
-
this.bindingsHolder
|
|
1109
|
-
) +
|
|
1110
|
-
' ' +
|
|
1111
|
-
operator_(
|
|
1112
|
-
statement.operator,
|
|
1113
|
-
this.builder,
|
|
1114
|
-
this.client,
|
|
1115
|
-
this.bindingsHolder
|
|
1116
|
-
) +
|
|
1117
|
-
' ' +
|
|
1118
|
-
this._valueClause(statement)
|
|
1119
|
-
);
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
whereExists(statement) {
|
|
1123
|
-
return (
|
|
1124
|
-
this._not(statement, 'exists') +
|
|
1125
|
-
' (' +
|
|
1126
|
-
rawOrFn_(
|
|
1127
|
-
statement.value,
|
|
1128
|
-
undefined,
|
|
1129
|
-
this.builder,
|
|
1130
|
-
this.client,
|
|
1131
|
-
this.bindingsHolder
|
|
1132
|
-
) +
|
|
1133
|
-
')'
|
|
1134
|
-
);
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
whereWrapped(statement) {
|
|
1138
|
-
const val = rawOrFn_(
|
|
1139
|
-
statement.value,
|
|
1140
|
-
'where',
|
|
1141
|
-
this.builder,
|
|
1142
|
-
this.client,
|
|
1143
|
-
this.bindingsHolder
|
|
1144
|
-
);
|
|
1145
|
-
return (val && this._not(statement, '') + '(' + val.slice(6) + ')') || '';
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
whereBetween(statement) {
|
|
1149
|
-
return (
|
|
1150
|
-
wrap_(
|
|
1151
|
-
statement.column,
|
|
1152
|
-
undefined,
|
|
1153
|
-
this.builder,
|
|
1154
|
-
this.client,
|
|
1155
|
-
this.bindingsHolder
|
|
1156
|
-
) +
|
|
1157
|
-
' ' +
|
|
1158
|
-
this._not(statement, 'between') +
|
|
1159
|
-
' ' +
|
|
1160
|
-
statement.value
|
|
1161
|
-
.map((value) =>
|
|
1162
|
-
this.client.parameter(value, this.builder, this.bindingsHolder)
|
|
1163
|
-
)
|
|
1164
|
-
.join(' and ')
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
// Compiles a "whereRaw" query.
|
|
1169
|
-
whereRaw(statement) {
|
|
1170
|
-
return (
|
|
1171
|
-
this._not(statement, '') +
|
|
1172
|
-
unwrapRaw_(
|
|
1173
|
-
statement.value,
|
|
1174
|
-
undefined,
|
|
1175
|
-
this.builder,
|
|
1176
|
-
this.client,
|
|
1177
|
-
this.bindingsHolder
|
|
1178
|
-
)
|
|
1179
|
-
);
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
_jsonWrapValue(jsonValue) {
|
|
1183
|
-
if (!this.builder._isJsonObject(jsonValue)) {
|
|
1184
|
-
try {
|
|
1185
|
-
return JSON.stringify(JSON.parse(jsonValue.replace(/\n|\t/g, '')));
|
|
1186
|
-
} catch (e) {
|
|
1187
|
-
return jsonValue;
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
return JSON.stringify(jsonValue);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
_jsonValueClause(statement) {
|
|
1194
|
-
statement.value = this._jsonWrapValue(statement.value);
|
|
1195
|
-
return this._valueClause(statement);
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
whereJsonObject(statement) {
|
|
1199
|
-
return `${this._columnClause(statement)} ${
|
|
1200
|
-
statement.not ? '!=' : '='
|
|
1201
|
-
} ${this._jsonValueClause(statement)}`;
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
wrap(str) {
|
|
1205
|
-
if (str.charAt(0) !== '(') return `(${str})`;
|
|
1206
|
-
return str;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
json(stmt) {
|
|
1210
|
-
return this[stmt.method](stmt.params);
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
analytic(stmt) {
|
|
1214
|
-
let sql = '';
|
|
1215
|
-
const self = this;
|
|
1216
|
-
sql += stmt.method + '() over (';
|
|
1217
|
-
|
|
1218
|
-
if (stmt.raw) {
|
|
1219
|
-
sql += stmt.raw;
|
|
1220
|
-
} else {
|
|
1221
|
-
if (stmt.partitions.length) {
|
|
1222
|
-
sql += 'partition by ';
|
|
1223
|
-
sql +=
|
|
1224
|
-
map(stmt.partitions, function (partition) {
|
|
1225
|
-
if (isString(partition)) {
|
|
1226
|
-
return self.formatter.columnize(partition);
|
|
1227
|
-
} else return self.formatter.columnize(partition.column) + (partition.order ? ' ' + partition.order : '');
|
|
1228
|
-
}).join(', ') + ' ';
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
sql += 'order by ';
|
|
1232
|
-
sql += map(stmt.order, function (order) {
|
|
1233
|
-
if (isString(order)) {
|
|
1234
|
-
return self.formatter.columnize(order);
|
|
1235
|
-
} else return self.formatter.columnize(order.column) + (order.order ? ' ' + order.order : '');
|
|
1236
|
-
}).join(', ');
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
sql += ')';
|
|
1240
|
-
|
|
1241
|
-
if (stmt.alias) {
|
|
1242
|
-
sql += ' as ' + stmt.alias;
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
return sql;
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
// Compiles all `with` statements on the query.
|
|
1249
|
-
with() {
|
|
1250
|
-
if (!this.grouped.with || !this.grouped.with.length) {
|
|
1251
|
-
return '';
|
|
1252
|
-
}
|
|
1253
|
-
const withs = this.grouped.with;
|
|
1254
|
-
if (!withs) return;
|
|
1255
|
-
const sql = [];
|
|
1256
|
-
let i = -1;
|
|
1257
|
-
let isRecursive = false;
|
|
1258
|
-
while (++i < withs.length) {
|
|
1259
|
-
const stmt = withs[i];
|
|
1260
|
-
if (stmt.recursive) {
|
|
1261
|
-
isRecursive = true;
|
|
1262
|
-
}
|
|
1263
|
-
const val = this[stmt.type](stmt);
|
|
1264
|
-
sql.push(val);
|
|
1265
|
-
}
|
|
1266
|
-
return `with ${isRecursive ? 'recursive ' : ''}${sql.join(', ')} `;
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
withWrapped(statement) {
|
|
1270
|
-
const val = rawOrFn_(
|
|
1271
|
-
statement.value,
|
|
1272
|
-
undefined,
|
|
1273
|
-
this.builder,
|
|
1274
|
-
this.client,
|
|
1275
|
-
this.bindingsHolder
|
|
1276
|
-
);
|
|
1277
|
-
const columnList = statement.columnList
|
|
1278
|
-
? '(' +
|
|
1279
|
-
columnize_(
|
|
1280
|
-
statement.columnList,
|
|
1281
|
-
this.builder,
|
|
1282
|
-
this.client,
|
|
1283
|
-
this.bindingsHolder
|
|
1284
|
-
) +
|
|
1285
|
-
')'
|
|
1286
|
-
: '';
|
|
1287
|
-
const materialized =
|
|
1288
|
-
statement.materialized === undefined
|
|
1289
|
-
? ''
|
|
1290
|
-
: statement.materialized
|
|
1291
|
-
? 'materialized '
|
|
1292
|
-
: 'not materialized ';
|
|
1293
|
-
return (
|
|
1294
|
-
(val &&
|
|
1295
|
-
columnize_(
|
|
1296
|
-
statement.alias,
|
|
1297
|
-
this.builder,
|
|
1298
|
-
this.client,
|
|
1299
|
-
this.bindingsHolder
|
|
1300
|
-
) +
|
|
1301
|
-
columnList +
|
|
1302
|
-
' as ' +
|
|
1303
|
-
materialized +
|
|
1304
|
-
'(' +
|
|
1305
|
-
val +
|
|
1306
|
-
')') ||
|
|
1307
|
-
''
|
|
1308
|
-
);
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
// Determines whether to add a "not" prefix to the where clause.
|
|
1312
|
-
_not(statement, str) {
|
|
1313
|
-
if (statement.not) return `not ${str}`;
|
|
1314
|
-
return str;
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
_prepInsert(data) {
|
|
1318
|
-
const isRaw = rawOrFn_(
|
|
1319
|
-
data,
|
|
1320
|
-
undefined,
|
|
1321
|
-
this.builder,
|
|
1322
|
-
this.client,
|
|
1323
|
-
this.bindingsHolder
|
|
1324
|
-
);
|
|
1325
|
-
if (isRaw) return isRaw;
|
|
1326
|
-
let columns = [];
|
|
1327
|
-
const values = [];
|
|
1328
|
-
if (!Array.isArray(data)) data = data ? [data] : [];
|
|
1329
|
-
let i = -1;
|
|
1330
|
-
while (++i < data.length) {
|
|
1331
|
-
if (data[i] == null) break;
|
|
1332
|
-
if (i === 0) columns = Object.keys(data[i]).sort();
|
|
1333
|
-
const row = new Array(columns.length);
|
|
1334
|
-
const keys = Object.keys(data[i]);
|
|
1335
|
-
let j = -1;
|
|
1336
|
-
while (++j < keys.length) {
|
|
1337
|
-
const key = keys[j];
|
|
1338
|
-
let idx = columns.indexOf(key);
|
|
1339
|
-
if (idx === -1) {
|
|
1340
|
-
columns = columns.concat(key).sort();
|
|
1341
|
-
idx = columns.indexOf(key);
|
|
1342
|
-
let k = -1;
|
|
1343
|
-
while (++k < values.length) {
|
|
1344
|
-
values[k].splice(idx, 0, undefined);
|
|
1345
|
-
}
|
|
1346
|
-
row.splice(idx, 0, undefined);
|
|
1347
|
-
}
|
|
1348
|
-
row[idx] = data[i][key];
|
|
1349
|
-
}
|
|
1350
|
-
values.push(row);
|
|
1351
|
-
}
|
|
1352
|
-
return {
|
|
1353
|
-
columns,
|
|
1354
|
-
values,
|
|
1355
|
-
};
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
// "Preps" the update.
|
|
1359
|
-
_prepUpdate(data = {}) {
|
|
1360
|
-
const { counter = {} } = this.single;
|
|
1361
|
-
|
|
1362
|
-
for (const column of Object.keys(counter)) {
|
|
1363
|
-
//Skip?
|
|
1364
|
-
if (has(data, column)) {
|
|
1365
|
-
//Needed?
|
|
1366
|
-
this.client.logger.warn(
|
|
1367
|
-
`increment/decrement called for a column that has already been specified in main .update() call. Ignoring increment/decrement and using value from .update() call.`
|
|
1368
|
-
);
|
|
1369
|
-
continue;
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
let value = counter[column];
|
|
1373
|
-
|
|
1374
|
-
const symbol = value < 0 ? '-' : '+';
|
|
1375
|
-
|
|
1376
|
-
if (symbol === '-') {
|
|
1377
|
-
value = -value;
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
data[column] = this.client.raw(`?? ${symbol} ?`, [column, value]);
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
data = omitBy(data, isUndefined);
|
|
1384
|
-
|
|
1385
|
-
const vals = [];
|
|
1386
|
-
const columns = Object.keys(data);
|
|
1387
|
-
let i = -1;
|
|
1388
|
-
|
|
1389
|
-
while (++i < columns.length) {
|
|
1390
|
-
vals.push(
|
|
1391
|
-
wrap_(
|
|
1392
|
-
columns[i],
|
|
1393
|
-
undefined,
|
|
1394
|
-
this.builder,
|
|
1395
|
-
this.client,
|
|
1396
|
-
this.bindingsHolder
|
|
1397
|
-
) +
|
|
1398
|
-
' = ' +
|
|
1399
|
-
this.client.parameter(
|
|
1400
|
-
data[columns[i]],
|
|
1401
|
-
this.builder,
|
|
1402
|
-
this.bindingsHolder
|
|
1403
|
-
)
|
|
1404
|
-
);
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
if (isEmpty(vals)) {
|
|
1408
|
-
throw new Error(
|
|
1409
|
-
[
|
|
1410
|
-
'Empty .update() call detected!',
|
|
1411
|
-
'Update data does not contain any values to update.',
|
|
1412
|
-
'This will result in a faulty query.',
|
|
1413
|
-
this.single.table ? `Table: ${this.single.table}.` : '',
|
|
1414
|
-
this.single.update
|
|
1415
|
-
? `Columns: ${Object.keys(this.single.update)}.`
|
|
1416
|
-
: '',
|
|
1417
|
-
].join(' ')
|
|
1418
|
-
);
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
return vals;
|
|
1422
|
-
}
|
|
1423
|
-
|
|
1424
|
-
_formatGroupsItemValue(value, nulls) {
|
|
1425
|
-
const { formatter } = this;
|
|
1426
|
-
let nullOrder = '';
|
|
1427
|
-
if (nulls === 'last') {
|
|
1428
|
-
nullOrder = ' is null';
|
|
1429
|
-
} else if (nulls === 'first') {
|
|
1430
|
-
nullOrder = ' is not null';
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
let groupOrder;
|
|
1434
|
-
if (value instanceof Raw) {
|
|
1435
|
-
groupOrder = unwrapRaw_(
|
|
1436
|
-
value,
|
|
1437
|
-
undefined,
|
|
1438
|
-
this.builder,
|
|
1439
|
-
this.client,
|
|
1440
|
-
this.bindingsHolder
|
|
1441
|
-
);
|
|
1442
|
-
} else if (value instanceof QueryBuilder || nulls) {
|
|
1443
|
-
groupOrder = '(' + formatter.columnize(value) + nullOrder + ')';
|
|
1444
|
-
} else {
|
|
1445
|
-
groupOrder = formatter.columnize(value);
|
|
1446
|
-
}
|
|
1447
|
-
return groupOrder;
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
|
-
_basicGroupOrder(item, type) {
|
|
1451
|
-
const column = this._formatGroupsItemValue(item.value, item.nulls);
|
|
1452
|
-
const direction =
|
|
1453
|
-
type === 'order' && item.type !== 'orderByRaw'
|
|
1454
|
-
? ` ${direction_(
|
|
1455
|
-
item.direction,
|
|
1456
|
-
this.builder,
|
|
1457
|
-
this.client,
|
|
1458
|
-
this.bindingsHolder
|
|
1459
|
-
)}`
|
|
1460
|
-
: '';
|
|
1461
|
-
return column + direction;
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
_groupOrder(item, type) {
|
|
1465
|
-
return this._basicGroupOrder(item, type);
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
_groupOrderNulls(item, type) {
|
|
1469
|
-
const column = this._formatGroupsItemValue(item.value);
|
|
1470
|
-
const direction =
|
|
1471
|
-
type === 'order' && item.type !== 'orderByRaw'
|
|
1472
|
-
? ` ${direction_(
|
|
1473
|
-
item.direction,
|
|
1474
|
-
this.builder,
|
|
1475
|
-
this.client,
|
|
1476
|
-
this.bindingsHolder
|
|
1477
|
-
)}`
|
|
1478
|
-
: '';
|
|
1479
|
-
if (item.nulls && !(item.value instanceof Raw)) {
|
|
1480
|
-
return `${column}${direction ? direction : ''} nulls ${item.nulls}`;
|
|
1481
|
-
}
|
|
1482
|
-
return column + direction;
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
// Compiles the `order by` statements.
|
|
1486
|
-
_groupsOrders(type) {
|
|
1487
|
-
const items = this.grouped[type];
|
|
1488
|
-
if (!items) return '';
|
|
1489
|
-
const sql = items.map((item) => {
|
|
1490
|
-
return this._groupOrder(item, type);
|
|
1491
|
-
});
|
|
1492
|
-
return sql.length ? type + ' by ' + sql.join(', ') : '';
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
// Get the table name, wrapping it if necessary.
|
|
1496
|
-
// Implemented as a property to prevent ordering issues as described in #704.
|
|
1497
|
-
get tableName() {
|
|
1498
|
-
if (!this._tableName) {
|
|
1499
|
-
// Only call this.formatter.wrap() the first time this property is accessed.
|
|
1500
|
-
let tableName = this.single.table;
|
|
1501
|
-
const schemaName = this.single.schema;
|
|
1502
|
-
|
|
1503
|
-
if (tableName && schemaName) {
|
|
1504
|
-
const isQueryBuilder = tableName instanceof QueryBuilder;
|
|
1505
|
-
const isRawQuery = tableName instanceof Raw;
|
|
1506
|
-
const isFunction = typeof tableName === 'function';
|
|
1507
|
-
|
|
1508
|
-
if (!isQueryBuilder && !isRawQuery && !isFunction) {
|
|
1509
|
-
tableName = `${schemaName}.${tableName}`;
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
this._tableName = tableName
|
|
1514
|
-
? // Wrap subQuery with parenthesis, #3485
|
|
1515
|
-
wrap_(
|
|
1516
|
-
tableName,
|
|
1517
|
-
tableName instanceof QueryBuilder,
|
|
1518
|
-
this.builder,
|
|
1519
|
-
this.client,
|
|
1520
|
-
this.bindingsHolder
|
|
1521
|
-
)
|
|
1522
|
-
: '';
|
|
1523
|
-
}
|
|
1524
|
-
return this._tableName;
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
_jsonPathWrap(extraction) {
|
|
1528
|
-
return this.client.parameter(
|
|
1529
|
-
extraction.path || extraction[1],
|
|
1530
|
-
this.builder,
|
|
1531
|
-
this.bindingsHolder
|
|
1532
|
-
);
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
// Json common functions
|
|
1536
|
-
_jsonExtract(nameFunction, params) {
|
|
1537
|
-
let extractions;
|
|
1538
|
-
if (Array.isArray(params.column)) {
|
|
1539
|
-
extractions = params.column;
|
|
1540
|
-
} else {
|
|
1541
|
-
extractions = [params];
|
|
1542
|
-
}
|
|
1543
|
-
if (!Array.isArray(nameFunction)) {
|
|
1544
|
-
nameFunction = [nameFunction];
|
|
1545
|
-
}
|
|
1546
|
-
return extractions
|
|
1547
|
-
.map((extraction) => {
|
|
1548
|
-
let jsonCol = `${columnize_(
|
|
1549
|
-
extraction.column || extraction[0],
|
|
1550
|
-
this.builder,
|
|
1551
|
-
this.client,
|
|
1552
|
-
this.bindingsHolder
|
|
1553
|
-
)}, ${this._jsonPathWrap(extraction)}`;
|
|
1554
|
-
nameFunction.forEach((f) => {
|
|
1555
|
-
jsonCol = f + '(' + jsonCol + ')';
|
|
1556
|
-
});
|
|
1557
|
-
const alias = extraction.alias || extraction[2];
|
|
1558
|
-
return alias
|
|
1559
|
-
? this.client.alias(jsonCol, this.formatter.wrap(alias))
|
|
1560
|
-
: jsonCol;
|
|
1561
|
-
})
|
|
1562
|
-
.join(', ');
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
_jsonSet(nameFunction, params) {
|
|
1566
|
-
const jsonSet = `${nameFunction}(${columnize_(
|
|
1567
|
-
params.column,
|
|
1568
|
-
this.builder,
|
|
1569
|
-
this.client,
|
|
1570
|
-
this.bindingsHolder
|
|
1571
|
-
)}, ${this.client.parameter(
|
|
1572
|
-
params.path,
|
|
1573
|
-
this.builder,
|
|
1574
|
-
this.bindingsHolder
|
|
1575
|
-
)}, ${this.client.parameter(
|
|
1576
|
-
params.value,
|
|
1577
|
-
this.builder,
|
|
1578
|
-
this.bindingsHolder
|
|
1579
|
-
)})`;
|
|
1580
|
-
return params.alias
|
|
1581
|
-
? this.client.alias(jsonSet, this.formatter.wrap(params.alias))
|
|
1582
|
-
: jsonSet;
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
_whereJsonPath(nameFunction, statement) {
|
|
1586
|
-
return `${nameFunction}(${this._columnClause(
|
|
1587
|
-
statement
|
|
1588
|
-
)}, ${this._jsonPathWrap({ path: statement.jsonPath })}) ${operator_(
|
|
1589
|
-
statement.operator,
|
|
1590
|
-
this.builder,
|
|
1591
|
-
this.client,
|
|
1592
|
-
this.bindingsHolder
|
|
1593
|
-
)} ${this._jsonValueClause(statement)}`;
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
_onJsonPathEquals(nameJoinFunction, clause) {
|
|
1597
|
-
return (
|
|
1598
|
-
nameJoinFunction +
|
|
1599
|
-
'(' +
|
|
1600
|
-
wrap_(
|
|
1601
|
-
clause.columnFirst,
|
|
1602
|
-
undefined,
|
|
1603
|
-
this.builder,
|
|
1604
|
-
this.client,
|
|
1605
|
-
this.bindingsHolder
|
|
1606
|
-
) +
|
|
1607
|
-
', ' +
|
|
1608
|
-
this.client.parameter(
|
|
1609
|
-
clause.jsonPathFirst,
|
|
1610
|
-
this.builder,
|
|
1611
|
-
this.bindingsHolder
|
|
1612
|
-
) +
|
|
1613
|
-
') = ' +
|
|
1614
|
-
nameJoinFunction +
|
|
1615
|
-
'(' +
|
|
1616
|
-
wrap_(
|
|
1617
|
-
clause.columnSecond,
|
|
1618
|
-
undefined,
|
|
1619
|
-
this.builder,
|
|
1620
|
-
this.client,
|
|
1621
|
-
this.bindingsHolder
|
|
1622
|
-
) +
|
|
1623
|
-
', ' +
|
|
1624
|
-
this.client.parameter(
|
|
1625
|
-
clause.jsonPathSecond,
|
|
1626
|
-
this.builder,
|
|
1627
|
-
this.bindingsHolder
|
|
1628
|
-
) +
|
|
1629
|
-
')'
|
|
1630
|
-
);
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
module.exports = QueryCompiler;
|
|
1
|
+
// Query Compiler
|
|
2
|
+
// -------
|
|
3
|
+
const helpers = require('../util/helpers');
|
|
4
|
+
const { hasOwn } = require('../util/security');
|
|
5
|
+
const Raw = require('../raw');
|
|
6
|
+
const QueryBuilder = require('./querybuilder');
|
|
7
|
+
const JoinClause = require('./joinclause');
|
|
8
|
+
const debug = require('debug');
|
|
9
|
+
|
|
10
|
+
const assign = require('lodash/assign');
|
|
11
|
+
const compact = require('lodash/compact');
|
|
12
|
+
const groupBy = require('lodash/groupBy');
|
|
13
|
+
const has = require('lodash/has');
|
|
14
|
+
const isEmpty = require('lodash/isEmpty');
|
|
15
|
+
const map = require('lodash/map');
|
|
16
|
+
const omitBy = require('lodash/omitBy');
|
|
17
|
+
const reduce = require('lodash/reduce');
|
|
18
|
+
const { nanoid } = require('../util/nanoid');
|
|
19
|
+
const { isString, isUndefined } = require('../util/is');
|
|
20
|
+
const {
|
|
21
|
+
columnize: columnize_,
|
|
22
|
+
direction: direction_,
|
|
23
|
+
operator: operator_,
|
|
24
|
+
wrap: wrap_,
|
|
25
|
+
unwrapRaw: unwrapRaw_,
|
|
26
|
+
rawOrFn: rawOrFn_,
|
|
27
|
+
} = require('../formatter/wrappingFormatter');
|
|
28
|
+
|
|
29
|
+
const debugBindings = debug('knex:bindings');
|
|
30
|
+
|
|
31
|
+
const components = [
|
|
32
|
+
'comments',
|
|
33
|
+
'columns',
|
|
34
|
+
'join',
|
|
35
|
+
'where',
|
|
36
|
+
'union',
|
|
37
|
+
'group',
|
|
38
|
+
'having',
|
|
39
|
+
'order',
|
|
40
|
+
'limit',
|
|
41
|
+
'offset',
|
|
42
|
+
'lock',
|
|
43
|
+
'waitMode',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const methodAliases = {
|
|
47
|
+
del: 'delete',
|
|
48
|
+
first: 'select',
|
|
49
|
+
pluck: 'select',
|
|
50
|
+
};
|
|
51
|
+
const invalidClauses = {
|
|
52
|
+
delete: ['having', 'limit'],
|
|
53
|
+
truncate: ['where', 'having', 'limit'],
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// The "QueryCompiler" takes all of the query statements which
|
|
57
|
+
// have been gathered in the "QueryBuilder" and turns them into a
|
|
58
|
+
// properly formatted / bound query string.
|
|
59
|
+
class QueryCompiler {
|
|
60
|
+
constructor(client, builder, bindings) {
|
|
61
|
+
this.client = client;
|
|
62
|
+
this.method = builder._method || 'select';
|
|
63
|
+
this.options = builder._options;
|
|
64
|
+
this.single = builder._single;
|
|
65
|
+
this.queryComments = builder._comments;
|
|
66
|
+
this.timeout = builder._timeout || false;
|
|
67
|
+
this.cancelOnTimeout = builder._cancelOnTimeout || false;
|
|
68
|
+
this.grouped = groupBy(builder._statements, 'grouping');
|
|
69
|
+
this.formatter = client.formatter(builder);
|
|
70
|
+
// Used when the insert call is empty.
|
|
71
|
+
this._emptyInsertValue = 'default values';
|
|
72
|
+
this.first = this.select;
|
|
73
|
+
|
|
74
|
+
this.bindings = bindings || [];
|
|
75
|
+
this.formatter.bindings = this.bindings;
|
|
76
|
+
this.bindingsHolder = this;
|
|
77
|
+
this.builder = this.formatter.builder;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Categorically refuse to execute certain queries that have defined certain clause groups
|
|
81
|
+
// For example, if a "having" clause is defined but we're executing a "delete" query, that
|
|
82
|
+
// is never valid in any of the supported dialects.
|
|
83
|
+
_preValidate() {
|
|
84
|
+
// Query builders don't really store the SQL verb they expect to generate; this would
|
|
85
|
+
// be nicer if we could avoid the fanout of "call an arbitrary method on one of a dozen
|
|
86
|
+
// classes". Instead, we keep an alias list to derive the expected intent from the
|
|
87
|
+
// methods used by the codebase for now.
|
|
88
|
+
const method = this.method;
|
|
89
|
+
const verb = hasOwn(methodAliases, method) ? methodAliases[method] : method;
|
|
90
|
+
if (!hasOwn(invalidClauses, verb)) return;
|
|
91
|
+
|
|
92
|
+
// For certain verbs, certain clauses just don't exist / aren't supported. The list
|
|
93
|
+
// here is intentionally not complete; it's just checking the things that allow users
|
|
94
|
+
// to make dangerous errors.
|
|
95
|
+
const invalid = invalidClauses[verb];
|
|
96
|
+
for (let i = 0; i < invalid.length; i++) {
|
|
97
|
+
const clause = invalid[i];
|
|
98
|
+
|
|
99
|
+
const hasNonEmptyGrouped =
|
|
100
|
+
hasOwn(this.grouped, clause) && this.grouped[clause].length > 0;
|
|
101
|
+
const hasNonEmptySingle =
|
|
102
|
+
hasOwn(this.single, clause) && this.single[clause] != null;
|
|
103
|
+
|
|
104
|
+
if (hasNonEmptyGrouped || hasNonEmptySingle) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Aborted query compilation: \`${clause}\` has no effect on a \`${verb}\` statement`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Collapse the builder into a single object
|
|
113
|
+
toSQL(method, tz) {
|
|
114
|
+
this._preValidate();
|
|
115
|
+
|
|
116
|
+
this._undefinedInWhereClause = false;
|
|
117
|
+
this.undefinedBindingsInfo = [];
|
|
118
|
+
|
|
119
|
+
method = method || this.method;
|
|
120
|
+
const val = this[method]() || '';
|
|
121
|
+
|
|
122
|
+
const query = {
|
|
123
|
+
method,
|
|
124
|
+
options: reduce(this.options, assign, {}),
|
|
125
|
+
timeout: this.timeout,
|
|
126
|
+
cancelOnTimeout: this.cancelOnTimeout,
|
|
127
|
+
bindings: this.bindingsHolder.bindings || [],
|
|
128
|
+
__knexQueryUid: nanoid(),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
Object.defineProperties(query, {
|
|
132
|
+
toNative: {
|
|
133
|
+
value: () => {
|
|
134
|
+
return {
|
|
135
|
+
sql: this.client.positionBindings(query.sql),
|
|
136
|
+
bindings: this.client.prepBindings(query.bindings),
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
enumerable: false,
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
if (isString(val)) {
|
|
144
|
+
query.sql = val;
|
|
145
|
+
} else {
|
|
146
|
+
assign(query, val);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (method === 'select' || method === 'first') {
|
|
150
|
+
if (this.single.as) {
|
|
151
|
+
query.as = this.single.as;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (this._undefinedInWhereClause) {
|
|
156
|
+
debugBindings(query.bindings);
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Undefined binding(s) detected when compiling ` +
|
|
159
|
+
`${method.toUpperCase()}. Undefined column(s): [${this.undefinedBindingsInfo.join(
|
|
160
|
+
', '
|
|
161
|
+
)}] query: ${query.sql}`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return query;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Compiles the `select` statement, or nested sub-selects by calling each of
|
|
169
|
+
// the component compilers, trimming out the empties, and returning a
|
|
170
|
+
// generated query string.
|
|
171
|
+
select() {
|
|
172
|
+
let sql = this.with();
|
|
173
|
+
|
|
174
|
+
let unionStatement = '';
|
|
175
|
+
|
|
176
|
+
const firstStatements = [];
|
|
177
|
+
const endStatements = [];
|
|
178
|
+
|
|
179
|
+
components.forEach((component) => {
|
|
180
|
+
const statement = this[component](this);
|
|
181
|
+
// We store the 'union' statement to append it at the end.
|
|
182
|
+
// We still need to call the component sequentially because of
|
|
183
|
+
// order of bindings.
|
|
184
|
+
switch (component) {
|
|
185
|
+
case 'union':
|
|
186
|
+
unionStatement = statement;
|
|
187
|
+
break;
|
|
188
|
+
case 'comments':
|
|
189
|
+
case 'columns':
|
|
190
|
+
case 'join':
|
|
191
|
+
case 'where':
|
|
192
|
+
firstStatements.push(statement);
|
|
193
|
+
break;
|
|
194
|
+
default:
|
|
195
|
+
endStatements.push(statement);
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Check if we need to wrap the main query.
|
|
201
|
+
// We need to wrap main query if one of union have wrap options to true
|
|
202
|
+
// to avoid error syntax (in PostgreSQL for example).
|
|
203
|
+
const wrapMainQuery =
|
|
204
|
+
this.grouped.union &&
|
|
205
|
+
this.grouped.union.map((u) => u.wrap).some((u) => u);
|
|
206
|
+
|
|
207
|
+
if (this.onlyUnions()) {
|
|
208
|
+
const statements = compact(firstStatements.concat(endStatements)).join(
|
|
209
|
+
' '
|
|
210
|
+
);
|
|
211
|
+
sql += unionStatement + (statements ? ' ' + statements : '');
|
|
212
|
+
} else {
|
|
213
|
+
const allStatements =
|
|
214
|
+
(wrapMainQuery ? '(' : '') +
|
|
215
|
+
compact(firstStatements).join(' ') +
|
|
216
|
+
(wrapMainQuery ? ')' : '');
|
|
217
|
+
const endStat = compact(endStatements).join(' ');
|
|
218
|
+
sql +=
|
|
219
|
+
allStatements +
|
|
220
|
+
(unionStatement ? ' ' + unionStatement : '') +
|
|
221
|
+
(endStat ? ' ' + endStat : endStat);
|
|
222
|
+
}
|
|
223
|
+
return sql;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
pluck() {
|
|
227
|
+
let toPluck = this.single.pluck;
|
|
228
|
+
if (toPluck.indexOf('.') !== -1) {
|
|
229
|
+
toPluck = toPluck.split('.').slice(-1)[0];
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
sql: this.select(),
|
|
233
|
+
pluck: toPluck,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Compiles an "insert" query, allowing for multiple
|
|
238
|
+
// inserts using a single query statement.
|
|
239
|
+
insert() {
|
|
240
|
+
const insertValues = this.single.insert || [];
|
|
241
|
+
const sql = this.with() + `insert into ${this.tableName} `;
|
|
242
|
+
const body = this._insertBody(insertValues);
|
|
243
|
+
return body === '' ? '' : sql + body;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
_onConflictClause(columns) {
|
|
247
|
+
return columns instanceof Raw
|
|
248
|
+
? this.formatter.wrap(columns)
|
|
249
|
+
: `(${this.formatter.columnize(columns)})`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
_buildInsertValues(insertData) {
|
|
253
|
+
let sql = '';
|
|
254
|
+
let i = -1;
|
|
255
|
+
while (++i < insertData.values.length) {
|
|
256
|
+
if (i !== 0) sql += '), (';
|
|
257
|
+
sql += this.client.parameterize(
|
|
258
|
+
insertData.values[i],
|
|
259
|
+
this.client.valueForUndefined,
|
|
260
|
+
this.builder,
|
|
261
|
+
this.bindingsHolder
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return sql;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
_insertBody(insertValues) {
|
|
268
|
+
let sql = '';
|
|
269
|
+
if (Array.isArray(insertValues)) {
|
|
270
|
+
if (insertValues.length === 0) {
|
|
271
|
+
return '';
|
|
272
|
+
}
|
|
273
|
+
} else if (typeof insertValues === 'object' && isEmpty(insertValues)) {
|
|
274
|
+
return sql + this._emptyInsertValue;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const insertData = this._prepInsert(insertValues);
|
|
278
|
+
if (typeof insertData === 'string') {
|
|
279
|
+
sql += insertData;
|
|
280
|
+
} else {
|
|
281
|
+
if (insertData.columns.length) {
|
|
282
|
+
sql += `(${columnize_(
|
|
283
|
+
insertData.columns,
|
|
284
|
+
this.builder,
|
|
285
|
+
this.client,
|
|
286
|
+
this.bindingsHolder
|
|
287
|
+
)}`;
|
|
288
|
+
sql += ') values (' + this._buildInsertValues(insertData) + ')';
|
|
289
|
+
} else if (insertValues.length === 1 && insertValues[0]) {
|
|
290
|
+
sql += this._emptyInsertValue;
|
|
291
|
+
} else {
|
|
292
|
+
sql = '';
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return sql;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Compiles the "update" query.
|
|
299
|
+
update() {
|
|
300
|
+
// Make sure tableName is processed by the formatter first.
|
|
301
|
+
const withSQL = this.with();
|
|
302
|
+
const { tableName } = this;
|
|
303
|
+
const updateData = this._prepUpdate(this.single.update);
|
|
304
|
+
const wheres = this.where();
|
|
305
|
+
return (
|
|
306
|
+
withSQL +
|
|
307
|
+
`update ${this.single.only ? 'only ' : ''}${tableName}` +
|
|
308
|
+
' set ' +
|
|
309
|
+
updateData.join(', ') +
|
|
310
|
+
(wheres ? ` ${wheres}` : '')
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
_hintComments() {
|
|
315
|
+
let hints = this.grouped.hintComments || [];
|
|
316
|
+
hints = hints.map((hint) => compact(hint.value).join(' '));
|
|
317
|
+
hints = compact(hints).join(' ');
|
|
318
|
+
return hints ? `/*+ ${hints} */ ` : '';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Compiles the columns in the query, specifying if an item was distinct.
|
|
322
|
+
columns() {
|
|
323
|
+
let distinctClause = '';
|
|
324
|
+
if (this.onlyUnions()) return '';
|
|
325
|
+
const hints = this._hintComments();
|
|
326
|
+
const columns = this.grouped.columns || [];
|
|
327
|
+
let i = -1,
|
|
328
|
+
sql = [];
|
|
329
|
+
if (columns) {
|
|
330
|
+
while (++i < columns.length) {
|
|
331
|
+
const stmt = columns[i];
|
|
332
|
+
if (stmt.distinct) distinctClause = 'distinct ';
|
|
333
|
+
if (stmt.distinctOn) {
|
|
334
|
+
distinctClause = this.distinctOn(stmt.value);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (stmt.type === 'aggregate') {
|
|
338
|
+
sql.push(...this.aggregate(stmt));
|
|
339
|
+
} else if (stmt.type === 'aggregateRaw') {
|
|
340
|
+
sql.push(this.aggregateRaw(stmt));
|
|
341
|
+
} else if (stmt.type === 'analytic') {
|
|
342
|
+
sql.push(this.analytic(stmt));
|
|
343
|
+
} else if (stmt.type === 'json') {
|
|
344
|
+
sql.push(this.json(stmt));
|
|
345
|
+
} else if (stmt.value && stmt.value.length > 0) {
|
|
346
|
+
sql.push(
|
|
347
|
+
columnize_(
|
|
348
|
+
stmt.value,
|
|
349
|
+
this.builder,
|
|
350
|
+
this.client,
|
|
351
|
+
this.bindingsHolder
|
|
352
|
+
)
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (sql.length === 0) sql = ['*'];
|
|
358
|
+
const select = this.onlyJson() ? '' : 'select ';
|
|
359
|
+
return (
|
|
360
|
+
`${select}${hints}${distinctClause}` +
|
|
361
|
+
sql.join(', ') +
|
|
362
|
+
(this.tableName
|
|
363
|
+
? ` from ${this.single.only ? 'only ' : ''}${this.tableName}`
|
|
364
|
+
: '')
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Add comments to the query
|
|
369
|
+
comments() {
|
|
370
|
+
if (!this.queryComments.length) return '';
|
|
371
|
+
return this.queryComments
|
|
372
|
+
.map((comment) => `/* ${comment.comment} */`)
|
|
373
|
+
.join(' ');
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
_aggregate(stmt, { aliasSeparator = ' as ', distinctParentheses } = {}) {
|
|
377
|
+
const value = stmt.value;
|
|
378
|
+
const method = stmt.method;
|
|
379
|
+
const distinct = stmt.aggregateDistinct ? 'distinct ' : '';
|
|
380
|
+
const wrap = (identifier) =>
|
|
381
|
+
wrap_(
|
|
382
|
+
identifier,
|
|
383
|
+
undefined,
|
|
384
|
+
this.builder,
|
|
385
|
+
this.client,
|
|
386
|
+
this.bindingsHolder
|
|
387
|
+
);
|
|
388
|
+
const addAlias = (value, alias) => {
|
|
389
|
+
if (alias) {
|
|
390
|
+
return value + aliasSeparator + wrap(alias);
|
|
391
|
+
}
|
|
392
|
+
return value;
|
|
393
|
+
};
|
|
394
|
+
const aggregateArray = (value, alias) => {
|
|
395
|
+
let columns = value.map(wrap).join(', ');
|
|
396
|
+
if (distinct) {
|
|
397
|
+
const openParen = distinctParentheses ? '(' : ' ';
|
|
398
|
+
const closeParen = distinctParentheses ? ')' : '';
|
|
399
|
+
columns = distinct.trim() + openParen + columns + closeParen;
|
|
400
|
+
}
|
|
401
|
+
const aggregated = `${method}(${columns})`;
|
|
402
|
+
return addAlias(aggregated, alias);
|
|
403
|
+
};
|
|
404
|
+
const aggregateString = (value, alias) => {
|
|
405
|
+
const aggregated = `${method}(${distinct + wrap(value)})`;
|
|
406
|
+
return addAlias(aggregated, alias);
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
if (Array.isArray(value)) {
|
|
410
|
+
return [aggregateArray(value)];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (typeof value === 'object') {
|
|
414
|
+
if (stmt.alias) {
|
|
415
|
+
throw new Error('When using an object explicit alias can not be used');
|
|
416
|
+
}
|
|
417
|
+
return Object.entries(value).map(([alias, column]) => {
|
|
418
|
+
if (Array.isArray(column)) {
|
|
419
|
+
return aggregateArray(column, alias);
|
|
420
|
+
}
|
|
421
|
+
return aggregateString(column, alias);
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Allows us to speciy an alias for the aggregate types.
|
|
426
|
+
const splitOn = value.toLowerCase().indexOf(' as ');
|
|
427
|
+
let column = value;
|
|
428
|
+
let { alias } = stmt;
|
|
429
|
+
if (splitOn !== -1) {
|
|
430
|
+
column = value.slice(0, splitOn);
|
|
431
|
+
if (alias) {
|
|
432
|
+
throw new Error(`Found multiple aliases for same column: ${column}`);
|
|
433
|
+
}
|
|
434
|
+
alias = value.slice(splitOn + 4);
|
|
435
|
+
}
|
|
436
|
+
return [aggregateString(column, alias)];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
aggregate(stmt) {
|
|
440
|
+
return this._aggregate(stmt);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
aggregateRaw(stmt) {
|
|
444
|
+
const distinct = stmt.aggregateDistinct ? 'distinct ' : '';
|
|
445
|
+
return `${stmt.method}(${
|
|
446
|
+
distinct +
|
|
447
|
+
unwrapRaw_(
|
|
448
|
+
stmt.value,
|
|
449
|
+
undefined,
|
|
450
|
+
this.builder,
|
|
451
|
+
this.client,
|
|
452
|
+
this.bindingsHolder
|
|
453
|
+
)
|
|
454
|
+
})`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
_joinTable(join) {
|
|
458
|
+
return join.schema && !(join.table instanceof Raw)
|
|
459
|
+
? `${join.schema}.${join.table}`
|
|
460
|
+
: join.table;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Compiles all each of the `join` clauses on the query,
|
|
464
|
+
// including any nested join queries.
|
|
465
|
+
join() {
|
|
466
|
+
let sql = '';
|
|
467
|
+
let i = -1;
|
|
468
|
+
const joins = this.grouped.join;
|
|
469
|
+
if (!joins) return '';
|
|
470
|
+
while (++i < joins.length) {
|
|
471
|
+
const join = joins[i];
|
|
472
|
+
const table = this._joinTable(join);
|
|
473
|
+
if (i > 0) sql += ' ';
|
|
474
|
+
if (join.joinType === 'raw') {
|
|
475
|
+
sql += unwrapRaw_(
|
|
476
|
+
join.table,
|
|
477
|
+
undefined,
|
|
478
|
+
this.builder,
|
|
479
|
+
this.client,
|
|
480
|
+
this.bindingsHolder
|
|
481
|
+
);
|
|
482
|
+
} else {
|
|
483
|
+
sql +=
|
|
484
|
+
join.joinType +
|
|
485
|
+
' join ' +
|
|
486
|
+
wrap_(
|
|
487
|
+
table,
|
|
488
|
+
undefined,
|
|
489
|
+
this.builder,
|
|
490
|
+
this.client,
|
|
491
|
+
this.bindingsHolder
|
|
492
|
+
);
|
|
493
|
+
let ii = -1;
|
|
494
|
+
while (++ii < join.clauses.length) {
|
|
495
|
+
const clause = join.clauses[ii];
|
|
496
|
+
if (ii > 0) {
|
|
497
|
+
sql += ` ${clause.bool} `;
|
|
498
|
+
} else {
|
|
499
|
+
sql += ` ${clause.type === 'onUsing' ? 'using' : 'on'} `;
|
|
500
|
+
}
|
|
501
|
+
const val = this[clause.type](clause);
|
|
502
|
+
if (val) {
|
|
503
|
+
sql += val;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return sql;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
onBetween(statement) {
|
|
512
|
+
return (
|
|
513
|
+
wrap_(
|
|
514
|
+
statement.column,
|
|
515
|
+
undefined,
|
|
516
|
+
this.builder,
|
|
517
|
+
this.client,
|
|
518
|
+
this.bindingsHolder
|
|
519
|
+
) +
|
|
520
|
+
' ' +
|
|
521
|
+
this._not(statement, 'between') +
|
|
522
|
+
' ' +
|
|
523
|
+
statement.value
|
|
524
|
+
.map((value) =>
|
|
525
|
+
this.client.parameter(value, this.builder, this.bindingsHolder)
|
|
526
|
+
)
|
|
527
|
+
.join(' and ')
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
onNull(statement) {
|
|
532
|
+
return (
|
|
533
|
+
wrap_(
|
|
534
|
+
statement.column,
|
|
535
|
+
undefined,
|
|
536
|
+
this.builder,
|
|
537
|
+
this.client,
|
|
538
|
+
this.bindingsHolder
|
|
539
|
+
) +
|
|
540
|
+
' is ' +
|
|
541
|
+
this._not(statement, 'null')
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
onExists(statement) {
|
|
546
|
+
return (
|
|
547
|
+
this._not(statement, 'exists') +
|
|
548
|
+
' (' +
|
|
549
|
+
rawOrFn_(
|
|
550
|
+
statement.value,
|
|
551
|
+
undefined,
|
|
552
|
+
this.builder,
|
|
553
|
+
this.client,
|
|
554
|
+
this.bindingsHolder
|
|
555
|
+
) +
|
|
556
|
+
')'
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
onIn(statement) {
|
|
561
|
+
if (Array.isArray(statement.column)) return this.multiOnIn(statement);
|
|
562
|
+
|
|
563
|
+
let values;
|
|
564
|
+
if (statement.value instanceof Raw) {
|
|
565
|
+
values = this.client.parameter(
|
|
566
|
+
statement.value,
|
|
567
|
+
this.builder,
|
|
568
|
+
this.formatter
|
|
569
|
+
);
|
|
570
|
+
} else {
|
|
571
|
+
values = this.client.parameterize(
|
|
572
|
+
statement.value,
|
|
573
|
+
undefined,
|
|
574
|
+
this.builder,
|
|
575
|
+
this.bindingsHolder
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return (
|
|
580
|
+
wrap_(
|
|
581
|
+
statement.column,
|
|
582
|
+
undefined,
|
|
583
|
+
this.builder,
|
|
584
|
+
this.client,
|
|
585
|
+
this.bindingsHolder
|
|
586
|
+
) +
|
|
587
|
+
' ' +
|
|
588
|
+
this._not(statement, 'in ') +
|
|
589
|
+
this.wrap(values)
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
multiOnIn(statement) {
|
|
594
|
+
let i = -1,
|
|
595
|
+
sql = `(${columnize_(
|
|
596
|
+
statement.column,
|
|
597
|
+
this.builder,
|
|
598
|
+
this.client,
|
|
599
|
+
this.bindingsHolder
|
|
600
|
+
)}) `;
|
|
601
|
+
sql += this._not(statement, 'in ') + '((';
|
|
602
|
+
while (++i < statement.value.length) {
|
|
603
|
+
if (i !== 0) sql += '),(';
|
|
604
|
+
sql += this.client.parameterize(
|
|
605
|
+
statement.value[i],
|
|
606
|
+
undefined,
|
|
607
|
+
this.builder,
|
|
608
|
+
this.bindingsHolder
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
return sql + '))';
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Compiles all `where` statements on the query.
|
|
615
|
+
where() {
|
|
616
|
+
const wheres = this.grouped.where;
|
|
617
|
+
if (!wheres) return;
|
|
618
|
+
const sql = [];
|
|
619
|
+
let i = -1;
|
|
620
|
+
while (++i < wheres.length) {
|
|
621
|
+
const stmt = wheres[i];
|
|
622
|
+
if (
|
|
623
|
+
Object.prototype.hasOwnProperty.call(stmt, 'value') &&
|
|
624
|
+
helpers.containsUndefined(stmt.value)
|
|
625
|
+
) {
|
|
626
|
+
this.undefinedBindingsInfo.push(stmt.column);
|
|
627
|
+
this._undefinedInWhereClause = true;
|
|
628
|
+
}
|
|
629
|
+
const val = this[stmt.type](stmt);
|
|
630
|
+
if (val) {
|
|
631
|
+
if (sql.length === 0) {
|
|
632
|
+
sql[0] = 'where';
|
|
633
|
+
} else {
|
|
634
|
+
sql.push(stmt.bool);
|
|
635
|
+
}
|
|
636
|
+
sql.push(val);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return sql.length > 1 ? sql.join(' ') : '';
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
group() {
|
|
643
|
+
return this._groupsOrders('group');
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
order() {
|
|
647
|
+
return this._groupsOrders('order');
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Compiles the `having` statements.
|
|
651
|
+
having() {
|
|
652
|
+
const havings = this.grouped.having;
|
|
653
|
+
if (!havings) return '';
|
|
654
|
+
const sql = ['having'];
|
|
655
|
+
for (let i = 0, l = havings.length; i < l; i++) {
|
|
656
|
+
const s = havings[i];
|
|
657
|
+
const val = this[s.type](s);
|
|
658
|
+
if (val) {
|
|
659
|
+
if (sql.length === 0) {
|
|
660
|
+
sql[0] = 'where';
|
|
661
|
+
}
|
|
662
|
+
if (sql.length > 1 || (sql.length === 1 && sql[0] !== 'having')) {
|
|
663
|
+
sql.push(s.bool);
|
|
664
|
+
}
|
|
665
|
+
sql.push(val);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return sql.length > 1 ? sql.join(' ') : '';
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
havingRaw(statement) {
|
|
672
|
+
return (
|
|
673
|
+
this._not(statement, '') +
|
|
674
|
+
unwrapRaw_(
|
|
675
|
+
statement.value,
|
|
676
|
+
undefined,
|
|
677
|
+
this.builder,
|
|
678
|
+
this.client,
|
|
679
|
+
this.bindingsHolder
|
|
680
|
+
)
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
havingWrapped(statement) {
|
|
685
|
+
const val = rawOrFn_(
|
|
686
|
+
statement.value,
|
|
687
|
+
'where',
|
|
688
|
+
this.builder,
|
|
689
|
+
this.client,
|
|
690
|
+
this.bindingsHolder
|
|
691
|
+
);
|
|
692
|
+
return (val && this._not(statement, '') + '(' + val.slice(6) + ')') || '';
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
havingBasic(statement) {
|
|
696
|
+
return (
|
|
697
|
+
this._not(statement, '') +
|
|
698
|
+
wrap_(
|
|
699
|
+
statement.column,
|
|
700
|
+
undefined,
|
|
701
|
+
this.builder,
|
|
702
|
+
this.client,
|
|
703
|
+
this.bindingsHolder
|
|
704
|
+
) +
|
|
705
|
+
' ' +
|
|
706
|
+
operator_(
|
|
707
|
+
statement.operator,
|
|
708
|
+
this.builder,
|
|
709
|
+
this.client,
|
|
710
|
+
this.bindingsHolder
|
|
711
|
+
) +
|
|
712
|
+
' ' +
|
|
713
|
+
this.client.parameter(statement.value, this.builder, this.bindingsHolder)
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
havingNull(statement) {
|
|
718
|
+
return (
|
|
719
|
+
wrap_(
|
|
720
|
+
statement.column,
|
|
721
|
+
undefined,
|
|
722
|
+
this.builder,
|
|
723
|
+
this.client,
|
|
724
|
+
this.bindingsHolder
|
|
725
|
+
) +
|
|
726
|
+
' is ' +
|
|
727
|
+
this._not(statement, 'null')
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
havingExists(statement) {
|
|
732
|
+
return (
|
|
733
|
+
this._not(statement, 'exists') +
|
|
734
|
+
' (' +
|
|
735
|
+
rawOrFn_(
|
|
736
|
+
statement.value,
|
|
737
|
+
undefined,
|
|
738
|
+
this.builder,
|
|
739
|
+
this.client,
|
|
740
|
+
this.bindingsHolder
|
|
741
|
+
) +
|
|
742
|
+
')'
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
havingBetween(statement) {
|
|
747
|
+
return (
|
|
748
|
+
wrap_(
|
|
749
|
+
statement.column,
|
|
750
|
+
undefined,
|
|
751
|
+
this.builder,
|
|
752
|
+
this.client,
|
|
753
|
+
this.bindingsHolder
|
|
754
|
+
) +
|
|
755
|
+
' ' +
|
|
756
|
+
this._not(statement, 'between') +
|
|
757
|
+
' ' +
|
|
758
|
+
statement.value
|
|
759
|
+
.map((value) =>
|
|
760
|
+
this.client.parameter(value, this.builder, this.bindingsHolder)
|
|
761
|
+
)
|
|
762
|
+
.join(' and ')
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
havingIn(statement) {
|
|
767
|
+
if (Array.isArray(statement.column)) return this.multiHavingIn(statement);
|
|
768
|
+
return (
|
|
769
|
+
wrap_(
|
|
770
|
+
statement.column,
|
|
771
|
+
undefined,
|
|
772
|
+
this.builder,
|
|
773
|
+
this.client,
|
|
774
|
+
this.bindingsHolder
|
|
775
|
+
) +
|
|
776
|
+
' ' +
|
|
777
|
+
this._not(statement, 'in ') +
|
|
778
|
+
this.wrap(
|
|
779
|
+
this.client.parameterize(
|
|
780
|
+
statement.value,
|
|
781
|
+
undefined,
|
|
782
|
+
this.builder,
|
|
783
|
+
this.bindingsHolder
|
|
784
|
+
)
|
|
785
|
+
)
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
multiHavingIn(statement) {
|
|
790
|
+
return this.multiOnIn(statement);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Compile the "union" queries attached to the main query.
|
|
794
|
+
union() {
|
|
795
|
+
const onlyUnions = this.onlyUnions();
|
|
796
|
+
const unions = this.grouped.union;
|
|
797
|
+
if (!unions) return '';
|
|
798
|
+
let sql = '';
|
|
799
|
+
for (let i = 0, l = unions.length; i < l; i++) {
|
|
800
|
+
const union = unions[i];
|
|
801
|
+
if (i > 0) sql += ' ';
|
|
802
|
+
if (i > 0 || !onlyUnions) sql += union.clause + ' ';
|
|
803
|
+
const statement = rawOrFn_(
|
|
804
|
+
union.value,
|
|
805
|
+
undefined,
|
|
806
|
+
this.builder,
|
|
807
|
+
this.client,
|
|
808
|
+
this.bindingsHolder
|
|
809
|
+
);
|
|
810
|
+
if (statement) {
|
|
811
|
+
const wrap = union.wrap;
|
|
812
|
+
if (wrap) sql += '(';
|
|
813
|
+
sql += statement;
|
|
814
|
+
if (wrap) sql += ')';
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
return sql;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// If we haven't specified any columns or a `tableName`, we're assuming this
|
|
821
|
+
// is only being used for unions.
|
|
822
|
+
onlyUnions() {
|
|
823
|
+
return (
|
|
824
|
+
(!this.grouped.columns || !!this.grouped.columns[0].value) &&
|
|
825
|
+
this.grouped.union &&
|
|
826
|
+
!this.tableName
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
_getValueOrParameterFromAttribute(attribute, rawValue) {
|
|
831
|
+
if (this.single.skipBinding[attribute] === true) {
|
|
832
|
+
return rawValue !== undefined && rawValue !== null
|
|
833
|
+
? rawValue
|
|
834
|
+
: this.single[attribute];
|
|
835
|
+
}
|
|
836
|
+
return this.client.parameter(
|
|
837
|
+
this.single[attribute],
|
|
838
|
+
this.builder,
|
|
839
|
+
this.bindingsHolder
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
onlyJson() {
|
|
844
|
+
return (
|
|
845
|
+
!this.tableName &&
|
|
846
|
+
this.grouped.columns &&
|
|
847
|
+
this.grouped.columns.length === 1 &&
|
|
848
|
+
this.grouped.columns[0].type === 'json'
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
limit() {
|
|
853
|
+
const noLimit = !this.single.limit && this.single.limit !== 0;
|
|
854
|
+
if (noLimit) return '';
|
|
855
|
+
return `limit ${this._getValueOrParameterFromAttribute('limit')}`;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
offset() {
|
|
859
|
+
if (!this.single.offset) return '';
|
|
860
|
+
return `offset ${this._getValueOrParameterFromAttribute('offset')}`;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Compiles a `delete` query.
|
|
864
|
+
del() {
|
|
865
|
+
// Make sure tableName is processed by the formatter first.
|
|
866
|
+
const { tableName } = this;
|
|
867
|
+
const withSQL = this.with();
|
|
868
|
+
const wheres = this.where();
|
|
869
|
+
const joins = this.join();
|
|
870
|
+
// When using joins, delete the "from" table values as a default
|
|
871
|
+
const deleteSelector = joins ? tableName + ' ' : '';
|
|
872
|
+
return (
|
|
873
|
+
withSQL +
|
|
874
|
+
`delete ${deleteSelector}from ${
|
|
875
|
+
this.single.only ? 'only ' : ''
|
|
876
|
+
}${tableName}` +
|
|
877
|
+
(joins ? ` ${joins}` : '') +
|
|
878
|
+
(wheres ? ` ${wheres}` : '')
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Compiles a `truncate` query.
|
|
883
|
+
truncate() {
|
|
884
|
+
return `truncate ${this.tableName}`;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// Compiles the "locks".
|
|
888
|
+
lock() {
|
|
889
|
+
if (this.single.lock) {
|
|
890
|
+
return this[this.single.lock]();
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// Compiles the wait mode on the locks.
|
|
895
|
+
waitMode() {
|
|
896
|
+
if (this.single.waitMode) {
|
|
897
|
+
return this[this.single.waitMode]();
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// Fail on unsupported databases
|
|
902
|
+
skipLocked() {
|
|
903
|
+
throw new Error(
|
|
904
|
+
'.skipLocked() is currently only supported on MySQL 8.0+ and PostgreSQL 9.5+'
|
|
905
|
+
);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// Fail on unsupported databases
|
|
909
|
+
noWait() {
|
|
910
|
+
throw new Error(
|
|
911
|
+
'.noWait() is currently only supported on MySQL 8.0+, MariaDB 10.3.0+ and PostgreSQL 9.5+'
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
distinctOn(value) {
|
|
916
|
+
throw new Error('.distinctOn() is currently only supported on PostgreSQL');
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// On Clause
|
|
920
|
+
// ------
|
|
921
|
+
|
|
922
|
+
onWrapped(clause) {
|
|
923
|
+
const self = this;
|
|
924
|
+
|
|
925
|
+
const wrapJoin = new JoinClause();
|
|
926
|
+
clause.value.call(wrapJoin, wrapJoin);
|
|
927
|
+
|
|
928
|
+
let sql = '';
|
|
929
|
+
|
|
930
|
+
for (let ii = 0; ii < wrapJoin.clauses.length; ii++) {
|
|
931
|
+
const wrapClause = wrapJoin.clauses[ii];
|
|
932
|
+
if (ii > 0) {
|
|
933
|
+
sql += ` ${wrapClause.bool} `;
|
|
934
|
+
}
|
|
935
|
+
const val = self[wrapClause.type](wrapClause);
|
|
936
|
+
if (val) {
|
|
937
|
+
sql += val;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
if (sql.length) {
|
|
942
|
+
return `(${sql})`;
|
|
943
|
+
}
|
|
944
|
+
return '';
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
onBasic(clause) {
|
|
948
|
+
const toWrap = clause.value instanceof QueryBuilder;
|
|
949
|
+
return (
|
|
950
|
+
wrap_(
|
|
951
|
+
clause.column,
|
|
952
|
+
undefined,
|
|
953
|
+
this.builder,
|
|
954
|
+
this.client,
|
|
955
|
+
this.bindingsHolder
|
|
956
|
+
) +
|
|
957
|
+
' ' +
|
|
958
|
+
operator_(
|
|
959
|
+
clause.operator,
|
|
960
|
+
this.builder,
|
|
961
|
+
this.client,
|
|
962
|
+
this.bindingsHolder
|
|
963
|
+
) +
|
|
964
|
+
' ' +
|
|
965
|
+
(toWrap ? '(' : '') +
|
|
966
|
+
wrap_(
|
|
967
|
+
clause.value,
|
|
968
|
+
undefined,
|
|
969
|
+
this.builder,
|
|
970
|
+
this.client,
|
|
971
|
+
this.bindingsHolder
|
|
972
|
+
) +
|
|
973
|
+
(toWrap ? ')' : '')
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
onVal(clause) {
|
|
978
|
+
return (
|
|
979
|
+
wrap_(
|
|
980
|
+
clause.column,
|
|
981
|
+
undefined,
|
|
982
|
+
this.builder,
|
|
983
|
+
this.client,
|
|
984
|
+
this.bindingsHolder
|
|
985
|
+
) +
|
|
986
|
+
' ' +
|
|
987
|
+
operator_(
|
|
988
|
+
clause.operator,
|
|
989
|
+
this.builder,
|
|
990
|
+
this.client,
|
|
991
|
+
this.bindingsHolder
|
|
992
|
+
) +
|
|
993
|
+
' ' +
|
|
994
|
+
this.client.parameter(clause.value, this.builder, this.bindingsHolder)
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
onRaw(clause) {
|
|
999
|
+
return unwrapRaw_(
|
|
1000
|
+
clause.value,
|
|
1001
|
+
undefined,
|
|
1002
|
+
this.builder,
|
|
1003
|
+
this.client,
|
|
1004
|
+
this.bindingsHolder
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
onUsing(clause) {
|
|
1009
|
+
return (
|
|
1010
|
+
'(' +
|
|
1011
|
+
columnize_(
|
|
1012
|
+
clause.column,
|
|
1013
|
+
this.builder,
|
|
1014
|
+
this.client,
|
|
1015
|
+
this.bindingsHolder
|
|
1016
|
+
) +
|
|
1017
|
+
')'
|
|
1018
|
+
);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// Where Clause
|
|
1022
|
+
// ------
|
|
1023
|
+
|
|
1024
|
+
_valueClause(statement) {
|
|
1025
|
+
return statement.asColumn
|
|
1026
|
+
? wrap_(
|
|
1027
|
+
statement.value,
|
|
1028
|
+
undefined,
|
|
1029
|
+
this.builder,
|
|
1030
|
+
this.client,
|
|
1031
|
+
this.bindingsHolder
|
|
1032
|
+
)
|
|
1033
|
+
: this.client.parameter(
|
|
1034
|
+
statement.value,
|
|
1035
|
+
this.builder,
|
|
1036
|
+
this.bindingsHolder
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
_columnClause(statement) {
|
|
1041
|
+
let columns;
|
|
1042
|
+
if (Array.isArray(statement.column)) {
|
|
1043
|
+
columns = `(${columnize_(
|
|
1044
|
+
statement.column,
|
|
1045
|
+
this.builder,
|
|
1046
|
+
this.client,
|
|
1047
|
+
this.bindingsHolder
|
|
1048
|
+
)})`;
|
|
1049
|
+
} else {
|
|
1050
|
+
columns = wrap_(
|
|
1051
|
+
statement.column,
|
|
1052
|
+
undefined,
|
|
1053
|
+
this.builder,
|
|
1054
|
+
this.client,
|
|
1055
|
+
this.bindingsHolder
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
return columns;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
whereIn(statement) {
|
|
1062
|
+
const columns = this._columnClause(statement);
|
|
1063
|
+
const values = this.client.values(
|
|
1064
|
+
statement.value,
|
|
1065
|
+
this.builder,
|
|
1066
|
+
this.bindingsHolder
|
|
1067
|
+
);
|
|
1068
|
+
return `${columns} ${this._not(statement, 'in ')}${values}`;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
whereLike(statement) {
|
|
1072
|
+
return `${this._columnClause(statement)} ${this._not(
|
|
1073
|
+
statement,
|
|
1074
|
+
'like '
|
|
1075
|
+
)}${this._valueClause(statement)}`;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
whereILike(statement) {
|
|
1079
|
+
return `${this._columnClause(statement)} ${this._not(
|
|
1080
|
+
statement,
|
|
1081
|
+
'ilike '
|
|
1082
|
+
)}${this._valueClause(statement)}`;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
whereNull(statement) {
|
|
1086
|
+
return (
|
|
1087
|
+
wrap_(
|
|
1088
|
+
statement.column,
|
|
1089
|
+
undefined,
|
|
1090
|
+
this.builder,
|
|
1091
|
+
this.client,
|
|
1092
|
+
this.bindingsHolder
|
|
1093
|
+
) +
|
|
1094
|
+
' is ' +
|
|
1095
|
+
this._not(statement, 'null')
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
// Compiles a basic "where" clause.
|
|
1100
|
+
whereBasic(statement) {
|
|
1101
|
+
return (
|
|
1102
|
+
this._not(statement, '') +
|
|
1103
|
+
wrap_(
|
|
1104
|
+
statement.column,
|
|
1105
|
+
undefined,
|
|
1106
|
+
this.builder,
|
|
1107
|
+
this.client,
|
|
1108
|
+
this.bindingsHolder
|
|
1109
|
+
) +
|
|
1110
|
+
' ' +
|
|
1111
|
+
operator_(
|
|
1112
|
+
statement.operator,
|
|
1113
|
+
this.builder,
|
|
1114
|
+
this.client,
|
|
1115
|
+
this.bindingsHolder
|
|
1116
|
+
) +
|
|
1117
|
+
' ' +
|
|
1118
|
+
this._valueClause(statement)
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
whereExists(statement) {
|
|
1123
|
+
return (
|
|
1124
|
+
this._not(statement, 'exists') +
|
|
1125
|
+
' (' +
|
|
1126
|
+
rawOrFn_(
|
|
1127
|
+
statement.value,
|
|
1128
|
+
undefined,
|
|
1129
|
+
this.builder,
|
|
1130
|
+
this.client,
|
|
1131
|
+
this.bindingsHolder
|
|
1132
|
+
) +
|
|
1133
|
+
')'
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
whereWrapped(statement) {
|
|
1138
|
+
const val = rawOrFn_(
|
|
1139
|
+
statement.value,
|
|
1140
|
+
'where',
|
|
1141
|
+
this.builder,
|
|
1142
|
+
this.client,
|
|
1143
|
+
this.bindingsHolder
|
|
1144
|
+
);
|
|
1145
|
+
return (val && this._not(statement, '') + '(' + val.slice(6) + ')') || '';
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
whereBetween(statement) {
|
|
1149
|
+
return (
|
|
1150
|
+
wrap_(
|
|
1151
|
+
statement.column,
|
|
1152
|
+
undefined,
|
|
1153
|
+
this.builder,
|
|
1154
|
+
this.client,
|
|
1155
|
+
this.bindingsHolder
|
|
1156
|
+
) +
|
|
1157
|
+
' ' +
|
|
1158
|
+
this._not(statement, 'between') +
|
|
1159
|
+
' ' +
|
|
1160
|
+
statement.value
|
|
1161
|
+
.map((value) =>
|
|
1162
|
+
this.client.parameter(value, this.builder, this.bindingsHolder)
|
|
1163
|
+
)
|
|
1164
|
+
.join(' and ')
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// Compiles a "whereRaw" query.
|
|
1169
|
+
whereRaw(statement) {
|
|
1170
|
+
return (
|
|
1171
|
+
this._not(statement, '') +
|
|
1172
|
+
unwrapRaw_(
|
|
1173
|
+
statement.value,
|
|
1174
|
+
undefined,
|
|
1175
|
+
this.builder,
|
|
1176
|
+
this.client,
|
|
1177
|
+
this.bindingsHolder
|
|
1178
|
+
)
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
_jsonWrapValue(jsonValue) {
|
|
1183
|
+
if (!this.builder._isJsonObject(jsonValue)) {
|
|
1184
|
+
try {
|
|
1185
|
+
return JSON.stringify(JSON.parse(jsonValue.replace(/\n|\t/g, '')));
|
|
1186
|
+
} catch (e) {
|
|
1187
|
+
return jsonValue;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return JSON.stringify(jsonValue);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
_jsonValueClause(statement) {
|
|
1194
|
+
statement.value = this._jsonWrapValue(statement.value);
|
|
1195
|
+
return this._valueClause(statement);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
whereJsonObject(statement) {
|
|
1199
|
+
return `${this._columnClause(statement)} ${
|
|
1200
|
+
statement.not ? '!=' : '='
|
|
1201
|
+
} ${this._jsonValueClause(statement)}`;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
wrap(str) {
|
|
1205
|
+
if (str.charAt(0) !== '(') return `(${str})`;
|
|
1206
|
+
return str;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
json(stmt) {
|
|
1210
|
+
return this[stmt.method](stmt.params);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
analytic(stmt) {
|
|
1214
|
+
let sql = '';
|
|
1215
|
+
const self = this;
|
|
1216
|
+
sql += stmt.method + '() over (';
|
|
1217
|
+
|
|
1218
|
+
if (stmt.raw) {
|
|
1219
|
+
sql += stmt.raw;
|
|
1220
|
+
} else {
|
|
1221
|
+
if (stmt.partitions.length) {
|
|
1222
|
+
sql += 'partition by ';
|
|
1223
|
+
sql +=
|
|
1224
|
+
map(stmt.partitions, function (partition) {
|
|
1225
|
+
if (isString(partition)) {
|
|
1226
|
+
return self.formatter.columnize(partition);
|
|
1227
|
+
} else return self.formatter.columnize(partition.column) + (partition.order ? ' ' + partition.order : '');
|
|
1228
|
+
}).join(', ') + ' ';
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
sql += 'order by ';
|
|
1232
|
+
sql += map(stmt.order, function (order) {
|
|
1233
|
+
if (isString(order)) {
|
|
1234
|
+
return self.formatter.columnize(order);
|
|
1235
|
+
} else return self.formatter.columnize(order.column) + (order.order ? ' ' + order.order : '');
|
|
1236
|
+
}).join(', ');
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
sql += ')';
|
|
1240
|
+
|
|
1241
|
+
if (stmt.alias) {
|
|
1242
|
+
sql += ' as ' + stmt.alias;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
return sql;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
// Compiles all `with` statements on the query.
|
|
1249
|
+
with() {
|
|
1250
|
+
if (!this.grouped.with || !this.grouped.with.length) {
|
|
1251
|
+
return '';
|
|
1252
|
+
}
|
|
1253
|
+
const withs = this.grouped.with;
|
|
1254
|
+
if (!withs) return;
|
|
1255
|
+
const sql = [];
|
|
1256
|
+
let i = -1;
|
|
1257
|
+
let isRecursive = false;
|
|
1258
|
+
while (++i < withs.length) {
|
|
1259
|
+
const stmt = withs[i];
|
|
1260
|
+
if (stmt.recursive) {
|
|
1261
|
+
isRecursive = true;
|
|
1262
|
+
}
|
|
1263
|
+
const val = this[stmt.type](stmt);
|
|
1264
|
+
sql.push(val);
|
|
1265
|
+
}
|
|
1266
|
+
return `with ${isRecursive ? 'recursive ' : ''}${sql.join(', ')} `;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
withWrapped(statement) {
|
|
1270
|
+
const val = rawOrFn_(
|
|
1271
|
+
statement.value,
|
|
1272
|
+
undefined,
|
|
1273
|
+
this.builder,
|
|
1274
|
+
this.client,
|
|
1275
|
+
this.bindingsHolder
|
|
1276
|
+
);
|
|
1277
|
+
const columnList = statement.columnList
|
|
1278
|
+
? '(' +
|
|
1279
|
+
columnize_(
|
|
1280
|
+
statement.columnList,
|
|
1281
|
+
this.builder,
|
|
1282
|
+
this.client,
|
|
1283
|
+
this.bindingsHolder
|
|
1284
|
+
) +
|
|
1285
|
+
')'
|
|
1286
|
+
: '';
|
|
1287
|
+
const materialized =
|
|
1288
|
+
statement.materialized === undefined
|
|
1289
|
+
? ''
|
|
1290
|
+
: statement.materialized
|
|
1291
|
+
? 'materialized '
|
|
1292
|
+
: 'not materialized ';
|
|
1293
|
+
return (
|
|
1294
|
+
(val &&
|
|
1295
|
+
columnize_(
|
|
1296
|
+
statement.alias,
|
|
1297
|
+
this.builder,
|
|
1298
|
+
this.client,
|
|
1299
|
+
this.bindingsHolder
|
|
1300
|
+
) +
|
|
1301
|
+
columnList +
|
|
1302
|
+
' as ' +
|
|
1303
|
+
materialized +
|
|
1304
|
+
'(' +
|
|
1305
|
+
val +
|
|
1306
|
+
')') ||
|
|
1307
|
+
''
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// Determines whether to add a "not" prefix to the where clause.
|
|
1312
|
+
_not(statement, str) {
|
|
1313
|
+
if (statement.not) return `not ${str}`;
|
|
1314
|
+
return str;
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
_prepInsert(data) {
|
|
1318
|
+
const isRaw = rawOrFn_(
|
|
1319
|
+
data,
|
|
1320
|
+
undefined,
|
|
1321
|
+
this.builder,
|
|
1322
|
+
this.client,
|
|
1323
|
+
this.bindingsHolder
|
|
1324
|
+
);
|
|
1325
|
+
if (isRaw) return isRaw;
|
|
1326
|
+
let columns = [];
|
|
1327
|
+
const values = [];
|
|
1328
|
+
if (!Array.isArray(data)) data = data ? [data] : [];
|
|
1329
|
+
let i = -1;
|
|
1330
|
+
while (++i < data.length) {
|
|
1331
|
+
if (data[i] == null) break;
|
|
1332
|
+
if (i === 0) columns = Object.keys(data[i]).sort();
|
|
1333
|
+
const row = new Array(columns.length);
|
|
1334
|
+
const keys = Object.keys(data[i]);
|
|
1335
|
+
let j = -1;
|
|
1336
|
+
while (++j < keys.length) {
|
|
1337
|
+
const key = keys[j];
|
|
1338
|
+
let idx = columns.indexOf(key);
|
|
1339
|
+
if (idx === -1) {
|
|
1340
|
+
columns = columns.concat(key).sort();
|
|
1341
|
+
idx = columns.indexOf(key);
|
|
1342
|
+
let k = -1;
|
|
1343
|
+
while (++k < values.length) {
|
|
1344
|
+
values[k].splice(idx, 0, undefined);
|
|
1345
|
+
}
|
|
1346
|
+
row.splice(idx, 0, undefined);
|
|
1347
|
+
}
|
|
1348
|
+
row[idx] = data[i][key];
|
|
1349
|
+
}
|
|
1350
|
+
values.push(row);
|
|
1351
|
+
}
|
|
1352
|
+
return {
|
|
1353
|
+
columns,
|
|
1354
|
+
values,
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// "Preps" the update.
|
|
1359
|
+
_prepUpdate(data = {}) {
|
|
1360
|
+
const { counter = {} } = this.single;
|
|
1361
|
+
|
|
1362
|
+
for (const column of Object.keys(counter)) {
|
|
1363
|
+
//Skip?
|
|
1364
|
+
if (has(data, column)) {
|
|
1365
|
+
//Needed?
|
|
1366
|
+
this.client.logger.warn(
|
|
1367
|
+
`increment/decrement called for a column that has already been specified in main .update() call. Ignoring increment/decrement and using value from .update() call.`
|
|
1368
|
+
);
|
|
1369
|
+
continue;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
let value = counter[column];
|
|
1373
|
+
|
|
1374
|
+
const symbol = value < 0 ? '-' : '+';
|
|
1375
|
+
|
|
1376
|
+
if (symbol === '-') {
|
|
1377
|
+
value = -value;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
data[column] = this.client.raw(`?? ${symbol} ?`, [column, value]);
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
data = omitBy(data, isUndefined);
|
|
1384
|
+
|
|
1385
|
+
const vals = [];
|
|
1386
|
+
const columns = Object.keys(data);
|
|
1387
|
+
let i = -1;
|
|
1388
|
+
|
|
1389
|
+
while (++i < columns.length) {
|
|
1390
|
+
vals.push(
|
|
1391
|
+
wrap_(
|
|
1392
|
+
columns[i],
|
|
1393
|
+
undefined,
|
|
1394
|
+
this.builder,
|
|
1395
|
+
this.client,
|
|
1396
|
+
this.bindingsHolder
|
|
1397
|
+
) +
|
|
1398
|
+
' = ' +
|
|
1399
|
+
this.client.parameter(
|
|
1400
|
+
data[columns[i]],
|
|
1401
|
+
this.builder,
|
|
1402
|
+
this.bindingsHolder
|
|
1403
|
+
)
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
if (isEmpty(vals)) {
|
|
1408
|
+
throw new Error(
|
|
1409
|
+
[
|
|
1410
|
+
'Empty .update() call detected!',
|
|
1411
|
+
'Update data does not contain any values to update.',
|
|
1412
|
+
'This will result in a faulty query.',
|
|
1413
|
+
this.single.table ? `Table: ${this.single.table}.` : '',
|
|
1414
|
+
this.single.update
|
|
1415
|
+
? `Columns: ${Object.keys(this.single.update)}.`
|
|
1416
|
+
: '',
|
|
1417
|
+
].join(' ')
|
|
1418
|
+
);
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
return vals;
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
_formatGroupsItemValue(value, nulls) {
|
|
1425
|
+
const { formatter } = this;
|
|
1426
|
+
let nullOrder = '';
|
|
1427
|
+
if (nulls === 'last') {
|
|
1428
|
+
nullOrder = ' is null';
|
|
1429
|
+
} else if (nulls === 'first') {
|
|
1430
|
+
nullOrder = ' is not null';
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
let groupOrder;
|
|
1434
|
+
if (value instanceof Raw) {
|
|
1435
|
+
groupOrder = unwrapRaw_(
|
|
1436
|
+
value,
|
|
1437
|
+
undefined,
|
|
1438
|
+
this.builder,
|
|
1439
|
+
this.client,
|
|
1440
|
+
this.bindingsHolder
|
|
1441
|
+
);
|
|
1442
|
+
} else if (value instanceof QueryBuilder || nulls) {
|
|
1443
|
+
groupOrder = '(' + formatter.columnize(value) + nullOrder + ')';
|
|
1444
|
+
} else {
|
|
1445
|
+
groupOrder = formatter.columnize(value);
|
|
1446
|
+
}
|
|
1447
|
+
return groupOrder;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
_basicGroupOrder(item, type) {
|
|
1451
|
+
const column = this._formatGroupsItemValue(item.value, item.nulls);
|
|
1452
|
+
const direction =
|
|
1453
|
+
type === 'order' && item.type !== 'orderByRaw'
|
|
1454
|
+
? ` ${direction_(
|
|
1455
|
+
item.direction,
|
|
1456
|
+
this.builder,
|
|
1457
|
+
this.client,
|
|
1458
|
+
this.bindingsHolder
|
|
1459
|
+
)}`
|
|
1460
|
+
: '';
|
|
1461
|
+
return column + direction;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
_groupOrder(item, type) {
|
|
1465
|
+
return this._basicGroupOrder(item, type);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
_groupOrderNulls(item, type) {
|
|
1469
|
+
const column = this._formatGroupsItemValue(item.value);
|
|
1470
|
+
const direction =
|
|
1471
|
+
type === 'order' && item.type !== 'orderByRaw'
|
|
1472
|
+
? ` ${direction_(
|
|
1473
|
+
item.direction,
|
|
1474
|
+
this.builder,
|
|
1475
|
+
this.client,
|
|
1476
|
+
this.bindingsHolder
|
|
1477
|
+
)}`
|
|
1478
|
+
: '';
|
|
1479
|
+
if (item.nulls && !(item.value instanceof Raw)) {
|
|
1480
|
+
return `${column}${direction ? direction : ''} nulls ${item.nulls}`;
|
|
1481
|
+
}
|
|
1482
|
+
return column + direction;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Compiles the `order by` statements.
|
|
1486
|
+
_groupsOrders(type) {
|
|
1487
|
+
const items = this.grouped[type];
|
|
1488
|
+
if (!items) return '';
|
|
1489
|
+
const sql = items.map((item) => {
|
|
1490
|
+
return this._groupOrder(item, type);
|
|
1491
|
+
});
|
|
1492
|
+
return sql.length ? type + ' by ' + sql.join(', ') : '';
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// Get the table name, wrapping it if necessary.
|
|
1496
|
+
// Implemented as a property to prevent ordering issues as described in #704.
|
|
1497
|
+
get tableName() {
|
|
1498
|
+
if (!this._tableName) {
|
|
1499
|
+
// Only call this.formatter.wrap() the first time this property is accessed.
|
|
1500
|
+
let tableName = this.single.table;
|
|
1501
|
+
const schemaName = this.single.schema;
|
|
1502
|
+
|
|
1503
|
+
if (tableName && schemaName) {
|
|
1504
|
+
const isQueryBuilder = tableName instanceof QueryBuilder;
|
|
1505
|
+
const isRawQuery = tableName instanceof Raw;
|
|
1506
|
+
const isFunction = typeof tableName === 'function';
|
|
1507
|
+
|
|
1508
|
+
if (!isQueryBuilder && !isRawQuery && !isFunction) {
|
|
1509
|
+
tableName = `${schemaName}.${tableName}`;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
this._tableName = tableName
|
|
1514
|
+
? // Wrap subQuery with parenthesis, #3485
|
|
1515
|
+
wrap_(
|
|
1516
|
+
tableName,
|
|
1517
|
+
tableName instanceof QueryBuilder,
|
|
1518
|
+
this.builder,
|
|
1519
|
+
this.client,
|
|
1520
|
+
this.bindingsHolder
|
|
1521
|
+
)
|
|
1522
|
+
: '';
|
|
1523
|
+
}
|
|
1524
|
+
return this._tableName;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
_jsonPathWrap(extraction) {
|
|
1528
|
+
return this.client.parameter(
|
|
1529
|
+
extraction.path || extraction[1],
|
|
1530
|
+
this.builder,
|
|
1531
|
+
this.bindingsHolder
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
// Json common functions
|
|
1536
|
+
_jsonExtract(nameFunction, params) {
|
|
1537
|
+
let extractions;
|
|
1538
|
+
if (Array.isArray(params.column)) {
|
|
1539
|
+
extractions = params.column;
|
|
1540
|
+
} else {
|
|
1541
|
+
extractions = [params];
|
|
1542
|
+
}
|
|
1543
|
+
if (!Array.isArray(nameFunction)) {
|
|
1544
|
+
nameFunction = [nameFunction];
|
|
1545
|
+
}
|
|
1546
|
+
return extractions
|
|
1547
|
+
.map((extraction) => {
|
|
1548
|
+
let jsonCol = `${columnize_(
|
|
1549
|
+
extraction.column || extraction[0],
|
|
1550
|
+
this.builder,
|
|
1551
|
+
this.client,
|
|
1552
|
+
this.bindingsHolder
|
|
1553
|
+
)}, ${this._jsonPathWrap(extraction)}`;
|
|
1554
|
+
nameFunction.forEach((f) => {
|
|
1555
|
+
jsonCol = f + '(' + jsonCol + ')';
|
|
1556
|
+
});
|
|
1557
|
+
const alias = extraction.alias || extraction[2];
|
|
1558
|
+
return alias
|
|
1559
|
+
? this.client.alias(jsonCol, this.formatter.wrap(alias))
|
|
1560
|
+
: jsonCol;
|
|
1561
|
+
})
|
|
1562
|
+
.join(', ');
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
_jsonSet(nameFunction, params) {
|
|
1566
|
+
const jsonSet = `${nameFunction}(${columnize_(
|
|
1567
|
+
params.column,
|
|
1568
|
+
this.builder,
|
|
1569
|
+
this.client,
|
|
1570
|
+
this.bindingsHolder
|
|
1571
|
+
)}, ${this.client.parameter(
|
|
1572
|
+
params.path,
|
|
1573
|
+
this.builder,
|
|
1574
|
+
this.bindingsHolder
|
|
1575
|
+
)}, ${this.client.parameter(
|
|
1576
|
+
params.value,
|
|
1577
|
+
this.builder,
|
|
1578
|
+
this.bindingsHolder
|
|
1579
|
+
)})`;
|
|
1580
|
+
return params.alias
|
|
1581
|
+
? this.client.alias(jsonSet, this.formatter.wrap(params.alias))
|
|
1582
|
+
: jsonSet;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
_whereJsonPath(nameFunction, statement) {
|
|
1586
|
+
return `${nameFunction}(${this._columnClause(
|
|
1587
|
+
statement
|
|
1588
|
+
)}, ${this._jsonPathWrap({ path: statement.jsonPath })}) ${operator_(
|
|
1589
|
+
statement.operator,
|
|
1590
|
+
this.builder,
|
|
1591
|
+
this.client,
|
|
1592
|
+
this.bindingsHolder
|
|
1593
|
+
)} ${this._jsonValueClause(statement)}`;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
_onJsonPathEquals(nameJoinFunction, clause) {
|
|
1597
|
+
return (
|
|
1598
|
+
nameJoinFunction +
|
|
1599
|
+
'(' +
|
|
1600
|
+
wrap_(
|
|
1601
|
+
clause.columnFirst,
|
|
1602
|
+
undefined,
|
|
1603
|
+
this.builder,
|
|
1604
|
+
this.client,
|
|
1605
|
+
this.bindingsHolder
|
|
1606
|
+
) +
|
|
1607
|
+
', ' +
|
|
1608
|
+
this.client.parameter(
|
|
1609
|
+
clause.jsonPathFirst,
|
|
1610
|
+
this.builder,
|
|
1611
|
+
this.bindingsHolder
|
|
1612
|
+
) +
|
|
1613
|
+
') = ' +
|
|
1614
|
+
nameJoinFunction +
|
|
1615
|
+
'(' +
|
|
1616
|
+
wrap_(
|
|
1617
|
+
clause.columnSecond,
|
|
1618
|
+
undefined,
|
|
1619
|
+
this.builder,
|
|
1620
|
+
this.client,
|
|
1621
|
+
this.bindingsHolder
|
|
1622
|
+
) +
|
|
1623
|
+
', ' +
|
|
1624
|
+
this.client.parameter(
|
|
1625
|
+
clause.jsonPathSecond,
|
|
1626
|
+
this.builder,
|
|
1627
|
+
this.bindingsHolder
|
|
1628
|
+
) +
|
|
1629
|
+
')'
|
|
1630
|
+
);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
module.exports = QueryCompiler;
|