@cerbos/orm-prisma 1.0.0-alpha.0 → 1.0.0
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 +1 -1
- package/lib/cjs/index.js +114 -112
- package/lib/index.js +114 -112
- package/package.json +1 -1
package/README.md
CHANGED
package/lib/cjs/index.js
CHANGED
|
@@ -4,34 +4,44 @@ exports.queryPlanToPrisma = exports.PlanKind = void 0;
|
|
|
4
4
|
const core_1 = require("@cerbos/core");
|
|
5
5
|
exports.PlanKind = core_1.PlanKind;
|
|
6
6
|
function queryPlanToPrisma({ queryPlan, fieldNameMapper, relationMapper = {} }) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (typeof relationMapper === "function") {
|
|
27
|
-
return relationMapper(key);
|
|
28
|
-
}
|
|
29
|
-
else if (relationMapper[key]) {
|
|
30
|
-
return relationMapper[key];
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
}, {})
|
|
7
|
+
const toFieldName = (key) => {
|
|
8
|
+
if (typeof fieldNameMapper === "function") {
|
|
9
|
+
return fieldNameMapper(key);
|
|
10
|
+
}
|
|
11
|
+
else if (fieldNameMapper[key]) {
|
|
12
|
+
return fieldNameMapper[key];
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return key;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const toRelationName = (key) => {
|
|
19
|
+
if (typeof relationMapper === "function") {
|
|
20
|
+
return relationMapper(key);
|
|
21
|
+
}
|
|
22
|
+
else if (relationMapper[key]) {
|
|
23
|
+
return relationMapper[key];
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
34
26
|
};
|
|
27
|
+
switch (queryPlan.kind) {
|
|
28
|
+
case exports.PlanKind.ALWAYS_ALLOWED:
|
|
29
|
+
return {
|
|
30
|
+
kind: exports.PlanKind.ALWAYS_ALLOWED,
|
|
31
|
+
filters: {}
|
|
32
|
+
};
|
|
33
|
+
case exports.PlanKind.ALWAYS_DENIED:
|
|
34
|
+
return {
|
|
35
|
+
kind: exports.PlanKind.ALWAYS_DENIED
|
|
36
|
+
};
|
|
37
|
+
case exports.PlanKind.CONDITIONAL:
|
|
38
|
+
return {
|
|
39
|
+
kind: exports.PlanKind.CONDITIONAL,
|
|
40
|
+
filters: mapOperand(queryPlan.condition, toFieldName, toRelationName)
|
|
41
|
+
};
|
|
42
|
+
default:
|
|
43
|
+
throw Error(`Invalid query plan.`);
|
|
44
|
+
}
|
|
35
45
|
}
|
|
36
46
|
exports.queryPlanToPrisma = queryPlanToPrisma;
|
|
37
47
|
function isExpression(e) {
|
|
@@ -43,102 +53,94 @@ function isValue(e) {
|
|
|
43
53
|
function isVariable(e) {
|
|
44
54
|
return e.variable !== undefined;
|
|
45
55
|
}
|
|
46
|
-
function
|
|
56
|
+
function getOperandVariable(operands) {
|
|
47
57
|
const op = operands.find(o => o.hasOwnProperty("name"));
|
|
48
58
|
if (!op)
|
|
49
59
|
return;
|
|
50
60
|
return op.name;
|
|
51
61
|
}
|
|
52
62
|
function getOperandValue(operands) {
|
|
53
|
-
const op = operands.find(o => o
|
|
63
|
+
const op = operands.find(o => isValue(o));
|
|
54
64
|
if (!op)
|
|
55
65
|
return;
|
|
56
66
|
return op.value;
|
|
57
67
|
}
|
|
68
|
+
const OPERATORS = {
|
|
69
|
+
"eq": {
|
|
70
|
+
relationalCondition: "is",
|
|
71
|
+
fieldCondition: "equals"
|
|
72
|
+
},
|
|
73
|
+
"ne": {
|
|
74
|
+
relationalCondition: "isNot",
|
|
75
|
+
fieldCondition: "not"
|
|
76
|
+
},
|
|
77
|
+
"in": {
|
|
78
|
+
relationalCondition: "some",
|
|
79
|
+
fieldCondition: "in"
|
|
80
|
+
},
|
|
81
|
+
"lt": {
|
|
82
|
+
fieldCondition: "lt"
|
|
83
|
+
},
|
|
84
|
+
"gt": {
|
|
85
|
+
fieldCondition: "gt"
|
|
86
|
+
},
|
|
87
|
+
"le": {
|
|
88
|
+
fieldCondition: "lte"
|
|
89
|
+
},
|
|
90
|
+
"ge": {
|
|
91
|
+
fieldCondition: "gte"
|
|
92
|
+
}
|
|
93
|
+
};
|
|
58
94
|
function mapOperand(operand, getFieldName, getRelationName, output = {}) {
|
|
59
|
-
if (isExpression(operand))
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
output[relation.relation] = {
|
|
97
|
-
isNot: {
|
|
98
|
-
[relation.field]: opValue
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
else if (fieldName) {
|
|
103
|
-
output[fieldName] = {
|
|
104
|
-
not: opValue,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (operator == "lt" && fieldName) {
|
|
109
|
-
output[fieldName] = {
|
|
110
|
-
lt: opValue,
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
if (operator == "gt" && fieldName) {
|
|
114
|
-
output[fieldName] = {
|
|
115
|
-
gt: opValue,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (operator == "le" && fieldName) {
|
|
119
|
-
output[fieldName] = {
|
|
120
|
-
lte: opValue,
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
if (operator == "ge" && fieldName) {
|
|
124
|
-
output[fieldName] = {
|
|
125
|
-
gte: opValue,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
if (operator == "in") {
|
|
129
|
-
if (relation) {
|
|
130
|
-
output[relation.relation] = {
|
|
131
|
-
some: {
|
|
132
|
-
[relation.field]: opValue
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
else if (fieldName) {
|
|
137
|
-
output[fieldName] = {
|
|
138
|
-
in: opValue,
|
|
139
|
-
};
|
|
95
|
+
if (!isExpression(operand))
|
|
96
|
+
throw Error(`Query plan did not contain an expression for operand ${operand}`);
|
|
97
|
+
const { operator, operands } = operand;
|
|
98
|
+
// HANDLE NESTING OPERATIONS: AND/OR/NOT
|
|
99
|
+
if (operator == "and") {
|
|
100
|
+
if (operands.length < 2)
|
|
101
|
+
throw Error("Expected atleast 2 operands");
|
|
102
|
+
output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
|
|
103
|
+
return output;
|
|
104
|
+
}
|
|
105
|
+
if (operator == "or") {
|
|
106
|
+
if (operands.length < 2)
|
|
107
|
+
throw Error("Expected atleast 2 operands");
|
|
108
|
+
output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
|
|
109
|
+
return output;
|
|
110
|
+
}
|
|
111
|
+
if (operator == "not") {
|
|
112
|
+
if (operands.length > 1)
|
|
113
|
+
throw Error("Expected only one operand");
|
|
114
|
+
output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0];
|
|
115
|
+
return output;
|
|
116
|
+
}
|
|
117
|
+
// get the operation parameters
|
|
118
|
+
const operation = OPERATORS[operator];
|
|
119
|
+
if (!operation)
|
|
120
|
+
throw Error(`Unsupported operator ${operator}`);
|
|
121
|
+
const opVariable = getOperandVariable(operands);
|
|
122
|
+
if (!opVariable)
|
|
123
|
+
throw Error(`Unexpected variable ${operands}`);
|
|
124
|
+
const opValue = getOperandValue(operands);
|
|
125
|
+
const relation = getRelationName(opVariable);
|
|
126
|
+
const fieldName = getFieldName(opVariable);
|
|
127
|
+
// There is a relational mapper for this variable
|
|
128
|
+
if (relation && operation.relationalCondition) {
|
|
129
|
+
output[relation.relation] = {
|
|
130
|
+
[operation.relationalCondition]: {
|
|
131
|
+
[relation.field]: opValue
|
|
140
132
|
}
|
|
141
|
-
}
|
|
133
|
+
};
|
|
134
|
+
return output;
|
|
135
|
+
}
|
|
136
|
+
else if (fieldName && operation.fieldCondition) {
|
|
137
|
+
// There is a field mapper for this variable
|
|
138
|
+
output[fieldName] = {
|
|
139
|
+
[operation.fieldCondition]: opValue,
|
|
140
|
+
};
|
|
141
|
+
return output;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
throw Error("Failed to map");
|
|
142
145
|
}
|
|
143
|
-
return output;
|
|
144
146
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,34 +1,44 @@
|
|
|
1
1
|
import { PlanKind as PK } from "@cerbos/core";
|
|
2
2
|
export const PlanKind = PK;
|
|
3
3
|
export function queryPlanToPrisma({ queryPlan, fieldNameMapper, relationMapper = {} }) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (typeof relationMapper === "function") {
|
|
24
|
-
return relationMapper(key);
|
|
25
|
-
}
|
|
26
|
-
else if (relationMapper[key]) {
|
|
27
|
-
return relationMapper[key];
|
|
28
|
-
}
|
|
29
|
-
return null;
|
|
30
|
-
}, {})
|
|
4
|
+
const toFieldName = (key) => {
|
|
5
|
+
if (typeof fieldNameMapper === "function") {
|
|
6
|
+
return fieldNameMapper(key);
|
|
7
|
+
}
|
|
8
|
+
else if (fieldNameMapper[key]) {
|
|
9
|
+
return fieldNameMapper[key];
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return key;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const toRelationName = (key) => {
|
|
16
|
+
if (typeof relationMapper === "function") {
|
|
17
|
+
return relationMapper(key);
|
|
18
|
+
}
|
|
19
|
+
else if (relationMapper[key]) {
|
|
20
|
+
return relationMapper[key];
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
31
23
|
};
|
|
24
|
+
switch (queryPlan.kind) {
|
|
25
|
+
case PlanKind.ALWAYS_ALLOWED:
|
|
26
|
+
return {
|
|
27
|
+
kind: PlanKind.ALWAYS_ALLOWED,
|
|
28
|
+
filters: {}
|
|
29
|
+
};
|
|
30
|
+
case PlanKind.ALWAYS_DENIED:
|
|
31
|
+
return {
|
|
32
|
+
kind: PlanKind.ALWAYS_DENIED
|
|
33
|
+
};
|
|
34
|
+
case PlanKind.CONDITIONAL:
|
|
35
|
+
return {
|
|
36
|
+
kind: PlanKind.CONDITIONAL,
|
|
37
|
+
filters: mapOperand(queryPlan.condition, toFieldName, toRelationName)
|
|
38
|
+
};
|
|
39
|
+
default:
|
|
40
|
+
throw Error(`Invalid query plan.`);
|
|
41
|
+
}
|
|
32
42
|
}
|
|
33
43
|
function isExpression(e) {
|
|
34
44
|
return e.operator !== undefined;
|
|
@@ -39,102 +49,94 @@ function isValue(e) {
|
|
|
39
49
|
function isVariable(e) {
|
|
40
50
|
return e.variable !== undefined;
|
|
41
51
|
}
|
|
42
|
-
function
|
|
52
|
+
function getOperandVariable(operands) {
|
|
43
53
|
const op = operands.find(o => o.hasOwnProperty("name"));
|
|
44
54
|
if (!op)
|
|
45
55
|
return;
|
|
46
56
|
return op.name;
|
|
47
57
|
}
|
|
48
58
|
function getOperandValue(operands) {
|
|
49
|
-
const op = operands.find(o => o
|
|
59
|
+
const op = operands.find(o => isValue(o));
|
|
50
60
|
if (!op)
|
|
51
61
|
return;
|
|
52
62
|
return op.value;
|
|
53
63
|
}
|
|
64
|
+
const OPERATORS = {
|
|
65
|
+
"eq": {
|
|
66
|
+
relationalCondition: "is",
|
|
67
|
+
fieldCondition: "equals"
|
|
68
|
+
},
|
|
69
|
+
"ne": {
|
|
70
|
+
relationalCondition: "isNot",
|
|
71
|
+
fieldCondition: "not"
|
|
72
|
+
},
|
|
73
|
+
"in": {
|
|
74
|
+
relationalCondition: "some",
|
|
75
|
+
fieldCondition: "in"
|
|
76
|
+
},
|
|
77
|
+
"lt": {
|
|
78
|
+
fieldCondition: "lt"
|
|
79
|
+
},
|
|
80
|
+
"gt": {
|
|
81
|
+
fieldCondition: "gt"
|
|
82
|
+
},
|
|
83
|
+
"le": {
|
|
84
|
+
fieldCondition: "lte"
|
|
85
|
+
},
|
|
86
|
+
"ge": {
|
|
87
|
+
fieldCondition: "gte"
|
|
88
|
+
}
|
|
89
|
+
};
|
|
54
90
|
function mapOperand(operand, getFieldName, getRelationName, output = {}) {
|
|
55
|
-
if (isExpression(operand))
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
output[relation.relation] = {
|
|
93
|
-
isNot: {
|
|
94
|
-
[relation.field]: opValue
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
else if (fieldName) {
|
|
99
|
-
output[fieldName] = {
|
|
100
|
-
not: opValue,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (operator == "lt" && fieldName) {
|
|
105
|
-
output[fieldName] = {
|
|
106
|
-
lt: opValue,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
if (operator == "gt" && fieldName) {
|
|
110
|
-
output[fieldName] = {
|
|
111
|
-
gt: opValue,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (operator == "le" && fieldName) {
|
|
115
|
-
output[fieldName] = {
|
|
116
|
-
lte: opValue,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
if (operator == "ge" && fieldName) {
|
|
120
|
-
output[fieldName] = {
|
|
121
|
-
gte: opValue,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
if (operator == "in") {
|
|
125
|
-
if (relation) {
|
|
126
|
-
output[relation.relation] = {
|
|
127
|
-
some: {
|
|
128
|
-
[relation.field]: opValue
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
else if (fieldName) {
|
|
133
|
-
output[fieldName] = {
|
|
134
|
-
in: opValue,
|
|
135
|
-
};
|
|
91
|
+
if (!isExpression(operand))
|
|
92
|
+
throw Error(`Query plan did not contain an expression for operand ${operand}`);
|
|
93
|
+
const { operator, operands } = operand;
|
|
94
|
+
// HANDLE NESTING OPERATIONS: AND/OR/NOT
|
|
95
|
+
if (operator == "and") {
|
|
96
|
+
if (operands.length < 2)
|
|
97
|
+
throw Error("Expected atleast 2 operands");
|
|
98
|
+
output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
|
|
99
|
+
return output;
|
|
100
|
+
}
|
|
101
|
+
if (operator == "or") {
|
|
102
|
+
if (operands.length < 2)
|
|
103
|
+
throw Error("Expected atleast 2 operands");
|
|
104
|
+
output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
|
|
105
|
+
return output;
|
|
106
|
+
}
|
|
107
|
+
if (operator == "not") {
|
|
108
|
+
if (operands.length > 1)
|
|
109
|
+
throw Error("Expected only one operand");
|
|
110
|
+
output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0];
|
|
111
|
+
return output;
|
|
112
|
+
}
|
|
113
|
+
// get the operation parameters
|
|
114
|
+
const operation = OPERATORS[operator];
|
|
115
|
+
if (!operation)
|
|
116
|
+
throw Error(`Unsupported operator ${operator}`);
|
|
117
|
+
const opVariable = getOperandVariable(operands);
|
|
118
|
+
if (!opVariable)
|
|
119
|
+
throw Error(`Unexpected variable ${operands}`);
|
|
120
|
+
const opValue = getOperandValue(operands);
|
|
121
|
+
const relation = getRelationName(opVariable);
|
|
122
|
+
const fieldName = getFieldName(opVariable);
|
|
123
|
+
// There is a relational mapper for this variable
|
|
124
|
+
if (relation && operation.relationalCondition) {
|
|
125
|
+
output[relation.relation] = {
|
|
126
|
+
[operation.relationalCondition]: {
|
|
127
|
+
[relation.field]: opValue
|
|
136
128
|
}
|
|
137
|
-
}
|
|
129
|
+
};
|
|
130
|
+
return output;
|
|
131
|
+
}
|
|
132
|
+
else if (fieldName && operation.fieldCondition) {
|
|
133
|
+
// There is a field mapper for this variable
|
|
134
|
+
output[fieldName] = {
|
|
135
|
+
[operation.fieldCondition]: opValue,
|
|
136
|
+
};
|
|
137
|
+
return output;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
throw Error("Failed to map");
|
|
138
141
|
}
|
|
139
|
-
return output;
|
|
140
142
|
}
|