// Copyright IBM Corp. 2014,2018. All Rights Reserved. // Node module: loopback-datasource-juggler // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT 'use strict'; const debug = require('debug')('loopback:mixin'); const assert = require('assert'); const DefaultModelBaseClass = require('./model.js'); function isModelClass(cls) { if (!cls) { return false; } return cls.prototype instanceof DefaultModelBaseClass; } module.exports = MixinProvider; function MixinProvider(modelBuilder) { this.modelBuilder = modelBuilder; this.mixins = {}; } /** * Apply named mixin to the model class * @param {Model} modelClass * @param {String} name * @param {Object} options */ MixinProvider.prototype.applyMixin = function applyMixin(modelClass, name, options) { const fn = this.mixins[name]; if (typeof fn === 'function') { if (modelClass.dataSource) { fn(modelClass, options || {}); } else { modelClass.once('dataSourceAttached', function() { fn(modelClass, options || {}); }); } } else { // Try model name const model = this.modelBuilder.getModel(name); if (model) { debug('Mixin is resolved to a model: %s', name); modelClass.mixin(model, options); } else { const errMsg = 'Model "' + modelClass.modelName + '" uses unknown mixin: ' + name; debug(errMsg); throw new Error(errMsg); } } }; /** * Define a mixin with name * @param {String} name Name of the mixin * @param {*) mixin The mixin function or a model */ MixinProvider.prototype.define = function defineMixin(name, mixin) { assert(typeof mixin === 'function', 'The mixin must be a function or model class'); if (this.mixins[name]) { debug('Duplicate mixin: %s', name); } else { debug('Defining mixin: %s', name); } if (isModelClass(mixin)) { this.mixins[name] = function(Model, options) { Model.mixin(mixin, options); }; } else if (typeof mixin === 'function') { this.mixins[name] = mixin; } };