(p)repair is a project to help people reduce their consumption of products. Firstly, we bet on building a mobile application. You can read more in the project’s manifesto.

This article is part of the Migration to Ash series. Click for the summary, or just pick what you want here!


For more context, read our previous article: Migrate Ecto Schemas into Ash Resources (2/3)

After we did the migration of all our Ecto Schemas into Ash Resources, don’t forget to commit all these new Ash Resources (you’ll still be able to amend it if further modifications are needed), and then, it’s time to generate our first migration on Ash!

We can run the command that we’ve seen in the part 1 of this post series: [Migrate Ecto Schemas into Ash Resources 1/3]((p)repair / Blog / Migration to Ash series / Migrate Ecto Schemas into Ash Resources 1/3)

mix ash.codegen migrate_to_ash

This generates:

  • 1 migration file which installs Ash functions in our database (remember, we added a few code mentioning it inside our repo.ex file)
  • 1 migration file which defines a full migration from scratch for all our Ash Resources
  • 1 folder located at priv/resource_snapshots and containing snapshots for all our resources, which means an instant ‘picture’ of what is described inside our Ash Resources at the time we ran the mix ash.codegen command. We also talked about snapshots in the first article of this serie, so we don’t go further on explanations here.

We normally don’t need to do any changes inside the first migration file, in which Ash installs new functions in our database.

We don’t need to modify any resource_snapshot files contained in the resource_snapshot folder: it would create an offset between the picture of our Resource and the reality of our Resource, which is really not what we want.

Compare the Ash generated migration with our already existing database

Some of the commands you will find below are valable for the Postgresql database, but they may differ for other databases supported by Ash. You may need to do some adjustments on the first 2 commands.

Note: we assume you are using a tool to manage differences within your code (such as Git: we already wrote about commits several times). It will be really more easy to delete files and later cancel their deletion through the changes in your code when they are correctly tracked.

The easiest way to achieve a comparison is to:

  1. export our current database schema, and give the export file a name like legacy_database.sql
  2. delete all migrations files prior to the 2 files generated by Ash
  3. migrate our database with only the 2 files generated by Ash with the command mix ash.reset. It will drop our database, then recreate it, then migrate it accordingly to the migration files which are currently under the priv/repo/migrations path.
  4. export your database schema after this, and give the export file a name like ash_database.sql
  5. compare the 2 export files to see differences, with a tool such as meld

In our terminal, you can run commands such as:

### STEP 1:
pg_dump -U $USER -h $HOST -p $PORT -s -d $DB -f $LEGACY_SCHEMA_EXPORT

### STEP 2:
### nothing to do in the terminal, just delete all migrations files prior to the 2 files generated by Ash

### STEP 3:
mix ash.reset

### STEP 4:
pg_dump -U $USER -h $HOST -p $PORT -s -d $DB -f $ASH_SCHEMA_EXPORT

### STEP 5:
meld $LEGACY_SCHEMA_EXPORT $ASH_SCHEMA_EXPORT

For our project, it gives something like that:

pg_dump -U postgres -h localhost -p 5432 -s -d prepair_dev -f prepair_legacy.sql

### delete all migrations files prior to the 2 files generated by Ash

mix ash.reset

pg_dump -U postgres -h localhost -p 5432 -s -d preAnd finally, we can compare the 2 files with a comparing tool like meld:pair_dev -f prepair_ash.sql

meld prepair_legacy.sql prepair_ash.sql

You can also use other comparing tools at your convenience for comparing the 2 schemas.

Now that you have a view on the differences, you can see if you’ve done good work writing you Ash Resources to fit what was already on your database.

Adapt the Ash autogenerated migration

After you exported the 2 versions of your whole database schema, you can cancel the deletion of all your previous migrations files, otherwise it would be a break in the history of your project’s database migrations, it would not represent the reality, and it would prevent you from doing rollbacks if necessary.

The last steps are to:

  1. adapt your Ash Resource descriptions if needed, to remove a few differences you could still see between the 2 versions of your database schema → do again the all comparison we defined in this article and continue to iterate that way until there are no differences, or only differences you assume to be effectively part of your migration
  2. adapt the generated Ash migration to fit the differences you assume to be effectively part of your migration

In any case, you will:

  • keep all your precedent migration files
  • keep the first Ash autogenerated migration file which installs Ash functions

An then:

if there are no differences at all between your 2 exports (the legacy database schema and the one entirely created through the Ash autogenerated migration), you can simply keep the second Ash autogenerated migration file which create a full migration from all your Resource description, but remove all code from it. You can just let a comment to explain what happened like:

@moduledoc """
Migration to Ash.

No modifications in the database.

The resources snapshots at the time of this first autogenerated migration reflects perfectly the state of the database when all the previous migrations has been run.
"""

else, in the case you still have differences between the 2 versions of your database schema, you will need to adapt the autogenerated migration file, to keep only the description of changes to be done in the database to reflect your Ash Resource snapshots. You’ll need to adapt it up and down, to allow you doing a rollback later if necessary. Once it’s done, you can re-do the database exported schema comparison, but don’t delete the adapted Ash migration file, it is now part of your “legacy” export. And so your legacy export should now reflects perfectly the Ash fully autogenerated database migration from scratch.

Once you’re done with it, it means you fully migrated your application to now use Ash Resources as a description of your application tables and relations. You will then be able to enjoy all the fabulous features Ash has to offer you, and we will see that in further articles while continuing the migration of our Phoenix context functions to Ash Resources actions and code_interface.

You can run the migration, verify your application pass all tests, and commit all these changes you’ve done successfully ! 😃

See you in next article!