Development guide
This document is meant for developers of the Eyened database and ORM. It explains how to develop changes and how to create and test database migrations.
ORM Conventions
We use Annotated Declarative Syntax to specify columns. This has the advantages that the resulting ORM objects have type annotations and everything is very readable.
Column Definitions
- Every column should have a
Mappedtype declaration, e.g.MyColumn: Mapped[int] - Use
Optionalto create a nullable column, e.g.MyColumn: Mapped[Optional[int]] - Use
mapped_column()on the right hand side if necessary.mapped_column()derives the datatype and nullability from theMappedannotation.mapped_column()is not necessary if there are no additional arguments to pass such asindex,unique, ordefault - Specify VARCHAR lengths on the right, e.g.
MyColumn: Mapped[str] = mapped_column(String(64))will create aVARCHAR(64) - JSON should be coded as
Mapped[Dict[str,Any]] - ENUM columns should be defined as Python types. The left hand values should match the desired SQL ENUM. The right hand side is not relevant. To create
ENUM('OCT', 'CF'):Then set up the column as:class FeatureModalityEnum(enum.Enum):OCT = 1CF = 2MyColumn: Mapped[FeatureModalityEnum]
Relationships
To add new relationships, take a look at how they are currently set up in the ORM. For more information refer to the Relationship docs.
Naming Conventions
- Classmethods starting with
by_are selectors. For example,by_idin theImageInstanceclass will query the database and return an image object with the given ID. - Classmethods starting with
from_are alternative constructors. For example,from_imagesetsin theTaskclass will construct a Task object given lists of image IDs and other arguments needed to define a Task.
Migrations
We use Alembic for managing database migrations. This section explains our processes:
Setting up Alembic
Development Repository
Make sure eyened_orm is installed (see Getting Started). Alembic is installed with eyened_orm. Make sure the alembic command is available in the terminal.
To set up a testing environment, check the README here: https://github.com/Eyened/eyened-platform/tree/main/orm/migrations
Committing to Production
When committing migrations to production:
- Ensure all tests pass
- Create a pull request with the migration changes
- Get code review approval
- Merge to main branch
- Deploy the changes following the deployment procedure
Developing Migrations
-
Prepare a copy of the production database (see https://github.com/Eyened/eyened-platform/tree/main/orm/migrations)
-
Change the ORM code to reflect the desired change in database structure. See ORM Conventions above. Then navigate to the migrations directory:
Terminal window cd orm/migrations -
Auto-generate Alembic migration:
Terminal window alembic revision --autogenerate -m "my migration description"This will create a new migration file in
alembic/versions. Every migration*.pyscript contains two functions:upgrade()anddowngrade().upgrade()is the migration and will apply any changes necessary to make the database match the current state of the ORM. It should contain commands that apply your newly made changes to the database. If you auto-generate the migration without making any changes to the ORM (i.e., when DB and ORM are in sync), the function should be blank (pass). Thedowngrade()function contains instructions to undo the migration. -
Check if
alembic revision --autogenerate -m "test"leaves a blank migration file. If not, fix discrepancies and generate a new migration. -
Manually edit the migration functions
upgrade()anddowngrade() -
Once you are satisfied with the migration file, run the migration on the test database:
Terminal window alembic upgrade head -
If the migration fails, recreate the test database and then repeat steps 4-6 until the migration is successful.
-
The test database and test ORM are now in sync. Store the full SQL migration by running:
Terminal window ./generate_alembic_sql.shThis script is located in the
orm/migrationsdirectory. -
Push the changes on a branch with a convenient name that reflects the changes made. Submit a pull request.
Testing Migrations
Environment Setup
The ORM includes a utility to easily create a copy of the production database into a running MySQL server for testing. For this to work, the ORM needs access to the database credentials for both production and test databases. Add source.env (production) and test.env (test) files as explained in ORM Configuration.
Set up Alembic to work with your testing environment:
cd orm/migrationspython set_connection_string.py test.envThis sets up the connection string in alembic.ini based on the variables in the specified .env file. Replace test.env with the path to your test environment file.
Create Test Database
Once this is done, you have two options to populate the database:
-
Full Database Copy (Recommended, but might take a while):
Terminal window eorm database-mirror-full -c transfer-config.ymlThis creates a complete copy of the production database. The configuration file should specify source and target database settings.
-
Limited Data Copy (For a faster copy, e.g., during development work when you need to test a migration several times):
Terminal window eorm database-mirror-test -c transfer-config.ymlThis creates a small test database with only the data specified in
transfer-config.yml. The configuration file should specify source and target database settings and which objects to copy.
Both options will:
- Dump the production database to a temporary file
- Drop and re-create the test database
- Load the dump file into the new test database
Test the Migration
-
Check out the relevant
eyened_ormcommit/branch that you wish to test in your development repository (or test virtualenv set up for this purpose). -
Apply the migration on the test database (from the migrations directory):
Terminal window alembic upgrade headThis should always succeed. If there are issues with running the migration, it could be a bug or that other migrations have been applied in between. In this case, changing the
down_revisionmight be necessary. Be careful!
What to Test
Test any code the migration might affect, including at least:
- Data integrity after migration
- EyeNED viewer
- Importing images