Row Level Security
Row level security is PostgreSQL only. drizzle-kit sees your roles and policies in your migrations, and your row types do not change.
import * as DZ from '@mionjs/drizzle-orm-pg-core';
import {sql} from '@mionjs/drizzle-orm';
export const appUser = DZ.pgRole('app_user', {
createDb: false,
createRole: false,
inherit: true,
});
// a managed role from your provider, say
export const authenticated = DZ.pgRole('authenticated').existing();
export const documents = DZ.pgTable(
'documents',
{
id: DZ.uuid('id', {defaultRandom: true, primaryKey: true}),
ownerId: DZ.uuid('owner_id', {notNull: true}),
title: DZ.varchar('title', {length: 200, notNull: true}),
body: DZ.text('body'),
},
(t) => [
DZ.index('documents_owner_idx').on(t.ownerId),
DZ.pgPolicy('documents_owner_reads', {
as: 'permissive',
for: 'select',
to: authenticated,
using: sql`${t.ownerId} = current_setting('app.user_id')::uuid`,
}),
DZ.pgPolicy('documents_owner_writes', {
as: 'permissive',
for: 'insert',
to: appUser,
withCheck: sql`${t.ownerId} = current_setting('app.user_id')::uuid`,
}),
]
).enableRLS();
// needs its own toDrizzle call in the schema file
export const adminReadsEverything = DZ.pgPolicy('documents_admin_reads', {
for: 'select',
to: 'postgres',
using: sql`true`,
}).link(documents);
// @ts-expect-error RLS is already enabled on this table
export const doubleEnabled = documents.enableRLS();
Database Roles
pgRole(name, config) declares a role for drizzle-kit to create. existing() marks a role that is already there, so drizzle-kit leaves it alone:
const appUser = pgRole('app_user', {createRole: true});
const authenticated = pgRole('authenticated').existing();
Security Policies
A policy declared in the table's third argument belongs to that table and comes with it. as, for, to, using and withCheck are Drizzle's own options.
A policy declared apart and attached with link() belongs to no table, so export it and materialize it yourself, or your migrations will not see it:
export const adminReads = pgPolicy('admin_reads', {for: 'select', using: sql`true`}).link(documents);
Enabling Row Level Security
enableRLS() turns row level security on for a table. You can call it only once: the type it returns drops the method, as in Drizzle.
Provider Policy Helpers
Helpers like crudPolicy from drizzle-orm/neon, and the predefined roles in drizzle-orm/supabase, are not wrapped here. Import them from Drizzle and put the result in the array as is:
import {crudPolicy} from 'drizzle-orm/neon';
pgTable('docs', {...}, () => [crudPolicy({role: admin, read: true, modify: false})]);