UNPKG

@cerbos/orm-prisma

Version:

Prisma adapter for Cerbos query plans

1,336 lines 166 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const _1 = require("."); const globals_1 = require("@jest/globals"); const client_1 = require("@prisma/client"); const grpc_1 = require("@cerbos/grpc"); const prisma = new client_1.PrismaClient(); const cerbos = new grpc_1.GRPC("127.0.0.1:3593", { tls: false }); function createConditionalPlan(condition) { return { kind: _1.PlanKind.CONDITIONAL, condition, cerbosCallId: "", requestId: "", validationErrors: [], metadata: undefined, }; } function getExpressionOperand(expression, index) { const operand = expression.operands[index]; if (!operand) { throw new Error(`Missing operand at index ${index}`); } return operand; } const fixtureUsers = [ { id: "user1", aBool: true, aNumber: 1, aString: "string", }, { id: "user2", aBool: true, aNumber: 2, aString: "string", }, ]; const fixtureNextLevelResources = [ { id: "nextLevel1", aBool: true, aNumber: 1, aString: "string", }, { id: "nextLevel2", aBool: false, aNumber: 1, aString: "string", }, { id: "nextLevel3", aBool: true, aNumber: 1, aString: "string", }, ]; const fixtureTags = [ { id: "tag1", name: "public", }, { id: "tag2", name: "private", }, { id: "tag3", name: "draft", }, ]; const fixtureNestedResources = [ { id: "nested1", aBool: true, aNumber: 1, aString: "string", nextlevel: { connect: { id: "nextLevel1", }, }, }, { id: "nested2", aBool: false, aNumber: 1, aString: "string", nextlevel: { connect: { id: "nextLevel2", }, }, }, { id: "nested3", aBool: true, aNumber: 1, aString: "string", nextlevel: { connect: { id: "nextLevel3", }, }, }, ]; const fixtureLabels = [ { id: "label1", name: "important" }, { id: "label2", name: "archived" }, { id: "label3", name: "flagged" }, ]; const fixtureSubCategories = [ { id: "sub1", name: "finance", labels: { connect: [{ id: "label1" }, { id: "label2" }], }, }, { id: "sub2", name: "tech", labels: { connect: [{ id: "label2" }, { id: "label3" }], }, }, ]; const fixtureCategories = [ { id: "cat1", name: "business", subCategories: { connect: [{ id: "sub1" }], }, }, { id: "cat2", name: "development", subCategories: { connect: [{ id: "sub2" }], }, }, ]; const fixtureResources = [ { id: "resource1", aBool: true, aNumber: 1, aString: "string", aOptionalString: "optionalString", createdBy: { connect: { id: "user1", }, }, ownedBy: { connect: [ { id: "user1", }, ], }, nested: { connect: { id: "nested1", }, }, tags: { connect: [ { id: "tag1" }, // public ], }, categories: { connect: [{ id: "cat1" }], }, }, { id: "resource2", aBool: false, aNumber: 2, aString: "string2", createdBy: { connect: { id: "user2", }, }, ownedBy: { connect: [ { id: "user2", }, ], }, nested: { connect: { id: "nested3", }, }, tags: { connect: [ { id: "tag2" }, // private ], }, categories: { connect: [{ id: "cat2" }], }, }, { id: "resource3", aBool: false, aNumber: 3, aString: "string3", createdBy: { connect: { id: "user1", }, }, ownedBy: { connect: [ { id: "user1", }, { id: "user2", }, ], }, nested: { connect: { id: "nested3", }, }, tags: { connect: [ { id: "tag1" }, // public { id: "tag3" }, // draft ], }, categories: { connect: [{ id: "cat1" }, { id: "cat2" }], }, }, ]; (0, globals_1.beforeAll)(async () => { await prisma.resource.deleteMany(); await prisma.nextLevelNestedResource.deleteMany(); await prisma.nestedResource.deleteMany(); await prisma.tag.deleteMany(); await prisma.user.deleteMany(); }); (0, globals_1.beforeEach)(async () => { for (const tag of fixtureTags) { await prisma.tag.create({ data: tag }); } for (const user of fixtureUsers) { await prisma.user.create({ data: user }); } for (const resource of fixtureNextLevelResources) { await prisma.nextLevelNestedResource.create({ data: resource }); } for (const resource of fixtureNestedResources) { await prisma.nestedResource.create({ data: resource }); } for (const label of fixtureLabels) { await prisma.label.create({ data: label }); } for (const subCategory of fixtureSubCategories) { await prisma.subCategory.create({ data: subCategory }); } for (const category of fixtureCategories) { await prisma.category.create({ data: category }); } for (const resource of fixtureResources) { await prisma.resource.create({ data: resource }); } }); (0, globals_1.afterEach)(async () => { await prisma.resource.deleteMany(); await prisma.nestedResource.deleteMany(); await prisma.nextLevelNestedResource.deleteMany(); await prisma.tag.deleteMany(); await prisma.user.deleteMany(); await prisma.category.deleteMany(); await prisma.subCategory.deleteMany(); await prisma.label.deleteMany(); }); // Core Functionality (0, globals_1.describe)("Basic Plan Types", () => { (0, globals_1.test)("always allowed", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "always-allow", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.ALWAYS_ALLOWED); const result = (0, _1.queryPlanToPrisma)({ queryPlan, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.ALWAYS_ALLOWED, }); const query = await prisma.resource.findMany({}); (0, globals_1.expect)(query.length).toEqual(fixtureResources.length); }); (0, globals_1.test)("always denied", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "always-deny", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.ALWAYS_DENIED); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: {}, }); (0, globals_1.expect)(result).toEqual({ kind: _1.PlanKind.ALWAYS_DENIED, }); }); }); // Field Operations (0, globals_1.describe)("Field Operations", () => { (0, globals_1.describe)("Basic Field Tests", () => { (0, globals_1.test)("conditional - eq", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "equal", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "eq", operands: [{ name: "request.resource.attr.aBool" }, { value: true }], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aBool": { field: "aBool" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aBool: { equals: true } }, }); const query = await prisma.resource.findMany({ where: result.kind === _1.PlanKind.CONDITIONAL ? { ...result.filters } : {}, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources.filter((a) => a.aBool).map((r) => r.id)); }); (0, globals_1.test)("conditional - eq - inverted order", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "equal", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "eq", operands: [{ name: "request.resource.attr.aBool" }, { value: true }], }); const typeQp = queryPlan; const invertedQueryPlan = { ...typeQp, condition: { ...typeQp.condition, operands: [ getExpressionOperand(typeQp.condition, 1), getExpressionOperand(typeQp.condition, 0), ], }, }; const result = (0, _1.queryPlanToPrisma)({ queryPlan: invertedQueryPlan, mapper: { "request.resource.attr.aBool": { field: "aBool" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aBool: { equals: true } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources.filter((a) => a.aBool).map((r) => r.id)); }); (0, globals_1.test)("conditional - ne", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "ne", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "ne", operands: [ { name: "request.resource.attr.aString" }, { value: "string" }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aString": { field: "aString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aString: { not: "string" } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources.filter((a) => a.aString != "string").map((r) => r.id)); }); (0, globals_1.test)("conditional - explicit-deny", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "explicit-deny", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "not", operands: [ { operator: "eq", operands: [ { name: "request.resource.attr.aBool" }, { value: true }, ], }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aBool": { field: "aBool" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { NOT: { aBool: { equals: true } } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources.filter((a) => !a.aBool).map((r) => r.id)); }); }); (0, globals_1.describe)("Comparison Tests", () => { (0, globals_1.test)("conditional - gt", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "gt", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "gt", operands: [{ name: "request.resource.attr.aNumber" }, { value: 1 }], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aNumber": { field: "aNumber" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aNumber: { gt: 1 }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((r) => { return r.aNumber > 1; }) .map((r) => r.id)); }); (0, globals_1.test)("conditional - lt", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "lt", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "lt", operands: [{ name: "request.resource.attr.aNumber" }, { value: 2 }], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aNumber": { field: "aNumber" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aNumber: { lt: 2 }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((r) => { return r.aNumber < 2; }) .map((r) => r.id)); }); (0, globals_1.test)("conditional - gte", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "gte", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "ge", operands: [{ name: "request.resource.attr.aNumber" }, { value: 1 }], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aNumber": { field: "aNumber" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aNumber: { gte: 1 }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((r) => { return r.aNumber >= 1; }) .map((r) => r.id)); }); (0, globals_1.test)("conditional - lte", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "lte", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "le", operands: [{ name: "request.resource.attr.aNumber" }, { value: 2 }], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aNumber": { field: "aNumber" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aNumber: { lte: 2 }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((r) => { return r.aNumber <= 2; }) .map((r) => r.id)); }); }); (0, globals_1.describe)("String Tests", () => { (0, globals_1.test)("conditional - contains", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "contains", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operands: [ { name: "request.resource.attr.aString", }, { value: "str", }, ], operator: "contains", }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aString": { field: "aString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aString: { contains: "str" } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((a) => a.aString.includes("str")) .map((r) => r.id)); }); (0, globals_1.test)("conditional - startsWith", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "starts-with", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operands: [ { name: "request.resource.attr.aString", }, { value: "str", }, ], operator: "startsWith", }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aString": { field: "aString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aString: { startsWith: "str" } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((a) => a.aString.startsWith("str")) .map((r) => r.id)); }); (0, globals_1.test)("conditional - endsWith", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "ends-with", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operands: [ { name: "request.resource.attr.aString", }, { value: "ing", }, ], operator: "endsWith", }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aString": { field: "aString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aString: { endsWith: "ing" } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((a) => a.aString.endsWith("ing")) .map((r) => r.id)); }); (0, globals_1.test)("conditional - isSet", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "is-set", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operands: [ { name: "request.resource.attr.aOptionalString", }, { value: null, }, ], operator: "ne", }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aOptionalString": { field: "aOptionalString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aOptionalString: { not: null } }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources.filter((a) => a.aOptionalString).map((r) => r.id)); }); }); }); // Collection Operations (0, globals_1.describe)("Collection Operations", () => { (0, globals_1.describe)("Basic Collections", () => { (0, globals_1.test)("conditional - in", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "in", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "in", operands: [ { name: "request.resource.attr.aString" }, { value: ["string", "anotherString"] }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aString": { field: "aString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aString: { in: ["string", "anotherString"] }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((r) => { return ["string", "anotherString"].includes(r.aString); }) .map((r) => r.id)); }); (0, globals_1.test)("conditional - in - scalar value", async () => { const queryPlan = createConditionalPlan({ operator: "in", operands: [ { name: "request.resource.attr.aString" }, { value: "string" }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.aString": { field: "aString" }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { aString: "string" }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id).sort()).toEqual(fixtureResources .filter((r) => r.aString === "string") .map((r) => r.id) .sort()); }); (0, globals_1.test)("conditional - relation in", async () => { const queryPlan = createConditionalPlan({ operator: "in", operands: [ { name: "request.resource.attr.categories.name" }, { value: ["business"] }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.categories": { relation: { name: "categories", type: "many", fields: { name: { field: "name" }, }, }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { categories: { some: { name: "business", }, }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id).sort()).toEqual(fixtureResources .filter((resource) => { const categoryRefs = resource.categories?.connect ?? []; return categoryRefs.some((categoryRef) => { const category = fixtureCategories.find((fc) => fc.id === categoryRef.id); return category?.name === "business"; }); }) .map((r) => r.id) .sort()); }); (0, globals_1.test)("conditional - relation in multiple values", async () => { const queryPlan = createConditionalPlan({ operator: "in", operands: [ { name: "request.resource.attr.categories.name" }, { value: ["business", "development"] }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.categories": { relation: { name: "categories", type: "many", fields: { name: { field: "name" }, }, }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { categories: { some: { name: { in: ["business", "development"] }, }, }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id).sort()).toEqual(fixtureResources .filter((resource) => { const categoryRefs = resource.categories?.connect ?? []; return categoryRefs.some((categoryRef) => { const category = fixtureCategories.find((fc) => fc.id === categoryRef.id); return ["business", "development"].includes(category?.name ?? ""); }); }) .map((r) => r.id) .sort()); }); (0, globals_1.test)("conditional - except relation subset", async () => { const queryPlan = createConditionalPlan({ operator: "except", operands: [ { name: "request.resource.attr.categories" }, { operator: "lambda", operands: [ { operator: "eq", operands: [ { name: "cat.name" }, { value: "business" }, ], }, { name: "cat" }, ], }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.categories": { relation: { name: "categories", type: "many", fields: { name: { field: "name" }, }, }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { categories: { some: { NOT: { name: { equals: "business" }, }, }, }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id).sort()).toEqual(fixtureResources .filter((resource) => { const categoryRefs = resource.categories?.connect ?? []; return categoryRefs.some((categoryRef) => { const category = fixtureCategories.find((fc) => fc.id === categoryRef.id); return category?.name !== "business"; }); }) .map((r) => r.id) .sort()); }); (0, globals_1.test)("conditional - except nested relation subset", async () => { const queryPlan = createConditionalPlan({ operator: "except", operands: [ { name: "request.resource.attr.categories" }, { operator: "lambda", operands: [ { operator: "exists", operands: [ { name: "cat.subCategories" }, { operator: "lambda", operands: [ { operator: "eq", operands: [ { name: "sub.name" }, { value: "finance" }, ], }, { name: "sub" }, ], }, ], }, { name: "cat" }, ], }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.categories": { relation: { name: "categories", type: "many", fields: { subCategories: { relation: { name: "subCategories", type: "many", fields: { name: { field: "name" }, }, }, }, }, }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { categories: { some: { NOT: { subCategories: { some: { name: { equals: "finance" }, }, }, }, }, }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id).sort()).toEqual(fixtureResources .filter((resource) => { const categoryRefs = resource.categories?.connect ?? []; return categoryRefs.some((categoryRef) => { const category = fixtureCategories.find((fc) => fc.id === categoryRef.id); if (!category) { return false; } const subCategoryRefs = category.subCategories?.connect ?? []; return !subCategoryRefs.some((subCategoryRef) => { const subCategory = fixtureSubCategories.find((fsc) => fsc.id === subCategoryRef.id); return subCategory?.name === "finance"; }); }); }) .map((r) => r.id) .sort()); }); (0, globals_1.test)("conditional - exists single", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "exists-single", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "exists", operands: [ { name: "request.resource.attr.tags", }, { operator: "lambda", operands: [ { operator: "eq", operands: [ { name: "tag.id", }, { value: "tag1", }, ], }, { name: "tag", }, ], }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.tags": { relation: { name: "tags", type: "many", }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { tags: { some: { id: { equals: "tag1", }, }, }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((a) => Array.isArray(a.tags?.connect) && a.tags?.connect .map((t) => { return fixtureTags.find((f) => f.id === t.id); }) .filter((t) => t?.id == "tag1").length > 0) .map((r) => r.id)); }); (0, globals_1.test)("conditional - exists multiple", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "exists-multiple", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "exists", operands: [ { name: "request.resource.attr.tags", }, { operator: "lambda", operands: [ { operator: "and", operands: [ { operator: "eq", operands: [ { name: "tag.id", }, { value: "tag1", }, ], }, { operator: "eq", operands: [ { name: "tag.name", }, { value: "public", }, ], }, ], }, { name: "tag", }, ], }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.tags": { relation: { name: "tags", type: "many", }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { tags: { some: { AND: [ { id: { equals: "tag1", }, }, { name: { equals: "public", }, }, ], }, }, }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((a) => Array.isArray(a.tags?.connect) && a.tags?.connect .map((t) => { return fixtureTags.find((f) => f.id === t.id); }) .filter((t) => t?.id === "tag1" && t?.name === "public") .length > 0) .map((r) => r.id)); }); (0, globals_1.test)("conditional - exists_one", async () => { const queryPlan = await cerbos.planResources({ principal: { id: "user1", roles: ["USER"] }, resource: { kind: "resource" }, action: "exists-one", }); (0, globals_1.expect)(queryPlan.kind).toEqual(_1.PlanKind.CONDITIONAL); (0, globals_1.expect)(queryPlan.condition).toEqual({ operator: "exists_one", operands: [ { name: "request.resource.attr.tags", }, { operator: "lambda", operands: [ { operator: "eq", operands: [ { name: "tag.name", }, { value: "public", }, ], }, { name: "tag", }, ], }, ], }); const result = (0, _1.queryPlanToPrisma)({ queryPlan, mapper: { "request.resource.attr.tags": { relation: { name: "tags", type: "many", }, }, }, }); (0, globals_1.expect)(result).toStrictEqual({ kind: _1.PlanKind.CONDITIONAL, filters: { tags: { some: { name: { equals: "public" }, }, }, AND: [ { tags: { every: { OR: [ { name: { equals: "public" } }, { NOT: { name: { equals: "public" } } }, ], }, }, }, ], }, }); if (result.kind !== _1.PlanKind.CONDITIONAL) { throw new Error("Expected CONDITIONAL result"); } const query = await prisma.resource.findMany({ where: { ...result.filters }, }); (0, globals_1.expect)(query.map((r) => r.id)).toEqual(fixtureResources .filter((a) => Array.isArray(a.tags?.connect) && a.tags?.connect .map((t) => { return fixtureTags.find((f) => f.id === t.id); }) .filter((t) =>