UNPKG

baqend

Version:

Baqend JavaScript SDK

121 lines (106 loc) 3.29 kB
/* eslint-disable no-param-reassign,max-classes-per-file */ import { Class } from '../util/Class'; import { Attribute, ManagedType } from '../metamodel'; import type { Managed } from './Managed'; const BAQEND_ID = Symbol('BaqendId'); const BAQEND_TYPE = Symbol('BaqendType'); export class Enhancer { /** * @param superClass * @return typeConstructor */ createProxy<T extends S, S>(superClass: Class<S>): Class<T> { return class Proxy extends (superClass as any) {} as Class<T>; } /** * @param typeConstructor * @returns type the managed type metadata for this class */ static getBaqendType(typeConstructor: Class<any> | Function): ManagedType<any> | null { return (typeConstructor as any)[BAQEND_TYPE]; } /** * @param typeConstructor * @return */ static getIdentifier(typeConstructor: Class<any> | Function): string | null { return (typeConstructor as any)[BAQEND_ID]; } /** * @param typeConstructor * @param identifier */ static setIdentifier(typeConstructor: Class<any>, identifier: string): void { (typeConstructor as any)[BAQEND_ID] = identifier; } /** * @param type * @param typeConstructor */ enhance<T extends Managed>(type: ManagedType<T>, typeConstructor: Class<T>): void { if ((typeConstructor as any)[BAQEND_TYPE] === type) { return; } if (Object.prototype.hasOwnProperty.call(typeConstructor, BAQEND_TYPE)) { throw new Error('Type is already used by a different manager'); } (typeConstructor as any)[BAQEND_TYPE] = type; Enhancer.setIdentifier(typeConstructor, type.ref); this.enhancePrototype(typeConstructor.prototype, type); } /** * Enhance the prototype of the type * @param proto * @param type */ enhancePrototype<T extends Managed>(proto: T, type: ManagedType<T>): void { if (type.isEmbeddable) { return; // we do not need to enhance the prototype of embeddable } if (proto.toString === Object.prototype.toString) { // implements a better convenience toString method Object.defineProperty(proto, 'toString', { value: function toString() { return this._metadata.id || this._metadata.bucket; }, enumerable: false, }); } // enhance all persistent object properties if (type.superType && type.superType.name === 'Object') { type.superType.declaredAttributes.forEach((attr) => { if (!attr.isMetadata) { this.enhanceProperty(proto, attr); } }); } // enhance all persistent properties type.declaredAttributes.forEach((attr) => { this.enhanceProperty(proto, attr); }); } /** * @param proto * @param attribute */ enhanceProperty<T>(proto: T, attribute: Attribute<any>): void { const { name } = attribute; Object.defineProperty(proto, name, { get() { this._metadata.throwUnloadedPropertyAccess(name); return null; }, set(value) { this._metadata.throwUnloadedPropertyAccess(name); Object.defineProperty(this, name, { value, writable: true, enumerable: true, configurable: true, }); }, configurable: true, enumerable: true, }); } }