UNPKG

@clickup/ent-framework

Version:

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

122 lines 4.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HelpersMixin = HelpersMixin; const types_1 = require("../../types"); const EntAccessError_1 = require("../errors/EntAccessError"); const EntNotFoundError_1 = require("../errors/EntNotFoundError"); const EntUniqueKeyError_1 = require("../errors/EntUniqueKeyError"); /** * Modifies the passed class adding convenience methods (like loadX() which * throws when an Ent can't be loaded instead of returning null as it's done in * the primitive operations). */ function HelpersMixin(Base) { class HelpersMixin extends Base { static async insert(vc, input) { const id = await this.insertIfNotExists(vc, input); if (!id) { throw new EntUniqueKeyError_1.EntUniqueKeyError(this.name, input); } return id; } static async insertReturning(vc, input) { const id = await this.insert(vc, input); return this.loadX(vc, id); } static async upsertReturning(vc, input) { const id = await this.upsert(vc, input); return this.loadX(vc, id); } static async loadIfReadableNullable(vc, id) { try { return await this.loadNullable(vc, id); } catch (e) { if (e instanceof EntAccessError_1.EntAccessError) { return null; } throw e; } } static async loadX(vc, id) { const ent = await this.loadNullable(vc, id); if (!ent) { throw new EntNotFoundError_1.EntNotFoundError(this.name, { [types_1.ID]: id }); } return ent; } static async loadByX(vc, input) { const ent = await this.loadByNullable(vc, input); if (!ent) { throw new EntNotFoundError_1.EntNotFoundError(this.name, input); } return ent; } async updateChanged(input) { const changedFields = []; const changedInput = {}; // Iterate over BOTH regular fields AND symbol fields. Notice that for // symbol fields, we'll always have a "changed" signal since the input Ent // doesn't have them (they are to be used in triggers only). for (const keyOrSymbol of Reflect.ownKeys(this.constructor.SCHEMA.table)) { // ID field is always treated as immutable. if (keyOrSymbol === types_1.ID) { continue; } const field = keyOrSymbol; const value = input[field]; const existingValue = this[field]; // Undefined is treated as "do not touch" signal for the field. if (value === undefined) { continue; } // Exact equality means "do not touch". if (existingValue === value) { continue; } // Works for most of Node built-in types: Date, Buffer, as well as for // user-defined custom types. if (value !== null && typeof value === "object" && existingValue !== null && typeof existingValue === "object" && JSON.stringify(value) === JSON.stringify(existingValue)) { continue; } // There IS a change in this field. Record it. changedInput[field] = value; changedFields.push(field); } if (changedFields.length > 0) { if (input.$literal) { changedInput.$literal = input.$literal; } if (input.$cas) { changedInput.$cas = input.$cas; } return (await this.updateOriginal(changedInput)) ? changedFields : false; } return null; } async updateChangedReturningX(input) { return (await this.updateChanged(input)) ? this.constructor.loadX(this.vc, this[types_1.ID]) : this; } async updateReturningNullable(input) { const updated = await this.updateOriginal(input); return updated ? this.constructor.loadNullable(this.vc, this[types_1.ID]) : null; } async updateReturningX(input) { const res = await this.updateReturningNullable(input); if (!res) { throw new EntNotFoundError_1.EntNotFoundError(this.constructor.name, { [types_1.ID]: this[types_1.ID] }); } return res; } } return HelpersMixin; } //# sourceMappingURL=HelpersMixin.js.map