UNPKG

@directus/api

Version:

Directus is a real-time API and App dashboard for managing SQL database content

55 lines (54 loc) 2.82 kB
import { getUnaliasedFieldKey } from '../../../utils/get-unaliased-field-key.js'; import { uniq } from 'lodash-es'; import { getCases } from './get-cases.js'; /** * Mutates passed AST * * @param ast - Read query AST * @param permissions - Expected to be filtered down for the policies and action already */ export function injectCases(ast, permissions) { ast.cases = processChildren(ast.name, ast.children, permissions); } function processChildren(collection, children, permissions) { // Use uniq here, since there might be multiple duplications due to aliases or functions const requestedKeys = uniq(children.map(getUnaliasedFieldKey)); const { cases, caseMap, allowedFields } = getCases(collection, permissions, requestedKeys); // TODO this can be optimized if there is only one rule to skip the whole case/where system, // since fields that are not allowed at all are already filtered out // TODO this can be optimized if all cases are the same for all requested keys, as those should be // for (const child of children) { const fieldKey = getUnaliasedFieldKey(child); const globalWhenCase = caseMap['*']; const fieldWhenCase = caseMap[fieldKey]; // Validation should catch any fields that are attempted to be read that don't have any access control configured. // When there are no access rules for this field, and no rules for "all" fields `*`, we missed something in the validation // and should abort. if (!globalWhenCase && !fieldWhenCase) { throw new Error(`Cannot extract access permissions for field "${fieldKey}" in collection "${collection}"`); } // The case/when system only needs to take place if no full access is given on this field, // otherwise we can skip and thus safe some query perf overhead if (!allowedFields.has('*') && !allowedFields.has(fieldKey)) { // Global and field can't both be undefined as per the error check prior child.whenCase = [...(globalWhenCase ?? []), ...(fieldWhenCase ?? [])]; } if (child.type === 'm2o') { child.cases = processChildren(child.relation.related_collection, child.children, permissions); } if (child.type === 'o2m') { child.cases = processChildren(child.relation.collection, child.children, permissions); } if (child.type === 'a2o') { for (const collection of child.names) { child.cases[collection] = processChildren(collection, child.children[collection] ?? [], permissions); } } if (child.type === 'functionField') { const { cases } = getCases(child.relatedCollection, permissions, []); child.cases = cases; } } return cases; }