@sequenceholdings/orm 2.2.0 → 2.4.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/dist/cli.cjs +132 -61
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +132 -61
- package/dist/cli.js.map +1 -1
- package/dist/compiler.cjs +139 -33
- package/dist/compiler.cjs.map +1 -1
- package/dist/compiler.d.cts +6 -4
- package/dist/compiler.d.ts +6 -4
- package/dist/compiler.js +139 -33
- package/dist/compiler.js.map +1 -1
- package/dist/index.cjs +9 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/ir.cjs +9 -1
- package/dist/ir.cjs.map +1 -1
- package/dist/ir.d.cts +89 -3
- package/dist/ir.d.ts +89 -3
- package/dist/ir.js +8 -2
- package/dist/ir.js.map +1 -1
- package/dist/predicate-v2.cjs +127 -14
- package/dist/predicate-v2.cjs.map +1 -1
- package/dist/predicate-v2.d.cts +49 -4
- package/dist/predicate-v2.d.ts +49 -4
- package/dist/predicate-v2.js +127 -14
- package/dist/predicate-v2.js.map +1 -1
- package/dist/sdl.cjs +2 -1
- package/dist/sdl.cjs.map +1 -1
- package/dist/sdl.js +2 -1
- package/dist/sdl.js.map +1 -1
- package/package.json +1 -1
package/dist/compiler.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { CanonicalEnum, CanonicalDefinition } from './canonical.cjs';
|
|
|
2
2
|
import { ClaimKey, PredIr, RootIr, InputRefKind, TableMetaIr, CompiledOperation, CompiledArtifact, VariableIr, OrderIr, SelectionIr } from './ir.cjs';
|
|
3
3
|
import { DocumentNode, OperationDefinitionNode, FragmentDefinitionNode, GraphQLSchema, ValueNode, SelectionSetNode } from 'graphql';
|
|
4
4
|
export { DynamicInputIssue, DynamicInputResult, NormalizedBoolExp, NormalizedOnConflict, NormalizedOrderBy, NormalizedRow, ORDER_BY_DIRECTIONS, ScalarKind, allowedBoolExpOperators, allowedOps, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput } from './dynamic-input.cjs';
|
|
5
|
-
export { CompilePolicyInput, CompilePredicateInput, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, ParsedPolicy, PolicyColumnInfo, PolicyCompareOp, PolicyCompileError, PolicyCompileErrorCode, PolicyLinkInfo, PolicyNode, PolicyOperand, PolicyParseError, PolicyResolver, PolicyTableInfo, assertClaimsOnlyWhen, compilePolicy, compilePredicateV2, parsePolicy, walkPolicy } from './predicate-v2.cjs';
|
|
5
|
+
export { CompilePolicyInput, CompilePredicateInput, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, ParsedPolicy, PolicyAccess, PolicyColumnInfo, PolicyCompareOp, PolicyCompileError, PolicyCompileErrorCode, PolicyLinkInfo, PolicyNode, PolicyOperand, PolicyParseError, PolicyResolver, PolicyTableInfo, assertClaimsOnlyWhen, compilePolicy, compilePredicateV2, parsePolicy, walkPolicy } from './predicate-v2.cjs';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
export { P as PLATFORM_USER_TYPENAME, c as camelCase, g as enumTypeName, p as pascalCase } from './naming-CU9ThP_E.cjs';
|
|
8
8
|
export { S as SqlOperationDefinition, d as defineOperation, s as sqlOperationDefinitionSchema } from './definition-DjfC7Lll.cjs';
|
|
@@ -50,9 +50,11 @@ declare class NamespaceCompileError extends Error {
|
|
|
50
50
|
* - document-authored relationship predicates (exists/aggPredicate) get the
|
|
51
51
|
* TARGET table's read policy injected too, so filtering through a link
|
|
52
52
|
* can't become an existence oracle on rows the caller can't read;
|
|
53
|
-
* - write policy AND-ed into update/delete row filters,
|
|
54
|
-
*
|
|
55
|
-
* exists
|
|
53
|
+
* - write policy AND-ed into update/delete row filters, set as the insert
|
|
54
|
+
* check for inserts, and re-checked against the NEW rows of every update.
|
|
55
|
+
* Link-traversing (exists/visible) write policies are evaluated by the data
|
|
56
|
+
* plane against the proposed rows in the same statement, so "only on a
|
|
57
|
+
* parent the caller can see" holds for inserts and FK-changing updates;
|
|
56
58
|
* - `col = claim(k)` AND-conjuncts of the write policy become pinned columns
|
|
57
59
|
* merged into every inserted row (and excluded from insertable/settable).
|
|
58
60
|
*/
|
package/dist/compiler.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { CanonicalEnum, CanonicalDefinition } from './canonical.js';
|
|
|
2
2
|
import { ClaimKey, PredIr, RootIr, InputRefKind, TableMetaIr, CompiledOperation, CompiledArtifact, VariableIr, OrderIr, SelectionIr } from './ir.js';
|
|
3
3
|
import { DocumentNode, OperationDefinitionNode, FragmentDefinitionNode, GraphQLSchema, ValueNode, SelectionSetNode } from 'graphql';
|
|
4
4
|
export { DynamicInputIssue, DynamicInputResult, NormalizedBoolExp, NormalizedOnConflict, NormalizedOrderBy, NormalizedRow, ORDER_BY_DIRECTIONS, ScalarKind, allowedBoolExpOperators, allowedOps, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput } from './dynamic-input.js';
|
|
5
|
-
export { CompilePolicyInput, CompilePredicateInput, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, ParsedPolicy, PolicyColumnInfo, PolicyCompareOp, PolicyCompileError, PolicyCompileErrorCode, PolicyLinkInfo, PolicyNode, PolicyOperand, PolicyParseError, PolicyResolver, PolicyTableInfo, assertClaimsOnlyWhen, compilePolicy, compilePredicateV2, parsePolicy, walkPolicy } from './predicate-v2.js';
|
|
5
|
+
export { CompilePolicyInput, CompilePredicateInput, POLICY_COMPARE_OPS, POLICY_MAX_LINK_DEPTH, ParsedPolicy, PolicyAccess, PolicyColumnInfo, PolicyCompareOp, PolicyCompileError, PolicyCompileErrorCode, PolicyLinkInfo, PolicyNode, PolicyOperand, PolicyParseError, PolicyResolver, PolicyTableInfo, assertClaimsOnlyWhen, compilePolicy, compilePredicateV2, parsePolicy, walkPolicy } from './predicate-v2.js';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
export { P as PLATFORM_USER_TYPENAME, c as camelCase, g as enumTypeName, p as pascalCase } from './naming-CPfx7EfF.js';
|
|
8
8
|
export { S as SqlOperationDefinition, d as defineOperation, s as sqlOperationDefinitionSchema } from './definition-DjfC7Lll.js';
|
|
@@ -50,9 +50,11 @@ declare class NamespaceCompileError extends Error {
|
|
|
50
50
|
* - document-authored relationship predicates (exists/aggPredicate) get the
|
|
51
51
|
* TARGET table's read policy injected too, so filtering through a link
|
|
52
52
|
* can't become an existence oracle on rows the caller can't read;
|
|
53
|
-
* - write policy AND-ed into update/delete row filters,
|
|
54
|
-
*
|
|
55
|
-
* exists
|
|
53
|
+
* - write policy AND-ed into update/delete row filters, set as the insert
|
|
54
|
+
* check for inserts, and re-checked against the NEW rows of every update.
|
|
55
|
+
* Link-traversing (exists/visible) write policies are evaluated by the data
|
|
56
|
+
* plane against the proposed rows in the same statement, so "only on a
|
|
57
|
+
* parent the caller can see" holds for inserts and FK-changing updates;
|
|
56
58
|
* - `col = claim(k)` AND-conjuncts of the write policy become pinned columns
|
|
57
59
|
* merged into every inserted row (and excluded from insertable/settable).
|
|
58
60
|
*/
|
package/dist/compiler.js
CHANGED
|
@@ -1121,14 +1121,20 @@ function requiredArtifactIrVersion(operations) {
|
|
|
1121
1121
|
var CLAIMS_CONTRACT = {
|
|
1122
1122
|
sub: "string",
|
|
1123
1123
|
org: "string?",
|
|
1124
|
+
ext_subject: "string?",
|
|
1125
|
+
ext_email: "string?",
|
|
1124
1126
|
roles: "string[]",
|
|
1125
1127
|
capabilities: "string[]"
|
|
1126
1128
|
};
|
|
1129
|
+
var EXTERNAL_POLICY_CLAIM_KEYS = ["ext_subject", "ext_email"];
|
|
1130
|
+
function isExternalPolicyClaimKey(key) {
|
|
1131
|
+
return EXTERNAL_POLICY_CLAIM_KEYS.includes(key);
|
|
1132
|
+
}
|
|
1127
1133
|
var scalarLiteral = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
|
1128
1134
|
var valueIrSchema = z.discriminatedUnion("kind", [
|
|
1129
1135
|
z.object({ kind: z.literal("literal"), value: z.union([scalarLiteral, z.array(scalarLiteral)]) }),
|
|
1130
1136
|
z.object({ kind: z.literal("variable"), name: z.string() }),
|
|
1131
|
-
z.object({ kind: z.literal("claim"), key: z.enum(["sub", "org"]) })
|
|
1137
|
+
z.object({ kind: z.literal("claim"), key: z.enum(["sub", "org", ...EXTERNAL_POLICY_CLAIM_KEYS]) })
|
|
1132
1138
|
]);
|
|
1133
1139
|
var CMP_OPS = [
|
|
1134
1140
|
"eq",
|
|
@@ -1848,6 +1854,7 @@ var Parser2 = class {
|
|
|
1848
1854
|
return node;
|
|
1849
1855
|
}
|
|
1850
1856
|
if (this.peekKeyword("exists")) return this.parseExists();
|
|
1857
|
+
if (this.peekKeyword("visible") && this.tokens[this.index + 1]?.kind === "lparen") return this.parseVisible();
|
|
1851
1858
|
return this.parseComparison();
|
|
1852
1859
|
}
|
|
1853
1860
|
parseBooleanCall(fn) {
|
|
@@ -1867,6 +1874,13 @@ var Parser2 = class {
|
|
|
1867
1874
|
this.expect("rparen", "')' closing exists(...)");
|
|
1868
1875
|
return { kind: "exists", path, where };
|
|
1869
1876
|
}
|
|
1877
|
+
parseVisible() {
|
|
1878
|
+
this.advance();
|
|
1879
|
+
this.expect("lparen", "'(' after visible");
|
|
1880
|
+
const path = this.parsePath("a link path in visible(...)");
|
|
1881
|
+
this.expect("rparen", "')' closing visible(...)");
|
|
1882
|
+
return { kind: "visible", path };
|
|
1883
|
+
}
|
|
1870
1884
|
parseComparison() {
|
|
1871
1885
|
const left = this.parseOperand();
|
|
1872
1886
|
const operator = this.expect("operator", "a comparison operator");
|
|
@@ -1982,6 +1996,24 @@ function parsePolicy(source) {
|
|
|
1982
1996
|
|
|
1983
1997
|
// src/predicate-v2/compile.ts
|
|
1984
1998
|
var POLICY_MAX_LINK_DEPTH = 3;
|
|
1999
|
+
function scopeToNamespace(pred, namespace) {
|
|
2000
|
+
switch (pred.kind) {
|
|
2001
|
+
case "capability":
|
|
2002
|
+
case "role":
|
|
2003
|
+
return pred.namespace ? pred : { ...pred, namespace };
|
|
2004
|
+
case "and":
|
|
2005
|
+
case "or":
|
|
2006
|
+
return { ...pred, operands: pred.operands.map((operand) => scopeToNamespace(operand, namespace)) };
|
|
2007
|
+
case "not":
|
|
2008
|
+
return { ...pred, operand: scopeToNamespace(pred.operand, namespace) };
|
|
2009
|
+
case "exists":
|
|
2010
|
+
return { ...pred, where: scopeToNamespace(pred.where, namespace) };
|
|
2011
|
+
case "aggPredicate":
|
|
2012
|
+
return pred.where ? { ...pred, where: scopeToNamespace(pred.where, namespace) } : pred;
|
|
2013
|
+
default:
|
|
2014
|
+
return pred;
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
1985
2017
|
var CMP_BY_OP = {
|
|
1986
2018
|
"=": "eq",
|
|
1987
2019
|
"!=": "neq",
|
|
@@ -2015,7 +2047,7 @@ function resolveLink(info, ref) {
|
|
|
2015
2047
|
function columnCandidates(info) {
|
|
2016
2048
|
return [...info.columns.map((c) => c.name), ...info.links.map((l) => l.name)];
|
|
2017
2049
|
}
|
|
2018
|
-
var PolicyCompiler = class {
|
|
2050
|
+
var PolicyCompiler = class _PolicyCompiler {
|
|
2019
2051
|
constructor(ctx) {
|
|
2020
2052
|
this.ctx = ctx;
|
|
2021
2053
|
}
|
|
@@ -2027,13 +2059,16 @@ var PolicyCompiler = class {
|
|
|
2027
2059
|
case "or":
|
|
2028
2060
|
return { kind: node.kind, operands: node.operands.map((operand) => this.compile(operand, table, depth)) };
|
|
2029
2061
|
case "not":
|
|
2030
|
-
|
|
2062
|
+
assertNoNegatedExternalClaim(node.operand);
|
|
2063
|
+
return { kind: "not", operand: new _PolicyCompiler({ ...this.ctx, negated: true }).compile(node.operand, table, depth) };
|
|
2031
2064
|
case "capability":
|
|
2032
2065
|
return { kind: "capability", key: node.key };
|
|
2033
2066
|
case "role":
|
|
2034
2067
|
return { kind: "role", key: node.key };
|
|
2035
2068
|
case "exists":
|
|
2036
2069
|
return this.compileExists(node.path, node.where, table, depth);
|
|
2070
|
+
case "visible":
|
|
2071
|
+
return this.compileVisible(node.path, table, depth);
|
|
2037
2072
|
case "compare":
|
|
2038
2073
|
return this.compileCompare(node, table, depth);
|
|
2039
2074
|
}
|
|
@@ -2047,6 +2082,36 @@ var PolicyCompiler = class {
|
|
|
2047
2082
|
}
|
|
2048
2083
|
return pred;
|
|
2049
2084
|
}
|
|
2085
|
+
/** `visible(path)` → `exists(path, <final target's read policy>)`. */
|
|
2086
|
+
compileVisible(path, table, depth) {
|
|
2087
|
+
const { links, finalTable } = this.resolveLinkPath(path, table, depth, { toOneOnly: false });
|
|
2088
|
+
const readPolicy = this.ctx.resolver.readPolicy;
|
|
2089
|
+
if (!readPolicy) {
|
|
2090
|
+
throw new PolicyCompileError(
|
|
2091
|
+
`visible(${path.join(".")}) needs the target's read policy, which this compile context does not provide`,
|
|
2092
|
+
"visible-unresolvable"
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
2095
|
+
if (this.ctx.visiting.includes(finalTable)) {
|
|
2096
|
+
throw new PolicyCompileError(
|
|
2097
|
+
`visible(${path.join(".")}) on '${table}' reaches '${finalTable}' whose read policy is already being expanded (${[...this.ctx.visiting, finalTable].join(" \u2192 ")})`,
|
|
2098
|
+
"visible-cycle"
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
const expression = readPolicy(finalTable);
|
|
2102
|
+
let pred = expression === void 0 ? { kind: "const", value: true } : compilePolicyAt({
|
|
2103
|
+
expression,
|
|
2104
|
+
table: finalTable,
|
|
2105
|
+
ctx: { ...this.ctx, visiting: [...this.ctx.visiting, finalTable] },
|
|
2106
|
+
depth: depth + links.length
|
|
2107
|
+
});
|
|
2108
|
+
const owner = this.ctx.resolver.policyNamespace?.(finalTable);
|
|
2109
|
+
if (owner) pred = scopeToNamespace(pred, owner);
|
|
2110
|
+
for (let i = links.length - 1; i >= 0; i -= 1) {
|
|
2111
|
+
pred = { kind: "exists", link: links[i].name, where: pred };
|
|
2112
|
+
}
|
|
2113
|
+
return pred;
|
|
2114
|
+
}
|
|
2050
2115
|
resolveLinkPath(path, table, depth, { toOneOnly }) {
|
|
2051
2116
|
const links = [];
|
|
2052
2117
|
let current = table;
|
|
@@ -2106,6 +2171,10 @@ var PolicyCompiler = class {
|
|
|
2106
2171
|
columnCandidates(info)
|
|
2107
2172
|
);
|
|
2108
2173
|
}
|
|
2174
|
+
if (valueSide.kind === "claim" && isExternalPolicyClaimKey(valueSide.key)) {
|
|
2175
|
+
if (this.ctx.negated) throw negatedExternalClaim(valueSide.key);
|
|
2176
|
+
assertExternalClaimComparison({ op, key: valueSide.key, column: info.columns.find((c) => c.name === column) });
|
|
2177
|
+
}
|
|
2109
2178
|
let cmp = this.buildCmp(op, column, valueSide);
|
|
2110
2179
|
for (let i = links.length - 1; i >= 0; i -= 1) {
|
|
2111
2180
|
cmp = { kind: "exists", link: links[i].name, where: cmp };
|
|
@@ -2126,10 +2195,45 @@ var PolicyCompiler = class {
|
|
|
2126
2195
|
return { kind: "cmp", op: CMP_BY_OP[op], column, value };
|
|
2127
2196
|
}
|
|
2128
2197
|
};
|
|
2198
|
+
function assertExternalClaimComparison({ op, key, column }) {
|
|
2199
|
+
if (op !== "=") {
|
|
2200
|
+
throw new PolicyCompileError(
|
|
2201
|
+
`claim('${key}') supports = comparisons only, got '${op}'`,
|
|
2202
|
+
"unsupported-comparison"
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
if (column?.type !== "text") {
|
|
2206
|
+
const actual = column?.type === void 0 ? "of unknown type" : typeof column.type === "string" ? column.type : "an enum";
|
|
2207
|
+
throw new PolicyCompileError(
|
|
2208
|
+
`claim('${key}') is text and compares to a text column only \u2014 '${column?.name ?? "?"}' is ${actual}`,
|
|
2209
|
+
"claim-type-mismatch"
|
|
2210
|
+
);
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
function negatedExternalClaim(key) {
|
|
2214
|
+
return new PolicyCompileError(
|
|
2215
|
+
`claim('${key}') cannot appear under not(): a negated borrower comparison admits other borrowers' rows`,
|
|
2216
|
+
"unsupported-comparison"
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2219
|
+
function assertNoNegatedExternalClaim(operand) {
|
|
2220
|
+
walkPolicy(operand, (node) => {
|
|
2221
|
+
if (node.kind !== "compare") return;
|
|
2222
|
+
const claim = [node.left, node.right].find((side) => side.kind === "claim" && isExternalPolicyClaimKey(side.key));
|
|
2223
|
+
if (claim?.kind === "claim") throw negatedExternalClaim(claim.key);
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2129
2226
|
function compilePredicateV2({ expression, table, resolver, maxLinkDepth }) {
|
|
2227
|
+
return compilePredicateAt({
|
|
2228
|
+
expression,
|
|
2229
|
+
table,
|
|
2230
|
+
depth: 0,
|
|
2231
|
+
ctx: { resolver, maxLinkDepth: maxLinkDepth ?? POLICY_MAX_LINK_DEPTH, visiting: [table] }
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
function compilePredicateAt({ expression, table, ctx, depth }) {
|
|
2130
2235
|
const parsed = typeof expression === "string" ? parsePolicy(expression) : expression;
|
|
2131
|
-
|
|
2132
|
-
return compiler.compile(parsed.ast, table, 0);
|
|
2236
|
+
return new PolicyCompiler(ctx).compile(parsed.ast, table, depth);
|
|
2133
2237
|
}
|
|
2134
2238
|
function assertClaimsOnlyWhen(parsed) {
|
|
2135
2239
|
walkPolicy(parsed.ast, (node) => {
|
|
@@ -2146,25 +2250,34 @@ function assertClaimsOnlyWhen(parsed) {
|
|
|
2146
2250
|
"when-not-claims-only"
|
|
2147
2251
|
);
|
|
2148
2252
|
}
|
|
2149
|
-
if (node.kind === "exists") {
|
|
2253
|
+
if (node.kind === "exists" || node.kind === "visible") {
|
|
2150
2254
|
throw new PolicyCompileError(
|
|
2151
|
-
|
|
2255
|
+
`variant 'when' guards are claims-only \u2014 ${node.kind}() is not allowed`,
|
|
2152
2256
|
"when-not-claims-only"
|
|
2153
2257
|
);
|
|
2154
2258
|
}
|
|
2155
2259
|
});
|
|
2156
2260
|
}
|
|
2157
|
-
function
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2261
|
+
function initialVisiting({ table, access }) {
|
|
2262
|
+
return (access ?? "read") === "read" ? [table] : [];
|
|
2263
|
+
}
|
|
2264
|
+
function compilePolicy({ expression, table, resolver, maxLinkDepth, access }) {
|
|
2265
|
+
return compilePolicyAt({
|
|
2266
|
+
expression,
|
|
2267
|
+
table,
|
|
2268
|
+
depth: 0,
|
|
2269
|
+
ctx: { resolver, maxLinkDepth: maxLinkDepth ?? POLICY_MAX_LINK_DEPTH, visiting: initialVisiting({ table, access }) }
|
|
2270
|
+
});
|
|
2271
|
+
}
|
|
2272
|
+
function compilePolicyAt({ expression, table, ctx, depth }) {
|
|
2273
|
+
if (typeof expression === "string") return compilePredicateAt({ expression, table, ctx, depth });
|
|
2274
|
+
const defaultPred = compilePredicateAt({ expression: expression.default, table, ctx, depth });
|
|
2162
2275
|
if (expression.variants.length === 0) return defaultPred;
|
|
2163
2276
|
const branches = expression.variants.map((variant) => {
|
|
2164
2277
|
const parsedWhen = parsePolicy(variant.when);
|
|
2165
2278
|
assertClaimsOnlyWhen(parsedWhen);
|
|
2166
|
-
const when =
|
|
2167
|
-
const grant = variant.allow === true ? { kind: "const", value: true } :
|
|
2279
|
+
const when = compilePredicateAt({ expression: parsedWhen, table, ctx, depth });
|
|
2280
|
+
const grant = variant.allow === true ? { kind: "const", value: true } : compilePredicateAt({ expression: variant.policy, table, ctx, depth });
|
|
2168
2281
|
return { kind: "and", operands: [when, grant] };
|
|
2169
2282
|
});
|
|
2170
2283
|
return { kind: "or", operands: [defaultPred, ...branches] };
|
|
@@ -2380,12 +2493,6 @@ var PolicyInjector = class {
|
|
|
2380
2493
|
if (root.op === "resolvedWrite") return this.injectResolvedWrite(root, returning);
|
|
2381
2494
|
if (root.op === "insert" || root.op === "insertOne") {
|
|
2382
2495
|
const insertPolicy = this.insert(table);
|
|
2383
|
-
if (predContainsExists(insertPolicy)) {
|
|
2384
|
-
throw new DocumentCompileError(
|
|
2385
|
-
`table '${table}' cannot be inserted into: v2.0 insert checks are claims + inserted-values only, but its insert policy traverses a link (exists)`,
|
|
2386
|
-
"insert-check-unrepresentable"
|
|
2387
|
-
);
|
|
2388
|
-
}
|
|
2389
2496
|
const pins = (this.ctx.pins.get(table) ?? []).map(
|
|
2390
2497
|
(pin) => ({ column: pin.column, value: { kind: "claim", key: pin.claim } })
|
|
2391
2498
|
);
|
|
@@ -2400,22 +2507,14 @@ var PolicyInjector = class {
|
|
|
2400
2507
|
const updatePolicy = this.update(table);
|
|
2401
2508
|
const where = andPred(updatePolicy, root.where ? this.injectDocPred(root.where, table) : void 0);
|
|
2402
2509
|
if (root.op === "update" || root.op === "updateByPk") {
|
|
2403
|
-
|
|
2404
|
-
return { ...root, where, ...check, returning };
|
|
2510
|
+
return { ...root, where, insertCheck: updatePolicy, returning };
|
|
2405
2511
|
}
|
|
2406
2512
|
if (root.op === "cowOverride") {
|
|
2407
2513
|
const insertPolicy = this.insert(table);
|
|
2408
|
-
if (predContainsExists(insertPolicy)) {
|
|
2409
|
-
throw new DocumentCompileError(
|
|
2410
|
-
`table '${table}' cannot be copy-on-write overridden: v2.0 insert checks are claims + inserted-values only, but its insert policy traverses a link (exists)`,
|
|
2411
|
-
"insert-check-unrepresentable"
|
|
2412
|
-
);
|
|
2413
|
-
}
|
|
2414
2514
|
const pins = (this.ctx.pins.get(table) ?? []).map(
|
|
2415
2515
|
(pin) => ({ column: pin.column, value: { kind: "claim", key: pin.claim } })
|
|
2416
2516
|
);
|
|
2417
|
-
|
|
2418
|
-
return { ...root, pinnedColumns: pins, cowCopyCheck: insertPolicy, where, ...check, returning };
|
|
2517
|
+
return { ...root, pinnedColumns: pins, cowCopyCheck: insertPolicy, where, insertCheck: updatePolicy, returning };
|
|
2419
2518
|
}
|
|
2420
2519
|
return { ...root, where, returning };
|
|
2421
2520
|
}
|
|
@@ -2637,7 +2736,7 @@ function scopePolicy(pred, namespace) {
|
|
|
2637
2736
|
switch (pred.kind) {
|
|
2638
2737
|
case "capability":
|
|
2639
2738
|
case "role":
|
|
2640
|
-
return { ...pred, namespace };
|
|
2739
|
+
return pred.namespace ? pred : { ...pred, namespace };
|
|
2641
2740
|
case "and":
|
|
2642
2741
|
case "or":
|
|
2643
2742
|
return { ...pred, operands: pred.operands.map((p) => scopePolicy(p, namespace)) };
|
|
@@ -2846,7 +2945,14 @@ function buildCompileContext(rawCanonical) {
|
|
|
2846
2945
|
const updatePolicies = /* @__PURE__ */ new Map();
|
|
2847
2946
|
const pins = /* @__PURE__ */ new Map();
|
|
2848
2947
|
const splitWritePolicyTables = /* @__PURE__ */ new Set();
|
|
2849
|
-
const
|
|
2948
|
+
const readPolicyExpressions = new Map(relations.map((relation) => [relation.table, relation.policies.read]));
|
|
2949
|
+
const resolver = {
|
|
2950
|
+
tables,
|
|
2951
|
+
readPolicy: (table) => readPolicyExpressions.get(table),
|
|
2952
|
+
// In a composed namespace, an imported table's read policy (inlined by
|
|
2953
|
+
// visible()) is checked against the namespace that owns it.
|
|
2954
|
+
...normalized.imports?.length ? { policyNamespace: (table) => owners.get(table)?.namespace } : {}
|
|
2955
|
+
};
|
|
2850
2956
|
for (const table of relations) {
|
|
2851
2957
|
const isView = viewNames.has(table.table);
|
|
2852
2958
|
const compilePolicyFor = (access, store) => {
|
|
@@ -2855,7 +2961,7 @@ function buildCompileContext(rawCanonical) {
|
|
|
2855
2961
|
return;
|
|
2856
2962
|
}
|
|
2857
2963
|
try {
|
|
2858
|
-
const pred = compilePolicy({ expression, table: table.table, resolver });
|
|
2964
|
+
const pred = compilePolicy({ expression, table: table.table, resolver, access });
|
|
2859
2965
|
store.set(table.table, normalized.imports?.length ? scopePolicy(pred, owners.get(table.table).namespace) : pred);
|
|
2860
2966
|
} catch (error) {
|
|
2861
2967
|
if (error instanceof PolicyCompileError || error instanceof PolicyParseError) {
|