Drizzle ORM
The Schema File
Export converted slim schemas for drizzle-kit migrations.
Point drizzle.config.ts at one file that converts your declarations to real Drizzle objects with toDrizzle. Migrations see only its exports.
import * as DZ from '@mionjs/drizzle-orm-pg-core';
import {sql} from '@mionjs/drizzle-orm';
export const plan = DZ.pgEnum('plan', ['free', 'pro']);
export const invoiceSeq = DZ.pgSequence('invoice_seq', {startWith: 1000});
export const billing = DZ.pgSchema('billing');
export const reader = DZ.pgRole('reader').existing();
export const accounts = DZ.pgTable(
'accounts',
{
id: DZ.uuid('id', {defaultRandom: true, primaryKey: true}),
email: DZ.varchar('email', {length: 200, notNull: true}),
plan: plan('plan', {notNull: true, default: ['free']}),
spend: DZ.numeric('spend', {precision: 10, scale: 2, mode: 'number'}),
},
(t) => [
DZ.uniqueIndex('accounts_email_uidx').on(t.email),
DZ.check('accounts_spend_check', sql`${t.spend} >= 0`),
DZ.pgPolicy('accounts_reader', {
for: 'select',
to: reader,
using: sql`true`,
}),
]
).enableRLS();
export const paidAccounts = DZ.pgView('paid_accounts', {
id: DZ.uuid('id'),
email: DZ.varchar('email', {length: 200, notNull: true}),
}).as(sql`select id, email from ${accounts} where plan = 'pro'`);
export const auditPolicy = DZ.pgPolicy('accounts_audit', {
for: 'select',
to: 'postgres',
using: sql`true`,
}).link(accounts);
import {toDrizzle} from '@mionjs/drizzle-orm-pg-core/drizzle';
import {
accounts,
paidAccounts,
plan,
invoiceSeq,
billing,
reader,
auditPolicy as recordedAuditPolicy,
} from './drizzle-schema-authoring-example.ts';
export const accountsTable = toDrizzle(accounts);
export const paidAccountsView = toDrizzle(paidAccounts);
export const planEnum = toDrizzle(plan);
export const invoiceSequence = toDrizzle(invoiceSeq);
export const billingSchema = toDrizzle(billing);
export const readerRole = toDrizzle(reader);
export const auditPolicy = toDrizzle(recordedAuditPolicy);
Standalone Objects
Materializing a table or view also covers its columns, indexes, constraints and inline policies. drizzle-kit reads standalone objects on their own, so each one needs its own toDrizzle call:
| Declared with | Materialize |
|---|---|
pgTable, pgView, pgMaterializedView | the table or view itself |
pgEnum, pgSequence, pgSchema, pgRole | each handle |
pgPolicy(...).link(table) | the policy itself |
pgPolicy inside a table's third argument | nothing, it comes with the table |
Importing Types in Your App
Your routes, models and client never import this file. They take their types from the schema module that declares the tables:
import {accounts} from './schema.ts';
import type {InferSelectModel} from '@mionjs/drizzle-orm';
export type Account = InferSelectModel<typeof accounts>;
The file above is the only one that loads Drizzle, and it only runs when you generate or apply migrations.