knex 2.0.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/CONTRIBUTING.md +10 -0
- package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -0
- package/lib/dialects/cockroachdb/index.js +5 -0
- package/lib/dialects/index.js +34 -0
- package/lib/dialects/mssql/index.js +20 -14
- package/lib/dialects/mssql/schema/mssql-compiler.js +9 -2
- package/lib/dialects/mysql/query/mysql-querycompiler.js +1 -1
- package/lib/dialects/mysql/schema/mysql-compiler.js +2 -2
- package/lib/dialects/oracledb/index.js +2 -1
- package/lib/dialects/postgres/schema/pg-columncompiler.js +8 -1
- package/lib/dialects/postgres/schema/pg-compiler.js +2 -2
- package/lib/dialects/postgres/schema/pg-tablecompiler.js +33 -6
- package/lib/dialects/sqlite3/index.js +20 -7
- package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +18 -1
- package/lib/execution/runner.js +2 -9
- package/lib/formatter/wrappingFormatter.js +1 -2
- package/lib/knex-builder/Knex.js +28 -0
- package/lib/knex-builder/internal/config-resolver.js +2 -3
- package/lib/knex-builder/internal/parse-connection.js +4 -2
- package/lib/migrations/migrate/MigrationGenerator.js +1 -1
- package/lib/migrations/migrate/stub/js-schema.stub +22 -0
- package/lib/migrations/migrate/stub/ts-schema.stub +21 -0
- package/lib/schema/builder.js +12 -0
- package/lib/schema/columnbuilder.js +12 -0
- package/lib/schema/columncompiler.js +4 -2
- package/lib/schema/tablebuilder.js +12 -0
- package/lib/schema/viewbuilder.js +12 -0
- package/package.json +33 -23
- package/scripts/clean.js +29 -0
- package/scripts/update_gitignore_for_tsc_output.js +85 -0
- package/types/index.d.ts +849 -396
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
# Master (Unreleased)
|
|
2
2
|
|
|
3
|
+
# 2.3.0 - 31 August, 2022
|
|
4
|
+
|
|
5
|
+
### New features:
|
|
6
|
+
|
|
7
|
+
- PostgreSQL: Explicit jsonb support for custom pg clients #5201
|
|
8
|
+
- SQLite: Support returning with sqlite3 and better-sqlite3 #5285
|
|
9
|
+
- MSSQL: Implement mapBinding mssql dialect option #5292
|
|
10
|
+
|
|
11
|
+
### Typings:
|
|
12
|
+
|
|
13
|
+
- Update types for TS 4.8 #5279
|
|
14
|
+
- Fix typo #5267
|
|
15
|
+
- Fix WhereJsonObject withCompositeTableType #5306
|
|
16
|
+
- Fix AnalyticFunction type #5304
|
|
17
|
+
- Infer specific column value type in aggregations #5297
|
|
18
|
+
|
|
19
|
+
# 2.2.0 - 19 July, 2022
|
|
20
|
+
|
|
21
|
+
### New features:
|
|
22
|
+
|
|
23
|
+
- Inline primary key creation for postgres flavours #5233
|
|
24
|
+
- SQLite: Add warning for undefined connection file #5223
|
|
25
|
+
- MSSQL: Add JSON parameter support for connection #5200
|
|
26
|
+
|
|
27
|
+
### Bug fixes:
|
|
28
|
+
|
|
29
|
+
- PostgreSQL: add primaryKey option for uuid #5212
|
|
30
|
+
|
|
31
|
+
### Typings:
|
|
32
|
+
|
|
33
|
+
- Add promisable and better types #5222
|
|
34
|
+
- Update raw query bind parameter type #5208
|
|
35
|
+
|
|
36
|
+
# 2.1.0 - 26 May, 2022
|
|
37
|
+
|
|
38
|
+
### New features:
|
|
39
|
+
|
|
40
|
+
- Improve bundling experience to safely import dialects while using static paths #5142
|
|
41
|
+
- Implement extendable builders #5041
|
|
42
|
+
- PostgreSQL: Refresh materialized view concurrently #5166
|
|
43
|
+
|
|
44
|
+
### Bug fixes:
|
|
45
|
+
|
|
46
|
+
- Use correct paths in package.json browser field #5174
|
|
47
|
+
- MariaDB: Fix 'NULL' returned instead of NULL on MariaDB 10.2.6+ #5181
|
|
48
|
+
- MySQL: fix hasColumn Error (hasColumn ('a_id') is true, but hasColumn('a_Id') is false) #5148
|
|
49
|
+
- MSSQL: Fix .hasTable result when using .withSchema #5176
|
|
50
|
+
- Oracle: correctly INSERTS Buffer #4869
|
|
51
|
+
|
|
52
|
+
### Typings:
|
|
53
|
+
|
|
54
|
+
- Update type definitions for pg connection #5139
|
|
55
|
+
|
|
3
56
|
# 2.0.0 - 21 April, 2022
|
|
4
57
|
|
|
5
58
|
### Breaking changes
|
package/CONTRIBUTING.md
CHANGED
|
@@ -169,6 +169,16 @@ Once this is done, check it works by attempting to login:
|
|
|
169
169
|
psql -h localhost -U postgres -d knex_test
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
## Typescript source files
|
|
173
|
+
|
|
174
|
+
> TL;DR: Starting with release 2.0.0 Knex is adding support for Typescript source files. Thus to develop in this repo you will need to run `npm run build` each time you edit `.ts` files to generate the resulting `.js` files. This is automatically run whenever you run `npm install` or checkout a new Git branch so when developing in Javascript you don't have to worry about it. It is encouraged that new functionality and sources be written in Typescript but this is not required.
|
|
175
|
+
|
|
176
|
+
Starting with release 2.0.0, Knex is support source additions in Typescript! This allows for better safety in the code added. However, pre-2.0.0 Knex was always written in pure Javascript and thus a "hybrid" approach is being used for 2.0.0 to allow for the new `.ts` files to exist along `.js` files that make up the majority of this repository.
|
|
177
|
+
|
|
178
|
+
To develop in this repository use the `npm run build` and `npm run clean` commands to compile and delete the `.js` and related files from `.ts` files. If you wish to have the `tsc` compiled watch and recompile on changes then run `npm run build:ts -- --watch`. Note that for easy integration with Javascript the outputted files are done in a "side-by-side" manner meaning that `lib/foo/bar.ts` will result in `lib/foo/bar.js`. This is done automatically via the npm script command `"prepare"` whenever you run `npm install` and Git hook for `post-checkout` (added by Husky) which executes when you run commands like `git checkout` , thus making it easier to not have to worry about this if you're working in pure Javascript.
|
|
179
|
+
|
|
180
|
+
The script file `./scripts/update_gitignore_for_tsc_output.js` file is called as part of the `npm run build` command which will update the `lib/.gitignore` file which is used to ensure generated `.js` and related files from `tsc` compilation are not checked into the git repo.
|
|
181
|
+
|
|
172
182
|
## Want to be Collaborator?
|
|
173
183
|
|
|
174
184
|
There is always room for more collaborators. Be active on resolving github issues / sending pull requests / reviewing code and we will ask you to join.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const ColumnCompiler_PG = require('../postgres/schema/pg-columncompiler.js');
|
|
2
|
+
|
|
3
|
+
class ColumnCompiler_CRDB extends ColumnCompiler_PG {
|
|
4
|
+
uuid(options = { primaryKey: false }) {
|
|
5
|
+
return (
|
|
6
|
+
'uuid' +
|
|
7
|
+
(this.tableCompiler._canBeAddPrimaryKey(options)
|
|
8
|
+
? ' primary key default gen_random_uuid()'
|
|
9
|
+
: '')
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = ColumnCompiler_CRDB;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const Client_PostgreSQL = require('../postgres');
|
|
4
4
|
const Transaction = require('../postgres/execution/pg-transaction');
|
|
5
5
|
const QueryCompiler = require('./crdb-querycompiler');
|
|
6
|
+
const ColumnCompiler = require('./crdb-columncompiler');
|
|
6
7
|
const TableCompiler = require('./crdb-tablecompiler');
|
|
7
8
|
const ViewCompiler = require('./crdb-viewcompiler');
|
|
8
9
|
const QueryBuilder = require('./crdb-querybuilder');
|
|
@@ -19,6 +20,10 @@ class Client_CockroachDB extends Client_PostgreSQL {
|
|
|
19
20
|
return new QueryCompiler(this, builder, formatter);
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
columnCompiler() {
|
|
24
|
+
return new ColumnCompiler(this, ...arguments);
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
tableCompiler() {
|
|
23
28
|
return new TableCompiler(this, ...arguments);
|
|
24
29
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDialectByNameOrAlias = void 0;
|
|
4
|
+
const { resolveClientNameWithAliases } = require('../util/helpers');
|
|
5
|
+
const dbNameToDialectLoader = Object.freeze({
|
|
6
|
+
'better-sqlite3': () => require('./better-sqlite3'),
|
|
7
|
+
cockroachdb: () => require('./cockroachdb'),
|
|
8
|
+
mssql: () => require('./mssql'),
|
|
9
|
+
mysql: () => require('./mysql'),
|
|
10
|
+
mysql2: () => require('./mysql2'),
|
|
11
|
+
oracle: () => require('./oracle'),
|
|
12
|
+
oracledb: () => require('./oracledb'),
|
|
13
|
+
pgnative: () => require('./pgnative'),
|
|
14
|
+
postgres: () => require('./postgres'),
|
|
15
|
+
redshift: () => require('./redshift'),
|
|
16
|
+
sqlite3: () => require('./sqlite3'),
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Gets the Dialect object with the given client name or throw an
|
|
20
|
+
* error if not found.
|
|
21
|
+
*
|
|
22
|
+
* NOTE: This is a replacement for prior practice of doing dynamic
|
|
23
|
+
* string construction for imports of Dialect objects.
|
|
24
|
+
*/
|
|
25
|
+
function getDialectByNameOrAlias(clientName) {
|
|
26
|
+
const resolvedClientName = resolveClientNameWithAliases(clientName);
|
|
27
|
+
const dialectLoader = dbNameToDialectLoader[resolvedClientName];
|
|
28
|
+
if (!dialectLoader) {
|
|
29
|
+
throw new Error(`Invalid clientName given: ${clientName}`);
|
|
30
|
+
}
|
|
31
|
+
return dialectLoader();
|
|
32
|
+
}
|
|
33
|
+
exports.getDialectByNameOrAlias = getDialectByNameOrAlias;
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -333,14 +333,24 @@ class Client_MSSQL extends Client {
|
|
|
333
333
|
_typeForBinding(binding) {
|
|
334
334
|
const Driver = this._driver();
|
|
335
335
|
|
|
336
|
+
if (
|
|
337
|
+
this.connectionSettings.options &&
|
|
338
|
+
this.connectionSettings.options.mapBinding
|
|
339
|
+
) {
|
|
340
|
+
const result = this.connectionSettings.options.mapBinding(binding);
|
|
341
|
+
if (result) {
|
|
342
|
+
return [result.value, result.type];
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
336
346
|
switch (typeof binding) {
|
|
337
347
|
case 'string':
|
|
338
|
-
return Driver.TYPES.NVarChar;
|
|
348
|
+
return [binding, Driver.TYPES.NVarChar];
|
|
339
349
|
case 'boolean':
|
|
340
|
-
return Driver.TYPES.Bit;
|
|
350
|
+
return [binding, Driver.TYPES.Bit];
|
|
341
351
|
case 'number': {
|
|
342
352
|
if (binding % 1 !== 0) {
|
|
343
|
-
return Driver.TYPES.Float;
|
|
353
|
+
return [binding, Driver.TYPES.Float];
|
|
344
354
|
}
|
|
345
355
|
|
|
346
356
|
if (binding < SQL_INT4.MIN || binding > SQL_INT4.MAX) {
|
|
@@ -350,25 +360,21 @@ class Client_MSSQL extends Client {
|
|
|
350
360
|
);
|
|
351
361
|
}
|
|
352
362
|
|
|
353
|
-
return Driver.TYPES.BigInt;
|
|
363
|
+
return [binding, Driver.TYPES.BigInt];
|
|
354
364
|
}
|
|
355
365
|
|
|
356
|
-
return Driver.TYPES.Int;
|
|
366
|
+
return [binding, Driver.TYPES.Int];
|
|
357
367
|
}
|
|
358
368
|
default: {
|
|
359
|
-
// if (binding === null || typeof binding === 'undefined') {
|
|
360
|
-
// return tedious.TYPES.Null;
|
|
361
|
-
// }
|
|
362
|
-
|
|
363
369
|
if (binding instanceof Date) {
|
|
364
|
-
return Driver.TYPES.DateTime;
|
|
370
|
+
return [binding, Driver.TYPES.DateTime];
|
|
365
371
|
}
|
|
366
372
|
|
|
367
373
|
if (binding instanceof Buffer) {
|
|
368
|
-
return Driver.TYPES.VarBinary;
|
|
374
|
+
return [binding, Driver.TYPES.VarBinary];
|
|
369
375
|
}
|
|
370
376
|
|
|
371
|
-
return Driver.TYPES.NVarChar;
|
|
377
|
+
return [binding, Driver.TYPES.NVarChar];
|
|
372
378
|
}
|
|
373
379
|
}
|
|
374
380
|
}
|
|
@@ -401,8 +407,8 @@ class Client_MSSQL extends Client {
|
|
|
401
407
|
}
|
|
402
408
|
|
|
403
409
|
// sets a request input parameter. Detects bigints and decimals and sets type appropriately.
|
|
404
|
-
_setReqInput(req, i,
|
|
405
|
-
const tediousType = this._typeForBinding(
|
|
410
|
+
_setReqInput(req, i, inputBinding) {
|
|
411
|
+
const [binding, tediousType] = this._typeForBinding(inputBinding);
|
|
406
412
|
const bindingName = 'p'.concat(i);
|
|
407
413
|
let options;
|
|
408
414
|
|
|
@@ -49,10 +49,17 @@ class SchemaCompiler_MSSQL extends SchemaCompiler {
|
|
|
49
49
|
this.builder,
|
|
50
50
|
this.bindingsHolder
|
|
51
51
|
);
|
|
52
|
-
const
|
|
52
|
+
const bindings = [tableName];
|
|
53
|
+
let sql =
|
|
53
54
|
`SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES ` +
|
|
54
55
|
`WHERE TABLE_NAME = ${formattedTable}`;
|
|
55
|
-
|
|
56
|
+
|
|
57
|
+
if (this.schema) {
|
|
58
|
+
sql += ' AND TABLE_SCHEMA = ?';
|
|
59
|
+
bindings.push(this.schema);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.pushQuery({ sql, bindings, output: (resp) => resp.length > 0 });
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
// Check whether a column exists on the schema.
|
|
@@ -131,7 +131,7 @@ class QueryCompiler_MySQL extends QueryCompiler {
|
|
|
131
131
|
output(resp) {
|
|
132
132
|
const out = resp.reduce(function (columns, val) {
|
|
133
133
|
columns[val.COLUMN_NAME] = {
|
|
134
|
-
defaultValue: val.COLUMN_DEFAULT,
|
|
134
|
+
defaultValue: val.COLUMN_DEFAULT === 'NULL' ? null : val.COLUMN_DEFAULT,
|
|
135
135
|
type: val.DATA_TYPE,
|
|
136
136
|
maxLength: val.CHARACTER_MAXIMUM_LENGTH,
|
|
137
137
|
nullable: val.IS_NULLABLE === 'YES',
|
|
@@ -48,8 +48,8 @@ class SchemaCompiler_MySQL extends SchemaCompiler {
|
|
|
48
48
|
output(resp) {
|
|
49
49
|
return resp.some((row) => {
|
|
50
50
|
return (
|
|
51
|
-
this.client.wrapIdentifier(row.Field) ===
|
|
52
|
-
this.client.wrapIdentifier(column)
|
|
51
|
+
this.client.wrapIdentifier(row.Field.toLowerCase()) ===
|
|
52
|
+
this.client.wrapIdentifier(column.toLowerCase())
|
|
53
53
|
);
|
|
54
54
|
});
|
|
55
55
|
},
|
|
@@ -111,7 +111,8 @@ class Client_Oracledb extends Client_Oracle {
|
|
|
111
111
|
this
|
|
112
112
|
);
|
|
113
113
|
} else if (value instanceof BlobHelper) {
|
|
114
|
-
|
|
114
|
+
formatter.bindings.push(value.value);
|
|
115
|
+
return '?';
|
|
115
116
|
}
|
|
116
117
|
return unwrapRaw(value, true, builder, this, formatter) || '?';
|
|
117
118
|
}
|
|
@@ -124,6 +124,13 @@ class ColumnCompiler_PG extends ColumnCompiler {
|
|
|
124
124
|
(this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
|
|
125
125
|
);
|
|
126
126
|
}
|
|
127
|
+
|
|
128
|
+
uuid(options = { primaryKey: false }) {
|
|
129
|
+
return (
|
|
130
|
+
'uuid' +
|
|
131
|
+
(this.tableCompiler._canBeAddPrimaryKey(options) ? ' primary key' : '')
|
|
132
|
+
);
|
|
133
|
+
}
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
ColumnCompiler_PG.prototype.bigint = 'bigint';
|
|
@@ -133,12 +140,12 @@ ColumnCompiler_PG.prototype.double = 'double precision';
|
|
|
133
140
|
ColumnCompiler_PG.prototype.floating = 'real';
|
|
134
141
|
ColumnCompiler_PG.prototype.smallint = 'smallint';
|
|
135
142
|
ColumnCompiler_PG.prototype.tinyint = 'smallint';
|
|
136
|
-
ColumnCompiler_PG.prototype.uuid = 'uuid';
|
|
137
143
|
|
|
138
144
|
function jsonColumn(client, jsonb) {
|
|
139
145
|
if (
|
|
140
146
|
!client.version ||
|
|
141
147
|
client.config.client === 'cockroachdb' ||
|
|
148
|
+
client.config.jsonbSupport === true ||
|
|
142
149
|
parseFloat(client.version) >= 9.2
|
|
143
150
|
) {
|
|
144
151
|
return jsonb ? 'jsonb' : 'json';
|
|
@@ -118,9 +118,9 @@ class SchemaCompiler_PG extends SchemaCompiler {
|
|
|
118
118
|
);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
refreshMaterializedView(viewName) {
|
|
121
|
+
refreshMaterializedView(viewName, concurrently = false) {
|
|
122
122
|
this.pushQuery({
|
|
123
|
-
sql: `refresh materialized view ${this.formatter.wrap(viewName)}`,
|
|
123
|
+
sql: `refresh materialized view${concurrently ? " concurrently" : ""} ${this.formatter.wrap(viewName)}`,
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -44,7 +44,10 @@ class TableCompiler_PG extends TableCompiler {
|
|
|
44
44
|
const createStatement = ifNot
|
|
45
45
|
? 'create table if not exists '
|
|
46
46
|
: 'create table ';
|
|
47
|
-
const columnsSql =
|
|
47
|
+
const columnsSql = ` (${columns.sql.join(', ')}${
|
|
48
|
+
this.primaryKeys() || ''
|
|
49
|
+
}${this._addChecks()})`;
|
|
50
|
+
|
|
48
51
|
let sql =
|
|
49
52
|
createStatement +
|
|
50
53
|
this.tableName() +
|
|
@@ -65,6 +68,28 @@ class TableCompiler_PG extends TableCompiler {
|
|
|
65
68
|
if (hasComment) this.comment(this.single.comment);
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
primaryKeys() {
|
|
72
|
+
const pks = (this.grouped.alterTable || []).filter(
|
|
73
|
+
(k) => k.method === 'primary'
|
|
74
|
+
);
|
|
75
|
+
if (pks.length > 0 && pks[0].args.length > 0) {
|
|
76
|
+
const columns = pks[0].args[0];
|
|
77
|
+
let constraintName = pks[0].args[1] || '';
|
|
78
|
+
let deferrable;
|
|
79
|
+
if (isObject(constraintName)) {
|
|
80
|
+
({ constraintName, deferrable } = constraintName);
|
|
81
|
+
}
|
|
82
|
+
deferrable = deferrable ? ` deferrable initially ${deferrable}` : '';
|
|
83
|
+
constraintName = constraintName
|
|
84
|
+
? this.formatter.wrap(constraintName)
|
|
85
|
+
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);
|
|
86
|
+
|
|
87
|
+
return `, constraint ${constraintName} primary key (${this.formatter.columnize(
|
|
88
|
+
columns
|
|
89
|
+
)})${deferrable}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
68
93
|
addColumns(columns, prefix, colCompilers) {
|
|
69
94
|
if (prefix === this.alterColumnsPrefix) {
|
|
70
95
|
// alter columns
|
|
@@ -153,11 +178,13 @@ class TableCompiler_PG extends TableCompiler {
|
|
|
153
178
|
constraintName = constraintName
|
|
154
179
|
? this.formatter.wrap(constraintName)
|
|
155
180
|
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);
|
|
156
|
-
this.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
181
|
+
if (this.method !== 'create' && this.method !== 'createIfNot') {
|
|
182
|
+
this.pushQuery(
|
|
183
|
+
`alter table ${this.tableName()} add constraint ${constraintName} primary key (${this.formatter.columnize(
|
|
184
|
+
columns
|
|
185
|
+
)})${deferrable}`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
161
188
|
}
|
|
162
189
|
|
|
163
190
|
unique(columns, indexName) {
|
|
@@ -20,11 +20,20 @@ const QueryBuilder = require('./query/sqlite-querybuilder');
|
|
|
20
20
|
class Client_SQLite3 extends Client {
|
|
21
21
|
constructor(config) {
|
|
22
22
|
super(config);
|
|
23
|
+
|
|
24
|
+
if (config.connection && config.connection.filename === undefined) {
|
|
25
|
+
this.logger.warn(
|
|
26
|
+
'Could not find `connection.filename` in config. Please specify ' +
|
|
27
|
+
'the database path and name to avoid errors. ' +
|
|
28
|
+
'(see docs https://knexjs.org/guide/#configuration-options)'
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
23
32
|
if (config.useNullAsDefault === undefined) {
|
|
24
33
|
this.logger.warn(
|
|
25
34
|
'sqlite does not support inserting default values. Set the ' +
|
|
26
35
|
'`useNullAsDefault` flag to hide this warning. ' +
|
|
27
|
-
'(see docs
|
|
36
|
+
'(see docs https://knexjs.org/guide/query-builder.html#insert).'
|
|
28
37
|
);
|
|
29
38
|
}
|
|
30
39
|
}
|
|
@@ -117,6 +126,8 @@ class Client_SQLite3 extends Client {
|
|
|
117
126
|
switch (method) {
|
|
118
127
|
case 'insert':
|
|
119
128
|
case 'update':
|
|
129
|
+
callMethod = obj.returning ? 'all' : 'run';
|
|
130
|
+
break;
|
|
120
131
|
case 'counter':
|
|
121
132
|
case 'del':
|
|
122
133
|
callMethod = 'run';
|
|
@@ -181,16 +192,18 @@ class Client_SQLite3 extends Client {
|
|
|
181
192
|
if (response) {
|
|
182
193
|
return response;
|
|
183
194
|
}
|
|
184
|
-
|
|
185
|
-
// ToDo Implement after https://github.com/microsoft/vscode-node-sqlite3/issues/15 is resolved
|
|
186
|
-
this.logger.warn(
|
|
187
|
-
'node-sqlite3 does not currently support RETURNING clause'
|
|
188
|
-
);
|
|
189
195
|
}
|
|
190
196
|
return [ctx.lastID];
|
|
191
197
|
}
|
|
198
|
+
case 'update': {
|
|
199
|
+
if (returning) {
|
|
200
|
+
if (response) {
|
|
201
|
+
return response;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return ctx.changes;
|
|
205
|
+
}
|
|
192
206
|
case 'del':
|
|
193
|
-
case 'update':
|
|
194
207
|
case 'counter':
|
|
195
208
|
return ctx.changes;
|
|
196
209
|
default: {
|
|
@@ -76,7 +76,7 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
|
|
|
76
76
|
throw new TypeError(
|
|
77
77
|
'`sqlite` does not support inserting default values. Specify ' +
|
|
78
78
|
'values explicitly or use the `useNullAsDefault` config flag. ' +
|
|
79
|
-
'(see docs
|
|
79
|
+
'(see docs https://knexjs.org/guide/query-builder.html#insert).'
|
|
80
80
|
);
|
|
81
81
|
});
|
|
82
82
|
});
|
|
@@ -149,6 +149,23 @@ class QueryCompiler_SQLite3 extends QueryCompiler {
|
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
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
|
+
|
|
152
169
|
_ignore(columns) {
|
|
153
170
|
if (columns === true) {
|
|
154
171
|
return ' on conflict do nothing';
|
package/lib/execution/runner.js
CHANGED
|
@@ -61,22 +61,15 @@ class Runner {
|
|
|
61
61
|
Transform = Transform || require('stream').Transform;
|
|
62
62
|
|
|
63
63
|
const queryContext = this.builder.queryContext();
|
|
64
|
-
let queryStream;
|
|
65
64
|
|
|
66
65
|
const stream = new Transform({
|
|
67
66
|
objectMode: true,
|
|
68
67
|
transform: (chunk, _, callback) => {
|
|
69
68
|
callback(null, this.client.postProcessResponse(chunk, queryContext));
|
|
70
69
|
},
|
|
71
|
-
destroy() {
|
|
72
|
-
// For some reason destroy is not available for mssql on Node 14. Might be a problem with tedious: https://github.com/tediousjs/tedious/issues/1139
|
|
73
|
-
if (queryStream && queryStream.destroy) {
|
|
74
|
-
queryStream.destroy(new Error('stream destroyed'));
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
70
|
});
|
|
78
|
-
stream.on('
|
|
79
|
-
|
|
71
|
+
stream.on('close', () => {
|
|
72
|
+
this.client.releaseConnection(this.connection);
|
|
80
73
|
});
|
|
81
74
|
|
|
82
75
|
const connectionAcquirePromise = this.ensureConnection(
|
|
@@ -225,8 +225,7 @@ function rawOrFn(value, method, builder, client, bindingHolder) {
|
|
|
225
225
|
compileCallback(value, method, client, bindingHolder),
|
|
226
226
|
undefined,
|
|
227
227
|
builder,
|
|
228
|
-
client
|
|
229
|
-
bindingHolder
|
|
228
|
+
client
|
|
230
229
|
);
|
|
231
230
|
}
|
|
232
231
|
return unwrapRaw(value, undefined, builder, client, bindingHolder) || '';
|
package/lib/knex-builder/Knex.js
CHANGED
|
@@ -5,6 +5,10 @@ const QueryInterface = require('../query/method-constants');
|
|
|
5
5
|
const makeKnex = require('./make-knex');
|
|
6
6
|
const { KnexTimeoutError } = require('../util/timeout');
|
|
7
7
|
const { resolveConfig } = require('./internal/config-resolver');
|
|
8
|
+
const SchemaBuilder = require('../schema/builder');
|
|
9
|
+
const ViewBuilder = require('../schema/viewbuilder');
|
|
10
|
+
const ColumnBuilder = require('../schema/columnbuilder');
|
|
11
|
+
const TableBuilder = require('../schema/tablebuilder');
|
|
8
12
|
|
|
9
13
|
function knex(config) {
|
|
10
14
|
const { resolvedConfig, Dialect } = resolveConfig(...arguments);
|
|
@@ -28,4 +32,28 @@ knex.QueryBuilder = {
|
|
|
28
32
|
},
|
|
29
33
|
};
|
|
30
34
|
|
|
35
|
+
knex.SchemaBuilder = {
|
|
36
|
+
extend: function (methodName, fn) {
|
|
37
|
+
SchemaBuilder.extend(methodName, fn);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
knex.ViewBuilder = {
|
|
42
|
+
extend: function (methodName, fn) {
|
|
43
|
+
ViewBuilder.extend(methodName, fn);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
knex.ColumnBuilder = {
|
|
48
|
+
extend: function (methodName, fn) {
|
|
49
|
+
ColumnBuilder.extend(methodName, fn);
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
knex.TableBuilder = {
|
|
54
|
+
extend: function (methodName, fn) {
|
|
55
|
+
TableBuilder.extend(methodName, fn);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
31
59
|
module.exports = knex;
|
|
@@ -2,7 +2,7 @@ const Client = require('../../client');
|
|
|
2
2
|
const { SUPPORTED_CLIENTS } = require('../../constants');
|
|
3
3
|
|
|
4
4
|
const parseConnection = require('./parse-connection');
|
|
5
|
-
const {
|
|
5
|
+
const { getDialectByNameOrAlias } = require('../../dialects');
|
|
6
6
|
|
|
7
7
|
function resolveConfig(config) {
|
|
8
8
|
let Dialect;
|
|
@@ -34,8 +34,7 @@ function resolveConfig(config) {
|
|
|
34
34
|
);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
Dialect = require(`../../dialects/${resolvedClientName}/index.js`);
|
|
37
|
+
Dialect = getDialectByNameOrAlias(clientName);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
// If config connection parameter is passed as string, try to parse it
|
|
@@ -69,8 +69,10 @@ function connectionObject(parsed) {
|
|
|
69
69
|
}
|
|
70
70
|
if (parsed.searchParams) {
|
|
71
71
|
for (const [key, value] of parsed.searchParams.entries()) {
|
|
72
|
-
const
|
|
73
|
-
|
|
72
|
+
const isNestedConfigSupported = ['mysql:', 'mariadb:', 'mssql:'].includes(
|
|
73
|
+
parsed.protocol
|
|
74
|
+
);
|
|
75
|
+
if (isNestedConfigSupported) {
|
|
74
76
|
try {
|
|
75
77
|
connection[key] = JSON.parse(value);
|
|
76
78
|
} catch (err) {
|
|
@@ -41,7 +41,7 @@ class MigrationGenerator {
|
|
|
41
41
|
|
|
42
42
|
_getNewMigrationName(name) {
|
|
43
43
|
if (name[0] === '-') name = name.slice(1);
|
|
44
|
-
return yyyymmddhhmmss() + '_' + name + '.' + this.config.extension;
|
|
44
|
+
return yyyymmddhhmmss() + '_' + name + '.' + this.config.extension.split('-')[0];
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
_getNewMigrationPath(name) {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param { import("knex").Knex } knex
|
|
3
|
+
* @returns { Promise<void> }
|
|
4
|
+
*/
|
|
5
|
+
exports.up = function({schema}) {
|
|
6
|
+
<% if (d.tableName) { %>
|
|
7
|
+
return schema.createTable("<%= d.tableName %>", function(t) {
|
|
8
|
+
t.increments();
|
|
9
|
+
t.timestamp();
|
|
10
|
+
});
|
|
11
|
+
<% } %>
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param { import("knex").Knex } knex
|
|
16
|
+
* @returns { Promise<void> }
|
|
17
|
+
*/
|
|
18
|
+
exports.down = function({schema}) {
|
|
19
|
+
<% if (d.tableName) { %>
|
|
20
|
+
return schema.dropTable("<%= d.tableName %>");
|
|
21
|
+
<% } %>
|
|
22
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
<% if (d.tableName) { %>
|
|
4
|
+
export async function up({schema}: Knex): Promise<Knex.SchemaBuilder> {
|
|
5
|
+
return schema.createTable("<%= d.tableName %>", (t) => {
|
|
6
|
+
t.increments();
|
|
7
|
+
t.timestamps();
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
<% } else { %>
|
|
11
|
+
export async function up({schema}: Knex): Promise<void> {
|
|
12
|
+
}
|
|
13
|
+
<% } %>
|
|
14
|
+
<% if (d.tableName) { %>
|
|
15
|
+
export async function down({schema}: Knex): Promise<Knex.SchemaBuilder> {
|
|
16
|
+
return schema.dropTable("<%= d.tableName %>");
|
|
17
|
+
}
|
|
18
|
+
<% } else { %>
|
|
19
|
+
export async function down({schema}: Knex): Promise<void> {
|
|
20
|
+
}
|
|
21
|
+
<% } %>
|
package/lib/schema/builder.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { EventEmitter } = require('events');
|
|
2
2
|
const toArray = require('lodash/toArray');
|
|
3
|
+
const assign = require('lodash/assign');
|
|
3
4
|
const { addQueryContext } = require('../util/helpers');
|
|
4
5
|
const saveAsyncStack = require('../util/save-async-stack');
|
|
5
6
|
const {
|
|
@@ -96,6 +97,17 @@ class SchemaBuilder extends EventEmitter {
|
|
|
96
97
|
};
|
|
97
98
|
});
|
|
98
99
|
|
|
100
|
+
|
|
101
|
+
SchemaBuilder.extend = (methodName, fn) => {
|
|
102
|
+
if (Object.prototype.hasOwnProperty.call(SchemaBuilder.prototype, methodName)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Can't extend SchemaBuilder with existing method ('${methodName}').`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
assign(SchemaBuilder.prototype, { [methodName]: fn });
|
|
109
|
+
};
|
|
110
|
+
|
|
99
111
|
augmentWithBuilderInterface(SchemaBuilder);
|
|
100
112
|
addQueryContext(SchemaBuilder);
|
|
101
113
|
|