Skip to content

Commit

Permalink
implement migrateUp, migrateDown and migrateTo methods
Browse files Browse the repository at this point in the history
  • Loading branch information
koskimas committed Dec 28, 2021
1 parent f0d817f commit 066a8c7
Show file tree
Hide file tree
Showing 15 changed files with 938 additions and 255 deletions.
44 changes: 34 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,32 +252,56 @@ await db.migration.migrateToLatest(pathToMigrationsFolder)
```

to run all migrations that have not yet been run. The migrations are executed in alphabetical
order by their file name.
order by their name. See the [migration module](https://koskimas.github.io/kysely/classes/MigrationModule.html)
documentation for more info.

Kysely doesn't have a CLI for running migrations and probably never will. This is because Kysely's
migrations are also written in typescript. To run the migrations, you need to first build the
typescript code into javascript. The CLI would cause confusion over which migrations are being
run, the typescript ones or the javascript ones. If we added support for both, it would mean the
CLI would depend on a typescript compiler, which most production environments don't (and shouldn't)
run, the typescript ones or the javascript ones. If we added support for both, the CLI would
need to depend on a typescript compiler, which most production environments don't (and shouldn't)
have. You will probably want to add a simple migration script to your projects like this:

```ts
import path from 'path'

// This example assumes you have a file named `database.ts` that
// creates and exports a `Kysely` instance `db`. You can just
// as well create a new `Kysely` instance in the function below
// or do something completely different to obtain an instance
// of `Kysely`.
import { db } from './database'

db.migration
.migrateToLatest(path.join(__dirname, 'migrations'))
.then(() => db.destroy())
async function migrateToLatest() {
const { error, results } = await db.migration.migrateToLatest(
path.join(__dirname, 'migrations')
)

// Destroy the `Kysely` instance to make the script exit faster.
await db.destroy()

results?.forEach((it) => {
if (it.status === 'Success') {
console.log(`migration "${it.migrationName}" was executed successfully`)
} else if (it.status === 'Error') {
console.error(`failed to execute migration "${it.migrationName}"`)
}
})

if (error) {
console.error('failed to migrate')
console.error(error)
process.exit(1)
}
}

migrateToLatest()
```

The migration methods use a lock on the database level, and parallel calls are executed serially.
This means that you can safely call `migrateToLatest` and other migration methods from multiple
server instances simultaneously and the migrations are guaranteed to only be executed once.

NOTE: Only `db.migration.migrateToLatest` method is implemented at the moment. There is no way
to run the down migrations, or to go forward to a specific migration. These methods will be
added soon.

# Why not just contribute to knex

Kysely is very similar to knex, but it also attempts to fix things that I personally find not-so-good
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kysely",
"version": "0.12.2",
"version": "0.13.0",
"description": "Type safe SQL query builder",
"repository": {
"type": "git",
Expand Down
4 changes: 2 additions & 2 deletions src/dialect/mysql/mysql-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Kysely } from '../../kysely.js'
import { DialectAdapter } from '../dialect-adapter.js'
import { DialectAdapterBase } from '../dialect-adapter-base.js'

const LOCK_ID = 'ea586330-2c93-47c8-908d-981d9d270f9d'
const LOCK_TIMEOUT_SECONDS = 60 * 60

export class MysqlAdapter implements DialectAdapter {
export class MysqlAdapter extends DialectAdapterBase {
get supportsTransactionalDdl(): boolean {
return false
}
Expand Down
6 changes: 3 additions & 3 deletions src/dialect/postgres/postgres-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Kysely } from '../../kysely.js'
import { DialectAdapter } from '../dialect-adapter.js'
import { DialectAdapterBase } from '../dialect-adapter-base.js'

// Random id for our transaction lock.
const LOCK_ID = '3853314791062309107'

export class PostgresAdapter implements DialectAdapter {
export class PostgresAdapter extends DialectAdapterBase {
get supportsTransactionalDdl(): boolean {
return true
}

get supportsReturning(): boolean {
return true
}

async acquireMigrationLock(db: Kysely<any>): Promise<void> {
// Acquire a transaction level advisory lock.
await db.raw(`select pg_advisory_xact_lock(${LOCK_ID})`).execute()
Expand Down
4 changes: 2 additions & 2 deletions src/dialect/sqlite/sqlite-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { DialectAdapter } from '../dialect-adapter.js'
import { DialectAdapterBase } from '../dialect-adapter-base.js'

export class SqliteAdapter implements DialectAdapter {
export class SqliteAdapter implements DialectAdapterBase {
get supportsTransactionalDdl(): boolean {
return false
}
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export {
export {
SelectExpression,
SelectExpressionOrList,
Selection,
} from './parser/select-parser.js'
export {
ReferenceExpression,
Expand Down
Loading

0 comments on commit 066a8c7

Please sign in to comment.