prisma-extension-casl
Version:
Enforce casl abilities on prisma client
58 lines (53 loc) • 2.01 kB
text/typescript
import { AbilityTuple, PureAbility } from '@casl/ability'
import { PrismaQuery } from '@casl/prisma'
import { getPermittedFields, relationFieldsByModel } from './helpers'
/**
* gets permitted fields for current model
* and adds select query with only permitted properties
* and if args has include, it will be converted to select
*
* @param abilities Casl prisma abilities
* @param args query
* @param model prisma model
* @returns enriched query with selection of fields considering casl authorization
*/
export function applySelectPermittedFields(abilities: PureAbility<AbilityTuple, PrismaQuery>, args: any, model: string) {
const permittedFields = getPermittedFields(abilities, 'read', model)
if (permittedFields) {
// prepare select statement and transform include to select if necessary
if (args === true) {
args = {
select: {}
}
}
if (args.include) {
args.select = { ...args.include }
delete args.include
}
if (!args.select) {
args.select = {}
}
const queriedFields = args.select ? Object.keys(args.select) : []
// remove all fields that are not a relation or not permitted
const remainingFields = queriedFields.filter((field) => {
const isRelation = relationFieldsByModel[model][field] ? true : false
if (!(permittedFields.includes(field)) && !isRelation) {
delete args.select[field]
return false
} else if (isRelation) {
return false
}
return true
})
// if not fields are left, we use a default query of all permitted fields of the model
if (remainingFields.length === 0) {
permittedFields.forEach((field) => {
args.select = {
...args.select,
[]: true
}
})
}
}
return args
}