Shape
array() wraps a scalar. picklist() narrows a string column. enum() creates a Postgres type.
Where this fits
A column is one value until you wrap it. An array repeats a scalar, a picklist narrows text, and an enum is a Postgres type. Names are what the database stores.
An array repeats one scalar. A picklist keeps the column as text and checks the value. An enum is its own Postgres type.
Array
.array() wraps a scalar. The SQL type gains one [] per rank. There is no second .array() call to add a dimension.
An empty array is a value. An element cannot be null. .nullable() makes the whole column null, not an element. A picklist or an enum is wrapped after it is declared: .picklist(values).array() or t.enum(name, labels).array().
dims | Result |
|---|---|
| omitted | Rank 1. text[]. |
2 to 6 | That many []. 2 is integer[][]. |
| outside 1 to 6 | Refused. |
one
Omit dims for a list.
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";
const notes = table("notes", {
id: t.identity(),
tags: t.text().array(),
});
const app = schema({ tables: [notes] });
export async function add(url: string) {
await using db = connect(url, { schema: app });
return db.notes.insert({ tags: ["ship"] });
}rank
dims is the rank. 2 is a matrix.
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";
const notes = table("notes", {
id: t.identity(),
grid: t.integer().array({ dims: 2 }),
});
const app = schema({ tables: [notes] });
export async function add(url: string) {
await using db = connect(url, { schema: app });
return db.notes.insert({ grid: [[1, 2]] });
}OKM1060
A rank outside 1 to 6 is refused. Calling .array() on a column that is already an array is refused.
OKM1210
A value that is not an array is rejected, and so is a null element. A rank that does not match dims is rejected when the value is read back.
Picklist
.picklist(values) narrows a string column to that union. A default has to be one of the values. .picklist(values).default("open") and .default("open").picklist(values) both check it.
check | Result |
|---|---|
| omitted | The catalog CHECK is column IN (...), in the order you listed. |
false | The list stays in the type. The catalog has no CHECK. Encode still rejects a value outside the list. |
check
The default writes the CHECK.
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";
const notes = table("notes", {
id: t.identity(),
status: t.text().picklist(["open", "done"]).default("open"),
});
const app = schema({ tables: [notes] });
export async function close(url: string, id: string) {
await using db = connect(url, { schema: app });
return db.notes.update({ where: { id }, set: { status: "done" } });
}type
{ check: false } keeps the union and skips the CHECK.
import { table, t } from "okmodel/pg";
export const notes = table("notes", {
id: t.identity(),
status: t.text().picklist(["open", "done"], { check: false }),
});OKM1060
An empty list, an empty value, or a repeated value is refused. A default outside the list is refused. The message names the value.
OKM1210
A value outside the list is rejected when it is encoded. The message names the accepted values.
Enum
t.enum(name, labels) creates a Postgres enum. The column type is that name, not text. Labels are stored in that order. The TypeScript type is the union of the labels. Two columns may share the name when the label lists match.
A picklist stays a string column and adds a CHECK. An enum is its own type. Adding a label, with the labels you already have still in that order, plans ALTER TYPE … ADD VALUE, and that step runs on its own. Removing a label, or changing their order, replaces the type and rewrites each column that uses it.
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";
const notes = table("notes", {
id: t.identity(),
status: t.enum("note_status", ["open", "done"]),
});
const app = schema({ tables: [notes] });
export async function open(url: string) {
await using db = connect(url, { schema: app });
return db.notes.insert({ status: "open" });
}OKM1060
An empty name, an empty list, an empty label, or a repeated label is refused.
OKM1210
A value outside the labels is rejected when it is encoded. The message names the accepted labels.
OKM1020
The same enum name with a different label list is refused. The message names both tables.