Skip to content

Commit 27ffced

Browse files
authored
Implement support for enum ordering (#2111)
* Implement support for enum ordering * Handle cases where inserting after last element and slice has not already had capacity increased * Update version in end to end tests
1 parent a2b0622 commit 27ffced

File tree

10 files changed

+243
-6
lines changed

10 files changed

+243
-6
lines changed

internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/db.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/models.go

Lines changed: 90 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/querier.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/enum_ordering/postgresql/stdlib/go/query.sql.go

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- name: GetAll :many
2+
SELECT * FROM foo;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CREATE TYPE enum_type AS ENUM ('first', 'last');
2+
ALTER TYPE enum_type ADD VALUE 'afterlast' AFTER 'last';
3+
ALTER TYPE enum_type ADD VALUE 'third' AFTER 'first';
4+
ALTER TYPE enum_type ADD VALUE 'fourth' BEFORE 'last';
5+
ALTER TYPE enum_type ADD VALUE 'fifth' AFTER 'fourth';
6+
ALTER TYPE enum_type ADD VALUE 'second' BEFORE 'third';
7+
ALTER TYPE enum_type ADD VALUE 'beforefirst' BEFORE 'first';
8+
9+
CREATE TABLE foo (
10+
id SERIAL PRIMARY KEY
11+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"version": "2",
3+
"sql": [
4+
{
5+
"engine": "postgresql",
6+
"schema": "schema.sql",
7+
"queries": "query.sql",
8+
"gen": {
9+
"go": {
10+
"out" : "go",
11+
"package" : "db",
12+
"emit_interface": true,
13+
"emit_all_enum_values": true,
14+
"emit_enum_valid_method": true
15+
}
16+
}
17+
}
18+
]
19+
}

internal/engine/postgresql/parse.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ func translate(node *nodes.Node) (ast.Node, error) {
211211
return &ast.AlterTypeAddValueStmt{
212212
Type: rel.TypeName(),
213213
NewValue: makeString(n.NewVal),
214+
NewValHasNeighbor: len(n.NewValNeighbor) > 0,
215+
NewValNeighbor: makeString(n.NewValNeighbor),
216+
NewValIsAfter: n.NewValIsAfter,
214217
SkipIfNewValExists: n.SkipIfNewValExists,
215218
}, nil
216219
}

internal/sql/ast/alter_type_add_value_stmt.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package ast
33
type AlterTypeAddValueStmt struct {
44
Type *TypeName
55
NewValue *string
6+
NewValHasNeighbor bool
7+
NewValNeighbor *string
8+
NewValIsAfter bool
69
SkipIfNewValExists bool
710
}
811

internal/sql/catalog/types.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package catalog
33
import (
44
"errors"
55
"fmt"
6-
76
"github.com/kyleconroy/sqlc/internal/sql/ast"
87
"github.com/kyleconroy/sqlc/internal/sql/sqlerr"
98
)
@@ -197,20 +196,47 @@ func (c *Catalog) alterTypeAddValue(stmt *ast.AlterTypeAddValueStmt) error {
197196
return fmt.Errorf("type is not an enum: %T", stmt.Type)
198197
}
199198

200-
newIndex := -1
199+
existingIndex := -1
201200
for i, val := range enum.Vals {
202201
if val == *stmt.NewValue {
203-
newIndex = i
202+
existingIndex = i
204203
}
205204
}
206-
if newIndex >= 0 {
205+
206+
if existingIndex >= 0 {
207207
if !stmt.SkipIfNewValExists {
208-
return fmt.Errorf("type %T already has value %s", stmt.Type, *stmt.NewValue)
208+
return fmt.Errorf("enum %s already has value %s", enum.Name, *stmt.NewValue)
209209
} else {
210210
return nil
211211
}
212212
}
213-
enum.Vals = append(enum.Vals, *stmt.NewValue)
213+
214+
if stmt.NewValHasNeighbor {
215+
insertIndex := -1
216+
for i, val := range enum.Vals {
217+
if val == *stmt.NewValNeighbor {
218+
if stmt.NewValIsAfter {
219+
insertIndex = i + 1
220+
} else {
221+
insertIndex = i
222+
}
223+
}
224+
}
225+
226+
if insertIndex == -1 {
227+
return fmt.Errorf("enum %s unable to find existing neighbor value %s for new value %s", enum.Name, *stmt.NewValNeighbor, *stmt.NewValue)
228+
}
229+
230+
if insertIndex == len(enum.Vals) {
231+
enum.Vals = append(enum.Vals, *stmt.NewValue)
232+
} else {
233+
enum.Vals = append(enum.Vals[:insertIndex+1], enum.Vals[insertIndex:]...)
234+
enum.Vals[insertIndex] = *stmt.NewValue
235+
}
236+
} else {
237+
enum.Vals = append(enum.Vals, *stmt.NewValue)
238+
}
239+
214240
return nil
215241
}
216242

0 commit comments

Comments
 (0)