@cerbos/orm-prisma 0.1.1 → 0.1.4

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 CHANGED
@@ -6,6 +6,7 @@ The following conditions are supported: `and`, `or`, `eq`, `ne`, `lt`, `gt`, `lt
6
6
 
7
7
  ## Requirements
8
8
  - Cerbos > v0.16
9
+ - `@cerbos/http` or `@cerbos/grpc` client
9
10
 
10
11
  ## Usage
11
12
 
@@ -21,24 +22,67 @@ queryPlanToPrisma({ queryPlan, fieldNameMapper }): PrismaCondition
21
22
 
22
23
  The function reqiures the full query plan from Cerbos to be passed in an object along with a `fieldNameMapper`.
23
24
 
25
+ A basic implementation can be as simple as:
26
+
27
+ ```js
28
+ import { GRPC as Cerbos } from "@cerbos/grpc";
29
+ import { PrismaClient } from "@prisma/client";
30
+
31
+ const prisma = new PrismaClient();
32
+ const cerbos = new Cerbos("localhost:3592", { tls: false });
33
+
34
+ // Fetch the query plan from Cerbos passing in the principal
35
+ // resource type and action
36
+ const queryPlan = await cerbos.planResources({
37
+ principal: {....},
38
+ resource: { kind: "resourceKind" },
39
+ action: "view"
40
+ })
41
+
42
+ // Generate the prisma filter from the query plan
43
+ const filters = queryPlanToPrisma({
44
+ queryPlan,
45
+ fieldNameMapper: {
46
+ "request.resource.attr.aFieldName": "prismaModelFieldName"
47
+ }
48
+ });
49
+
50
+ // Pass the filters in as where conditions
51
+ // If you have prexisting where conditions, you can pass them in an AND clause
52
+ const result = await prisma.myModel.findMany({
53
+ where: {
54
+ AND: filters
55
+ },
56
+ });
57
+
58
+ console.log(result)
59
+ ```
60
+
24
61
  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
62
 
26
63
  ```js
27
- {
28
- "request.resource.attr.aFieldName": "prismaModelFieldName"
29
- }
64
+ const filters = queryPlanToPrisma({
65
+ queryPlan,
66
+ fieldNameMapper: {
67
+ "request.resource.attr.aFieldName": "prismaModelFieldName"
68
+ }
69
+ });
70
+
30
71
 
31
72
  //or
32
73
 
33
- (fieldName: string): string => {
34
- if(fieldName.indexOf("request.resource.") > 0) {
35
- return fieldName.replace("request.resource.attr", "")
36
- }
74
+ const filters = queryPlanToPrisma({
75
+ queryPlan,
76
+ fieldNameMapper: (fieldName: string): string => {
77
+ if(fieldName.indexOf("request.resource.") > 0) {
78
+ return fieldName.replace("request.resource.attr", "")
79
+ }
37
80
 
38
- if(fieldName.indexOf("request.principal.") > 0) {
39
- return fieldName.replace("request.principal.attr", "")
81
+ if(fieldName.indexOf("request.principal.") > 0) {
82
+ return fieldName.replace("request.principal.attr", "")
83
+ }
40
84
  }
41
- }
85
+ });
42
86
  ```
43
87
 
44
88
  ## Full Example
package/lib/cjs/index.js CHANGED
@@ -25,6 +25,12 @@ function isValue(e) {
25
25
  function isVariable(e) {
26
26
  return e.variable !== undefined;
27
27
  }
28
+ function getOperandName(operands) {
29
+ return (operands.find(o => o.hasOwnProperty("name"))).name;
30
+ }
31
+ function getOperandValue(operands) {
32
+ return (operands.find(o => o.hasOwnProperty("value"))).value;
33
+ }
28
34
  function mapOperand(operand, getFieldName, output = {}) {
29
35
  if (isExpression(operand)) {
30
36
  const { operator, operands } = operand;
@@ -36,38 +42,38 @@ function mapOperand(operand, getFieldName, output = {}) {
36
42
  output.OR = operands.map((o) => mapOperand(o, getFieldName, {}));
37
43
  break;
38
44
  case "eq":
39
- output[getFieldName(operands[0].name)] = {
40
- equals: operands[1].value,
45
+ output[getFieldName(getOperandName(operands))] = {
46
+ equals: getOperandValue(operands),
41
47
  };
42
48
  break;
43
49
  case "ne":
44
- output[getFieldName(operands[0].name)] = {
45
- not: operands[1].value,
50
+ output[getFieldName(getOperandName(operands))] = {
51
+ not: getOperandValue(operands),
46
52
  };
47
53
  break;
48
54
  case "lt":
49
- output[getFieldName(operands[0].name)] = {
50
- lt: operands[1].value,
55
+ output[getFieldName(getOperandName(operands))] = {
56
+ lt: getOperandValue(operands),
51
57
  };
52
58
  break;
53
59
  case "gt":
54
- output[getFieldName(operands[0].name)] = {
55
- gt: operands[1].value,
60
+ output[getFieldName(getOperandName(operands))] = {
61
+ gt: getOperandValue(operands),
56
62
  };
57
63
  break;
58
- case "lte":
59
- output[getFieldName(operands[0].name)] = {
60
- lte: operands[1].value,
64
+ case "le":
65
+ output[getFieldName(getOperandName(operands))] = {
66
+ lte: getOperandValue(operands),
61
67
  };
62
68
  break;
63
- case "gte":
64
- output[getFieldName(operands[0].name)] = {
65
- gte: operands[1].value,
69
+ case "ge":
70
+ output[getFieldName(getOperandName(operands))] = {
71
+ gte: getOperandValue(operands),
66
72
  };
67
73
  break;
68
74
  case "in":
69
- output[getFieldName(operands[0].name)] = {
70
- in: operands[1].value,
75
+ output[getFieldName(getOperandName(operands))] = {
76
+ in: getOperandValue(operands),
71
77
  };
72
78
  break;
73
79
  }
package/lib/index.js CHANGED
@@ -22,6 +22,12 @@ function isValue(e) {
22
22
  function isVariable(e) {
23
23
  return e.variable !== undefined;
24
24
  }
25
+ function getOperandName(operands) {
26
+ return (operands.find(o => o.hasOwnProperty("name"))).name;
27
+ }
28
+ function getOperandValue(operands) {
29
+ return (operands.find(o => o.hasOwnProperty("value"))).value;
30
+ }
25
31
  function mapOperand(operand, getFieldName, output = {}) {
26
32
  if (isExpression(operand)) {
27
33
  const { operator, operands } = operand;
@@ -33,38 +39,38 @@ function mapOperand(operand, getFieldName, output = {}) {
33
39
  output.OR = operands.map((o) => mapOperand(o, getFieldName, {}));
34
40
  break;
35
41
  case "eq":
36
- output[getFieldName(operands[0].name)] = {
37
- equals: operands[1].value,
42
+ output[getFieldName(getOperandName(operands))] = {
43
+ equals: getOperandValue(operands),
38
44
  };
39
45
  break;
40
46
  case "ne":
41
- output[getFieldName(operands[0].name)] = {
42
- not: operands[1].value,
47
+ output[getFieldName(getOperandName(operands))] = {
48
+ not: getOperandValue(operands),
43
49
  };
44
50
  break;
45
51
  case "lt":
46
- output[getFieldName(operands[0].name)] = {
47
- lt: operands[1].value,
52
+ output[getFieldName(getOperandName(operands))] = {
53
+ lt: getOperandValue(operands),
48
54
  };
49
55
  break;
50
56
  case "gt":
51
- output[getFieldName(operands[0].name)] = {
52
- gt: operands[1].value,
57
+ output[getFieldName(getOperandName(operands))] = {
58
+ gt: getOperandValue(operands),
53
59
  };
54
60
  break;
55
- case "lte":
56
- output[getFieldName(operands[0].name)] = {
57
- lte: operands[1].value,
61
+ case "le":
62
+ output[getFieldName(getOperandName(operands))] = {
63
+ lte: getOperandValue(operands),
58
64
  };
59
65
  break;
60
- case "gte":
61
- output[getFieldName(operands[0].name)] = {
62
- gte: operands[1].value,
66
+ case "ge":
67
+ output[getFieldName(getOperandName(operands))] = {
68
+ gte: getOperandValue(operands),
63
69
  };
64
70
  break;
65
71
  case "in":
66
- output[getFieldName(operands[0].name)] = {
67
- in: operands[1].value,
72
+ output[getFieldName(getOperandName(operands))] = {
73
+ in: getOperandValue(operands),
68
74
  };
69
75
  break;
70
76
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerbos/orm-prisma",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "homepage": "https://cerbos.dev",
5
5
  "description": "",
6
6
  "private": false,
@@ -14,15 +14,23 @@
14
14
  "prepare": "npm run build",
15
15
  "preversion": "npm run lint",
16
16
  "version": "git add -A src",
17
- "postversion": "git push && git push --tags"
17
+ "postversion": "git push && git push --tags",
18
+ "test": "npx prisma db push --force-reset && cerbos run --log-level=error --set=storage.disk.directory=../policies --set=telemetry.disabled=true -- jest src/**.test.ts",
19
+ "cerbos": "cerbos server --config=./cerbos-config.yaml"
18
20
  },
19
21
  "author": "Cerbos",
20
22
  "license": "Apache-2.0",
21
23
  "devDependencies": {
24
+ "@prisma/client": "^4.3.1",
25
+ "@types/jest": "^29.0.3",
26
+ "@types/node": "^18.7.21",
27
+ "prisma": "^4.3.1",
28
+ "ts-jest": "^28.0.8",
22
29
  "ts-node": "^10.4.0",
23
30
  "typescript": "^4.5.4"
24
31
  },
25
32
  "dependencies": {
26
- "@cerbos/core": "^0.5.0"
33
+ "@cerbos/core": "^0.5.1",
34
+ "@cerbos/grpc": "^0.8.0"
27
35
  }
28
36
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}