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,1793 +1,1793 @@
|
|
|
1
|
-
// Builder
|
|
2
|
-
// -------
|
|
3
|
-
const assert = require('assert');
|
|
4
|
-
const { EventEmitter } = require('events');
|
|
5
|
-
const assign = require('lodash/assign');
|
|
6
|
-
const clone = require('lodash/clone');
|
|
7
|
-
const each = require('lodash/each');
|
|
8
|
-
const isEmpty = require('lodash/isEmpty');
|
|
9
|
-
const isPlainObject = require('lodash/isPlainObject');
|
|
10
|
-
const last = require('lodash/last');
|
|
11
|
-
const reject = require('lodash/reject');
|
|
12
|
-
const tail = require('lodash/tail');
|
|
13
|
-
const toArray = require('lodash/toArray');
|
|
14
|
-
|
|
15
|
-
const { addQueryContext, normalizeArr } = require('../util/helpers');
|
|
16
|
-
const JoinClause = require('./joinclause');
|
|
17
|
-
const Analytic = require('./analytic');
|
|
18
|
-
const saveAsyncStack = require('../util/save-async-stack');
|
|
19
|
-
const {
|
|
20
|
-
isBoolean,
|
|
21
|
-
isNumber,
|
|
22
|
-
isObject,
|
|
23
|
-
isString,
|
|
24
|
-
isFunction,
|
|
25
|
-
} = require('../util/is');
|
|
26
|
-
|
|
27
|
-
const { lockMode, waitMode } = require('./constants');
|
|
28
|
-
const {
|
|
29
|
-
augmentWithBuilderInterface,
|
|
30
|
-
} = require('../builder-interface-augmenter');
|
|
31
|
-
|
|
32
|
-
const SELECT_COMMANDS = new Set(['pluck', 'first', 'select']);
|
|
33
|
-
const CLEARABLE_STATEMENTS = new Set([
|
|
34
|
-
'with',
|
|
35
|
-
'select',
|
|
36
|
-
'columns',
|
|
37
|
-
'hintComments',
|
|
38
|
-
'where',
|
|
39
|
-
'union',
|
|
40
|
-
'join',
|
|
41
|
-
'group',
|
|
42
|
-
'order',
|
|
43
|
-
'having',
|
|
44
|
-
'limit',
|
|
45
|
-
'offset',
|
|
46
|
-
'counter',
|
|
47
|
-
'counters',
|
|
48
|
-
]);
|
|
49
|
-
const LOCK_MODES = new Set([
|
|
50
|
-
lockMode.forShare,
|
|
51
|
-
lockMode.forUpdate,
|
|
52
|
-
lockMode.forNoKeyUpdate,
|
|
53
|
-
lockMode.forKeyShare,
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
// Typically called from `knex.builder`,
|
|
57
|
-
// start a new query building chain.
|
|
58
|
-
class Builder extends EventEmitter {
|
|
59
|
-
constructor(client) {
|
|
60
|
-
super();
|
|
61
|
-
this.client = client;
|
|
62
|
-
this.and = this;
|
|
63
|
-
this._single = {};
|
|
64
|
-
this._comments = [];
|
|
65
|
-
this._statements = [];
|
|
66
|
-
this._method = 'select';
|
|
67
|
-
if (client.config) {
|
|
68
|
-
saveAsyncStack(this, 5);
|
|
69
|
-
this._debug = client.config.debug;
|
|
70
|
-
}
|
|
71
|
-
// Internal flags used in the builder.
|
|
72
|
-
this._joinFlag = 'inner';
|
|
73
|
-
this._boolFlag = 'and';
|
|
74
|
-
this._notFlag = false;
|
|
75
|
-
this._asColumnFlag = false;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
toString() {
|
|
79
|
-
return this.toQuery();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Convert the current query "toSQL"
|
|
83
|
-
toSQL(method, tz) {
|
|
84
|
-
return this.client.queryCompiler(this).toSQL(method || this._method, tz);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Create a shallow clone of the current query builder.
|
|
88
|
-
clone() {
|
|
89
|
-
const cloned = new this.constructor(this.client);
|
|
90
|
-
cloned._method = this._method;
|
|
91
|
-
cloned._single = clone(this._single);
|
|
92
|
-
cloned._comments = clone(this._comments);
|
|
93
|
-
cloned._statements = clone(this._statements);
|
|
94
|
-
cloned._debug = this._debug;
|
|
95
|
-
|
|
96
|
-
// `_option` is assigned by the `Interface` mixin.
|
|
97
|
-
if (this._options !== undefined) {
|
|
98
|
-
cloned._options = clone(this._options);
|
|
99
|
-
}
|
|
100
|
-
if (this._queryContext !== undefined) {
|
|
101
|
-
cloned._queryContext = clone(this._queryContext);
|
|
102
|
-
}
|
|
103
|
-
if (this._connection !== undefined) {
|
|
104
|
-
cloned._connection = this._connection;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return cloned;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
timeout(ms, { cancel } = {}) {
|
|
111
|
-
if (isNumber(ms) && ms > 0) {
|
|
112
|
-
this._timeout = ms;
|
|
113
|
-
if (cancel) {
|
|
114
|
-
this.client.assertCanCancelQuery();
|
|
115
|
-
this._cancelOnTimeout = true;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
return this;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// With
|
|
122
|
-
// ------
|
|
123
|
-
isValidStatementArg(statement) {
|
|
124
|
-
return (
|
|
125
|
-
typeof statement === 'function' ||
|
|
126
|
-
statement instanceof Builder ||
|
|
127
|
-
(statement && statement.isRawInstance)
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
_validateWithArgs(alias, statementOrColumnList, nothingOrStatement, method) {
|
|
132
|
-
const [query, columnList] =
|
|
133
|
-
typeof nothingOrStatement === 'undefined'
|
|
134
|
-
? [statementOrColumnList, undefined]
|
|
135
|
-
: [nothingOrStatement, statementOrColumnList];
|
|
136
|
-
if (typeof alias !== 'string') {
|
|
137
|
-
throw new Error(`${method}() first argument must be a string`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (this.isValidStatementArg(query) && typeof columnList === 'undefined') {
|
|
141
|
-
// Validated as two-arg variant (alias, statement).
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Attempt to interpret as three-arg variant (alias, columnList, statement).
|
|
146
|
-
const isNonEmptyNameList =
|
|
147
|
-
Array.isArray(columnList) &&
|
|
148
|
-
columnList.length > 0 &&
|
|
149
|
-
columnList.every((it) => typeof it === 'string');
|
|
150
|
-
if (!isNonEmptyNameList) {
|
|
151
|
-
throw new Error(
|
|
152
|
-
`${method}() second argument must be a statement or non-empty column name list.`
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (this.isValidStatementArg(query)) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
throw new Error(
|
|
160
|
-
`${method}() third argument must be a function / QueryBuilder or a raw when its second argument is a column name list`
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
with(alias, statementOrColumnList, nothingOrStatement) {
|
|
165
|
-
this._validateWithArgs(
|
|
166
|
-
alias,
|
|
167
|
-
statementOrColumnList,
|
|
168
|
-
nothingOrStatement,
|
|
169
|
-
'with'
|
|
170
|
-
);
|
|
171
|
-
return this.withWrapped(alias, statementOrColumnList, nothingOrStatement);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
withMaterialized(alias, statementOrColumnList, nothingOrStatement) {
|
|
175
|
-
throw new Error('With materialized is not supported by this dialect');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
withNotMaterialized(alias, statementOrColumnList, nothingOrStatement) {
|
|
179
|
-
throw new Error('With materialized is not supported by this dialect');
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Helper for compiling any advanced `with` queries.
|
|
183
|
-
withWrapped(alias, statementOrColumnList, nothingOrStatement, materialized) {
|
|
184
|
-
const [query, columnList] =
|
|
185
|
-
typeof nothingOrStatement === 'undefined'
|
|
186
|
-
? [statementOrColumnList, undefined]
|
|
187
|
-
: [nothingOrStatement, statementOrColumnList];
|
|
188
|
-
const statement = {
|
|
189
|
-
grouping: 'with',
|
|
190
|
-
type: 'withWrapped',
|
|
191
|
-
alias: alias,
|
|
192
|
-
columnList,
|
|
193
|
-
value: query,
|
|
194
|
-
};
|
|
195
|
-
if (materialized !== undefined) {
|
|
196
|
-
statement.materialized = materialized;
|
|
197
|
-
}
|
|
198
|
-
this._statements.push(statement);
|
|
199
|
-
return this;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// With Recursive
|
|
203
|
-
// ------
|
|
204
|
-
|
|
205
|
-
withRecursive(alias, statementOrColumnList, nothingOrStatement) {
|
|
206
|
-
this._validateWithArgs(
|
|
207
|
-
alias,
|
|
208
|
-
statementOrColumnList,
|
|
209
|
-
nothingOrStatement,
|
|
210
|
-
'withRecursive'
|
|
211
|
-
);
|
|
212
|
-
return this.withRecursiveWrapped(
|
|
213
|
-
alias,
|
|
214
|
-
statementOrColumnList,
|
|
215
|
-
nothingOrStatement
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Helper for compiling any advanced `withRecursive` queries.
|
|
220
|
-
withRecursiveWrapped(alias, statementOrColumnList, nothingOrStatement) {
|
|
221
|
-
this.withWrapped(alias, statementOrColumnList, nothingOrStatement);
|
|
222
|
-
this._statements[this._statements.length - 1].recursive = true;
|
|
223
|
-
return this;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Select
|
|
227
|
-
// ------
|
|
228
|
-
|
|
229
|
-
// Adds a column or columns to the list of "columns"
|
|
230
|
-
// being selected on the query.
|
|
231
|
-
columns(column) {
|
|
232
|
-
if (!column && column !== 0) return this;
|
|
233
|
-
this._statements.push({
|
|
234
|
-
grouping: 'columns',
|
|
235
|
-
value: normalizeArr(...arguments),
|
|
236
|
-
});
|
|
237
|
-
return this;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Adds a comment to the query
|
|
241
|
-
comment(txt) {
|
|
242
|
-
if (!isString(txt)) {
|
|
243
|
-
throw new Error('Comment must be a string');
|
|
244
|
-
}
|
|
245
|
-
const forbiddenChars = ['/*', '*/', '?'];
|
|
246
|
-
if (forbiddenChars.some((chars) => txt.includes(chars))) {
|
|
247
|
-
throw new Error(`Cannot include ${forbiddenChars.join(', ')} in comment`);
|
|
248
|
-
}
|
|
249
|
-
this._comments.push({
|
|
250
|
-
comment: txt,
|
|
251
|
-
});
|
|
252
|
-
return this;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Allow for a sub-select to be explicitly aliased as a column,
|
|
256
|
-
// without needing to compile the query in a where.
|
|
257
|
-
as(column) {
|
|
258
|
-
this._single.as = column;
|
|
259
|
-
return this;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Adds a single hint or an array of hits to the list of "hintComments" on the query.
|
|
263
|
-
hintComment(hints) {
|
|
264
|
-
hints = Array.isArray(hints) ? hints : [hints];
|
|
265
|
-
if (hints.some((hint) => !isString(hint))) {
|
|
266
|
-
throw new Error('Hint comment must be a string');
|
|
267
|
-
}
|
|
268
|
-
if (hints.some((hint) => hint.includes('/*') || hint.includes('*/'))) {
|
|
269
|
-
throw new Error('Hint comment cannot include "/*" or "*/"');
|
|
270
|
-
}
|
|
271
|
-
if (hints.some((hint) => hint.includes('?'))) {
|
|
272
|
-
throw new Error('Hint comment cannot include "?"');
|
|
273
|
-
}
|
|
274
|
-
this._statements.push({
|
|
275
|
-
grouping: 'hintComments',
|
|
276
|
-
value: hints,
|
|
277
|
-
});
|
|
278
|
-
return this;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Prepends the `schemaName` on `tableName` defined by `.table` and `.join`.
|
|
282
|
-
withSchema(schemaName) {
|
|
283
|
-
this._single.schema = schemaName;
|
|
284
|
-
return this;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Sets the `tableName` on the query.
|
|
288
|
-
// Alias to "from" for select and "into" for insert statements
|
|
289
|
-
// e.g. builder.insert({a: value}).into('tableName')
|
|
290
|
-
// `options`: options object containing keys:
|
|
291
|
-
// - `only`: whether the query should use SQL's ONLY to not return
|
|
292
|
-
// inheriting table data. Defaults to false.
|
|
293
|
-
table(tableName, options = {}) {
|
|
294
|
-
this._single.table = tableName;
|
|
295
|
-
this._single.only = options.only === true;
|
|
296
|
-
return this;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Adds a `distinct` clause to the query.
|
|
300
|
-
distinct(...args) {
|
|
301
|
-
this._statements.push({
|
|
302
|
-
grouping: 'columns',
|
|
303
|
-
value: normalizeArr(...args),
|
|
304
|
-
distinct: true,
|
|
305
|
-
});
|
|
306
|
-
return this;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
distinctOn(...args) {
|
|
310
|
-
if (isEmpty(args)) {
|
|
311
|
-
throw new Error('distinctOn requires at least on argument');
|
|
312
|
-
}
|
|
313
|
-
this._statements.push({
|
|
314
|
-
grouping: 'columns',
|
|
315
|
-
value: normalizeArr(...args),
|
|
316
|
-
distinctOn: true,
|
|
317
|
-
});
|
|
318
|
-
return this;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Adds a join clause to the query, allowing for advanced joins
|
|
322
|
-
// with an anonymous function as the second argument.
|
|
323
|
-
join(table, first, ...args) {
|
|
324
|
-
let join;
|
|
325
|
-
const schema =
|
|
326
|
-
table instanceof Builder || typeof table === 'function'
|
|
327
|
-
? undefined
|
|
328
|
-
: this._single.schema;
|
|
329
|
-
const joinType = this._joinType();
|
|
330
|
-
if (typeof first === 'function') {
|
|
331
|
-
join = new JoinClause(table, joinType, schema);
|
|
332
|
-
first.call(join, join);
|
|
333
|
-
} else if (joinType === 'raw') {
|
|
334
|
-
join = new JoinClause(this.client.raw(table, first), 'raw');
|
|
335
|
-
} else {
|
|
336
|
-
join = new JoinClause(table, joinType, schema);
|
|
337
|
-
if (first) {
|
|
338
|
-
join.on(first, ...args);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
this._statements.push(join);
|
|
342
|
-
return this;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
using(tables) {
|
|
346
|
-
throw new Error(
|
|
347
|
-
"'using' function is only available in PostgreSQL dialect with Delete statements."
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// JOIN blocks:
|
|
352
|
-
innerJoin(...args) {
|
|
353
|
-
return this._joinType('inner').join(...args);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
leftJoin(...args) {
|
|
357
|
-
return this._joinType('left').join(...args);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
leftOuterJoin(...args) {
|
|
361
|
-
return this._joinType('left outer').join(...args);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
rightJoin(...args) {
|
|
365
|
-
return this._joinType('right').join(...args);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
rightOuterJoin(...args) {
|
|
369
|
-
return this._joinType('right outer').join(...args);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
outerJoin(...args) {
|
|
373
|
-
return this._joinType('outer').join(...args);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
fullOuterJoin(...args) {
|
|
377
|
-
return this._joinType('full outer').join(...args);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
crossJoin(...args) {
|
|
381
|
-
return this._joinType('cross').join(...args);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
joinRaw(...args) {
|
|
385
|
-
return this._joinType('raw').join(...args);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// Where modifiers:
|
|
389
|
-
get or() {
|
|
390
|
-
return this._bool('or');
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
get not() {
|
|
394
|
-
return this._not(true);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// The where function can be used in several ways:
|
|
398
|
-
// The most basic is `where(key, value)`, which expands to
|
|
399
|
-
// where key = value.
|
|
400
|
-
where(column, operator, value) {
|
|
401
|
-
const argsLength = arguments.length;
|
|
402
|
-
|
|
403
|
-
// Support "where true || where false"
|
|
404
|
-
if (column === false || column === true) {
|
|
405
|
-
return this.where(1, '=', column ? 1 : 0);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Check if the column is a function, in which case it's
|
|
409
|
-
// a where statement wrapped in parens.
|
|
410
|
-
if (typeof column === 'function') {
|
|
411
|
-
return this.whereWrapped(column);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
// Allows `where({id: 2})` syntax.
|
|
415
|
-
if (isObject(column) && !column.isRawInstance)
|
|
416
|
-
return this._objectWhere(column);
|
|
417
|
-
|
|
418
|
-
// Allow a raw statement to be passed along to the query.
|
|
419
|
-
if (column && column.isRawInstance && argsLength === 1)
|
|
420
|
-
return this.whereRaw(column);
|
|
421
|
-
|
|
422
|
-
// Enable the where('key', value) syntax, only when there
|
|
423
|
-
// are explicitly two arguments passed, so it's not possible to
|
|
424
|
-
// do where('key', '!=') and have that turn into where key != null
|
|
425
|
-
if (argsLength === 2) {
|
|
426
|
-
value = operator;
|
|
427
|
-
operator = '=';
|
|
428
|
-
|
|
429
|
-
// If the value is null, and it's a two argument query,
|
|
430
|
-
// we assume we're going for a `whereNull`.
|
|
431
|
-
if (value === null) {
|
|
432
|
-
return this.whereNull(column);
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// lower case the operator for comparison purposes
|
|
437
|
-
const checkOperator = `${operator}`.toLowerCase().trim();
|
|
438
|
-
|
|
439
|
-
// If there are 3 arguments, check whether 'in' is one of them.
|
|
440
|
-
if (argsLength === 3) {
|
|
441
|
-
if (checkOperator === 'in' || checkOperator === 'not in') {
|
|
442
|
-
return this._not(checkOperator === 'not in').whereIn(column, value);
|
|
443
|
-
}
|
|
444
|
-
if (checkOperator === 'between' || checkOperator === 'not between') {
|
|
445
|
-
return this._not(checkOperator === 'not between').whereBetween(
|
|
446
|
-
column,
|
|
447
|
-
value
|
|
448
|
-
);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// If the value is still null, check whether they're meaning
|
|
453
|
-
// where value is null
|
|
454
|
-
if (value === null) {
|
|
455
|
-
// Check for .where(key, 'is', null) or .where(key, 'is not', 'null');
|
|
456
|
-
if (checkOperator === 'is' || checkOperator === 'is not') {
|
|
457
|
-
return this._not(checkOperator === 'is not').whereNull(column);
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Push onto the where statement stack.
|
|
462
|
-
this._statements.push({
|
|
463
|
-
grouping: 'where',
|
|
464
|
-
type: 'whereBasic',
|
|
465
|
-
column,
|
|
466
|
-
operator,
|
|
467
|
-
value,
|
|
468
|
-
not: this._not(),
|
|
469
|
-
bool: this._bool(),
|
|
470
|
-
asColumn: this._asColumnFlag,
|
|
471
|
-
});
|
|
472
|
-
return this;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
whereColumn(...args) {
|
|
476
|
-
this._asColumnFlag = true;
|
|
477
|
-
this.where(...args);
|
|
478
|
-
this._asColumnFlag = false;
|
|
479
|
-
return this;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// Adds an `or where` clause to the query.
|
|
483
|
-
orWhere(column, ...args) {
|
|
484
|
-
this._bool('or');
|
|
485
|
-
const obj = column;
|
|
486
|
-
if (isObject(obj) && !obj.isRawInstance) {
|
|
487
|
-
return this.whereWrapped(function () {
|
|
488
|
-
for (const key in obj) {
|
|
489
|
-
this.andWhere(key, obj[key]);
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
return this.where(column, ...args);
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
orWhereColumn(column, ...args) {
|
|
497
|
-
this._bool('or');
|
|
498
|
-
const obj = column;
|
|
499
|
-
if (isObject(obj) && !obj.isRawInstance) {
|
|
500
|
-
return this.whereWrapped(function () {
|
|
501
|
-
for (const key in obj) {
|
|
502
|
-
this.andWhereColumn(key, '=', obj[key]);
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
return this.whereColumn(column, ...args);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// Adds an `not where` clause to the query.
|
|
510
|
-
whereNot(column, ...args) {
|
|
511
|
-
if (args.length >= 2) {
|
|
512
|
-
if (args[0] === 'in' || args[0] === 'between') {
|
|
513
|
-
this.client.logger.warn(
|
|
514
|
-
'whereNot is not suitable for "in" and "between" type subqueries. You should use "not in" and "not between" instead.'
|
|
515
|
-
);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
return this._not(true).where(column, ...args);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
whereNotColumn(...args) {
|
|
522
|
-
return this._not(true).whereColumn(...args);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// Adds an `or not where` clause to the query.
|
|
526
|
-
orWhereNot(...args) {
|
|
527
|
-
return this._bool('or').whereNot(...args);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
orWhereNotColumn(...args) {
|
|
531
|
-
return this._bool('or').whereNotColumn(...args);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// Processes an object literal provided in a "where" clause.
|
|
535
|
-
_objectWhere(obj) {
|
|
536
|
-
const boolVal = this._bool();
|
|
537
|
-
const notVal = this._not() ? 'Not' : '';
|
|
538
|
-
for (const key in obj) {
|
|
539
|
-
this[boolVal + 'Where' + notVal](key, obj[key]);
|
|
540
|
-
}
|
|
541
|
-
return this;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Adds a raw `where` clause to the query.
|
|
545
|
-
whereRaw(sql, bindings) {
|
|
546
|
-
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
547
|
-
|
|
548
|
-
this._statements.push({
|
|
549
|
-
grouping: 'where',
|
|
550
|
-
type: 'whereRaw',
|
|
551
|
-
value: raw,
|
|
552
|
-
not: this._not(),
|
|
553
|
-
bool: this._bool(),
|
|
554
|
-
});
|
|
555
|
-
return this;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
orWhereRaw(sql, bindings) {
|
|
559
|
-
return this._bool('or').whereRaw(sql, bindings);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Helper for compiling any advanced `where` queries.
|
|
563
|
-
whereWrapped(callback) {
|
|
564
|
-
this._statements.push({
|
|
565
|
-
grouping: 'where',
|
|
566
|
-
type: 'whereWrapped',
|
|
567
|
-
value: callback,
|
|
568
|
-
not: this._not(),
|
|
569
|
-
bool: this._bool(),
|
|
570
|
-
});
|
|
571
|
-
return this;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// Adds a `where exists` clause to the query.
|
|
575
|
-
whereExists(callback) {
|
|
576
|
-
this._statements.push({
|
|
577
|
-
grouping: 'where',
|
|
578
|
-
type: 'whereExists',
|
|
579
|
-
value: callback,
|
|
580
|
-
not: this._not(),
|
|
581
|
-
bool: this._bool(),
|
|
582
|
-
});
|
|
583
|
-
return this;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// Adds an `or where exists` clause to the query.
|
|
587
|
-
orWhereExists(callback) {
|
|
588
|
-
return this._bool('or').whereExists(callback);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// Adds a `where not exists` clause to the query.
|
|
592
|
-
whereNotExists(callback) {
|
|
593
|
-
return this._not(true).whereExists(callback);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Adds a `or where not exists` clause to the query.
|
|
597
|
-
orWhereNotExists(callback) {
|
|
598
|
-
return this._bool('or').whereNotExists(callback);
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Adds a `where in` clause to the query.
|
|
602
|
-
whereIn(column, values) {
|
|
603
|
-
if (Array.isArray(values) && isEmpty(values))
|
|
604
|
-
return this.where(this._not());
|
|
605
|
-
this._statements.push({
|
|
606
|
-
grouping: 'where',
|
|
607
|
-
type: 'whereIn',
|
|
608
|
-
column,
|
|
609
|
-
value: values,
|
|
610
|
-
not: this._not(),
|
|
611
|
-
bool: this._bool(),
|
|
612
|
-
});
|
|
613
|
-
return this;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
// Adds a `or where in` clause to the query.
|
|
617
|
-
orWhereIn(column, values) {
|
|
618
|
-
return this._bool('or').whereIn(column, values);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
// Adds a `where not in` clause to the query.
|
|
622
|
-
whereNotIn(column, values) {
|
|
623
|
-
return this._not(true).whereIn(column, values);
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Adds a `or where not in` clause to the query.
|
|
627
|
-
orWhereNotIn(column, values) {
|
|
628
|
-
return this._bool('or')._not(true).whereIn(column, values);
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// Adds a `where null` clause to the query.
|
|
632
|
-
whereNull(column) {
|
|
633
|
-
this._statements.push({
|
|
634
|
-
grouping: 'where',
|
|
635
|
-
type: 'whereNull',
|
|
636
|
-
column,
|
|
637
|
-
not: this._not(),
|
|
638
|
-
bool: this._bool(),
|
|
639
|
-
});
|
|
640
|
-
return this;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Adds a `or where null` clause to the query.
|
|
644
|
-
orWhereNull(column) {
|
|
645
|
-
return this._bool('or').whereNull(column);
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Adds a `where not null` clause to the query.
|
|
649
|
-
whereNotNull(column) {
|
|
650
|
-
return this._not(true).whereNull(column);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
// Adds a `or where not null` clause to the query.
|
|
654
|
-
orWhereNotNull(column) {
|
|
655
|
-
return this._bool('or').whereNotNull(column);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
// Adds a `where between` clause to the query.
|
|
659
|
-
whereBetween(column, values) {
|
|
660
|
-
assert(
|
|
661
|
-
Array.isArray(values),
|
|
662
|
-
'The second argument to whereBetween must be an array.'
|
|
663
|
-
);
|
|
664
|
-
assert(
|
|
665
|
-
values.length === 2,
|
|
666
|
-
'You must specify 2 values for the whereBetween clause'
|
|
667
|
-
);
|
|
668
|
-
this._statements.push({
|
|
669
|
-
grouping: 'where',
|
|
670
|
-
type: 'whereBetween',
|
|
671
|
-
column,
|
|
672
|
-
value: values,
|
|
673
|
-
not: this._not(),
|
|
674
|
-
bool: this._bool(),
|
|
675
|
-
});
|
|
676
|
-
return this;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// Adds a `where not between` clause to the query.
|
|
680
|
-
whereNotBetween(column, values) {
|
|
681
|
-
return this._not(true).whereBetween(column, values);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// Adds a `or where between` clause to the query.
|
|
685
|
-
orWhereBetween(column, values) {
|
|
686
|
-
return this._bool('or').whereBetween(column, values);
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// Adds a `or where not between` clause to the query.
|
|
690
|
-
orWhereNotBetween(column, values) {
|
|
691
|
-
return this._bool('or').whereNotBetween(column, values);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
_whereLike(type, column, value) {
|
|
695
|
-
this._statements.push({
|
|
696
|
-
grouping: 'where',
|
|
697
|
-
type: type,
|
|
698
|
-
column,
|
|
699
|
-
value: value,
|
|
700
|
-
not: this._not(),
|
|
701
|
-
bool: this._bool(),
|
|
702
|
-
asColumn: this._asColumnFlag,
|
|
703
|
-
});
|
|
704
|
-
return this;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
// Adds a `where like` clause to the query.
|
|
708
|
-
whereLike(column, value) {
|
|
709
|
-
return this._whereLike('whereLike', column, value);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
// Adds a `or where like` clause to the query.
|
|
713
|
-
orWhereLike(column, value) {
|
|
714
|
-
return this._bool('or')._whereLike('whereLike', column, value);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
// Adds a `where ilike` clause to the query.
|
|
718
|
-
whereILike(column, value) {
|
|
719
|
-
return this._whereLike('whereILike', column, value);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// Adds a `or where ilike` clause to the query.
|
|
723
|
-
orWhereILike(column, value) {
|
|
724
|
-
return this._bool('or')._whereLike('whereILike', column, value);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
// Adds a `group by` clause to the query.
|
|
728
|
-
groupBy(item) {
|
|
729
|
-
if (item && item.isRawInstance) {
|
|
730
|
-
return this.groupByRaw.apply(this, arguments);
|
|
731
|
-
}
|
|
732
|
-
this._statements.push({
|
|
733
|
-
grouping: 'group',
|
|
734
|
-
type: 'groupByBasic',
|
|
735
|
-
value: normalizeArr(...arguments),
|
|
736
|
-
});
|
|
737
|
-
return this;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
// Adds a raw `group by` clause to the query.
|
|
741
|
-
groupByRaw(sql, bindings) {
|
|
742
|
-
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
743
|
-
this._statements.push({
|
|
744
|
-
grouping: 'group',
|
|
745
|
-
type: 'groupByRaw',
|
|
746
|
-
value: raw,
|
|
747
|
-
});
|
|
748
|
-
return this;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
// Adds a `order by` clause to the query.
|
|
752
|
-
orderBy(column, direction, nulls = '') {
|
|
753
|
-
if (Array.isArray(column)) {
|
|
754
|
-
return this._orderByArray(column);
|
|
755
|
-
}
|
|
756
|
-
this._statements.push({
|
|
757
|
-
grouping: 'order',
|
|
758
|
-
type: 'orderByBasic',
|
|
759
|
-
value: column,
|
|
760
|
-
direction,
|
|
761
|
-
nulls,
|
|
762
|
-
});
|
|
763
|
-
return this;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// Adds a `order by` with multiple columns to the query.
|
|
767
|
-
_orderByArray(columnDefs) {
|
|
768
|
-
for (let i = 0; i < columnDefs.length; i++) {
|
|
769
|
-
const columnInfo = columnDefs[i];
|
|
770
|
-
if (isObject(columnInfo)) {
|
|
771
|
-
this._statements.push({
|
|
772
|
-
grouping: 'order',
|
|
773
|
-
type: 'orderByBasic',
|
|
774
|
-
value: columnInfo['column'],
|
|
775
|
-
direction: columnInfo['order'],
|
|
776
|
-
nulls: columnInfo['nulls'],
|
|
777
|
-
});
|
|
778
|
-
} else if (isString(columnInfo) || isNumber(columnInfo)) {
|
|
779
|
-
this._statements.push({
|
|
780
|
-
grouping: 'order',
|
|
781
|
-
type: 'orderByBasic',
|
|
782
|
-
value: columnInfo,
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
return this;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// Add a raw `order by` clause to the query.
|
|
790
|
-
orderByRaw(sql, bindings) {
|
|
791
|
-
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
792
|
-
this._statements.push({
|
|
793
|
-
grouping: 'order',
|
|
794
|
-
type: 'orderByRaw',
|
|
795
|
-
value: raw,
|
|
796
|
-
});
|
|
797
|
-
return this;
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
_union(clause, args) {
|
|
801
|
-
let callbacks = args[0];
|
|
802
|
-
let wrap = args[1];
|
|
803
|
-
if (args.length === 1 || (args.length === 2 && isBoolean(wrap))) {
|
|
804
|
-
if (!Array.isArray(callbacks)) {
|
|
805
|
-
callbacks = [callbacks];
|
|
806
|
-
}
|
|
807
|
-
for (let i = 0, l = callbacks.length; i < l; i++) {
|
|
808
|
-
this._statements.push({
|
|
809
|
-
grouping: 'union',
|
|
810
|
-
clause: clause,
|
|
811
|
-
value: callbacks[i],
|
|
812
|
-
wrap: wrap || false,
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
} else {
|
|
816
|
-
callbacks = toArray(args).slice(0, args.length - 1);
|
|
817
|
-
wrap = args[args.length - 1];
|
|
818
|
-
if (!isBoolean(wrap)) {
|
|
819
|
-
callbacks.push(wrap);
|
|
820
|
-
wrap = false;
|
|
821
|
-
}
|
|
822
|
-
this._union(clause, [callbacks, wrap]);
|
|
823
|
-
}
|
|
824
|
-
return this;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
// Add a union statement to the query.
|
|
828
|
-
union(...args) {
|
|
829
|
-
return this._union('union', args);
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// Adds a union all statement to the query.
|
|
833
|
-
unionAll(...args) {
|
|
834
|
-
return this._union('union all', args);
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
intersect(...args) {
|
|
838
|
-
return this._union('intersect', args);
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
except(...args) {
|
|
842
|
-
return this._union('except', args);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// Adds a `having` clause to the query.
|
|
846
|
-
having(column, operator, value) {
|
|
847
|
-
if (column.isRawInstance && arguments.length === 1) {
|
|
848
|
-
return this.havingRaw(column);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// Check if the column is a function, in which case it's
|
|
852
|
-
// a having statement wrapped in parens.
|
|
853
|
-
if (typeof column === 'function') {
|
|
854
|
-
return this.havingWrapped(column);
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
this._statements.push({
|
|
858
|
-
grouping: 'having',
|
|
859
|
-
type: 'havingBasic',
|
|
860
|
-
column,
|
|
861
|
-
operator,
|
|
862
|
-
value,
|
|
863
|
-
bool: this._bool(),
|
|
864
|
-
not: this._not(),
|
|
865
|
-
});
|
|
866
|
-
return this;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
orHaving(column, ...args) {
|
|
870
|
-
this._bool('or');
|
|
871
|
-
const obj = column;
|
|
872
|
-
if (isObject(obj) && !obj.isRawInstance) {
|
|
873
|
-
return this.havingWrapped(function () {
|
|
874
|
-
for (const key in obj) {
|
|
875
|
-
this.andHaving(key, obj[key]);
|
|
876
|
-
}
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
return this.having(column, ...args);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// Helper for compiling any advanced `having` queries.
|
|
883
|
-
havingWrapped(callback) {
|
|
884
|
-
this._statements.push({
|
|
885
|
-
grouping: 'having',
|
|
886
|
-
type: 'havingWrapped',
|
|
887
|
-
value: callback,
|
|
888
|
-
bool: this._bool(),
|
|
889
|
-
not: this._not(),
|
|
890
|
-
});
|
|
891
|
-
return this;
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
havingNull(column) {
|
|
895
|
-
this._statements.push({
|
|
896
|
-
grouping: 'having',
|
|
897
|
-
type: 'havingNull',
|
|
898
|
-
column,
|
|
899
|
-
not: this._not(),
|
|
900
|
-
bool: this._bool(),
|
|
901
|
-
});
|
|
902
|
-
return this;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
orHavingNull(callback) {
|
|
906
|
-
return this._bool('or').havingNull(callback);
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
havingNotNull(callback) {
|
|
910
|
-
return this._not(true).havingNull(callback);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
orHavingNotNull(callback) {
|
|
914
|
-
return this._not(true)._bool('or').havingNull(callback);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
havingExists(callback) {
|
|
918
|
-
this._statements.push({
|
|
919
|
-
grouping: 'having',
|
|
920
|
-
type: 'havingExists',
|
|
921
|
-
value: callback,
|
|
922
|
-
not: this._not(),
|
|
923
|
-
bool: this._bool(),
|
|
924
|
-
});
|
|
925
|
-
return this;
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
orHavingExists(callback) {
|
|
929
|
-
return this._bool('or').havingExists(callback);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
havingNotExists(callback) {
|
|
933
|
-
return this._not(true).havingExists(callback);
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
orHavingNotExists(callback) {
|
|
937
|
-
return this._not(true)._bool('or').havingExists(callback);
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
havingBetween(column, values) {
|
|
941
|
-
assert(
|
|
942
|
-
Array.isArray(values),
|
|
943
|
-
'The second argument to havingBetween must be an array.'
|
|
944
|
-
);
|
|
945
|
-
assert(
|
|
946
|
-
values.length === 2,
|
|
947
|
-
'You must specify 2 values for the havingBetween clause'
|
|
948
|
-
);
|
|
949
|
-
this._statements.push({
|
|
950
|
-
grouping: 'having',
|
|
951
|
-
type: 'havingBetween',
|
|
952
|
-
column,
|
|
953
|
-
value: values,
|
|
954
|
-
not: this._not(),
|
|
955
|
-
bool: this._bool(),
|
|
956
|
-
});
|
|
957
|
-
return this;
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
orHavingBetween(column, values) {
|
|
961
|
-
return this._bool('or').havingBetween(column, values);
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
havingNotBetween(column, values) {
|
|
965
|
-
return this._not(true).havingBetween(column, values);
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
orHavingNotBetween(column, values) {
|
|
969
|
-
return this._not(true)._bool('or').havingBetween(column, values);
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
havingIn(column, values) {
|
|
973
|
-
if (Array.isArray(values) && isEmpty(values))
|
|
974
|
-
return this.where(this._not());
|
|
975
|
-
this._statements.push({
|
|
976
|
-
grouping: 'having',
|
|
977
|
-
type: 'havingIn',
|
|
978
|
-
column,
|
|
979
|
-
value: values,
|
|
980
|
-
not: this._not(),
|
|
981
|
-
bool: this._bool(),
|
|
982
|
-
});
|
|
983
|
-
return this;
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// Adds a `or where in` clause to the query.
|
|
987
|
-
orHavingIn(column, values) {
|
|
988
|
-
return this._bool('or').havingIn(column, values);
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
// Adds a `where not in` clause to the query.
|
|
992
|
-
havingNotIn(column, values) {
|
|
993
|
-
return this._not(true).havingIn(column, values);
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
// Adds a `or where not in` clause to the query.
|
|
997
|
-
orHavingNotIn(column, values) {
|
|
998
|
-
return this._bool('or')._not(true).havingIn(column, values);
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
// Adds a raw `having` clause to the query.
|
|
1002
|
-
havingRaw(sql, bindings) {
|
|
1003
|
-
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
1004
|
-
this._statements.push({
|
|
1005
|
-
grouping: 'having',
|
|
1006
|
-
type: 'havingRaw',
|
|
1007
|
-
value: raw,
|
|
1008
|
-
bool: this._bool(),
|
|
1009
|
-
not: this._not(),
|
|
1010
|
-
});
|
|
1011
|
-
return this;
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
orHavingRaw(sql, bindings) {
|
|
1015
|
-
return this._bool('or').havingRaw(sql, bindings);
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
// set the skip binding parameter (= insert the raw value in the query) for an attribute.
|
|
1019
|
-
_setSkipBinding(attribute, options) {
|
|
1020
|
-
let skipBinding = options;
|
|
1021
|
-
if (isObject(options)) {
|
|
1022
|
-
skipBinding = options.skipBinding;
|
|
1023
|
-
}
|
|
1024
|
-
this._single.skipBinding = this._single.skipBinding || {};
|
|
1025
|
-
this._single.skipBinding[attribute] = skipBinding;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
// Only allow a single "offset" to be set for the current query.
|
|
1029
|
-
offset(value, options) {
|
|
1030
|
-
if (value == null || value.isRawInstance || value instanceof Builder) {
|
|
1031
|
-
// Builder for backward compatibility
|
|
1032
|
-
this._single.offset = value;
|
|
1033
|
-
} else {
|
|
1034
|
-
const val = parseInt(value, 10);
|
|
1035
|
-
if (isNaN(val)) {
|
|
1036
|
-
this.client.logger.warn('A valid integer must be provided to offset');
|
|
1037
|
-
} else if (val < 0) {
|
|
1038
|
-
throw new Error(`A non-negative integer must be provided to offset.`);
|
|
1039
|
-
} else {
|
|
1040
|
-
this._single.offset = val;
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
this._setSkipBinding('offset', options);
|
|
1044
|
-
return this;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
// Only allow a single "limit" to be set for the current query.
|
|
1048
|
-
limit(value, options) {
|
|
1049
|
-
const val = parseInt(value, 10);
|
|
1050
|
-
if (isNaN(val)) {
|
|
1051
|
-
this.client.logger.warn('A valid integer must be provided to limit');
|
|
1052
|
-
} else {
|
|
1053
|
-
this._single.limit = val;
|
|
1054
|
-
this._setSkipBinding('limit', options);
|
|
1055
|
-
}
|
|
1056
|
-
return this;
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// Retrieve the "count" result of the query.
|
|
1060
|
-
count(column, options) {
|
|
1061
|
-
return this._aggregate('count', column || '*', options);
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
// Retrieve the minimum value of a given column.
|
|
1065
|
-
min(column, options) {
|
|
1066
|
-
return this._aggregate('min', column, options);
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
// Retrieve the maximum value of a given column.
|
|
1070
|
-
max(column, options) {
|
|
1071
|
-
return this._aggregate('max', column, options);
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
// Retrieve the sum of the values of a given column.
|
|
1075
|
-
sum(column, options) {
|
|
1076
|
-
return this._aggregate('sum', column, options);
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// Retrieve the average of the values of a given column.
|
|
1080
|
-
avg(column, options) {
|
|
1081
|
-
return this._aggregate('avg', column, options);
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
// Retrieve the "count" of the distinct results of the query.
|
|
1085
|
-
countDistinct(...columns) {
|
|
1086
|
-
let options;
|
|
1087
|
-
if (columns.length > 1 && isPlainObject(last(columns))) {
|
|
1088
|
-
[options] = columns.splice(columns.length - 1, 1);
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
if (!columns.length) {
|
|
1092
|
-
columns = '*';
|
|
1093
|
-
} else if (columns.length === 1) {
|
|
1094
|
-
columns = columns[0];
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
return this._aggregate('count', columns, { ...options, distinct: true });
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
// Retrieve the sum of the distinct values of a given column.
|
|
1101
|
-
sumDistinct(column, options) {
|
|
1102
|
-
return this._aggregate('sum', column, { ...options, distinct: true });
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
// Retrieve the vg of the distinct results of the query.
|
|
1106
|
-
avgDistinct(column, options) {
|
|
1107
|
-
return this._aggregate('avg', column, { ...options, distinct: true });
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
// Increments a column's value by the specified amount.
|
|
1111
|
-
increment(column, amount = 1) {
|
|
1112
|
-
if (isObject(column)) {
|
|
1113
|
-
for (const key in column) {
|
|
1114
|
-
this._counter(key, column[key]);
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
return this;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
return this._counter(column, amount);
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
// Decrements a column's value by the specified amount.
|
|
1124
|
-
decrement(column, amount = 1) {
|
|
1125
|
-
if (isObject(column)) {
|
|
1126
|
-
for (const key in column) {
|
|
1127
|
-
this._counter(key, -column[key]);
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
return this;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
return this._counter(column, -amount);
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
// Clears increments/decrements
|
|
1137
|
-
clearCounters() {
|
|
1138
|
-
this._single.counter = {};
|
|
1139
|
-
return this;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
// Sets the values for a `select` query, informing that only the first
|
|
1143
|
-
// row should be returned (limit 1).
|
|
1144
|
-
first(...args) {
|
|
1145
|
-
if (this._method && this._method !== 'select') {
|
|
1146
|
-
throw new Error(`Cannot chain .first() on "${this._method}" query`);
|
|
1147
|
-
}
|
|
1148
|
-
|
|
1149
|
-
this.select(normalizeArr(...args));
|
|
1150
|
-
this._method = 'first';
|
|
1151
|
-
this.limit(1);
|
|
1152
|
-
return this;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
// Use existing connection to execute the query
|
|
1156
|
-
// Same value that client.acquireConnection() for an according client returns should be passed
|
|
1157
|
-
connection(_connection) {
|
|
1158
|
-
this._connection = _connection;
|
|
1159
|
-
this.client.processPassedConnection(_connection);
|
|
1160
|
-
return this;
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
// Pluck a column from a query.
|
|
1164
|
-
pluck(column) {
|
|
1165
|
-
if (this._method && this._method !== 'select') {
|
|
1166
|
-
throw new Error(`Cannot chain .pluck() on "${this._method}" query`);
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
this._method = 'pluck';
|
|
1170
|
-
this._single.pluck = column;
|
|
1171
|
-
this._statements.push({
|
|
1172
|
-
grouping: 'columns',
|
|
1173
|
-
type: 'pluck',
|
|
1174
|
-
value: column,
|
|
1175
|
-
});
|
|
1176
|
-
return this;
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
// Deprecated. Remove everything from select clause
|
|
1180
|
-
clearSelect() {
|
|
1181
|
-
this._clearGrouping('columns');
|
|
1182
|
-
return this;
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
// Deprecated. Remove everything from where clause
|
|
1186
|
-
clearWhere() {
|
|
1187
|
-
this._clearGrouping('where');
|
|
1188
|
-
return this;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
// Deprecated. Remove everything from group clause
|
|
1192
|
-
clearGroup() {
|
|
1193
|
-
this._clearGrouping('group');
|
|
1194
|
-
return this;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
// Deprecated. Remove everything from order clause
|
|
1198
|
-
clearOrder() {
|
|
1199
|
-
this._clearGrouping('order');
|
|
1200
|
-
return this;
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// Deprecated. Remove everything from having clause
|
|
1204
|
-
clearHaving() {
|
|
1205
|
-
this._clearGrouping('having');
|
|
1206
|
-
return this;
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
// Remove everything from statement clause
|
|
1210
|
-
clear(statement) {
|
|
1211
|
-
if (!CLEARABLE_STATEMENTS.has(statement))
|
|
1212
|
-
throw new Error(`Knex Error: unknown statement '${statement}'`);
|
|
1213
|
-
if (statement.startsWith('counter')) return this.clearCounters();
|
|
1214
|
-
if (statement === 'select') {
|
|
1215
|
-
statement = 'columns';
|
|
1216
|
-
}
|
|
1217
|
-
this._clearGrouping(statement);
|
|
1218
|
-
return this;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
// Insert & Update
|
|
1222
|
-
// ------
|
|
1223
|
-
|
|
1224
|
-
// Sets the values for an `insert` query.
|
|
1225
|
-
insert(values, returning, options) {
|
|
1226
|
-
this._method = 'insert';
|
|
1227
|
-
if (!isEmpty(returning)) this.returning(returning, options);
|
|
1228
|
-
this._single.insert = values;
|
|
1229
|
-
return this;
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
// Sets the values for an `update`, allowing for both
|
|
1233
|
-
// `.update(key, value, [returning])` and `.update(obj, [returning])` syntaxes.
|
|
1234
|
-
update(values, returning, options) {
|
|
1235
|
-
let ret;
|
|
1236
|
-
const obj = this._single.update || {};
|
|
1237
|
-
this._method = 'update';
|
|
1238
|
-
if (isString(values)) {
|
|
1239
|
-
if (isPlainObject(returning)) {
|
|
1240
|
-
obj[values] = JSON.stringify(returning);
|
|
1241
|
-
} else {
|
|
1242
|
-
obj[values] = returning;
|
|
1243
|
-
}
|
|
1244
|
-
if (arguments.length > 2) {
|
|
1245
|
-
ret = arguments[2];
|
|
1246
|
-
}
|
|
1247
|
-
} else {
|
|
1248
|
-
const keys = Object.keys(values);
|
|
1249
|
-
if (this._single.update) {
|
|
1250
|
-
this.client.logger.warn('Update called multiple times with objects.');
|
|
1251
|
-
}
|
|
1252
|
-
let i = -1;
|
|
1253
|
-
while (++i < keys.length) {
|
|
1254
|
-
obj[keys[i]] = values[keys[i]];
|
|
1255
|
-
}
|
|
1256
|
-
ret = arguments[1];
|
|
1257
|
-
}
|
|
1258
|
-
if (!isEmpty(ret)) this.returning(ret, options);
|
|
1259
|
-
this._single.update = obj;
|
|
1260
|
-
return this;
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
// Sets the returning value for the query.
|
|
1264
|
-
returning(returning, options) {
|
|
1265
|
-
this._single.returning = returning;
|
|
1266
|
-
this._single.options = options;
|
|
1267
|
-
return this;
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
onConflict(columns) {
|
|
1271
|
-
if (typeof columns === 'string') {
|
|
1272
|
-
columns = [columns];
|
|
1273
|
-
}
|
|
1274
|
-
return new OnConflictBuilder(this, columns || true);
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
// Delete
|
|
1278
|
-
// ------
|
|
1279
|
-
|
|
1280
|
-
// Executes a delete statement on the query;
|
|
1281
|
-
delete(ret, options) {
|
|
1282
|
-
this._method = 'del';
|
|
1283
|
-
if (!isEmpty(ret)) this.returning(ret, options);
|
|
1284
|
-
return this;
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
// Truncates a table, ends the query chain.
|
|
1288
|
-
truncate(tableName) {
|
|
1289
|
-
this._method = 'truncate';
|
|
1290
|
-
if (tableName) {
|
|
1291
|
-
this._single.table = tableName;
|
|
1292
|
-
}
|
|
1293
|
-
return this;
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
// Retrieves columns for the table specified by `knex(tableName)`
|
|
1297
|
-
columnInfo(column) {
|
|
1298
|
-
this._method = 'columnInfo';
|
|
1299
|
-
this._single.columnInfo = column;
|
|
1300
|
-
return this;
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
// Set a lock for update constraint.
|
|
1304
|
-
forUpdate(...tables) {
|
|
1305
|
-
this._single.lock = lockMode.forUpdate;
|
|
1306
|
-
if (tables.length === 1 && Array.isArray(tables[0])) {
|
|
1307
|
-
this._single.lockTables = tables[0];
|
|
1308
|
-
} else {
|
|
1309
|
-
this._single.lockTables = tables;
|
|
1310
|
-
}
|
|
1311
|
-
return this;
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
// Set a lock for share constraint.
|
|
1315
|
-
forShare(...tables) {
|
|
1316
|
-
this._single.lock = lockMode.forShare;
|
|
1317
|
-
this._single.lockTables = tables;
|
|
1318
|
-
return this;
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
// Set a lock for no key update constraint.
|
|
1322
|
-
forNoKeyUpdate(...tables) {
|
|
1323
|
-
this._single.lock = lockMode.forNoKeyUpdate;
|
|
1324
|
-
this._single.lockTables = tables;
|
|
1325
|
-
return this;
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
// Set a lock for key share constraint.
|
|
1329
|
-
forKeyShare(...tables) {
|
|
1330
|
-
this._single.lock = lockMode.forKeyShare;
|
|
1331
|
-
this._single.lockTables = tables;
|
|
1332
|
-
return this;
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
// Skips locked rows when using a lock constraint.
|
|
1336
|
-
skipLocked() {
|
|
1337
|
-
if (!this._isSelectQuery()) {
|
|
1338
|
-
throw new Error(`Cannot chain .skipLocked() on "${this._method}" query!`);
|
|
1339
|
-
}
|
|
1340
|
-
if (!this._hasLockMode()) {
|
|
1341
|
-
throw new Error(
|
|
1342
|
-
'.skipLocked() can only be used after a call to .forShare() or .forUpdate()!'
|
|
1343
|
-
);
|
|
1344
|
-
}
|
|
1345
|
-
if (this._single.waitMode === waitMode.noWait) {
|
|
1346
|
-
throw new Error('.skipLocked() cannot be used together with .noWait()!');
|
|
1347
|
-
}
|
|
1348
|
-
this._single.waitMode = waitMode.skipLocked;
|
|
1349
|
-
return this;
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
// Causes error when acessing a locked row instead of waiting for it to be released.
|
|
1353
|
-
noWait() {
|
|
1354
|
-
if (!this._isSelectQuery()) {
|
|
1355
|
-
throw new Error(`Cannot chain .noWait() on "${this._method}" query!`);
|
|
1356
|
-
}
|
|
1357
|
-
if (!this._hasLockMode()) {
|
|
1358
|
-
throw new Error(
|
|
1359
|
-
'.noWait() can only be used after a call to .forShare() or .forUpdate()!'
|
|
1360
|
-
);
|
|
1361
|
-
}
|
|
1362
|
-
if (this._single.waitMode === waitMode.skipLocked) {
|
|
1363
|
-
throw new Error('.noWait() cannot be used together with .skipLocked()!');
|
|
1364
|
-
}
|
|
1365
|
-
this._single.waitMode = waitMode.noWait;
|
|
1366
|
-
return this;
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
// Takes a JS object of methods to call and calls them
|
|
1370
|
-
fromJS(obj) {
|
|
1371
|
-
each(obj, (val, key) => {
|
|
1372
|
-
if (typeof this[key] !== 'function') {
|
|
1373
|
-
this.client.logger.warn(`Knex Error: unknown key ${key}`);
|
|
1374
|
-
}
|
|
1375
|
-
if (Array.isArray(val)) {
|
|
1376
|
-
this[key].apply(this, val);
|
|
1377
|
-
} else {
|
|
1378
|
-
this[key](val);
|
|
1379
|
-
}
|
|
1380
|
-
});
|
|
1381
|
-
return this;
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
|
-
fromRaw(sql, bindings) {
|
|
1385
|
-
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
1386
|
-
return this.from(raw);
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
// Passes query to provided callback function, useful for e.g. composing
|
|
1390
|
-
// domain-specific helpers
|
|
1391
|
-
modify(callback) {
|
|
1392
|
-
callback.apply(this, [this].concat(tail(arguments)));
|
|
1393
|
-
return this;
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
upsert(values, returning, options) {
|
|
1397
|
-
throw new Error(
|
|
1398
|
-
`Upsert is not yet supported for dialect ${this.client.dialect}`
|
|
1399
|
-
);
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
// JSON support functions
|
|
1403
|
-
_json(nameFunction, params) {
|
|
1404
|
-
this._statements.push({
|
|
1405
|
-
grouping: 'columns',
|
|
1406
|
-
type: 'json',
|
|
1407
|
-
method: nameFunction,
|
|
1408
|
-
params: params,
|
|
1409
|
-
});
|
|
1410
|
-
return this;
|
|
1411
|
-
}
|
|
1412
|
-
|
|
1413
|
-
jsonExtract() {
|
|
1414
|
-
const column = arguments[0];
|
|
1415
|
-
let path;
|
|
1416
|
-
let alias;
|
|
1417
|
-
let singleValue = true;
|
|
1418
|
-
|
|
1419
|
-
// We use arguments to have the signatures :
|
|
1420
|
-
// - column (string or array)
|
|
1421
|
-
// - column + path
|
|
1422
|
-
// - column + path + alias
|
|
1423
|
-
// - column + path + alias + singleValue
|
|
1424
|
-
// - column array + singleValue
|
|
1425
|
-
if (arguments.length >= 2) {
|
|
1426
|
-
path = arguments[1];
|
|
1427
|
-
}
|
|
1428
|
-
if (arguments.length >= 3) {
|
|
1429
|
-
alias = arguments[2];
|
|
1430
|
-
}
|
|
1431
|
-
if (arguments.length === 4) {
|
|
1432
|
-
singleValue = arguments[3];
|
|
1433
|
-
}
|
|
1434
|
-
if (
|
|
1435
|
-
arguments.length === 2 &&
|
|
1436
|
-
Array.isArray(arguments[0]) &&
|
|
1437
|
-
isBoolean(arguments[1])
|
|
1438
|
-
) {
|
|
1439
|
-
singleValue = arguments[1];
|
|
1440
|
-
}
|
|
1441
|
-
return this._json('jsonExtract', {
|
|
1442
|
-
column: column,
|
|
1443
|
-
path: path,
|
|
1444
|
-
alias: alias,
|
|
1445
|
-
singleValue, // boolean used only in MSSQL to use function for extract value instead of object/array.
|
|
1446
|
-
});
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
jsonSet(column, path, value, alias) {
|
|
1450
|
-
return this._json('jsonSet', {
|
|
1451
|
-
column: column,
|
|
1452
|
-
path: path,
|
|
1453
|
-
value: value,
|
|
1454
|
-
alias: alias,
|
|
1455
|
-
});
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
jsonInsert(column, path, value, alias) {
|
|
1459
|
-
return this._json('jsonInsert', {
|
|
1460
|
-
column: column,
|
|
1461
|
-
path: path,
|
|
1462
|
-
value: value,
|
|
1463
|
-
alias: alias,
|
|
1464
|
-
});
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
jsonRemove(column, path, alias) {
|
|
1468
|
-
return this._json('jsonRemove', {
|
|
1469
|
-
column: column,
|
|
1470
|
-
path: path,
|
|
1471
|
-
alias: alias,
|
|
1472
|
-
});
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
// Wheres for JSON
|
|
1476
|
-
_isJsonObject(jsonValue) {
|
|
1477
|
-
return isObject(jsonValue) && !(jsonValue instanceof Builder);
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
_whereJsonWrappedValue(type, column, value) {
|
|
1481
|
-
const whereJsonClause = {
|
|
1482
|
-
grouping: 'where',
|
|
1483
|
-
type: type,
|
|
1484
|
-
column,
|
|
1485
|
-
value: value,
|
|
1486
|
-
not: this._not(),
|
|
1487
|
-
bool: this._bool(),
|
|
1488
|
-
asColumn: this._asColumnFlag,
|
|
1489
|
-
};
|
|
1490
|
-
if (arguments[3]) {
|
|
1491
|
-
whereJsonClause.operator = arguments[3];
|
|
1492
|
-
}
|
|
1493
|
-
if (arguments[4]) {
|
|
1494
|
-
whereJsonClause.jsonPath = arguments[4];
|
|
1495
|
-
}
|
|
1496
|
-
this._statements.push(whereJsonClause);
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
whereJsonObject(column, value) {
|
|
1500
|
-
this._whereJsonWrappedValue('whereJsonObject', column, value);
|
|
1501
|
-
return this;
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
orWhereJsonObject(column, value) {
|
|
1505
|
-
return this._bool('or').whereJsonObject(column, value);
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
whereNotJsonObject(column, value) {
|
|
1509
|
-
return this._not(true).whereJsonObject(column, value);
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
orWhereNotJsonObject(column, value) {
|
|
1513
|
-
return this._bool('or').whereNotJsonObject(column, value);
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
whereJsonPath(column, path, operator, value) {
|
|
1517
|
-
this._whereJsonWrappedValue('whereJsonPath', column, value, operator, path);
|
|
1518
|
-
return this;
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
orWhereJsonPath(column, path, operator, value) {
|
|
1522
|
-
return this._bool('or').whereJsonPath(column, path, operator, value);
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
// Json superset wheres
|
|
1526
|
-
whereJsonSupersetOf(column, value) {
|
|
1527
|
-
this._whereJsonWrappedValue('whereJsonSupersetOf', column, value);
|
|
1528
|
-
return this;
|
|
1529
|
-
}
|
|
1530
|
-
|
|
1531
|
-
whereJsonNotSupersetOf(column, value) {
|
|
1532
|
-
return this._not(true).whereJsonSupersetOf(column, value);
|
|
1533
|
-
}
|
|
1534
|
-
|
|
1535
|
-
orWhereJsonSupersetOf(column, value) {
|
|
1536
|
-
return this._bool('or').whereJsonSupersetOf(column, value);
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
orWhereJsonNotSupersetOf(column, value) {
|
|
1540
|
-
return this._bool('or').whereJsonNotSupersetOf(column, value);
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
// Json subset wheres
|
|
1544
|
-
whereJsonSubsetOf(column, value) {
|
|
1545
|
-
this._whereJsonWrappedValue('whereJsonSubsetOf', column, value);
|
|
1546
|
-
return this;
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
whereJsonNotSubsetOf(column, value) {
|
|
1550
|
-
return this._not(true).whereJsonSubsetOf(column, value);
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
orWhereJsonSubsetOf(column, value) {
|
|
1554
|
-
return this._bool('or').whereJsonSubsetOf(column, value);
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
orWhereJsonNotSubsetOf(column, value) {
|
|
1558
|
-
return this._bool('or').whereJsonNotSubsetOf(column, value);
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
whereJsonHasNone(column, values) {
|
|
1562
|
-
this._not(true).whereJsonHasAll(column, values);
|
|
1563
|
-
return this;
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
|
-
// end of wheres for JSON
|
|
1567
|
-
|
|
1568
|
-
_analytic(alias, second, third) {
|
|
1569
|
-
let analytic;
|
|
1570
|
-
const { schema } = this._single;
|
|
1571
|
-
const method = this._analyticMethod();
|
|
1572
|
-
alias = typeof alias === 'string' ? alias : null;
|
|
1573
|
-
|
|
1574
|
-
assert(
|
|
1575
|
-
typeof second === 'function' ||
|
|
1576
|
-
second.isRawInstance ||
|
|
1577
|
-
Array.isArray(second) ||
|
|
1578
|
-
typeof second === 'string' ||
|
|
1579
|
-
typeof second === 'object',
|
|
1580
|
-
`The second argument to an analytic function must be either a function, a raw,
|
|
1581
|
-
an array of string or object, an object or a single string.`
|
|
1582
|
-
);
|
|
1583
|
-
|
|
1584
|
-
if (third) {
|
|
1585
|
-
assert(
|
|
1586
|
-
Array.isArray(third) ||
|
|
1587
|
-
typeof third === 'string' ||
|
|
1588
|
-
typeof third === 'object',
|
|
1589
|
-
'The third argument to an analytic function must be either a string, an array of string or object or an object.'
|
|
1590
|
-
);
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
if (isFunction(second)) {
|
|
1594
|
-
analytic = new Analytic(method, schema, alias);
|
|
1595
|
-
second.call(analytic, analytic);
|
|
1596
|
-
} else if (second.isRawInstance) {
|
|
1597
|
-
const raw = second;
|
|
1598
|
-
analytic = {
|
|
1599
|
-
grouping: 'columns',
|
|
1600
|
-
type: 'analytic',
|
|
1601
|
-
method: method,
|
|
1602
|
-
raw: raw,
|
|
1603
|
-
alias: alias,
|
|
1604
|
-
};
|
|
1605
|
-
} else {
|
|
1606
|
-
const order = !Array.isArray(second) ? [second] : second;
|
|
1607
|
-
let partitions = third || [];
|
|
1608
|
-
partitions = !Array.isArray(partitions) ? [partitions] : partitions;
|
|
1609
|
-
analytic = {
|
|
1610
|
-
grouping: 'columns',
|
|
1611
|
-
type: 'analytic',
|
|
1612
|
-
method: method,
|
|
1613
|
-
order: order,
|
|
1614
|
-
alias: alias,
|
|
1615
|
-
partitions: partitions,
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
|
-
this._statements.push(analytic);
|
|
1619
|
-
return this;
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
rank(...args) {
|
|
1623
|
-
return this._analyticMethod('rank')._analytic(...args);
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
denseRank(...args) {
|
|
1627
|
-
return this._analyticMethod('dense_rank')._analytic(...args);
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
|
-
rowNumber(...args) {
|
|
1631
|
-
return this._analyticMethod('row_number')._analytic(...args);
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
// ----------------------------------------------------------------------
|
|
1635
|
-
|
|
1636
|
-
// Helper for the incrementing/decrementing queries.
|
|
1637
|
-
_counter(column, amount) {
|
|
1638
|
-
amount = parseFloat(amount);
|
|
1639
|
-
|
|
1640
|
-
this._method = 'update';
|
|
1641
|
-
|
|
1642
|
-
this._single.counter = this._single.counter || {};
|
|
1643
|
-
|
|
1644
|
-
this._single.counter[column] = amount;
|
|
1645
|
-
|
|
1646
|
-
return this;
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
// Helper to get or set the "boolFlag" value.
|
|
1650
|
-
_bool(val) {
|
|
1651
|
-
if (arguments.length === 1) {
|
|
1652
|
-
this._boolFlag = val;
|
|
1653
|
-
return this;
|
|
1654
|
-
}
|
|
1655
|
-
const ret = this._boolFlag;
|
|
1656
|
-
this._boolFlag = 'and';
|
|
1657
|
-
return ret;
|
|
1658
|
-
}
|
|
1659
|
-
|
|
1660
|
-
// Helper to get or set the "notFlag" value.
|
|
1661
|
-
_not(val) {
|
|
1662
|
-
if (arguments.length === 1) {
|
|
1663
|
-
this._notFlag = val;
|
|
1664
|
-
return this;
|
|
1665
|
-
}
|
|
1666
|
-
const ret = this._notFlag;
|
|
1667
|
-
this._notFlag = false;
|
|
1668
|
-
return ret;
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
// Helper to get or set the "joinFlag" value.
|
|
1672
|
-
_joinType(val) {
|
|
1673
|
-
if (arguments.length === 1) {
|
|
1674
|
-
this._joinFlag = val;
|
|
1675
|
-
return this;
|
|
1676
|
-
}
|
|
1677
|
-
const ret = this._joinFlag || 'inner';
|
|
1678
|
-
this._joinFlag = 'inner';
|
|
1679
|
-
return ret;
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
_analyticMethod(val) {
|
|
1683
|
-
if (arguments.length === 1) {
|
|
1684
|
-
this._analyticFlag = val;
|
|
1685
|
-
return this;
|
|
1686
|
-
}
|
|
1687
|
-
return this._analyticFlag || 'row_number';
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
// Helper for compiling any aggregate queries.
|
|
1691
|
-
_aggregate(method, column, options = {}) {
|
|
1692
|
-
this._statements.push({
|
|
1693
|
-
grouping: 'columns',
|
|
1694
|
-
type: column.isRawInstance ? 'aggregateRaw' : 'aggregate',
|
|
1695
|
-
method,
|
|
1696
|
-
value: column,
|
|
1697
|
-
aggregateDistinct: options.distinct || false,
|
|
1698
|
-
alias: options.as,
|
|
1699
|
-
});
|
|
1700
|
-
return this;
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
// Helper function for clearing or reseting a grouping type from the builder
|
|
1704
|
-
_clearGrouping(grouping) {
|
|
1705
|
-
if (grouping in this._single) {
|
|
1706
|
-
this._single[grouping] = undefined;
|
|
1707
|
-
} else {
|
|
1708
|
-
this._statements = reject(this._statements, { grouping });
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
// Helper function that checks if the builder will emit a select query
|
|
1713
|
-
_isSelectQuery() {
|
|
1714
|
-
return SELECT_COMMANDS.has(this._method);
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
// Helper function that checks if the query has a lock mode set
|
|
1718
|
-
_hasLockMode() {
|
|
1719
|
-
return LOCK_MODES.has(this._single.lock);
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
Builder.prototype.select = Builder.prototype.columns;
|
|
1724
|
-
Builder.prototype.column = Builder.prototype.columns;
|
|
1725
|
-
Builder.prototype.andWhereNot = Builder.prototype.whereNot;
|
|
1726
|
-
Builder.prototype.andWhereNotColumn = Builder.prototype.whereNotColumn;
|
|
1727
|
-
Builder.prototype.andWhere = Builder.prototype.where;
|
|
1728
|
-
Builder.prototype.andWhereColumn = Builder.prototype.whereColumn;
|
|
1729
|
-
Builder.prototype.andWhereRaw = Builder.prototype.whereRaw;
|
|
1730
|
-
Builder.prototype.andWhereBetween = Builder.prototype.whereBetween;
|
|
1731
|
-
Builder.prototype.andWhereNotBetween = Builder.prototype.whereNotBetween;
|
|
1732
|
-
Builder.prototype.andWhereJsonObject = Builder.prototype.whereJsonObject;
|
|
1733
|
-
Builder.prototype.andWhereNotJsonObject = Builder.prototype.whereNotJsonObject;
|
|
1734
|
-
Builder.prototype.andWhereJsonPath = Builder.prototype.whereJsonPath;
|
|
1735
|
-
Builder.prototype.andWhereLike = Builder.prototype.whereLike;
|
|
1736
|
-
Builder.prototype.andWhereILike = Builder.prototype.whereILike;
|
|
1737
|
-
Builder.prototype.andHaving = Builder.prototype.having;
|
|
1738
|
-
Builder.prototype.andHavingIn = Builder.prototype.havingIn;
|
|
1739
|
-
Builder.prototype.andHavingNotIn = Builder.prototype.havingNotIn;
|
|
1740
|
-
Builder.prototype.andHavingNull = Builder.prototype.havingNull;
|
|
1741
|
-
Builder.prototype.andHavingNotNull = Builder.prototype.havingNotNull;
|
|
1742
|
-
Builder.prototype.andHavingExists = Builder.prototype.havingExists;
|
|
1743
|
-
Builder.prototype.andHavingNotExists = Builder.prototype.havingNotExists;
|
|
1744
|
-
Builder.prototype.andHavingBetween = Builder.prototype.havingBetween;
|
|
1745
|
-
Builder.prototype.andHavingNotBetween = Builder.prototype.havingNotBetween;
|
|
1746
|
-
Builder.prototype.from = Builder.prototype.table;
|
|
1747
|
-
Builder.prototype.into = Builder.prototype.table;
|
|
1748
|
-
Builder.prototype.del = Builder.prototype.delete;
|
|
1749
|
-
|
|
1750
|
-
// Attach all of the top level promise methods that should be chainable.
|
|
1751
|
-
augmentWithBuilderInterface(Builder);
|
|
1752
|
-
addQueryContext(Builder);
|
|
1753
|
-
|
|
1754
|
-
Builder.extend = (methodName, fn) => {
|
|
1755
|
-
if (Object.prototype.hasOwnProperty.call(Builder.prototype, methodName)) {
|
|
1756
|
-
throw new Error(
|
|
1757
|
-
`Can't extend QueryBuilder with existing method ('${methodName}').`
|
|
1758
|
-
);
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
assign(Builder.prototype, { [methodName]: fn });
|
|
1762
|
-
};
|
|
1763
|
-
|
|
1764
|
-
// Sub-builder for onConflict clauses
|
|
1765
|
-
class OnConflictBuilder {
|
|
1766
|
-
constructor(builder, columns) {
|
|
1767
|
-
this.builder = builder;
|
|
1768
|
-
this._columns = columns;
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
// Sets insert query to ignore conflicts
|
|
1772
|
-
ignore() {
|
|
1773
|
-
this.builder._single.onConflict = this._columns;
|
|
1774
|
-
this.builder._single.ignore = true;
|
|
1775
|
-
return this.builder;
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
// Sets insert query to update on conflict
|
|
1779
|
-
merge(updates) {
|
|
1780
|
-
this.builder._single.onConflict = this._columns;
|
|
1781
|
-
this.builder._single.merge = { updates };
|
|
1782
|
-
return this.builder;
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
// Prevent
|
|
1786
|
-
then() {
|
|
1787
|
-
throw new Error(
|
|
1788
|
-
'Incomplete onConflict clause. .onConflict() must be directly followed by either .merge() or .ignore()'
|
|
1789
|
-
);
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
module.exports = Builder;
|
|
1
|
+
// Builder
|
|
2
|
+
// -------
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
const { EventEmitter } = require('events');
|
|
5
|
+
const assign = require('lodash/assign');
|
|
6
|
+
const clone = require('lodash/clone');
|
|
7
|
+
const each = require('lodash/each');
|
|
8
|
+
const isEmpty = require('lodash/isEmpty');
|
|
9
|
+
const isPlainObject = require('lodash/isPlainObject');
|
|
10
|
+
const last = require('lodash/last');
|
|
11
|
+
const reject = require('lodash/reject');
|
|
12
|
+
const tail = require('lodash/tail');
|
|
13
|
+
const toArray = require('lodash/toArray');
|
|
14
|
+
|
|
15
|
+
const { addQueryContext, normalizeArr } = require('../util/helpers');
|
|
16
|
+
const JoinClause = require('./joinclause');
|
|
17
|
+
const Analytic = require('./analytic');
|
|
18
|
+
const saveAsyncStack = require('../util/save-async-stack');
|
|
19
|
+
const {
|
|
20
|
+
isBoolean,
|
|
21
|
+
isNumber,
|
|
22
|
+
isObject,
|
|
23
|
+
isString,
|
|
24
|
+
isFunction,
|
|
25
|
+
} = require('../util/is');
|
|
26
|
+
|
|
27
|
+
const { lockMode, waitMode } = require('./constants');
|
|
28
|
+
const {
|
|
29
|
+
augmentWithBuilderInterface,
|
|
30
|
+
} = require('../builder-interface-augmenter');
|
|
31
|
+
|
|
32
|
+
const SELECT_COMMANDS = new Set(['pluck', 'first', 'select']);
|
|
33
|
+
const CLEARABLE_STATEMENTS = new Set([
|
|
34
|
+
'with',
|
|
35
|
+
'select',
|
|
36
|
+
'columns',
|
|
37
|
+
'hintComments',
|
|
38
|
+
'where',
|
|
39
|
+
'union',
|
|
40
|
+
'join',
|
|
41
|
+
'group',
|
|
42
|
+
'order',
|
|
43
|
+
'having',
|
|
44
|
+
'limit',
|
|
45
|
+
'offset',
|
|
46
|
+
'counter',
|
|
47
|
+
'counters',
|
|
48
|
+
]);
|
|
49
|
+
const LOCK_MODES = new Set([
|
|
50
|
+
lockMode.forShare,
|
|
51
|
+
lockMode.forUpdate,
|
|
52
|
+
lockMode.forNoKeyUpdate,
|
|
53
|
+
lockMode.forKeyShare,
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
// Typically called from `knex.builder`,
|
|
57
|
+
// start a new query building chain.
|
|
58
|
+
class Builder extends EventEmitter {
|
|
59
|
+
constructor(client) {
|
|
60
|
+
super();
|
|
61
|
+
this.client = client;
|
|
62
|
+
this.and = this;
|
|
63
|
+
this._single = {};
|
|
64
|
+
this._comments = [];
|
|
65
|
+
this._statements = [];
|
|
66
|
+
this._method = 'select';
|
|
67
|
+
if (client.config) {
|
|
68
|
+
saveAsyncStack(this, 5);
|
|
69
|
+
this._debug = client.config.debug;
|
|
70
|
+
}
|
|
71
|
+
// Internal flags used in the builder.
|
|
72
|
+
this._joinFlag = 'inner';
|
|
73
|
+
this._boolFlag = 'and';
|
|
74
|
+
this._notFlag = false;
|
|
75
|
+
this._asColumnFlag = false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
toString() {
|
|
79
|
+
return this.toQuery();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Convert the current query "toSQL"
|
|
83
|
+
toSQL(method, tz) {
|
|
84
|
+
return this.client.queryCompiler(this).toSQL(method || this._method, tz);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Create a shallow clone of the current query builder.
|
|
88
|
+
clone() {
|
|
89
|
+
const cloned = new this.constructor(this.client);
|
|
90
|
+
cloned._method = this._method;
|
|
91
|
+
cloned._single = clone(this._single);
|
|
92
|
+
cloned._comments = clone(this._comments);
|
|
93
|
+
cloned._statements = clone(this._statements);
|
|
94
|
+
cloned._debug = this._debug;
|
|
95
|
+
|
|
96
|
+
// `_option` is assigned by the `Interface` mixin.
|
|
97
|
+
if (this._options !== undefined) {
|
|
98
|
+
cloned._options = clone(this._options);
|
|
99
|
+
}
|
|
100
|
+
if (this._queryContext !== undefined) {
|
|
101
|
+
cloned._queryContext = clone(this._queryContext);
|
|
102
|
+
}
|
|
103
|
+
if (this._connection !== undefined) {
|
|
104
|
+
cloned._connection = this._connection;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return cloned;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
timeout(ms, { cancel } = {}) {
|
|
111
|
+
if (isNumber(ms) && ms > 0) {
|
|
112
|
+
this._timeout = ms;
|
|
113
|
+
if (cancel) {
|
|
114
|
+
this.client.assertCanCancelQuery();
|
|
115
|
+
this._cancelOnTimeout = true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// With
|
|
122
|
+
// ------
|
|
123
|
+
isValidStatementArg(statement) {
|
|
124
|
+
return (
|
|
125
|
+
typeof statement === 'function' ||
|
|
126
|
+
statement instanceof Builder ||
|
|
127
|
+
(statement && statement.isRawInstance)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
_validateWithArgs(alias, statementOrColumnList, nothingOrStatement, method) {
|
|
132
|
+
const [query, columnList] =
|
|
133
|
+
typeof nothingOrStatement === 'undefined'
|
|
134
|
+
? [statementOrColumnList, undefined]
|
|
135
|
+
: [nothingOrStatement, statementOrColumnList];
|
|
136
|
+
if (typeof alias !== 'string') {
|
|
137
|
+
throw new Error(`${method}() first argument must be a string`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (this.isValidStatementArg(query) && typeof columnList === 'undefined') {
|
|
141
|
+
// Validated as two-arg variant (alias, statement).
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Attempt to interpret as three-arg variant (alias, columnList, statement).
|
|
146
|
+
const isNonEmptyNameList =
|
|
147
|
+
Array.isArray(columnList) &&
|
|
148
|
+
columnList.length > 0 &&
|
|
149
|
+
columnList.every((it) => typeof it === 'string');
|
|
150
|
+
if (!isNonEmptyNameList) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
`${method}() second argument must be a statement or non-empty column name list.`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (this.isValidStatementArg(query)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
throw new Error(
|
|
160
|
+
`${method}() third argument must be a function / QueryBuilder or a raw when its second argument is a column name list`
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
with(alias, statementOrColumnList, nothingOrStatement) {
|
|
165
|
+
this._validateWithArgs(
|
|
166
|
+
alias,
|
|
167
|
+
statementOrColumnList,
|
|
168
|
+
nothingOrStatement,
|
|
169
|
+
'with'
|
|
170
|
+
);
|
|
171
|
+
return this.withWrapped(alias, statementOrColumnList, nothingOrStatement);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
withMaterialized(alias, statementOrColumnList, nothingOrStatement) {
|
|
175
|
+
throw new Error('With materialized is not supported by this dialect');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
withNotMaterialized(alias, statementOrColumnList, nothingOrStatement) {
|
|
179
|
+
throw new Error('With materialized is not supported by this dialect');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Helper for compiling any advanced `with` queries.
|
|
183
|
+
withWrapped(alias, statementOrColumnList, nothingOrStatement, materialized) {
|
|
184
|
+
const [query, columnList] =
|
|
185
|
+
typeof nothingOrStatement === 'undefined'
|
|
186
|
+
? [statementOrColumnList, undefined]
|
|
187
|
+
: [nothingOrStatement, statementOrColumnList];
|
|
188
|
+
const statement = {
|
|
189
|
+
grouping: 'with',
|
|
190
|
+
type: 'withWrapped',
|
|
191
|
+
alias: alias,
|
|
192
|
+
columnList,
|
|
193
|
+
value: query,
|
|
194
|
+
};
|
|
195
|
+
if (materialized !== undefined) {
|
|
196
|
+
statement.materialized = materialized;
|
|
197
|
+
}
|
|
198
|
+
this._statements.push(statement);
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// With Recursive
|
|
203
|
+
// ------
|
|
204
|
+
|
|
205
|
+
withRecursive(alias, statementOrColumnList, nothingOrStatement) {
|
|
206
|
+
this._validateWithArgs(
|
|
207
|
+
alias,
|
|
208
|
+
statementOrColumnList,
|
|
209
|
+
nothingOrStatement,
|
|
210
|
+
'withRecursive'
|
|
211
|
+
);
|
|
212
|
+
return this.withRecursiveWrapped(
|
|
213
|
+
alias,
|
|
214
|
+
statementOrColumnList,
|
|
215
|
+
nothingOrStatement
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Helper for compiling any advanced `withRecursive` queries.
|
|
220
|
+
withRecursiveWrapped(alias, statementOrColumnList, nothingOrStatement) {
|
|
221
|
+
this.withWrapped(alias, statementOrColumnList, nothingOrStatement);
|
|
222
|
+
this._statements[this._statements.length - 1].recursive = true;
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Select
|
|
227
|
+
// ------
|
|
228
|
+
|
|
229
|
+
// Adds a column or columns to the list of "columns"
|
|
230
|
+
// being selected on the query.
|
|
231
|
+
columns(column) {
|
|
232
|
+
if (!column && column !== 0) return this;
|
|
233
|
+
this._statements.push({
|
|
234
|
+
grouping: 'columns',
|
|
235
|
+
value: normalizeArr(...arguments),
|
|
236
|
+
});
|
|
237
|
+
return this;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Adds a comment to the query
|
|
241
|
+
comment(txt) {
|
|
242
|
+
if (!isString(txt)) {
|
|
243
|
+
throw new Error('Comment must be a string');
|
|
244
|
+
}
|
|
245
|
+
const forbiddenChars = ['/*', '*/', '?'];
|
|
246
|
+
if (forbiddenChars.some((chars) => txt.includes(chars))) {
|
|
247
|
+
throw new Error(`Cannot include ${forbiddenChars.join(', ')} in comment`);
|
|
248
|
+
}
|
|
249
|
+
this._comments.push({
|
|
250
|
+
comment: txt,
|
|
251
|
+
});
|
|
252
|
+
return this;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Allow for a sub-select to be explicitly aliased as a column,
|
|
256
|
+
// without needing to compile the query in a where.
|
|
257
|
+
as(column) {
|
|
258
|
+
this._single.as = column;
|
|
259
|
+
return this;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Adds a single hint or an array of hits to the list of "hintComments" on the query.
|
|
263
|
+
hintComment(hints) {
|
|
264
|
+
hints = Array.isArray(hints) ? hints : [hints];
|
|
265
|
+
if (hints.some((hint) => !isString(hint))) {
|
|
266
|
+
throw new Error('Hint comment must be a string');
|
|
267
|
+
}
|
|
268
|
+
if (hints.some((hint) => hint.includes('/*') || hint.includes('*/'))) {
|
|
269
|
+
throw new Error('Hint comment cannot include "/*" or "*/"');
|
|
270
|
+
}
|
|
271
|
+
if (hints.some((hint) => hint.includes('?'))) {
|
|
272
|
+
throw new Error('Hint comment cannot include "?"');
|
|
273
|
+
}
|
|
274
|
+
this._statements.push({
|
|
275
|
+
grouping: 'hintComments',
|
|
276
|
+
value: hints,
|
|
277
|
+
});
|
|
278
|
+
return this;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Prepends the `schemaName` on `tableName` defined by `.table` and `.join`.
|
|
282
|
+
withSchema(schemaName) {
|
|
283
|
+
this._single.schema = schemaName;
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Sets the `tableName` on the query.
|
|
288
|
+
// Alias to "from" for select and "into" for insert statements
|
|
289
|
+
// e.g. builder.insert({a: value}).into('tableName')
|
|
290
|
+
// `options`: options object containing keys:
|
|
291
|
+
// - `only`: whether the query should use SQL's ONLY to not return
|
|
292
|
+
// inheriting table data. Defaults to false.
|
|
293
|
+
table(tableName, options = {}) {
|
|
294
|
+
this._single.table = tableName;
|
|
295
|
+
this._single.only = options.only === true;
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Adds a `distinct` clause to the query.
|
|
300
|
+
distinct(...args) {
|
|
301
|
+
this._statements.push({
|
|
302
|
+
grouping: 'columns',
|
|
303
|
+
value: normalizeArr(...args),
|
|
304
|
+
distinct: true,
|
|
305
|
+
});
|
|
306
|
+
return this;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
distinctOn(...args) {
|
|
310
|
+
if (isEmpty(args)) {
|
|
311
|
+
throw new Error('distinctOn requires at least on argument');
|
|
312
|
+
}
|
|
313
|
+
this._statements.push({
|
|
314
|
+
grouping: 'columns',
|
|
315
|
+
value: normalizeArr(...args),
|
|
316
|
+
distinctOn: true,
|
|
317
|
+
});
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Adds a join clause to the query, allowing for advanced joins
|
|
322
|
+
// with an anonymous function as the second argument.
|
|
323
|
+
join(table, first, ...args) {
|
|
324
|
+
let join;
|
|
325
|
+
const schema =
|
|
326
|
+
table instanceof Builder || typeof table === 'function'
|
|
327
|
+
? undefined
|
|
328
|
+
: this._single.schema;
|
|
329
|
+
const joinType = this._joinType();
|
|
330
|
+
if (typeof first === 'function') {
|
|
331
|
+
join = new JoinClause(table, joinType, schema);
|
|
332
|
+
first.call(join, join);
|
|
333
|
+
} else if (joinType === 'raw') {
|
|
334
|
+
join = new JoinClause(this.client.raw(table, first), 'raw');
|
|
335
|
+
} else {
|
|
336
|
+
join = new JoinClause(table, joinType, schema);
|
|
337
|
+
if (first) {
|
|
338
|
+
join.on(first, ...args);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
this._statements.push(join);
|
|
342
|
+
return this;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
using(tables) {
|
|
346
|
+
throw new Error(
|
|
347
|
+
"'using' function is only available in PostgreSQL dialect with Delete statements."
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// JOIN blocks:
|
|
352
|
+
innerJoin(...args) {
|
|
353
|
+
return this._joinType('inner').join(...args);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
leftJoin(...args) {
|
|
357
|
+
return this._joinType('left').join(...args);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
leftOuterJoin(...args) {
|
|
361
|
+
return this._joinType('left outer').join(...args);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
rightJoin(...args) {
|
|
365
|
+
return this._joinType('right').join(...args);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
rightOuterJoin(...args) {
|
|
369
|
+
return this._joinType('right outer').join(...args);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
outerJoin(...args) {
|
|
373
|
+
return this._joinType('outer').join(...args);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
fullOuterJoin(...args) {
|
|
377
|
+
return this._joinType('full outer').join(...args);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
crossJoin(...args) {
|
|
381
|
+
return this._joinType('cross').join(...args);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
joinRaw(...args) {
|
|
385
|
+
return this._joinType('raw').join(...args);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Where modifiers:
|
|
389
|
+
get or() {
|
|
390
|
+
return this._bool('or');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
get not() {
|
|
394
|
+
return this._not(true);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// The where function can be used in several ways:
|
|
398
|
+
// The most basic is `where(key, value)`, which expands to
|
|
399
|
+
// where key = value.
|
|
400
|
+
where(column, operator, value) {
|
|
401
|
+
const argsLength = arguments.length;
|
|
402
|
+
|
|
403
|
+
// Support "where true || where false"
|
|
404
|
+
if (column === false || column === true) {
|
|
405
|
+
return this.where(1, '=', column ? 1 : 0);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Check if the column is a function, in which case it's
|
|
409
|
+
// a where statement wrapped in parens.
|
|
410
|
+
if (typeof column === 'function') {
|
|
411
|
+
return this.whereWrapped(column);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Allows `where({id: 2})` syntax.
|
|
415
|
+
if (isObject(column) && !column.isRawInstance)
|
|
416
|
+
return this._objectWhere(column);
|
|
417
|
+
|
|
418
|
+
// Allow a raw statement to be passed along to the query.
|
|
419
|
+
if (column && column.isRawInstance && argsLength === 1)
|
|
420
|
+
return this.whereRaw(column);
|
|
421
|
+
|
|
422
|
+
// Enable the where('key', value) syntax, only when there
|
|
423
|
+
// are explicitly two arguments passed, so it's not possible to
|
|
424
|
+
// do where('key', '!=') and have that turn into where key != null
|
|
425
|
+
if (argsLength === 2) {
|
|
426
|
+
value = operator;
|
|
427
|
+
operator = '=';
|
|
428
|
+
|
|
429
|
+
// If the value is null, and it's a two argument query,
|
|
430
|
+
// we assume we're going for a `whereNull`.
|
|
431
|
+
if (value === null) {
|
|
432
|
+
return this.whereNull(column);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// lower case the operator for comparison purposes
|
|
437
|
+
const checkOperator = `${operator}`.toLowerCase().trim();
|
|
438
|
+
|
|
439
|
+
// If there are 3 arguments, check whether 'in' is one of them.
|
|
440
|
+
if (argsLength === 3) {
|
|
441
|
+
if (checkOperator === 'in' || checkOperator === 'not in') {
|
|
442
|
+
return this._not(checkOperator === 'not in').whereIn(column, value);
|
|
443
|
+
}
|
|
444
|
+
if (checkOperator === 'between' || checkOperator === 'not between') {
|
|
445
|
+
return this._not(checkOperator === 'not between').whereBetween(
|
|
446
|
+
column,
|
|
447
|
+
value
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// If the value is still null, check whether they're meaning
|
|
453
|
+
// where value is null
|
|
454
|
+
if (value === null) {
|
|
455
|
+
// Check for .where(key, 'is', null) or .where(key, 'is not', 'null');
|
|
456
|
+
if (checkOperator === 'is' || checkOperator === 'is not') {
|
|
457
|
+
return this._not(checkOperator === 'is not').whereNull(column);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Push onto the where statement stack.
|
|
462
|
+
this._statements.push({
|
|
463
|
+
grouping: 'where',
|
|
464
|
+
type: 'whereBasic',
|
|
465
|
+
column,
|
|
466
|
+
operator,
|
|
467
|
+
value,
|
|
468
|
+
not: this._not(),
|
|
469
|
+
bool: this._bool(),
|
|
470
|
+
asColumn: this._asColumnFlag,
|
|
471
|
+
});
|
|
472
|
+
return this;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
whereColumn(...args) {
|
|
476
|
+
this._asColumnFlag = true;
|
|
477
|
+
this.where(...args);
|
|
478
|
+
this._asColumnFlag = false;
|
|
479
|
+
return this;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Adds an `or where` clause to the query.
|
|
483
|
+
orWhere(column, ...args) {
|
|
484
|
+
this._bool('or');
|
|
485
|
+
const obj = column;
|
|
486
|
+
if (isObject(obj) && !obj.isRawInstance) {
|
|
487
|
+
return this.whereWrapped(function () {
|
|
488
|
+
for (const key in obj) {
|
|
489
|
+
this.andWhere(key, obj[key]);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
return this.where(column, ...args);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
orWhereColumn(column, ...args) {
|
|
497
|
+
this._bool('or');
|
|
498
|
+
const obj = column;
|
|
499
|
+
if (isObject(obj) && !obj.isRawInstance) {
|
|
500
|
+
return this.whereWrapped(function () {
|
|
501
|
+
for (const key in obj) {
|
|
502
|
+
this.andWhereColumn(key, '=', obj[key]);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
return this.whereColumn(column, ...args);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Adds an `not where` clause to the query.
|
|
510
|
+
whereNot(column, ...args) {
|
|
511
|
+
if (args.length >= 2) {
|
|
512
|
+
if (args[0] === 'in' || args[0] === 'between') {
|
|
513
|
+
this.client.logger.warn(
|
|
514
|
+
'whereNot is not suitable for "in" and "between" type subqueries. You should use "not in" and "not between" instead.'
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return this._not(true).where(column, ...args);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
whereNotColumn(...args) {
|
|
522
|
+
return this._not(true).whereColumn(...args);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Adds an `or not where` clause to the query.
|
|
526
|
+
orWhereNot(...args) {
|
|
527
|
+
return this._bool('or').whereNot(...args);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
orWhereNotColumn(...args) {
|
|
531
|
+
return this._bool('or').whereNotColumn(...args);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Processes an object literal provided in a "where" clause.
|
|
535
|
+
_objectWhere(obj) {
|
|
536
|
+
const boolVal = this._bool();
|
|
537
|
+
const notVal = this._not() ? 'Not' : '';
|
|
538
|
+
for (const key in obj) {
|
|
539
|
+
this[boolVal + 'Where' + notVal](key, obj[key]);
|
|
540
|
+
}
|
|
541
|
+
return this;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Adds a raw `where` clause to the query.
|
|
545
|
+
whereRaw(sql, bindings) {
|
|
546
|
+
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
547
|
+
|
|
548
|
+
this._statements.push({
|
|
549
|
+
grouping: 'where',
|
|
550
|
+
type: 'whereRaw',
|
|
551
|
+
value: raw,
|
|
552
|
+
not: this._not(),
|
|
553
|
+
bool: this._bool(),
|
|
554
|
+
});
|
|
555
|
+
return this;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
orWhereRaw(sql, bindings) {
|
|
559
|
+
return this._bool('or').whereRaw(sql, bindings);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Helper for compiling any advanced `where` queries.
|
|
563
|
+
whereWrapped(callback) {
|
|
564
|
+
this._statements.push({
|
|
565
|
+
grouping: 'where',
|
|
566
|
+
type: 'whereWrapped',
|
|
567
|
+
value: callback,
|
|
568
|
+
not: this._not(),
|
|
569
|
+
bool: this._bool(),
|
|
570
|
+
});
|
|
571
|
+
return this;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Adds a `where exists` clause to the query.
|
|
575
|
+
whereExists(callback) {
|
|
576
|
+
this._statements.push({
|
|
577
|
+
grouping: 'where',
|
|
578
|
+
type: 'whereExists',
|
|
579
|
+
value: callback,
|
|
580
|
+
not: this._not(),
|
|
581
|
+
bool: this._bool(),
|
|
582
|
+
});
|
|
583
|
+
return this;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Adds an `or where exists` clause to the query.
|
|
587
|
+
orWhereExists(callback) {
|
|
588
|
+
return this._bool('or').whereExists(callback);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Adds a `where not exists` clause to the query.
|
|
592
|
+
whereNotExists(callback) {
|
|
593
|
+
return this._not(true).whereExists(callback);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Adds a `or where not exists` clause to the query.
|
|
597
|
+
orWhereNotExists(callback) {
|
|
598
|
+
return this._bool('or').whereNotExists(callback);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// Adds a `where in` clause to the query.
|
|
602
|
+
whereIn(column, values) {
|
|
603
|
+
if (Array.isArray(values) && isEmpty(values))
|
|
604
|
+
return this.where(this._not());
|
|
605
|
+
this._statements.push({
|
|
606
|
+
grouping: 'where',
|
|
607
|
+
type: 'whereIn',
|
|
608
|
+
column,
|
|
609
|
+
value: values,
|
|
610
|
+
not: this._not(),
|
|
611
|
+
bool: this._bool(),
|
|
612
|
+
});
|
|
613
|
+
return this;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Adds a `or where in` clause to the query.
|
|
617
|
+
orWhereIn(column, values) {
|
|
618
|
+
return this._bool('or').whereIn(column, values);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Adds a `where not in` clause to the query.
|
|
622
|
+
whereNotIn(column, values) {
|
|
623
|
+
return this._not(true).whereIn(column, values);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Adds a `or where not in` clause to the query.
|
|
627
|
+
orWhereNotIn(column, values) {
|
|
628
|
+
return this._bool('or')._not(true).whereIn(column, values);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Adds a `where null` clause to the query.
|
|
632
|
+
whereNull(column) {
|
|
633
|
+
this._statements.push({
|
|
634
|
+
grouping: 'where',
|
|
635
|
+
type: 'whereNull',
|
|
636
|
+
column,
|
|
637
|
+
not: this._not(),
|
|
638
|
+
bool: this._bool(),
|
|
639
|
+
});
|
|
640
|
+
return this;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Adds a `or where null` clause to the query.
|
|
644
|
+
orWhereNull(column) {
|
|
645
|
+
return this._bool('or').whereNull(column);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Adds a `where not null` clause to the query.
|
|
649
|
+
whereNotNull(column) {
|
|
650
|
+
return this._not(true).whereNull(column);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
// Adds a `or where not null` clause to the query.
|
|
654
|
+
orWhereNotNull(column) {
|
|
655
|
+
return this._bool('or').whereNotNull(column);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Adds a `where between` clause to the query.
|
|
659
|
+
whereBetween(column, values) {
|
|
660
|
+
assert(
|
|
661
|
+
Array.isArray(values),
|
|
662
|
+
'The second argument to whereBetween must be an array.'
|
|
663
|
+
);
|
|
664
|
+
assert(
|
|
665
|
+
values.length === 2,
|
|
666
|
+
'You must specify 2 values for the whereBetween clause'
|
|
667
|
+
);
|
|
668
|
+
this._statements.push({
|
|
669
|
+
grouping: 'where',
|
|
670
|
+
type: 'whereBetween',
|
|
671
|
+
column,
|
|
672
|
+
value: values,
|
|
673
|
+
not: this._not(),
|
|
674
|
+
bool: this._bool(),
|
|
675
|
+
});
|
|
676
|
+
return this;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Adds a `where not between` clause to the query.
|
|
680
|
+
whereNotBetween(column, values) {
|
|
681
|
+
return this._not(true).whereBetween(column, values);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Adds a `or where between` clause to the query.
|
|
685
|
+
orWhereBetween(column, values) {
|
|
686
|
+
return this._bool('or').whereBetween(column, values);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Adds a `or where not between` clause to the query.
|
|
690
|
+
orWhereNotBetween(column, values) {
|
|
691
|
+
return this._bool('or').whereNotBetween(column, values);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
_whereLike(type, column, value) {
|
|
695
|
+
this._statements.push({
|
|
696
|
+
grouping: 'where',
|
|
697
|
+
type: type,
|
|
698
|
+
column,
|
|
699
|
+
value: value,
|
|
700
|
+
not: this._not(),
|
|
701
|
+
bool: this._bool(),
|
|
702
|
+
asColumn: this._asColumnFlag,
|
|
703
|
+
});
|
|
704
|
+
return this;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Adds a `where like` clause to the query.
|
|
708
|
+
whereLike(column, value) {
|
|
709
|
+
return this._whereLike('whereLike', column, value);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Adds a `or where like` clause to the query.
|
|
713
|
+
orWhereLike(column, value) {
|
|
714
|
+
return this._bool('or')._whereLike('whereLike', column, value);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// Adds a `where ilike` clause to the query.
|
|
718
|
+
whereILike(column, value) {
|
|
719
|
+
return this._whereLike('whereILike', column, value);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Adds a `or where ilike` clause to the query.
|
|
723
|
+
orWhereILike(column, value) {
|
|
724
|
+
return this._bool('or')._whereLike('whereILike', column, value);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Adds a `group by` clause to the query.
|
|
728
|
+
groupBy(item) {
|
|
729
|
+
if (item && item.isRawInstance) {
|
|
730
|
+
return this.groupByRaw.apply(this, arguments);
|
|
731
|
+
}
|
|
732
|
+
this._statements.push({
|
|
733
|
+
grouping: 'group',
|
|
734
|
+
type: 'groupByBasic',
|
|
735
|
+
value: normalizeArr(...arguments),
|
|
736
|
+
});
|
|
737
|
+
return this;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Adds a raw `group by` clause to the query.
|
|
741
|
+
groupByRaw(sql, bindings) {
|
|
742
|
+
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
743
|
+
this._statements.push({
|
|
744
|
+
grouping: 'group',
|
|
745
|
+
type: 'groupByRaw',
|
|
746
|
+
value: raw,
|
|
747
|
+
});
|
|
748
|
+
return this;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Adds a `order by` clause to the query.
|
|
752
|
+
orderBy(column, direction, nulls = '') {
|
|
753
|
+
if (Array.isArray(column)) {
|
|
754
|
+
return this._orderByArray(column);
|
|
755
|
+
}
|
|
756
|
+
this._statements.push({
|
|
757
|
+
grouping: 'order',
|
|
758
|
+
type: 'orderByBasic',
|
|
759
|
+
value: column,
|
|
760
|
+
direction,
|
|
761
|
+
nulls,
|
|
762
|
+
});
|
|
763
|
+
return this;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// Adds a `order by` with multiple columns to the query.
|
|
767
|
+
_orderByArray(columnDefs) {
|
|
768
|
+
for (let i = 0; i < columnDefs.length; i++) {
|
|
769
|
+
const columnInfo = columnDefs[i];
|
|
770
|
+
if (isObject(columnInfo)) {
|
|
771
|
+
this._statements.push({
|
|
772
|
+
grouping: 'order',
|
|
773
|
+
type: 'orderByBasic',
|
|
774
|
+
value: columnInfo['column'],
|
|
775
|
+
direction: columnInfo['order'],
|
|
776
|
+
nulls: columnInfo['nulls'],
|
|
777
|
+
});
|
|
778
|
+
} else if (isString(columnInfo) || isNumber(columnInfo)) {
|
|
779
|
+
this._statements.push({
|
|
780
|
+
grouping: 'order',
|
|
781
|
+
type: 'orderByBasic',
|
|
782
|
+
value: columnInfo,
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// Add a raw `order by` clause to the query.
|
|
790
|
+
orderByRaw(sql, bindings) {
|
|
791
|
+
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
792
|
+
this._statements.push({
|
|
793
|
+
grouping: 'order',
|
|
794
|
+
type: 'orderByRaw',
|
|
795
|
+
value: raw,
|
|
796
|
+
});
|
|
797
|
+
return this;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
_union(clause, args) {
|
|
801
|
+
let callbacks = args[0];
|
|
802
|
+
let wrap = args[1];
|
|
803
|
+
if (args.length === 1 || (args.length === 2 && isBoolean(wrap))) {
|
|
804
|
+
if (!Array.isArray(callbacks)) {
|
|
805
|
+
callbacks = [callbacks];
|
|
806
|
+
}
|
|
807
|
+
for (let i = 0, l = callbacks.length; i < l; i++) {
|
|
808
|
+
this._statements.push({
|
|
809
|
+
grouping: 'union',
|
|
810
|
+
clause: clause,
|
|
811
|
+
value: callbacks[i],
|
|
812
|
+
wrap: wrap || false,
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
} else {
|
|
816
|
+
callbacks = toArray(args).slice(0, args.length - 1);
|
|
817
|
+
wrap = args[args.length - 1];
|
|
818
|
+
if (!isBoolean(wrap)) {
|
|
819
|
+
callbacks.push(wrap);
|
|
820
|
+
wrap = false;
|
|
821
|
+
}
|
|
822
|
+
this._union(clause, [callbacks, wrap]);
|
|
823
|
+
}
|
|
824
|
+
return this;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// Add a union statement to the query.
|
|
828
|
+
union(...args) {
|
|
829
|
+
return this._union('union', args);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// Adds a union all statement to the query.
|
|
833
|
+
unionAll(...args) {
|
|
834
|
+
return this._union('union all', args);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
intersect(...args) {
|
|
838
|
+
return this._union('intersect', args);
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
except(...args) {
|
|
842
|
+
return this._union('except', args);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Adds a `having` clause to the query.
|
|
846
|
+
having(column, operator, value) {
|
|
847
|
+
if (column.isRawInstance && arguments.length === 1) {
|
|
848
|
+
return this.havingRaw(column);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Check if the column is a function, in which case it's
|
|
852
|
+
// a having statement wrapped in parens.
|
|
853
|
+
if (typeof column === 'function') {
|
|
854
|
+
return this.havingWrapped(column);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
this._statements.push({
|
|
858
|
+
grouping: 'having',
|
|
859
|
+
type: 'havingBasic',
|
|
860
|
+
column,
|
|
861
|
+
operator,
|
|
862
|
+
value,
|
|
863
|
+
bool: this._bool(),
|
|
864
|
+
not: this._not(),
|
|
865
|
+
});
|
|
866
|
+
return this;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
orHaving(column, ...args) {
|
|
870
|
+
this._bool('or');
|
|
871
|
+
const obj = column;
|
|
872
|
+
if (isObject(obj) && !obj.isRawInstance) {
|
|
873
|
+
return this.havingWrapped(function () {
|
|
874
|
+
for (const key in obj) {
|
|
875
|
+
this.andHaving(key, obj[key]);
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
return this.having(column, ...args);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// Helper for compiling any advanced `having` queries.
|
|
883
|
+
havingWrapped(callback) {
|
|
884
|
+
this._statements.push({
|
|
885
|
+
grouping: 'having',
|
|
886
|
+
type: 'havingWrapped',
|
|
887
|
+
value: callback,
|
|
888
|
+
bool: this._bool(),
|
|
889
|
+
not: this._not(),
|
|
890
|
+
});
|
|
891
|
+
return this;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
havingNull(column) {
|
|
895
|
+
this._statements.push({
|
|
896
|
+
grouping: 'having',
|
|
897
|
+
type: 'havingNull',
|
|
898
|
+
column,
|
|
899
|
+
not: this._not(),
|
|
900
|
+
bool: this._bool(),
|
|
901
|
+
});
|
|
902
|
+
return this;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
orHavingNull(callback) {
|
|
906
|
+
return this._bool('or').havingNull(callback);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
havingNotNull(callback) {
|
|
910
|
+
return this._not(true).havingNull(callback);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
orHavingNotNull(callback) {
|
|
914
|
+
return this._not(true)._bool('or').havingNull(callback);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
havingExists(callback) {
|
|
918
|
+
this._statements.push({
|
|
919
|
+
grouping: 'having',
|
|
920
|
+
type: 'havingExists',
|
|
921
|
+
value: callback,
|
|
922
|
+
not: this._not(),
|
|
923
|
+
bool: this._bool(),
|
|
924
|
+
});
|
|
925
|
+
return this;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
orHavingExists(callback) {
|
|
929
|
+
return this._bool('or').havingExists(callback);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
havingNotExists(callback) {
|
|
933
|
+
return this._not(true).havingExists(callback);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
orHavingNotExists(callback) {
|
|
937
|
+
return this._not(true)._bool('or').havingExists(callback);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
havingBetween(column, values) {
|
|
941
|
+
assert(
|
|
942
|
+
Array.isArray(values),
|
|
943
|
+
'The second argument to havingBetween must be an array.'
|
|
944
|
+
);
|
|
945
|
+
assert(
|
|
946
|
+
values.length === 2,
|
|
947
|
+
'You must specify 2 values for the havingBetween clause'
|
|
948
|
+
);
|
|
949
|
+
this._statements.push({
|
|
950
|
+
grouping: 'having',
|
|
951
|
+
type: 'havingBetween',
|
|
952
|
+
column,
|
|
953
|
+
value: values,
|
|
954
|
+
not: this._not(),
|
|
955
|
+
bool: this._bool(),
|
|
956
|
+
});
|
|
957
|
+
return this;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
orHavingBetween(column, values) {
|
|
961
|
+
return this._bool('or').havingBetween(column, values);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
havingNotBetween(column, values) {
|
|
965
|
+
return this._not(true).havingBetween(column, values);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
orHavingNotBetween(column, values) {
|
|
969
|
+
return this._not(true)._bool('or').havingBetween(column, values);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
havingIn(column, values) {
|
|
973
|
+
if (Array.isArray(values) && isEmpty(values))
|
|
974
|
+
return this.where(this._not());
|
|
975
|
+
this._statements.push({
|
|
976
|
+
grouping: 'having',
|
|
977
|
+
type: 'havingIn',
|
|
978
|
+
column,
|
|
979
|
+
value: values,
|
|
980
|
+
not: this._not(),
|
|
981
|
+
bool: this._bool(),
|
|
982
|
+
});
|
|
983
|
+
return this;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// Adds a `or where in` clause to the query.
|
|
987
|
+
orHavingIn(column, values) {
|
|
988
|
+
return this._bool('or').havingIn(column, values);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// Adds a `where not in` clause to the query.
|
|
992
|
+
havingNotIn(column, values) {
|
|
993
|
+
return this._not(true).havingIn(column, values);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Adds a `or where not in` clause to the query.
|
|
997
|
+
orHavingNotIn(column, values) {
|
|
998
|
+
return this._bool('or')._not(true).havingIn(column, values);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// Adds a raw `having` clause to the query.
|
|
1002
|
+
havingRaw(sql, bindings) {
|
|
1003
|
+
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
1004
|
+
this._statements.push({
|
|
1005
|
+
grouping: 'having',
|
|
1006
|
+
type: 'havingRaw',
|
|
1007
|
+
value: raw,
|
|
1008
|
+
bool: this._bool(),
|
|
1009
|
+
not: this._not(),
|
|
1010
|
+
});
|
|
1011
|
+
return this;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
orHavingRaw(sql, bindings) {
|
|
1015
|
+
return this._bool('or').havingRaw(sql, bindings);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// set the skip binding parameter (= insert the raw value in the query) for an attribute.
|
|
1019
|
+
_setSkipBinding(attribute, options) {
|
|
1020
|
+
let skipBinding = options;
|
|
1021
|
+
if (isObject(options)) {
|
|
1022
|
+
skipBinding = options.skipBinding;
|
|
1023
|
+
}
|
|
1024
|
+
this._single.skipBinding = this._single.skipBinding || {};
|
|
1025
|
+
this._single.skipBinding[attribute] = skipBinding;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// Only allow a single "offset" to be set for the current query.
|
|
1029
|
+
offset(value, options) {
|
|
1030
|
+
if (value == null || value.isRawInstance || value instanceof Builder) {
|
|
1031
|
+
// Builder for backward compatibility
|
|
1032
|
+
this._single.offset = value;
|
|
1033
|
+
} else {
|
|
1034
|
+
const val = parseInt(value, 10);
|
|
1035
|
+
if (isNaN(val)) {
|
|
1036
|
+
this.client.logger.warn('A valid integer must be provided to offset');
|
|
1037
|
+
} else if (val < 0) {
|
|
1038
|
+
throw new Error(`A non-negative integer must be provided to offset.`);
|
|
1039
|
+
} else {
|
|
1040
|
+
this._single.offset = val;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
this._setSkipBinding('offset', options);
|
|
1044
|
+
return this;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// Only allow a single "limit" to be set for the current query.
|
|
1048
|
+
limit(value, options) {
|
|
1049
|
+
const val = parseInt(value, 10);
|
|
1050
|
+
if (isNaN(val)) {
|
|
1051
|
+
this.client.logger.warn('A valid integer must be provided to limit');
|
|
1052
|
+
} else {
|
|
1053
|
+
this._single.limit = val;
|
|
1054
|
+
this._setSkipBinding('limit', options);
|
|
1055
|
+
}
|
|
1056
|
+
return this;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// Retrieve the "count" result of the query.
|
|
1060
|
+
count(column, options) {
|
|
1061
|
+
return this._aggregate('count', column || '*', options);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// Retrieve the minimum value of a given column.
|
|
1065
|
+
min(column, options) {
|
|
1066
|
+
return this._aggregate('min', column, options);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// Retrieve the maximum value of a given column.
|
|
1070
|
+
max(column, options) {
|
|
1071
|
+
return this._aggregate('max', column, options);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// Retrieve the sum of the values of a given column.
|
|
1075
|
+
sum(column, options) {
|
|
1076
|
+
return this._aggregate('sum', column, options);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// Retrieve the average of the values of a given column.
|
|
1080
|
+
avg(column, options) {
|
|
1081
|
+
return this._aggregate('avg', column, options);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
// Retrieve the "count" of the distinct results of the query.
|
|
1085
|
+
countDistinct(...columns) {
|
|
1086
|
+
let options;
|
|
1087
|
+
if (columns.length > 1 && isPlainObject(last(columns))) {
|
|
1088
|
+
[options] = columns.splice(columns.length - 1, 1);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
if (!columns.length) {
|
|
1092
|
+
columns = '*';
|
|
1093
|
+
} else if (columns.length === 1) {
|
|
1094
|
+
columns = columns[0];
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
return this._aggregate('count', columns, { ...options, distinct: true });
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Retrieve the sum of the distinct values of a given column.
|
|
1101
|
+
sumDistinct(column, options) {
|
|
1102
|
+
return this._aggregate('sum', column, { ...options, distinct: true });
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// Retrieve the vg of the distinct results of the query.
|
|
1106
|
+
avgDistinct(column, options) {
|
|
1107
|
+
return this._aggregate('avg', column, { ...options, distinct: true });
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// Increments a column's value by the specified amount.
|
|
1111
|
+
increment(column, amount = 1) {
|
|
1112
|
+
if (isObject(column)) {
|
|
1113
|
+
for (const key in column) {
|
|
1114
|
+
this._counter(key, column[key]);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
return this;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
return this._counter(column, amount);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// Decrements a column's value by the specified amount.
|
|
1124
|
+
decrement(column, amount = 1) {
|
|
1125
|
+
if (isObject(column)) {
|
|
1126
|
+
for (const key in column) {
|
|
1127
|
+
this._counter(key, -column[key]);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
return this;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
return this._counter(column, -amount);
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// Clears increments/decrements
|
|
1137
|
+
clearCounters() {
|
|
1138
|
+
this._single.counter = {};
|
|
1139
|
+
return this;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Sets the values for a `select` query, informing that only the first
|
|
1143
|
+
// row should be returned (limit 1).
|
|
1144
|
+
first(...args) {
|
|
1145
|
+
if (this._method && this._method !== 'select') {
|
|
1146
|
+
throw new Error(`Cannot chain .first() on "${this._method}" query`);
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
this.select(normalizeArr(...args));
|
|
1150
|
+
this._method = 'first';
|
|
1151
|
+
this.limit(1);
|
|
1152
|
+
return this;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// Use existing connection to execute the query
|
|
1156
|
+
// Same value that client.acquireConnection() for an according client returns should be passed
|
|
1157
|
+
connection(_connection) {
|
|
1158
|
+
this._connection = _connection;
|
|
1159
|
+
this.client.processPassedConnection(_connection);
|
|
1160
|
+
return this;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// Pluck a column from a query.
|
|
1164
|
+
pluck(column) {
|
|
1165
|
+
if (this._method && this._method !== 'select') {
|
|
1166
|
+
throw new Error(`Cannot chain .pluck() on "${this._method}" query`);
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
this._method = 'pluck';
|
|
1170
|
+
this._single.pluck = column;
|
|
1171
|
+
this._statements.push({
|
|
1172
|
+
grouping: 'columns',
|
|
1173
|
+
type: 'pluck',
|
|
1174
|
+
value: column,
|
|
1175
|
+
});
|
|
1176
|
+
return this;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
// Deprecated. Remove everything from select clause
|
|
1180
|
+
clearSelect() {
|
|
1181
|
+
this._clearGrouping('columns');
|
|
1182
|
+
return this;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Deprecated. Remove everything from where clause
|
|
1186
|
+
clearWhere() {
|
|
1187
|
+
this._clearGrouping('where');
|
|
1188
|
+
return this;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// Deprecated. Remove everything from group clause
|
|
1192
|
+
clearGroup() {
|
|
1193
|
+
this._clearGrouping('group');
|
|
1194
|
+
return this;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// Deprecated. Remove everything from order clause
|
|
1198
|
+
clearOrder() {
|
|
1199
|
+
this._clearGrouping('order');
|
|
1200
|
+
return this;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// Deprecated. Remove everything from having clause
|
|
1204
|
+
clearHaving() {
|
|
1205
|
+
this._clearGrouping('having');
|
|
1206
|
+
return this;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// Remove everything from statement clause
|
|
1210
|
+
clear(statement) {
|
|
1211
|
+
if (!CLEARABLE_STATEMENTS.has(statement))
|
|
1212
|
+
throw new Error(`Knex Error: unknown statement '${statement}'`);
|
|
1213
|
+
if (statement.startsWith('counter')) return this.clearCounters();
|
|
1214
|
+
if (statement === 'select') {
|
|
1215
|
+
statement = 'columns';
|
|
1216
|
+
}
|
|
1217
|
+
this._clearGrouping(statement);
|
|
1218
|
+
return this;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// Insert & Update
|
|
1222
|
+
// ------
|
|
1223
|
+
|
|
1224
|
+
// Sets the values for an `insert` query.
|
|
1225
|
+
insert(values, returning, options) {
|
|
1226
|
+
this._method = 'insert';
|
|
1227
|
+
if (!isEmpty(returning)) this.returning(returning, options);
|
|
1228
|
+
this._single.insert = values;
|
|
1229
|
+
return this;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// Sets the values for an `update`, allowing for both
|
|
1233
|
+
// `.update(key, value, [returning])` and `.update(obj, [returning])` syntaxes.
|
|
1234
|
+
update(values, returning, options) {
|
|
1235
|
+
let ret;
|
|
1236
|
+
const obj = this._single.update || {};
|
|
1237
|
+
this._method = 'update';
|
|
1238
|
+
if (isString(values)) {
|
|
1239
|
+
if (isPlainObject(returning)) {
|
|
1240
|
+
obj[values] = JSON.stringify(returning);
|
|
1241
|
+
} else {
|
|
1242
|
+
obj[values] = returning;
|
|
1243
|
+
}
|
|
1244
|
+
if (arguments.length > 2) {
|
|
1245
|
+
ret = arguments[2];
|
|
1246
|
+
}
|
|
1247
|
+
} else {
|
|
1248
|
+
const keys = Object.keys(values);
|
|
1249
|
+
if (this._single.update) {
|
|
1250
|
+
this.client.logger.warn('Update called multiple times with objects.');
|
|
1251
|
+
}
|
|
1252
|
+
let i = -1;
|
|
1253
|
+
while (++i < keys.length) {
|
|
1254
|
+
obj[keys[i]] = values[keys[i]];
|
|
1255
|
+
}
|
|
1256
|
+
ret = arguments[1];
|
|
1257
|
+
}
|
|
1258
|
+
if (!isEmpty(ret)) this.returning(ret, options);
|
|
1259
|
+
this._single.update = obj;
|
|
1260
|
+
return this;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// Sets the returning value for the query.
|
|
1264
|
+
returning(returning, options) {
|
|
1265
|
+
this._single.returning = returning;
|
|
1266
|
+
this._single.options = options;
|
|
1267
|
+
return this;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
onConflict(columns) {
|
|
1271
|
+
if (typeof columns === 'string') {
|
|
1272
|
+
columns = [columns];
|
|
1273
|
+
}
|
|
1274
|
+
return new OnConflictBuilder(this, columns || true);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
// Delete
|
|
1278
|
+
// ------
|
|
1279
|
+
|
|
1280
|
+
// Executes a delete statement on the query;
|
|
1281
|
+
delete(ret, options) {
|
|
1282
|
+
this._method = 'del';
|
|
1283
|
+
if (!isEmpty(ret)) this.returning(ret, options);
|
|
1284
|
+
return this;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// Truncates a table, ends the query chain.
|
|
1288
|
+
truncate(tableName) {
|
|
1289
|
+
this._method = 'truncate';
|
|
1290
|
+
if (tableName) {
|
|
1291
|
+
this._single.table = tableName;
|
|
1292
|
+
}
|
|
1293
|
+
return this;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// Retrieves columns for the table specified by `knex(tableName)`
|
|
1297
|
+
columnInfo(column) {
|
|
1298
|
+
this._method = 'columnInfo';
|
|
1299
|
+
this._single.columnInfo = column;
|
|
1300
|
+
return this;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// Set a lock for update constraint.
|
|
1304
|
+
forUpdate(...tables) {
|
|
1305
|
+
this._single.lock = lockMode.forUpdate;
|
|
1306
|
+
if (tables.length === 1 && Array.isArray(tables[0])) {
|
|
1307
|
+
this._single.lockTables = tables[0];
|
|
1308
|
+
} else {
|
|
1309
|
+
this._single.lockTables = tables;
|
|
1310
|
+
}
|
|
1311
|
+
return this;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// Set a lock for share constraint.
|
|
1315
|
+
forShare(...tables) {
|
|
1316
|
+
this._single.lock = lockMode.forShare;
|
|
1317
|
+
this._single.lockTables = tables;
|
|
1318
|
+
return this;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// Set a lock for no key update constraint.
|
|
1322
|
+
forNoKeyUpdate(...tables) {
|
|
1323
|
+
this._single.lock = lockMode.forNoKeyUpdate;
|
|
1324
|
+
this._single.lockTables = tables;
|
|
1325
|
+
return this;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Set a lock for key share constraint.
|
|
1329
|
+
forKeyShare(...tables) {
|
|
1330
|
+
this._single.lock = lockMode.forKeyShare;
|
|
1331
|
+
this._single.lockTables = tables;
|
|
1332
|
+
return this;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// Skips locked rows when using a lock constraint.
|
|
1336
|
+
skipLocked() {
|
|
1337
|
+
if (!this._isSelectQuery()) {
|
|
1338
|
+
throw new Error(`Cannot chain .skipLocked() on "${this._method}" query!`);
|
|
1339
|
+
}
|
|
1340
|
+
if (!this._hasLockMode()) {
|
|
1341
|
+
throw new Error(
|
|
1342
|
+
'.skipLocked() can only be used after a call to .forShare() or .forUpdate()!'
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
if (this._single.waitMode === waitMode.noWait) {
|
|
1346
|
+
throw new Error('.skipLocked() cannot be used together with .noWait()!');
|
|
1347
|
+
}
|
|
1348
|
+
this._single.waitMode = waitMode.skipLocked;
|
|
1349
|
+
return this;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Causes error when acessing a locked row instead of waiting for it to be released.
|
|
1353
|
+
noWait() {
|
|
1354
|
+
if (!this._isSelectQuery()) {
|
|
1355
|
+
throw new Error(`Cannot chain .noWait() on "${this._method}" query!`);
|
|
1356
|
+
}
|
|
1357
|
+
if (!this._hasLockMode()) {
|
|
1358
|
+
throw new Error(
|
|
1359
|
+
'.noWait() can only be used after a call to .forShare() or .forUpdate()!'
|
|
1360
|
+
);
|
|
1361
|
+
}
|
|
1362
|
+
if (this._single.waitMode === waitMode.skipLocked) {
|
|
1363
|
+
throw new Error('.noWait() cannot be used together with .skipLocked()!');
|
|
1364
|
+
}
|
|
1365
|
+
this._single.waitMode = waitMode.noWait;
|
|
1366
|
+
return this;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// Takes a JS object of methods to call and calls them
|
|
1370
|
+
fromJS(obj) {
|
|
1371
|
+
each(obj, (val, key) => {
|
|
1372
|
+
if (typeof this[key] !== 'function') {
|
|
1373
|
+
this.client.logger.warn(`Knex Error: unknown key ${key}`);
|
|
1374
|
+
}
|
|
1375
|
+
if (Array.isArray(val)) {
|
|
1376
|
+
this[key].apply(this, val);
|
|
1377
|
+
} else {
|
|
1378
|
+
this[key](val);
|
|
1379
|
+
}
|
|
1380
|
+
});
|
|
1381
|
+
return this;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
fromRaw(sql, bindings) {
|
|
1385
|
+
const raw = sql.isRawInstance ? sql : this.client.raw(sql, bindings);
|
|
1386
|
+
return this.from(raw);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// Passes query to provided callback function, useful for e.g. composing
|
|
1390
|
+
// domain-specific helpers
|
|
1391
|
+
modify(callback) {
|
|
1392
|
+
callback.apply(this, [this].concat(tail(arguments)));
|
|
1393
|
+
return this;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
upsert(values, returning, options) {
|
|
1397
|
+
throw new Error(
|
|
1398
|
+
`Upsert is not yet supported for dialect ${this.client.dialect}`
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// JSON support functions
|
|
1403
|
+
_json(nameFunction, params) {
|
|
1404
|
+
this._statements.push({
|
|
1405
|
+
grouping: 'columns',
|
|
1406
|
+
type: 'json',
|
|
1407
|
+
method: nameFunction,
|
|
1408
|
+
params: params,
|
|
1409
|
+
});
|
|
1410
|
+
return this;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
jsonExtract() {
|
|
1414
|
+
const column = arguments[0];
|
|
1415
|
+
let path;
|
|
1416
|
+
let alias;
|
|
1417
|
+
let singleValue = true;
|
|
1418
|
+
|
|
1419
|
+
// We use arguments to have the signatures :
|
|
1420
|
+
// - column (string or array)
|
|
1421
|
+
// - column + path
|
|
1422
|
+
// - column + path + alias
|
|
1423
|
+
// - column + path + alias + singleValue
|
|
1424
|
+
// - column array + singleValue
|
|
1425
|
+
if (arguments.length >= 2) {
|
|
1426
|
+
path = arguments[1];
|
|
1427
|
+
}
|
|
1428
|
+
if (arguments.length >= 3) {
|
|
1429
|
+
alias = arguments[2];
|
|
1430
|
+
}
|
|
1431
|
+
if (arguments.length === 4) {
|
|
1432
|
+
singleValue = arguments[3];
|
|
1433
|
+
}
|
|
1434
|
+
if (
|
|
1435
|
+
arguments.length === 2 &&
|
|
1436
|
+
Array.isArray(arguments[0]) &&
|
|
1437
|
+
isBoolean(arguments[1])
|
|
1438
|
+
) {
|
|
1439
|
+
singleValue = arguments[1];
|
|
1440
|
+
}
|
|
1441
|
+
return this._json('jsonExtract', {
|
|
1442
|
+
column: column,
|
|
1443
|
+
path: path,
|
|
1444
|
+
alias: alias,
|
|
1445
|
+
singleValue, // boolean used only in MSSQL to use function for extract value instead of object/array.
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
jsonSet(column, path, value, alias) {
|
|
1450
|
+
return this._json('jsonSet', {
|
|
1451
|
+
column: column,
|
|
1452
|
+
path: path,
|
|
1453
|
+
value: value,
|
|
1454
|
+
alias: alias,
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
jsonInsert(column, path, value, alias) {
|
|
1459
|
+
return this._json('jsonInsert', {
|
|
1460
|
+
column: column,
|
|
1461
|
+
path: path,
|
|
1462
|
+
value: value,
|
|
1463
|
+
alias: alias,
|
|
1464
|
+
});
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
jsonRemove(column, path, alias) {
|
|
1468
|
+
return this._json('jsonRemove', {
|
|
1469
|
+
column: column,
|
|
1470
|
+
path: path,
|
|
1471
|
+
alias: alias,
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// Wheres for JSON
|
|
1476
|
+
_isJsonObject(jsonValue) {
|
|
1477
|
+
return isObject(jsonValue) && !(jsonValue instanceof Builder);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
_whereJsonWrappedValue(type, column, value) {
|
|
1481
|
+
const whereJsonClause = {
|
|
1482
|
+
grouping: 'where',
|
|
1483
|
+
type: type,
|
|
1484
|
+
column,
|
|
1485
|
+
value: value,
|
|
1486
|
+
not: this._not(),
|
|
1487
|
+
bool: this._bool(),
|
|
1488
|
+
asColumn: this._asColumnFlag,
|
|
1489
|
+
};
|
|
1490
|
+
if (arguments[3]) {
|
|
1491
|
+
whereJsonClause.operator = arguments[3];
|
|
1492
|
+
}
|
|
1493
|
+
if (arguments[4]) {
|
|
1494
|
+
whereJsonClause.jsonPath = arguments[4];
|
|
1495
|
+
}
|
|
1496
|
+
this._statements.push(whereJsonClause);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
whereJsonObject(column, value) {
|
|
1500
|
+
this._whereJsonWrappedValue('whereJsonObject', column, value);
|
|
1501
|
+
return this;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
orWhereJsonObject(column, value) {
|
|
1505
|
+
return this._bool('or').whereJsonObject(column, value);
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
whereNotJsonObject(column, value) {
|
|
1509
|
+
return this._not(true).whereJsonObject(column, value);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
orWhereNotJsonObject(column, value) {
|
|
1513
|
+
return this._bool('or').whereNotJsonObject(column, value);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
whereJsonPath(column, path, operator, value) {
|
|
1517
|
+
this._whereJsonWrappedValue('whereJsonPath', column, value, operator, path);
|
|
1518
|
+
return this;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
orWhereJsonPath(column, path, operator, value) {
|
|
1522
|
+
return this._bool('or').whereJsonPath(column, path, operator, value);
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
// Json superset wheres
|
|
1526
|
+
whereJsonSupersetOf(column, value) {
|
|
1527
|
+
this._whereJsonWrappedValue('whereJsonSupersetOf', column, value);
|
|
1528
|
+
return this;
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
whereJsonNotSupersetOf(column, value) {
|
|
1532
|
+
return this._not(true).whereJsonSupersetOf(column, value);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
orWhereJsonSupersetOf(column, value) {
|
|
1536
|
+
return this._bool('or').whereJsonSupersetOf(column, value);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
orWhereJsonNotSupersetOf(column, value) {
|
|
1540
|
+
return this._bool('or').whereJsonNotSupersetOf(column, value);
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// Json subset wheres
|
|
1544
|
+
whereJsonSubsetOf(column, value) {
|
|
1545
|
+
this._whereJsonWrappedValue('whereJsonSubsetOf', column, value);
|
|
1546
|
+
return this;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
whereJsonNotSubsetOf(column, value) {
|
|
1550
|
+
return this._not(true).whereJsonSubsetOf(column, value);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
orWhereJsonSubsetOf(column, value) {
|
|
1554
|
+
return this._bool('or').whereJsonSubsetOf(column, value);
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
orWhereJsonNotSubsetOf(column, value) {
|
|
1558
|
+
return this._bool('or').whereJsonNotSubsetOf(column, value);
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
whereJsonHasNone(column, values) {
|
|
1562
|
+
this._not(true).whereJsonHasAll(column, values);
|
|
1563
|
+
return this;
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// end of wheres for JSON
|
|
1567
|
+
|
|
1568
|
+
_analytic(alias, second, third) {
|
|
1569
|
+
let analytic;
|
|
1570
|
+
const { schema } = this._single;
|
|
1571
|
+
const method = this._analyticMethod();
|
|
1572
|
+
alias = typeof alias === 'string' ? alias : null;
|
|
1573
|
+
|
|
1574
|
+
assert(
|
|
1575
|
+
typeof second === 'function' ||
|
|
1576
|
+
second.isRawInstance ||
|
|
1577
|
+
Array.isArray(second) ||
|
|
1578
|
+
typeof second === 'string' ||
|
|
1579
|
+
typeof second === 'object',
|
|
1580
|
+
`The second argument to an analytic function must be either a function, a raw,
|
|
1581
|
+
an array of string or object, an object or a single string.`
|
|
1582
|
+
);
|
|
1583
|
+
|
|
1584
|
+
if (third) {
|
|
1585
|
+
assert(
|
|
1586
|
+
Array.isArray(third) ||
|
|
1587
|
+
typeof third === 'string' ||
|
|
1588
|
+
typeof third === 'object',
|
|
1589
|
+
'The third argument to an analytic function must be either a string, an array of string or object or an object.'
|
|
1590
|
+
);
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
if (isFunction(second)) {
|
|
1594
|
+
analytic = new Analytic(method, schema, alias);
|
|
1595
|
+
second.call(analytic, analytic);
|
|
1596
|
+
} else if (second.isRawInstance) {
|
|
1597
|
+
const raw = second;
|
|
1598
|
+
analytic = {
|
|
1599
|
+
grouping: 'columns',
|
|
1600
|
+
type: 'analytic',
|
|
1601
|
+
method: method,
|
|
1602
|
+
raw: raw,
|
|
1603
|
+
alias: alias,
|
|
1604
|
+
};
|
|
1605
|
+
} else {
|
|
1606
|
+
const order = !Array.isArray(second) ? [second] : second;
|
|
1607
|
+
let partitions = third || [];
|
|
1608
|
+
partitions = !Array.isArray(partitions) ? [partitions] : partitions;
|
|
1609
|
+
analytic = {
|
|
1610
|
+
grouping: 'columns',
|
|
1611
|
+
type: 'analytic',
|
|
1612
|
+
method: method,
|
|
1613
|
+
order: order,
|
|
1614
|
+
alias: alias,
|
|
1615
|
+
partitions: partitions,
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
this._statements.push(analytic);
|
|
1619
|
+
return this;
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
rank(...args) {
|
|
1623
|
+
return this._analyticMethod('rank')._analytic(...args);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
denseRank(...args) {
|
|
1627
|
+
return this._analyticMethod('dense_rank')._analytic(...args);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
rowNumber(...args) {
|
|
1631
|
+
return this._analyticMethod('row_number')._analytic(...args);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
// ----------------------------------------------------------------------
|
|
1635
|
+
|
|
1636
|
+
// Helper for the incrementing/decrementing queries.
|
|
1637
|
+
_counter(column, amount) {
|
|
1638
|
+
amount = parseFloat(amount);
|
|
1639
|
+
|
|
1640
|
+
this._method = 'update';
|
|
1641
|
+
|
|
1642
|
+
this._single.counter = this._single.counter || {};
|
|
1643
|
+
|
|
1644
|
+
this._single.counter[column] = amount;
|
|
1645
|
+
|
|
1646
|
+
return this;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
// Helper to get or set the "boolFlag" value.
|
|
1650
|
+
_bool(val) {
|
|
1651
|
+
if (arguments.length === 1) {
|
|
1652
|
+
this._boolFlag = val;
|
|
1653
|
+
return this;
|
|
1654
|
+
}
|
|
1655
|
+
const ret = this._boolFlag;
|
|
1656
|
+
this._boolFlag = 'and';
|
|
1657
|
+
return ret;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
// Helper to get or set the "notFlag" value.
|
|
1661
|
+
_not(val) {
|
|
1662
|
+
if (arguments.length === 1) {
|
|
1663
|
+
this._notFlag = val;
|
|
1664
|
+
return this;
|
|
1665
|
+
}
|
|
1666
|
+
const ret = this._notFlag;
|
|
1667
|
+
this._notFlag = false;
|
|
1668
|
+
return ret;
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// Helper to get or set the "joinFlag" value.
|
|
1672
|
+
_joinType(val) {
|
|
1673
|
+
if (arguments.length === 1) {
|
|
1674
|
+
this._joinFlag = val;
|
|
1675
|
+
return this;
|
|
1676
|
+
}
|
|
1677
|
+
const ret = this._joinFlag || 'inner';
|
|
1678
|
+
this._joinFlag = 'inner';
|
|
1679
|
+
return ret;
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
_analyticMethod(val) {
|
|
1683
|
+
if (arguments.length === 1) {
|
|
1684
|
+
this._analyticFlag = val;
|
|
1685
|
+
return this;
|
|
1686
|
+
}
|
|
1687
|
+
return this._analyticFlag || 'row_number';
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
// Helper for compiling any aggregate queries.
|
|
1691
|
+
_aggregate(method, column, options = {}) {
|
|
1692
|
+
this._statements.push({
|
|
1693
|
+
grouping: 'columns',
|
|
1694
|
+
type: column.isRawInstance ? 'aggregateRaw' : 'aggregate',
|
|
1695
|
+
method,
|
|
1696
|
+
value: column,
|
|
1697
|
+
aggregateDistinct: options.distinct || false,
|
|
1698
|
+
alias: options.as,
|
|
1699
|
+
});
|
|
1700
|
+
return this;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// Helper function for clearing or reseting a grouping type from the builder
|
|
1704
|
+
_clearGrouping(grouping) {
|
|
1705
|
+
if (grouping in this._single) {
|
|
1706
|
+
this._single[grouping] = undefined;
|
|
1707
|
+
} else {
|
|
1708
|
+
this._statements = reject(this._statements, { grouping });
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
// Helper function that checks if the builder will emit a select query
|
|
1713
|
+
_isSelectQuery() {
|
|
1714
|
+
return SELECT_COMMANDS.has(this._method);
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
// Helper function that checks if the query has a lock mode set
|
|
1718
|
+
_hasLockMode() {
|
|
1719
|
+
return LOCK_MODES.has(this._single.lock);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
Builder.prototype.select = Builder.prototype.columns;
|
|
1724
|
+
Builder.prototype.column = Builder.prototype.columns;
|
|
1725
|
+
Builder.prototype.andWhereNot = Builder.prototype.whereNot;
|
|
1726
|
+
Builder.prototype.andWhereNotColumn = Builder.prototype.whereNotColumn;
|
|
1727
|
+
Builder.prototype.andWhere = Builder.prototype.where;
|
|
1728
|
+
Builder.prototype.andWhereColumn = Builder.prototype.whereColumn;
|
|
1729
|
+
Builder.prototype.andWhereRaw = Builder.prototype.whereRaw;
|
|
1730
|
+
Builder.prototype.andWhereBetween = Builder.prototype.whereBetween;
|
|
1731
|
+
Builder.prototype.andWhereNotBetween = Builder.prototype.whereNotBetween;
|
|
1732
|
+
Builder.prototype.andWhereJsonObject = Builder.prototype.whereJsonObject;
|
|
1733
|
+
Builder.prototype.andWhereNotJsonObject = Builder.prototype.whereNotJsonObject;
|
|
1734
|
+
Builder.prototype.andWhereJsonPath = Builder.prototype.whereJsonPath;
|
|
1735
|
+
Builder.prototype.andWhereLike = Builder.prototype.whereLike;
|
|
1736
|
+
Builder.prototype.andWhereILike = Builder.prototype.whereILike;
|
|
1737
|
+
Builder.prototype.andHaving = Builder.prototype.having;
|
|
1738
|
+
Builder.prototype.andHavingIn = Builder.prototype.havingIn;
|
|
1739
|
+
Builder.prototype.andHavingNotIn = Builder.prototype.havingNotIn;
|
|
1740
|
+
Builder.prototype.andHavingNull = Builder.prototype.havingNull;
|
|
1741
|
+
Builder.prototype.andHavingNotNull = Builder.prototype.havingNotNull;
|
|
1742
|
+
Builder.prototype.andHavingExists = Builder.prototype.havingExists;
|
|
1743
|
+
Builder.prototype.andHavingNotExists = Builder.prototype.havingNotExists;
|
|
1744
|
+
Builder.prototype.andHavingBetween = Builder.prototype.havingBetween;
|
|
1745
|
+
Builder.prototype.andHavingNotBetween = Builder.prototype.havingNotBetween;
|
|
1746
|
+
Builder.prototype.from = Builder.prototype.table;
|
|
1747
|
+
Builder.prototype.into = Builder.prototype.table;
|
|
1748
|
+
Builder.prototype.del = Builder.prototype.delete;
|
|
1749
|
+
|
|
1750
|
+
// Attach all of the top level promise methods that should be chainable.
|
|
1751
|
+
augmentWithBuilderInterface(Builder);
|
|
1752
|
+
addQueryContext(Builder);
|
|
1753
|
+
|
|
1754
|
+
Builder.extend = (methodName, fn) => {
|
|
1755
|
+
if (Object.prototype.hasOwnProperty.call(Builder.prototype, methodName)) {
|
|
1756
|
+
throw new Error(
|
|
1757
|
+
`Can't extend QueryBuilder with existing method ('${methodName}').`
|
|
1758
|
+
);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
assign(Builder.prototype, { [methodName]: fn });
|
|
1762
|
+
};
|
|
1763
|
+
|
|
1764
|
+
// Sub-builder for onConflict clauses
|
|
1765
|
+
class OnConflictBuilder {
|
|
1766
|
+
constructor(builder, columns) {
|
|
1767
|
+
this.builder = builder;
|
|
1768
|
+
this._columns = columns;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// Sets insert query to ignore conflicts
|
|
1772
|
+
ignore() {
|
|
1773
|
+
this.builder._single.onConflict = this._columns;
|
|
1774
|
+
this.builder._single.ignore = true;
|
|
1775
|
+
return this.builder;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// Sets insert query to update on conflict
|
|
1779
|
+
merge(updates) {
|
|
1780
|
+
this.builder._single.onConflict = this._columns;
|
|
1781
|
+
this.builder._single.merge = { updates };
|
|
1782
|
+
return this.builder;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// Prevent
|
|
1786
|
+
then() {
|
|
1787
|
+
throw new Error(
|
|
1788
|
+
'Incomplete onConflict clause. .onConflict() must be directly followed by either .merge() or .ignore()'
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
module.exports = Builder;
|