Skip to content

Commit

Permalink
change Migrator option to allowUnorderedMigrations
Browse files Browse the repository at this point in the history
  • Loading branch information
tracehelms committed Nov 13, 2023
1 parent 305ba9b commit a363dee
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 33 deletions.
10 changes: 5 additions & 5 deletions site/docs/migrations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ Migrations can use the `Kysely.schema` module to modify the schema. Migrations c

## Execution order

There are two options for ordering migrations in Kysely: strict and permissive. Both options are based on the alphanumeric ordering of the migration name. In either case, an excellent way to name your migrations is to prefix them with an ISO 8601 date string.
Migrations will be run in the alpha-numeric order of your migration names. An excellent way to name your migrations is to prefix them with an ISO 8601 date string.

Strict ordering (the default) will give an error if the alphanumeric order of your migration files does not match the execution order of them in the database. This adds safety by always executing your migrations in the correct, alphanumeric order.
By default, Kysely will also ensure this order matches the execution order of any previously executed migrations in your database. If the orders do not match (for example, a new migration was added alphabetically before a previously executed one), an error will be returned. This adds safety by always executing your migrations in the correct, alphanumeric order.

Permissive ordering will allow new migrations to be run even if they are added alphabetically before ones that have already executed. Permissive ordering works well in large teams where multiple team members may add migrations at the same time in parallel commits without knowing about the other migrations. Permissive ordering will run pending (unexecuted) migrations in order when migrating up. When migrating down, migrations will be undone in the opposite order in which they were executed (reverse sorted by execution timestamp).
There is also an `allowUnorderedMigrations` option. This option will allow new migrations to be run even if they are added alphabetically before ones that have already executed. Allowing unordered migrations works well in large teams where multiple team members may add migrations at the same time in parallel commits without knowing about the other migrations. Pending (unexecuted) migrations will be run in alpha-numeric order when migrating up. When migrating down, migrations will be undone in the opposite order in which they were executed (reverse sorted by execution timestamp).

To use permissive ordering, pass the `migrationOrder` option to Migrator:
To allow unordered migrations, pass the `allowUnorderedMigrations` option to Migrator:

```ts
const migrator = new Migrator({
db,
provider: new FileMigrationProvider(...),
migrationOrder: 'permissive'
allowUnorderedMigrations: true
})
```

Expand Down
16 changes: 9 additions & 7 deletions src/migration/migrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { freeze, getLast } from '../util/object-utils.js'

export const DEFAULT_MIGRATION_TABLE = 'kysely_migration'
export const DEFAULT_MIGRATION_LOCK_TABLE = 'kysely_migration_lock'
export const DEFAULT_MIGRATION_ORDER = 'strict'
export const DEFAULT_ALLOW_UNORDERED_MIGRATIONS = false
export const MIGRATION_LOCK_ID = 'migration_lock'
export const NO_MIGRATIONS: NoMigrations = freeze({ __noMigrations__: true })

Expand Down Expand Up @@ -268,8 +268,10 @@ export class Migrator {
return this.#props.migrationLockTableName ?? DEFAULT_MIGRATION_LOCK_TABLE
}

get #migrationOrder(): 'strict' | 'permissive' | undefined {
return this.#props.migrationOrder ?? DEFAULT_MIGRATION_ORDER
get #allowUnorderedMigrations(): boolean {
return (
this.#props.allowUnorderedMigrations ?? DEFAULT_ALLOW_UNORDERED_MIGRATIONS
)
}

get #schemaPlugin(): KyselyPlugin {
Expand Down Expand Up @@ -464,7 +466,7 @@ export class Migrator {
const executedMigrations = await this.#getExecutedMigrations(db)

this.#ensureNoMissingMigrations(migrations, executedMigrations)
if (this.#migrationOrder !== 'permissive') {
if (!this.#allowUnorderedMigrations) {
this.#ensureMigrationsInOrder(migrations, executedMigrations)
}

Expand Down Expand Up @@ -716,17 +718,17 @@ export interface MigratorProps {
/**
* Enforces whether or not migrations must be run in alpha-numeric order.
*
* In strict mode, migrations must be run in their exact alpha-numeric order.
* When false, migrations must be run in their exact alpha-numeric order.
* This is checked against the migrations already run in the database
* (`migrationTableName'). This ensures your migrations are always run in
* the same order and is the safest option.
*
* In permissive mode, migrations are still run in alpha-numeric order, but
* When true, migrations are still run in alpha-numeric order, but
* the order is not checked against already-run migrations in the database.
* Kysely will simply run all migrations that haven't run yet, in alpha-numeric
* order.
*/
readonly migrationOrder?: 'strict' | 'permissive'
readonly allowUnorderedMigrations?: boolean
}

/**
Expand Down
42 changes: 21 additions & 21 deletions test/node/src/migration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,17 @@ for (const dialect of DIALECTS) {
expect(executedUpMethods2).to.eql([])
})

it('should run a new migration added before the last executed one with permissive ordering enabled', async () => {
it('should run a new migration added before the last executed one with allowUnorderedMigrations enabled', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration3'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results1 } = await migrator1.migrateToLatest()

const [migrator2, executedUpMethods2] = createMigrations(
['migration1', 'migration2', 'migration3', 'migration4'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results2 } = await migrator2.migrateToLatest()
Expand Down Expand Up @@ -218,18 +218,18 @@ for (const dialect of DIALECTS) {
expect(executedUpMethods2).to.eql([])
})

describe('with permissive ordering', () => {
describe('with allowUnorderedMigrations', () => {
it('should return an error if a previously executed migration is missing', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration2', 'migration3'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

await migrator1.migrateToLatest()

const [migrator2, executedUpMethods2] = createMigrations(
['migration2', 'migration3', 'migration4'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { error } = await migrator2.migrateToLatest()
Expand All @@ -250,12 +250,12 @@ for (const dialect of DIALECTS) {
it('should return an error if a the last executed migration is not found', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration2', 'migration3'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const [migrator2, executedUpMethods2] = createMigrations(
['migration1', 'migration2', 'migration4'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

await migrator1.migrateToLatest()
Expand Down Expand Up @@ -456,11 +456,11 @@ for (const dialect of DIALECTS) {
expect(executedDownMethods2).to.eql(['migration4', 'migration3'])
})

describe('with permissive ordering enabled', () => {
describe('with allowUnorderedMigrations enabled', () => {
it('should migrate up to a specific migration', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration3', 'migration4', 'migration5'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results1 } = await migrator1.migrateTo('migration3')
Expand All @@ -473,7 +473,7 @@ for (const dialect of DIALECTS) {
'migration4',
'migration5',
],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results2 } = await migrator2.migrateTo('migration4')
Expand All @@ -495,15 +495,15 @@ for (const dialect of DIALECTS) {
it('should migrate all the way down', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration2', 'migration4'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results1 } = await migrator1.migrateToLatest()

const [migrator2, executedUpMethods2, executedDownMethods2] =
createMigrations(
['migration1', 'migration2', 'migration3', 'migration4'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results2 } = await migrator2.migrateTo(NO_MIGRATIONS)
Expand Down Expand Up @@ -548,7 +548,7 @@ for (const dialect of DIALECTS) {
it('should migrate down to a specific migration', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration2', 'migration3', 'migration5'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results1 } = await migrator1.migrateTo('migration5')
Expand All @@ -562,7 +562,7 @@ for (const dialect of DIALECTS) {
'migration4',
'migration5',
],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results2 } = await migrator2.migrateTo('migration2')
Expand Down Expand Up @@ -655,17 +655,17 @@ for (const dialect of DIALECTS) {
expect(executedUpMethods2).to.eql([])
})

it('should migrate up one step with permissive ordering enabled', async () => {
it('should migrate up one step with allowUnorderedMigrations enabled', async () => {
const [migrator1, executedUpMethods1] = createMigrations(
['migration1', 'migration3'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results1 } = await migrator1.migrateToLatest()

const [migrator2, executedUpMethods2] = createMigrations(
['migration1', 'migration2', 'migration3', 'migration4'],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results2 } = await migrator2.migrateUp()
Expand Down Expand Up @@ -742,10 +742,10 @@ for (const dialect of DIALECTS) {
expect(executedDownMethods2).to.eql([])
})

it('should migrate down one step with permissive ordering enabled', async () => {
it('should migrate down one step with allowUnorderedMigrations enabled', async () => {
const [migrator1, executedUpMethods1, _executedDownMethods1] =
createMigrations(['migration1', 'migration2', 'migration4'], {
migrationOrder: 'permissive',
allowUnorderedMigrations: true,
})

await migrator1.migrateToLatest()
Expand All @@ -759,7 +759,7 @@ for (const dialect of DIALECTS) {
'migration4',
'migration5',
],
{ migrationOrder: 'permissive' }
{ allowUnorderedMigrations: true }
)

const { results: results1 } = await migrator2.migrateDown()
Expand Down

0 comments on commit a363dee

Please sign in to comment.