UNPKG

@themost/data

Version:

MOST Web Framework Codename Blueshift - Data module

1,086 lines (1,000 loc) 37.4 kB
// MOST Web Framework 2.0 Codename Blueshift BSD-3-Clause license Copyright (c) 2017-2022, THEMOST LP All rights reserved var _ = require('lodash'); var Symbol = require('symbol'); var {TraceUtils} = require('@themost/common'); var path = require('path'); var pluralize = require('pluralize'); var {Args} = require('@themost/common'); var {ConfigurationBase} = require('@themost/common'); var {ConfigurationStrategy} = require('@themost/common'); var {PathUtils} = require('@themost/common'); var {RandomUtils} = require('@themost/common'); var {AbstractMethodError} = require('@themost/common'); var {DataCacheStrategy} = require('./data-cache'); var {DefaultDataCacheStrategy} = require('./data-cache'); var {hasOwnProperty} = require('./has-own-property'); var {ModuleLoader} = require('./module-loader'); var {DefaultModuleLoader} = require('./module-loader'); var modelsProperty = Symbol('models'); var modelPathProperty = Symbol('modelPath'); var filesProperty = Symbol('files'); var dataTypesProperty = Symbol('dataTypes'); var currentConfiguration = Symbol('current'); var namedConfigurations = Symbol('namedConfigurations'); function interopRequireDefault(path) { const hashIndex = path.indexOf('#'); if (hashIndex > 0) { var modulePath = path.substr(0, hashIndex); var memberName = path.substr(hashIndex + 1); var module = require(modulePath); if (Object.prototype.hasOwnProperty.call(module, memberName)) { return module[memberName]; } else { throw new Error('Module exported member not found'); } } /** * @type {*|{__esModule: *, default: *}} */ var obj = require(path); return obj && obj.__esModule ? obj.default : obj; } /** * * @param s * @returns {*} * @private */ function _dasherize(s) { if (_.isString(s)) return _.trim(s).replace(/[_\s]+/g, '-').replace(/([A-Z])/g, '-$1').replace(/-+/g, '-').replace(/^-/,'').toLowerCase(); return s; } /** * @method dasherize * @memberOf _ */ if (typeof _.dasherize !== 'function') { _.mixin({'dasherize' : _dasherize}); } /** * @class * @constructor * @interface */ function DataTypePropertiesConfiguration() { /** * Gets a pattern (commonly a regular expression) that validates a value of this data type * @name DataTypePropertiesConfiguration#pattern * @type {string} * @example "^[-][0-9]*$" is the pattern of NegativeInteger data type */ /** * Gets a message that describes the pattern of this data type * @name DataTypePropertiesConfiguration#patternMessage * @type {string} * @example "The value should be an integer lower than zero." */ /** * Gets the minimum value allowed for a data type * @name DataTypePropertiesConfiguration#minValue * @type {*} * @example 0 is the minimum value of NonNegativeInteger data type */ /** * Gets the maximum value allowed for a data type * @name DataTypePropertiesConfiguration#maxValue * @type {*} * @example 2147483647 is the maximum value of NonNegativeInteger data type */ } /** * @class * @constructor * @interface */ function DataTypeConfiguration() { /** * Gets a short description for this data type * @name DataTypeConfiguration#comment * @type {string} * @example "Float data type is a single-precision 32-bit floating point." */ /** * Gets a collection of additional properties of this data type * @name DataTypeConfiguration#properties * @type {DataTypePropertiesConfiguration} */ /** * Gets a title for this data type * @name DataTypeConfiguration#label * @type {string} * @example "Float" */ /** * Gets a string which represents a URL that contains information for this data type * @name DataTypeConfiguration#url * @type {string} * @example "https://www.w3.org/TR/xmlschema-2/#float" */ /** * Gets a type which is associated with this data type * @name DataTypeConfiguration#type * @type {string} * @example "number" */ /** * Gets the equivalent SQL data type * @name DataTypeConfiguration#sqltype * @type {string} * @example "FLOAT" */ /** * Gets an array of values associated with data type * @name DataTypeConfiguration#instances * @type {Array.<*>} * @example [ true, false ] are the instances of Boolean data type */ /** * Gets an array of super * @name DataTypeConfiguration#supertypes * @type {Array.<string>} * @example [ "Integer" ] are the supertypes of NegativeInteger data type */ /** * Gets a string which represents the version of this data type configuration * @name DataTypeConfiguration#version * @type {string} * @example "1.0" */ } /** * @class * @constructor * @interface * @example * { * "name":"SQLite Data Adapter", * "invariantName": "sqlite", * "type":"most-data-sqlite" * } */ function DataAdapterConfiguration() { /** * Gets a string which represents the name of this data adapter * @name DataAdapterConfiguration#name * @type {string} * @example "SQLite Data Adapter" */ /** * Gets a string which represents the invariant name of this data adapter * @name DataAdapterConfiguration#invariantName * @type {string} * @example "sqlite" */ /** * Gets a boolean which indicates whether this adapter is the default adapter or not * @name DataAdapterConfiguration#default * @type {boolean} */ /** * Gets a dictionary object which represents the connection options of this data adapter * @name DataAdapterConfiguration#options * @type {*} */ } /** * @class * @constructor * @interface * @example * { * "name":"SQLite Data Adapter", * "invariantName": "sqlite", * "type":"most-data-sqlite" * } */ function DataAdapterTypeConfiguration() { /** * Gets a string which represents the name of this data adapter * @name DataAdapterTypeConfiguration#name * @type {string} * @example "SQLite Data Adapter" */ /** * Gets a string which represents the invariant name of this data adapter * @name DataAdapterTypeConfiguration#invariantName * @type {string} * @example "sqlite" */ /** * Gets a string which represents the module that loads this data adapter * @name DataAdapterTypeConfiguration#type * @type {string} * @example "@themost/sqlite" */ } /** * @class * @constructor */ function AuthSettingsConfiguration() { /** * Gets or sets a string which represents the cookie name that is going to be used to identify a user session * @type {string} */ this.name = '.MAUTH'; /** * Gets or sets a string which represents the name of unattended execution account * @type {string} */ this.unattendedExecutionAccount = RandomUtils.randomHex(16); /** * Gets or sets a number which represents the lifetime (in minutes) of an authentication cookie * @type {number} */ this.timeout = 480; /** * Gets or sets a boolean which indicates whether an authentication cookie will have a sliding expiration or not * @type {boolean} */ this.slidingExpiration = false; /** * Gets or sets a string which represents the login URI of the current application * @type {string} */ this.loginPage = '/login'; } class DataConfiguration extends ConfigurationBase { constructor(configPath) { super(configPath); //use default data configuration strategy this.useStrategy(DataConfigurationStrategy,DataConfigurationStrategy); } /** * @returns {DataConfigurationStrategy} */ getDataConfiguration() { return this.getStrategy(DataConfigurationStrategy); } /** * @returns {DataConfiguration} */ static getCurrent() { if (DataConfiguration[currentConfiguration] instanceof DataConfiguration) { return DataConfiguration[currentConfiguration] } DataConfiguration[currentConfiguration] = new DataConfiguration(); return DataConfiguration[currentConfiguration]; } /** * @param {DataConfiguration} config * @returns {DataConfiguration} */ static setCurrent(config) { Args.check(config instanceof DataConfiguration, 'Invalid argument. Expected an instance of DataConfiguration class.'); DataConfiguration[currentConfiguration] = config; return DataConfiguration[currentConfiguration]; } /** * @param {string=} name */ static getNamedConfiguration(name) { if (_.isNil(name)) { return DataConfiguration.getCurrent(); } Args.notString(name, 'Configuration Name'); Args.notEmpty(name, 'Configuration name'); if (/^current$/i.test(name)) { return DataConfiguration.getCurrent(); } if (_.isNil(DataConfiguration[namedConfigurations])) { DataConfiguration[namedConfigurations] = { }; } if (typeof DataConfiguration[namedConfigurations][name] !== 'undefined') return DataConfiguration[namedConfigurations][name]; DataConfiguration[namedConfigurations][name] = new DataConfiguration(); return DataConfiguration[namedConfigurations][name]; } } class DataConfigurationStrategy extends ConfigurationStrategy { constructor(config) { super(config); ///register other strategies if (!config.hasStrategy(SchemaLoaderStrategy)) { config.useStrategy(SchemaLoaderStrategy, DefaultSchemaLoaderStrategy); } if (!config.hasStrategy(ModelClassLoaderStrategy)) { config.useStrategy(ModelClassLoaderStrategy, DefaultModelClassLoaderStrategy); } if (!config.hasStrategy(DataCacheStrategy)) { //process is running under node.js if (typeof process !== 'undefined' && process.nextTick) { //add default cache strategy (using node-cache) config.useStrategy(DataCacheStrategy, DefaultDataCacheStrategy); } } if (!this.getConfiguration().hasSourceAt('adapters')) { this.getConfiguration().setSourceAt('adapters',[]); } if (!this.getConfiguration().hasSourceAt('adapterTypes')) { this.getConfiguration().setSourceAt('adapterTypes',[]); } if (!this.getConfiguration().hasSourceAt('settings/auth')) { this.getConfiguration().setSourceAt('settings/auth', new AuthSettingsConfiguration()); } /** * @type {Map<string, Function>} */ var adapterTypes = new Map(); Object.defineProperty(this, 'adapterTypes', { get: function () { return adapterTypes; }, enumerable: false, configurable: true }); /** * @type {DataAdapterTypeConfiguration[]} */ var configAdapterTypes = this.getConfiguration().getSourceAt('adapterTypes'); var self = this; //configure adapter types _.forEach(configAdapterTypes, function(x) { //first of all validate module x.invariantName = x.invariantName || 'unknown'; x.name = x.name || 'Unknown Data Adapter'; var valid = false; var adapterModule; var AdapterCtor; // if adapter type is function if (typeof x.type === 'function') { // set adapter self.adapterTypes.set(x.invariantName, { invariantName: x.invariantName, name: x.name, type: AdapterCtor }); return; } if (x.type) { try { // add current execution directory to module.paths const executionPath = self.getConfiguration().getExecutionPath() || process.cwd(); let extraPath = path.resolve(executionPath, 'node_modules'); while(extraPath.length && module.paths.includes(extraPath) === false) { module.paths.push(extraPath); extraPath = path.resolve(extraPath, '..', '..', 'node_modules'); } if (/#/.test(x.type)) { var modulePath = x.type.substr(0, x.type.indexOf('#')); var moduleMember = x.type.substr(x.type.indexOf('#')+1); adapterModule = require(modulePath); AdapterCtor = adapterModule[moduleMember]; } else { adapterModule = require(x.type); } if (typeof AdapterCtor === 'function' || typeof adapterModule.createInstance === 'function') { valid = true; } else { TraceUtils.warn(`The specified data adapter type (${x.invariantName}) does not have the appropriate constructor. Adapter type cannot be loaded.`); } } catch(err) { // catch error TraceUtils.error(err); // and log a specific error for this adapter type TraceUtils.error(`The specified data adapter type (${x.invariantName}) cannot be instantiated. Adapter type cannot be loaded.`); } if (valid) { // register adapter if (typeof AdapterCtor === 'function') { self.adapterTypes.set(x.invariantName, { invariantName: x.invariantName, name: x.name, type: AdapterCtor }); } else { // backward compatibility using a factory method self.adapterTypes.set(x.invariantName, { invariantName: x.invariantName, name: x.name, createInstance: adapterModule.createInstance }); } } } else { TraceUtils.warn(`The specified data adapter type (${x.invariantName}) does not have a type defined. Adapter type cannot be loaded.`); } }); /** * @name DataConfigurationStrategy#dataTypes * @type {Object.<string,DataTypeConfiguration>} */ Object.defineProperty(this,'dataTypes', { get:function() { if (this[dataTypesProperty]) { return this[dataTypesProperty]; } //get data types from configuration file try { var dataTypes = require(path.join(this.getConfiguration().getConfigurationPath(), 'dataTypes.json')); if (_.isNil(dataTypes)) { TraceUtils.log('Data: Application data types are empty. The default data types will be loaded instead.'); dataTypes = require('./dataTypes.json'); } else { //append default data types which are not defined in application data types var defaultDataTypes = require('./dataTypes.json'); //enumerate default data types and replace or append application specific data types _.forEach(_.keys(defaultDataTypes), function(key) { if (hasOwnProperty(dataTypes, key)) { if (dataTypes[key].version) { if (dataTypes[key].version <= defaultDataTypes[key].version) { //replace data type due to lower version dataTypes[key] = defaultDataTypes[key]; } } else { //replace data type due to invalid version dataTypes[key] = defaultDataTypes[key]; } } else { //append data type dataTypes[key] = defaultDataTypes[key]; } }); } } catch(err) { if (err.code === 'MODULE_NOT_FOUND') { TraceUtils.log('Data: Application specific data types are missing. The default data types will be loaded instead.'); } else { TraceUtils.log('Data: An error occurred while loading application data types.'); throw err; } dataTypes = require('./dataTypes.json'); } this[dataTypesProperty] = dataTypes; return this[dataTypesProperty]; } }); /** * @name DataConfigurationStrategy#adapters * @type {Array.<DataAdapterConfiguration>} */ Object.defineProperty(this,'adapters', { get:function() { return this.getConfiguration().getSourceAt('adapters'); } }); } /** * @returns {AuthSettingsConfiguration|*} */ getAuthSettings() { return this.getConfiguration().getSourceAt('settings/auth'); } /** * @param {string} invariantName * @returns {*} */ getAdapterType(invariantName) { return this.adapterTypes.get(invariantName); } /** * Gets a boolean which indicates whether the specified data type is defined in data types collection or not. * @param name * @returns {boolean} */ hasDataType(name) { if (_.isNil(name)) { return false; } if (typeof name !== 'string') { return false; } return hasOwnProperty(this.dataTypes, name); } /** * Gets a native object which represents the definition of the model with the given name. * @param {string} name * @returns {*} */ getModelDefinition(name) { /** * @type {SchemaLoaderStrategy} */ var schemaLoader = this.getConfiguration().getStrategy(SchemaLoaderStrategy); return schemaLoader.getModelDefinition(name); } /** * Gets a native object which represents the definition of the model with the given name. * @param {*} data * @returns {DataConfigurationStrategy} */ setModelDefinition(data) { /** * @type {SchemaLoaderStrategy} */ var schemaLoader = this.getConfiguration().getStrategy(SchemaLoaderStrategy); schemaLoader.setModelDefinition(data); return this; } /** * @returns {*} * @param name {string} */ model(name) { return this.getModelDefinition(name); } /** * Gets the current data configuration * @returns DataConfigurationStrategy - An instance of DataConfiguration class which represents the current data configuration */ static getCurrent() { var configuration = ConfigurationBase.getCurrent(); if (!configuration.hasStrategy(DataConfigurationStrategy)) { configuration.useStrategy(DataConfigurationStrategy, DataConfigurationStrategy); } return configuration.getStrategy(DataConfigurationStrategy); } } class SchemaLoaderStrategy extends ConfigurationStrategy { constructor(config) { super(config); this[modelsProperty] = {}; this.setModelDefinition({ 'name':'Migration', 'title':'Data Model Migrations', 'id': 14, 'source':'migrations', 'view':'migrations', 'hidden': true, 'sealed':true, 'fields':[ { 'name':'id', 'type':'Counter', 'primary':true }, { 'name':'appliesTo', 'type':'Text', 'size':180, 'nullable':false }, { 'name':'model', 'type':'Text', 'size':120 }, { 'name':'description', 'type':'Text', 'size':512}, { 'name':'version', 'type':'Text', 'size':40, 'nullable':false } ], 'constraints':[ { 'type':'unique', 'fields':[ 'appliesTo', 'version' ] } ] }); } /** * Gets a model definition * @param {string} name * @returns {*} */ getModelDefinition(name) { Args.notString(name,'Model name'); var result = this[modelsProperty][name]; if (typeof result !== 'undefined') { return result; } var re = new RegExp('^'+name+'$','ig'); result = _.find(_.keys(this[modelsProperty]), function(x) { return re.test(x); }); return result; } /** * Sets a model definition * @param {*} data * @returns {SchemaLoaderStrategy} */ setModelDefinition(data) { if (data == null) { throw new Error('Invalid model definition. Expected object.') } if (typeof data === 'object') { if (typeof data.name === 'undefined' || data.name === null) { throw new Error('Invalid model definition. Expected model name.') } this[modelsProperty][data.name] = data; } return this; } /** * Gets an array of strings which represents the loaded models * @returns {Array.<string>} */ getModels() { return _.keys(this[modelsProperty]); } /** * @abstract * @returns Array<string> */ readSync() { throw new AbstractMethodError(); } } class FileSchemaLoaderStrategy extends SchemaLoaderStrategy { constructor(config) { super(config); // set default path for *.json schemas this[modelPathProperty] = PathUtils.join(config.getConfigurationPath(), 'models'); /** * @type {DefaultSchemaLoaderStrategyOptions} */ var schemaOptions = config.getSourceAt('settings/schema'); /** * set default options * @type {DefaultSchemaLoaderStrategyOptions} */ this.options = { usePlural: true }; // get only DefaultSchemaLoaderStrategyOptions.usePlural if exists if (schemaOptions && hasOwnProperty(schemaOptions, 'usePlural')) { this.options.usePlural = schemaOptions.usePlural; } } /** * Gets a string which represents the directory which contains model definitions. * @returns {string} */ getModelPath() { return this[modelPathProperty]; } /** * Reads available schemas * @returns {Array<string>} */ readSync() { // load native fs module var nativeFsModule = 'fs'; var modelPath = this.getModelPath(); var fs = require(nativeFsModule); var files = []; // read directory if (typeof fs.readdirSync === 'function') { var dirExists = true; if (typeof fs.existsSync === 'function') { dirExists = fs.existsSync(modelPath); } if (dirExists) { // set files property files = _.map(_.filter(fs.readdirSync(modelPath), function(file) { // filter *.json files return /\.json$/i.test(file); }), function(file) { //strip file extension return file.replace(/\.json$/i, ''); }); } } // return collection of schemas return files; } /** * Sets the directory of model definitions. * @param {string} p * @returns this */ setModelPath(p) { this[modelPathProperty] = p; return this; } /** * Gets a model definition * @param {string} name * @returns {*} */ getModelDefinition(name) { var getModelDefinitionSuper = super.getModelDefinition; var i; if (typeof name !== 'string') return; //exclude registered data types if (this.getConfiguration().getStrategy(DataConfigurationStrategy).hasDataType(name)) { return; } var modelDefinition = getModelDefinitionSuper.bind(this)(name); //first of all try to find if model definition is already in cache if (modelDefinition) { //and return it return modelDefinition; } // hold singular name of var singularName; if (this.options.usePlural && pluralize.isPlural(name)) { // try to find model based on singular name singularName = pluralize.singular(name); // call super func modelDefinition = getModelDefinitionSuper.bind(this)(singularName); if (modelDefinition) { //and return it return modelDefinition; } } if (this[filesProperty] == null) { this[filesProperty] = this.readSync().map( file => { return file.concat('.json') }); } /** * @type Array<string> */ var files = this[filesProperty]; if (files.length===0) { return; } var modelPath = this.getModelPath(); var searchName; if (singularName) { // search for singular name also e.g. ^(User|Users)\.json$ searchName = new RegExp('^(' + singularName + '|' + name + ')\\.json$','i'); } else { // otherwise search for name e.g. ^User\.json$ searchName = new RegExp('^' + name + '\\.json$','i'); } for (i = 0; i < files.length; i++) { searchName.lastIndex=0; if (searchName.test(files[i])) { // build model file path var finalPath = PathUtils.join(modelPath, files[i]); // get model var result = require(finalPath); // clone var finalResult = _.cloneDeep(result); // clone and set definition this.setModelDefinition(finalResult); // return this definition return finalResult; } } } } class DefaultSchemaLoaderStrategy extends FileSchemaLoaderStrategy { constructor(config) { super(config); this[modelPathProperty] = PathUtils.join(config.getConfigurationPath(), 'models'); /** * @type {Array<SchemaLoaderStrategy>} */ this.loaders = []; /** * get loaders from configuration * @type {DefaultSchemaLoaderStrategyOptions} * @example * [ * { * "loaderType": "any-library#CustomSchemaLoader" * }, * { * "loaderType": "another-library#AnotherSchemaLoader" * } * ] */ var schemaOptions = config.getSourceAt('settings/schema'); /** * prepare options * @type {DefaultSchemaLoaderStrategyOptions} */ this.options = _.assign({}, { usePlural: true }, schemaOptions); // set loaders var thisArg = this; // if configuration has a collection of loaders if (this.options.loaders && this.options.loaders.length) { // get module loader service var moduleLoader = config.getStrategy(ModuleLoader); if (moduleLoader == null) { moduleLoader = new DefaultModuleLoader(config.getExecutionPath()); } // enumerate loader types _.forEach(this.options.loaders, function(x) { // if loader has a hash e.g. ./lib/index#AnotherLoader var hashIndex = x.loaderType.indexOf('#'); if (hashIndex>-1) { // get loader module var typeModule = moduleLoader.require(x.loaderType.substr(0,hashIndex)); // get loader constructor var typeCtor = x.loaderType.substr(hashIndex+1,x.loaderType.length-hashIndex); // if module exports loader constructor if (hasOwnProperty(typeModule, typeCtor)) { var LoaderCtor = typeModule[typeCtor]; // add loader to collection thisArg.loaders.push(new LoaderCtor(config)); } } else { // simply add module to collection of loaders // we assume that module exports the required methods // and acts like an instance of SchemaLoader class thisArg.loaders.push(moduleLoader.require(x.loaderType)); } }); } } /** * Gets a model definition * @param {string} name * @returns {*} */ getModelDefinition(name) { // get super class method var getModelDefinitionSuper = super.getModelDefinition; // execute method var model = getModelDefinitionSuper.bind(this)(name); // if model is missing if (model == null) { // try to load model from alternative loaders if any if (this.loaders && this.loaders.length) { for (let i = 0; i < this.loaders.length; i++) { /** * @type {SchemaLoaderStrategy} */ var loader = this.loaders[i]; // try to get model model = loader.getModelDefinition(name); // if model exists if (model != null) { // set model definition to avoid searching loaders again this.setModelDefinition(model); // and return return model; } } } } return model; } } class ModelClassLoaderStrategy extends ConfigurationStrategy { constructor(config) { super(config); } /** * @param {DataModel} model * @returns {DataObjectConstructor} */ // eslint-disable-next-line no-unused-vars resolve(model) { throw new AbstractMethodError(); } } class DefaultModelClassLoaderStrategy extends ModelClassLoaderStrategy { constructor(config) { super(config); } /** * @param {*} model * @returns {DataObjectConstructor} */ resolve(model) { Args.notNull(model, 'Model'); var dataObjectClassProperty = 'DataObjectClass'; // get data object class from the given model var DataObjectClass = model.DataObjectClass; // if DataObjectClass is a constructor if (typeof DataObjectClass === 'function') { return DataObjectClass; } // get model definition var modelDefinition = this.getConfiguration().getStrategy(SchemaLoaderStrategy).getModelDefinition(model.name); var executionPath = this.getConfiguration().getExecutionPath(); // noinspection ExceptionCaughtLocallyJS if (typeof model.classPath === 'string') { if (/^\.\//.test(model.classPath)) { modelDefinition[dataObjectClassProperty] = DataObjectClass = interopRequireDefault(PathUtils.join(executionPath, model.classPath)); } else { modelDefinition[dataObjectClassProperty] = DataObjectClass = interopRequireDefault(model.classPath); } } else { var requireModules = [ // e.g. ./models/OrderDetail PathUtils.join(executionPath, 'models', model.name), // e.g. ./models/OrderDetailModel PathUtils.join(executionPath,'models', model.name.concat('Model')), // e.g. ./models/order-detail-model PathUtils.join(executionPath,'models',_.dasherize(model.name).concat('-model')), // e.g. ./models/order-detail.model PathUtils.join(executionPath,'models',_.dasherize(model.name).concat('.model')), ]; for (var requiredModule of requireModules) { try { var module = require(requiredModule); // try to find if module has an exported member with name equal to this model name if (hasOwnProperty(module, model.name) && typeof module[model.name] === 'function') { modelDefinition[dataObjectClassProperty] = DataObjectClass = module[model.name]; } else if (hasOwnProperty(module, '__esModule') && typeof module.default === 'function') { // try to find the default export modelDefinition[dataObjectClassProperty] = DataObjectClass = module.default; } else if (typeof module === 'function') { // otherwise validate module modelDefinition[dataObjectClassProperty] = DataObjectClass = module; } if (DataObjectClass != null) { return DataObjectClass; } // and throw error if module has an invalid format var error = Object.assign(new Error('Data model class module is invalid. Expected a class to be exported as default or named member'), { code: 'MODULE_INVALID', module: requiredModule }); throw error; } catch (err) { if (err.code !== 'MODULE_NOT_FOUND') { throw err; } // otherwise, continue } } // check if model inherits another model and return its class if (model.inherits != null) { var inheritedModel = model.context.model(model.inherits); if (inheritedModel == null) { throw new Error('Inherited model cannot be found'); } modelDefinition[dataObjectClassProperty] = DataObjectClass = this.resolve(inheritedModel); } else if (model.implements != null) { var implementedModel = model.context.model(model.implements); if (implementedModel == null) { throw new Error('Implemented model cannot be found'); } modelDefinition[dataObjectClassProperty] = DataObjectClass = this.resolve(implementedModel); } else { // finally, return DataObject modelDefinition[dataObjectClassProperty] = DataObjectClass = require('./data-object').DataObject; } } return DataObjectClass; } } /** * Gets the current data configuration * @returns DataConfiguration - An instance of DataConfiguration class which represents the current data configuration */ function getCurrent() { return DataConfiguration.getCurrent(); } /** * Sets the current data configuration * @param {DataConfiguration} configuration * @returns DataConfiguration - An instance of DataConfiguration class which represents the current data configuration */ function setCurrent(configuration) { return DataConfiguration.setCurrent(configuration); } /** * Creates an instance of DataConfiguration class * @returns {DataConfiguration} - Returns an instance of DataConfiguration class */ function createInstance() { return new DataConfiguration(); } /** * Gets an instance of DataConfiguration class based on the given name. * If the named data configuration does not exist, it will create a new instance of DataConfiguration class with the given name. * @param {string} name - A string which represents the name of the data configuration * @returns {DataConfiguration} */ function getNamedConfiguration(name) { return DataConfiguration.getNamedConfiguration(name); } module.exports = { getCurrent, setCurrent, createInstance, getNamedConfiguration, DataTypePropertiesConfiguration, DataTypeConfiguration, DataAdapterTypeConfiguration, DataAdapterConfiguration, AuthSettingsConfiguration, DataConfiguration, DataConfigurationStrategy, SchemaLoaderStrategy, FileSchemaLoaderStrategy, DefaultSchemaLoaderStrategy, ModelClassLoaderStrategy, DefaultModelClassLoaderStrategy };