Source: DBMappingRegistry.js

"use strict";

const ModelFactory = require("./ModelFactory");
let instance;

/**
 * Holds all Mappings and converts them to Bookshelf Models
 */
class DBMappingRegistry {

    constructor(ModelFactory) {
        this.mappings = {};
        this.compiled = {};
        this.ModelFactory = ModelFactory;
    }

    static getInstance() {
        if (!instance) {
            instance = new DBMappingRegistry(ModelFactory);
        }

        return instance;
    }

    /**
     * Register a Mapping
     * @param {string} name - Name of the mapping
     * @param {string} dbContextName - DB context / connection name
     * @param {BookshelfMapping} mapping - Mapping description of columns, relations etc.
     */
    register(name, dbContextName, mapping) {
        if (this.isRegistered(name)) {
            throw new Error(`A mapping with name '${name}' is already registered`);
        }

        this.mappings[name] = {
            dbContextName: dbContextName,
            mapping: mapping
        };
    }

    get(name) {
        return this.mappings[name].mapping;
    }

    isRegistered(name) {
        return name in this.mappings;
    }

    /**
     * Compile a BookshelfMapping for use with an EntityRepository
     * @param {string} name - Name of a registered Mapping
     * @returns {EntityRepository} compiled Mapping, ready to use
     */
    compile(name) {
        if (!this.isCached(name)) {
            this.compileAndCache(name);
        }

        return this.compiled[name];
    }

    compileAndCache(name) {
        if (!this.isRegistered(name)) {
            throw new Error(name + " is not a registered mapping");
        }

        const factory = this.ModelFactory.context[this.mappings[name].dbContextName];
        const mapping = Object.create(this.get(name));

        if (mapping.relations) {
            mapping.relations.forEach((relation) => {
                const getCompiled = this.compile.bind(this, relation.references.mapping);

                Object.defineProperty(relation.references, "mapping", {

                    get() {
                        return getCompiled();
                    }

                });

            });
        }

        this.compiled[name] = factory.createModel(mapping);
    }

    isCached(name) {
        return name in this.compiled;
    }

}

module.exports = DBMappingRegistry;