UNPKG

@aarconada/urserver

Version:

Basic Server definitions to develope REST API with a node + express Server

512 lines (453 loc) 30.4 kB
/** * 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; }