@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 CHANGED
@@ -12,8 +12,8 @@ Not Supported:
12
12
  - `mode`
13
13
  - `startsWith`
14
14
  - `endsWith`
15
+ - `isSet`
15
16
  - Scalar filters
16
- - Composite type filters
17
17
  - Atomic number operations
18
18
  - Composite keys
19
19
 
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
- if (queryPlan.kind === exports.PlanKind.ALWAYS_ALLOWED)
8
- return {
9
- kind: exports.PlanKind.ALWAYS_ALLOWED,
10
- filters: {}
11
- };
12
- if (queryPlan.kind === exports.PlanKind.ALWAYS_DENIED)
13
- return {
14
- kind: exports.PlanKind.ALWAYS_DENIED
15
- };
16
- return {
17
- kind: exports.PlanKind.CONDITIONAL,
18
- filters: mapOperand(queryPlan.condition, (key) => {
19
- if (typeof fieldNameMapper === "function") {
20
- return fieldNameMapper(key);
21
- }
22
- else {
23
- return (fieldNameMapper[key] = fieldNameMapper[key] || key);
24
- }
25
- }, (key) => {
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 getOperandName(operands) {
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.hasOwnProperty("value"));
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
- const { operator, operands } = operand;
61
- const opName = getOperandName(operands);
62
- const opValue = getOperandValue(operands);
63
- const relation = opName && getRelationName(opName);
64
- const fieldName = opName && getFieldName(opName);
65
- if (operator == "and") {
66
- if (operands.length < 2)
67
- throw Error("Expected atleast 2 operands");
68
- output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
69
- }
70
- if (operator == "or") {
71
- if (operands.length < 2)
72
- throw Error("Expected atleast 2 operands");
73
- output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
74
- }
75
- if (operator == "not") {
76
- if (operands.length > 1)
77
- throw Error("Expected only one operand");
78
- output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0];
79
- }
80
- if (operator == "eq") {
81
- if (relation) {
82
- output[relation.relation] = {
83
- is: {
84
- [relation.field]: opValue
85
- }
86
- };
87
- }
88
- else if (fieldName) {
89
- output[fieldName] = {
90
- equals: opValue,
91
- };
92
- }
93
- }
94
- if (operator == "ne") {
95
- if (relation) {
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
- if (queryPlan.kind === PlanKind.ALWAYS_ALLOWED)
5
- return {
6
- kind: PlanKind.ALWAYS_ALLOWED,
7
- filters: {}
8
- };
9
- if (queryPlan.kind === PlanKind.ALWAYS_DENIED)
10
- return {
11
- kind: PlanKind.ALWAYS_DENIED
12
- };
13
- return {
14
- kind: PlanKind.CONDITIONAL,
15
- filters: mapOperand(queryPlan.condition, (key) => {
16
- if (typeof fieldNameMapper === "function") {
17
- return fieldNameMapper(key);
18
- }
19
- else {
20
- return (fieldNameMapper[key] = fieldNameMapper[key] || key);
21
- }
22
- }, (key) => {
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 getOperandName(operands) {
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.hasOwnProperty("value"));
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
- const { operator, operands } = operand;
57
- const opName = getOperandName(operands);
58
- const opValue = getOperandValue(operands);
59
- const relation = opName && getRelationName(opName);
60
- const fieldName = opName && getFieldName(opName);
61
- if (operator == "and") {
62
- if (operands.length < 2)
63
- throw Error("Expected atleast 2 operands");
64
- output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
65
- }
66
- if (operator == "or") {
67
- if (operands.length < 2)
68
- throw Error("Expected atleast 2 operands");
69
- output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}));
70
- }
71
- if (operator == "not") {
72
- if (operands.length > 1)
73
- throw Error("Expected only one operand");
74
- output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0];
75
- }
76
- if (operator == "eq") {
77
- if (relation) {
78
- output[relation.relation] = {
79
- is: {
80
- [relation.field]: opValue
81
- }
82
- };
83
- }
84
- else if (fieldName) {
85
- output[fieldName] = {
86
- equals: opValue,
87
- };
88
- }
89
- }
90
- if (operator == "ne") {
91
- if (relation) {
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerbos/orm-prisma",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0",
4
4
  "homepage": "https://cerbos.dev",
5
5
  "description": "",
6
6
  "private": false,