casl-bridge
v1.5.0
Published
A query bridge between CASL rules and database ORMs
Readme
casl-bridge
A query bridge between CASL rules and TypeORM
Supports both CommonJS (require) and ESM (import).
Installation
This is a module available through the npm registry.
$ npm install casl-bridgeExamples
A simple demonstration...
async function main() {
const source = getTypeOrmSource()
const builder = new AbilityBuilder(createMongoAbility)
builder.can('read', 'Book', { id: 1 })
builder.can('read', 'Book', { 'author.id': 3 })
const ability = builder.build()
/* --------------------------------------
* link everything together with a bridge
*/
const bridge = new CaslBridge(source, ability)
}Basic Calls
/* --------------------------------------
* query all entries
*/
const books = await bridge
.createQueryTo('read', 'Book')
.getMany()
/* --------------------------------------
* query a single field
*/
const ids = await bridge
.createQueryTo('read', 'Book', 'id')
.getMany()
/* --------------------------------------
* select specific fields
*/
const select = ['id', 'title', ['author', ['name']]]
const names = await bridge
.createQueryTo('read', 'Book', select)
.limit(3)
.getMany()
/* --------------------------------------
* add extra mongo-like query filters
*/
const filter = { id: { $ge: 10, $le: 20 } }
const limited = await bridge
.createQueryTo('read', 'Book', select, filter)
.limit(3)
.getMany()
/* --------------------------------------
* using just the filter feature
*/
const filtered = await bridge
.createFilterFor('Book', {
'author.name': 'Jane Austen',
id: { $in: [2, 3, 5] },
})
.getMany()
/* --------------------------------------
* [experimental] apply filter to query
*/
const query = bookRepo
.createQueryBuilder('book')
.leftJoin('book.author', 'author')
.where('book.id > :bookId', { bookId: 3 })
bridge.applyFilterTo(query, 'author', {
name: 'Jane Austen'
})
const moreBooks = await query.getOne()
filterOptions
All three methods (createQueryTo, createFilterFor, applyFilterTo) accept an optional
filterOptions object to control how filter conditions are compiled and applied.
| Option | Type | Default | Description |
|---|---|---|---|
| maxDepth | number | undefined | Maximum number of relation hops permitted in an external filter. Omit to allow any depth. |
| onViolation | 'throw' \| 'false' \| 'strip' | 'throw' | How to handle a maxDepth or pathPolicy violation. |
| pathPolicy | PathPolicy | undefined | Allow/deny rules for field paths in external filters. |
| joinType | 'left' \| 'inner' | 'left' | SQL join type used for all joins generated by casl-bridge (both ability-derived rule joins and external filter joins). 'left' = LEFT JOIN; 'inner' = INNER JOIN. Does not affect joins already present on a user-supplied query builder. |
/* --------------------------------------
* use INNER JOIN for all library joins
*/
const results = await bridge
.createQueryTo({
action: 'read',
subject: 'Book',
filters: { author: { name: 'Jane Austen' } },
filterOptions: { joinType: 'inner' },
})
.getMany()Database Setup
import { DataSource } from 'typeorm'
/* --------------------------------------
* Our TypeOrm database connection
*/
const source = new DataSource({
type: 'better-sqlite3',
database: ':memory:',
dropSchema: true,
synchronize: true,
entities: [
AuthorSchema,
BookSchema
],
})
async function connect() {
await source.initialize()
/* --------------------------------------
* ...seed your database here
*/
}More docs
- Getting Started — prerequisites, minimal setup, common patterns, and troubleshooting
- CaslBridge API — full API reference with TypeScript signatures and examples
- CastleGuard API — filter validation and sanitization reference
