@amberjs/core
Version:
Amber.js core module
254 lines (221 loc) • 6.36 kB
JavaScript
/**
* Import Awilix
* */
const {
createContainer,
Lifetime,
asClass,
asFunction,
asValue
} = require('awilix');
const serverless = require('serverless-http');
const { scopePerRequest } = require('awilix-express');
const dataSourceFactory = require('./factories/dataSourceFactory');
const logger = require('./logger');
const server = require('./Server');
const { readFiles } = require('./utils');
class Application {
constructor(config) {
this.config = config;
this.container = createContainer();
}
getServer() {
return this.container.resolve('server');
}
getServerless() {
return serverless(this.container.resolve('server').express);
}
_boot() {
const { sources } = this.config.app;
return this._loadSources(sources).then(
([
useCases,
dataSourceConfigs,
modelDefinitions,
repositories,
middlewares,
controllers,
router
]) => {
// Build Models and Datasources
const { models, datasources } = this._buildModelsAndDatasources(
modelDefinitions,
dataSourceConfigs
);
// Set Application properties and inject as dependencies to container
this._setConfig(this.config);
this._setUseCases(useCases);
this._setDatasources(datasources);
this._setModels(models);
this._setRepositories(repositories);
this._setContainerMiddleware();
this._setMiddlewares(middlewares);
this._setControllers(controllers);
this._setLogger(logger);
this._setRouter(router);
this._setServer(server);
}
);
}
_setUseCases(useCases) {
this.useCases = useCases;
this.container.register(
Object.keys(useCases).reduce((acc, val) => {
acc[val] = asClass(useCases[val]);
return acc;
}, {})
);
}
_setDatasources(datasources) {
this.datasources = datasources;
this.container.register(
Object.keys(datasources).reduce((acc, val) => {
acc[val] = asValue(datasources[val]);
return acc;
}, {})
);
}
_setModels(models) {
this.models = models;
this.container.register(
Object.keys(models).reduce((acc, val) => {
acc[val] = asValue(models[val]);
return acc;
}, {})
);
}
_setRepositories(repositories) {
this.repositories = repositories;
this.container.register(
Object.keys(repositories).reduce((acc, val) => {
acc[val] = asClass(repositories[val], { lifetime: Lifetime.SINGLETON });
return acc;
}, {})
);
}
_setContainerMiddleware() {
this.container.register({
containerMiddleware: asValue(scopePerRequest(this.container))
});
}
_setMiddlewares(middlewares) {
this.middlewares = middlewares;
this.container.register(
Object.keys(middlewares).reduce((acc, val) => {
acc[val] = asValue(middlewares[val]);
return acc;
}, {})
);
}
_setControllers(controllers) {
this.controllers = controllers;
this.container.register(
Object.keys(controllers).reduce((acc, val) => {
acc[val] = asClass(controllers[val], { lifetime: Lifetime.SINGLETON });
return acc;
}, {})
);
}
_setRouter(router) {
this.router = router;
this.container.register({
router: asFunction(router, { lifetime: Lifetime.SINGLETON })
});
}
_setServer(server) {
this.container.register({
server: asClass(server, { lifetime: Lifetime.SINGLETON })
});
this.server = this.container.resolve('server');
this.serverless = serverless(this.server.express);
}
_setLogger(logger) {
this.logger = logger;
this.container.register({
logger: asFunction(logger, { lifetime: Lifetime.SINGLETON })
});
}
_setConfig(config) {
this.container.register({
config: asValue(config)
});
}
_loadSources(sources) {
return Promise.all([
readFiles(sources.app),
readFiles(sources.dataSource, false),
readFiles(sources.model, false),
readFiles(sources.repository),
readFiles(sources.middleware),
readFiles(sources.controller)
]).then(result => {
result.push(require(sources.router));
return result;
});
}
_buildModelsAndDatasources(modelDefinitions, dataSourceConfigs) {
let datasourceInstances = {};
if (dataSourceConfigs.length > 0) {
// build dataSources
datasourceInstances = dataSourceConfigs.reduce(
(dataSources, dataSourceConfig) => {
dataSources[dataSourceConfig.name] = dataSourceFactory(
dataSourceConfig
);
return dataSources;
},
{}
);
}
// group models by datasource
const modelDefinitionsByDatasource = modelDefinitions.reduce((acc, val) => {
if (!(val.datasource in datasourceInstances)) {
throw new Error(
`Datasource "${val.datasource}" defined in model "${val.name}" doesnt exist`
);
}
if (!(val.datasource in acc)) {
acc[val.datasource] = [];
}
acc[val.datasource].push({
definition: val.definition,
name: val.name
});
return acc;
}, {});
let models = {};
let datasources = {};
// create models and datasources
Object.keys(modelDefinitionsByDatasource).forEach(key => {
const datasourceInstance = datasourceInstances[key];
const datasourceModels = modelDefinitionsByDatasource[key];
const thisModels = {};
datasourceModels.forEach(modelDefinition => {
const model = modelDefinition.definition(
datasourceInstance,
datasourceInstance.DataTypes
);
thisModels[modelDefinition.name] = model;
});
Object.keys(thisModels).forEach(modelName => {
if (thisModels[modelName].associate) {
thisModels[modelName].associate();
}
});
if (datasourceInstance.isSync) {
if (datasourceInstance.alter) {
datasourceInstance.sync({ alter: true });
} else {
datasourceInstance.sync();
}
}
Object.assign(models, thisModels);
datasources[key] = datasourceInstance;
});
return {
models,
datasources
};
}
}
module.exports = Application;