PostgreSQL schemas & enums
Two Postgres-specific organizational tools: named schemas for namespacing your tables, and native enum types.
pgSchema
A Postgres schema is a namespace inside a database. Create one and hang tables, enums and views off it:
import {pgSchema} from 'rado/postgres'
import {integer, text} from 'rado/postgres'
const app = pgSchema('app')
const User = app.table('user', {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: text().notNull()
})
Queries reference the schema-qualified name automatically:
select "id", "name" from "app"."user"
The schema object itself can be passed to db.create / db.drop:
await db.create(app, User) // create schema if not exists "app"; create table ...
await db.drop(app) // drop schema if exists "app" cascade
Everything a schema can contain:
app.table('user', {...})
app.enum('mood', ['sad', 'ok', 'happy'])
app.view('actives').as(...)
app.materializedView('stats').as(...)
MySQL has an equivalent mysqlSchema export in rado/mysql for
schema-qualified table names.
pgEnum
Native Postgres enums are real types in the database, created with
create type ... as enum:
import {pgEnum, pgTable} from 'rado/postgres'
const mood = pgEnum('mood', ['sad', 'ok', 'happy'])
const MoodEntry = pgTable('mood_entry', {
state: mood().notNull() // typed as 'sad' | 'ok' | 'happy'
})
The enum is a column factory: call it (optionally with a column name) wherever
you'd use a column type. The TypeScript type is the union of its values, so
db.insert(MoodEntry).values({state: 'grumpy'}) is a compile error, as it
should be.
Creating the type
When you db.create a table that uses an enum, rado emits the
create type statement for you first. The enum can also live inside a schema:
const app = pgSchema('app')
const mood = app.enum('mood', ['sad', 'ok', 'happy'])
Dropping
Dropping a table does not drop the type (other tables might use it). Remove it explicitly when you're sure:
import {sql} from 'rado'
await db.run(sql`drop type if exists ${sql.identifier('mood')}`)
Enums on other databases
SQLite and MySQL don't get pgEnum, but you can constrain text columns at the
type level with SQLite's text({enum: [...]}) option. You get the same TypeScript
ergonomics, no database-side enforcement:
import {text} from 'rado/sqlite'
status: text({enum: ['draft', 'published']}) // 'draft' | 'published'