Skip to content

Commit

Permalink
Add UNIQUE constraints to pgroll's internal schema representation (
Browse files Browse the repository at this point in the history
…#242)

Add knowledge of `UNIQUE` constraints defined on a table to `pgroll`'s
internal schema representation.

`UNIQUE` constraints were already present as indexes, but this PR adds
them as their own top-level field in the `Table` schema and includes
information about the columns involved in the constraint.

Part of #105
  • Loading branch information
andrew-farries committed Jan 18, 2024
1 parent 70a7c8e commit 994a1aa
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 0 deletions.
11 changes: 11 additions & 0 deletions pkg/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ type Table struct {

// CheckConstraints is a map of all check constraints defined on the table
CheckConstraints map[string]CheckConstraint `json:"checkConstraints"`

// UniqueConstraints is a map of all unique constraints defined on the table
UniqueConstraints map[string]UniqueConstraint `json:"uniqueConstraints"`
}

type Column struct {
Expand Down Expand Up @@ -99,6 +102,14 @@ type CheckConstraint struct {
Definition string `json:"definition"`
}

type UniqueConstraint struct {
// Name is the name of the unique constraint in postgres
Name string `json:"name"`

// The columns that the unique constraint is defined on
Columns []string `json:"columns"`
}

func (s *Schema) GetTable(name string) *Table {
if s.Tables == nil {
return nil
Expand Down
17 changes: 17 additions & 0 deletions pkg/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,23 @@ BEGIN
AND cc_constraint.contype = 'c'
GROUP BY cc_constraint.oid
) AS cc_details
),
'uniqueConstraints', (
SELECT json_object_agg(uc_details.conname, json_build_object(
'name', uc_details.conname,
'columns', uc_details.columns
))
FROM (
SELECT
uc_constraint.conname,
array_agg(uc_attr.attname ORDER BY uc_constraint.conkey::int[]) AS columns,
pg_get_constraintdef(uc_constraint.oid) AS definition
FROM pg_constraint AS uc_constraint
INNER JOIN pg_attribute uc_attr ON uc_attr.attrelid = uc_constraint.conrelid AND uc_attr.attnum = ANY(uc_constraint.conkey)
WHERE uc_constraint.conrelid = t.oid
AND uc_constraint.contype = 'u'
GROUP BY uc_constraint.oid
) AS uc_details
),
'foreignKeys', (
SELECT json_object_agg(fk_details.conname, json_build_object(
Expand Down
47 changes: 47 additions & 0 deletions pkg/state/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ func TestReadSchema(t *testing.T) {
Name: "id_unique",
},
},
UniqueConstraints: map[string]schema.UniqueConstraint{
"id_unique": {
Name: "id_unique",
Columns: []string{"id"},
},
},
},
},
},
Expand Down Expand Up @@ -193,6 +199,47 @@ func TestReadSchema(t *testing.T) {
},
},
},
{
name: "unique constraint",
createStmt: "CREATE TABLE public.table1 (id int PRIMARY KEY, name TEXT, CONSTRAINT name_unique UNIQUE(name) );",
wantSchema: &schema.Schema{
Name: "public",
Tables: map[string]schema.Table{
"table1": {
Name: "table1",
Columns: map[string]schema.Column{
"id": {
Name: "id",
Type: "integer",
Nullable: false,
Unique: true,
},
"name": {
Name: "name",
Type: "text",
Unique: true,
Nullable: true,
},
},
PrimaryKey: []string{"id"},
Indexes: map[string]schema.Index{
"table1_pkey": {
Name: "table1_pkey",
},
"name_unique": {
Name: "name_unique",
},
},
UniqueConstraints: map[string]schema.UniqueConstraint{
"name_unique": {
Name: "name_unique",
Columns: []string{"name"},
},
},
},
},
},
},
}

// init the state
Expand Down

0 comments on commit 994a1aa

Please sign in to comment.