kysely 0.29.2 → 0.29.3
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/README.md +1 -1
- package/dist/dialect/mssql/mssql-adapter.d.ts +3 -2
- package/dist/dialect/mssql/mssql-adapter.js +13 -7
- package/dist/dialect/mysql/mysql-dialect-config.d.ts +8 -6
- package/dist/dialect/postgres/postgres-adapter.d.ts +1 -1
- package/dist/dialect/postgres/postgres-adapter.js +13 -7
- package/dist/migration/migrator.js +23 -18
- package/dist/query-builder/json-path-builder.d.ts +2 -2
- package/package.json +19 -19
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[](https://stand-with-ukraine.pp.ua)
|
|
2
2
|
|
|
3
3
|
[](https://github.com/kysely-org/kysely/releases/latest)
|
|
4
|
-
[](https://socket.dev/npm/package/kysely/overview/0.29.3)
|
|
5
5
|
[](https://github.com/kysely-org/kysely)
|
|
6
6
|
[](https://github.com/kysely-org/kysely/blob/master/LICENSE)
|
|
7
7
|
[](https://github.com/kysely-org/kysely/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Kysely } from '../../kysely.js';
|
|
2
2
|
import { DialectAdapterBase } from '../dialect-adapter-base.js';
|
|
3
|
+
import type { MigrationLockOptions } from '../dialect-adapter.js';
|
|
3
4
|
export declare class MssqlAdapter extends DialectAdapterBase {
|
|
4
5
|
get supportsCreateIfNotExists(): boolean;
|
|
5
6
|
get supportsTransactionalDdl(): boolean;
|
|
@@ -58,7 +59,7 @@ export declare class MssqlAdapter extends DialectAdapterBase {
|
|
|
58
59
|
* `db` is a single connection (session) that will be used to execute the
|
|
59
60
|
* migrations.
|
|
60
61
|
*/
|
|
61
|
-
acquireMigrationLock(db: Kysely<any
|
|
62
|
+
acquireMigrationLock(db: Kysely<any>, _opt: MigrationLockOptions): Promise<void>;
|
|
62
63
|
/**
|
|
63
64
|
* Releases the migration lock. See {@link acquireMigrationLock}.
|
|
64
65
|
*
|
|
@@ -67,5 +68,5 @@ export declare class MssqlAdapter extends DialectAdapterBase {
|
|
|
67
68
|
* is a single connection (session) that was used to execute the migrations
|
|
68
69
|
* and the `acquireMigrationLock` call.
|
|
69
70
|
*/
|
|
70
|
-
releaseMigrationLock(): Promise<void>;
|
|
71
|
+
releaseMigrationLock(db: Kysely<any>, _opt: MigrationLockOptions): Promise<void>;
|
|
71
72
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { DEFAULT_MIGRATION_TABLE } from '../../migration/migrator.js';
|
|
3
3
|
import { sql } from '../../raw-builder/sql.js';
|
|
4
4
|
import { DialectAdapterBase } from '../dialect-adapter-base.js';
|
|
5
|
+
const LOCK_PRINCIPAL = 'dbo';
|
|
5
6
|
export class MssqlAdapter extends DialectAdapterBase {
|
|
6
7
|
get supportsCreateIfNotExists() {
|
|
7
8
|
return false;
|
|
@@ -12,14 +13,19 @@ export class MssqlAdapter extends DialectAdapterBase {
|
|
|
12
13
|
get supportsOutput() {
|
|
13
14
|
return true;
|
|
14
15
|
}
|
|
15
|
-
async acquireMigrationLock(db) {
|
|
16
|
-
// Acquire a
|
|
16
|
+
async acquireMigrationLock(db, _opt) {
|
|
17
|
+
// Acquire a session-level exclusive lock on the migrations table. A
|
|
18
|
+
// session-level lock (as opposed to the default transaction-level lock)
|
|
19
|
+
// stays held after the migration transaction commits and until we release
|
|
20
|
+
// it explicitly in `releaseMigrationLock` OR the session ends. This way we
|
|
21
|
+
// know the lock is either released by us after successful or failed
|
|
22
|
+
// migrations OR it's released by SQL Server if the connection dies.
|
|
17
23
|
// https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-getapplock-transact-sql?view=sql-server-ver16
|
|
18
|
-
await sql `exec sp_getapplock @DbPrincipal = ${sql.lit(
|
|
24
|
+
await sql `exec sp_getapplock @DbPrincipal = ${sql.lit(LOCK_PRINCIPAL)}, @Resource = ${sql.lit(DEFAULT_MIGRATION_TABLE)}, @LockMode = ${sql.lit('Exclusive')}, @LockOwner = ${sql.lit('Session')}`.execute(db);
|
|
19
25
|
}
|
|
20
|
-
async releaseMigrationLock() {
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
|
|
26
|
+
async releaseMigrationLock(db, _opt) {
|
|
27
|
+
// Release the session-level lock acquired in `acquireMigrationLock`.
|
|
28
|
+
// https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-releaseapplock-transact-sql?view=sql-server-ver16
|
|
29
|
+
await sql `exec sp_releaseapplock @DbPrincipal = ${sql.lit(LOCK_PRINCIPAL)}, @Resource = ${sql.lit(DEFAULT_MIGRATION_TABLE)}, @LockOwner = ${sql.lit('Session')}`.execute(db);
|
|
24
30
|
}
|
|
25
31
|
}
|
|
@@ -10,7 +10,10 @@ export interface MysqlDialectConfig {
|
|
|
10
10
|
*
|
|
11
11
|
* This is useful for cancelling queries on the database side.
|
|
12
12
|
*/
|
|
13
|
-
controlConnection?:
|
|
13
|
+
controlConnection?: {
|
|
14
|
+
(connectionUri: string): MysqlConnection;
|
|
15
|
+
(config: object): MysqlConnection;
|
|
16
|
+
};
|
|
14
17
|
/**
|
|
15
18
|
* A mysql2 Pool instance or a function that returns one.
|
|
16
19
|
*
|
|
@@ -44,10 +47,9 @@ export interface MysqlConnection {
|
|
|
44
47
|
config: object;
|
|
45
48
|
connect(callback?: (error: unknown) => void): void;
|
|
46
49
|
destroy(): void;
|
|
47
|
-
query(sql: string, parameters:
|
|
48
|
-
stream:
|
|
50
|
+
query(sql: string, parameters: any, callback?: (error: unknown, result: MysqlQueryResult) => void): {
|
|
51
|
+
stream: (options: MysqlStreamOptions) => MysqlStream;
|
|
49
52
|
};
|
|
50
|
-
query(sql: string, parameters: Array<unknown>, callback: (error: unknown, result: MysqlQueryResult) => void): void;
|
|
51
53
|
threadId: number;
|
|
52
54
|
}
|
|
53
55
|
export type MysqlConectionConstructor = new (opts?: object) => MysqlConnection;
|
|
@@ -58,8 +60,8 @@ export interface MysqlStreamOptions {
|
|
|
58
60
|
highWaterMark?: number;
|
|
59
61
|
objectMode?: true;
|
|
60
62
|
}
|
|
61
|
-
export interface MysqlStream
|
|
62
|
-
[Symbol.asyncIterator]():
|
|
63
|
+
export interface MysqlStream {
|
|
64
|
+
[Symbol.asyncIterator](): any;
|
|
63
65
|
}
|
|
64
66
|
export interface MysqlOkPacket {
|
|
65
67
|
affectedRows: number;
|
|
@@ -67,5 +67,5 @@ export declare class PostgresAdapter extends DialectAdapterBase {
|
|
|
67
67
|
* is a single connection (session) that was used to execute the migrations
|
|
68
68
|
* and the `acquireMigrationLock` call.
|
|
69
69
|
*/
|
|
70
|
-
releaseMigrationLock(
|
|
70
|
+
releaseMigrationLock(db: Kysely<any>, _opt: MigrationLockOptions): Promise<void>;
|
|
71
71
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/// <reference types="./postgres-adapter.d.ts" />
|
|
2
2
|
import { sql } from '../../raw-builder/sql.js';
|
|
3
3
|
import { DialectAdapterBase } from '../dialect-adapter-base.js';
|
|
4
|
-
// Random id for our transaction lock.
|
|
5
4
|
const LOCK_ID = BigInt('3853314791062309107');
|
|
5
|
+
const LOCK_TIMEOUT_MILLISECONDS = 60 * 60 * 1_000;
|
|
6
6
|
export class PostgresAdapter extends DialectAdapterBase {
|
|
7
7
|
get supportsTransactionalDdl() {
|
|
8
8
|
return true;
|
|
@@ -11,12 +11,18 @@ export class PostgresAdapter extends DialectAdapterBase {
|
|
|
11
11
|
return true;
|
|
12
12
|
}
|
|
13
13
|
async acquireMigrationLock(db, _opt) {
|
|
14
|
-
//
|
|
15
|
-
|
|
14
|
+
// in 1 RTT, acquire a session-level advisory lock with a timeout.
|
|
15
|
+
//
|
|
16
|
+
// if ever this runs inside a transaction, niche edge case we support - the
|
|
17
|
+
// user is responsible to set a different timeout value or disable (`0` value).
|
|
18
|
+
await sql `
|
|
19
|
+
with set_timeout as (
|
|
20
|
+
select set_config('lock_timeout', '${sql.lit(LOCK_TIMEOUT_MILLISECONDS)}', true) as config_val
|
|
21
|
+
)
|
|
22
|
+
select pg_advisory_lock(${sql.lit(LOCK_ID)})
|
|
23
|
+
from set_timeout`.execute(db);
|
|
16
24
|
}
|
|
17
|
-
async releaseMigrationLock(
|
|
18
|
-
|
|
19
|
-
// end of the transaction and since `supportsTransactionalDdl` true, we know
|
|
20
|
-
// the `db` instance passed to acquireMigrationLock is actually a transaction.
|
|
25
|
+
async releaseMigrationLock(db, _opt) {
|
|
26
|
+
await sql `select pg_advisory_unlock(${sql.lit(LOCK_ID)})`.execute(db);
|
|
21
27
|
}
|
|
22
28
|
}
|
|
@@ -404,23 +404,26 @@ export class Migrator {
|
|
|
404
404
|
lockTableSchema: this.#props.migrationTableSchema,
|
|
405
405
|
});
|
|
406
406
|
const run = async (db) => {
|
|
407
|
+
const state = await this.#getState(db);
|
|
408
|
+
if (state.migrations.length === 0) {
|
|
409
|
+
return { results: [] };
|
|
410
|
+
}
|
|
411
|
+
const { direction, step } = getMigrationDirectionAndStep(state);
|
|
412
|
+
if (step <= 0) {
|
|
413
|
+
return { results: [] };
|
|
414
|
+
}
|
|
415
|
+
if (direction === 'Down') {
|
|
416
|
+
return await this.#migrateDown(db, state, step);
|
|
417
|
+
}
|
|
418
|
+
else if (direction === 'Up') {
|
|
419
|
+
return await this.#migrateUp(db, state, step);
|
|
420
|
+
}
|
|
421
|
+
return { results: [] };
|
|
422
|
+
};
|
|
423
|
+
const runWithLock = async (db, cb) => {
|
|
407
424
|
try {
|
|
408
425
|
await adapter.acquireMigrationLock(db, lockOptions);
|
|
409
|
-
|
|
410
|
-
if (state.migrations.length === 0) {
|
|
411
|
-
return { results: [] };
|
|
412
|
-
}
|
|
413
|
-
const { direction, step } = getMigrationDirectionAndStep(state);
|
|
414
|
-
if (step <= 0) {
|
|
415
|
-
return { results: [] };
|
|
416
|
-
}
|
|
417
|
-
if (direction === 'Down') {
|
|
418
|
-
return await this.#migrateDown(db, state, step);
|
|
419
|
-
}
|
|
420
|
-
else if (direction === 'Up') {
|
|
421
|
-
return await this.#migrateUp(db, state, step);
|
|
422
|
-
}
|
|
423
|
-
return { results: [] };
|
|
426
|
+
return await cb(db);
|
|
424
427
|
}
|
|
425
428
|
finally {
|
|
426
429
|
await adapter.releaseMigrationLock(db, lockOptions);
|
|
@@ -434,12 +437,14 @@ export class Migrator {
|
|
|
434
437
|
if (disableTransactions) {
|
|
435
438
|
throw new Error('`disableTransactions` is true but the migrator was given a transaction. Passing a transaction to this migrator would result in failure or unexpected behavior.');
|
|
436
439
|
}
|
|
437
|
-
return
|
|
440
|
+
return runWithLock(this.#props.db, run);
|
|
438
441
|
}
|
|
439
442
|
if (adapter.supportsTransactionalDdl && !disableTransactions) {
|
|
440
|
-
return this.#props.db
|
|
443
|
+
return this.#props.db
|
|
444
|
+
.connection()
|
|
445
|
+
.execute((db) => runWithLock(db, (db) => db.transaction().execute((trx) => run(trx))));
|
|
441
446
|
}
|
|
442
|
-
return this.#props.db.connection().execute(run);
|
|
447
|
+
return this.#props.db.connection().execute((db) => runWithLock(db, run));
|
|
443
448
|
}
|
|
444
449
|
async #getState(db) {
|
|
445
450
|
const migrations = await this.#resolveMigrations();
|
|
@@ -73,7 +73,7 @@ export declare class JSONPathBuilder<S, O = S> {
|
|
|
73
73
|
* select "nicknames"->>'$[#-1]' as `last_nickname` from `person`
|
|
74
74
|
* ```
|
|
75
75
|
*/
|
|
76
|
-
at<I extends any[] extends O ? number | 'last' | `#-${number}` : never, O2 = null | NonNullable<NonNullable<O>[keyof NonNullable<O> & number]>>(index: `${I}` extends `${any}.${any}` | `#--${any}` ? never : I): TraversedJSONPathBuilder<S, O2>;
|
|
76
|
+
at<I extends (any[] extends O ? number | 'last' | `#-${number}` : never), O2 = null | NonNullable<NonNullable<O>[keyof NonNullable<O> & number]>>(index: `${I}` extends `${any}.${any}` | `#--${any}` ? never : I): TraversedJSONPathBuilder<S, O2>;
|
|
77
77
|
/**
|
|
78
78
|
* Access a property of a JSON object.
|
|
79
79
|
*
|
|
@@ -123,7 +123,7 @@ export declare class JSONPathBuilder<S, O = S> {
|
|
|
123
123
|
* select "profile"->'addresses'->0->'city' as "city" from "person"
|
|
124
124
|
* ```
|
|
125
125
|
*/
|
|
126
|
-
key<K extends any[] extends O ? never : O extends object ? keyof NonNullable<O> & string : never, O2 = undefined extends O ? null | NonNullable<NonNullable<O>[K]> : null extends O ? null | NonNullable<NonNullable<O>[K]> : string extends keyof NonNullable<O> ? null | NonNullable<NonNullable<O>[K]> : NonNullable<O>[K]>(key: K): TraversedJSONPathBuilder<S, O2>;
|
|
126
|
+
key<K extends (any[] extends O ? never : O extends object ? keyof NonNullable<O> & string : never), O2 = undefined extends O ? null | NonNullable<NonNullable<O>[K]> : null extends O ? null | NonNullable<NonNullable<O>[K]> : string extends keyof NonNullable<O> ? null | NonNullable<NonNullable<O>[K]> : NonNullable<O>[K]>(key: K): TraversedJSONPathBuilder<S, O2>;
|
|
127
127
|
}
|
|
128
128
|
export declare class TraversedJSONPathBuilder<S, O> extends JSONPathBuilder<S, O> implements AliasableExpression<O> {
|
|
129
129
|
#private;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kysely",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.3",
|
|
4
4
|
"description": "Type safe SQL query builder",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -61,40 +61,40 @@
|
|
|
61
61
|
"Igal Klebanov <igalklebanov@gmail.com>"
|
|
62
62
|
],
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@arethetypeswrong/cli": "0.18.
|
|
65
|
-
"@ark/attest": "0.56.
|
|
66
|
-
"@electric-sql/pglite": "0.
|
|
64
|
+
"@arethetypeswrong/cli": "0.18.4",
|
|
65
|
+
"@ark/attest": "0.56.2",
|
|
66
|
+
"@electric-sql/pglite": "0.5.3",
|
|
67
67
|
"@types/better-sqlite3": "7.6.13",
|
|
68
68
|
"@types/chai": "5.2.3",
|
|
69
69
|
"@types/chai-as-promised": "8.0.2",
|
|
70
70
|
"@types/mocha": "10.0.10",
|
|
71
|
-
"@types/node": "
|
|
71
|
+
"@types/node": "26.1.0",
|
|
72
72
|
"@types/pg": "8.20.0",
|
|
73
73
|
"@types/pg-cursor": "2.7.2",
|
|
74
74
|
"@types/prototype-pollution-vulnerable-lodash.merge-dont-upgrade": "npm:@types/lodash.merge@4.6.1",
|
|
75
75
|
"@types/semver": "7.7.1",
|
|
76
|
-
"@types/sinon": "
|
|
77
|
-
"better-sqlite3": "12.
|
|
76
|
+
"@types/sinon": "22.0.0",
|
|
77
|
+
"better-sqlite3": "12.11.1",
|
|
78
78
|
"chai": "6.2.2",
|
|
79
79
|
"chai-as-promised": "8.0.2",
|
|
80
|
-
"esbuild": "0.28.
|
|
80
|
+
"esbuild": "0.28.1",
|
|
81
81
|
"jsr": "0.14.3",
|
|
82
|
-
"mocha": "11.7.
|
|
83
|
-
"mysql2": "3.22.
|
|
82
|
+
"mocha": "11.7.6",
|
|
83
|
+
"mysql2": "3.22.5",
|
|
84
84
|
"pathe": "2.0.3",
|
|
85
|
-
"pg": "8.
|
|
86
|
-
"pg-cursor": "2.
|
|
87
|
-
"playwright": "1.
|
|
88
|
-
"prettier": "3.
|
|
85
|
+
"pg": "8.22.0",
|
|
86
|
+
"pg-cursor": "2.21.0",
|
|
87
|
+
"playwright": "1.61.1",
|
|
88
|
+
"prettier": "3.9.4",
|
|
89
89
|
"prototype-pollution-vulnerable-lodash.merge-dont-upgrade": "npm:lodash.merge@4.6.1",
|
|
90
|
-
"remeda": "2.
|
|
91
|
-
"semver": "7.8.
|
|
90
|
+
"remeda": "2.39.0",
|
|
91
|
+
"semver": "7.8.5",
|
|
92
92
|
"sinon": "22.0.0",
|
|
93
93
|
"std-env": "4.1.0",
|
|
94
|
-
"tarn": "3.0
|
|
95
|
-
"tedious": "
|
|
94
|
+
"tarn": "3.1.0",
|
|
95
|
+
"tedious": "20.0.0",
|
|
96
96
|
"tsd": "0.33.0",
|
|
97
|
-
"tsx": "4.22.
|
|
97
|
+
"tsx": "4.22.4",
|
|
98
98
|
"typescript": "6.0.3"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|