kysely 0.29.4 → 0.30.0-beta.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/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.4)](https://socket.dev/npm/package/kysely/overview/0.29.4)
4
+ [![Socket Badge](https://badge.socket.dev/npm/package/kysely/0.30.0-beta.0)](https://socket.dev/npm/package/kysely/overview/0.30.0-beta.0)
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,7 +1,14 @@
1
1
  import type { Expression } from '../expression/expression.js';
2
2
  import type { SelectQueryBuilderExpression } from '../query-builder/select-query-builder-expression.js';
3
3
  import type { RawBuilder } from '../raw-builder/raw-builder.js';
4
- import type { ShallowDehydrateObject, ShallowDehydrateValue, Simplify } from '../util/type-utils.js';
4
+ import type { KyselyTypeError } from '../util/type-error.js';
5
+ import type { IsNever, ShallowDehydrateObject, ShallowDehydrateValue, Simplify } from '../util/type-utils.js';
6
+ /**
7
+ * Used to check for `BLOB` column existence in result records.
8
+ */
9
+ export type ExtractBlobs<O> = {
10
+ [K in keyof O]: O[K] extends Expression<infer V> ? Extract<V, Uint8Array> : Extract<O[K], Uint8Array>;
11
+ }[keyof O];
5
12
  /**
6
13
  * A SQLite helper for aggregating a subquery into a JSON array.
7
14
  *
@@ -63,7 +70,7 @@ import type { ShallowDehydrateObject, ShallowDehydrateValue, Simplify } from '..
63
70
  * from "person"
64
71
  * ```
65
72
  */
66
- export declare function jsonArrayFrom<O>(expr: SelectQueryBuilderExpression<O>): RawBuilder<Simplify<ShallowDehydrateObject<O>>[]>;
73
+ export declare function jsonArrayFrom<O>(expr: IsNever<ExtractBlobs<O>> extends true ? SelectQueryBuilderExpression<O> : KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>): RawBuilder<Simplify<ShallowDehydrateObject<O>>[]>;
67
74
  /**
68
75
  * A SQLite helper for turning a subquery into a JSON object.
69
76
  *
@@ -127,7 +134,7 @@ export declare function jsonArrayFrom<O>(expr: SelectQueryBuilderExpression<O>):
127
134
  * from "person";
128
135
  * ```
129
136
  */
130
- export declare function jsonObjectFrom<O>(expr: SelectQueryBuilderExpression<O>): RawBuilder<Simplify<ShallowDehydrateObject<O>> | null>;
137
+ export declare function jsonObjectFrom<O>(expr: IsNever<ExtractBlobs<O>> extends true ? SelectQueryBuilderExpression<O> : KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>): RawBuilder<Simplify<ShallowDehydrateObject<O>> | null>;
131
138
  /**
132
139
  * The SQLite `json_object` function.
133
140
  *
@@ -184,6 +191,6 @@ export declare function jsonObjectFrom<O>(expr: SelectQueryBuilderExpression<O>)
184
191
  * from "person"
185
192
  * ```
186
193
  */
187
- export declare function jsonBuildObject<O extends Record<string, Expression<unknown>>>(obj: O): RawBuilder<Simplify<{
194
+ export declare function jsonBuildObject<O extends Record<string, Expression<unknown>>>(obj: IsNever<ExtractBlobs<O>> extends true ? O : KyselyTypeError<'SQLite does not support passing `BLOB` values to `json_object`. Cast to `TEXT`.'>): RawBuilder<Simplify<{
188
195
  [K in keyof O]: O[K] extends Expression<infer V> ? ShallowDehydrateValue<V> : never;
189
196
  }>>;
@@ -188,7 +188,10 @@ export function jsonObjectFrom(expr) {
188
188
  * ```
189
189
  */
190
190
  export function jsonBuildObject(obj) {
191
- return sql `json_object(${sql.join(Object.keys(obj).flatMap((k) => [sql.lit(k), obj[k]]))})`;
191
+ return sql `json_object(${sql.join(Object.keys(obj).flatMap((k) => [
192
+ sql.lit(k),
193
+ obj[k],
194
+ ]))})`;
192
195
  }
193
196
  function getSqliteJsonObjectArgs(node, table) {
194
197
  try {
@@ -1,4 +1,5 @@
1
- import type { Migration, MigrationProvider } from './migrator.js';
1
+ import type { Migration } from './migration.js';
2
+ import type { MigrationProvider } from './migrator.js';
2
3
  /**
3
4
  * Reads all migrations from a folder.
4
5
  *
@@ -1,2 +1,3 @@
1
1
  export * from './file-migration-provider.js';
2
+ export * from './migration.js';
2
3
  export * from './migrator.js';
@@ -1,3 +1,4 @@
1
1
  /// <reference types="./index.d.ts" />
2
2
  export * from './file-migration-provider.js';
3
+ export * from './migration.js';
3
4
  export * from './migrator.js';
@@ -0,0 +1,70 @@
1
+ import type { Kysely } from '../kysely.js';
2
+ /**
3
+ * The shape of a migration's module.
4
+ */
5
+ export interface Migration {
6
+ /**
7
+ * Configuration object for this migration module.
8
+ *
9
+ * See {@link MigrationConfig}.
10
+ */
11
+ config?: MigrationConfig;
12
+ /**
13
+ * The `down` method that reverts the changes made by it's sibling {@link Migration.up}
14
+ * method.
15
+ */
16
+ down?(db: Kysely<any>): Promise<void>;
17
+ /**
18
+ * The `up` method that changes the database schema.
19
+ *
20
+ * See {@link Migration.down}.
21
+ */
22
+ up(db: Kysely<any>): Promise<void>;
23
+ }
24
+ /**
25
+ * Configuration for a single migration.
26
+ */
27
+ export interface MigrationConfig {
28
+ /**
29
+ * Controls whether this migration runs inside its own transaction, when
30
+ * {@link MigrateOptions.transactionMode} is `'per-migration'` — the only
31
+ * mode that honors this property. Defaults to `true` in that mode: the
32
+ * migration runs in its own transaction unless this is set to `false`.
33
+ *
34
+ * In any other transaction mode, leaving this property out is the only
35
+ * valid state — providing a value, either one, results in an error: in
36
+ * `'per-run'` mode a single shared transaction cannot partially exclude a
37
+ * migration, and in `'none'` mode there are no transactions to configure.
38
+ * This is the one place an explicit `true` differs from the default —
39
+ * `true` asserts a requirement that non-`'per-migration'` modes refuse,
40
+ * while leaving the property out never errors.
41
+ *
42
+ * Setting `false` makes the migration run without a transaction. This is
43
+ * required for statements that cannot run inside a transaction, such as
44
+ * PostgreSQL's `CREATE INDEX CONCURRENTLY`. Note that without a
45
+ * transaction, a failure can leave the migration partially applied, and the
46
+ * migration table record is written separately after the migration
47
+ * completes. Prefer a single statement per non-transactional migration, and
48
+ * write it so it can be safely retried — for example, drop a
49
+ * possibly-leftover invalid index before creating it.
50
+ */
51
+ readonly transaction?: boolean;
52
+ }
53
+ /**
54
+ * Helps define a single migration by taking over types duties and enforcing the contract.
55
+ *
56
+ * ### Examples
57
+ *
58
+ * ```ts
59
+ * import { defineMigration } from 'kysely/migration'
60
+ *
61
+ * export default defineMigration({
62
+ * async up(db) {
63
+ * // ...
64
+ * },
65
+ *
66
+ * config: { transaction: false },
67
+ * })
68
+ * ```
69
+ */
70
+ export declare function defineMigration(migration: Migration): Migration;
@@ -0,0 +1,21 @@
1
+ /// <reference types="./migration.d.ts" />
2
+ /**
3
+ * Helps define a single migration by taking over types duties and enforcing the contract.
4
+ *
5
+ * ### Examples
6
+ *
7
+ * ```ts
8
+ * import { defineMigration } from 'kysely/migration'
9
+ *
10
+ * export default defineMigration({
11
+ * async up(db) {
12
+ * // ...
13
+ * },
14
+ *
15
+ * config: { transaction: false },
16
+ * })
17
+ * ```
18
+ */
19
+ export function defineMigration(migration) {
20
+ return migration;
21
+ }
@@ -1,19 +1,10 @@
1
1
  import type { Kysely } from '../kysely.js';
2
+ import type { Migration } from './migration.js';
2
3
  export declare const DEFAULT_MIGRATION_TABLE = "kysely_migration";
3
4
  export declare const DEFAULT_MIGRATION_LOCK_TABLE = "kysely_migration_lock";
4
5
  export declare const DEFAULT_ALLOW_UNORDERED_MIGRATIONS = false;
5
6
  export declare const MIGRATION_LOCK_ID = "migration_lock";
6
7
  export declare const NO_MIGRATIONS: NoMigrations;
7
- export interface Migration {
8
- up(db: Kysely<any>): Promise<void>;
9
- /**
10
- * An optional down method.
11
- *
12
- * If you don't provide a down method, the migration is skipped when
13
- * migrating down.
14
- */
15
- down?(db: Kysely<any>): Promise<void>;
16
- }
17
8
  /**
18
9
  * A class for running migrations.
19
10
  *
@@ -221,10 +212,51 @@ export interface MigrateOptions {
221
212
  *
222
213
  * Default is `false`.
223
214
  *
224
- * This is useful when some migrations include queries that would fail otherwise.
215
+ * @deprecated Use {@link transactionMode} instead — `disableTransactions: true`
216
+ * is equivalent to `transactionMode: 'none'`. Setting both to contradicting
217
+ * values results in an error.
225
218
  */
226
219
  readonly disableTransactions?: boolean;
220
+ /**
221
+ * Controls how migrations are wrapped in transactions, when the dialect
222
+ * supports transactional DDL ({@link DialectAdapter.supportsTransactionalDdl}).
223
+ *
224
+ * - `'per-run'` — the entire migration run is wrapped in a single transaction.
225
+ * Either every migration in the run is applied, or none are. Any migration
226
+ * with a per-migration `transaction` configuration ({@link MigrationConfig.transaction})
227
+ * results in an error, since a single shared transaction cannot partially
228
+ * exclude a migration. Requires transactional DDL — results in an error on
229
+ * dialects without it (e.g. MySQL).
230
+ *
231
+ * - `'per-migration'` — each migration runs in its own transaction, together
232
+ * with the insertion/deletion of its migration table record. A failure rolls
233
+ * back only the failing migration; previously completed migrations stay
234
+ * applied. Individual migrations can opt out of their transaction with
235
+ * `config: { transaction: false }` — required for statements that cannot
236
+ * run inside a transaction, such as PostgreSQL's `CREATE INDEX CONCURRENTLY`
237
+ * or `ALTER TYPE ... ADD VALUE` (pre-12). Requires transactional DDL —
238
+ * results in an error on dialects without it.
239
+ *
240
+ * - `'none'` — migrations run without any transactions. Any migration with a
241
+ * per-migration `transaction` configuration results in an error.
242
+ *
243
+ * When not provided, the current default is `'per-run'` on dialects that
244
+ * support transactional DDL and `'none'` on dialects that don't. This
245
+ * default might change to `'per-migration'` in a future version of Kysely —
246
+ * running multiple migrations without an explicit `transactionMode` logs a
247
+ * message about this. Provide an explicit `transactionMode` to make the
248
+ * migrator's behavior independent of the default.
249
+ *
250
+ * Note that transactions spanning multiple migrations (`'per-run'`) can make
251
+ * otherwise-valid migration sequences fail. For example, a new PostgreSQL enum
252
+ * value cannot be used in the same transaction that added it, so a migration
253
+ * that runs `ALTER TYPE ... ADD VALUE` followed by a migration that uses the
254
+ * new value works when the two run in separate transactions, but fails when
255
+ * both are pending in a single `'per-run'` mode run.
256
+ */
257
+ readonly transactionMode?: MigratorTransactionMode;
227
258
  }
259
+ export type MigratorTransactionMode = 'per-run' | 'per-migration' | 'none';
228
260
  export interface MigratorProps extends MigrateOptions {
229
261
  readonly db: Kysely<any>;
230
262
  readonly provider: MigrationProvider;
@@ -1,7 +1,8 @@
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 { freeze, getLast, isObject } from '../util/object-utils.js';
4
+ import { logOnce } from '../util/log-once.js';
5
+ import { freeze, 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;
@@ -403,6 +404,7 @@ export class Migrator {
403
404
  lockRowId: MIGRATION_LOCK_ID,
404
405
  lockTableSchema: this.#props.migrationTableSchema,
405
406
  });
407
+ const transactionMode = this.#resolveTransactionMode(options, adapter);
406
408
  const run = async (db) => {
407
409
  const state = await this.#getState(db);
408
410
  if (state.migrations.length === 0) {
@@ -412,13 +414,34 @@ export class Migrator {
412
414
  if (step <= 0) {
413
415
  return { results: [] };
414
416
  }
415
- if (direction === 'Down') {
416
- return await this.#migrateDown(db, state, step);
417
+ const migrationsToRun = this.#getMigrationsToRun(state, direction, step);
418
+ const [orchestrator, runner] = direction === 'Down'
419
+ ? [
420
+ this.#rollbackMigrations.bind(this),
421
+ this.#rollbackMigration.bind(this),
422
+ ]
423
+ : [this.#applyMigrations.bind(this), this.#applyMigration.bind(this)];
424
+ if (transactionMode.value === 'per-migration') {
425
+ return await orchestrator(migrationsToRun, async (migration) => {
426
+ if (migration.config?.transaction === false) {
427
+ return await runner(db, migration);
428
+ }
429
+ await db.transaction().execute((trx) => runner(trx, migration));
430
+ });
431
+ }
432
+ const migrationWithTransactionConfig = migrationsToRun.find((migration) => migration.config?.transaction != null);
433
+ if (migrationWithTransactionConfig) {
434
+ const modeDescription = transactionMode.explicit
435
+ ? `\`transactionMode\` is '${transactionMode.value}'`
436
+ : `\`transactionMode\` was not provided and defaults to '${transactionMode.value}'`;
437
+ throw new Error(`Migration "${migrationWithTransactionConfig.name}" has a \`transaction\` configuration but ${modeDescription}. Per-migration transaction configuration is only supported when \`transactionMode\` is 'per-migration'. Set \`transactionMode: 'per-migration'\` on the migrator or the migrate call to enable it.`);
417
438
  }
418
- else if (direction === 'Up') {
419
- return await this.#migrateUp(db, state, step);
439
+ if (!transactionMode.explicit &&
440
+ adapter.supportsTransactionalDdl &&
441
+ migrationsToRun.length > 1) {
442
+ logOnce("kysely:migrator: multiple migrations were run in a single transaction ('per-run'). This default might change in a future version of Kysely. Pass an explicit `transactionMode` to the migrator to pin the behavior and silence this message: 'per-run' to keep the current behavior, or 'per-migration' to run each migration in its own transaction.");
420
443
  }
421
- return { results: [] };
444
+ return await orchestrator(migrationsToRun, (migration) => runner(db, migration));
422
445
  };
423
446
  const runWithLock = async (db, cb) => {
424
447
  try {
@@ -429,51 +452,92 @@ export class Migrator {
429
452
  await adapter.releaseMigrationLock(db, lockOptions);
430
453
  }
431
454
  };
432
- const disableTransactions = options?.disableTransactions ?? this.#props.disableTransactions;
433
455
  if (this.#props.db.isTransaction) {
434
456
  if (!adapter.supportsTransactionalDdl) {
435
457
  throw new Error('Transactional DDL is not supported in this dialect. Passing a transaction to this migrator would result in failure or unexpected behavior.');
436
458
  }
437
- if (disableTransactions) {
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.');
459
+ if (transactionMode.value !== 'per-run') {
460
+ throw new Error(`The transaction mode is '${transactionMode.value}' but the migrator was given a transaction. Passing a transaction to this migrator is only supported when \`transactionMode\` is 'per-run'.`);
439
461
  }
440
462
  return runWithLock(this.#props.db, run);
441
463
  }
442
- if (adapter.supportsTransactionalDdl && !disableTransactions) {
464
+ if (transactionMode.value === 'per-run') {
443
465
  return this.#props.db
444
466
  .connection()
445
- .execute((db) => runWithLock(db, (db) => db.transaction().execute((trx) => run(trx))));
467
+ .execute((db) => runWithLock(db, (db) => db.transaction().execute(run)));
446
468
  }
447
469
  return this.#props.db.connection().execute((db) => runWithLock(db, run));
448
470
  }
471
+ #resolveTransactionMode(options, adapter) {
472
+ const resolveLevel = (options, source) => {
473
+ if (!options) {
474
+ return;
475
+ }
476
+ const { disableTransactions, transactionMode } = options;
477
+ if (disableTransactions != null &&
478
+ transactionMode &&
479
+ (transactionMode === 'none') !== disableTransactions) {
480
+ throw new Error(`\`transactionMode\` is '${transactionMode}' but \`disableTransactions\` is ${disableTransactions} in the ${source}. These options contradict each other. Prefer \`transactionMode\` — \`disableTransactions\` is deprecated.`);
481
+ }
482
+ if (transactionMode) {
483
+ if (transactionMode !== 'none' && !adapter.supportsTransactionalDdl) {
484
+ throw new Error(`\`transactionMode\` is '${transactionMode}' but transactional DDL is not supported in this dialect. Migrations would fail or behave unexpectedly.`);
485
+ }
486
+ return { explicit: true, value: transactionMode };
487
+ }
488
+ if (disableTransactions == null) {
489
+ return;
490
+ }
491
+ if (disableTransactions === true) {
492
+ return { explicit: true, value: 'none' };
493
+ }
494
+ return {
495
+ explicit: false,
496
+ value: adapter.supportsTransactionalDdl ? 'per-run' : 'none',
497
+ };
498
+ };
499
+ return (resolveLevel(options, 'migrate call options') ||
500
+ resolveLevel(this.#props, 'migrator properties') || {
501
+ explicit: false,
502
+ value: adapter.supportsTransactionalDdl ? 'per-run' : 'none',
503
+ });
504
+ }
505
+ #getMigrationsToRun(state, direction, step) {
506
+ if (direction === 'Down') {
507
+ return state.executedMigrations
508
+ .toReversed()
509
+ .slice(0, step)
510
+ .map((name) => {
511
+ return state.migrations.find((it) => it.name === name);
512
+ });
513
+ }
514
+ return state.pendingMigrations.slice(0, step);
515
+ }
449
516
  async #getState(db) {
450
- const migrations = await this.#resolveMigrations();
451
- const executedMigrations = await this.#getExecutedMigrations(db);
517
+ const [migrations, executedMigrations] = await Promise.all([
518
+ this.#resolveMigrations(),
519
+ this.#getExecutedMigrations(db),
520
+ ]);
452
521
  this.#ensureNoMissingMigrations(migrations, executedMigrations);
453
522
  if (!this.#allowUnorderedMigrations) {
454
523
  this.#ensureMigrationsInOrder(migrations, executedMigrations);
455
524
  }
456
525
  const pendingMigrations = this.#getPendingMigrations(migrations, executedMigrations);
457
526
  return freeze({
458
- migrations,
459
527
  executedMigrations,
460
- lastMigration: getLast(executedMigrations),
528
+ lastMigration: executedMigrations.at(-1),
529
+ migrations,
461
530
  pendingMigrations,
462
531
  });
463
532
  }
464
533
  #getPendingMigrations(migrations, executedMigrations) {
465
- return migrations.filter((migration) => {
466
- return !executedMigrations.includes(migration.name);
467
- });
534
+ return migrations.filter((migration) => !executedMigrations.includes(migration.name));
468
535
  }
469
536
  async #resolveMigrations() {
470
537
  const allMigrations = await this.#props.provider.getMigrations();
471
538
  return Object.keys(allMigrations)
472
539
  .sort()
473
- .map((name) => ({
474
- ...allMigrations[name],
475
- name,
476
- }));
540
+ .map((name) => ({ ...allMigrations[name], name }));
477
541
  }
478
542
  async #getExecutedMigrations(db) {
479
543
  const executedMigrations = await db
@@ -509,92 +573,63 @@ export class Migrator {
509
573
  }
510
574
  }
511
575
  }
512
- async #migrateDown(db, state, step) {
513
- const migrationsToRollback = state.executedMigrations
514
- .toReversed()
515
- .slice(0, step)
516
- .map((name) => {
517
- return state.migrations.find((it) => it.name === name);
518
- });
519
- const results = migrationsToRollback.map((migration) => {
520
- return {
521
- migrationName: migration.name,
522
- direction: 'Down',
523
- status: 'NotExecuted',
524
- };
525
- });
576
+ async #rollbackMigrations(migrationsToRollback, rollbacker) {
577
+ const results = migrationsToRollback.map((migration) => ({
578
+ direction: 'Down',
579
+ migrationName: migration.name,
580
+ status: 'NotExecuted',
581
+ }));
526
582
  for (let i = 0; i < results.length; ++i) {
527
583
  const migration = migrationsToRollback[i];
584
+ if (!migration.down) {
585
+ continue;
586
+ }
528
587
  try {
529
- if (migration.down) {
530
- await migration.down(db);
531
- await db
532
- .withPlugin(this.#schemaPlugin)
533
- .deleteFrom(this.#migrationTable)
534
- .where('name', '=', migration.name)
535
- .execute();
536
- results[i] = {
537
- migrationName: migration.name,
538
- direction: 'Down',
539
- status: 'Success',
540
- };
541
- }
588
+ await rollbacker(migration);
589
+ results[i].status = 'Success';
542
590
  }
543
591
  catch (error) {
544
- results[i] = {
545
- migrationName: migration.name,
546
- direction: 'Down',
547
- status: 'Error',
548
- };
549
- throw new MigrationResultSetError({
550
- error,
551
- results,
552
- });
592
+ results[i].status = 'Error';
593
+ throw new MigrationResultSetError({ error, results });
553
594
  }
554
595
  }
555
596
  return { results };
556
597
  }
557
- async #migrateUp(db, state, step) {
558
- const migrationsToRun = state.pendingMigrations.slice(0, step);
559
- const results = migrationsToRun.map((migration) => {
560
- return {
561
- migrationName: migration.name,
562
- direction: 'Up',
563
- status: 'NotExecuted',
564
- };
565
- });
598
+ async #applyMigrations(migrationsToRun, applier) {
599
+ const results = migrationsToRun.map((migration) => ({
600
+ direction: 'Up',
601
+ migrationName: migration.name,
602
+ status: 'NotExecuted',
603
+ }));
566
604
  for (let i = 0; i < results.length; i++) {
567
- const migration = state.pendingMigrations[i];
605
+ const migration = migrationsToRun[i];
568
606
  try {
569
- await migration.up(db);
570
- await db
571
- .withPlugin(this.#schemaPlugin)
572
- .insertInto(this.#migrationTable)
573
- .values({
574
- name: migration.name,
575
- timestamp: new Date().toISOString(),
576
- })
577
- .execute();
578
- results[i] = {
579
- migrationName: migration.name,
580
- direction: 'Up',
581
- status: 'Success',
582
- };
607
+ await applier(migration);
608
+ results[i].status = 'Success';
583
609
  }
584
610
  catch (error) {
585
- results[i] = {
586
- migrationName: migration.name,
587
- direction: 'Up',
588
- status: 'Error',
589
- };
590
- throw new MigrationResultSetError({
591
- error,
592
- results,
593
- });
611
+ results[i].status = 'Error';
612
+ throw new MigrationResultSetError({ error, results });
594
613
  }
595
614
  }
596
615
  return { results };
597
616
  }
617
+ async #applyMigration(db, migration) {
618
+ await migration.up(db);
619
+ await db
620
+ .withPlugin(this.#schemaPlugin)
621
+ .insertInto(this.#migrationTable)
622
+ .values({ name: migration.name, timestamp: new Date().toISOString() })
623
+ .execute();
624
+ }
625
+ async #rollbackMigration(db, migration) {
626
+ await migration.down(db);
627
+ await db
628
+ .withPlugin(this.#schemaPlugin)
629
+ .deleteFrom(this.#migrationTable)
630
+ .where('name', '=', migration.name)
631
+ .execute();
632
+ }
598
633
  async #createIfNotExists(qb) {
599
634
  if (this.#props.db.getExecutor().adapter.supportsCreateIfNotExists) {
600
635
  qb = qb.ifNotExists();
@@ -14,7 +14,6 @@ export declare function isFunction(obj: unknown): obj is Function;
14
14
  export declare function isObject(obj: unknown): obj is ShallowRecord<string, unknown>;
15
15
  export declare function isArrayBufferOrView(obj: unknown): obj is ArrayBuffer | ArrayBufferView;
16
16
  export declare function isPlainObject(obj: unknown): obj is Record<string, unknown>;
17
- export declare function getLast<T>(arr: ArrayLike<T>): T | undefined;
18
17
  export declare function freeze<T>(obj: T): Readonly<T>;
19
18
  export declare function asArray<T>(arg: T | ReadonlyArray<T>): ReadonlyArray<T>;
20
19
  export declare function asReadonlyArray<T>(arg: T | ReadonlyArray<T>): ReadonlyArray<T>;
@@ -56,9 +56,6 @@ export function isPlainObject(obj) {
56
56
  }
57
57
  return Object.getPrototypeOf(obj) === proto;
58
58
  }
59
- export function getLast(arr) {
60
- return arr[arr.length - 1];
61
- }
62
59
  export function freeze(obj) {
63
60
  return Object.freeze(obj);
64
61
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kysely",
3
- "version": "0.29.4",
3
+ "version": "0.30.0-beta.0",
4
4
  "description": "Type safe SQL query builder",
5
5
  "repository": {
6
6
  "type": "git",