knex 3.2.3 → 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 -293
- 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,341 +1,341 @@
|
|
|
1
|
-
// SQLite3 Query Builder & Compiler
|
|
2
|
-
|
|
3
|
-
const constant = require('lodash/constant');
|
|
4
|
-
const each = require('lodash/each');
|
|
5
|
-
const identity = require('lodash/identity');
|
|
6
|
-
const isEmpty = require('lodash/isEmpty');
|
|
7
|
-
const reduce = require('lodash/reduce');
|
|
8
|
-
|
|
9
|
-
const QueryCompiler = require('../../../query/querycompiler');
|
|
10
|
-
const noop = require('../../../util/noop');
|
|
11
|
-
const { isString } = require('../../../util/is');
|
|
12
|
-
const {
|
|
13
|
-
wrapString,
|
|
14
|
-
columnize: columnize_,
|
|
15
|
-
} = require('../../../formatter/wrappingFormatter');
|
|
16
|
-
|
|
17
|
-
const emptyStr = constant('');
|
|
18
|
-
|
|
19
|
-
class QueryCompiler_SQLite3 extends QueryCompiler {
|
|
20
|
-
constructor(client, builder, formatter) {
|
|
21
|
-
super(client, builder, formatter);
|
|
22
|
-
|
|
23
|
-
// The locks are not applicable in SQLite3
|
|
24
|
-
this.forShare = emptyStr;
|
|
25
|
-
this.forKeyShare = emptyStr;
|
|
26
|
-
this.forUpdate = emptyStr;
|
|
27
|
-
this.forNoKeyUpdate = emptyStr;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// SQLite requires us to build the multi-row insert as a listing of select with
|
|
31
|
-
// unions joining them together. So we'll build out this list of columns and
|
|
32
|
-
// then join them all together with select unions to complete the queries.
|
|
33
|
-
insert() {
|
|
34
|
-
const insertValues = this.single.insert || [];
|
|
35
|
-
let sql = this.with() + `insert into ${this.tableName} `;
|
|
36
|
-
|
|
37
|
-
if (Array.isArray(insertValues)) {
|
|
38
|
-
if (insertValues.length === 0) {
|
|
39
|
-
return '';
|
|
40
|
-
} else if (
|
|
41
|
-
insertValues.length === 1 &&
|
|
42
|
-
insertValues[0] &&
|
|
43
|
-
isEmpty(insertValues[0])
|
|
44
|
-
) {
|
|
45
|
-
return {
|
|
46
|
-
sql: sql + this._emptyInsertValue,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
} else if (typeof insertValues === 'object' && isEmpty(insertValues)) {
|
|
50
|
-
return {
|
|
51
|
-
sql: sql + this._emptyInsertValue,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const insertData = this._prepInsert(insertValues);
|
|
56
|
-
|
|
57
|
-
if (isString(insertData)) {
|
|
58
|
-
return {
|
|
59
|
-
sql: sql + insertData,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (insertData.columns.length === 0) {
|
|
64
|
-
return {
|
|
65
|
-
sql: '',
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
sql += `(${this.formatter.columnize(insertData.columns)})`;
|
|
70
|
-
|
|
71
|
-
// backwards compatible error
|
|
72
|
-
if (this.client.valueForUndefined !== null) {
|
|
73
|
-
insertData.values.forEach((bindings) => {
|
|
74
|
-
each(bindings, (binding) => {
|
|
75
|
-
if (binding === undefined)
|
|
76
|
-
throw new TypeError(
|
|
77
|
-
'`sqlite` does not support inserting default values. Specify ' +
|
|
78
|
-
'values explicitly or use the `useNullAsDefault` config flag. ' +
|
|
79
|
-
'(see docs https://knexjs.org/guide/query-builder.html#insert).'
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (insertData.values.length === 1) {
|
|
86
|
-
const parameters = this.client.parameterize(
|
|
87
|
-
insertData.values[0],
|
|
88
|
-
this.client.valueForUndefined,
|
|
89
|
-
this.builder,
|
|
90
|
-
this.bindingsHolder
|
|
91
|
-
);
|
|
92
|
-
sql += ` values (${parameters})`;
|
|
93
|
-
|
|
94
|
-
const { onConflict, ignore, merge } = this.single;
|
|
95
|
-
if (onConflict && ignore) sql += this._ignore(onConflict);
|
|
96
|
-
else if (onConflict && merge) {
|
|
97
|
-
sql += this._merge(merge.updates, onConflict, insertValues);
|
|
98
|
-
const wheres = this.where();
|
|
99
|
-
if (wheres) sql += ` ${wheres}`;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const { returning } = this.single;
|
|
103
|
-
if (returning) {
|
|
104
|
-
sql += this._returning(returning);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
sql,
|
|
109
|
-
returning,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const blocks = [];
|
|
114
|
-
let i = -1;
|
|
115
|
-
while (++i < insertData.values.length) {
|
|
116
|
-
let i2 = -1;
|
|
117
|
-
const block = (blocks[i] = []);
|
|
118
|
-
let current = insertData.values[i];
|
|
119
|
-
current = current === undefined ? this.client.valueForUndefined : current;
|
|
120
|
-
while (++i2 < insertData.columns.length) {
|
|
121
|
-
block.push(
|
|
122
|
-
this.client.alias(
|
|
123
|
-
this.client.parameter(
|
|
124
|
-
current[i2],
|
|
125
|
-
this.builder,
|
|
126
|
-
this.bindingsHolder
|
|
127
|
-
),
|
|
128
|
-
this.formatter.wrap(insertData.columns[i2])
|
|
129
|
-
)
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
blocks[i] = block.join(', ');
|
|
133
|
-
}
|
|
134
|
-
sql += ' select ' + blocks.join(' union all select ');
|
|
135
|
-
|
|
136
|
-
const { onConflict, ignore, merge } = this.single;
|
|
137
|
-
if (onConflict && ignore) sql += ' where true' + this._ignore(onConflict);
|
|
138
|
-
else if (onConflict && merge) {
|
|
139
|
-
sql +=
|
|
140
|
-
' where true' + this._merge(merge.updates, onConflict, insertValues);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const { returning } = this.single;
|
|
144
|
-
if (returning) sql += this._returning(returning);
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
sql,
|
|
148
|
-
returning,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Compiles an `update` query, allowing for a return value.
|
|
153
|
-
update() {
|
|
154
|
-
const withSQL = this.with();
|
|
155
|
-
const updateData = this._prepUpdate(this.single.update);
|
|
156
|
-
const wheres = this.where();
|
|
157
|
-
const { returning } = this.single;
|
|
158
|
-
return {
|
|
159
|
-
sql:
|
|
160
|
-
withSQL +
|
|
161
|
-
`update ${this.single.only ? 'only ' : ''}${this.tableName} ` +
|
|
162
|
-
`set ${updateData.join(', ')}` +
|
|
163
|
-
(wheres ? ` ${wheres}` : '') +
|
|
164
|
-
this._returning(returning),
|
|
165
|
-
returning,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
_ignore(columns) {
|
|
170
|
-
if (columns === true) {
|
|
171
|
-
return ' on conflict do nothing';
|
|
172
|
-
}
|
|
173
|
-
return ` on conflict ${this._onConflictClause(columns)} do nothing`;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
_merge(updates, columns, insert) {
|
|
177
|
-
let sql = ` on conflict ${this._onConflictClause(columns)} do update set `;
|
|
178
|
-
if (updates && Array.isArray(updates)) {
|
|
179
|
-
sql += updates
|
|
180
|
-
.map((column) =>
|
|
181
|
-
wrapString(
|
|
182
|
-
column.split('.').pop(),
|
|
183
|
-
this.formatter.builder,
|
|
184
|
-
this.client,
|
|
185
|
-
this.formatter
|
|
186
|
-
)
|
|
187
|
-
)
|
|
188
|
-
.map((column) => `${column} = excluded.${column}`)
|
|
189
|
-
.join(', ');
|
|
190
|
-
|
|
191
|
-
return sql;
|
|
192
|
-
} else if (updates && typeof updates === 'object') {
|
|
193
|
-
const updateData = this._prepUpdate(updates);
|
|
194
|
-
if (typeof updateData === 'string') {
|
|
195
|
-
sql += updateData;
|
|
196
|
-
} else {
|
|
197
|
-
sql += updateData.join(',');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return sql;
|
|
201
|
-
} else {
|
|
202
|
-
const insertData = this._prepInsert(insert);
|
|
203
|
-
if (typeof insertData === 'string') {
|
|
204
|
-
throw new Error(
|
|
205
|
-
'If using merge with a raw insert query, then updates must be provided'
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
sql += insertData.columns
|
|
210
|
-
.map((column) =>
|
|
211
|
-
wrapString(column.split('.').pop(), this.builder, this.client)
|
|
212
|
-
)
|
|
213
|
-
.map((column) => `${column} = excluded.${column}`)
|
|
214
|
-
.join(', ');
|
|
215
|
-
|
|
216
|
-
return sql;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
_returning(value) {
|
|
221
|
-
return value ? ` returning ${this.formatter.columnize(value)}` : '';
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Compile a truncate table statement into SQL.
|
|
225
|
-
truncate() {
|
|
226
|
-
const { table } = this.single;
|
|
227
|
-
return {
|
|
228
|
-
sql: `delete from ${this.tableName}`,
|
|
229
|
-
output() {
|
|
230
|
-
return this.query({
|
|
231
|
-
sql: `delete from sqlite_sequence where name = '${table}'`,
|
|
232
|
-
}).catch(noop);
|
|
233
|
-
},
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// Compiles a `columnInfo` query
|
|
238
|
-
columnInfo() {
|
|
239
|
-
const column = this.single.columnInfo;
|
|
240
|
-
|
|
241
|
-
// The user may have specified a custom wrapIdentifier function in the config. We
|
|
242
|
-
// need to run the identifiers through that function, but not format them as
|
|
243
|
-
// identifiers otherwise.
|
|
244
|
-
const table = this.client.customWrapIdentifier(this.single.table, identity);
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
sql: `PRAGMA table_info(\`${table}\`)`,
|
|
248
|
-
output(resp) {
|
|
249
|
-
const maxLengthRegex = /.*\((\d+)\)/;
|
|
250
|
-
const out = reduce(
|
|
251
|
-
resp,
|
|
252
|
-
function (columns, val) {
|
|
253
|
-
let { type } = val;
|
|
254
|
-
let maxLength = type.match(maxLengthRegex);
|
|
255
|
-
if (maxLength) {
|
|
256
|
-
maxLength = maxLength[1];
|
|
257
|
-
}
|
|
258
|
-
type = maxLength ? type.split('(')[0] : type;
|
|
259
|
-
columns[val.name] = {
|
|
260
|
-
type: type.toLowerCase(),
|
|
261
|
-
maxLength,
|
|
262
|
-
nullable: !val.notnull,
|
|
263
|
-
defaultValue: val.dflt_value,
|
|
264
|
-
};
|
|
265
|
-
return columns;
|
|
266
|
-
},
|
|
267
|
-
{}
|
|
268
|
-
);
|
|
269
|
-
return (column && out[column]) || out;
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
limit() {
|
|
275
|
-
const noLimit = !this.single.limit && this.single.limit !== 0;
|
|
276
|
-
if (noLimit && !this.single.offset) return '';
|
|
277
|
-
|
|
278
|
-
// Workaround for offset only,
|
|
279
|
-
// see http://stackoverflow.com/questions/10491492/sqllite-with-skip-offset-only-not-limit
|
|
280
|
-
this.single.limit = noLimit ? -1 : this.single.limit;
|
|
281
|
-
return `limit ${this._getValueOrParameterFromAttribute('limit')}`;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Json functions
|
|
285
|
-
jsonExtract(params) {
|
|
286
|
-
return this._jsonExtract('json_extract', params);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
jsonSet(params) {
|
|
290
|
-
return this._jsonSet('json_set', params);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
jsonInsert(params) {
|
|
294
|
-
return this._jsonSet('json_insert', params);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
jsonRemove(params) {
|
|
298
|
-
const jsonCol = `json_remove(${columnize_(
|
|
299
|
-
params.column,
|
|
300
|
-
this.builder,
|
|
301
|
-
this.client,
|
|
302
|
-
this.bindingsHolder
|
|
303
|
-
)},${this.client.parameter(
|
|
304
|
-
params.path,
|
|
305
|
-
this.builder,
|
|
306
|
-
this.bindingsHolder
|
|
307
|
-
)})`;
|
|
308
|
-
return params.alias
|
|
309
|
-
? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
|
|
310
|
-
: jsonCol;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
whereJsonPath(statement) {
|
|
314
|
-
return this._whereJsonPath('json_extract', statement);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
whereJsonSupersetOf(statement) {
|
|
318
|
-
throw new Error(
|
|
319
|
-
'Json superset where clause not actually supported by SQLite'
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
whereJsonSubsetOf(statement) {
|
|
324
|
-
throw new Error(
|
|
325
|
-
'Json subset where clause not actually supported by SQLite'
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
onJsonPathEquals(clause) {
|
|
330
|
-
return this._onJsonPathEquals('json_extract', clause);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
whereILike(statement) {
|
|
334
|
-
return `${this._columnClause(statement)} ${this._not(
|
|
335
|
-
statement,
|
|
336
|
-
'like '
|
|
337
|
-
)}${this._valueClause(statement)}`;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
module.exports = QueryCompiler_SQLite3;
|
|
1
|
+
// SQLite3 Query Builder & Compiler
|
|
2
|
+
|
|
3
|
+
const constant = require('lodash/constant');
|
|
4
|
+
const each = require('lodash/each');
|
|
5
|
+
const identity = require('lodash/identity');
|
|
6
|
+
const isEmpty = require('lodash/isEmpty');
|
|
7
|
+
const reduce = require('lodash/reduce');
|
|
8
|
+
|
|
9
|
+
const QueryCompiler = require('../../../query/querycompiler');
|
|
10
|
+
const noop = require('../../../util/noop');
|
|
11
|
+
const { isString } = require('../../../util/is');
|
|
12
|
+
const {
|
|
13
|
+
wrapString,
|
|
14
|
+
columnize: columnize_,
|
|
15
|
+
} = require('../../../formatter/wrappingFormatter');
|
|
16
|
+
|
|
17
|
+
const emptyStr = constant('');
|
|
18
|
+
|
|
19
|
+
class QueryCompiler_SQLite3 extends QueryCompiler {
|
|
20
|
+
constructor(client, builder, formatter) {
|
|
21
|
+
super(client, builder, formatter);
|
|
22
|
+
|
|
23
|
+
// The locks are not applicable in SQLite3
|
|
24
|
+
this.forShare = emptyStr;
|
|
25
|
+
this.forKeyShare = emptyStr;
|
|
26
|
+
this.forUpdate = emptyStr;
|
|
27
|
+
this.forNoKeyUpdate = emptyStr;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// SQLite requires us to build the multi-row insert as a listing of select with
|
|
31
|
+
// unions joining them together. So we'll build out this list of columns and
|
|
32
|
+
// then join them all together with select unions to complete the queries.
|
|
33
|
+
insert() {
|
|
34
|
+
const insertValues = this.single.insert || [];
|
|
35
|
+
let sql = this.with() + `insert into ${this.tableName} `;
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(insertValues)) {
|
|
38
|
+
if (insertValues.length === 0) {
|
|
39
|
+
return '';
|
|
40
|
+
} else if (
|
|
41
|
+
insertValues.length === 1 &&
|
|
42
|
+
insertValues[0] &&
|
|
43
|
+
isEmpty(insertValues[0])
|
|
44
|
+
) {
|
|
45
|
+
return {
|
|
46
|
+
sql: sql + this._emptyInsertValue,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
} else if (typeof insertValues === 'object' && isEmpty(insertValues)) {
|
|
50
|
+
return {
|
|
51
|
+
sql: sql + this._emptyInsertValue,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const insertData = this._prepInsert(insertValues);
|
|
56
|
+
|
|
57
|
+
if (isString(insertData)) {
|
|
58
|
+
return {
|
|
59
|
+
sql: sql + insertData,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (insertData.columns.length === 0) {
|
|
64
|
+
return {
|
|
65
|
+
sql: '',
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
sql += `(${this.formatter.columnize(insertData.columns)})`;
|
|
70
|
+
|
|
71
|
+
// backwards compatible error
|
|
72
|
+
if (this.client.valueForUndefined !== null) {
|
|
73
|
+
insertData.values.forEach((bindings) => {
|
|
74
|
+
each(bindings, (binding) => {
|
|
75
|
+
if (binding === undefined)
|
|
76
|
+
throw new TypeError(
|
|
77
|
+
'`sqlite` does not support inserting default values. Specify ' +
|
|
78
|
+
'values explicitly or use the `useNullAsDefault` config flag. ' +
|
|
79
|
+
'(see docs https://knexjs.org/guide/query-builder.html#insert).'
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (insertData.values.length === 1) {
|
|
86
|
+
const parameters = this.client.parameterize(
|
|
87
|
+
insertData.values[0],
|
|
88
|
+
this.client.valueForUndefined,
|
|
89
|
+
this.builder,
|
|
90
|
+
this.bindingsHolder
|
|
91
|
+
);
|
|
92
|
+
sql += ` values (${parameters})`;
|
|
93
|
+
|
|
94
|
+
const { onConflict, ignore, merge } = this.single;
|
|
95
|
+
if (onConflict && ignore) sql += this._ignore(onConflict);
|
|
96
|
+
else if (onConflict && merge) {
|
|
97
|
+
sql += this._merge(merge.updates, onConflict, insertValues);
|
|
98
|
+
const wheres = this.where();
|
|
99
|
+
if (wheres) sql += ` ${wheres}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const { returning } = this.single;
|
|
103
|
+
if (returning) {
|
|
104
|
+
sql += this._returning(returning);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
sql,
|
|
109
|
+
returning,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const blocks = [];
|
|
114
|
+
let i = -1;
|
|
115
|
+
while (++i < insertData.values.length) {
|
|
116
|
+
let i2 = -1;
|
|
117
|
+
const block = (blocks[i] = []);
|
|
118
|
+
let current = insertData.values[i];
|
|
119
|
+
current = current === undefined ? this.client.valueForUndefined : current;
|
|
120
|
+
while (++i2 < insertData.columns.length) {
|
|
121
|
+
block.push(
|
|
122
|
+
this.client.alias(
|
|
123
|
+
this.client.parameter(
|
|
124
|
+
current[i2],
|
|
125
|
+
this.builder,
|
|
126
|
+
this.bindingsHolder
|
|
127
|
+
),
|
|
128
|
+
this.formatter.wrap(insertData.columns[i2])
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
blocks[i] = block.join(', ');
|
|
133
|
+
}
|
|
134
|
+
sql += ' select ' + blocks.join(' union all select ');
|
|
135
|
+
|
|
136
|
+
const { onConflict, ignore, merge } = this.single;
|
|
137
|
+
if (onConflict && ignore) sql += ' where true' + this._ignore(onConflict);
|
|
138
|
+
else if (onConflict && merge) {
|
|
139
|
+
sql +=
|
|
140
|
+
' where true' + this._merge(merge.updates, onConflict, insertValues);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const { returning } = this.single;
|
|
144
|
+
if (returning) sql += this._returning(returning);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
sql,
|
|
148
|
+
returning,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Compiles an `update` query, allowing for a return value.
|
|
153
|
+
update() {
|
|
154
|
+
const withSQL = this.with();
|
|
155
|
+
const updateData = this._prepUpdate(this.single.update);
|
|
156
|
+
const wheres = this.where();
|
|
157
|
+
const { returning } = this.single;
|
|
158
|
+
return {
|
|
159
|
+
sql:
|
|
160
|
+
withSQL +
|
|
161
|
+
`update ${this.single.only ? 'only ' : ''}${this.tableName} ` +
|
|
162
|
+
`set ${updateData.join(', ')}` +
|
|
163
|
+
(wheres ? ` ${wheres}` : '') +
|
|
164
|
+
this._returning(returning),
|
|
165
|
+
returning,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_ignore(columns) {
|
|
170
|
+
if (columns === true) {
|
|
171
|
+
return ' on conflict do nothing';
|
|
172
|
+
}
|
|
173
|
+
return ` on conflict ${this._onConflictClause(columns)} do nothing`;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_merge(updates, columns, insert) {
|
|
177
|
+
let sql = ` on conflict ${this._onConflictClause(columns)} do update set `;
|
|
178
|
+
if (updates && Array.isArray(updates)) {
|
|
179
|
+
sql += updates
|
|
180
|
+
.map((column) =>
|
|
181
|
+
wrapString(
|
|
182
|
+
column.split('.').pop(),
|
|
183
|
+
this.formatter.builder,
|
|
184
|
+
this.client,
|
|
185
|
+
this.formatter
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
.map((column) => `${column} = excluded.${column}`)
|
|
189
|
+
.join(', ');
|
|
190
|
+
|
|
191
|
+
return sql;
|
|
192
|
+
} else if (updates && typeof updates === 'object') {
|
|
193
|
+
const updateData = this._prepUpdate(updates);
|
|
194
|
+
if (typeof updateData === 'string') {
|
|
195
|
+
sql += updateData;
|
|
196
|
+
} else {
|
|
197
|
+
sql += updateData.join(',');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return sql;
|
|
201
|
+
} else {
|
|
202
|
+
const insertData = this._prepInsert(insert);
|
|
203
|
+
if (typeof insertData === 'string') {
|
|
204
|
+
throw new Error(
|
|
205
|
+
'If using merge with a raw insert query, then updates must be provided'
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
sql += insertData.columns
|
|
210
|
+
.map((column) =>
|
|
211
|
+
wrapString(column.split('.').pop(), this.builder, this.client)
|
|
212
|
+
)
|
|
213
|
+
.map((column) => `${column} = excluded.${column}`)
|
|
214
|
+
.join(', ');
|
|
215
|
+
|
|
216
|
+
return sql;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
_returning(value) {
|
|
221
|
+
return value ? ` returning ${this.formatter.columnize(value)}` : '';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Compile a truncate table statement into SQL.
|
|
225
|
+
truncate() {
|
|
226
|
+
const { table } = this.single;
|
|
227
|
+
return {
|
|
228
|
+
sql: `delete from ${this.tableName}`,
|
|
229
|
+
output() {
|
|
230
|
+
return this.query({
|
|
231
|
+
sql: `delete from sqlite_sequence where name = '${table}'`,
|
|
232
|
+
}).catch(noop);
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Compiles a `columnInfo` query
|
|
238
|
+
columnInfo() {
|
|
239
|
+
const column = this.single.columnInfo;
|
|
240
|
+
|
|
241
|
+
// The user may have specified a custom wrapIdentifier function in the config. We
|
|
242
|
+
// need to run the identifiers through that function, but not format them as
|
|
243
|
+
// identifiers otherwise.
|
|
244
|
+
const table = this.client.customWrapIdentifier(this.single.table, identity);
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
sql: `PRAGMA table_info(\`${table}\`)`,
|
|
248
|
+
output(resp) {
|
|
249
|
+
const maxLengthRegex = /.*\((\d+)\)/;
|
|
250
|
+
const out = reduce(
|
|
251
|
+
resp,
|
|
252
|
+
function (columns, val) {
|
|
253
|
+
let { type } = val;
|
|
254
|
+
let maxLength = type.match(maxLengthRegex);
|
|
255
|
+
if (maxLength) {
|
|
256
|
+
maxLength = maxLength[1];
|
|
257
|
+
}
|
|
258
|
+
type = maxLength ? type.split('(')[0] : type;
|
|
259
|
+
columns[val.name] = {
|
|
260
|
+
type: type.toLowerCase(),
|
|
261
|
+
maxLength,
|
|
262
|
+
nullable: !val.notnull,
|
|
263
|
+
defaultValue: val.dflt_value,
|
|
264
|
+
};
|
|
265
|
+
return columns;
|
|
266
|
+
},
|
|
267
|
+
{}
|
|
268
|
+
);
|
|
269
|
+
return (column && out[column]) || out;
|
|
270
|
+
},
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
limit() {
|
|
275
|
+
const noLimit = !this.single.limit && this.single.limit !== 0;
|
|
276
|
+
if (noLimit && !this.single.offset) return '';
|
|
277
|
+
|
|
278
|
+
// Workaround for offset only,
|
|
279
|
+
// see http://stackoverflow.com/questions/10491492/sqllite-with-skip-offset-only-not-limit
|
|
280
|
+
this.single.limit = noLimit ? -1 : this.single.limit;
|
|
281
|
+
return `limit ${this._getValueOrParameterFromAttribute('limit')}`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Json functions
|
|
285
|
+
jsonExtract(params) {
|
|
286
|
+
return this._jsonExtract('json_extract', params);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
jsonSet(params) {
|
|
290
|
+
return this._jsonSet('json_set', params);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
jsonInsert(params) {
|
|
294
|
+
return this._jsonSet('json_insert', params);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
jsonRemove(params) {
|
|
298
|
+
const jsonCol = `json_remove(${columnize_(
|
|
299
|
+
params.column,
|
|
300
|
+
this.builder,
|
|
301
|
+
this.client,
|
|
302
|
+
this.bindingsHolder
|
|
303
|
+
)},${this.client.parameter(
|
|
304
|
+
params.path,
|
|
305
|
+
this.builder,
|
|
306
|
+
this.bindingsHolder
|
|
307
|
+
)})`;
|
|
308
|
+
return params.alias
|
|
309
|
+
? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
|
|
310
|
+
: jsonCol;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
whereJsonPath(statement) {
|
|
314
|
+
return this._whereJsonPath('json_extract', statement);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
whereJsonSupersetOf(statement) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
'Json superset where clause not actually supported by SQLite'
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
whereJsonSubsetOf(statement) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
'Json subset where clause not actually supported by SQLite'
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
onJsonPathEquals(clause) {
|
|
330
|
+
return this._onJsonPathEquals('json_extract', clause);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
whereILike(statement) {
|
|
334
|
+
return `${this._columnClause(statement)} ${this._not(
|
|
335
|
+
statement,
|
|
336
|
+
'like '
|
|
337
|
+
)}${this._valueClause(statement)}`;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
module.exports = QueryCompiler_SQLite3;
|