Skip to content

Instantly share code, notes, and snippets.

@mdwheele
Last active January 7, 2025 19:22
Show Gist options
  • Save mdwheele/da321695477513e530c9df3833723b9a to your computer and use it in GitHub Desktop.
Save mdwheele/da321695477513e530c9df3833723b9a to your computer and use it in GitHub Desktop.
const { subject, createMongoAbility, AbilityBuilder } = require('@casl/ability')
const { rulesToQuery } = require('@casl/ability/extra')
const { CompoundCondition } = require('@ucast/core')
const { allInterpreters, createSqlInterpreter, mysql } = require('@ucast/sql')
const { can, cannot, build } = new AbilityBuilder(createMongoAbility)
// Imagine there is a "Category" of Posts that I cannot manage.
cannot('manage', 'Post', { id: 1 })
cannot('manage', 'Post', { id: 2 })
cannot('manage', 'Post', { id: 3 })
// But there is a single Post that I am allowed to manage within that Category.
can('manage', 'Post', { id: 1 })
const ability = build()
// We CAN update a post with id == 1...
console.log(
ability.can('update', subject('Post', { id: 1 }))
)
const interpret = createSqlInterpreter(allInterpreters)
const OPS_INVERTED = {
eq: 'ne',
ne: 'eq',
gt: 'lte',
gte: 'lt',
lt: 'gte',
lte: 'gt',
in: 'nin',
nin: 'in',
}
const { $and = [], $or = [] } = rulesToQuery(ability, 'update', 'Post', rule => {
if (!rule.ast) {
throw new Error('Unable to create knex query without AST')
}
if (rule.inverted) {
return {
...rule.ast,
operator: OPS_INVERTED[rule.ast.operator],
}
}
return rule.ast
})
const condition = new CompoundCondition('and', [
...$and,
new CompoundCondition('or', $or),
])
const [sql, replacements] = interpret(condition, {
...mysql,
paramPlaceholder: () => '?',
})
console.log()
console.log(`The matching SQL constraint would be...`)
console.log(` `, sql, replacements)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment