knex 0.95.12 → 1.0.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 +75 -0
- package/UPGRADING.md +7 -0
- package/lib/client.js +14 -1
- package/lib/constants.js +2 -0
- package/lib/dialects/better-sqlite3/index.js +72 -0
- package/lib/dialects/cockroachdb/crdb-querycompiler.js +87 -33
- package/lib/dialects/cockroachdb/crdb-tablecompiler.js +19 -0
- package/lib/dialects/cockroachdb/index.js +13 -0
- package/lib/dialects/mssql/index.js +0 -11
- package/lib/dialects/mssql/query/mssql-querycompiler.js +122 -64
- package/lib/dialects/mssql/schema/mssql-columncompiler.js +41 -6
- package/lib/dialects/mssql/schema/mssql-tablecompiler.js +24 -9
- package/lib/dialects/mssql/schema/mssql-viewcompiler.js +15 -1
- package/lib/dialects/mysql/index.js +3 -7
- package/lib/dialects/mysql/query/mysql-querycompiler.js +91 -5
- package/lib/dialects/mysql/schema/mysql-columncompiler.js +32 -5
- package/lib/dialects/mysql/schema/mysql-tablecompiler.js +28 -4
- package/lib/dialects/mysql2/index.js +7 -4
- package/lib/dialects/oracle/query/oracle-querycompiler.js +7 -6
- package/lib/dialects/oracle/schema/internal/trigger.js +1 -1
- package/lib/dialects/oracle/schema/oracle-columncompiler.js +10 -4
- package/lib/dialects/oracle/schema/oracle-tablecompiler.js +17 -6
- package/lib/dialects/oracledb/index.js +0 -4
- package/lib/dialects/oracledb/query/oracledb-querycompiler.js +104 -0
- package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +23 -0
- package/lib/dialects/postgres/index.js +21 -6
- package/lib/dialects/postgres/query/pg-querybuilder.js +8 -0
- package/lib/dialects/postgres/query/pg-querycompiler.js +166 -5
- package/lib/dialects/postgres/schema/pg-columncompiler.js +29 -15
- package/lib/dialects/postgres/schema/pg-tablecompiler.js +55 -47
- package/lib/dialects/redshift/index.js +12 -0
- package/lib/dialects/redshift/query/redshift-querycompiler.js +62 -26
- package/lib/dialects/redshift/schema/redshift-columncompiler.js +2 -1
- package/lib/dialects/redshift/schema/redshift-tablecompiler.js +4 -1
- package/lib/dialects/sqlite3/index.js +18 -4
- package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +85 -18
- package/lib/dialects/sqlite3/schema/ddl.js +274 -282
- package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +18 -8
- package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +20 -0
- package/lib/dialects/sqlite3/schema/sqlite-compiler.js +16 -12
- package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +15 -5
- package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +31 -2
- package/lib/execution/runner.js +37 -2
- package/lib/knex-builder/FunctionHelper.js +21 -0
- package/lib/migrations/common/MigrationsLoader.js +36 -0
- package/lib/migrations/migrate/MigrationGenerator.js +1 -1
- package/lib/migrations/migrate/Migrator.js +20 -23
- package/lib/migrations/migrate/migration-list-resolver.js +2 -5
- package/lib/migrations/migrate/{configuration-merger.js → migrator-configuration-merger.js} +2 -4
- package/lib/migrations/migrate/sources/fs-migrations.js +4 -29
- package/lib/migrations/migrate/stub/js.stub +8 -1
- package/lib/migrations/migrate/stub/knexfile-js.stub +3 -0
- package/lib/migrations/migrate/stub/knexfile-ts.stub +5 -2
- package/lib/migrations/migrate/table-creator.js +6 -5
- package/lib/migrations/seed/Seeder.js +25 -92
- package/lib/migrations/seed/seeder-configuration-merger.js +60 -0
- package/lib/migrations/seed/sources/fs-seeds.js +65 -0
- package/lib/migrations/seed/stub/js.stub +4 -1
- package/lib/migrations/util/import-file.js +0 -1
- package/lib/query/joinclause.js +24 -5
- package/lib/query/method-constants.js +37 -0
- package/lib/query/querybuilder.js +230 -5
- package/lib/query/querycompiler.js +269 -84
- package/lib/schema/columnbuilder.js +8 -0
- package/lib/schema/columncompiler.js +132 -5
- package/lib/schema/compiler.js +1 -0
- package/lib/schema/tablebuilder.js +41 -8
- package/lib/schema/tablecompiler.js +57 -0
- package/lib/schema/viewcompiler.js +13 -10
- package/package.json +30 -22
- package/scripts/docker-compose.yml +7 -7
- package/scripts/oracledb-install-driver-libs.sh +82 -0
- package/scripts/runkit-example.js +1 -1
- package/scripts/stress-test/docker-compose.yml +3 -3
- package/scripts/stress-test/knex-stress-test.js +1 -1
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +1 -1
- package/types/index.d.ts +130 -20
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# Master (Unreleased)
|
|
2
2
|
|
|
3
|
+
# 1.0.0 - 16 January, 2022
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- Dropped support for Node 10;
|
|
8
|
+
- Replaced unsupported `sqlite3` driver with `@vscode/sqlite3`;
|
|
9
|
+
- Changed data structure from `RETURNING` operation to be consistent with `SELECT`;
|
|
10
|
+
- Changed Migrator to return list of migrations as objects consistently.
|
|
11
|
+
|
|
12
|
+
### New features:
|
|
13
|
+
|
|
14
|
+
- Support fromRaw #4781
|
|
15
|
+
- Support zero precision in timestamp/datetime #4784
|
|
16
|
+
- Support whereLike and whereILike #4779
|
|
17
|
+
- Add JSDoc (TS flavor) to stub files #4809
|
|
18
|
+
- Allow skip binding in limit and offset #4811
|
|
19
|
+
- Support creating a new table in the database based on another table #4821
|
|
20
|
+
- Accept Raw on onIn joins #4830
|
|
21
|
+
- Implement support for custom seed sources #4842
|
|
22
|
+
- Add binary uuid option #4836
|
|
23
|
+
- ForUpdate array parameter #4882
|
|
24
|
+
- Add camel case to timestamps method #4803
|
|
25
|
+
- Advanced JSON support #4859
|
|
26
|
+
- Add type to TypeScript knexfile #4909
|
|
27
|
+
- Checks Constraints Support #4874
|
|
28
|
+
- Support creating multiple PKs with increments #4903
|
|
29
|
+
- Enable wrapIdentifier for SQLite .hasTable #4915
|
|
30
|
+
- MSSQL: Add support for unique constraint #4887
|
|
31
|
+
- SQLite: New dialect, using better-sqlite3 driver #4871
|
|
32
|
+
- SQLite: Switch to @vscode/sqlite3 #4866
|
|
33
|
+
- SQLite: Support createViewOrReplace #4856
|
|
34
|
+
- SQLite: Support RETURNING statements for better-sqlite3 driver #4934
|
|
35
|
+
- PostgreSQL: Support JOIN and USING syntax for Delete Statement #4800
|
|
36
|
+
|
|
37
|
+
### Bug fixes:
|
|
38
|
+
|
|
39
|
+
- Fix overzealous warning on use of whereNot with "in" or "between" #4780
|
|
40
|
+
- Fix Union all + first syntax error #4799
|
|
41
|
+
- Make view columns optional in create view like #4829
|
|
42
|
+
- Insert lock row fix during migration #4865
|
|
43
|
+
- Fix for createViewOrReplace #4856
|
|
44
|
+
- SQLite: Fix foreign key constraints when altering a table #4189
|
|
45
|
+
- MySQL: Validate connection fix #4794
|
|
46
|
+
- MySQL: Set comment size warning limit to 1024 #4867
|
|
47
|
+
|
|
48
|
+
### Typings:
|
|
49
|
+
|
|
50
|
+
- Allow string indexType in index creation #4791
|
|
51
|
+
- Add missing ints typings #4832
|
|
52
|
+
- Returning method types #4881
|
|
53
|
+
- Improve columnInfo type #4868
|
|
54
|
+
|
|
55
|
+
# 0.95.15 - 22 December, 2021
|
|
56
|
+
|
|
57
|
+
### Bug fixes:
|
|
58
|
+
|
|
59
|
+
- Oracle:
|
|
60
|
+
- MariaDB: lock row fix during migration in MariaDB and Oracle #4865
|
|
61
|
+
|
|
62
|
+
# 0.95.14 - 09 November, 2021
|
|
63
|
+
|
|
64
|
+
### Bug fixes:
|
|
65
|
+
|
|
66
|
+
- MySQL: mysql2 dialect validate connection fix #4794
|
|
67
|
+
|
|
68
|
+
# 0.95.13 - 02 November, 2021
|
|
69
|
+
|
|
70
|
+
### Bug fixes:
|
|
71
|
+
|
|
72
|
+
- PostgreSQL: Support zero precision in timestamp/datetime #4784
|
|
73
|
+
|
|
74
|
+
### Typings:
|
|
75
|
+
|
|
76
|
+
- Allow string indexType in index creation #4791
|
|
77
|
+
|
|
3
78
|
# 0.95.12 - 28 October, 2021
|
|
4
79
|
|
|
5
80
|
### New features:
|
package/UPGRADING.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## Upgrading to new knex.js versions
|
|
2
2
|
|
|
3
|
+
### Upgrading to version 1.0.0+
|
|
4
|
+
|
|
5
|
+
* Node.js older than 12 is no longer supported, make sure to update your environment;
|
|
6
|
+
* If you are using `sqlite3` driver, please replace it with `@vscode/sqlite3`;
|
|
7
|
+
* `RETURNING` operations now always return an object with column names;
|
|
8
|
+
* Migrator now returns list of migrations as objects.
|
|
9
|
+
|
|
3
10
|
### Upgrading to version 0.95.0+
|
|
4
11
|
|
|
5
12
|
* TypeScript type exports changed significantly. While `import Knex from 'knex';` used to import the knex instantiation function, the namespace and the interface for the knex instantiation function/object, there is now a clear distinction between them:
|
package/lib/client.js
CHANGED
|
@@ -30,6 +30,7 @@ const Logger = require('./logger');
|
|
|
30
30
|
const { POOL_CONFIG_OPTIONS } = require('./constants');
|
|
31
31
|
const ViewBuilder = require('./schema/viewbuilder.js');
|
|
32
32
|
const ViewCompiler = require('./schema/viewcompiler.js');
|
|
33
|
+
const isPlainObject = require('lodash/isPlainObject');
|
|
33
34
|
|
|
34
35
|
const debug = require('debug')('knex:client');
|
|
35
36
|
|
|
@@ -51,6 +52,7 @@ class Client extends EventEmitter {
|
|
|
51
52
|
`Using 'this.dialect' to identify the client is deprecated and support for it will be removed in the future. Please use configuration option 'client' instead.`
|
|
52
53
|
);
|
|
53
54
|
}
|
|
55
|
+
|
|
54
56
|
const dbClient = this.config.client || this.dialect;
|
|
55
57
|
if (!dbClient) {
|
|
56
58
|
throw new Error(
|
|
@@ -392,8 +394,13 @@ class Client extends EventEmitter {
|
|
|
392
394
|
i = -1;
|
|
393
395
|
while (++i < values.length) {
|
|
394
396
|
if (i > 0) str += ', ';
|
|
397
|
+
let value = values[i];
|
|
398
|
+
// json columns can have object in values.
|
|
399
|
+
if (isPlainObject(value)) {
|
|
400
|
+
value = JSON.stringify(value);
|
|
401
|
+
}
|
|
395
402
|
str += this.parameter(
|
|
396
|
-
|
|
403
|
+
value === undefined ? notSetValue : value,
|
|
397
404
|
builder,
|
|
398
405
|
bindingsHolder
|
|
399
406
|
);
|
|
@@ -442,6 +449,12 @@ class Client extends EventEmitter {
|
|
|
442
449
|
processPassedConnection(connection) {
|
|
443
450
|
// Default implementation is noop
|
|
444
451
|
}
|
|
452
|
+
|
|
453
|
+
toPathForJson(jsonPath) {
|
|
454
|
+
// By default, we want a json path, so if this function is not overriden,
|
|
455
|
+
// we return the path.
|
|
456
|
+
return jsonPath;
|
|
457
|
+
}
|
|
445
458
|
}
|
|
446
459
|
|
|
447
460
|
Object.assign(Client.prototype, {
|
package/lib/constants.js
CHANGED
|
@@ -16,6 +16,7 @@ const SUPPORTED_CLIENTS = Object.freeze(
|
|
|
16
16
|
'redshift',
|
|
17
17
|
'sqlite3',
|
|
18
18
|
'cockroachdb',
|
|
19
|
+
'better-sqlite3',
|
|
19
20
|
].concat(Object.keys(CLIENT_ALIASES))
|
|
20
21
|
);
|
|
21
22
|
|
|
@@ -29,6 +30,7 @@ const DRIVER_NAMES = Object.freeze({
|
|
|
29
30
|
Redshift: 'pg-redshift',
|
|
30
31
|
SQLite: 'sqlite3',
|
|
31
32
|
CockroachDB: 'cockroachdb',
|
|
33
|
+
BetterSQLite3: 'better-sqlite3',
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
const POOL_CONFIG_OPTIONS = Object.freeze([
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// better-sqlite3 Client
|
|
2
|
+
// -------
|
|
3
|
+
const Client_SQLite3 = require('../sqlite3');
|
|
4
|
+
|
|
5
|
+
class Client_BetterSQLite3 extends Client_SQLite3 {
|
|
6
|
+
_driver() {
|
|
7
|
+
return require('better-sqlite3');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Get a raw connection from the database, returning a promise with the connection object.
|
|
11
|
+
async acquireRawConnection() {
|
|
12
|
+
return new this.driver(this.connectionSettings.filename);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Used to explicitly close a connection, called internally by the pool when
|
|
16
|
+
// a connection times out or the pool is shutdown.
|
|
17
|
+
async destroyRawConnection(connection) {
|
|
18
|
+
return connection.close();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Runs the query on the specified connection, providing the bindings and any
|
|
22
|
+
// other necessary prep work.
|
|
23
|
+
async _query(connection, obj) {
|
|
24
|
+
if (!obj.sql) throw new Error('The query is empty');
|
|
25
|
+
|
|
26
|
+
if (!connection) {
|
|
27
|
+
throw new Error('No connection provided');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const statement = connection.prepare(obj.sql);
|
|
31
|
+
const bindings = this._formatBindings(obj.bindings);
|
|
32
|
+
|
|
33
|
+
if (statement.reader) {
|
|
34
|
+
const response = await statement.all(bindings);
|
|
35
|
+
obj.response = response;
|
|
36
|
+
return obj;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const response = await statement.run(bindings);
|
|
40
|
+
obj.response = response;
|
|
41
|
+
obj.context = {
|
|
42
|
+
lastID: response.lastInsertRowid,
|
|
43
|
+
changes: response.changes,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return obj;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
_formatBindings(bindings) {
|
|
50
|
+
if (!bindings) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
return bindings.map((binding) => {
|
|
54
|
+
if (binding instanceof Date) {
|
|
55
|
+
return binding.valueOf();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (typeof binding === 'boolean') {
|
|
59
|
+
return String(binding);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return binding;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Object.assign(Client_BetterSQLite3.prototype, {
|
|
68
|
+
// The "dialect", for reference .
|
|
69
|
+
driverName: 'better-sqlite3',
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
module.exports = Client_BetterSQLite3;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const QueryCompiler_PG = require('../postgres/query/pg-querycompiler');
|
|
2
|
-
const
|
|
3
|
-
|
|
2
|
+
const {
|
|
3
|
+
columnize: columnize_,
|
|
4
|
+
wrap: wrap_,
|
|
5
|
+
operator: operator_,
|
|
6
|
+
} = require('../../formatter/wrappingFormatter');
|
|
4
7
|
|
|
5
8
|
class QueryCompiler_CRDB extends QueryCompiler_PG {
|
|
6
9
|
truncate() {
|
|
@@ -20,43 +23,94 @@ class QueryCompiler_CRDB extends QueryCompiler_PG {
|
|
|
20
23
|
|
|
21
24
|
_upsert() {
|
|
22
25
|
const upsertValues = this.single.upsert || [];
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
const sql = this.with() + `upsert into ${this.tableName} `;
|
|
27
|
+
const body = this._insertBody(upsertValues);
|
|
28
|
+
return body === '' ? '' : sql + body;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
whereJsonPath(statement) {
|
|
32
|
+
let castValue = '';
|
|
33
|
+
if (parseInt(statement.value)) {
|
|
34
|
+
castValue = '::int';
|
|
35
|
+
} else if (parseFloat(statement.value)) {
|
|
36
|
+
castValue = '::float';
|
|
37
|
+
} else {
|
|
38
|
+
castValue = " #>> '{}'";
|
|
28
39
|
}
|
|
40
|
+
return `json_extract_path(${this._columnClause(
|
|
41
|
+
statement
|
|
42
|
+
)}, ${this.client.toArrayPathFromJsonPath(
|
|
43
|
+
statement.jsonPath,
|
|
44
|
+
this.builder,
|
|
45
|
+
this.bindingsHolder
|
|
46
|
+
)})${castValue} ${operator_(
|
|
47
|
+
statement.operator,
|
|
48
|
+
this.builder,
|
|
49
|
+
this.client,
|
|
50
|
+
this.bindingsHolder
|
|
51
|
+
)} ${this._jsonValueClause(statement)}`;
|
|
52
|
+
}
|
|
29
53
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
54
|
+
// Json common functions
|
|
55
|
+
_jsonExtract(nameFunction, params) {
|
|
56
|
+
let extractions;
|
|
57
|
+
if (Array.isArray(params.column)) {
|
|
58
|
+
extractions = params.column;
|
|
33
59
|
} else {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
60
|
+
extractions = [params];
|
|
61
|
+
}
|
|
62
|
+
return extractions
|
|
63
|
+
.map((extraction) => {
|
|
64
|
+
const jsonCol = `json_extract_path(${columnize_(
|
|
65
|
+
extraction.column || extraction[0],
|
|
37
66
|
this.builder,
|
|
38
67
|
this.client,
|
|
39
68
|
this.bindingsHolder
|
|
40
|
-
)}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
)}, ${this.client.toArrayPathFromJsonPath(
|
|
70
|
+
extraction.path || extraction[1],
|
|
71
|
+
this.builder,
|
|
72
|
+
this.bindingsHolder
|
|
73
|
+
)})`;
|
|
74
|
+
const alias = extraction.alias || extraction[2];
|
|
75
|
+
return alias
|
|
76
|
+
? this.client.alias(jsonCol, this.formatter.wrap(alias))
|
|
77
|
+
: jsonCol;
|
|
78
|
+
})
|
|
79
|
+
.join(', ');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_onJsonPathEquals(nameJoinFunction, clause) {
|
|
83
|
+
return (
|
|
84
|
+
'json_extract_path(' +
|
|
85
|
+
wrap_(
|
|
86
|
+
clause.columnFirst,
|
|
87
|
+
undefined,
|
|
88
|
+
this.builder,
|
|
89
|
+
this.client,
|
|
90
|
+
this.bindingsHolder
|
|
91
|
+
) +
|
|
92
|
+
', ' +
|
|
93
|
+
this.client.toArrayPathFromJsonPath(
|
|
94
|
+
clause.jsonPathFirst,
|
|
95
|
+
this.builder,
|
|
96
|
+
this.bindingsHolder
|
|
97
|
+
) +
|
|
98
|
+
') = json_extract_path(' +
|
|
99
|
+
wrap_(
|
|
100
|
+
clause.columnSecond,
|
|
101
|
+
undefined,
|
|
102
|
+
this.builder,
|
|
103
|
+
this.client,
|
|
104
|
+
this.bindingsHolder
|
|
105
|
+
) +
|
|
106
|
+
', ' +
|
|
107
|
+
this.client.toArrayPathFromJsonPath(
|
|
108
|
+
clause.jsonPathSecond,
|
|
109
|
+
this.builder,
|
|
110
|
+
this.bindingsHolder
|
|
111
|
+
) +
|
|
112
|
+
')'
|
|
113
|
+
);
|
|
60
114
|
}
|
|
61
115
|
}
|
|
62
116
|
|
|
@@ -7,6 +7,25 @@ class TableCompiler_CRDB extends TableCompiler {
|
|
|
7
7
|
super(client, tableBuilder);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
addColumns(columns, prefix, colCompilers) {
|
|
11
|
+
if (prefix === this.alterColumnsPrefix) {
|
|
12
|
+
// alter columns
|
|
13
|
+
for (const col of colCompilers) {
|
|
14
|
+
this.client.logger.warn(
|
|
15
|
+
'Experimental alter column in use, see issue: https://github.com/cockroachdb/cockroach/issues/49329'
|
|
16
|
+
);
|
|
17
|
+
this.pushQuery({
|
|
18
|
+
sql: 'SET enable_experimental_alter_column_type_general = true',
|
|
19
|
+
bindings: [],
|
|
20
|
+
});
|
|
21
|
+
super._addColumn(col);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
// base class implementation for normal add
|
|
25
|
+
super.addColumns(columns, prefix);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
10
29
|
dropUnique(columns, indexName) {
|
|
11
30
|
indexName = indexName
|
|
12
31
|
? this.formatter.wrap(indexName)
|
|
@@ -58,6 +58,19 @@ class Client_CockroachDB extends Client_PostgreSQL {
|
|
|
58
58
|
connectionToKill.activeQuery
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
toArrayPathFromJsonPath(jsonPath, builder, bindingsHolder) {
|
|
63
|
+
return jsonPath
|
|
64
|
+
.replace(/^(\$\.)/, '') // remove the first dollar
|
|
65
|
+
.replace(/\[([0-9]+)]/, '.$1')
|
|
66
|
+
.split('.')
|
|
67
|
+
.map(
|
|
68
|
+
function (v) {
|
|
69
|
+
return this.parameter(v, builder, bindingsHolder);
|
|
70
|
+
}.bind(this)
|
|
71
|
+
)
|
|
72
|
+
.join(', ');
|
|
73
|
+
}
|
|
61
74
|
}
|
|
62
75
|
|
|
63
76
|
Object.assign(Client_CockroachDB.prototype, {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// MSSQL Client
|
|
2
2
|
// -------
|
|
3
|
-
const flatten = require('lodash/flatten');
|
|
4
3
|
const map = require('lodash/map');
|
|
5
|
-
const values = require('lodash/values');
|
|
6
4
|
const isNil = require('lodash/isNil');
|
|
7
5
|
|
|
8
6
|
const Client = require('../../client');
|
|
@@ -472,15 +470,6 @@ class Client_MSSQL extends Client {
|
|
|
472
470
|
if (query.returning === '@@rowcount') {
|
|
473
471
|
return response[0][''];
|
|
474
472
|
}
|
|
475
|
-
|
|
476
|
-
if (
|
|
477
|
-
(Array.isArray(query.returning) && query.returning.length > 1) ||
|
|
478
|
-
query.returning[0] === '*'
|
|
479
|
-
) {
|
|
480
|
-
return response;
|
|
481
|
-
}
|
|
482
|
-
// return an array with values if only one returning value was specified
|
|
483
|
-
return flatten(map(response, values));
|
|
484
473
|
}
|
|
485
474
|
return response;
|
|
486
475
|
default:
|
|
@@ -6,6 +6,9 @@ const compact = require('lodash/compact');
|
|
|
6
6
|
const identity = require('lodash/identity');
|
|
7
7
|
const isEmpty = require('lodash/isEmpty');
|
|
8
8
|
const Raw = require('../../../raw.js');
|
|
9
|
+
const {
|
|
10
|
+
columnize: columnize_,
|
|
11
|
+
} = require('../../../formatter/wrappingFormatter');
|
|
9
12
|
|
|
10
13
|
const components = [
|
|
11
14
|
'columns',
|
|
@@ -100,40 +103,37 @@ class QueryCompiler_MSSQL extends QueryCompiler {
|
|
|
100
103
|
returning,
|
|
101
104
|
};
|
|
102
105
|
}
|
|
106
|
+
sql += this._buildInsertData(insertValues, returningSql);
|
|
103
107
|
|
|
108
|
+
if (returning) {
|
|
109
|
+
sql += this._buildReturningSelect(returning);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
sql,
|
|
114
|
+
returning,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_buildInsertData(insertValues, returningSql) {
|
|
119
|
+
let sql = '';
|
|
104
120
|
const insertData = this._prepInsert(insertValues);
|
|
105
121
|
if (typeof insertData === 'string') {
|
|
106
122
|
sql += insertData;
|
|
107
123
|
} else {
|
|
108
124
|
if (insertData.columns.length) {
|
|
109
125
|
sql += `(${this.formatter.columnize(insertData.columns)}`;
|
|
110
|
-
sql +=
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
sql += this.client.parameterize(
|
|
115
|
-
insertData.values[i],
|
|
116
|
-
this.client.valueForUndefined,
|
|
117
|
-
this.builder,
|
|
118
|
-
this.bindingsHolder
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
sql += ')';
|
|
126
|
+
sql +=
|
|
127
|
+
`) ${returningSql}values (` +
|
|
128
|
+
this._buildInsertValues(insertData) +
|
|
129
|
+
')';
|
|
122
130
|
} else if (insertValues.length === 1 && insertValues[0]) {
|
|
123
131
|
sql += returningSql + this._emptyInsertValue;
|
|
124
132
|
} else {
|
|
125
|
-
|
|
133
|
+
return '';
|
|
126
134
|
}
|
|
127
135
|
}
|
|
128
|
-
|
|
129
|
-
if (returning) {
|
|
130
|
-
sql += this._buildReturningSelect(returning);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return {
|
|
134
|
-
sql,
|
|
135
|
-
returning,
|
|
136
|
-
};
|
|
136
|
+
return sql;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
standardInsert() {
|
|
@@ -155,30 +155,7 @@ class QueryCompiler_MSSQL extends QueryCompiler {
|
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
if (typeof insertData === 'string') {
|
|
160
|
-
sql += insertData;
|
|
161
|
-
} else {
|
|
162
|
-
if (insertData.columns.length) {
|
|
163
|
-
sql += `(${this.formatter.columnize(insertData.columns)}`;
|
|
164
|
-
sql += `) ${returningSql}values (`;
|
|
165
|
-
let i = -1;
|
|
166
|
-
while (++i < insertData.values.length) {
|
|
167
|
-
if (i !== 0) sql += '), (';
|
|
168
|
-
sql += this.client.parameterize(
|
|
169
|
-
insertData.values[i],
|
|
170
|
-
this.client.valueForUndefined,
|
|
171
|
-
this.builder,
|
|
172
|
-
this.bindingsHolder
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
sql += ')';
|
|
176
|
-
} else if (insertValues.length === 1 && insertValues[0]) {
|
|
177
|
-
sql += returningSql + this._emptyInsertValue;
|
|
178
|
-
} else {
|
|
179
|
-
sql = '';
|
|
180
|
-
}
|
|
181
|
-
}
|
|
158
|
+
sql += this._buildInsertData(insertValues, returningSql);
|
|
182
159
|
|
|
183
160
|
return {
|
|
184
161
|
sql,
|
|
@@ -354,15 +331,17 @@ class QueryCompiler_MSSQL extends QueryCompiler {
|
|
|
354
331
|
sql.push(this.aggregateRaw(stmt));
|
|
355
332
|
} else if (stmt.type === 'analytic') {
|
|
356
333
|
sql.push(this.analytic(stmt));
|
|
334
|
+
} else if (stmt.type === 'json') {
|
|
335
|
+
sql.push(this.json(stmt));
|
|
357
336
|
} else if (stmt.value && stmt.value.length > 0) {
|
|
358
337
|
sql.push(this.formatter.columnize(stmt.value));
|
|
359
338
|
}
|
|
360
339
|
}
|
|
361
340
|
}
|
|
362
341
|
if (sql.length === 0) sql = ['*'];
|
|
363
|
-
|
|
342
|
+
const select = this.onlyJson() ? '' : 'select ';
|
|
364
343
|
return (
|
|
365
|
-
|
|
344
|
+
`${select}${hints}${distinctClause}` +
|
|
366
345
|
(top ? top + ' ' : '') +
|
|
367
346
|
sql.join(', ') +
|
|
368
347
|
(this.tableName ? ` from ${this.tableName}` : '')
|
|
@@ -502,11 +481,7 @@ class QueryCompiler_MSSQL extends QueryCompiler {
|
|
|
502
481
|
const noLimit = !this.single.limit && this.single.limit !== 0;
|
|
503
482
|
const noOffset = !this.single.offset;
|
|
504
483
|
if (noLimit || !noOffset) return '';
|
|
505
|
-
return `top (${this.
|
|
506
|
-
this.single.limit,
|
|
507
|
-
this.builder,
|
|
508
|
-
this.bindingsHolder
|
|
509
|
-
)})`;
|
|
484
|
+
return `top (${this._getValueOrParameterFromAttribute('limit')})`;
|
|
510
485
|
}
|
|
511
486
|
|
|
512
487
|
limit() {
|
|
@@ -518,23 +493,106 @@ class QueryCompiler_MSSQL extends QueryCompiler {
|
|
|
518
493
|
const noOffset = !this.single.offset;
|
|
519
494
|
if (noOffset) return '';
|
|
520
495
|
let offset = `offset ${
|
|
521
|
-
noOffset
|
|
522
|
-
? '0'
|
|
523
|
-
: this.client.parameter(
|
|
524
|
-
this.single.offset,
|
|
525
|
-
this.builder,
|
|
526
|
-
this.bindingsHolder
|
|
527
|
-
)
|
|
496
|
+
noOffset ? '0' : this._getValueOrParameterFromAttribute('offset')
|
|
528
497
|
} rows`;
|
|
529
498
|
if (!noLimit) {
|
|
530
|
-
offset += ` fetch next ${this.
|
|
531
|
-
|
|
532
|
-
this.builder,
|
|
533
|
-
this.bindingsHolder
|
|
499
|
+
offset += ` fetch next ${this._getValueOrParameterFromAttribute(
|
|
500
|
+
'limit'
|
|
534
501
|
)} rows only`;
|
|
535
502
|
}
|
|
536
503
|
return offset;
|
|
537
504
|
}
|
|
505
|
+
|
|
506
|
+
whereLike(statement) {
|
|
507
|
+
return `${this._columnClause(
|
|
508
|
+
statement
|
|
509
|
+
)} collate SQL_Latin1_General_CP1_CS_AS ${this._not(
|
|
510
|
+
statement,
|
|
511
|
+
'like '
|
|
512
|
+
)}${this._valueClause(statement)}`;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
whereILike(statement) {
|
|
516
|
+
return `${this._columnClause(
|
|
517
|
+
statement
|
|
518
|
+
)} collate SQL_Latin1_General_CP1_CI_AS ${this._not(
|
|
519
|
+
statement,
|
|
520
|
+
'like '
|
|
521
|
+
)}${this._valueClause(statement)}`;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
jsonExtract(params) {
|
|
525
|
+
// JSON_VALUE return NULL if we query object or array
|
|
526
|
+
// JSON_QUERY return NULL if we query literal/single value
|
|
527
|
+
return this._jsonExtract(
|
|
528
|
+
params.singleValue ? 'JSON_VALUE' : 'JSON_QUERY',
|
|
529
|
+
params
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
jsonSet(params) {
|
|
534
|
+
return this._jsonSet('JSON_MODIFY', params);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
jsonInsert(params) {
|
|
538
|
+
return this._jsonSet('JSON_MODIFY', params);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
jsonRemove(params) {
|
|
542
|
+
const jsonCol = `JSON_MODIFY(${columnize_(
|
|
543
|
+
params.column,
|
|
544
|
+
this.builder,
|
|
545
|
+
this.client,
|
|
546
|
+
this.bindingsHolder
|
|
547
|
+
)},${this.client.parameter(
|
|
548
|
+
params.path,
|
|
549
|
+
this.builder,
|
|
550
|
+
this.bindingsHolder
|
|
551
|
+
)}, NULL)`;
|
|
552
|
+
return params.alias
|
|
553
|
+
? this.client.alias(jsonCol, this.formatter.wrap(params.alias))
|
|
554
|
+
: jsonCol;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
whereJsonPath(statement) {
|
|
558
|
+
return this._whereJsonPath('JSON_VALUE', statement);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
whereJsonSupersetOf(statement) {
|
|
562
|
+
throw new Error(
|
|
563
|
+
'Json superset where clause not actually supported by MSSQL'
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
whereJsonSubsetOf(statement) {
|
|
568
|
+
throw new Error('Json subset where clause not actually supported by MSSQL');
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
_getExtracts(statement, operator) {
|
|
572
|
+
const column = columnize_(
|
|
573
|
+
statement.column,
|
|
574
|
+
this.builder,
|
|
575
|
+
this.client,
|
|
576
|
+
this.bindingsHolder
|
|
577
|
+
);
|
|
578
|
+
return (
|
|
579
|
+
Array.isArray(statement.values) ? statement.values : [statement.values]
|
|
580
|
+
)
|
|
581
|
+
.map(function (value) {
|
|
582
|
+
return (
|
|
583
|
+
'JSON_VALUE(' +
|
|
584
|
+
column +
|
|
585
|
+
',' +
|
|
586
|
+
this.client.parameter(value, this.builder, this.bindingsHolder) +
|
|
587
|
+
')'
|
|
588
|
+
);
|
|
589
|
+
}, this)
|
|
590
|
+
.join(operator);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
onJsonPathEquals(clause) {
|
|
594
|
+
return this._onJsonPathEquals('JSON_VALUE', clause);
|
|
595
|
+
}
|
|
538
596
|
}
|
|
539
597
|
|
|
540
598
|
// Set the QueryBuilder & QueryCompiler on the client object,
|