pgroll/examples/22_add_check_constraint.json
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

15 lines
325 B
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"
}
}
]
}