kysely 0.29.8 → 0.29.9
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/pglite/pglite-driver.js +18 -6
- package/dist/driver/aborted-transaction-error.d.ts +1 -1
- package/dist/driver/aborted-transaction-error.js +2 -2
- package/dist/kysely.d.ts +48 -0
- package/dist/kysely.js +48 -0
- package/dist/migration/file-migration-provider.d.ts +66 -0
- package/dist/migration/file-migration-provider.js +10 -0
- package/dist/migration/migrator.d.ts +10 -0
- package/dist/migration/migrator.js +45 -7
- package/dist/plugin/with-schema/with-schema-transformer.js +11 -8
- package/dist/query-builder/json-path-builder.d.ts +5 -2
- package/dist/query-compiler/compiled-query.d.ts +72 -0
- package/dist/util/log-once.d.ts +5 -0
- package/dist/util/log-once.js +11 -0
- package/package.json +5 -5
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.9)
|
|
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,8 +1,9 @@
|
|
|
1
1
|
/// <reference types="./pglite-driver.d.ts" />
|
|
2
|
+
import { AbortedTransactionError } from '../../driver/aborted-transaction-error.js';
|
|
2
3
|
import { parseSavepointCommand } from '../../parser/savepoint-parser.js';
|
|
3
4
|
import { waitOrAbort, } from '../../util/abort.js';
|
|
4
5
|
import { Deferred } from '../../util/deferred.js';
|
|
5
|
-
import { freeze, isFunction } from '../../util/object-utils.js';
|
|
6
|
+
import { freeze, isFunction, isObject } from '../../util/object-utils.js';
|
|
6
7
|
import { createQueryId } from '../../util/query-id.js';
|
|
7
8
|
import { extendStackTrace } from '../../util/stack-trace-utils.js';
|
|
8
9
|
const PRIVATE_BEGIN_TRANSACTION_METHOD = Symbol();
|
|
@@ -102,11 +103,22 @@ class PGliteConnection {
|
|
|
102
103
|
}
|
|
103
104
|
async [PRIVATE_COMMIT_TRANSACTION_METHOD]() {
|
|
104
105
|
this.#commitTransaction?.();
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
try {
|
|
107
|
+
await this.#transactionClosedPromise;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
// https://github.com/electric-sql/pglite/blob/bac163ecc92e968adda68864b74b7e3d65a68e97/packages/pglite/src/errors.ts#L11-L17
|
|
111
|
+
if (isObject(error) && 'code' in error && error.code === '25P02') {
|
|
112
|
+
throw new AbortedTransactionError({ cause: error });
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
this.#commitTransaction = undefined;
|
|
118
|
+
this.#rollbackTransaction = undefined;
|
|
119
|
+
this.#transaction = undefined;
|
|
120
|
+
this.#transactionClosedPromise = undefined;
|
|
121
|
+
}
|
|
110
122
|
}
|
|
111
123
|
async [PRIVATE_ROLLBACK_TRANSACTION_METHOD]() {
|
|
112
124
|
this.#rollbackTransaction?.();
|
|
@@ -5,7 +5,7 @@ declare const ABORTED_TRANSACTION_ERROR: unique symbol;
|
|
|
5
5
|
export declare class AbortedTransactionError extends Error {
|
|
6
6
|
name: string;
|
|
7
7
|
readonly [ABORTED_TRANSACTION_ERROR] = true;
|
|
8
|
-
constructor();
|
|
8
|
+
constructor(options?: ErrorOptions);
|
|
9
9
|
}
|
|
10
10
|
export declare function isAbortedTransactionError(error: unknown): error is AbortedTransactionError;
|
|
11
11
|
export {};
|
|
@@ -7,8 +7,8 @@ const ABORTED_TRANSACTION_ERROR = Symbol.for('kysely.AbortedTransactionError');
|
|
|
7
7
|
export class AbortedTransactionError extends Error {
|
|
8
8
|
name = 'AbortedTransactionError';
|
|
9
9
|
[ABORTED_TRANSACTION_ERROR] = true;
|
|
10
|
-
constructor() {
|
|
11
|
-
super('Transaction was rolled back instead of committed');
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super('Transaction was rolled back instead of committed', options);
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
export function isAbortedTransactionError(error) {
|
package/dist/kysely.d.ts
CHANGED
|
@@ -477,6 +477,54 @@ export declare class Kysely<DB> extends QueryCreator<DB> implements QueryExecuto
|
|
|
477
477
|
/**
|
|
478
478
|
* Executes a given compiled query or query builder.
|
|
479
479
|
*
|
|
480
|
+
* Returns a {@link QueryResult} containing `rows` and any metadata provided
|
|
481
|
+
* by the dialect, such as `numAffectedRows` or `insertId`.
|
|
482
|
+
* Unlike a query builder's `execute`, this method doesn't wrap write metadata
|
|
483
|
+
* in an {@link InsertResult}, {@link UpdateResult} or {@link DeleteResult}.
|
|
484
|
+
* Without `returning` or `output`, a write normally has an empty `rows` array.
|
|
485
|
+
*
|
|
486
|
+
* ### Examples
|
|
487
|
+
*
|
|
488
|
+
* ```ts
|
|
489
|
+
* const query = db
|
|
490
|
+
* .selectFrom('person')
|
|
491
|
+
* .select(['id', 'first_name'])
|
|
492
|
+
* .where('id', '=', 123)
|
|
493
|
+
* .compile()
|
|
494
|
+
*
|
|
495
|
+
* const { rows } = await db.executeQuery(query)
|
|
496
|
+
* console.log(rows[0]?.first_name)
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* The generated SQL (PostgreSQL):
|
|
500
|
+
*
|
|
501
|
+
* ```sql
|
|
502
|
+
* select "id", "first_name"
|
|
503
|
+
* from "person"
|
|
504
|
+
* where "id" = $1
|
|
505
|
+
* ```
|
|
506
|
+
*
|
|
507
|
+
* Read metadata from a write query:
|
|
508
|
+
*
|
|
509
|
+
* ```ts
|
|
510
|
+
* const query = db
|
|
511
|
+
* .updateTable('person')
|
|
512
|
+
* .set({ first_name: 'Jennifer' })
|
|
513
|
+
* .where('id', '=', 123)
|
|
514
|
+
* .compile()
|
|
515
|
+
*
|
|
516
|
+
* const { numAffectedRows } = await db.executeQuery(query)
|
|
517
|
+
* console.log(numAffectedRows)
|
|
518
|
+
* ```
|
|
519
|
+
*
|
|
520
|
+
* The generated SQL (PostgreSQL):
|
|
521
|
+
*
|
|
522
|
+
* ```sql
|
|
523
|
+
* update "person"
|
|
524
|
+
* set "first_name" = $1
|
|
525
|
+
* where "id" = $2
|
|
526
|
+
* ```
|
|
527
|
+
*
|
|
480
528
|
* See {@link https://github.com/kysely-org/kysely/blob/master/site/docs/recipes/0004-splitting-query-building-and-execution.md#execute-compiled-queries splitting build, compile and execute code recipe} for more information.
|
|
481
529
|
*/
|
|
482
530
|
executeQuery<R>(query: CompiledQuery<R> | Compilable<R>, options?: AbortableQueryOptions): Promise<QueryResult<R>>;
|
package/dist/kysely.js
CHANGED
|
@@ -539,6 +539,54 @@ export class Kysely extends QueryCreator {
|
|
|
539
539
|
/**
|
|
540
540
|
* Executes a given compiled query or query builder.
|
|
541
541
|
*
|
|
542
|
+
* Returns a {@link QueryResult} containing `rows` and any metadata provided
|
|
543
|
+
* by the dialect, such as `numAffectedRows` or `insertId`.
|
|
544
|
+
* Unlike a query builder's `execute`, this method doesn't wrap write metadata
|
|
545
|
+
* in an {@link InsertResult}, {@link UpdateResult} or {@link DeleteResult}.
|
|
546
|
+
* Without `returning` or `output`, a write normally has an empty `rows` array.
|
|
547
|
+
*
|
|
548
|
+
* ### Examples
|
|
549
|
+
*
|
|
550
|
+
* ```ts
|
|
551
|
+
* const query = db
|
|
552
|
+
* .selectFrom('person')
|
|
553
|
+
* .select(['id', 'first_name'])
|
|
554
|
+
* .where('id', '=', 123)
|
|
555
|
+
* .compile()
|
|
556
|
+
*
|
|
557
|
+
* const { rows } = await db.executeQuery(query)
|
|
558
|
+
* console.log(rows[0]?.first_name)
|
|
559
|
+
* ```
|
|
560
|
+
*
|
|
561
|
+
* The generated SQL (PostgreSQL):
|
|
562
|
+
*
|
|
563
|
+
* ```sql
|
|
564
|
+
* select "id", "first_name"
|
|
565
|
+
* from "person"
|
|
566
|
+
* where "id" = $1
|
|
567
|
+
* ```
|
|
568
|
+
*
|
|
569
|
+
* Read metadata from a write query:
|
|
570
|
+
*
|
|
571
|
+
* ```ts
|
|
572
|
+
* const query = db
|
|
573
|
+
* .updateTable('person')
|
|
574
|
+
* .set({ first_name: 'Jennifer' })
|
|
575
|
+
* .where('id', '=', 123)
|
|
576
|
+
* .compile()
|
|
577
|
+
*
|
|
578
|
+
* const { numAffectedRows } = await db.executeQuery(query)
|
|
579
|
+
* console.log(numAffectedRows)
|
|
580
|
+
* ```
|
|
581
|
+
*
|
|
582
|
+
* The generated SQL (PostgreSQL):
|
|
583
|
+
*
|
|
584
|
+
* ```sql
|
|
585
|
+
* update "person"
|
|
586
|
+
* set "first_name" = $1
|
|
587
|
+
* where "id" = $2
|
|
588
|
+
* ```
|
|
589
|
+
*
|
|
542
590
|
* See {@link https://github.com/kysely-org/kysely/blob/master/site/docs/recipes/0004-splitting-query-building-and-execution.md#execute-compiled-queries splitting build, compile and execute code recipe} for more information.
|
|
543
591
|
*/
|
|
544
592
|
async executeQuery(query, options) {
|
|
@@ -2,11 +2,21 @@ import type { Migration, MigrationProvider } from './migrator.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Reads all migrations from a folder.
|
|
4
4
|
*
|
|
5
|
+
* Loads `.js`, `.ts`, `.mjs`, `.mts`, `.cjs` and `.cts` files, excluding
|
|
6
|
+
* TypeScript declaration files. Loading TypeScript requires a runtime or
|
|
7
|
+
* loader that supports it. Subdirectories are not scanned.
|
|
8
|
+
*
|
|
9
|
+
* A module must export an `up` function, either as a named export or as part
|
|
10
|
+
* of a default export object. The filename without its extension is used as
|
|
11
|
+
* the migration name. See {@link FileMigrationProviderProps.onFileIgnored}
|
|
12
|
+
* to report files that aren't loaded.
|
|
13
|
+
*
|
|
5
14
|
* ### Examples
|
|
6
15
|
*
|
|
7
16
|
* ```ts
|
|
8
17
|
* import { promises as fs } from 'node:fs'
|
|
9
18
|
* import path from 'node:path'
|
|
19
|
+
* import { FileMigrationProvider } from 'kysely/migration'
|
|
10
20
|
*
|
|
11
21
|
* new FileMigrationProvider({
|
|
12
22
|
* fs,
|
|
@@ -43,9 +53,65 @@ export interface FileMigrationProviderPath {
|
|
|
43
53
|
join(...path: string[]): string;
|
|
44
54
|
}
|
|
45
55
|
export interface FileMigrationProviderProps {
|
|
56
|
+
/**
|
|
57
|
+
* Provides the directory listing. For Node.js, use `promises` from `node:fs`.
|
|
58
|
+
*/
|
|
46
59
|
fs: FileMigrationProviderFS;
|
|
60
|
+
/**
|
|
61
|
+
* Overrides how migration modules are imported. Receives the joined file path
|
|
62
|
+
* and returns the module exports. Defaults to a dynamic `import`.
|
|
63
|
+
*
|
|
64
|
+
* ### Examples
|
|
65
|
+
*
|
|
66
|
+
* Use a file URL when importing absolute paths in Node.js:
|
|
67
|
+
*
|
|
68
|
+
* ```ts
|
|
69
|
+
* import { promises as fs } from 'node:fs'
|
|
70
|
+
* import path from 'node:path'
|
|
71
|
+
* import { pathToFileURL } from 'node:url'
|
|
72
|
+
* import { FileMigrationProvider } from 'kysely/migration'
|
|
73
|
+
*
|
|
74
|
+
* const provider = new FileMigrationProvider({
|
|
75
|
+
* fs,
|
|
76
|
+
* path,
|
|
77
|
+
* migrationFolder: path.resolve('migrations'),
|
|
78
|
+
* import: (filePath) => import(pathToFileURL(filePath).href),
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
47
82
|
import?(module: string): Promise<any>;
|
|
83
|
+
/**
|
|
84
|
+
* The path to the migration directory. Use an absolute path to avoid
|
|
85
|
+
* depending on the current working directory.
|
|
86
|
+
*/
|
|
48
87
|
migrationFolder: string;
|
|
88
|
+
/**
|
|
89
|
+
* Called when a directory entry is ignored.
|
|
90
|
+
*
|
|
91
|
+
* `Extension` means the filename doesn't have a supported extension.
|
|
92
|
+
* `NotMigration` means the imported module has no supported `up` export.
|
|
93
|
+
* Import errors are thrown instead of being reported through this callback.
|
|
94
|
+
*
|
|
95
|
+
* ### Examples
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* import { promises as fs } from 'node:fs'
|
|
99
|
+
* import path from 'node:path'
|
|
100
|
+
* import { FileMigrationProvider } from 'kysely/migration'
|
|
101
|
+
*
|
|
102
|
+
* const provider = new FileMigrationProvider({
|
|
103
|
+
* fs,
|
|
104
|
+
* path,
|
|
105
|
+
* migrationFolder: path.resolve('migrations'),
|
|
106
|
+
* onFileIgnored(fileName, reason) {
|
|
107
|
+
* console.log(`Ignored ${fileName}: ${reason}`)
|
|
108
|
+
* },
|
|
109
|
+
* })
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
49
112
|
onFileIgnored?(fileName: string, reason: 'Extension' | 'NotMigration'): void;
|
|
113
|
+
/**
|
|
114
|
+
* Provides path joining. For Node.js, use `node:path`.
|
|
115
|
+
*/
|
|
50
116
|
path: FileMigrationProviderPath;
|
|
51
117
|
}
|
|
@@ -3,11 +3,21 @@ import { isFunction, isObject } from '../util/object-utils.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Reads all migrations from a folder.
|
|
5
5
|
*
|
|
6
|
+
* Loads `.js`, `.ts`, `.mjs`, `.mts`, `.cjs` and `.cts` files, excluding
|
|
7
|
+
* TypeScript declaration files. Loading TypeScript requires a runtime or
|
|
8
|
+
* loader that supports it. Subdirectories are not scanned.
|
|
9
|
+
*
|
|
10
|
+
* A module must export an `up` function, either as a named export or as part
|
|
11
|
+
* of a default export object. The filename without its extension is used as
|
|
12
|
+
* the migration name. See {@link FileMigrationProviderProps.onFileIgnored}
|
|
13
|
+
* to report files that aren't loaded.
|
|
14
|
+
*
|
|
6
15
|
* ### Examples
|
|
7
16
|
*
|
|
8
17
|
* ```ts
|
|
9
18
|
* import { promises as fs } from 'node:fs'
|
|
10
19
|
* import path from 'node:path'
|
|
20
|
+
* import { FileMigrationProvider } from 'kysely/migration'
|
|
11
21
|
*
|
|
12
22
|
* new FileMigrationProvider({
|
|
13
23
|
* fs,
|
|
@@ -386,6 +386,16 @@ export interface MigrationInfo {
|
|
|
386
386
|
/**
|
|
387
387
|
* When was the migration executed.
|
|
388
388
|
*
|
|
389
|
+
* In most cases, this is the time on the machine running the migrator when
|
|
390
|
+
* the migration was applied (as reported by `Date.now()`), not the database
|
|
391
|
+
* server's time.
|
|
392
|
+
* Execution timestamps are used to determine the order in which migrations
|
|
393
|
+
* were executed, so they never go backwards. If the machine clock is behind
|
|
394
|
+
* the latest recorded execution timestamp (e.g. it was stepped back by an NTP
|
|
395
|
+
* sync, it drifted from the clock of another machine running migrations, or
|
|
396
|
+
* it was ahead when a previous migration was applied), the migration is
|
|
397
|
+
* recorded 1 millisecond after the latest recorded execution timestamp instead.
|
|
398
|
+
*
|
|
389
399
|
* If this is undefined, the migration hasn't been executed yet.
|
|
390
400
|
*/
|
|
391
401
|
executedAt?: Date;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/// <reference types="./migrator.d.ts" />
|
|
2
2
|
import { NoopPlugin } from '../plugin/noop-plugin.js';
|
|
3
3
|
import { WithSchemaPlugin } from '../plugin/with-schema/with-schema-plugin.js';
|
|
4
|
+
import { warnOnce } from '../util/log-once.js';
|
|
4
5
|
import { freeze, getLast, isObject } from '../util/object-utils.js';
|
|
5
6
|
export const DEFAULT_MIGRATION_TABLE = 'kysely_migration';
|
|
6
7
|
export const DEFAULT_MIGRATION_LOCK_TABLE = 'kysely_migration_lock';
|
|
7
8
|
export const DEFAULT_ALLOW_UNORDERED_MIGRATIONS = false;
|
|
8
9
|
export const MIGRATION_LOCK_ID = 'migration_lock';
|
|
9
10
|
export const NO_MIGRATIONS = freeze({ __noMigrations__: true });
|
|
11
|
+
const CLOCK_BEHIND_WARNING_THRESHOLD_MILLISECONDS = 1_000;
|
|
10
12
|
/**
|
|
11
13
|
* A class for running migrations.
|
|
12
14
|
*
|
|
@@ -448,7 +450,7 @@ export class Migrator {
|
|
|
448
450
|
}
|
|
449
451
|
async #getState(db) {
|
|
450
452
|
const migrations = await this.#resolveMigrations();
|
|
451
|
-
const executedMigrations = await this.#getExecutedMigrations(db);
|
|
453
|
+
const { executedMigrations, maxExecutedAt } = await this.#getExecutedMigrations(db);
|
|
452
454
|
this.#ensureNoMissingMigrations(migrations, executedMigrations);
|
|
453
455
|
if (!this.#allowUnorderedMigrations) {
|
|
454
456
|
this.#ensureMigrationsInOrder(migrations, executedMigrations);
|
|
@@ -458,6 +460,7 @@ export class Migrator {
|
|
|
458
460
|
migrations,
|
|
459
461
|
executedMigrations,
|
|
460
462
|
lastMigration: getLast(executedMigrations),
|
|
463
|
+
maxExecutedAt,
|
|
461
464
|
pendingMigrations,
|
|
462
465
|
});
|
|
463
466
|
}
|
|
@@ -476,22 +479,44 @@ export class Migrator {
|
|
|
476
479
|
}));
|
|
477
480
|
}
|
|
478
481
|
async #getExecutedMigrations(db) {
|
|
479
|
-
const
|
|
482
|
+
const rows = await db
|
|
480
483
|
.withPlugin(this.#schemaPlugin)
|
|
481
484
|
.selectFrom(this.#migrationTable)
|
|
482
485
|
.select(['name', 'timestamp'])
|
|
483
486
|
.$narrowType()
|
|
484
487
|
.execute();
|
|
488
|
+
if (rows.length === 0) {
|
|
489
|
+
return { executedMigrations: [], maxExecutedAt: 0 };
|
|
490
|
+
}
|
|
491
|
+
if (rows.length === 1) {
|
|
492
|
+
const [{ name, timestamp }] = rows;
|
|
493
|
+
return {
|
|
494
|
+
executedMigrations: [name],
|
|
495
|
+
maxExecutedAt: this.#getExecutedAt(name, timestamp),
|
|
496
|
+
};
|
|
497
|
+
}
|
|
485
498
|
const nameComparator = this.#props.nameComparator || ((a, b) => a.localeCompare(b));
|
|
486
|
-
|
|
499
|
+
let maxExecutedAt = 0;
|
|
500
|
+
const executedMigrations = rows
|
|
487
501
|
// https://github.com/kysely-org/kysely/issues/843
|
|
488
502
|
.sort((a, b) => {
|
|
489
|
-
|
|
503
|
+
const aExecutedAt = this.#getExecutedAt(a.name, a.timestamp);
|
|
504
|
+
const bExecutedAt = this.#getExecutedAt(b.name, b.timestamp);
|
|
505
|
+
maxExecutedAt = Math.max(maxExecutedAt, aExecutedAt, bExecutedAt);
|
|
506
|
+
if (aExecutedAt === bExecutedAt) {
|
|
490
507
|
return nameComparator(a.name, b.name);
|
|
491
508
|
}
|
|
492
|
-
return
|
|
509
|
+
return aExecutedAt - bExecutedAt;
|
|
493
510
|
})
|
|
494
|
-
.map((it) => it.name)
|
|
511
|
+
.map((it) => it.name);
|
|
512
|
+
return { executedMigrations, maxExecutedAt };
|
|
513
|
+
}
|
|
514
|
+
#getExecutedAt(name, timestamp) {
|
|
515
|
+
const executedAt = new Date(timestamp).getTime();
|
|
516
|
+
if (Number.isNaN(executedAt)) {
|
|
517
|
+
throw new Error(`corrupted migrations: previously executed migration ${name} has an invalid timestamp ${timestamp}`);
|
|
518
|
+
}
|
|
519
|
+
return executedAt;
|
|
495
520
|
}
|
|
496
521
|
#ensureNoMissingMigrations(migrations, executedMigrations) {
|
|
497
522
|
// Ensure all executed migrations exist in the `migrations` list.
|
|
@@ -563,16 +588,18 @@ export class Migrator {
|
|
|
563
588
|
status: 'NotExecuted',
|
|
564
589
|
};
|
|
565
590
|
});
|
|
591
|
+
let { maxExecutedAt } = state;
|
|
566
592
|
for (let i = 0; i < results.length; i++) {
|
|
567
593
|
const migration = state.pendingMigrations[i];
|
|
568
594
|
try {
|
|
569
595
|
await migration.up(db);
|
|
596
|
+
maxExecutedAt = this.#getNextExecutedAt(maxExecutedAt);
|
|
570
597
|
await db
|
|
571
598
|
.withPlugin(this.#schemaPlugin)
|
|
572
599
|
.insertInto(this.#migrationTable)
|
|
573
600
|
.values({
|
|
574
601
|
name: migration.name,
|
|
575
|
-
timestamp: new Date().toISOString(),
|
|
602
|
+
timestamp: new Date(maxExecutedAt).toISOString(),
|
|
576
603
|
})
|
|
577
604
|
.execute();
|
|
578
605
|
results[i] = {
|
|
@@ -601,6 +628,17 @@ export class Migrator {
|
|
|
601
628
|
}
|
|
602
629
|
await qb.execute();
|
|
603
630
|
}
|
|
631
|
+
// https://github.com/kysely-org/kysely/issues/2244
|
|
632
|
+
#getNextExecutedAt(maxExecutedAt) {
|
|
633
|
+
const now = Date.now();
|
|
634
|
+
if (now > maxExecutedAt) {
|
|
635
|
+
return now;
|
|
636
|
+
}
|
|
637
|
+
if (maxExecutedAt - now >= CLOCK_BEHIND_WARNING_THRESHOLD_MILLISECONDS) {
|
|
638
|
+
warnOnce('The machine clock is behind the latest migration `executedAt`. Recording migrations 1 millisecond after it instead.');
|
|
639
|
+
}
|
|
640
|
+
return maxExecutedAt + 1;
|
|
641
|
+
}
|
|
604
642
|
}
|
|
605
643
|
class MigrationResultSetError extends Error {
|
|
606
644
|
#resultSet;
|
|
@@ -78,10 +78,7 @@ export class WithSchemaTransformer extends OperationNodeTransformer {
|
|
|
78
78
|
return {
|
|
79
79
|
...super.transformSelectModifier({ ...node, of: undefined }, queryId),
|
|
80
80
|
of: node.of?.map((item) => TableNode.is(item) && !item.table.schema
|
|
81
|
-
?
|
|
82
|
-
...item,
|
|
83
|
-
table: this.transformIdentifier(item.table.identifier, queryId),
|
|
84
|
-
}
|
|
81
|
+
? this.#transformTableWithoutSchema(item, queryId)
|
|
85
82
|
: this.transformNode(item, queryId)),
|
|
86
83
|
};
|
|
87
84
|
}
|
|
@@ -89,12 +86,18 @@ export class WithSchemaTransformer extends OperationNodeTransformer {
|
|
|
89
86
|
return SCHEMALESS_FUNCTIONS[node.func]
|
|
90
87
|
? node[argsKey].map((arg) => !TableNode.is(arg) || arg.table.schema
|
|
91
88
|
? this.transformNode(arg, queryId)
|
|
92
|
-
:
|
|
93
|
-
...arg,
|
|
94
|
-
table: this.transformIdentifier(arg.table.identifier, queryId),
|
|
95
|
-
})
|
|
89
|
+
: this.#transformTableWithoutSchema(arg, queryId))
|
|
96
90
|
: this.transformNodeList(node[argsKey], queryId);
|
|
97
91
|
}
|
|
92
|
+
#transformTableWithoutSchema(node, queryId) {
|
|
93
|
+
return {
|
|
94
|
+
...node,
|
|
95
|
+
table: {
|
|
96
|
+
...node.table,
|
|
97
|
+
identifier: this.transformIdentifier(node.table.identifier, queryId),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
98
101
|
#collectSchemableIds(node) {
|
|
99
102
|
const schemableIds = new Set();
|
|
100
103
|
if ('name' in node && node.name && SchemableIdentifierNode.is(node.name)) {
|
|
@@ -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)
|
|
76
|
+
at<I extends (any[] extends O ? number | 'last' | `#-${number}` : never)>(index: `${I}` extends `${any}.${any}` | `#--${any}` ? never : I): TraversedJSONPathBuilder<S, JSONArrayElementType<O>>;
|
|
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)
|
|
126
|
+
key<K extends (any[] extends O ? never : O extends object ? keyof NonNullable<O> & string : never)>(key: K): TraversedJSONPathBuilder<S, JSONObjectValueType<O, K>>;
|
|
127
127
|
}
|
|
128
128
|
export declare class TraversedJSONPathBuilder<S, O> extends JSONPathBuilder<S, O> implements AliasableExpression<O> {
|
|
129
129
|
#private;
|
|
@@ -292,3 +292,6 @@ export declare class AliasedJSONPathBuilder<O, A extends string> implements Alia
|
|
|
292
292
|
*/
|
|
293
293
|
toOperationNode(): AliasNode;
|
|
294
294
|
}
|
|
295
|
+
type JSONArrayElementType<O> = null | NonNullable<NonNullable<O>[keyof NonNullable<O> & number]>;
|
|
296
|
+
type JSONObjectValueType<O, K extends keyof NonNullable<O>> = 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];
|
|
297
|
+
export {};
|
|
@@ -1,13 +1,85 @@
|
|
|
1
1
|
import { type RootOperationNode } from '../operation-node/root-operation-node.js';
|
|
2
2
|
import { type QueryId } from '../util/query-id.js';
|
|
3
|
+
/**
|
|
4
|
+
* A SQL query compiled for a specific dialect, together with its parameters
|
|
5
|
+
* and operation node tree.
|
|
6
|
+
*
|
|
7
|
+
* The output type `O` describes a result row. It doesn't validate or convert
|
|
8
|
+
* values returned by the database driver.
|
|
9
|
+
*
|
|
10
|
+
* Query builders create compiled queries with {@link Compilable.compile | compile()},
|
|
11
|
+
* and {@link RawBuilder}s with `compile(db)`. Compiling doesn't execute the query.
|
|
12
|
+
*
|
|
13
|
+
* See {@link Kysely.executeQuery} for execution and {@link CompiledQuery.raw}
|
|
14
|
+
* for constructing a query from an existing SQL string.
|
|
15
|
+
*
|
|
16
|
+
* ### Examples
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const compiledQuery = db
|
|
20
|
+
* .selectFrom('person')
|
|
21
|
+
* .select('first_name')
|
|
22
|
+
* .where('id', '=', 123)
|
|
23
|
+
* .compile()
|
|
24
|
+
*
|
|
25
|
+
* console.log(compiledQuery.sql) // select "first_name" from "person" where "id" = $1
|
|
26
|
+
* console.log(compiledQuery.parameters) // [123]
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
3
29
|
export interface CompiledQuery<O = unknown> {
|
|
30
|
+
/**
|
|
31
|
+
* The operation node tree used to compile the query, after query plugins have run.
|
|
32
|
+
*/
|
|
4
33
|
readonly query: RootOperationNode;
|
|
34
|
+
/**
|
|
35
|
+
* Identifies the query when passing data between plugin hooks.
|
|
36
|
+
*/
|
|
5
37
|
readonly queryId: QueryId;
|
|
38
|
+
/**
|
|
39
|
+
* The SQL string, with placeholders in the target dialect's syntax.
|
|
40
|
+
*/
|
|
6
41
|
readonly sql: string;
|
|
42
|
+
/**
|
|
43
|
+
* The parameter values in the order expected by the placeholders in {@link CompiledQuery.sql | sql}.
|
|
44
|
+
*/
|
|
7
45
|
readonly parameters: ReadonlyArray<unknown>;
|
|
8
46
|
}
|
|
9
47
|
export declare function isCompiledQuery<R>(thing: unknown): thing is CompiledQuery<R>;
|
|
10
48
|
type CompiledQueryFactory = Readonly<{
|
|
49
|
+
/**
|
|
50
|
+
* Creates a compiled query from an existing SQL string and parameter values.
|
|
51
|
+
*
|
|
52
|
+
* The SQL is used as provided. This method doesn't escape SQL, generate
|
|
53
|
+
* placeholders, or check that the parameters match the placeholders.
|
|
54
|
+
* Use the target dialect's placeholder syntax, such as `$1` for PostgreSQL
|
|
55
|
+
* or `?` for MySQL and SQLite. For SQL built from interpolated values,
|
|
56
|
+
* prefer the {@link sql} template tag.
|
|
57
|
+
*
|
|
58
|
+
* ### Examples
|
|
59
|
+
*
|
|
60
|
+
* Execute a parameterized PostgreSQL query:
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { CompiledQuery } from 'kysely'
|
|
64
|
+
*
|
|
65
|
+
* const result = await db.executeQuery<{ first_name: string }>(
|
|
66
|
+
* CompiledQuery.raw(
|
|
67
|
+
* 'select "first_name" from "person" where "id" = $1',
|
|
68
|
+
* [123],
|
|
69
|
+
* ),
|
|
70
|
+
* )
|
|
71
|
+
*
|
|
72
|
+
* const firstName: string | undefined = result.rows[0]?.first_name
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* The generated SQL (PostgreSQL):
|
|
76
|
+
*
|
|
77
|
+
* ```sql
|
|
78
|
+
* select "first_name"
|
|
79
|
+
* from "person"
|
|
80
|
+
* where "id" = $1
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
11
83
|
raw(sql: string, parameters?: unknown[]): Readonly<CompiledQuery>;
|
|
12
84
|
}>;
|
|
13
85
|
export declare const CompiledQuery: CompiledQueryFactory;
|
package/dist/util/log-once.d.ts
CHANGED
|
@@ -3,3 +3,8 @@
|
|
|
3
3
|
* Logs a message and ensures it won't be logged again.
|
|
4
4
|
*/
|
|
5
5
|
export declare function logOnce(message: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Use for system-level warnings.
|
|
8
|
+
* Logs a warning and ensures it won't be logged again.
|
|
9
|
+
*/
|
|
10
|
+
export declare function warnOnce(message: string): void;
|
package/dist/util/log-once.js
CHANGED
|
@@ -11,3 +11,14 @@ export function logOnce(message) {
|
|
|
11
11
|
LOGGED_MESSAGES.add(message);
|
|
12
12
|
console.log(message);
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Use for system-level warnings.
|
|
16
|
+
* Logs a warning and ensures it won't be logged again.
|
|
17
|
+
*/
|
|
18
|
+
export function warnOnce(message) {
|
|
19
|
+
if (LOGGED_MESSAGES.has(message)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
LOGGED_MESSAGES.add(message);
|
|
23
|
+
console.warn(message);
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kysely",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.9",
|
|
4
4
|
"description": "Type safe SQL query builder",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
],
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@arethetypeswrong/cli": "0.18.5",
|
|
65
|
-
"@electric-sql/pglite": "0.5.
|
|
65
|
+
"@electric-sql/pglite": "0.5.16",
|
|
66
66
|
"@types/better-sqlite3": "9.6.0",
|
|
67
67
|
"@types/chai": "5.2.3",
|
|
68
68
|
"@types/chai-as-promised": "8.0.2",
|
|
@@ -83,11 +83,11 @@
|
|
|
83
83
|
"pathe": "2.0.3",
|
|
84
84
|
"pg": "8.23.1",
|
|
85
85
|
"pg-cursor": "2.22.1",
|
|
86
|
-
"playwright": "1.
|
|
86
|
+
"playwright": "1.65.0",
|
|
87
87
|
"prettier": "3.9.10",
|
|
88
88
|
"prototype-pollution-vulnerable-lodash.merge-dont-upgrade": "npm:lodash.merge@4.6.1",
|
|
89
|
-
"remeda": "2.
|
|
90
|
-
"semver": "7.8.
|
|
89
|
+
"remeda": "2.59.0",
|
|
90
|
+
"semver": "7.8.6",
|
|
91
91
|
"sinon": "22.1.0",
|
|
92
92
|
"tarn": "3.1.2",
|
|
93
93
|
"tedious": "20.3.8",
|