{"id":26124438,"url":"https://github.com/dnaeon/cl-migratum","last_synced_at":"2025-06-24T15:11:37.149Z","repository":{"id":39758963,"uuid":"257635082","full_name":"dnaeon/cl-migratum","owner":"dnaeon","description":"Database Schema Migration System for Common Lisp","archived":false,"fork":false,"pushed_at":"2023-12-07T12:04:01.000Z","size":1061,"stargazers_count":46,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-10T16:08:18.566Z","etag":null,"topics":["common-lisp","database-management","database-migrations","database-schema","lisp"],"latest_commit_sha":null,"homepage":null,"language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dnaeon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.org","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["dnaeon"]}},"created_at":"2020-04-21T15:15:06.000Z","updated_at":"2025-02-28T13:32:53.000Z","dependencies_parsed_at":"2024-06-21T17:31:04.799Z","dependency_job_id":"1d1c605f-a95f-4550-b12d-4f85ef555aba","html_url":"https://github.com/dnaeon/cl-migratum","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/dnaeon/cl-migratum","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnaeon%2Fcl-migratum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnaeon%2Fcl-migratum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnaeon%2Fcl-migratum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnaeon%2Fcl-migratum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dnaeon","download_url":"https://codeload.github.com/dnaeon/cl-migratum/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dnaeon%2Fcl-migratum/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261700856,"owners_count":23196506,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["common-lisp","database-management","database-migrations","database-schema","lisp"],"created_at":"2025-03-10T16:08:21.142Z","updated_at":"2025-06-24T15:11:37.126Z","avatar_url":"https://github.com/dnaeon.png","language":"Common Lisp","funding_links":["https://github.com/sponsors/dnaeon"],"categories":["Expert Systems"],"sub_categories":[],"readme":"# Database Schema Migration System for Common Lisp\n\n`cl-migratum` is a Common Lisp system, which provides facilities for\nperforming [database schema\nmigrations](https://en.wikipedia.org/wiki/Schema_migration).\n\n![migratum-demo](./images/migratum-demo.gif)\n\n## Requirements\n\n* [Quicklisp](https://www.quicklisp.org/beta/)\n\n## Systems\n\nThe following systems are available as part of this repo.\n\n| System                                     | Description                                         |\n|--------------------------------------------|-----------------------------------------------------|\n| `cl-migratum`                              | Core system                                         |\n| `cl-migratum.provider.local-path`          | Provider which discovers migrations from local-path |\n| `cl-migratum.driver.dbi`                   | `cl-dbi` database driver                            |\n| `cl-migratum.driver.rmdbs-postgresql`      | PostgreSQL driver based on `hu.dwim.rdbms`          |\n| `cl-migratum.driver.postmodern-postgresql` | PostgreSQL driver based on `postmodern`             |\n| `cl-migratum.driver.mixins`                | Various mixin classes used by drivers               |\n| `cl-migratum.test`                         | Test suite for `cl-migratum`                        |\n| `cl-migratum.cli`                          | CLI application of `migratum`                       |\n\n## Installation\n\nInstallation is possible via [roswell](https://github.com/roswell/roswell). This will also build the `migratum` binary (see section CLI):\n\n``` shell\nros install cl-migratum\n```\n\nThe latest development version can be installed from the Git repo.\n\nClone the [cl-migratum](https://github.com/dnaeon/cl-migratum) repo in your\n[Quicklisp local-projects directory](https://www.quicklisp.org/beta/faq.html).\n\n``` shell\ngit clone https://github.com/dnaeon/cl-migratum.git\n```\n\n## CLI\n\nYou can install the CLI application of `migratum` by executing the\nfollowing command.\n\n``` shell\nmake cli\n```\n\nThe `migratum` binary will be built into the `bin/migratum`\ndirectory. You can now install the binary somewhere in your `PATH`.\n\nOnce the `migratum` binary is built you can also generate the Zsh\ncompletions by executing the following command.\n\n``` shell\nmigratum zsh-completions \u003e ~/.zsh-completions/_migratum\n```\n\nMake sure that `~/.zsh-completions` is part of your Zsh `FPATH`.\n\nIn order to generate the Markdown documentation of the CLI app use the\n`cli-doc` target:\n\n``` shell\nmake cli-doc\n```\n\nOr you can build a Docker image instead.\n\n``` shell\ndocker build -t migratum.cli:latest -f Dockerfile.cli .\n```\n\n## Concepts\n\nThe `cl-migratum` system uses the following concepts to describe\nthe process of discovering and applying schema migrations, so it is\nimportant that you get familiar with them first.\n\n### Migration\n\nA `migration` represents a resource that provides information about a\nschema change, e.g. it provides the unique id of the change, the\nrequired scripts that can be used to upgrade and/or downgrade the\ndatabase.\n\nMigration resources are discovered via `providers` and are being\nused by `drivers` during the upgrade or downgrade process.\n\n### Provider\n\nThe `provider` is responsible for discovering migration resources.\n\nFor example a provider can discover migrations from a local path by\nscanning for files that match a given pattern or fetch migrations from\na remote endpoint (e.g. HTTP service).\n\nThe `provider` is also responsible for creating new migration\nsequences.\n\nThe following providers are supported by `cl-migratum`.\n\n| Name         | Description                                                      | System                            |\n|--------------|------------------------------------------------------------------|-----------------------------------|\n| `local-path` | Provider that can discover migration resources from a local path | `cl-migratum.provider.local-path` |\n\n### Driver\n\nThe `driver` carries out the communication with the database against\nwhich schema changes will be applied.\n\nIt is responsible for applying schema changes, registering\nsuccessfully applied migrations and unregistering them when reverting\nback to a previous state.\n\nA `driver` internally uses a `provider` in order to discover\n`migrations`, which can be applied against the database it is\nconnected to.\n\nThe following drivers are currently supported by `cl-migratum`.\n\n| Name               | Description                                                                                                               | System                                | Migration Registration |\n|--------------------|---------------------------------------------------------------------------------------------------------------------------|---------------------------------------|------------------------|\n| `dbi`              | Driver for performing schema migrations against a SQL database using [CL-DBI](https://github.com/fukamachi/cl-dbi)        | `cl-migratum.driver.dbi`              | In table `migration`   |\n| `rdbms-postgresql` | Driver for performing schema migrations against a SQL database using [hu.dwim.rdbms](http://dwim.hu/darcs/hu.dwim.rdbms/) | `cl-migratum.driver.rdbms-postgresql` | In table `migration`   |\n\n## Usage\n\nThe following section contains some examples to get you started.\n\nIn order to use `cl-migratum` you will need to load the core system,\nalong with any `provider` and `driver` systems.\n\nLoad the core system.\n\n``` shell\nCL-USER\u003e (ql:quickload :cl-migratum)\n```\n\n### Create Provider\n\nFirst, we will create a new `provider` that can discover migration\nfiles from a local path. In order to create a `local-path` provider we\nneed to load the respective system.\n\n``` common-lisp\nCL-USER\u003e (ql:quickload :cl-migratum.provider.local-path)\n```\n\nOnce you load the system we can create a `local-path` provider. The\n`local-path` provider can discover migrations from multiple paths.\n\nTypical example where having multiple paths with migration resources\nmight be useful is when you have a set of base migrations you want to\napply to all environments, and then have a separate path for each\nenvironment with their own migrations. For example you might want to\nrun specific migrations only in your `dev` environment, but don't want\nthem in your `production` environment.\n\nIn that case it makes sense to separate the migration resources in\nmultiple paths, for each environment respectively.\n\n``` common-lisp\nCL-USER\u003e (defparameter *provider*\n           (migratum.provider.local-path:make-provider (list #P\"/path/to/cl-migratum/t/migrations/\")))\n*PROVIDER*\n```\n\nThe `LOCAL-PATH-PROVIDER` discovers migration files which match the\nfollowing pattern.\n\n| Pattern                          | Description      |\n|----------------------------------|------------------|\n| `\u003cid\u003e-\u003cdescription\u003e.up.\u003ckind\u003e`   | Upgrade script   |\n| `\u003cid\u003e-\u003cdescription\u003e.down.\u003ckind\u003e` | Downgrade script |\n\nIn above pattern `\u003cid\u003e` is a monotonically increasing integer, which\nrepresents the timestamp the migration has been created. The format of\n`\u003cid\u003e` is `YYYYMMDDHHMMSS`.\n\nThe supported migration kinds by `LOCAL-PATH-PROVIDER` are these.\n\n| Extension | Kind    | Description                                      |\n|-----------|---------|--------------------------------------------------|\n| `.sql`    | `:sql`  | SQL migration resource                           |\n| `.lisp`   | `:lisp` | Migration resource which invokes a Lisp function |\n\nA provider can optionally be initialized, which can be done using the\n`MIGRATUM:PROVIDER-INIT` generic function. Not all providers would\nrequire initialization, but some will and therefore it is good that\nyou always initialize them first.\n\nIn order to list the migrations provided by a `provider` you can use\nthe `MIGRATUM:PROVIDER-LIST-MIGRATIONS` function, e.g.\n\n``` common-lisp\nCL-USER\u003e (migratum:provider-list-migrations *provider*)\n(#\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:LISP-MIGRATION {1004713F73}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {1004603BE3}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {1004603B03}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {10046039B3}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {1004603733}\u003e)\n```\n\nThe following generic functions can be used to interact with\ndiscovered migrations.\n\n| Method                           | Description                                                   |\n|----------------------------------|---------------------------------------------------------------|\n| `MIGRATUM:MIGRATION-ID`          | Returns the unique migration id                               |\n| `MIGRATUM:MIGRATION-DESCRIPTION` | Returns the description of the migration                      |\n| `MIGRATUM:MIGRATION-APPLIED`     | Returns the timestamp of when the migration was applied       |\n| `MIGRATUM:MIGRATION-LOAD`        | Loads the `:up` or `:down` migration                          |\n| `MIGRATUM:MIGRATION-KIND`        | Returns the kind of the migration, e.g. `:sql`, `:lisp`, etc. |\n\nFor example in order to collect the unique IDs of all migration\nresources you can evaluate the following while at the REPL.\n\n``` common-lisp\nCL-USER\u003e (mapcar #'migratum:migration-id\n                 (migratum:provider-list-migrations *provider*))\n(20200421180337 20200421173908 20200421173657 ...)\n```\n\n### Create Driver\n\nOnce we have a provider for discovering migration resources we need to\ncreate a driver, which can be used to communicate with the database\nwe want to apply migrations on.\n\n#### DBI Driver\n\nHere is how we can create a `dbi` driver. First, lets load the system,\nwhich provides that driver.\n\n``` common-lisp\nCL-USER\u003e (ql:quickload :cl-migratum.driver.dbi)\n```\n\nThe `dbi` driver uses [CL-DBI](https://github.com/fukamachi/cl-dbi)\ninterface to communicate with the database, so we will need to create\na database connection in order to initialize it.\n\n``` common-lisp\nCL-USER\u003e (defparameter *conn*\n           (dbi:connect :sqlite3 :database-name \"/path/to/migratum.db\"))\n*CONN*\n```\n\nAnd now we can instantiate our SQL driver using the previously created\nprovider and connection.\n\n``` common-lisp\nCL-USER\u003e (defparameter *driver*\n           (migratum.driver.dbi:make-driver *provider* *conn*))\n*DRIVER*\n```\n\n#### RDBMS PostgreSQL Driver\n\nThe process to create an `rdbms-postgresql` driver is analogous.  The\ndriver needs a connection specification to create a DB connection. In\nthis example we use the same environment variables which are used by\nthe PostgreSQL client `psql` to override the defaults:\n\n``` common-lisp\n(ql:quickload :cl-migratum.driver.rdbms-postgresql)\n(defparameter *driver*\n  (migratum.driver.rdbms-postgresql:make-driver\n   *provider*\n   `(:host ,(or (uiop:getenv \"PGHOST\") \"localhost\")\n     :database ,(or (uiop:getenv \"PGDATABASE\") \"migratum\")\n     :user-name ,(or (uiop:getenv \"PGUSER\") \"migratum\")\n     :password ,(or (uiop:getenv \"PGPASSWORD\") \"tiger\"))))\n```\n\n### Initialization\n\nA `driver` and `provider` may require some initialization steps to be\nexecuted before being able to apply migrations, so make sure that you\ninitialize them.\n\nIn order to initialize your `provider` use the\n`MIGRATUM:PROVIDER-INIT` function.\n\n``` common-lisp\nCL-USER\u003e (migratum:provider-init *provider*)\n```\n\nAn example requirement for a driver might be to create some required\ndatabase schema used to track which migrations have been applied\nalready, so lets initialize our driver first.\n\n``` common-lisp\nCL-USER\u003e (migratum:driver-init *driver*)\n```\n\n### Pending Migrations\n\nIn order to get the list of pending (not applied yet) migrations we can\nuse the `MIGRATUM:LIST-PENDING` function, e.g.\n\n``` common-lisp\nCL-USER\u003e (migratum:list-pending *driver*)\n(#\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {100363DFC3}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {100363E0A3}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {100363E183}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {100363E263}\u003e\n #\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:LISP-MIGRATION {100363E343}\u003e)\n```\n\nOr, we can display a table of the pending migrations using the\n`MIGRATUM:DISPLAY-PENDING` function instead.\n\n``` common-lisp\nCL-USER\u003e (migratum:display-pending *driver*)\n.---------------------------------------------.\n|             PENDING MIGRATIONS              |\n+----------------+---------------------+------+\n| ID             | DESCRIPTION         | KIND |\n+----------------+---------------------+------+\n| 20200421173657 | create_table_foo    | SQL  |\n| 20200421173908 | create_table_bar    | SQL  |\n| 20200421180337 | create_table_qux    | SQL  |\n| 20200605144633 | multiple_statements | SQL  |\n| 20220327224455 | lisp_code_migration | LISP |\n+----------------+---------------------+------+\n|                | TOTAL               |    5 |\n+----------------+---------------------+------+\nNIL\n```\n\nThe migrations will be sorted in the order they need to be applied.\n\n### Applying Migrations\n\nThe following functions are used for applying pending migrations.\n\n* `MIGRATUM:APPLY-PENDING` - applies all pending migrations\n* `MIGRATUM:APPLY-NEXT` - applies the next pending migration\n\nThis is how we can apply all pending migrations for example.\n\n``` common-lisp\nCL-USER\u003e (migratum:apply-pending *driver*)\n \u003cINFO\u003e [21:20:51] cl-migratum.core core.lisp (apply-pending base-driver) -\n  Found 5 pending migration(s) to be applied\n \u003cINFO\u003e [21:20:51] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200421173657 - create_table_foo (SQL)\n \u003cINFO\u003e [21:20:51] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200421173908 - create_table_bar (SQL)\n \u003cINFO\u003e [21:20:51] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200421180337 - create_table_qux (SQL)\n \u003cINFO\u003e [21:20:51] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200605144633 - multiple_statements (SQL)\n \u003cINFO\u003e [21:20:51] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20220327224455 - lisp_code_migration (LISP)\nNIL\n```\n\n### Get Latest Migration\n\nYou can use the `MIGRATUM:LATEST-MIGRATION` function to get the latest\napplied migration, e.g.\n\n``` common-lisp\nCL-USER\u003e (migratum:migration-id (migratum:latest-migration *driver*))\n20220327224455 (45 bits, #x1263E96BE487)\n```\n\nThe `MIGRATUM:CONTAINS-APPLIED-MIGRATIONS-P` predicate can be used to\nquery whether there are any migrations applied, e.g.\n\n``` common-lisp\nCL-USER\u003e (migratum:contains-applied-migrations-p *driver*)\nT\n```\n\n### Displaying Applied Migrations\n\nThe following functions can be used to get and display the\nlist of applied database migrations.\n\n| Function                       | Description                            |\n|--------------------------------|----------------------------------------|\n| `MIGRATUM:DRIVER-LIST-APPLIED` | Returns the list of applied migrations |\n| `MIGRATUM:DISPLAY-APPLIED`     | Display a table of applied migrations  |\n\nThis is how we can get the list of applied migrations.\n\n``` common-lisp\nCL-USER\u003e (migratum:driver-list-applied *driver*)\n(#\u003cCL-MIGRATUM.CORE:BASE-MIGRATION {1002175993}\u003e\n #\u003cCL-MIGRATUM.CORE:BASE-MIGRATION {10021759D3}\u003e\n #\u003cCL-MIGRATUM.CORE:BASE-MIGRATION {1002175A13}\u003e\n #\u003cCL-MIGRATUM.CORE:BASE-MIGRATION {1002175A53}\u003e\n #\u003cCL-MIGRATUM.CORE:BASE-MIGRATION {1002175A93}\u003e)\n```\n\nOr we can display a nice table of the applied migrations instead.\n\n``` common-lisp\nCL-USER\u003e (migratum:display-applied *driver*)\n.-------------------------------------------------------------------.\n|                        APPLIED MIGRATIONS                         |\n+----------------+---------------------+---------------------+------+\n| ID             | DESCRIPTION         | APPLIED             | KIND |\n+----------------+---------------------+---------------------+------+\n| 20220327224455 | lisp_code_migration | 2022-03-29 18:20:53 | LISP |\n| 20200605144633 | multiple_statements | 2022-03-29 18:20:51 | SQL  |\n| 20200421180337 | create_table_qux    | 2022-03-29 18:20:51 | SQL  |\n| 20200421173908 | create_table_bar    | 2022-03-29 18:20:51 | SQL  |\n| 20200421173657 | create_table_foo    | 2022-03-29 18:20:51 | SQL  |\n+----------------+---------------------+---------------------+------+\n|                |                     | TOTAL               |    5 |\n+----------------+---------------------+---------------------+------+\nNIL\n```\n\nThe output of these functions will be the applied migrations in\ndescending order by their id, first one being the most recent one.\n\nThe `dbi` and `rdbms-postgresql` drivers by default will fetch the\nlast 100 applied migrations. You can control this behaviour by using\nthe `:offset` and `:limit` keyword parameters, which allows you to\nfetch applied migrations in pages.\n\nFor example, if you are interested only in the last ten applied\nmigrations you can evaluate the following expression.\n\n``` common-lisp\nCL-USER\u003e (migratum:display-applied *driver* :limit 10)\n```\n\nOr if you want to skip the first ten migrations, you can evaluate\nthis expression instead.\n\n``` common-lisp\nCL-USER\u003e (migratum:display-applied *driver* :offset 10 :limit 10)\n```\n\n### Stepping through migrations\n\nUsing the following functions you can step through migrations.\n\n| Function               | Description                          |\n|------------------------|--------------------------------------|\n| `MIGRATUM:APPLY-NEXT`  | Apply the next pending migration(s)  |\n| `MIGRATUM:REVERT-LAST` | Revert the last applied migration(s) |\n\nThis is useful in situations when you don't want to apply\nall migrations at once, but rather do it one at a time. Both of these\nfunctions accept a keyword parameter `:count` which specifies the\nnumber of migrations to apply or revert.\n\nConsider the following pending migrations.\n\n``` common-lisp\nCL-USER\u003e (migratum:display-pending *driver*)\n.---------------------------------------------.\n|             PENDING MIGRATIONS              |\n+----------------+---------------------+------+\n| ID             | DESCRIPTION         | KIND |\n+----------------+---------------------+------+\n| 20200421173657 | create_table_foo    | SQL  |\n| 20200421173908 | create_table_bar    | SQL  |\n| 20200421180337 | create_table_qux    | SQL  |\n| 20200605144633 | multiple_statements | SQL  |\n| 20220327224455 | lisp_code_migration | LISP |\n+----------------+---------------------+------+\n|                | TOTAL               |    5 |\n+----------------+---------------------+------+\nNIL\n```\n\nWe can apply them one by one and verify them as we go.\n\n``` common-lisp\nCL-USER\u003e (migratum:apply-next *driver*)\n \u003cINFO\u003e [21:25:45] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200421173657 - create_table_foo (SQL)\nNIL\nCL-USER\u003e (migratum:apply-next *driver*)\n \u003cINFO\u003e [21:25:47] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200421173908 - create_table_bar (SQL)\nNIL\nCL-USER\u003e (migratum:apply-next *driver*)\n \u003cINFO\u003e [21:25:48] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200421180337 - create_table_qux (SQL)\nNIL\nCL-USER\u003e (migratum:apply-next *driver*)\n \u003cINFO\u003e [21:25:49] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20200605144633 - multiple_statements (SQL)\nNIL\nCL-USER\u003e (migratum:apply-next *driver*)\n \u003cINFO\u003e [21:25:50] cl-migratum.core core.lisp (apply-and-register base-driver) -\n  Applying migration 20220327224455 - lisp_code_migration (LISP)\nNIL\n```\n\nIf we want to revert the last three migrations we can use the\n`MIGRATUM:REVERT-LAST` function, e.g.\n\n``` common-lisp\nCL-USER\u003e (migratum:revert-last *driver* :count 3)\n \u003cINFO\u003e [21:26:14] cl-migratum.core core.lisp (revert-and-unregister base-driver) -\n  Reverting migration 20220327224455 - lisp_code_migration (LISP)\n \u003cINFO\u003e [21:26:14] cl-migratum.core core.lisp (revert-and-unregister base-driver) -\n  Reverting migration 20200605144633 - multiple_statements (SQL)\n \u003cINFO\u003e [21:26:14] cl-migratum.core core.lisp (revert-and-unregister base-driver) -\n  Reverting migration 20200421180337 - create_table_qux (SQL)\nNIL\n```\n\nNow, we should have 3 pending migrations again.\n\n``` common-lisp\nCL-USER\u003e (migratum:display-pending *driver*)\n.---------------------------------------------.\n|             PENDING MIGRATIONS              |\n+----------------+---------------------+------+\n| ID             | DESCRIPTION         | KIND |\n+----------------+---------------------+------+\n| 20200421180337 | create_table_qux    | SQL  |\n| 20200605144633 | multiple_statements | SQL  |\n| 20220327224455 | lisp_code_migration | LISP |\n+----------------+---------------------+------+\n|                | TOTAL               |    3 |\n+----------------+---------------------+------+\nNIL\n```\n\n### Creating New Migrations\n\nThe `MIGRATUM:PROVIDER-CREATE-MIGRATION` generic function creates a\nnew migration sequence. The arguments it expects are the `direction`\n(e.g. `:up` or `:down`), the migration `kind` (e.g. `:sql`, `:lisp`,\netc.), an instance of a `provider`, `id`, `description` and `content`.\n\nKnowing `migratum:provider-create-migration` by the documentation \nbelow, you can also use the wrapper \n`migratum.provider.local-path:touch-migration` to create a pair of \nup-and-down empty migrations with a `LOCAL-PATH` provider.\n\n#### SQL migrations\n\nHere's an example of using the `LOCAL-PATH` provider for creating a\nnew SQL migration.\n\n``` common-lisp\nCL-USER\u003e (defparameter *migration-id* (migratum:make-migration-id))\n*MIGRATION-ID*\nCL-USER\u003e\nCL-USER\u003e (migratum:provider-create-migration\n          :up            ;; \u003c- direction\n          :sql           ;; \u003c- kind\n          *provider*     ;; \u003c- provider\n          *migration-id* ;; \u003c- the migration id\n          \"fubar\"        ;; \u003c- description\n          \"CREATE ...\")  ;; \u003c- contents\n#\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:SQL-MIGRATION {1009570AD3}\u003e\n```\n\nThe downgrade migration is created in a similar way. Simply use the\n`:down` direction and the appropriate contents for it. Also, make sure\nthat the description and id are the same when creating a pair of\nupgrade/downgrade migrations.\n\n#### Lisp migrations\n\nThe `:lisp` migration kind allows invoking a handler, which performs\nthe upgrade and downgrade.\n\nThe handler is a regular Lisp function, which accepts a single\nargument that is an instance of a `driver`.\n\nIn order to create a `:lisp` migration you need to create a spec,\nwhich specifies the Common Lisp `system`, `package`, `upgrade` and\n`downgrade` handler.\n\nHere's an example of a spec, which is a regular property list.\n\n``` common-lisp\n(:system :my-system :package :my-system.package :handler :upgrade-handler)\n```\n\nAnd here's a full example of creating an `:up` and `:down` migration.\n\n``` common-lisp\nCL-USER\u003e (let ((id (migratum:make-migration-id))\n               (desc \"my lisp migration\")\n               (up-spec '(:system :my-system\n                          :package :my-system.package\n                          :handler :upgrade-handler))\n               (down-spec '(:system :my-system\n                            :package :my-system.package\n                            :handler :downgrade-handler)))\n           (values\n            (migratum:provider-create-migration :up :lisp *provider* id desc up-spec)\n            (migratum:provider-create-migration :down :lisp *provider* id desc down-spec)))\n#\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:LISP-MIGRATION {100A39C083}\u003e\n#\u003cCL-MIGRATUM.PROVIDER.LOCAL-PATH:LISP-MIGRATION {100A39D6C3}\u003e\n```\n\n### Multiple SQL Statements\n\nIf you need to run multiple SQL statements when using the `dbi` or\n`rdbms-postgresql` driver you can separate each statement in the\nmigration using the `--;;` separator.\n\nThe following example migration would create two tables as part of a\nsingle transaction.\n\n``` sql\nCREATE TABLE foo (\n    id INTEGER PRIMARY KEY\n);\n--;;\nCREATE TABLE bar (\n    id INTEGER PRIMARY KEY\n);\n```\n\n### Debug logging\n\n`cl-migratum` uses [log4cl](https://github.com/sharplispers/log4cl),\nso you can enable debug logging, if needed.\n\n``` common-lisp\nCL-USER\u003e (log:config :debug)\n```\n\n### Shutdown / Teardown\n\nOnce done with the migrations you should call the cleanup functions of\nthe `provider` and `driver`.\n\n``` common-lisp\nCL-USER\u003e (migratum:provider-shutdown *provider*)\nCL-USER\u003e (migratum:driver-shutdown *driver*)\n```\n\n## Implemeting new migration resources\n\nGenerally new migration resources will be implemented along with a\n`provider`, which discovers them.\n\nYou can implement a new migration resource by inheriting from the\n`MIGRATUM:BASE-MIGRATION` class.\n\nThe following generic functions should be implemented on the newly\ndefined class.\n\n| Method                    | Description                         |\n|---------------------------|-------------------------------------|\n| `MIGRATUM:MIGRATION-LOAD` | Loads the `:up` and `:down` scripts |\n| `MIGRATUM:MIGRATION-KIND` | Returns the kind of the migration   |\n\nThe following generic functions can be overriden, if needed.\n\n| Method                           | Description                                         |\n|----------------------------------|-----------------------------------------------------|\n| `MIGRATUM:MIGRATION-ID`          | Returns the unique migration id                     |\n| `MIGRATUM:MIGRATION-DESCRIPTION` | Returns description of the migration                |\n| `MIGRATUM:MIGRATION-APPLIED`     | Returns timestamp of when the migration was applied |\n\nExample implementation that loads migration resources from a remote\nHTTP server might look like this. The following code uses\n[Dexador](https://github.com/fukamachi/dexador) as the HTTP client.\n\n``` common-lisp\n(defun http-get (url)\n  \"HTTP GETs the given URL\"\n  (let ((contents (dex:get url :force-string t)))\n    contents))\n\n(defclass http-migration (base-migration)\n  ((up-script-url\n    :initarg :up-script-url\n    :initform (error \"Must specify URL to upgrade script\")\n    :accessor http-migration-up-script-url\n    :documentation \"URL to the upgrade script\")\n   (down-script-url\n    :initarg :down-script-url\n    :initform (error \"Must specify URL to downgrade script\")\n    :accessor http-migration-down-script-url\n    :documentation \"URL to the downgrade script\"))\n  (:documentation \"HTTP migration resource\"))\n\n(defmethod migration-load ((direction (eql :up)) (migration http-migration))\n  (http-get (http-migration-up-script-url migration)))\n\n(defmethod migration-load ((direction (eql :down)) (migration http-migration))\n  (http-get (http-migration-down-script-url migration)))\n```\n\nA provider should simply `MAKE-INSTANCE` of the `HTTP-MIGRATION` class by\nproviding values for the required slots while discovering migrations via\nthe `PROVIDER-LIST-MIGRATIONS` function.\n\n## Implementing new providers\n\nYou can implement custom `providers`, which can discover migration\nresources from various sources, e.g. local path, remote HTTP endpoints,\netc.\n\nEach `provider` determines the rules, which identify a resource as a\nvalid migration, so custom logic for discovering them can be\nimplemented by using your own provider. For example the `local-path`\nprovider considers files to be valid migrations, if they match a given\nregex pattern.\n\nIn order to create a new provider you should inherit from the\n`MIGRATUM:BASE-PROVIDER` class and implement the following generic\nfunctions on your newly defined class.\n\n| Method                               | Description                                |\n|--------------------------------------|--------------------------------------------|\n| `MIGRATUM:PROVIDER-LIST-MIGRATIONS`  | Responsible for discovering migrations     |\n| `MIGRATUM:PROVIDER-CREATE-MIGRATION` | Creates a new migration using the provider |\n\nThe following methods can be overriden, if needed.\n\n| Method                          | Description                                                  |\n|---------------------------------|--------------------------------------------------------------|\n| `MIGRATUM:PROVIDER-NAME`        | Returns a human-friendly name of the provider                |\n| `MIGRATUM:PROVIDER-INIT`        | Initializes the provider, if needed                          |\n| `MIGRATUM:PROVIDER-INITIALIZED` | Returns `T` if provider is initialized, `NIL` otherwise      |\n| `MIGRATUM:PROVIDER-SHUTDOWN`    | Shutdowns the provider and cleans up any allocated resources |\n\nYou can also check the [local-path\nprovider](./src/provider/local-path.lisp) implementation for some\nexample code.\n\n## Implementing new drivers\n\nA `driver` is responsible for communicating with the database we are\nmigrating and executes the upgrade and downgrade scripts.\n\nThe driver also takes care of registering applied migrations after\napplying an upgrade script and also unregistering them during\ndowngrade, thus it is the drivers' decision how to implement\nregistering and unregistering. For example the `dbi` builtin driver\nregisters applied migrations in the same database it is migrating, but\na custom driver could choose a different stategy instead, e.g. use a\nkey/value store, local files, or some remote endpoint instead.\n\nNew drivers can be implemented by inheriting from the\n`MIGRATUM:BASE-DRIVER` class. The following methods should be\nimplemented on new drivers.\n\n| Method                               | Description                                            |\n|--------------------------------------|--------------------------------------------------------|\n| `MIGRATUM:DRIVER-LIST-APPLIED`       | Returns the list of applied migrations                 |\n| `MIGRATUM:DRIVER-REGISTER-MIGRATION` | Registers/unregister a successfully applied migration  |\n| `MIGRATUM:DRIVER-APPLY-MIGRATION`    | Applies a migration according to the given `direction` |\n\nThe following methods can be overriden, if needed.\n\n| Method                        | Description                                                |\n|-------------------------------|------------------------------------------------------------|\n| `MIGRATUM:DRIVER-INIT`        | Initializes the driver, if needed                          |\n| `MIGRATUM:DRIVER-NAME`        | Returns the human-friendly name of the driver              |\n| `MIGRATUM:DRIVER-PROVIDER`    | Returns the `provider` used by the `driver`                |\n| `MIGRATUM:DRIVER-INITIALIZED` | Returns `T` if driver is initialized, `NIL` otherwise      |\n| `MIGRATUM:DRIVER-SHUTDOWN`    | Shutdowns the driver and cleans up any allocated resources |\n\nYou can check the [dbi driver](./src/driver/dbi.lisp) implementation\nfor some example code.\n\nAdditional methods can also be overriden, if needed. For example if\nyou need to have a different representation for the pending migrations\nyou can override the `MIGRATUM:DISPLAY-PENDING` method.\n\n## Tests\n\nTests are provided as part of the `cl-migratum.test` system.\n\nIn order to run the tests you can execute.\n\n``` common-lisp\nmake test\n```\n\nOr you can run the tests in a Docker container instead.\n\n## Contributing\n\n`cl-migratum` is hosted on\n[Github](https://github.com/dnaeon/cl-migratum). Please contribute by\nreporting issues, suggesting features or by sending patches using pull\nrequests.\n\n## Authors\n\n* Marin Atanasov Nikolov (dnaeon@gmail.com)\n\n## License\n\nThis project is Open Source and licensed under the [BSD\nLicense](http://opensource.org/licenses/BSD-2-Clause).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnaeon%2Fcl-migratum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdnaeon%2Fcl-migratum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdnaeon%2Fcl-migratum/lists"}