@aarconada/urserver
Version:
Basic Server definitions to develope REST API with a node + express Server
512 lines (453 loc) • 30.4 kB
JavaScript
/**
* Created by ubuntu on 12/11/18.
*/
'use strict';
const server = require('../server')();
const path = require('path');
const _ = require('lodash');
module.exports.enabled = server.configuration.generators.primeng.enabled;
if(server.configuration.generators.primeng.enabled) {
var generatedEndpoints;
const generate = function(origin, result) {
generatedEndpoints = [];
var originFiles = server.fileSystem.readDirectory(origin);
server.fileSystem.createDirectoryIfNotExists(result);
originFiles.forEach(currentFile => {
const fileOriginFullPath = path.join(origin, currentFile);
if(server.fileSystem.isDirectory(fileOriginFullPath)) {
//server.debug(fileOriginFullPath);
if(currentFile.toLowerCase() === 'assets') {
server.fileSystem.copyFolderRecursiveSync(fileOriginFullPath, result);
} else {
const fileResultFullPath = path.join(result, currentFile);
this.generate(fileOriginFullPath, fileResultFullPath);
}
} else {
const fileParse = path.parse(fileOriginFullPath);
if(fileParse.ext === server.configuration.generators.primeng.extension) {
//server.debug(fileOriginFullPath);
var fileContent = server.fileSystem.readAbsoluteFile(fileOriginFullPath);
if(!_.isUndefined(fileContent) && !_.isEmpty(fileContent)) {
//server.debug(result + fileParse.name);
var startTokenPosition = fileContent.indexOf('[#');
var saveFileContent = true;
const exampleService = getExampleService();
while (startTokenPosition !== -1) {
var endTokenPosition = fileContent.indexOf('#]', startTokenPosition);
if (endTokenPosition !== -1) {
var configurationItem = fileContent.substring(startTokenPosition + 2, endTokenPosition);
if(configurationItem === 'CONSTANTS') {
fileContent = generateConstants(fileContent, startTokenPosition, endTokenPosition + 2);
} else if(configurationItem === 'MODEL') {
saveFileContent = false;
generateModels(fileContent, startTokenPosition, endTokenPosition + 2, result);
} else if(configurationItem === 'SERVICE') {
saveFileContent = false;
generateModelServices(fileContent, startTokenPosition, endTokenPosition + 2, result);
generateCustomServices(fileContent, startTokenPosition, endTokenPosition + 2, result);
} else if(configurationItem === 'EXAMPLE_SERVICE_DEFINITION') {
fileContent = fileContent.substring(0, startTokenPosition) +
exampleService +
fileContent.substring((endTokenPosition + 2));
} else if(configurationItem === 'SERVICES_IMPORTS') {
fileContent = fileContent.substring(0, startTokenPosition) +
getServicesImports() +
fileContent.substring((endTokenPosition + 2));
} else if(configurationItem === 'SERVICES_PROVIDERS') {
fileContent = fileContent.substring(0, startTokenPosition) +
getServicesProviders() +
fileContent.substring((endTokenPosition + 2));
} else if(configurationItem === 'COMPONENTS_DECLARATIONS') {
fileContent = fileContent.substring(0, startTokenPosition) +
getComponentsDeclarations() +
fileContent.substring((endTokenPosition + 2));
} else if(configurationItem === 'MENU_ITEMS') {
fileContent = fileContent.substring(0, startTokenPosition) +
getMenuItems() +
fileContent.substring((endTokenPosition + 2));
} else {
var configurationItemParts = configurationItem.split('.');
var configurationValue = server;
for (var i = 0; i < configurationItemParts.length; i++) {
configurationValue = configurationValue[configurationItemParts[i]];
if (_.isUndefined(configurationValue)) {
configurationValue = '';
break;
}
}
fileContent = fileContent.substring(0, startTokenPosition) +
configurationValue +
fileContent.substring((endTokenPosition + 2));
}
}
startTokenPosition = fileContent.indexOf('[#', (startTokenPosition + 1));
}
if(saveFileContent) {
server.fileSystem.saveAbsoluteFile(
path.join(result, fileParse.name),
fileContent
);
}
}
}
}
});
};
const getExampleService = function() {
var result = '';
const existingKeys = Object.keys(server.sequelize.options);
for(var i = 0; i < existingKeys.length; i++) {
var currentOptions = server.sequelize.options[existingKeys[i]];
if(currentOptions.GET.all.enabled) {
result = existingKeys[i];
break;
}
};
return result;
}
const getComponentsDeclarations = function(baseFile, start, end, resultPath) {
var declarations = '';
//TODO: DEVELOPE COMPONENT DECLARATIONS
/*Object.keys(server.sequelize.options).forEach(currentModel => {
declarations += '\t\t' + currentModel + '_Service,\n'
});*/
return declarations;
}
const getServicesProviders = function(baseFile, start, end, resultPath) {
var providers = '';
Object.keys(server.sequelize.options).forEach(currentModel => {
providers += '\t\t' + currentModel + '_Service,\n'
});
return providers;
}
const getServicesImports = function(baseFile, start, end, resultPath) {
var includes = '';
includes += '//*****************************************************************************************************\n';
includes += '//*** AUTOGENERATED INCLUDES ***\n';
includes += '//*****************************************************************************************************\n';
Object.keys(server.sequelize.options).forEach(currentModel => {
includes += 'import {' + currentModel + '_Service} from "./private/service/' + currentModel + '";\n'
});
return includes;
}
const generateModelServices = function(baseFile, start, end, resultPath) {
Object.keys(server.sequelize.options).forEach(currentModel => {
var definedOptions = server.sequelize.options[currentModel];
var definedModel = server.sequelize[currentModel];
var tableName = server.sequelize[currentModel].tableName
var fileName = currentModel + '.ts';
var includes = '';
includes += '//*****************************************************************************************************\n';
includes += '//*** AUTOGENERATED INCLUDES ***\n';
includes += '//*****************************************************************************************************\n';
includes += 'import {Injectable, Injector} from "@angular/core";\n'
includes += 'import {BehaviorSubject, Observable, Subscription} from "rxjs";\n'
includes += 'import {Constants} from "../config/constants";\n'
includes += 'import {HttpClient} from "@angular/common/http";\n'
includes += 'import {CustomResponse} from "../config/CustomResponse";\n'
includes += 'import {' + currentModel + '_Model} from "../model/' + currentModel + '";\n'
var classDefinition = '';
classDefinition += '//*****************************************************************************************************\n';
classDefinition += '//*** AUTOGENERATED SERVICE DEFINITION ***\n';
classDefinition += '//*** DEVELOPED BY: Alberto Arconada ***\n';
classDefinition += '//*****************************************************************************************************\n';
classDefinition += '@Injectable()\n';
classDefinition += 'export class ' + currentModel + '_Service {\n';
var constructor = '';
constructor += '\t//*****************************************************************************************************\n';
constructor += '\t//*** AUTOGENERATED CONSTRUCTOR ***\n';
constructor += '\t//*****************************************************************************************************\n';
constructor += '\tconstructor(public injector: Injector) {\n';
if(definedOptions.GET.all.enabled) {
constructor += '\t\tthis.getAll()\n';
}
constructor += '\t}\n';
var service = '';
if(definedOptions.GET.all.enabled) {
service += '\tprivate elementsCountSubject = new BehaviorSubject<number>(0);\n'
service += '\tprivate elementsSubject = new BehaviorSubject<' + currentModel + '_Model[]>([]);\n';
}
if(definedOptions.GET.single.enabled) {
service += '\tprivate elementSubject = new BehaviorSubject<' + currentModel + '_Model>(null);\n';
}
if(definedOptions.GET.all.enabled) {
service += '\tprivate _elementsCount: number = 0;\n';
service += '\tprivate _elements: ' + currentModel + '_Model[] = [];\n\n';
}
if(definedOptions.GET.single.enabled) {
service += '\tprivate _element: ' + currentModel + '_Model = null;\n\n';
}
if(definedOptions.GET.all.enabled) {
service += '\tpublic getElementsCount(): Observable<number> {\n';
service += '\t\treturn this.elementsCountSubject.asObservable();\n';
service += '\t}\n';
service += '\tpublic getElements(): Observable<' + currentModel + '_Model[]> {\n';
service += '\t\treturn this.elementsSubject.asObservable();\n';
service += '\t}\n\n';
}
if(definedOptions.GET.single.enabled) {
service += '\tpublic getElement(): Observable<' + currentModel + '_Model> {\n';
service += '\t\treturn this.elementSubject.asObservable();\n';
service += '\t}\n\n';
}
if(definedOptions.GET.all.enabled) {
service += '\tprivate refreshElementsCountSubject(newElementsCount: number) {\n';
service += '\t\tthis._elementsCount = newElementsCount;\n'
service += '\t\tthis.elementsCountSubject.next(newElementsCount);\n';
service += '\t}\n';
service += '\tprivate refreshElementsSubject(newValues: ' + currentModel + '_Model[]) {\n';
service += '\t\tthis._elements = newValues;\n'
service += '\t\tthis.elementsSubject.next(newValues);\n';
service += '\t}\n\n';
}
if(definedOptions.GET.single.enabled) {
service += '\tprivate refreshElementSubject(newValue: ' + currentModel + '_Model) {\n';
service += '\t\tthis._element = newValue;\n'
service += '\t\tthis.elementSubject.next(newValue);\n';
service += '\t}\n\n';
}
if(definedOptions.GET.all.enabled) {
generatedEndpoints.push('Get ' + tableName);
service += '\tpublic getAll(): Subscription {\n';
service += '\t\tconst EP_URL = Constants.API_URL + Constants.GET_' + tableName.toUpperCase() + '_EP;\n'
service += '\t\tconst http = this.injector.get(HttpClient);\n';
service += '\t\treturn http.get<CustomResponse<' + currentModel + '_Model[]>>(EP_URL, {})\n';
service += '\t\t\t.subscribe(\n';
service += '\t\t\t\tresponse => {\n';
service += '\t\t\t\t\tif(response && response.code === Constants.RESPONSE_OK) {\n';
service += '\t\t\t\t\t\tthis.refreshElementsSubject(response.data.map(currentElement => {return new ' + currentModel + '_Model(currentElement);}));\n';
service += '\t\t\t\t\t\tthis.refreshElementsCountSubject(response.data.length));\n';
service += '\t\t\t\t\t} else {\n';
service += '\t\t\t\t\t\tthis.refreshElementsSubject([]);\n';
service += '\t\t\t\t\t}\n';
service += '\t\t\t\t},\n';
service += '\t\t\t\terror => {\n';
service += '\t\t\t\t\tthis.refreshElementsSubject([]);\n';
service += '\t\t\t\t}\n';
service += '\t\t\t);\n';
service += '\t}\n\n';
}
if(definedOptions.GET.single.enabled) {
generatedEndpoints.push('Get ' + currentModel);
service += '\tpublic getOne(id: number): Subscription {\n';
service += '\t\tvar EP_URL = Constants.API_URL + Constants.GET_' + currentModel.toUpperCase() + '_EP;\n';
service += '\t\tEP_URL = EP_URL.replace(\':id\', \'\'+id);\n';
service += '\t\tconst http = this.injector.get(HttpClient);\n';
service += '\t\treturn http.get<CustomResponse<' + currentModel + '_Model>>(EP_URL, {})\n';
service += '\t\t\t.subscribe(\n';
service += '\t\t\t\tresponse => {\n';
service += '\t\t\t\t\tif(response && response.code === Constants.RESPONSE_OK) {\n';
service += '\t\t\t\t\t\tthis.refreshElementSubject(new ' + currentModel + '_Model(response.data));\n';
service += '\t\t\t\t\t} else {\n';
service += '\t\t\t\t\t\tthis.refreshElementSubject(null);\n';
service += '\t\t\t\t\t}\n';
service += '\t\t\t\t},\n';
service += '\t\t\t\terror => {\n';
service += '\t\t\t\t\tthis.refreshElementSubject(null);\n';
service += '\t\t\t\t}\n';
service += '\t\t\t);\n';
service += '\t}\n\n';
}
if(definedOptions.POST.single.enabled) {
generatedEndpoints.push('Create ' + currentModel);
service += '\tpublic addOne(newElement: ' + currentModel + '_Model, resultCallback) {\n';
service += '\t\tvar EP_URL = Constants.API_URL + Constants.CREATE_' + currentModel.toUpperCase() + '_EP;\n';
service += '\t\tconst formData: FormData = new FormData();\n'
service += '\t\tconst http = this.injector.get(HttpClient);\n';
service += '\t\treturn http.post<CustomResponse<' + currentModel + '_Model>>(EP_URL, formData)\n';
service += '\t\t\t.subscribe(\n';
service += '\t\t\t\tresponse => {\n';
service += '\t\t\t\t\tif(response && response.code === Constants.RESPONSE_OK) {\n';
service += '\t\t\t\t\t\tresultCallback(true, response.result);\n';
service += '\t\t\t\t\t} else {\n';
service += '\t\t\t\t\t\tresultCallback(false, null);\n';
service += '\t\t\t\t\t}\n';
service += '\t\t\t\t},\n';
service += '\t\t\t\terror => {\n';
service += '\t\t\t\t\tresultCallback(false, null);\n';
service += '\t\t\t\t}\n';
service += '\t\t\t);\n';
service += '\t}\n\n';
}
//*** TODO: Add POST, DELETE AND PUT METHODS
var serviceContent = baseFile.substring(0, start) +
includes + '\n' +
classDefinition + '\n' +
service + '\n' +
constructor + '\n' +
'}' +
baseFile.substring(end);
server.fileSystem.saveAbsoluteFile(
path.join(resultPath, fileName),
serviceContent
);
})
}
const generateCustomServices = function(baseFile, start, end, resultPath) {
/*server.debug('Generating custom endpoints');
server.endpointmanager.endpoints.forEach(currentEndpoint => {
var result = generatedEndpoints.find(currentName => currentName === currentEndpoint.configuration.name);
if(!result || result === null) {
server.debug(currentEndpoint.configuration.name);
}
});
server.debug('---------------------------');*/
}
const getMenuItems = function(baseFile, start, end, resultPath) {
server.debug('Generating menu items...');
var menuItems = '';
Object.keys(server.sequelize.options).forEach(currentModel => {
var modelOptions = server.sequelize.options[currentModel];
server.debug('Generating menu item', currentModel, modelOptions);
menuItems += '\t\t\t{label: \'' + currentModel + '\', icon: \'' + modelOptions.configuration.icon + '\', routerLink: [\'/' + currentModel + '\']},\n'
});
return menuItems;
}
const generateModels = function(baseFile, start, end, resultPath) {
//server.debug(server.sequelize.options);
Object.keys(server.sequelize.options).forEach(currentModel => {
//server.debug('Generating model', currentModel);
var momentImported = false;
var fileName = currentModel + '.ts';
var includes = '';
var classDefinition = '';
classDefinition += '//*****************************************************************************************************\n';
classDefinition += '//*** AUTOGENERATED CLASS DEFINITION ***\n';
classDefinition += '//*** DEVELOPED BY: Alberto Arconada ***\n';
classDefinition += '//*****************************************************************************************************\n';
classDefinition += 'export class ' + currentModel + '_Model {\n';
var constructor = '';
constructor += '\t//*****************************************************************************************************\n';
constructor += '\t//*** AUTOGENERATED CONSTRUCTOR ***\n';
constructor += '\t//*****************************************************************************************************\n';
constructor += '\tconstructor(json?:any) {\n';
constructor += '\t\tif(json) {\n';
constructor += '\t\t\tObject.assign(this, json);\n';
constructor += '\t\t}\n';
constructor += '\t}\n';
var fields = '';
var getterssetters = '';
//var modelOptions = server.sequelize.options[currentModel];
var definedModel = server.sequelize[currentModel];
Object.keys(definedModel.attributes).forEach(currentSchemaDefinition => {
var fieldAttribute = definedModel.attributes[currentSchemaDefinition];
var attibuteType = '' + fieldAttribute.type;
//server.debug(fieldAttribute.type, server.sequelize.api.INTEGER, fieldAttribute.type === server.sequelize.api.INTEGER);
var fieldType = 'string';
if (attibuteType === 'INTEGER') {
fieldType = 'number';
} else if (attibuteType === 'FLOAT' || attibuteType === 'REAL' || attibuteType === 'DOUBLE' || attibuteType === 'DECIMAL') {
fieldType = 'number';
} else if (attibuteType === 'DATETIME' || attibuteType === 'DATE' || attibuteType === 'TIME' || attibuteType === 'DATEONLY') {
if(!momentImported) {
momentImported = true;
includes += 'import * as moment from \'moment\';\n';
}
fieldType = 'string';
} else if (attibuteType === 'BOOLEAN') {
fieldType = 'boolean';
}
fields += '\t_' + currentSchemaDefinition + ': ' + fieldType + ';\n';
getterssetters += '\tget ' + currentSchemaDefinition + '(): ' + fieldType + '{\n';
getterssetters += '\t\t return this._' + currentSchemaDefinition + ';\n';
getterssetters += '\t}\n';
if (attibuteType === 'DATETIME' || attibuteType === 'DATE' || attibuteType === 'TIME' || attibuteType === 'DATEONLY') {
getterssetters += '\tget ' + currentSchemaDefinition + '_Parsed(): any {\n';
getterssetters += '\t\t return moment(this._' + currentSchemaDefinition + ', "YYYY-MM-DDTHH:mm:ss.SSSS");\n';
getterssetters += '\t}\n\n';
} else {
}
getterssetters += '\tset ' + currentSchemaDefinition + '(newValue: ' + fieldType + ') {\n';
getterssetters += '\t\t this._' + currentSchemaDefinition + ' = newValue;\n';
getterssetters += '\t}\n\n';
});
Object.keys(definedModel.associations).forEach(associationName => {
var currentAssociation = definedModel.associations[associationName];
var multiAssociation = currentAssociation.isMultiAssociation;
var target = currentAssociation.target.name;
server.debug(' ', associationName, multiAssociation);
includes += 'import {' + target + '_Model} from "./' + target + '";\n';
fields += '\t' + associationName + ': ' + target + '_Model';
if(multiAssociation) {
fields += '[]';
}
fields += ';\n';
});
if(!_.isEmpty(includes)) {
var comment = '';
comment += '//*****************************************************************************************************\n';
comment += '//*** AUTOGENERATED INCLUDES ***\n';
comment += '//*****************************************************************************************************\n';
includes = comment + includes;
}
if(!_.isEmpty(getterssetters)) {
var comment = '';
comment += '\t//*****************************************************************************************************\n';
comment += '\t//*** AUTOGENERATED GETTERS/SETTERS ***\n';
comment += '\t//*****************************************************************************************************\n';
getterssetters = comment + getterssetters;
}
if(!_.isEmpty(fields)) {
var comment = '';
comment += '\t//*****************************************************************************************************\n';
comment += '\t//*** AUTOGENERATED FIELDS ***\n';
comment += '\t//*****************************************************************************************************\n';
fields = comment + fields;
}
var modelContent = baseFile.substring(0, start) +
includes + '\n' +
classDefinition + '\n' +
fields + '\n' +
getterssetters + '\n' +
constructor + '\n' +
'}' +
baseFile.substring(end);
server.fileSystem.saveAbsoluteFile(
path.join(resultPath, fileName),
modelContent
);
})
}
const generateConstants = function(constantsFile, start, end) {
var serverConstants = '';
serverConstants += '//*****************************************************************************************************\n';
serverConstants += '//*** CONSTANTS GENERATED BY @AARCONADA/URSERVER ***\n';
serverConstants += '//*** DEVELOPED BY: Alberto Arconada ***\n';
serverConstants += '//*****************************************************************************************************\n\n';
const serverUrl = ((!_.isUndefined(server.configuration.useHTTPS) ? server.configuration.useHTTPS : false) ? 'https://' : 'http://') +
(!_.isUndefined(server.configuration.host) ? server.configuration.host : 'localhost');
serverConstants += '//*****************************************************************************************************\n';
serverConstants += '//*** GENERAL POURPOSES CONSTANT DEFINITIONS ***\n';
serverConstants += '//*****************************************************************************************************\n';
serverConstants += '\tpublic static readonly SERVERNAME = \'' + server.configuration.serverName + '\';\n';
serverConstants += '\tpublic static readonly RESOURCESFOLDER = \'' + server.configuration.resourcesFolder + '\';\n';
serverConstants += '\tpublic static readonly USEHTTPS = ' + server.configuration.useHTTPS + ';\n';
serverConstants += '\tpublic static readonly PORT = ' + server.configuration.port + ';\n';
serverConstants += '\tpublic static readonly HOST = \'' + server.configuration.host + '\';\n';
serverConstants += '\tpublic static readonly SERVER_URL = \'' + serverUrl + '\';\n';
serverConstants += '\tpublic static readonly BASEURL = \'' + server.configuration.baseUrl + '\';\n';
serverConstants += '\tpublic static readonly APIPREFFIXPATH = \'' + server.configuration.apiPreffixPath + '\';\n';
serverConstants += '\tpublic static readonly API_URL = Constants.BASEURL + Constants.APIPREFFIXPATH;\n'
serverConstants += '\tpublic static readonly USESOCKET = ' + server.configuration.socket.enabled + ';\n';
if(server.configuration.socket.enabled) {
serverConstants += '\tpublic static readonly SOCKETPORT = ' + server.configuration.socket.port + ';\n';
serverConstants += '\tpublic static readonly SOCKET_URL = Constants.SERVER_URL + \':\' + Constants.SOCKETPORT;\n';
}
serverConstants += '\tpublic static readonly RESPONSE_OK = \'' + server.defaultResponses.success.code + '\';\n';
serverConstants += '//*****************************************************************************************************\n';
serverConstants += '//*** ENDPOINT CONSTANT DEFINITIONS ***\n';
serverConstants += '//*****************************************************************************************************\n';
server.endpointmanager.endpoints.forEach(currentEndpoint => {
const endpointName = currentEndpoint.configuration.name.toUpperCase().split(' ').join('_') + '_EP';
serverConstants += '\tpublic static readonly ' + endpointName + ' '.repeat(50 - endpointName.length) + '= \'' + currentEndpoint.configuration.route + '\';\n';
})
serverConstants += '//*****************************************************************************************************\n';
serverConstants += '//*** END CONSTANT DEFINITIONS ***\n';
serverConstants += '//*****************************************************************************************************';
constantsFile = constantsFile.substring(0, start) +
serverConstants +
constantsFile.substring(end);
return constantsFile;
}
module.exports.generate = generate;
}