@cerbos/orm-prisma
Advanced tools
Comparing version 1.0.0-alpha.0 to 1.0.0
@@ -7,30 +7,40 @@ "use strict"; | ||
function queryPlanToPrisma({ queryPlan, fieldNameMapper, relationMapper = {} }) { | ||
if (queryPlan.kind === exports.PlanKind.ALWAYS_ALLOWED) | ||
return { | ||
kind: exports.PlanKind.ALWAYS_ALLOWED, | ||
filters: {} | ||
}; | ||
if (queryPlan.kind === exports.PlanKind.ALWAYS_DENIED) | ||
return { | ||
kind: exports.PlanKind.ALWAYS_DENIED | ||
}; | ||
return { | ||
kind: exports.PlanKind.CONDITIONAL, | ||
filters: mapOperand(queryPlan.condition, (key) => { | ||
if (typeof fieldNameMapper === "function") { | ||
return fieldNameMapper(key); | ||
} | ||
else { | ||
return (fieldNameMapper[key] = fieldNameMapper[key] || key); | ||
} | ||
}, (key) => { | ||
if (typeof relationMapper === "function") { | ||
return relationMapper(key); | ||
} | ||
else if (relationMapper[key]) { | ||
return relationMapper[key]; | ||
} | ||
return null; | ||
}, {}) | ||
const toFieldName = (key) => { | ||
if (typeof fieldNameMapper === "function") { | ||
return fieldNameMapper(key); | ||
} | ||
else if (fieldNameMapper[key]) { | ||
return fieldNameMapper[key]; | ||
} | ||
else { | ||
return key; | ||
} | ||
}; | ||
const toRelationName = (key) => { | ||
if (typeof relationMapper === "function") { | ||
return relationMapper(key); | ||
} | ||
else if (relationMapper[key]) { | ||
return relationMapper[key]; | ||
} | ||
return null; | ||
}; | ||
switch (queryPlan.kind) { | ||
case exports.PlanKind.ALWAYS_ALLOWED: | ||
return { | ||
kind: exports.PlanKind.ALWAYS_ALLOWED, | ||
filters: {} | ||
}; | ||
case exports.PlanKind.ALWAYS_DENIED: | ||
return { | ||
kind: exports.PlanKind.ALWAYS_DENIED | ||
}; | ||
case exports.PlanKind.CONDITIONAL: | ||
return { | ||
kind: exports.PlanKind.CONDITIONAL, | ||
filters: mapOperand(queryPlan.condition, toFieldName, toRelationName) | ||
}; | ||
default: | ||
throw Error(`Invalid query plan.`); | ||
} | ||
} | ||
@@ -47,3 +57,3 @@ exports.queryPlanToPrisma = queryPlanToPrisma; | ||
} | ||
function getOperandName(operands) { | ||
function getOperandVariable(operands) { | ||
const op = operands.find(o => o.hasOwnProperty("name")); | ||
@@ -55,3 +65,3 @@ if (!op) | ||
function getOperandValue(operands) { | ||
const op = operands.find(o => o.hasOwnProperty("value")); | ||
const op = operands.find(o => isValue(o)); | ||
if (!op) | ||
@@ -61,88 +71,80 @@ return; | ||
} | ||
const OPERATORS = { | ||
"eq": { | ||
relationalCondition: "is", | ||
fieldCondition: "equals" | ||
}, | ||
"ne": { | ||
relationalCondition: "isNot", | ||
fieldCondition: "not" | ||
}, | ||
"in": { | ||
relationalCondition: "some", | ||
fieldCondition: "in" | ||
}, | ||
"lt": { | ||
fieldCondition: "lt" | ||
}, | ||
"gt": { | ||
fieldCondition: "gt" | ||
}, | ||
"le": { | ||
fieldCondition: "lte" | ||
}, | ||
"ge": { | ||
fieldCondition: "gte" | ||
} | ||
}; | ||
function mapOperand(operand, getFieldName, getRelationName, output = {}) { | ||
if (isExpression(operand)) { | ||
const { operator, operands } = operand; | ||
const opName = getOperandName(operands); | ||
const opValue = getOperandValue(operands); | ||
const relation = opName && getRelationName(opName); | ||
const fieldName = opName && getFieldName(opName); | ||
if (operator == "and") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
} | ||
if (operator == "or") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
} | ||
if (operator == "not") { | ||
if (operands.length > 1) | ||
throw Error("Expected only one operand"); | ||
output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0]; | ||
} | ||
if (operator == "eq") { | ||
if (relation) { | ||
output[relation.relation] = { | ||
is: { | ||
[relation.field]: opValue | ||
} | ||
}; | ||
if (!isExpression(operand)) | ||
throw Error(`Query plan did not contain an expression for operand ${operand}`); | ||
const { operator, operands } = operand; | ||
// HANDLE NESTING OPERATIONS: AND/OR/NOT | ||
if (operator == "and") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
return output; | ||
} | ||
if (operator == "or") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
return output; | ||
} | ||
if (operator == "not") { | ||
if (operands.length > 1) | ||
throw Error("Expected only one operand"); | ||
output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0]; | ||
return output; | ||
} | ||
// get the operation parameters | ||
const operation = OPERATORS[operator]; | ||
if (!operation) | ||
throw Error(`Unsupported operator ${operator}`); | ||
const opVariable = getOperandVariable(operands); | ||
if (!opVariable) | ||
throw Error(`Unexpected variable ${operands}`); | ||
const opValue = getOperandValue(operands); | ||
const relation = getRelationName(opVariable); | ||
const fieldName = getFieldName(opVariable); | ||
// There is a relational mapper for this variable | ||
if (relation && operation.relationalCondition) { | ||
output[relation.relation] = { | ||
[operation.relationalCondition]: { | ||
[relation.field]: opValue | ||
} | ||
else if (fieldName) { | ||
output[fieldName] = { | ||
equals: opValue, | ||
}; | ||
} | ||
} | ||
if (operator == "ne") { | ||
if (relation) { | ||
output[relation.relation] = { | ||
isNot: { | ||
[relation.field]: opValue | ||
} | ||
}; | ||
} | ||
else if (fieldName) { | ||
output[fieldName] = { | ||
not: opValue, | ||
}; | ||
} | ||
} | ||
if (operator == "lt" && fieldName) { | ||
output[fieldName] = { | ||
lt: opValue, | ||
}; | ||
} | ||
if (operator == "gt" && fieldName) { | ||
output[fieldName] = { | ||
gt: opValue, | ||
}; | ||
} | ||
if (operator == "le" && fieldName) { | ||
output[fieldName] = { | ||
lte: opValue, | ||
}; | ||
} | ||
if (operator == "ge" && fieldName) { | ||
output[fieldName] = { | ||
gte: opValue, | ||
}; | ||
} | ||
if (operator == "in") { | ||
if (relation) { | ||
output[relation.relation] = { | ||
some: { | ||
[relation.field]: opValue | ||
} | ||
}; | ||
} | ||
else if (fieldName) { | ||
output[fieldName] = { | ||
in: opValue, | ||
}; | ||
} | ||
} | ||
}; | ||
return output; | ||
} | ||
return output; | ||
else if (fieldName && operation.fieldCondition) { | ||
// There is a field mapper for this variable | ||
output[fieldName] = { | ||
[operation.fieldCondition]: opValue, | ||
}; | ||
return output; | ||
} | ||
else { | ||
throw Error("Failed to map"); | ||
} | ||
} |
226
lib/index.js
import { PlanKind as PK } from "@cerbos/core"; | ||
export const PlanKind = PK; | ||
export function queryPlanToPrisma({ queryPlan, fieldNameMapper, relationMapper = {} }) { | ||
if (queryPlan.kind === PlanKind.ALWAYS_ALLOWED) | ||
return { | ||
kind: PlanKind.ALWAYS_ALLOWED, | ||
filters: {} | ||
}; | ||
if (queryPlan.kind === PlanKind.ALWAYS_DENIED) | ||
return { | ||
kind: PlanKind.ALWAYS_DENIED | ||
}; | ||
return { | ||
kind: PlanKind.CONDITIONAL, | ||
filters: mapOperand(queryPlan.condition, (key) => { | ||
if (typeof fieldNameMapper === "function") { | ||
return fieldNameMapper(key); | ||
} | ||
else { | ||
return (fieldNameMapper[key] = fieldNameMapper[key] || key); | ||
} | ||
}, (key) => { | ||
if (typeof relationMapper === "function") { | ||
return relationMapper(key); | ||
} | ||
else if (relationMapper[key]) { | ||
return relationMapper[key]; | ||
} | ||
return null; | ||
}, {}) | ||
const toFieldName = (key) => { | ||
if (typeof fieldNameMapper === "function") { | ||
return fieldNameMapper(key); | ||
} | ||
else if (fieldNameMapper[key]) { | ||
return fieldNameMapper[key]; | ||
} | ||
else { | ||
return key; | ||
} | ||
}; | ||
const toRelationName = (key) => { | ||
if (typeof relationMapper === "function") { | ||
return relationMapper(key); | ||
} | ||
else if (relationMapper[key]) { | ||
return relationMapper[key]; | ||
} | ||
return null; | ||
}; | ||
switch (queryPlan.kind) { | ||
case PlanKind.ALWAYS_ALLOWED: | ||
return { | ||
kind: PlanKind.ALWAYS_ALLOWED, | ||
filters: {} | ||
}; | ||
case PlanKind.ALWAYS_DENIED: | ||
return { | ||
kind: PlanKind.ALWAYS_DENIED | ||
}; | ||
case PlanKind.CONDITIONAL: | ||
return { | ||
kind: PlanKind.CONDITIONAL, | ||
filters: mapOperand(queryPlan.condition, toFieldName, toRelationName) | ||
}; | ||
default: | ||
throw Error(`Invalid query plan.`); | ||
} | ||
} | ||
@@ -42,3 +52,3 @@ function isExpression(e) { | ||
} | ||
function getOperandName(operands) { | ||
function getOperandVariable(operands) { | ||
const op = operands.find(o => o.hasOwnProperty("name")); | ||
@@ -50,3 +60,3 @@ if (!op) | ||
function getOperandValue(operands) { | ||
const op = operands.find(o => o.hasOwnProperty("value")); | ||
const op = operands.find(o => isValue(o)); | ||
if (!op) | ||
@@ -56,88 +66,80 @@ return; | ||
} | ||
const OPERATORS = { | ||
"eq": { | ||
relationalCondition: "is", | ||
fieldCondition: "equals" | ||
}, | ||
"ne": { | ||
relationalCondition: "isNot", | ||
fieldCondition: "not" | ||
}, | ||
"in": { | ||
relationalCondition: "some", | ||
fieldCondition: "in" | ||
}, | ||
"lt": { | ||
fieldCondition: "lt" | ||
}, | ||
"gt": { | ||
fieldCondition: "gt" | ||
}, | ||
"le": { | ||
fieldCondition: "lte" | ||
}, | ||
"ge": { | ||
fieldCondition: "gte" | ||
} | ||
}; | ||
function mapOperand(operand, getFieldName, getRelationName, output = {}) { | ||
if (isExpression(operand)) { | ||
const { operator, operands } = operand; | ||
const opName = getOperandName(operands); | ||
const opValue = getOperandValue(operands); | ||
const relation = opName && getRelationName(opName); | ||
const fieldName = opName && getFieldName(opName); | ||
if (operator == "and") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
} | ||
if (operator == "or") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
} | ||
if (operator == "not") { | ||
if (operands.length > 1) | ||
throw Error("Expected only one operand"); | ||
output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0]; | ||
} | ||
if (operator == "eq") { | ||
if (relation) { | ||
output[relation.relation] = { | ||
is: { | ||
[relation.field]: opValue | ||
} | ||
}; | ||
if (!isExpression(operand)) | ||
throw Error(`Query plan did not contain an expression for operand ${operand}`); | ||
const { operator, operands } = operand; | ||
// HANDLE NESTING OPERATIONS: AND/OR/NOT | ||
if (operator == "and") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.AND = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
return output; | ||
} | ||
if (operator == "or") { | ||
if (operands.length < 2) | ||
throw Error("Expected atleast 2 operands"); | ||
output.OR = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {})); | ||
return output; | ||
} | ||
if (operator == "not") { | ||
if (operands.length > 1) | ||
throw Error("Expected only one operand"); | ||
output.NOT = operands.map((o) => mapOperand(o, getFieldName, getRelationName, {}))[0]; | ||
return output; | ||
} | ||
// get the operation parameters | ||
const operation = OPERATORS[operator]; | ||
if (!operation) | ||
throw Error(`Unsupported operator ${operator}`); | ||
const opVariable = getOperandVariable(operands); | ||
if (!opVariable) | ||
throw Error(`Unexpected variable ${operands}`); | ||
const opValue = getOperandValue(operands); | ||
const relation = getRelationName(opVariable); | ||
const fieldName = getFieldName(opVariable); | ||
// There is a relational mapper for this variable | ||
if (relation && operation.relationalCondition) { | ||
output[relation.relation] = { | ||
[operation.relationalCondition]: { | ||
[relation.field]: opValue | ||
} | ||
else if (fieldName) { | ||
output[fieldName] = { | ||
equals: opValue, | ||
}; | ||
} | ||
} | ||
if (operator == "ne") { | ||
if (relation) { | ||
output[relation.relation] = { | ||
isNot: { | ||
[relation.field]: opValue | ||
} | ||
}; | ||
} | ||
else if (fieldName) { | ||
output[fieldName] = { | ||
not: opValue, | ||
}; | ||
} | ||
} | ||
if (operator == "lt" && fieldName) { | ||
output[fieldName] = { | ||
lt: opValue, | ||
}; | ||
} | ||
if (operator == "gt" && fieldName) { | ||
output[fieldName] = { | ||
gt: opValue, | ||
}; | ||
} | ||
if (operator == "le" && fieldName) { | ||
output[fieldName] = { | ||
lte: opValue, | ||
}; | ||
} | ||
if (operator == "ge" && fieldName) { | ||
output[fieldName] = { | ||
gte: opValue, | ||
}; | ||
} | ||
if (operator == "in") { | ||
if (relation) { | ||
output[relation.relation] = { | ||
some: { | ||
[relation.field]: opValue | ||
} | ||
}; | ||
} | ||
else if (fieldName) { | ||
output[fieldName] = { | ||
in: opValue, | ||
}; | ||
} | ||
} | ||
}; | ||
return output; | ||
} | ||
return output; | ||
else if (fieldName && operation.fieldCondition) { | ||
// There is a field mapper for this variable | ||
output[fieldName] = { | ||
[operation.fieldCondition]: opValue, | ||
}; | ||
return output; | ||
} | ||
else { | ||
throw Error("Failed to map"); | ||
} | ||
} |
{ | ||
"name": "@cerbos/orm-prisma", | ||
"version": "1.0.0-alpha.0", | ||
"version": "1.0.0", | ||
"homepage": "https://cerbos.dev", | ||
@@ -5,0 +5,0 @@ "description": "", |
@@ -15,4 +15,4 @@ # Cerbos + Prisma ORM Adapter | ||
- `endsWith` | ||
- `isSet` | ||
- Scalar filters | ||
- Composite type filters | ||
- Atomic number operations | ||
@@ -19,0 +19,0 @@ - Composite keys |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
336
0
0
15944