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 CHANGED
@@ -1,7 +1,7 @@
1
1
  [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua)
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/kysely?style=flat&label=latest)](https://github.com/kysely-org/kysely/releases/latest)
4
- [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.29.2)](https://socket.dev/npm/package/kysely/overview/0.29.2)
4
+ [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.29.3)](https://socket.dev/npm/package/kysely/overview/0.29.3)
5
5
  [![Tests](https://github.com/kysely-org/kysely/actions/workflows/test.yml/badge.svg)](https://github.com/kysely-org/kysely)
6
6
  [![License](https://img.shields.io/github/license/kysely-org/kysely?style=flat)](https://github.com/kysely-org/kysely/blob/master/LICENSE)
7
7
  [![Issues](https://img.shields.io/github/issues-closed/kysely-org/kysely?logo=github)](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>): Promise<void>;
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 transaction-level exclusive lock on the migrations table.
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('dbo')}, @Resource = ${sql.lit(DEFAULT_MIGRATION_TABLE)}, @LockMode = ${sql.lit('Exclusive')}`.execute(db);
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
- // Nothing to do here. `sp_getapplock` is automatically released at the
22
- // end of the transaction and since `supportsTransactionalDdl` true, we know
23
- // the `db` instance passed to acquireMigrationLock is actually a transaction.
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?: (config: object) => MysqlConnection;
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: Array<unknown>): {
48
- stream: <T>(options: MysqlStreamOptions) => MysqlStream<T>;
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<T> {
62
- [Symbol.asyncIterator](): AsyncIterableIterator<T>;
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(_db: Kysely<any>, _opt: MigrationLockOptions): Promise<void>;
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
- // Acquire a transaction level advisory lock.
15
- await sql `select pg_advisory_xact_lock(${sql.lit(LOCK_ID)})`.execute(db);
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(_db, _opt) {
18
- // Nothing to do here. `pg_advisory_xact_lock` is automatically released at the
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
- const state = await this.#getState(db);
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 run(this.#props.db);
440
+ return runWithLock(this.#props.db, run);
438
441
  }
439
442
  if (adapter.supportsTransactionalDdl && !disableTransactions) {
440
- return this.#props.db.transaction().execute(run);
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.2",
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.2",
65
- "@ark/attest": "0.56.0",
66
- "@electric-sql/pglite": "0.4.5",
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": "25.8.0",
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": "21.0.1",
77
- "better-sqlite3": "12.10.0",
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.0",
80
+ "esbuild": "0.28.1",
81
81
  "jsr": "0.14.3",
82
- "mocha": "11.7.5",
83
- "mysql2": "3.22.3",
82
+ "mocha": "11.7.6",
83
+ "mysql2": "3.22.5",
84
84
  "pathe": "2.0.3",
85
- "pg": "8.20.0",
86
- "pg-cursor": "2.19.0",
87
- "playwright": "1.60.0",
88
- "prettier": "3.8.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.34.1",
91
- "semver": "7.8.0",
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.2",
95
- "tedious": "19.2.1",
94
+ "tarn": "3.1.0",
95
+ "tedious": "20.0.0",
96
96
  "tsd": "0.33.0",
97
- "tsx": "4.22.0",
97
+ "tsx": "4.22.4",
98
98
  "typescript": "6.0.3"
99
99
  },
100
100
  "scripts": {