MCPcopy Create free account
hub / github.com/zenstackhq/zenstack / check

Function check

packages/plugins/policy/src/functions.ts:10–107  ·  view source on GitHub ↗
(
    eb: ExpressionBuilder<any, any>,
    args: Expression<any>[],
    { client, model, modelAlias, operation }: ZModelFunctionContext<any>,
)

Source from the content-addressed store, hash-verified

8 * Relation checker implementation.
9 */
10export const check: ZModelFunction<any> = (
11 eb: ExpressionBuilder<any, any>,
12 args: Expression<any>[],
13 { client, model, modelAlias, operation }: ZModelFunctionContext<any>,
14) => {
15 invariant(args.length === 1 || args.length === 2, '"check" function requires 1 or 2 arguments');
16
17 const arg1Node = args[0]!.toOperationNode();
18
19 const arg2Node = args.length === 2 ? args[1]!.toOperationNode() : undefined;
20 if (arg2Node) {
21 invariant(
22 ValueNode.is(arg2Node) && typeof arg2Node.value === 'string',
23 '"operation" parameter must be a string literal when provided',
24 );
25 invariant(
26 CRUD.includes(arg2Node.value as CRUD),
27 '"operation" parameter must be one of "create", "read", "update", "delete"',
28 );
29 }
30
31 // first argument must be a field reference
32 const fieldName = QueryUtils.extractFieldName(arg1Node);
33 invariant(fieldName, 'Failed to extract field name from the first argument of "check" function');
34 const fieldDef = QueryUtils.requireField(client.$schema, model, fieldName);
35 invariant(fieldDef.relation, `Field "${fieldName}" is not a relation field in model "${model}"`);
36 invariant(!fieldDef.array, `Field "${fieldName}" is a to-many relation, which is not supported by "check"`);
37 const relationModel = fieldDef.type;
38
39 // build the join condition between the current model and the related model
40 const joinConditions: Expression<any>[] = [];
41 const fkInfo = QueryUtils.getRelationForeignKeyFieldPairs(client.$schema, model, fieldName);
42 const idFields = QueryUtils.requireIdFields(client.$schema, model);
43
44 // helper to build a base model select for delegate models
45 const buildBaseSelect = (baseModel: string, field: string): Expression<any> => {
46 return eb
47 .selectFrom(baseModel)
48 .select(field)
49 .where(
50 eb.and(
51 idFields.map((idField) =>
52 eb(eb.ref(`${fieldDef.originModel}.${idField}`), '=', eb.ref(`${modelAlias}.${idField}`)),
53 ),
54 ),
55 );
56 };
57
58 if (fkInfo.ownedByModel) {
59 // model owns the relation
60 joinConditions.push(
61 ...fkInfo.keyPairs.map(({ fk, pk }) => {
62 let fkRef: Expression<any>;
63 if (fieldDef.originModel && fieldDef.originModel !== model) {
64 // relation is actually defined in a delegate base model, select from there
65 fkRef = buildBaseSelect(fieldDef.originModel, fk);
66 } else {
67 fkRef = eb.ref(`${modelAlias}.${fk}`);

Callers

nothing calls this directly

Calls 5

buildPolicyFilterMethod · 0.95
invariantFunction · 0.90
buildBaseSelectFunction · 0.85
requireFieldMethod · 0.80
pushMethod · 0.80

Tested by

no test coverage detected