On this page
Work with enums, arrays and nested values
Use an SQL enum when the database must restrict a value to named labels. Seagull generates a Go type, constants and a Valid method. For collections and structured values, follow the separate array and DuckDB nested-value guides.
Declare the enum before the table
Add the enum and its table to your PostgreSQL migrations:
CREATE TYPE boat_status AS ENUM ('moored', 'at_sea', 'dry_dock');
CREATE TABLE boats (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL,
status boat_status NOT NULL DEFAULT 'moored'
);
Use the enum column directly in writes and reads:
-- sgl.query(SetStatus, execrows)
UPDATE boats SET status = $1 WHERE name = $2;
-- sgl.query(ListBoats, many)
SELECT name, status FROM boats ORDER BY id;
Run sgl generate; models.go declares BoatStatus and constants for the labels.
Use a generated enum constant
Construct store.New(database) and pass a constant rather than a free-form string:
if _, err := queries.SetStatus(ctx, store.SetStatusParams{Status: store.BoatStatusAtSea, Name: "Kittiwake"}); err != nil {
return fmt.Errorf("sending Kittiwake to sea: %w", err)
}
Validate an application-provided string before binding it. The example demonstrates that a value outside the enum labels fails validation and is refused by the server:
sunk := store.BoatStatus("sunk")
if err := queries.AddBoat(ctx, store.AddBoatParams{Name: "Wreck", Status: sunk}); err == nil {
return errors.New("adding a boat with status sunk: got no error, want the enum to refuse it")
}
fmt.Fprintf(output, "status %q: Valid() is %t, and the server refuses it, as it is not a boat_status label\n", sunk, sunk.Valid())
If callers need methods of their own, override the Go type with a type the driver can bind and read.
Check valid and invalid labels
From the Seagull repository root, run the enum example:
cd examples/postgres/007_enums
go test .
Set SGL_EXAMPLE_DSN to a disposable database before running this server-backed test; without it, the test skips. See running examples for connection setup.
The complete example produces:
status "sunk": Valid() is false, and the server refuses it, as it is not a boat_status label
ListBoats, where status is the generated store.BoatStatus:
Kittiwake at_sea store.BoatStatus
Salty Chip at_sea store.BoatStatus
Gull Wing dry_dock store.BoatStatus
Driftwood moored store.BoatStatus
BoatsWithStatus, where a go_type override makes status a harbour.Status:
Kittiwake out at sea harbour.Status
Salty Chip out at sea harbour.Status
Choose the scope of an enum override
A query-header go_type override changes only that query’s result column; its parameters keep the generated enum type. Put the override in a migration or configure a column override to affect model fields, direct projections and parameters. Set go.types.enum: string to use plain strings instead of generated enum types.
See the type mapping reference for the complete contract. The example browser exposes other engine variants; use their actual SQL rather than changing only the dialect name.