UNPKG

@clickup/ent-framework

Version:

A PostgreSQL graph-database-alike library with microsharding and row-level security

74 lines 3.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.IncomingEdgeFromVCExists = void 0; const misc_1 = require("../../internal/misc"); const types_1 = require("../../types"); const Predicate_1 = require("./Predicate"); /** * An ent may represent not necessarily a node in the graph, but also an edge * between two nodes. Consider EntMember in the below example: * * vc.principal <--- EntMember[user_id, company_id] ---> EntCompany * * This predicate verifies that for a e.g. given EntCompany row and a given VC, * an EntMember row exists (and optionally matches some criterion) in the * database. * * - entEdgeVCField = user_id in the above example * - entEdgeFKField = company_id in the above example * - if an EntMember object exists, it must also match entEdgeFilter() */ class IncomingEdgeFromVCExists { constructor(EntEdge, entEdgeVCField, entEdgeFKField, entEdgeFilter) { this.EntEdge = EntEdge; this.entEdgeVCField = entEdgeVCField; this.entEdgeFKField = entEdgeFKField; this.entEdgeFilter = entEdgeFilter; this.instanceID = (0, misc_1.localUniqueInt)(); this.name = this.constructor.name + "(" + this.EntEdge.name + "[" + `${this.entEdgeVCField}=vc, ` + `${this.entEdgeFKField}=row.${types_1.ID}` + "]" + ")"; } async check(vc, row) { const cache = vc.cache(Predicate_1.IDsCacheCanReadIncomingEdge); const cacheKey = (0, misc_1.nullthrows)(row[types_1.ID]) + ":" + this.instanceID; if (cache.has(cacheKey)) { return true; } const where = { [this.entEdgeFKField]: row[types_1.ID], [this.entEdgeVCField]: vc.principal, }; let allow; if (this.entEdgeFilter) { // We use an omni VC here to avoid cyclic references where the edge ent // delegates permission checks to the row ent, and row ent loads the edge // ent to run the edgeEntFilter function. It's safe, because: // 1. Omni VC is always demoted to the current user's VC (which is vc // since we filter by vc.principal above) or to a guest VC if it cannot // find a user_id field in the edge ent (which also never happens). // 2. The edgeEntFilter function is synchronous, so it can't physically // access the database anyway. const ents = await this.EntEdge.select(vc.toOmniDangerous(), where, 1); const filtered = ents.filter((ent) => this.entEdgeFilter(ent)); allow = filtered.length > 0; } else { // Exists is not privacy-checked (it doesn't fetch any row to be checked). allow = await this.EntEdge.exists(vc, where); } if (allow) { cache.add(cacheKey); return true; } return false; } } exports.IncomingEdgeFromVCExists = IncomingEdgeFromVCExists; //# sourceMappingURL=IncomingEdgeFromVCExists.js.map