@@ -2,7 +2,7 @@
22
33[](https://github.com/fabianlindfors/reshape/actions/workflows/test.yaml) [](https://github.com/fabianlindfors/reshape/releases)
44
5−> Also check out [ReshapeDB](https://reshapedb.com), a new database built from the ground up to make zero-downtime schema and data migrations as simple and safe as possible
5+> Also check out [ReshapeDB](https://reshapedb.com), a new database built from the ground up to make zero-downtime schema and data migrations as simple and safe as possible. If you'd like to chat about it, please [reach out](contact@reshapedb.com)!
66
77Reshape is an easy-to-use, zero-downtime schema migration tool for Postgres. It automatically handles complex migrations that would normally require downtime or manual multi-step changes. During a migration, Reshape ensures both the old and new schema are available at the same time, allowing you to gradually roll out your application. It will also perform all changes without excessive locking, avoiding downtime caused by blocking other queries. For a more thorough introduction to Reshape, check out the [introductory blog post](https://fabianlindfors.se/blog/schema-migrations-in-postgres-using-reshape/).
88
@@ -243,6 +243,7 @@ primary_key = ["user_id"]
243243 type = "TEXT"
244244
245245 # Backfill from `users` table and copy `users.email` to `user_email` column
246+ # This will perform an upsert based on the primary key to avoid duplicate rows
246247 [actions.up]
247248 table = "users"
248249 values = { user_id = "id", user_email = "email" }
@@ -621,7 +622,7 @@ abort = """
621622
622623### Complex changes across tables
623624
624−The `up` and `down` options available for many actions can also perform more complex changes that span tables.
625+The `up` and `down` options available when creating tables, adding columns and removing columns can also perform more complex changes that span tables.
625626
626627_Example: move `email` column from `users` to `profiles` table_
627628
@@ -653,6 +654,57 @@ table = "profiles"
653654 where = "user_id = id"
654655```
655656
657+_Example: turn a 1:N relationship between `users` and `accounts` into N:M and change the format of the associated `role`_
658+
659+```toml
660+# Add `user_account_connections` as a junction table
661+[[actions]]
662+type = "create_table"
663+name = "user_account_connections"
664+primary_key = ["account_id", "user_id"]
665+
666+ [[actions.columns]]
667+ name = "account_id"
668+ type = "INTEGER"
669+
670+ [[actions.columns]]
671+ name = "user_id"
672+ type = "INTEGER"
673+
674+ # `role` is currently stored directly on the `users` table but is part of the relationship
675+ [[actions.columns]]
676+ name = "role"
677+ type = "TEXT"
678+
679+ # Backfill the new table from `users` and uppercase the `role`
680+ [actions.up]
681+ table = "users"
682+ values = { user_id = "id", account_id = "account_id", role = "UPPER(account_role)" }
683+ where = "user_id = id"
684+
685+[[actions]]
686+type = "remove_column"
687+table = "users"
688+column = "account_id"
689+
690+ # When `user_account_connections` is updated, we write the `account_id` back to `users`
691+ [actions.down]
692+ table = "user_account_connections"
693+ value = "account_id"
694+ where = "id = user_id"
695+
696+[[actions]]
697+type = "remove_column"
698+table = "users"
699+column = "account_role"
700+
701+ # When `user_account_connections` is updated, we write the lowercase role back to `users`
702+ [actions.down]
703+ table = "user_account_connections"
704+ value = "LOWER(role)"
705+ where = "id = user_id"
706+```
707+
656708## Commands and options
657709
658710### `reshape migration start`