This checks for dangling temporary columns, triggers and function which
were used by migrations but should be removed once the migration has
been completed or aborted.
Improved backtrace support for errors in Rust is currently in progress:
https://github.com/rust-lang/rust/issues/53487. Adding the feature lets
anyhow add backtraces already which greatly improves readability of
errors in tests.
Column tracking refers to how temporary columns for a column are
tracked. This changes the tracking to use a single vector, the first
element is the original column name and subsequent ones are temporary
columns.
Migrations shouldn't need to know about any temporary schema changes
as they should already have been applied once the migration is going
to be completed.
This state is set as soon as a migration is started, before any
migrations are run. If a migration unexpectedly fails and doesn't abort
properly (which should happen automatically), the state will be left
dangling in `Applying`. In that case, it's fine for the user to run
migrate again as all migrations are idempotent.
Previously the column was added with its final name directly. This could
cause trouble if there was a column with the same name removed during
the same migration.
The previous implementation Schema couldn't handle some sequence of
migrations. For example when a temporary column is introduced for a
column and that column is then renamed. This new implementation keeps
track of all intermediate (temporary) columns to handle this.
This commit also greatly simplifies the API for `Schema`, creating a
single method on `TableChanges` and `ColumnChanges` for each possible
change: renaming, changing the backing column and removing.
This makes no difference right now but will make it easier to add
cross-compilation later as the cargo Github action has built-in support
for `cross`: https://github.com/actions-rs/cargo.
Before, we explicitly tracked the current schema and relied on that in
our migrations. This makes things more complicated as we need to keep
track of not just tables and columns but also primary keys, constraints
etc.
This commit remove the schema tracking and instead queries the
database for the current schema. During migrations, we temporarily store
the changes that are made, for example having temporary columns override
real ones and combine these with the current schema in the database.
This is handled in schema.rs.
These changes also broke our previously handling of triggers and
functions and how we detected if an insert/update was made against the
old or new schema during a migration. The previous method, using a
temporary __reshape_is_new column has been replaced with some helper
functions which inspect the search_path setting and uses that to
determine which schema is being used. During migrations, we can also set
the custom "reshape.is_old_schema" setting to force the old schema, for
example during batch updates.
This greatly simplifies the triggers as we can now simply call a helper
function in Postgres, `reshape.is_old_schema()`, to determine which
schema the modification was made for.
This is a first, small step in removing schema tracking entirely.
Instead we should probe the dabatase directly for the current schema.
This makes it easier to start using Reshape on an existing database
without having to specify the entire schema first.
Previously, having multiple alter_column actions for a single column
could cause issues as the triggers and batch updates referenced the
wrong columns.
This commit also simplifies the batch update procedure. Rather than
running the actual update on existing rows, a NOP update will be
run which in turn will trigger the triggers to update the new temporary
columns.
The alter_column was always using UPPER and LOWER rather than the passed
up and down settings. This commit also adjusts the column names for
temporary columns as multiple alter_columns actions would conflict if
they edited the same column. They still conflict in other places which
will be fixed later.
The context stores the index of the current migration and action. This
index is used to provide ordering of triggers as well as providing
unique names for things like temporary columns and procedures. The
Context struct exposes a prefix() function which returns a unique string
which can be used as a prefix to triggers, columns, procedures etc.