# Migrations

Shipclojure uses [migratus](https://github.com/yogthos/migratus) to handle migrations. For ease of creating migrations, there is the [migrations namespace](https://github.com/shipclojure/shipclojure/blob/main/env/dev/clj/migrations.clj)

## Store

By default, ShipClojure stores migrations in a table in the main DB

> See `db.sql/migrations` key in [system.edn](https://github.com/shipclojure/shipclojure/blob/main/resources/system.edn)

## Creating a migration

Let's say you need to create a new image table in the DB to store user images.

1. Visit [migrations.clj](https://github.com/shipclojure/shipclojure/blob/main/env/dev/clj/migrations.clj)
2. In the last comment, you'll see imported the `migration-config` from `user`
3. Write in the same comment

```clojure
  (create-migration (migration-config) "add-images-table" :sql)
```

4. Evaluate this in the REPL
5. Expect to see 2 new files `{current-date}-add-images-table.{up,down}.sql` in `resources/db/migrations`
6. Add the correct up & down configurations, and reset the integrant system. The migrations will be applied automatically

> *Important:* If you want to include multiple statements in the same migration file there is a special notation (`--;;`) you need to use, otherwise you'll get an error `Too many update results were returned`:

```sql
ALTER TABLE user_account
    DROP COLUMN IF EXISTS image_url;
--;;
CREATE TABLE user_image (
    id TEXT NOT NULL PRIMARY KEY,
    alt_text TEXT,
    content_type TEXT NOT NULL,
    blob BYTEA NOT NULL,
    created_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    user_id TEXT NOT NULL REFERENCES user_account(id) ON DELETE CASCADE ON UPDATE CASCADE
);
--;;
CREATE UNIQUE INDEX user_image_user_id_idx ON user_image(user_id);
```

## Rolling back migrations

To roll back migrations, use `user/rollback-latest-migration`
