@cerbos/orm-prisma 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # Cerbos + Prisma ORM Adapter
2
+
3
+ An adapater library that takes a [Cerbos](https://cerbos.dev) Query Plan ([PlanResources API](https://docs.cerbos.dev/cerbos/latest/api/index.html#resources-query-plan)) response and converts it into a [Prisma](https://prisma.io) where class object. This is designed to work alongside a project using the [Cerbos Javascript SDK](https://github.com/cerbos/cerbos-sdk-javascript).
4
+
5
+ The following conditions are supported: `and`, `or`, `eq`, `ne`, `lt`, `gt`, `lte`, `gte` and `in`.
6
+
7
+ ## Requirements
8
+ - Cerbos > v0.16
9
+
10
+ ## Usage
11
+
12
+ ```
13
+ npm install @cerbos/orm-prisma
14
+ ```
15
+
16
+ This package exports a single function:
17
+
18
+ ```js
19
+ queryPlanToPrisma({ queryPlan, fieldNameMapper }): PrismaCondition
20
+ ```
21
+
22
+ The function reqiures the full query plan from Cerbos to be passed in an object along with a `fieldNameMapper`.
23
+
24
+ The `fieldNameMapper` is used to convert the field names in the query plan response to names of fields in the Prisma model - this can be done as a map or a function:
25
+
26
+ ```js
27
+ {
28
+ "request.resource.attr.aFieldName": "prismaModelFieldName"
29
+ }
30
+
31
+ //or
32
+
33
+ (fieldName: string): string => {
34
+ if(fieldName.indexOf("request.resource.") > 0) {
35
+ return fieldName.replace("request.resource.attr", "")
36
+ }
37
+
38
+ if(fieldName.indexOf("request.principal.") > 0) {
39
+ return fieldName.replace("request.principal.attr", "")
40
+ }
41
+ }
42
+ ```
43
+
44
+ ## Full Example
45
+
46
+ A full Prisma application making use of this adapater can be found at [https://github.com/cerbos/express-prisma-cerbos](https://github.com/cerbos/express-prisma-cerbos)
@@ -0,0 +1,9 @@
1
+ import { PlanResourcesResponse } from "@cerbos/core";
2
+ interface QueryPlanToPrismaArgs {
3
+ queryPlan: PlanResourcesResponse;
4
+ fieldNameMapper: {
5
+ [key: string]: string;
6
+ } | ((key: string) => string);
7
+ }
8
+ export default function queryPlanToPrisma({ queryPlan, fieldNameMapper, }: QueryPlanToPrismaArgs): any;
9
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@cerbos/core");
4
+ function queryPlanToPrisma({ queryPlan, fieldNameMapper, }) {
5
+ if (queryPlan.kind === core_1.PlanKind.ALWAYS_ALLOWED)
6
+ return {};
7
+ if (queryPlan.kind === core_1.PlanKind.ALWAYS_DENIED)
8
+ return { "1": { "equals": 0 } };
9
+ return mapOperand(queryPlan.condition, (key) => {
10
+ if (typeof fieldNameMapper === "function") {
11
+ return fieldNameMapper(key);
12
+ }
13
+ else {
14
+ return (fieldNameMapper[key] = fieldNameMapper[key] || key);
15
+ }
16
+ }, {});
17
+ }
18
+ exports.default = queryPlanToPrisma;
19
+ function isExpression(e) {
20
+ return e.operator !== undefined;
21
+ }
22
+ function isValue(e) {
23
+ return e.value !== undefined;
24
+ }
25
+ function isVariable(e) {
26
+ return e.variable !== undefined;
27
+ }
28
+ function mapOperand(operand, getFieldName, output = {}) {
29
+ if (isExpression(operand)) {
30
+ const { operator, operands } = operand;
31
+ switch (operator) {
32
+ case "and":
33
+ output.AND = operands.map((o) => mapOperand(o, getFieldName, {}));
34
+ break;
35
+ case "or":
36
+ output.OR = operands.map((o) => mapOperand(o, getFieldName, {}));
37
+ break;
38
+ case "eq":
39
+ output[getFieldName(operands[0].name)] = {
40
+ equals: operands[1].value,
41
+ };
42
+ break;
43
+ case "ne":
44
+ output[getFieldName(operands[0].name)] = {
45
+ not: operands[1].value,
46
+ };
47
+ break;
48
+ case "lt":
49
+ output[getFieldName(operands[0].name)] = {
50
+ lt: operands[1].value,
51
+ };
52
+ break;
53
+ case "gt":
54
+ output[getFieldName(operands[0].name)] = {
55
+ gt: operands[1].value,
56
+ };
57
+ break;
58
+ case "lte":
59
+ output[getFieldName(operands[0].name)] = {
60
+ lte: operands[1].value,
61
+ };
62
+ break;
63
+ case "gte":
64
+ output[getFieldName(operands[0].name)] = {
65
+ gte: operands[1].value,
66
+ };
67
+ break;
68
+ case "in":
69
+ output[getFieldName(operands[0].name)] = {
70
+ in: operands[1].value,
71
+ };
72
+ break;
73
+ }
74
+ }
75
+ return output;
76
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { PlanResourcesResponse } from "@cerbos/core";
2
+ interface QueryPlanToPrismaArgs {
3
+ queryPlan: PlanResourcesResponse;
4
+ fieldNameMapper: {
5
+ [key: string]: string;
6
+ } | ((key: string) => string);
7
+ }
8
+ export default function queryPlanToPrisma({ queryPlan, fieldNameMapper, }: QueryPlanToPrismaArgs): any;
9
+ export {};
package/lib/index.js ADDED
@@ -0,0 +1,73 @@
1
+ import { PlanKind } from "@cerbos/core";
2
+ export default function queryPlanToPrisma({ queryPlan, fieldNameMapper, }) {
3
+ if (queryPlan.kind === PlanKind.ALWAYS_ALLOWED)
4
+ return {};
5
+ if (queryPlan.kind === PlanKind.ALWAYS_DENIED)
6
+ return { "1": { "equals": 0 } };
7
+ return mapOperand(queryPlan.condition, (key) => {
8
+ if (typeof fieldNameMapper === "function") {
9
+ return fieldNameMapper(key);
10
+ }
11
+ else {
12
+ return (fieldNameMapper[key] = fieldNameMapper[key] || key);
13
+ }
14
+ }, {});
15
+ }
16
+ function isExpression(e) {
17
+ return e.operator !== undefined;
18
+ }
19
+ function isValue(e) {
20
+ return e.value !== undefined;
21
+ }
22
+ function isVariable(e) {
23
+ return e.variable !== undefined;
24
+ }
25
+ function mapOperand(operand, getFieldName, output = {}) {
26
+ if (isExpression(operand)) {
27
+ const { operator, operands } = operand;
28
+ switch (operator) {
29
+ case "and":
30
+ output.AND = operands.map((o) => mapOperand(o, getFieldName, {}));
31
+ break;
32
+ case "or":
33
+ output.OR = operands.map((o) => mapOperand(o, getFieldName, {}));
34
+ break;
35
+ case "eq":
36
+ output[getFieldName(operands[0].name)] = {
37
+ equals: operands[1].value,
38
+ };
39
+ break;
40
+ case "ne":
41
+ output[getFieldName(operands[0].name)] = {
42
+ not: operands[1].value,
43
+ };
44
+ break;
45
+ case "lt":
46
+ output[getFieldName(operands[0].name)] = {
47
+ lt: operands[1].value,
48
+ };
49
+ break;
50
+ case "gt":
51
+ output[getFieldName(operands[0].name)] = {
52
+ gt: operands[1].value,
53
+ };
54
+ break;
55
+ case "lte":
56
+ output[getFieldName(operands[0].name)] = {
57
+ lte: operands[1].value,
58
+ };
59
+ break;
60
+ case "gte":
61
+ output[getFieldName(operands[0].name)] = {
62
+ gte: operands[1].value,
63
+ };
64
+ break;
65
+ case "in":
66
+ output[getFieldName(operands[0].name)] = {
67
+ in: operands[1].value,
68
+ };
69
+ break;
70
+ }
71
+ }
72
+ return output;
73
+ }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@cerbos/orm-prisma",
3
+ "version": "0.1.1",
4
+ "homepage": "https://cerbos.dev",
5
+ "description": "",
6
+ "private": false,
7
+ "main": "./lib/cjs/index.js",
8
+ "module": "./lib/esm/index.js",
9
+ "files": [
10
+ "lib/**/*"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
14
+ "prepare": "npm run build",
15
+ "preversion": "npm run lint",
16
+ "version": "git add -A src",
17
+ "postversion": "git push && git push --tags"
18
+ },
19
+ "author": "Cerbos",
20
+ "license": "Apache-2.0",
21
+ "devDependencies": {
22
+ "ts-node": "^10.4.0",
23
+ "typescript": "^4.5.4"
24
+ },
25
+ "dependencies": {
26
+ "@cerbos/core": "^0.5.0"
27
+ }
28
+ }