Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New operation: create_constraint #411

Closed
wants to merge 37 commits into from

Conversation

kvch
Copy link
Contributor

@kvch kvch commented Oct 17, 2024

This PR adds a new operation named create_constraint. Previously, we only supported adding constraints to columns. This operation lets us define table level constraints including multiple columns.

The operation supports foreign_key, check and unique constraint definition on tables.

Examples

Foreign key

{
  "name": "44_add_foreign_key_table_reference_constraint",
  "operations": [
    {
      "create_constraint": {
        "type": "foreign_key",
        "table": "tickets",
        "name": "fk_sellers",
        "columns": [
          "sellers_name",
          "sellers_zip"
        ],
        "references": {
          "table": "sellers",
          "columns": [
            "name",
            "zip"
          ],
          "on_delete": "CASCADE"
        }
      }
    }
  ]
}

Check

{
  "name": "45_add_table_check_constraint",
  "operations": [
    {
      "create_constraint": {
        "type": "check",
        "table": "tickets",
        "name": "check_zip_name",
        "check": "sellers_name IS NOT NULL AND sellers_zip < 1000",
        "up": "(SELECT 'noname', 999)",
        "down": "(SELECT sellers_name, sellers_zip FROM tickets WHERE sellers_name IS NOT NULL AND sellers_zip < 1000)"
      }
    }
  ]
}

Unique

{
  "name": "46_add_table_unique_constraint",
  "operations": [
    {
      "create_constraint": {
        "type": "unique",
        "table": "tickets",
        "name": "unique_zip_name",
        "columns": ["sellers_name", "sellers_zip"]
      }
    }
  ]
}

Related

Requires #413
Requires #426
Closes #81

@kvch kvch changed the title Add support for composite keys and multi-column foreign keys Add support for multi-column foreign keys Oct 17, 2024
@kvch kvch changed the title Add support for multi-column foreign keys New operation: create_constraint Nov 8, 2024
@kvch kvch marked this pull request as ready for review November 8, 2024 12:34
@JoachimKoenigslieb
Copy link

This seems super useful. Right now there is no other ways to add a UNIQUE constraint on a table that applies across columns right?

@ryanslade
Copy link
Collaborator

Drive by comment, I didn't do a full review, but the drop_constraint operation fails currently if the constraint was created against more than one column. Not sure if we want to change that here.

@kvch
Copy link
Contributor Author

kvch commented Nov 8, 2024

@JoachimKoenigslieb You can create a unique index on a table using create_index operation and specify a list of columns. When you add unique constraint to a column or groups of columns, PostgreSQL creates a unique index for it. So the outcome of both operation is the same, you can make sure that the values in those columns are unique.

@kvch
Copy link
Contributor Author

kvch commented Nov 8, 2024

@ryanslade If you are ok with reviewing a big PR, I am happy to add it. But to ease the burden on the reviewer, it would be better to address drop_constraint problems as a follow-up. Your choice.

@ryanslade
Copy link
Collaborator

@ryanslade If you are ok with reviewing a big PR, I am happy to add it. But to easy the burden on the reviewer, it would be better to address drop_constraint problems as a follow-up. Your choice.

Happy for it to be in another PR, just wanted to make sure you were aware of the limitation.

@kvch
Copy link
Contributor Author

kvch commented Nov 8, 2024

Created a follow up issue to track drop_constraint changes: #458

Copy link
Collaborator

@andrew-farries andrew-farries left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments.

Could this PR be split into three pieces? One each for CHECK, UNIQUE and FOREiGN KEY constraints. It think that's going to make the implementation and review easier.

I've only looked at the table levelCHECK constraints in detail so far. The implementation there adds the new constraint to the affected columns directly. In the case of single-column CHECK constraints added via the alter_column operation, the affected column is duplicated and backfilled and the constraint added to the new column. This gives us a 'zero downtime, multiversion' migration as the old column without the constraint is referenced by the old versioned view and the new column with the constraint is referenced from the new versioned view.

By adding the CHECK constraint directly to the columns, we break this as now both old and new versions of the schema will be affected by the constraint.

We will need to do the same thing for these potentially multi-column CHECK constraints as we do for the single column versions:

  • on Start : duplicate and backfill the affected columns and apply the constraint to the new columns.
  • on Complete: validate the check constraint
  • on Rollback: remove the duplicated columns

docs/README.md Outdated Show resolved Hide resolved
docs/README.md Outdated Show resolved Hide resolved
docs/README.md Show resolved Hide resolved
docs/README.md Outdated Show resolved Hide resolved
pkg/migrations/fk_reference_test.go Show resolved Hide resolved
pkg/migrations/op_add_column.go Show resolved Hide resolved
pkg/migrations/fk_reference.go Show resolved Hide resolved
pkg/migrations/op_create_constraint.go Show resolved Hide resolved
pkg/migrations/op_create_constraint.go Show resolved Hide resolved
kvch and others added 2 commits November 11, 2024 11:15
Co-authored-by: Andrew Farries <[email protected]>
Co-authored-by: Andrew Farries <[email protected]>
@kvch
Copy link
Contributor Author

kvch commented Nov 11, 2024

Turning it into draft and opening follow-up PRs.

@kvch kvch marked this pull request as draft November 11, 2024 13:28
kvch added a commit that referenced this pull request Nov 13, 2024
…h multiple columns (#459)

This PR adds a new operation named `create_constraint`. Previously, we
only supported adding constraints to columns. This operation lets us
define table level constraints including multiple columns.

The operation supports `unique` constraints for now. In a follow-up PR I
am adding `foreign_key` and `check` constraints as well.

### Unique

```json
{
  "name": "44_add_table_unique_constraint",
  "operations": [
    {
      "create_constraint": {
        "type": "unique",
        "table": "tickets",
        "name": "unique_zip_name",
        "columns": [
          "sellers_name",
          "sellers_zip"
        ],
        "up": {
          "sellers_name": "sellers_name",
          "sellers_zip": "sellers_zip"
        },
        "down": {
          "sellers_name": "sellers_name",
          "sellers_zip": "sellers_zip"
        }
      }
    }
  ]
}
```

### Related

Created from #411

---------

Co-authored-by: Andrew Farries <[email protected]>
Co-authored-by: Ryan Slade <[email protected]>
@kvch
Copy link
Contributor Author

kvch commented Nov 19, 2024

Closing as the last PR has been opened: #471

@kvch kvch closed this Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support multi-column foreign keys
4 participants