Skip to content

Create a database migration

All Invenio modules that provide database tables, must in addition to the SQLALchemy model also provide a database migration recipe which add, remove or modify the tables.

In the following example, we'll use Invenio-RDM-Records as an example module.

No alembic folder?

If the module you are working at does not have the alembic folder it means that there is no branch for it. Therefore the first step is to create the branch with the following command: invenio alembic revision --empty --branch <module_name> "<message>"

Step 1 - Install development module

First, install your Invenio module in a virtual environment

mkvirtualenv rdm-records
pip install -e ".[all,postgresql,elasticsearch7]"

Step 2 - Boot services

Next, boot the containers that you will also use for testing.

Check the exact command to run for booting the services in the run-tests.sh script.

cat ./run-tests.sh

Then run the command you found in run-tests.sh which would look similar to the one below:

eval "$(docker-services-cli up --db ${DB:-postgresql} --search ${SEARCH:-elasticsearch} --mq redis --env)"

Last, export an environment variable (SQLALCHEMY_DATABASE_URI gets added by docker-services-cli):

export INVENIO_SQLALCHEMY_DATABASE_URI=${SQLALCHEMY_DATABASE_URI}

Step 3 - Upgrade database to latest head

Next, you need to get the database to the head state, so that you can use Alembic to auto-generate a migration by comparing the code-level models with the database tables:

invenio db drop
invenio alembic upgrade

Step 4 - Find you parent recipe

Next, you need to find the parent recipe which your recipe should depend on. Run the following command, to show the latest heads for each of the different branches.

invenio alembic heads

Note, some migrations may need to depend both on a parent migration recipe as well as a migration recipe in another module (e.g. a table that creates a foreign key to a table defined in another module).

Step 5 - Create the migration recipe

Next, create your recipe:

invenio alembic revision -p <id of parent> -d <list of dependent ids> "Create bla bla."

Check the output path and move it into your module:

mv <path in output> invenio_rdm_records/alembic/

Please check the created recipe in detail. You'll as a minimum need to format the code according to the code style for tests not to break. See also troubleshooting guide below.

Step 6 - Update the unit test

Last, you need to update the unit test usually located in tests/test_alembic.py (test failure should tell you what to update).

Note that, if your module tests are adding mock modules with database tables you may need to filter those out in the tests.

Troubleshooting

Often, you'll find your answers by looking in previous migration recipes.

UUIDType and JSONType

If the tables use UUIDType or JSONType you'll need to add an import to the script:

from sqlalchemy_utils import JSONType, UUIDType

Failing alembic commands

While upgrading your database or trying to auto-generate migrations you may encounter exceptions from alembic. Often, this can be due to an older broken migration or failed SQL statement execution. In these cases, you can try to identify the failing migration and disable the failing parts.

Can I edit an existing Alembic migration?

You are allowed to edit an existing (i.e. already committed) Alembic migration if and only if the migration has not been released as part of Invenio Framework InvenioRDM or InvenioILS.

If you edit a migration that may already be in use in a production system, you risk to put the that production system in an inconsistent state once the following migrations are applied.

command not found: invenio

If the "invenio" command cannot be found, then simply install Invenio-App:

pip install invenio-app