Changelog - 2026-05-22
Schema-Qualified Casbin Tables
Breaking ChangeIn one line. DrizzleCasbinAdapter now targets a specific Postgres schema for its tables instead of relying on the connection's search_path.
What changed
- Per-entity
schemaName. Every entity (permission,role,policyDefinition) accepts an optionalschemaName, so the three tables may live in three different schemas; each defaults topublic. - Qualified SQL. Every
FROM/JOINnow reads"<schema>"."<table>", escaped viasql.identifier, instead of a bare table name. - Centralized resolution. A private
schemaOf()helper applies thepublicdefault at query-build time - no mutation of the caller-suppliedentitiesobject, no non-null assertions.
Who is affected
- Casbin tables already in the
publicschema. No action needed - the default reproduces the previous behavior. - Casbin tables in a non-
publicschema, relying onsearch_path. Must act - queries will fail to resolve the relation untilschemaNameis set explicitly. See breaking changes below.
Breaking changes
WARNING
Only affects deployments whose Casbin tables live outside the public schema and relied on search_path to resolve them.
Before (resolved via search_path):
typescript
new DrizzleCasbinAdapter({
dataSource,
entities: {
permission: { tableName: 'permissions', principalType: 'Permission' },
role: { tableName: 'roles', principalType: 'Role' },
policyDefinition: { tableName: 'policy_definitions', principalType: 'PolicyDefinition' },
},
});
// Emits: FROM "policy_definitions"After (explicit schema):
typescript
new DrizzleCasbinAdapter({
dataSource,
entities: {
permission: { schemaName: 'auth', tableName: 'permissions', principalType: 'Permission' },
role: { schemaName: 'auth', tableName: 'roles', principalType: 'Role' },
policyDefinition: {
schemaName: 'auth',
tableName: 'policy_definitions',
principalType: 'PolicyDefinition',
},
},
});
// Emits: FROM "auth"."policy_definitions"Migration step: add schemaName to every entity whose table is not in public. No change needed for tables already in public.
Details
NOTE
All three entities accept schemaName, so each table can live in a different schema. The current queries only read policy_definitions and permissions in a FROM/JOIN, so role.schemaName is accepted as configuration but does not yet affect emitted SQL.
| File | Package |
|---|---|
src/components/auth/authorize/adapters/drizzle-casbin.ts | core |
src/__tests__/authorize/drizzle-casbin-adapter.test.ts | core |