Commit Graph

4 Commits

Author SHA1 Message Date
Andrew Farries
0c7ecf2887
Move constraint name and expression into a new CheckConstraint struct (#107)
Move the `ConstraintName` and `Check` `string` fields on an
`alter_column` operation into a new `CheckConstraint` struct and make
validation a method on that new struct.

This is to facilitate being able to create tables and columns with
`CHECK` constraints in later PRs (#108, #109).
2023-09-19 10:49:40 +01:00
Andrew Farries
c1b8c65dd5
Make naming CHECK constraints mandatory (#99)
Make it required to supply a name for the `CHECK` constraint when adding
one with the `set_check_constraint` operation.

It should be possible to drop constraints with a later migration (not
yet implemented), so requiring a name and not relying on automatic
generation of constraint names will make this easier.

The same thing was done for indexes in
https://github.com/xataio/pg-roll/pull/59
2023-09-14 11:06:13 +01:00
Andrew Farries
6930e506c9
Move add foreign key and check constraint operations into alter_column (#92)
Move the `set_foreign_key` and `set_check_constraint` operations into
the new `alter_column` operation introduced in #91.

The pattern for moving the operations is the same as in #91:
* Update the example migrations to use the new operation type
* Remove serialization and deserialization logic for the individual
operations.
* Make the `alter_column` operation construct the right type of 'inner
operation'.
* Update tests for the foreign key and check constraint ops to use the
`alter_column` operation.
2023-09-14 05:42:41 +01:00
Andrew Farries
a105edd05e
Implement adding check constraints to existing columns (#83)
Add support for an operation to add a `CHECK` constraint to an existing
column. The new operation looks like this:

```json
{
  "name": "22_add_check_constraint",
  "operations": [
    {
      "set_check_constraint": {
        "table": "posts",
        "column": "title",
        "check": "length(title) > 3",
        "up": "(SELECT CASE WHEN length(title) <= 3 THEN LPAD(title, 4, '-') ELSE title END)",
        "down": "title"
      }
    }
  ]
}
```

This migrations adds a `CHECK (length(title) > 3)` constraint to the
`title` column on the `posts` table. Pre-existing values in the old
schema are rewritten to meet the constraint using the `up` SQL.

The implementation is similar to the **set not null**, **change column
type** and **set foreign key** operations.

* On `Start`:
* The column is duplicated and a `NOT VALID` `CHECK` constraint is added
to the new column.
* Values from the old column are backfilled into the new column using
`up` SQL.
* Triggers are created to copy values from old -> new with `up` SQL and
from new->old using `down` SQL.
* On `Complete`
  * The `CHECK` constraint is validated 
* The old column is dropped and the new column renamed to the name of
the old column.
* Postgres ensures that the `CHECK` constraint is also updated to apply
to the new column.
  * Triggers and trigger functions are removed.
* On `Rollback`
  * The new column is removed
  * Triggers and trigger functions are removed.

As with other operations involving `up` and `down` SQL, it is the user's
responsibility to ensure that values from the old schema that don't meet
the new `CHECK` constraint are correctly rewritten to meet the
constraint with `up` SQL. If the `up` SQL fails to produce a value that
meets the constraint, the migration will fail either at start (for
existing values in the old schema) or at runtime (for values written to
the old schema during the migration period).
2023-09-11 06:17:28 +01:00