@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 +54 -10
- package/lib/cjs/index.js +22 -16
- package/lib/index.js +22 -16
- package/package.json +11 -3
- package/lib/cjs/index.js.map +0 -1
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
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
39
|
-
|
|
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
|
|
40
|
-
equals: operands
|
|
45
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
46
|
+
equals: getOperandValue(operands),
|
|
41
47
|
};
|
|
42
48
|
break;
|
|
43
49
|
case "ne":
|
|
44
|
-
output[getFieldName(operands
|
|
45
|
-
not: operands
|
|
50
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
51
|
+
not: getOperandValue(operands),
|
|
46
52
|
};
|
|
47
53
|
break;
|
|
48
54
|
case "lt":
|
|
49
|
-
output[getFieldName(operands
|
|
50
|
-
lt: operands
|
|
55
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
56
|
+
lt: getOperandValue(operands),
|
|
51
57
|
};
|
|
52
58
|
break;
|
|
53
59
|
case "gt":
|
|
54
|
-
output[getFieldName(operands
|
|
55
|
-
gt: operands
|
|
60
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
61
|
+
gt: getOperandValue(operands),
|
|
56
62
|
};
|
|
57
63
|
break;
|
|
58
|
-
case "
|
|
59
|
-
output[getFieldName(operands
|
|
60
|
-
lte: operands
|
|
64
|
+
case "le":
|
|
65
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
66
|
+
lte: getOperandValue(operands),
|
|
61
67
|
};
|
|
62
68
|
break;
|
|
63
|
-
case "
|
|
64
|
-
output[getFieldName(operands
|
|
65
|
-
gte: operands
|
|
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
|
|
70
|
-
in: operands
|
|
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
|
|
37
|
-
equals: operands
|
|
42
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
43
|
+
equals: getOperandValue(operands),
|
|
38
44
|
};
|
|
39
45
|
break;
|
|
40
46
|
case "ne":
|
|
41
|
-
output[getFieldName(operands
|
|
42
|
-
not: operands
|
|
47
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
48
|
+
not: getOperandValue(operands),
|
|
43
49
|
};
|
|
44
50
|
break;
|
|
45
51
|
case "lt":
|
|
46
|
-
output[getFieldName(operands
|
|
47
|
-
lt: operands
|
|
52
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
53
|
+
lt: getOperandValue(operands),
|
|
48
54
|
};
|
|
49
55
|
break;
|
|
50
56
|
case "gt":
|
|
51
|
-
output[getFieldName(operands
|
|
52
|
-
gt: operands
|
|
57
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
58
|
+
gt: getOperandValue(operands),
|
|
53
59
|
};
|
|
54
60
|
break;
|
|
55
|
-
case "
|
|
56
|
-
output[getFieldName(operands
|
|
57
|
-
lte: operands
|
|
61
|
+
case "le":
|
|
62
|
+
output[getFieldName(getOperandName(operands))] = {
|
|
63
|
+
lte: getOperandValue(operands),
|
|
58
64
|
};
|
|
59
65
|
break;
|
|
60
|
-
case "
|
|
61
|
-
output[getFieldName(operands
|
|
62
|
-
gte: operands
|
|
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
|
|
67
|
-
in: operands
|
|
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.
|
|
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.
|
|
33
|
+
"@cerbos/core": "^0.5.1",
|
|
34
|
+
"@cerbos/grpc": "^0.8.0"
|
|
27
35
|
}
|
|
28
36
|
}
|
package/lib/cjs/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|