@cerbos/orm-prisma 4.0.0 → 5.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 +611 -460
- package/lib/collections.d.ts +30 -0
- package/lib/collections.d.ts.map +1 -0
- package/lib/collections.js +421 -0
- package/lib/collections.js.map +1 -0
- package/lib/comparison.d.ts +24 -0
- package/lib/comparison.d.ts.map +1 -0
- package/lib/comparison.js +731 -0
- package/lib/comparison.js.map +1 -0
- package/lib/errors.d.ts +13 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +17 -0
- package/lib/errors.js.map +1 -0
- package/lib/evaluate.d.ts +5 -0
- package/lib/evaluate.d.ts.map +1 -0
- package/lib/evaluate.js +118 -0
- package/lib/evaluate.js.map +1 -0
- package/lib/fields.d.ts +34 -0
- package/lib/fields.d.ts.map +1 -0
- package/lib/fields.js +253 -0
- package/lib/fields.js.map +1 -0
- package/lib/functions.d.ts +5 -0
- package/lib/functions.d.ts.map +1 -0
- package/lib/functions.js +408 -0
- package/lib/functions.js.map +1 -0
- package/lib/hierarchy.d.ts +6 -0
- package/lib/hierarchy.d.ts.map +1 -0
- package/lib/hierarchy.js +266 -0
- package/lib/hierarchy.js.map +1 -0
- package/lib/index.d.ts +91 -8
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +34 -2301
- package/lib/index.js.map +1 -1
- package/lib/literals.d.ts +20 -0
- package/lib/literals.d.ts.map +1 -0
- package/lib/literals.js +290 -0
- package/lib/literals.js.map +1 -0
- package/lib/mapping.d.ts +95 -0
- package/lib/mapping.d.ts.map +1 -0
- package/lib/mapping.js +316 -0
- package/lib/mapping.js.map +1 -0
- package/lib/narrowing.d.ts +12 -0
- package/lib/narrowing.d.ts.map +1 -0
- package/lib/narrowing.js +32 -0
- package/lib/narrowing.js.map +1 -0
- package/lib/plan.d.ts +49 -0
- package/lib/plan.d.ts.map +1 -0
- package/lib/plan.js +86 -0
- package/lib/plan.js.map +1 -0
- package/lib/presence.d.ts +25 -0
- package/lib/presence.d.ts.map +1 -0
- package/lib/presence.js +82 -0
- package/lib/presence.js.map +1 -0
- package/lib/regex.d.ts +33 -0
- package/lib/regex.d.ts.map +1 -0
- package/lib/regex.js +480 -0
- package/lib/regex.js.map +1 -0
- package/lib/relations.d.ts +58 -0
- package/lib/relations.d.ts.map +1 -0
- package/lib/relations.js +175 -0
- package/lib/relations.js.map +1 -0
- package/lib/rewrite.d.ts +36 -0
- package/lib/rewrite.d.ts.map +1 -0
- package/lib/rewrite.js +366 -0
- package/lib/rewrite.js.map +1 -0
- package/lib/solve.d.ts +20 -0
- package/lib/solve.d.ts.map +1 -0
- package/lib/solve.js +77 -0
- package/lib/solve.js.map +1 -0
- package/lib/strings.d.ts +12 -0
- package/lib/strings.d.ts.map +1 -0
- package/lib/strings.js +110 -0
- package/lib/strings.js.map +1 -0
- package/lib/ternary.d.ts +12 -0
- package/lib/ternary.d.ts.map +1 -0
- package/lib/ternary.js +192 -0
- package/lib/ternary.js.map +1 -0
- package/lib/timestamp.d.ts +45 -0
- package/lib/timestamp.d.ts.map +1 -0
- package/lib/timestamp.js +225 -0
- package/lib/timestamp.js.map +1 -0
- package/lib/translate.d.ts +20 -0
- package/lib/translate.d.ts.map +1 -0
- package/lib/translate.js +287 -0
- package/lib/translate.js.map +1 -0
- package/lib/types.d.ts +29 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +980 -0
- package/lib/types.js.map +1 -0
- package/lib/value.d.ts +8 -0
- package/lib/value.d.ts.map +1 -0
- package/lib/value.js +7 -0
- package/lib/value.js.map +1 -0
- package/package.json +31 -18
- package/src/adversarial.test.ts +488 -488
- package/src/collections.ts +738 -0
- package/src/comparison.ts +1157 -0
- package/src/corpus.ts +597 -0
- package/src/errors.ts +12 -0
- package/src/evaluate.ts +170 -0
- package/src/fields.ts +373 -0
- package/src/functions.ts +548 -0
- package/src/generated/prisma-adversarial/browser.ts +20 -0
- package/src/generated/prisma-adversarial/client.ts +20 -0
- package/src/generated/prisma-adversarial/commonInputTypes.ts +116 -127
- package/src/generated/prisma-adversarial/internal/class.ts +44 -4
- package/src/generated/prisma-adversarial/internal/prismaNamespace.ts +350 -3
- package/src/generated/prisma-adversarial/internal/prismaNamespaceBrowser.ts +49 -2
- package/src/generated/prisma-adversarial/models/AdversarialBoolListElement.ts +1272 -0
- package/src/generated/prisma-adversarial/models/AdversarialInner.ts +1369 -0
- package/src/generated/prisma-adversarial/models/AdversarialNumberListElement.ts +1316 -0
- package/src/generated/prisma-adversarial/models/AdversarialParent.ts +1474 -0
- package/src/generated/prisma-adversarial/models/AdversarialResource.ts +547 -75
- package/src/generated/prisma-adversarial/models.ts +4 -0
- package/src/generated/prisma-adversarial-mysql/browser.ts +64 -0
- package/src/generated/{prisma → prisma-adversarial-mysql}/client.ts +23 -18
- package/src/generated/{prisma → prisma-adversarial-mysql}/commonInputTypes.ts +167 -92
- package/src/generated/prisma-adversarial-mysql/internal/class.ts +284 -0
- package/src/generated/prisma-adversarial-mysql/internal/prismaNamespace.ts +1518 -0
- package/src/generated/prisma-adversarial-mysql/internal/prismaNamespaceBrowser.ts +274 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialBoolListElement.ts +1157 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialCategory.ts +1286 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialInner.ts +1247 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialLabel.ts +1157 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialNumberListElement.ts +1201 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialParent.ts +1352 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialResource.ts +2021 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialSubCategory.ts +1286 -0
- package/src/generated/prisma-adversarial-mysql/models/AdversarialTag.ts +1190 -0
- package/src/generated/prisma-adversarial-mysql/models.ts +20 -0
- package/src/generated/prisma-adversarial-mysql-v6/index.d.ts +13822 -0
- package/src/generated/prisma-adversarial-pg/browser.ts +64 -0
- package/src/generated/prisma-adversarial-pg/client.ts +86 -0
- package/src/generated/prisma-adversarial-pg/commonInputTypes.ts +345 -0
- package/src/generated/prisma-adversarial-pg/enums.ts +15 -0
- package/src/generated/prisma-adversarial-pg/internal/class.ts +284 -0
- package/src/generated/prisma-adversarial-pg/internal/prismaNamespace.ts +1542 -0
- package/src/generated/{prisma → prisma-adversarial-pg}/internal/prismaNamespaceBrowser.ts +72 -43
- package/src/generated/prisma-adversarial-pg/models/AdversarialBoolListElement.ts +1275 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialCategory.ts +1404 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialInner.ts +1371 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialLabel.ts +1275 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialNumberListElement.ts +1319 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialParent.ts +1476 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialResource.ts +2139 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialSubCategory.ts +1404 -0
- package/src/generated/prisma-adversarial-pg/models/AdversarialTag.ts +1310 -0
- package/src/generated/prisma-adversarial-pg/models.ts +20 -0
- package/src/generated/prisma-adversarial-pg-v6/client.d.ts +1 -0
- package/src/generated/prisma-adversarial-pg-v6/default.d.ts +1 -0
- package/src/generated/prisma-adversarial-pg-v6/edge.d.ts +1 -0
- package/src/generated/prisma-adversarial-pg-v6/index.d.ts +14918 -0
- package/src/generated/prisma-adversarial-pg-v6/runtime/index-browser.d.ts +370 -0
- package/src/generated/prisma-adversarial-pg-v6/runtime/library.d.ts +3982 -0
- package/src/generated/prisma-adversarial-pg-v6/wasm.d.ts +1 -0
- package/src/generated/prisma-adversarial-v6/index.d.ts +6515 -304
- package/src/hierarchy.ts +405 -0
- package/src/index.ts +134 -3325
- package/src/literals.ts +363 -0
- package/src/mapping.ts +474 -0
- package/src/narrowing.ts +33 -0
- package/src/plan.ts +125 -0
- package/src/presence.ts +114 -0
- package/src/regex.ts +596 -0
- package/src/relations.ts +226 -0
- package/src/rewrite.ts +524 -0
- package/src/solve.ts +96 -0
- package/src/strings.ts +152 -0
- package/src/ternary.ts +359 -0
- package/src/test-setup.adversarial-url.ts +21 -0
- package/src/test-setup.adversarial.mysql.v6.ts +13 -0
- package/src/test-setup.adversarial.mysql.v7.ts +12 -0
- package/src/test-setup.adversarial.pg.v6.ts +13 -0
- package/src/test-setup.adversarial.pg.v7.ts +9 -0
- package/src/test-setup.adversarial.v7.ts +1 -0
- package/src/timestamp.ts +308 -0
- package/src/translate.ts +419 -0
- package/src/translator.test.ts +766 -0
- package/src/types.ts +1310 -0
- package/src/value.ts +16 -0
- package/src/generated/prisma/browser.ts +0 -59
- package/src/generated/prisma/internal/class.ts +0 -274
- package/src/generated/prisma/internal/prismaNamespace.ts +0 -1403
- package/src/generated/prisma/models/Category.ts +0 -1412
- package/src/generated/prisma/models/Label.ts +0 -1276
- package/src/generated/prisma/models/NestedResource.ts +0 -1562
- package/src/generated/prisma/models/NextLevelNestedResource.ts +0 -1337
- package/src/generated/prisma/models/Resource.ts +0 -2196
- package/src/generated/prisma/models/SubCategory.ts +0 -1412
- package/src/generated/prisma/models/Tag.ts +0 -1276
- package/src/generated/prisma/models/User.ts +0 -1503
- package/src/generated/prisma/models.ts +0 -19
- package/src/generated/prisma-v6/index.d.ts +0 -13726
- package/src/index.test.ts +0 -8885
- package/src/test-setup.v6.ts +0 -5
- package/src/test-setup.v7.ts +0 -7
- /package/src/generated/{prisma → prisma-adversarial-mysql}/enums.ts +0 -0
- /package/src/generated/{prisma-v6 → prisma-adversarial-mysql-v6}/client.d.ts +0 -0
- /package/src/generated/{prisma-v6 → prisma-adversarial-mysql-v6}/default.d.ts +0 -0
- /package/src/generated/{prisma-v6 → prisma-adversarial-mysql-v6}/edge.d.ts +0 -0
- /package/src/generated/{prisma-v6 → prisma-adversarial-mysql-v6}/runtime/index-browser.d.ts +0 -0
- /package/src/generated/{prisma-v6 → prisma-adversarial-mysql-v6}/runtime/library.d.ts +0 -0
- /package/src/generated/{prisma-v6 → prisma-adversarial-mysql-v6}/wasm.d.ts +0 -0
package/lib/hierarchy.js
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The hierarchy operators: `overlaps`, `ancestorOf`, `descendentOf` over `hierarchy(...)`
|
|
3
|
+
// operands, lowered to equality, IN-lists of strict prefixes, and a prefix match on a column.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.handleOverlapsOperator = handleOverlapsOperator;
|
|
6
|
+
exports.handleAncestorDescendantOperator = handleAncestorDescendantOperator;
|
|
7
|
+
const fields_1 = require("./fields");
|
|
8
|
+
const mapping_1 = require("./mapping");
|
|
9
|
+
const plan_1 = require("./plan");
|
|
10
|
+
const translate_1 = require("./translate");
|
|
11
|
+
const errors_1 = require("./errors");
|
|
12
|
+
function resolveHierarchy(expr, context) {
|
|
13
|
+
const operands = expr.operands;
|
|
14
|
+
if (operands.length === 2) {
|
|
15
|
+
const strOperand = (0, plan_1.assertDefined)(operands[0], "hierarchy requires operands");
|
|
16
|
+
const delimOperand = (0, plan_1.assertDefined)(operands[1], "hierarchy requires a delimiter");
|
|
17
|
+
if (!(0, plan_1.isValueOperand)(delimOperand)) {
|
|
18
|
+
throw new errors_1.UnsupportedQueryPlanError("hierarchy delimiter must be a value");
|
|
19
|
+
}
|
|
20
|
+
const delimiter = String(delimOperand.value);
|
|
21
|
+
if ((0, plan_1.isValueOperand)(strOperand)) {
|
|
22
|
+
return {
|
|
23
|
+
type: "constant",
|
|
24
|
+
segments: splitPath(String(strOperand.value), delimiter),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if ((0, plan_1.isNamedOperand)(strOperand)) {
|
|
28
|
+
return {
|
|
29
|
+
type: "field",
|
|
30
|
+
fieldRef: (0, mapping_1.resolveFieldReference)(strOperand.name, context),
|
|
31
|
+
delimiter,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
throw new errors_1.UnsupportedQueryPlanError("hierarchy(string, delimiter) requires a value or field operand");
|
|
35
|
+
}
|
|
36
|
+
if (operands.length === 1) {
|
|
37
|
+
const inner = (0, plan_1.assertDefined)(operands[0], "hierarchy requires an operand");
|
|
38
|
+
if ((0, plan_1.isValueOperand)(inner)) {
|
|
39
|
+
return { type: "constant", segments: String(inner.value).split(".") };
|
|
40
|
+
}
|
|
41
|
+
if ((0, plan_1.isNamedOperand)(inner)) {
|
|
42
|
+
return {
|
|
43
|
+
type: "field",
|
|
44
|
+
fieldRef: (0, mapping_1.resolveFieldReference)(inner.name, context),
|
|
45
|
+
delimiter: ".",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if ((0, plan_1.isOperatorOperand)(inner) && inner.operator === "list") {
|
|
49
|
+
const segments = inner.operands.map((op) => {
|
|
50
|
+
const resolved = (0, translate_1.resolveOperand)(op, context);
|
|
51
|
+
if ((0, mapping_1.isResolvedValue)(resolved)) {
|
|
52
|
+
return { type: "constant", value: String(resolved.value) };
|
|
53
|
+
}
|
|
54
|
+
return { type: "field", fieldRef: resolved };
|
|
55
|
+
});
|
|
56
|
+
return { type: "segmented", segments };
|
|
57
|
+
}
|
|
58
|
+
throw new errors_1.UnsupportedQueryPlanError("hierarchy requires a value, field, or list operand");
|
|
59
|
+
}
|
|
60
|
+
throw new errors_1.UnsupportedQueryPlanError("hierarchy requires 1 or 2 operands");
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Cerbos splits a path with Go's `strings.Split`: an empty delimiter yields one segment per code
|
|
64
|
+
* point, and an empty path then has no segments at all.
|
|
65
|
+
*/
|
|
66
|
+
function splitPath(path, delimiter) {
|
|
67
|
+
return delimiter === "" ? Array.from(path) : path.split(delimiter);
|
|
68
|
+
}
|
|
69
|
+
function toSegments(resolved) {
|
|
70
|
+
switch (resolved.type) {
|
|
71
|
+
case "constant":
|
|
72
|
+
return resolved.segments.map((s) => ({ type: "constant", value: s }));
|
|
73
|
+
case "segmented":
|
|
74
|
+
return resolved.segments;
|
|
75
|
+
case "field":
|
|
76
|
+
throw new errors_1.UnsupportedQueryPlanError("Cannot get segments from a field-reference hierarchy");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** A segmented hierarchy whose segments are all constants is a constant hierarchy. */
|
|
80
|
+
function normalizeHierarchy(h) {
|
|
81
|
+
if (h.type !== "segmented")
|
|
82
|
+
return h;
|
|
83
|
+
const constants = [];
|
|
84
|
+
for (const segment of h.segments) {
|
|
85
|
+
if (segment.type !== "constant")
|
|
86
|
+
return h;
|
|
87
|
+
constants.push(segment.value);
|
|
88
|
+
}
|
|
89
|
+
return { type: "constant", segments: constants };
|
|
90
|
+
}
|
|
91
|
+
function checkPrefixConditions(shorter, longer) {
|
|
92
|
+
if (shorter.length > longer.length)
|
|
93
|
+
return null;
|
|
94
|
+
const conditions = [];
|
|
95
|
+
for (let i = 0; i < shorter.length; i++) {
|
|
96
|
+
const s = shorter[i];
|
|
97
|
+
const l = longer[i];
|
|
98
|
+
if (s.type === "constant" && l.type === "constant") {
|
|
99
|
+
if (s.value !== l.value)
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
else if (s.type === "field" && l.type === "constant") {
|
|
103
|
+
conditions.push((0, fields_1.buildFieldFilter)(s.fieldRef, "equals", l.value));
|
|
104
|
+
}
|
|
105
|
+
else if (s.type === "constant" && l.type === "field") {
|
|
106
|
+
conditions.push((0, fields_1.buildFieldFilter)(l.fieldRef, "equals", s.value));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
throw new errors_1.UnsupportedQueryPlanError("Cannot compare two field references in hierarchy overlap");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (conditions.length === 0)
|
|
113
|
+
return {};
|
|
114
|
+
if (conditions.length === 1)
|
|
115
|
+
return conditions[0];
|
|
116
|
+
return { AND: conditions };
|
|
117
|
+
}
|
|
118
|
+
function handleOverlapsOperator(operands, context) {
|
|
119
|
+
const [left, right] = extractHierarchyOperands("overlaps", operands, context);
|
|
120
|
+
if (left.type === "field" || right.type === "field") {
|
|
121
|
+
return handleFieldOverlaps(left, right);
|
|
122
|
+
}
|
|
123
|
+
const leftSegs = toSegments(left);
|
|
124
|
+
const rightSegs = toSegments(right);
|
|
125
|
+
const leftPrefixOfRight = checkPrefixConditions(leftSegs, rightSegs);
|
|
126
|
+
const rightPrefixOfLeft = checkPrefixConditions(rightSegs, leftSegs);
|
|
127
|
+
const validConditions = [leftPrefixOfRight, rightPrefixOfLeft].filter((c) => c !== null);
|
|
128
|
+
// Hierarchy construction evaluates every segment, including a trailing segment that
|
|
129
|
+
// neither prefix comparison needs. Preserve its SQL UNKNOWN under outer negation too.
|
|
130
|
+
const fields = [...leftSegs, ...rightSegs]
|
|
131
|
+
.filter((segment) => segment.type === "field")
|
|
132
|
+
.filter((segment) => segment.fieldRef.nullable !== false);
|
|
133
|
+
const pairs = fields.map(({ fieldRef }) => ({
|
|
134
|
+
equal: (0, fields_1.buildFieldFilter)(fieldRef, "equals", ""),
|
|
135
|
+
unequal: (0, fields_1.buildFieldFilter)(fieldRef, "not", ""),
|
|
136
|
+
}));
|
|
137
|
+
const presence = pairs.map(({ equal, unequal }) => ({
|
|
138
|
+
OR: [equal, unequal],
|
|
139
|
+
}));
|
|
140
|
+
const unknown = pairs.map(({ equal, unequal }) => ({
|
|
141
|
+
AND: [equal, unequal],
|
|
142
|
+
}));
|
|
143
|
+
if (validConditions.length === 0) {
|
|
144
|
+
if (unknown.length > 0)
|
|
145
|
+
return { OR: unknown };
|
|
146
|
+
const field = [...leftSegs, ...rightSegs].find((segment) => segment.type === "field");
|
|
147
|
+
if (field)
|
|
148
|
+
return (0, fields_1.buildImpossibleFilter)(field.fieldRef);
|
|
149
|
+
throw new errors_1.UnsupportedQueryPlanError("Cannot determine overlap: no field references found");
|
|
150
|
+
}
|
|
151
|
+
if (validConditions.some((condition) => Object.keys(condition).length === 0)) {
|
|
152
|
+
return presence.length === 0 ? {} : { AND: presence };
|
|
153
|
+
}
|
|
154
|
+
// Equal-length comparisons are identical in either direction. A contradiction is
|
|
155
|
+
// FALSE for a present field and UNKNOWN for NULL, restoring errors even if the
|
|
156
|
+
// prefix comparison is FALSE (FALSE AND NULL alone would lose that error).
|
|
157
|
+
const condition = validConditions[0];
|
|
158
|
+
return presence.length === 0
|
|
159
|
+
? condition
|
|
160
|
+
: {
|
|
161
|
+
OR: [{ AND: [condition, ...presence] }, ...unknown],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function handleFieldOverlaps(left, right) {
|
|
165
|
+
if (left.type === "field" && right.type === "field") {
|
|
166
|
+
throw new errors_1.UnsupportedQueryPlanError("overlaps: cannot compare two field-reference hierarchies");
|
|
167
|
+
}
|
|
168
|
+
// The caller routes here only when at least one side is a field hierarchy.
|
|
169
|
+
const field = left.type === "field" ? left : right.type === "field" ? right : undefined;
|
|
170
|
+
if (field === undefined) {
|
|
171
|
+
throw new errors_1.UnsupportedQueryPlanError("overlaps: neither side is a field-reference hierarchy");
|
|
172
|
+
}
|
|
173
|
+
const other = field === left ? right : left;
|
|
174
|
+
if (other.type !== "constant") {
|
|
175
|
+
throw new errors_1.UnsupportedQueryPlanError("overlaps: segmented hierarchies with field hierarchies are not supported");
|
|
176
|
+
}
|
|
177
|
+
const delimiter = field.delimiter;
|
|
178
|
+
const otherRaw = other.segments.join(delimiter);
|
|
179
|
+
const strictPrefixes = getStrictPrefixes(other.segments, delimiter);
|
|
180
|
+
const conditions = [];
|
|
181
|
+
if (strictPrefixes.length > 0) {
|
|
182
|
+
conditions.push((0, fields_1.buildFieldFilter)(field.fieldRef, "in", strictPrefixes));
|
|
183
|
+
}
|
|
184
|
+
conditions.push((0, fields_1.buildFieldFilter)(field.fieldRef, "equals", otherRaw));
|
|
185
|
+
conditions.push((0, fields_1.buildPrefixFilter)(field.fieldRef, otherRaw + delimiter));
|
|
186
|
+
return { OR: conditions };
|
|
187
|
+
}
|
|
188
|
+
function extractHierarchyOperands(operatorName, operands, context) {
|
|
189
|
+
if (operands.length !== 2) {
|
|
190
|
+
throw new errors_1.UnsupportedQueryPlanError(`${operatorName} requires exactly two operands`);
|
|
191
|
+
}
|
|
192
|
+
const leftOp = (0, plan_1.assertDefined)(operands[0], `${operatorName} requires a left operand`);
|
|
193
|
+
const rightOp = (0, plan_1.assertDefined)(operands[1], `${operatorName} requires a right operand`);
|
|
194
|
+
if (!(0, plan_1.isOperatorOperand)(leftOp) || leftOp.operator !== "hierarchy" ||
|
|
195
|
+
!(0, plan_1.isOperatorOperand)(rightOp) || rightOp.operator !== "hierarchy") {
|
|
196
|
+
throw new errors_1.UnsupportedQueryPlanError(`${operatorName} requires two hierarchy operands`);
|
|
197
|
+
}
|
|
198
|
+
return [
|
|
199
|
+
normalizeHierarchy(resolveHierarchy(leftOp, context)),
|
|
200
|
+
normalizeHierarchy(resolveHierarchy(rightOp, context)),
|
|
201
|
+
];
|
|
202
|
+
}
|
|
203
|
+
function getStrictPrefixes(segments, delimiter) {
|
|
204
|
+
if (delimiter === "") {
|
|
205
|
+
// Per code point, the empty path is itself a (zero-segment) strict prefix.
|
|
206
|
+
return segments.map((_, length) => segments.slice(0, length).join(""));
|
|
207
|
+
}
|
|
208
|
+
if (segments.length <= 1)
|
|
209
|
+
return [];
|
|
210
|
+
const prefixes = [];
|
|
211
|
+
let current = segments[0];
|
|
212
|
+
prefixes.push(current);
|
|
213
|
+
for (let i = 1; i < segments.length - 1; i++) {
|
|
214
|
+
current = current + delimiter + segments[i];
|
|
215
|
+
prefixes.push(current);
|
|
216
|
+
}
|
|
217
|
+
return prefixes;
|
|
218
|
+
}
|
|
219
|
+
function handleAncestorDescendantOperator(operands, context, direction) {
|
|
220
|
+
const operatorName = direction === "ancestor" ? "ancestorOf" : "descendentOf";
|
|
221
|
+
const [left, right] = extractHierarchyOperands(operatorName, operands, context);
|
|
222
|
+
// ancestorOf(A, B) = A is strict prefix of B
|
|
223
|
+
// descendentOf(A, B) = B is strict prefix of A
|
|
224
|
+
const ancestor = direction === "ancestor" ? left : right;
|
|
225
|
+
const descendant = direction === "ancestor" ? right : left;
|
|
226
|
+
if (ancestor.type === "field")
|
|
227
|
+
(0, fields_1.assertStringField)(ancestor.fieldRef, operatorName);
|
|
228
|
+
if (descendant.type === "field")
|
|
229
|
+
(0, fields_1.assertStringField)(descendant.fieldRef, operatorName);
|
|
230
|
+
if (ancestor.type === "constant" && descendant.type === "field") {
|
|
231
|
+
if (descendant.delimiter === "") {
|
|
232
|
+
// Per code point, a descendant is the ancestor followed by at least one more character.
|
|
233
|
+
return (0, fields_1.buildPrefixFilter)(descendant.fieldRef, ancestor.segments.join(""), true);
|
|
234
|
+
}
|
|
235
|
+
return (0, fields_1.buildPrefixFilter)(descendant.fieldRef, ancestor.segments.join(descendant.delimiter) + descendant.delimiter);
|
|
236
|
+
}
|
|
237
|
+
if (ancestor.type === "field" && descendant.type === "constant") {
|
|
238
|
+
const delimiter = ancestor.delimiter;
|
|
239
|
+
const prefixes = getStrictPrefixes(descendant.segments, delimiter);
|
|
240
|
+
if (prefixes.length === 0) {
|
|
241
|
+
if (ancestor.fieldRef.nullable === false)
|
|
242
|
+
return (0, fields_1.buildImpossibleFilter)(ancestor.fieldRef);
|
|
243
|
+
return {
|
|
244
|
+
AND: [
|
|
245
|
+
(0, fields_1.buildFieldFilter)(ancestor.fieldRef, "equals", ""),
|
|
246
|
+
(0, fields_1.buildFieldFilter)(ancestor.fieldRef, "not", ""),
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (prefixes.length === 1) {
|
|
251
|
+
return (0, fields_1.buildFieldFilter)(ancestor.fieldRef, "equals", prefixes[0]);
|
|
252
|
+
}
|
|
253
|
+
return (0, fields_1.buildFieldFilter)(ancestor.fieldRef, "in", prefixes);
|
|
254
|
+
}
|
|
255
|
+
if (ancestor.type === "constant" && descendant.type === "constant") {
|
|
256
|
+
const ancestorSegs = ancestor.segments;
|
|
257
|
+
const descendantSegs = descendant.segments;
|
|
258
|
+
if (descendantSegs.length > ancestorSegs.length &&
|
|
259
|
+
ancestorSegs.every((seg, i) => seg === descendantSegs[i])) {
|
|
260
|
+
return {};
|
|
261
|
+
}
|
|
262
|
+
throw new errors_1.UnsupportedQueryPlanError(`${operatorName}: constants do not satisfy ${direction} relationship`);
|
|
263
|
+
}
|
|
264
|
+
throw new errors_1.UnsupportedQueryPlanError(`${operatorName}: unsupported hierarchy type combination`);
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=hierarchy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hierarchy.js","sourceRoot":"","sources":["../src/hierarchy.ts"],"names":[],"mappings":";AAAA,0FAA0F;AAC1F,8FAA8F;;AA0L9F,wDAkEC;AAmFD,4EAoEC;AA/YD,qCAKkB;AAElB,uCAAmE;AAEnE,iCAKgB;AAEhB,2CAA6C;AAC7C,qCAAqD;AA0BrD,SAAS,gBAAgB,CACvB,IAAqB,EACrB,OAA2B;IAE3B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAE/B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAE7E,MAAM,YAAY,GAAG,IAAA,oBAAa,EAChC,QAAQ,CAAC,CAAC,CAAC,EACX,gCAAgC,CACjC,CAAC;QAEF,IAAI,CAAC,IAAA,qBAAc,EAAC,YAAY,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,kCAAyB,CAAC,qCAAqC,CAAC,CAAC;QAC7E,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAE7C,IAAI,IAAA,qBAAc,EAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;aACzD,CAAC;QACJ,CAAC;QAED,IAAI,IAAA,qBAAc,EAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,IAAA,+BAAqB,EAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;gBACzD,SAAS;aACV,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,kCAAyB,CAAC,gEAAgE,CAAC,CAAC;IACxG,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,+BAA+B,CAAC,CAAC;QAE1E,IAAI,IAAA,qBAAc,EAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxE,CAAC;QAED,IAAI,IAAA,qBAAc,EAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,IAAA,+BAAqB,EAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;gBACpD,SAAS,EAAE,GAAG;aACf,CAAC;QACJ,CAAC;QAED,IAAI,IAAA,wBAAiB,EAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAoB,EAAE;gBAC3D,MAAM,QAAQ,GAAG,IAAA,0BAAc,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAE7C,IAAI,IAAA,yBAAe,EAAC,QAAQ,CAAC,EAAE,CAAC;oBAC9B,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7D,CAAC;gBAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;YAC/C,CAAC,CAAC,CAAC;YAEH,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,IAAI,kCAAyB,CAAC,oDAAoD,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,IAAI,kCAAyB,CAAC,oCAAoC,CAAC,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,SAAiB;IAChD,OAAO,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,UAAU,CAAC,QAA2B;IAC7C,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,UAAmB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACjF,KAAK,WAAW;YACd,OAAO,QAAQ,CAAC,QAAQ,CAAC;QAC3B,KAAK,OAAO;YACV,MAAM,IAAI,kCAAyB,CACjC,sDAAsD,CACvD,CAAC;IACN,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,SAAS,kBAAkB,CAAC,CAAoB;IAC9C,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,CAAC,CAAC;IACrC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,OAAO,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACjC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,CAAC,CAAC;QAC1C,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACnD,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAA2B,EAC3B,MAA0B;IAE1B,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEhD,MAAM,UAAU,GAAmB,EAAE,CAAC;IAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QACtB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QAErB,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACnD,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;QACvC,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACvD,UAAU,CAAC,IAAI,CAAC,IAAA,yBAAgB,EAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACvD,UAAU,CAAC,IAAI,CAAC,IAAA,yBAAgB,EAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,kCAAyB,CACjC,0DAA0D,CAC3D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAE,CAAC;IAEnD,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;AAC7B,CAAC;AAED,SAAgB,sBAAsB,CACpC,QAAiC,EACjC,OAA2B;IAE3B,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,wBAAwB,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE9E,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACpD,OAAO,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAEpC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACrE,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAErE,MAAM,eAAe,GAAG,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,MAAM,CACnE,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC,KAAK,IAAI,CACrC,CAAC;IAEF,oFAAoF;IACpF,sFAAsF;IACtF,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,SAAS,CAAC;SACvC,MAAM,CAAC,CAAC,OAAO,EAA2B,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC;SACtE,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC;IAE5D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,KAAK,EAAE,IAAA,yBAAgB,EAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAA,yBAAgB,EAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;KAC/C,CAAC,CAAC,CAAC;IAEJ,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAClD,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC;KACrB,CAAC,CAAC,CAAC;IAEJ,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACjD,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC;KACtB,CAAC,CAAC,CAAC;IAEJ,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;QAE/C,MAAM,KAAK,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAC5C,CAAC,OAAO,EAA2B,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAC/D,CAAC;QAEF,IAAI,KAAK;YAAE,OAAO,IAAA,8BAAqB,EAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxD,MAAM,IAAI,kCAAyB,CAAC,qDAAqD,CAAC,CAAC;IAC7F,CAAC;IAED,IACE,eAAe,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,EACxE,CAAC;QACD,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;IACxD,CAAC;IAED,iFAAiF;IACjF,+EAA+E;IAC/E,2EAA2E;IAC3E,MAAM,SAAS,GAAG,eAAe,CAAC,CAAC,CAAE,CAAC;IAEtC,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC;QAC1B,CAAC,CAAC,SAAS;QACX,CAAC,CAAC;YACE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC;SACpD,CAAC;AACR,CAAC;AAED,SAAS,mBAAmB,CAC1B,IAAuB,EACvB,KAAwB;IAExB,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACpD,MAAM,IAAI,kCAAyB,CAAC,0DAA0D,CAAC,CAAC;IAClG,CAAC;IAED,2EAA2E;IAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAExF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,kCAAyB,CAAC,uDAAuD,CAAC,CAAC;IAC/F,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAE5C,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,kCAAyB,CAAC,0EAA0E,CAAC,CAAC;IAClH,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,cAAc,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAEpE,MAAM,UAAU,GAAmB,EAAE,CAAC;IAEtC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,UAAU,CAAC,IAAI,CAAC,IAAA,yBAAgB,EAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,UAAU,CAAC,IAAI,CAAC,IAAA,yBAAgB,EAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IACtE,UAAU,CAAC,IAAI,CAAC,IAAA,0BAAiB,EAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC;IAEzE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,wBAAwB,CAC/B,YAAoB,EACpB,QAAiC,EACjC,OAA2B;IAE3B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,kCAAyB,CAAC,GAAG,YAAY,gCAAgC,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,YAAY,0BAA0B,CAAC,CAAC;IACrF,MAAM,OAAO,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,YAAY,2BAA2B,CAAC,CAAC;IAEvF,IACE,CAAC,IAAA,wBAAiB,EAAC,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW;QAC7D,CAAC,IAAA,wBAAiB,EAAC,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,KAAK,WAAW,EAC/D,CAAC;QACD,MAAM,IAAI,kCAAyB,CAAC,GAAG,YAAY,kCAAkC,CAAC,CAAC;IACzF,CAAC;IAED,OAAO;QACL,kBAAkB,CAAC,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrD,kBAAkB,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACvD,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAkB,EAAE,SAAiB;IAC9D,IAAI,SAAS,KAAK,EAAE,EAAE,CAAC;QACrB,2EAA2E;QAC3E,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAgB,gCAAgC,CAC9C,QAAiC,EACjC,OAA2B,EAC3B,SAAoC;IAEpC,MAAM,YAAY,GAAG,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;IAC9E,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,wBAAwB,CAAC,YAAY,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAEhF,6CAA6C;IAC7C,+CAA+C;IAC/C,MAAM,QAAQ,GAAG,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IACzD,MAAM,UAAU,GAAG,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3D,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO;QAC3B,IAAA,0BAAiB,EAAC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAErD,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO;QAC7B,IAAA,0BAAiB,EAAC,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEvD,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAChE,IAAI,UAAU,CAAC,SAAS,KAAK,EAAE,EAAE,CAAC;YAChC,wFAAwF;YACxF,OAAO,IAAA,0BAAiB,EAAC,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAClF,CAAC;QAED,OAAO,IAAA,0BAAiB,EACtB,UAAU,CAAC,QAAQ,EACnB,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,UAAU,CAAC,SAAS,CACpE,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAChE,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;QACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAEnE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,KAAK,KAAK;gBAAE,OAAO,IAAA,8BAAqB,EAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAE1F,OAAO;gBACL,GAAG,EAAE;oBACH,IAAA,yBAAgB,EAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC;oBACjD,IAAA,yBAAgB,EAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;iBAC/C;aACF,CAAC;QACJ,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAA,yBAAgB,EAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,IAAA,yBAAgB,EAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU,IAAI,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACnE,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC;QACvC,MAAM,cAAc,GAAG,UAAU,CAAC,QAAQ,CAAC;QAE3C,IACE,cAAc,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM;YAC3C,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,EACzD,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,IAAI,kCAAyB,CAAC,GAAG,YAAY,8BAA8B,SAAS,eAAe,CAAC,CAAC;IAC7G,CAAC;IAED,MAAM,IAAI,kCAAyB,CAAC,GAAG,YAAY,0CAA0C,CAAC,CAAC;AACjG,CAAC"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,23 +1,59 @@
|
|
|
1
1
|
import { PlanKind } from "@cerbos/core";
|
|
2
2
|
import type { PlanResourcesResponse } from "@cerbos/core";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { UnsupportedQueryPlanError } from "./errors";
|
|
4
|
+
import type { PrismaFilter } from "./value";
|
|
5
|
+
export { PlanKind, UnsupportedQueryPlanError };
|
|
6
|
+
export type { PrismaFilter, PrismaValue } from "./value";
|
|
5
7
|
export type MapperConfig = {
|
|
6
8
|
field?: string;
|
|
7
9
|
/**
|
|
8
|
-
* Declares the
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* Declares the Prisma scalar kind so incompatible operands are rejected before query
|
|
11
|
+
* execution. Undeclared scalar kinds preserve the historical behavior. Date-time metadata
|
|
12
|
+
* is required for timestamp(field); raw DateTime column comparisons lose lexical spelling.
|
|
11
13
|
*/
|
|
12
|
-
valueType?: "dateTime";
|
|
14
|
+
valueType?: "dateTime" | "string" | "number" | "boolean";
|
|
13
15
|
/**
|
|
14
16
|
* Marks the mapped column as nullable in the database. Cerbos treats a missing attribute as
|
|
15
17
|
* an evaluation error (deny), which matches SQL three-valued logic for simple predicates —
|
|
16
18
|
* but relation subqueries (some/every/none) collapse UNKNOWN to false at the EXISTS boundary,
|
|
17
19
|
* so collection macros over elements with NULL fields need an explicit guard to stay
|
|
18
|
-
* deny-aligned.
|
|
20
|
+
* deny-aligned. An element column is treated as nullable unless this says `false`, because
|
|
21
|
+
* the unguarded filter is the one that over-grants; declare `nullable: false` on every required
|
|
22
|
+
* element column, since Prisma rejects a `null` comparison against one. Scalar hierarchy
|
|
23
|
+
* segments likewise preserve missing-value errors unless nullable: false declares that a
|
|
24
|
+
* segment cannot be NULL.
|
|
19
25
|
*/
|
|
20
26
|
nullable?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Declares that this column can be SQL NULL **and** how the caller represents that NULL in the
|
|
29
|
+
* attributes it sends to `check()`. Declaring it asserts both facts; leaving it undeclared means
|
|
30
|
+
* "treat this column as NOT NULL", which is the historical rendering.
|
|
31
|
+
*
|
|
32
|
+
* This is per attribute rather than per call because one policy suite can legitimately mix the
|
|
33
|
+
* two conventions — the same column can be mapped twice, sent as an explicit null under one
|
|
34
|
+
* attribute name and omitted under another. The call-level option cannot express that, which is
|
|
35
|
+
* what made cerbos/query-plan-adapters#308 unfixable with #302's option alone.
|
|
36
|
+
*
|
|
37
|
+
* - `"explicit"` — a NULL column is sent as an explicit `null` attribute, so CEL holds a null
|
|
38
|
+
* VALUE. `null != "x"` is then TRUE and `null == "x"` is FALSE, both definite, while Prisma's
|
|
39
|
+
* `{ not: "x" }` drops the row under both polarities. The equality family (`equals`, `not`,
|
|
40
|
+
* `in`) is therefore rendered so it can never depend on SQL's UNKNOWN.
|
|
41
|
+
* - `"omitted"` — a NULL column sends no attribute, so CEL raises a missing-attribute error and
|
|
42
|
+
* `check()` denies. Dropping the row is already right, so the rendering is unchanged; what the
|
|
43
|
+
* declaration adds is the same null-operand rejection the call-level `"omitted"` performs,
|
|
44
|
+
* scoped to this attribute.
|
|
45
|
+
*
|
|
46
|
+
* Only the equality family is affected. `lt`/`lte`/`gt`/`gte` and the string operators raise a
|
|
47
|
+
* no-overload error on a null receiver in CEL, which denies under both polarities exactly as a
|
|
48
|
+
* dropped row does, so they are left alone.
|
|
49
|
+
*
|
|
50
|
+
* Distinct from `nullable` above, which declares whether a *relation element* column can be NULL so
|
|
51
|
+
* collection macros gain their three-valued guards. The two are independent: `nullable` is about
|
|
52
|
+
* what a subquery does with an UNKNOWN element, this is about what the caller sent to the PDP.
|
|
53
|
+
*
|
|
54
|
+
* See https://github.com/cerbos/query-plan-adapters/issues/308.
|
|
55
|
+
*/
|
|
56
|
+
nullAttributeRepresentation?: NullAttributeRepresentation;
|
|
21
57
|
relation?: {
|
|
22
58
|
name: string;
|
|
23
59
|
type: "one" | "many";
|
|
@@ -29,9 +65,51 @@ export type MapperConfig = {
|
|
|
29
65
|
model?: string;
|
|
30
66
|
field?: string;
|
|
31
67
|
fields?: Record<string, MapperConfig>;
|
|
68
|
+
/**
|
|
69
|
+
* The predicate the application itself applies when it reads this relation — a soft-delete
|
|
70
|
+
* flag, a tenant column, a subtype discriminator, whatever narrows the rows that became the
|
|
71
|
+
* resource attributes.
|
|
72
|
+
*
|
|
73
|
+
* Prisma has no schema-level filtered relation. A `where` injected by a client extension or
|
|
74
|
+
* middleware rewrites the *top-level* query, never the nested `some`/`every`/`none` this
|
|
75
|
+
* adapter generates, so a narrowing the application applies to its own reads does not reach
|
|
76
|
+
* the subquery — and the subquery then matches records the application never serialised, a
|
|
77
|
+
* filter that returns rows the PDP denies. Declaring the predicate here restores the
|
|
78
|
+
* equality; the adapter cannot detect the omission, which is why the field is optional and
|
|
79
|
+
* silence is not a warning. See "Mapping hazards" in the README.
|
|
80
|
+
*
|
|
81
|
+
* It is a Prisma where-input over the RELATED model, ANDed into the nested filter, and it
|
|
82
|
+
* constrains every operator reached through this relation under both polarities. `every` is
|
|
83
|
+
* rewritten to the equivalent `none` so the restriction narrows the records examined rather
|
|
84
|
+
* than the records required to match.
|
|
85
|
+
*
|
|
86
|
+
* ```ts
|
|
87
|
+
* relation: { name: "tags", type: "many", subqueryFilter: { deletedAt: null } }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
subqueryFilter?: PrismaFilter;
|
|
32
91
|
};
|
|
33
92
|
};
|
|
34
93
|
export type Mapper = Record<string, MapperConfig> | ((key: string) => MapperConfig);
|
|
94
|
+
/**
|
|
95
|
+
* How the caller represents a NULL column when building the attributes it sends to `check()`.
|
|
96
|
+
*
|
|
97
|
+
* The planner emits the same `eq(attr, null)` node either way, so the plan cannot reveal which
|
|
98
|
+
* convention is in use and the adapter has to be told.
|
|
99
|
+
*
|
|
100
|
+
* - `"explicit"` — a NULL column is sent as an explicit `null` attribute. CEL compares
|
|
101
|
+
* `null == null`, so `IS NULL` selects exactly the rows `check()` allows.
|
|
102
|
+
* - `"omitted"` (default) — a NULL column sends no attribute at all. CEL then raises a
|
|
103
|
+
* missing-attribute error, which Cerbos treats as a deny, so a filter that *selects* NULL rows returns rows the
|
|
104
|
+
* PDP denies. A null comparison operand is never translated into a NULL-selecting filter.
|
|
105
|
+
*
|
|
106
|
+
* The default is the convention whose wrong guess fails closed: a caller that actually sends
|
|
107
|
+
* explicit nulls loses the NULL rows, never gains rows the PDP denies
|
|
108
|
+
* (docs/adr/0011-denial-fails-closed-in-the-result.md).
|
|
109
|
+
*
|
|
110
|
+
* See https://github.com/cerbos/query-plan-adapters/issues/302.
|
|
111
|
+
*/
|
|
112
|
+
export type NullAttributeRepresentation = "explicit" | "omitted";
|
|
35
113
|
export interface QueryPlanToPrismaArgs {
|
|
36
114
|
queryPlan: PlanResourcesResponse;
|
|
37
115
|
mapper?: Mapper;
|
|
@@ -41,6 +119,11 @@ export interface QueryPlanToPrismaArgs {
|
|
|
41
119
|
* references and need the model name as their container.
|
|
42
120
|
*/
|
|
43
121
|
model?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Which NULL-column representation the caller uses when building `check()` attributes.
|
|
124
|
+
* Defaults to `"omitted"`, which never selects NULL rows for an undeclared attribute.
|
|
125
|
+
*/
|
|
126
|
+
nullAttributeRepresentation?: NullAttributeRepresentation;
|
|
44
127
|
}
|
|
45
128
|
export type QueryPlanToPrismaResult = {
|
|
46
129
|
kind: PlanKind.ALWAYS_ALLOWED | PlanKind.ALWAYS_DENIED;
|
|
@@ -51,5 +134,5 @@ export type QueryPlanToPrismaResult = {
|
|
|
51
134
|
/**
|
|
52
135
|
* Converts a Cerbos query plan to a Prisma filter.
|
|
53
136
|
*/
|
|
54
|
-
export declare function queryPlanToPrisma({ queryPlan, mapper, model, }: QueryPlanToPrismaArgs): QueryPlanToPrismaResult;
|
|
137
|
+
export declare function queryPlanToPrisma({ queryPlan, mapper, model, nullAttributeRepresentation, }: QueryPlanToPrismaArgs): QueryPlanToPrismaResult;
|
|
55
138
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAW1D,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,yBAAyB,EAAE,CAAC;AAE/C,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEzD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,SAAS,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;IAC1D,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,KAAK,GAAG,MAAM,CAAC;QACrB;;;;WAIG;QACH,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACtC;;;;;;;;;;;;;;;;;;;;;WAqBG;QACH,cAAc,CAAC,EAAE,YAAY,CAAC;KAC/B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,MAAM,GACd,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAC5B,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,YAAY,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,2BAA2B,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,qBAAqB,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,2BAA2B,CAAC,EAAE,2BAA2B,CAAC;CAC3D;AAED,MAAM,MAAM,uBAAuB,GAC/B;IACE,IAAI,EAAE,QAAQ,CAAC,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC;CACxD,GACD;IACE,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC;IAC3B,OAAO,EAAE,YAAY,CAAC;CACvB,CAAC;AAEN;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,MAAW,EACX,KAAK,EACL,2BAAuC,GACxC,EAAE,qBAAqB,GAAG,uBAAuB,CAoDjD"}
|