UNPKG

prisma-rls

Version:

Prisma client extension for row-level security on any database

196 lines (195 loc) 13.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createRlsExtension = void 0; const extension_1 = require("@prisma/client/extension"); const library_1 = require("@prisma/client/runtime/library"); const errors_1 = require("./errors"); const logic_1 = require("./logic"); const utils_1 = require("./utils"); const createRlsExtension = ({ dmmf, permissionsConfig, context, authorizationError, checkRequiredBelongsTo }) => { const fieldsMap = (0, utils_1.buildFieldsMap)(dmmf); if (!authorizationError) { authorizationError = new errors_1.AuthorizationError(); } return extension_1.Prisma.defineExtension((prismaClient) => { return prismaClient.$extends({ name: "prisma-rls", query: { $allModels: { async $allOperations(rawAllOperationsArgs) { const allOperationsArgs = rawAllOperationsArgs; const { model: modelName, operation: operationName, args, query } = allOperationsArgs; const modelPermissions = permissionsConfig[modelName]; const modelResolver = new logic_1.ModelResolver(permissionsConfig, context, fieldsMap, authorizationError, !!checkRequiredBelongsTo); switch (operationName) { case "findUnique": case "findUniqueOrThrow": { if (!modelPermissions.read && operationName === "findUnique") { return Promise.resolve(null); } else if (!modelPermissions.read && operationName === "findUniqueOrThrow") { throw new library_1.PrismaClientKnownRequestError(`No ${modelName} found`, { code: "P2025", clientVersion: extension_1.Prisma.prismaVersion.client, }); } const relationsMetadata = []; const [selectAndInclude, where] = await Promise.all([ modelResolver.resolveSelectAndInclude(modelName, args.select, args.include, relationsMetadata, { path: "$" }), modelResolver.resolveWhereUnique(modelPermissions.read, modelName, args.where), ]); const result = await query({ ...args, ...selectAndInclude, where }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "findFirst": case "findFirstOrThrow": case "findMany": { if (!modelPermissions.read && operationName === "findFirst") { return Promise.resolve(null); } else if (!modelPermissions.read && operationName === "findFirstOrThrow") { throw new library_1.PrismaClientKnownRequestError(`No ${modelName} found`, { code: "P2025", clientVersion: extension_1.Prisma.prismaVersion.client, }); } else if (!modelPermissions.read && operationName === "findMany") { return Promise.resolve([]); } const relationsMetadata = []; const recursiveContext = { path: operationName === "findMany" ? "$.*" : "$" }; const [selectAndInclude, where] = await Promise.all([ modelResolver.resolveSelectAndInclude(modelName, args.select, args.include, relationsMetadata, recursiveContext), modelResolver.resolveWhere(modelPermissions.read, modelName, args.where), ]); const result = await query({ ...args, ...selectAndInclude, where }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "aggregate": case "count": case "groupBy": { if (!modelPermissions.read && operationName === "aggregate") { return query({ ...args, where: (0, utils_1.generateImpossibleWhere)(fieldsMap[modelName]) }); } else if (!modelPermissions.read && operationName === "count") { return query({ ...args, where: (0, utils_1.generateImpossibleWhere)(fieldsMap[modelName]) }); } else if (!modelPermissions.read && operationName === "groupBy") { return Promise.resolve([]); } return query({ ...args, where: await modelResolver.resolveWhere(modelPermissions.read, modelName, args.where) }); } case "create": { if (!modelPermissions.create) { throw authorizationError; } const relationsMetadata = []; const [selectAndInclude, data] = await Promise.all([ modelResolver.resolveSelectAndInclude(modelName, args.select, args.include, relationsMetadata, { path: "$" }), modelResolver.resolveCreate(modelName, args.data), ]); const result = await query({ ...args, ...selectAndInclude, data }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "createMany": { if (!modelPermissions.create) { throw authorizationError; } return query(args); } case "createManyAndReturn": { if (!modelPermissions.create) { throw authorizationError; } return query(args); } case "update": { if (!modelPermissions.update) { throw authorizationError; } const relationsMetadata = []; const [selectAndInclude, data, where] = await Promise.all([ modelResolver.resolveSelectAndInclude(modelName, args.select, args.include, relationsMetadata, { path: "$" }), modelResolver.resolveUpdate(modelName, args.data), modelResolver.resolveWhereUnique(modelPermissions.update, modelName, args.where), ]); const result = await query({ ...args, ...selectAndInclude, data, where }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "updateMany": { if (!modelPermissions.update) { throw authorizationError; } const relationsMetadata = []; const result = await query({ ...args, where: await modelResolver.resolveWhere(modelPermissions.update, modelName, args.where) }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "upsert": { if (!modelPermissions.create || !modelPermissions.update) { throw authorizationError; } const relationsMetadata = []; const [selectAndInclude, create, update, where] = await Promise.all([ modelResolver.resolveSelectAndInclude(modelName, args.select, args.include, relationsMetadata, { path: "$" }), modelResolver.resolveCreate(modelName, args.create), modelResolver.resolveUpdate(modelName, args.update), modelResolver.resolveWhereUnique(modelPermissions.update, modelName, args.where), ]); const result = await query({ ...args, ...selectAndInclude, create, update, where }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "delete": { if (!modelPermissions.delete) { throw authorizationError; } const relationsMetadata = []; const [selectAndInclude, where] = await Promise.all([ modelResolver.resolveSelectAndInclude(modelName, args.select, args.include, relationsMetadata, { path: "$" }), modelResolver.resolveWhereUnique(modelPermissions.delete, modelName, args.where), ]); const result = await query({ ...args, ...selectAndInclude, where }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } case "deleteMany": { if (!modelPermissions.delete) { throw authorizationError; } const relationsMetadata = []; const result = await query({ ...args, where: await modelResolver.resolveWhere(modelPermissions.delete, modelName, args.where) }); if (checkRequiredBelongsTo) { return modelResolver.performRelationProcessing((0, utils_1.getTransactionClient)(prismaClient, allOperationsArgs), result, relationsMetadata); } return result; } default: { return query(args); } } }, }, }, }); }); }; exports.createRlsExtension = createRlsExtension;