🪽 cigogne - Easy migrations in Gleam

Package Version Hex Docs

Cigogne (French for stork) is a simple tool to manage migrations for your Postgres database. The idea is that you have total control on your migrations, since you will be writing SQL files directly. That approach gives you more freedom on how you want to do your migrations for the price of a bit of time and learning some database skills.

For example, if you decide to rename a column, you can use a ALTER TABLE RENAME COLUMN query !
If you decide to change a column’s data type, you can decide how to populate it based on the old values.

As a plus, this integrates really well with the approach provided by squirrel.

Installation

gleam add --dev cigogne

Cigogne can also be installed as a regular dependency and used in your project.
See the “Usage” section to know more.

Note: cigogne can now only be used on the Erlang target.
This constraint is both imposed by pog and required to be able to work with libraries.
However, you can still have it in your JS project as a dev dependency and use the CLI.

Usage

To use cigogne, you first have to create your migration scripts in a folder (by default priv/migrations). Cigogne will look for .sql files in this folder to get your migrations.

Use the gleam run -m cigogne new --name NAME command to create a new migration

Cigogne expects the sql files to have the following format <MigrationTimestamp>-<MigrationName>.sql. This way we can get the order in which migrations should be applied and a descriptive name right away. It also allows for easy sorting of your migration scripts and forces you to give it a meaningful name.

You can then write your migration scripts. It should look like this:

--- migration:up
CREATE TABLE users(
    id UUID PRIMARY KEY,
    firstName TEXT NOT NULL,
    age INT NOT NULL
);

--- migration:down
DROP TABLE users;

--- migration:end

The --- migration: comments are used to separate between the queries used for the “up migration” (used when you apply the migration) and the “down migration” (used when you rollback the migration).

You are now ready to execute your migration ! The first way of executing your migration is via the command line :

# Apply the next migration
gleam run -m cigogne up
# Roll back the last applied migration
gleam run -m cigogne down
# Apply all migrations not yet applied
gleam run -m cigogne up-all
# Show the applied migration
gleam run -m cigogne show
# Create a new migration with name NAME
gleam run -m cigogne new --name NAME

Run gleam run -m cigogne help to get a list of all actions and gleam run -m cigogne help <action> to get details of all the available flags

You can also use cigogne in your server initalisation function to make sure your database is up-to-date.

import cigogne
import cigogne/config

pub fn init() -> Nil {
  use config <- result.try(config.get("my-app"))
  // Configure cigogne using a custom config object. Example:
  // let config = config.Config(
  //   ..config.default_config,
  //   database: config.UrlDbConfig("postgres://my_user@192.168.0.101:5433/my_db")
  // )

  use engine <- result.try(cigogne.create_engine(config))
  cigogne.apply_all(engine)
}

Further documentation can be found at https://hexdocs.pm/cigogne.

Libraries

Cigogne can also be used to get and apply migrations from your dependencies, if they use cigogne.

This is done via the include-lib action like so: gleam run -m cigogne include-lib --lib-name my_lib.

This action merges all the library’s migration in a new migration file in your project.
If you update the library and there are new migrations to include, simply run the command again and the remaining migrations will be included in a new file.

You can also “remove” a lib by using the remove-lib command. It does not remove the migrations that were created, but combines all migrations created by include-lib for the specified library and intervert the “up” and “down” migrations.

Configuration

Most of the cigogne commands can be configured to specify how you want to connect to the database, what table to use to store migration data or in which folder to get the migrations.
You can get more information on these flags by running gleam run -m cigogne help <command>.

To avoid writing a bunch of flags each time you want to run a cigogne command, you can also create a cigogne.toml file in your priv directory.
The easiest way to do it is by using this command: gleam run -m cigogne update-config, which will create a the file and write the default config in it.

As its name implies, you can also also use it to update an existing cigogne.toml file by passing the same flags as for the others commands.
However the command rewrite the configuration file, so create a backup if you added valuable information in it !

For reference, here is the default configuration file:

# This section will be overridden by eventual users of the library
[database]
# If url is defined, it is used to connect to the database
# url = ""

# If other data in this section is defined, it is used to connect
# Otherwise, we fallback to the DATABASE_URL environment variable
# host = "localhost"
# user = "postgres"
# # /!\ It is not recommended to have your password there
# password = "postgres"
# port = 5432
# name = "postgres"

# This section will be overridden by eventual users of the library
[migration-table]
# schema = "public"
# table = "_migrations"

[migrations]
# migration_folder = "migrations"

[migrations.dependencies]

Hashes

A hash of the migration file is saved to the database when a migration is applied. This way, we can ensure that migrations are not modified after being applied. If a migration has been modified, you will get an error as it probably means that you should reset your database to update a migration.

During development, you may want to edit your migrations after they have been applied to your database. In that case, you can use the --no-hash-check flag to bypass hash checking when you want to apply or rollback migrations. It isn’t recommended to use this flag in production, because then your migrations scripts don’t match what is in your database !

This feature was introduced in version 3 of cigogne. Note that it requires Gleam >=1.9.0. If you use earlier versions of the library, you can use the to_v3 script to have them filled automatically.

Command: gleam run -m cigogne/to_v3

Development ideas

If you have feature requests or ideas of improvments, don’t hesitate to open an issue.

Development

gleam run   # Run the project
gleam test  # Run the tests
Search Document