introduce a performance backend
This commit is contained in:
		
							
								
								
									
										4467
									
								
								config/performance.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4467
									
								
								config/performance.yaml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										595
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										595
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -26,6 +26,9 @@ | |||||||
|     "@nestjs/core": "^9.0.0", |     "@nestjs/core": "^9.0.0", | ||||||
|     "@nestjs/mongoose": "^9.2.0", |     "@nestjs/mongoose": "^9.2.0", | ||||||
|     "@nestjs/platform-express": "^9.0.0", |     "@nestjs/platform-express": "^9.0.0", | ||||||
|  |     "@nestjs/swagger": "^6.1.2", | ||||||
|  |     "class-transformer": "^0.5.1", | ||||||
|  |     "class-validator": "^0.13.2", | ||||||
|     "helmet": "^6.0.0", |     "helmet": "^6.0.0", | ||||||
|     "js-yaml": "^4.1.0", |     "js-yaml": "^4.1.0", | ||||||
|     "mongoose": "^6.6.7", |     "mongoose": "^6.6.7", | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ import { Module } from '@nestjs/common'; | |||||||
| import { ConfigModule, ConfigService } from '@nestjs/config'; | import { ConfigModule, ConfigService } from '@nestjs/config'; | ||||||
| import { MongooseModule } from '@nestjs/mongoose'; | import { MongooseModule } from '@nestjs/mongoose'; | ||||||
| import Configuration from './config/configuration'; | import Configuration from './config/configuration'; | ||||||
|  | import { VersioningModule } from './versioning/versioning.module'; | ||||||
|  | import { PerformanceModule } from './performance/performance.module'; | ||||||
|  |  | ||||||
| @Module({ | @Module({ | ||||||
|   imports: [ |   imports: [ | ||||||
| @@ -20,8 +22,8 @@ import Configuration from './config/configuration'; | |||||||
|         )}`, |         )}`, | ||||||
|       }), |       }), | ||||||
|     }), |     }), | ||||||
|  |     VersioningModule, | ||||||
|  |     PerformanceModule, | ||||||
|   ], |   ], | ||||||
|   controllers: [], |  | ||||||
|   providers: [], |  | ||||||
| }) | }) | ||||||
| export class AppModule {} | export class AppModule {} | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								src/performance/models/performance.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/performance/models/performance.model.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | ||||||
|  | import { Document } from 'mongoose'; | ||||||
|  | import { PerformanceEntry } from './performanceentry.model'; | ||||||
|  |  | ||||||
|  | export type PerformanceDocument = Performance & Document; | ||||||
|  |  | ||||||
|  | @Schema() | ||||||
|  | export class Performance { | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   icaoCode: string; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true, type: PerformanceEntry }) | ||||||
|  |   aboveFL240: PerformanceEntry; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true, type: PerformanceEntry }) | ||||||
|  |   aboveFL100: PerformanceEntry; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true, type: PerformanceEntry }) | ||||||
|  |   belowFL100: PerformanceEntry; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   minimalApproachSpeed: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const PerformanceSchema = SchemaFactory.createForClass(Performance); | ||||||
							
								
								
									
										16
									
								
								src/performance/models/performanceentry.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/performance/models/performanceentry.model.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | ||||||
|  | import { Document } from 'mongoose'; | ||||||
|  |  | ||||||
|  | export type PerformanceEntryDocument = PerformanceEntry & Document; | ||||||
|  |  | ||||||
|  | @Schema() | ||||||
|  | export class PerformanceEntry { | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   speed: number; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   rateOfDescend: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const PerformanceEntrySchema = | ||||||
|  |   SchemaFactory.createForClass(PerformanceEntry); | ||||||
							
								
								
									
										17
									
								
								src/performance/performance.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/performance/performance.module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | import { Module } from '@nestjs/common'; | ||||||
|  | import { MongooseModule } from '@nestjs/mongoose'; | ||||||
|  | import { PerformanceSchema } from './models/performance.model'; | ||||||
|  | import { PerformanceService } from './performance.service'; | ||||||
|  | import { VersioningModule } from '../versioning/versioning.module'; | ||||||
|  |  | ||||||
|  | @Module({ | ||||||
|  |   imports: [ | ||||||
|  |     MongooseModule.forFeature([ | ||||||
|  |       { name: 'performance', schema: PerformanceSchema }, | ||||||
|  |     ]), | ||||||
|  |     VersioningModule, | ||||||
|  |   ], | ||||||
|  |   providers: [PerformanceService], | ||||||
|  |   exports: [MongooseModule, PerformanceService], | ||||||
|  | }) | ||||||
|  | export class PerformanceModule {} | ||||||
							
								
								
									
										18
									
								
								src/performance/performance.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/performance/performance.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import { Test, TestingModule } from '@nestjs/testing'; | ||||||
|  | import { PerformanceService } from './performance.service'; | ||||||
|  |  | ||||||
|  | describe('PerformanceService', () => { | ||||||
|  |   let service: PerformanceService; | ||||||
|  |  | ||||||
|  |   beforeEach(async () => { | ||||||
|  |     const module: TestingModule = await Test.createTestingModule({ | ||||||
|  |       providers: [PerformanceService], | ||||||
|  |     }).compile(); | ||||||
|  |  | ||||||
|  |     service = module.get<PerformanceService>(PerformanceService); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should be defined', () => { | ||||||
|  |     expect(service).toBeDefined(); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										99
									
								
								src/performance/performance.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/performance/performance.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | import { Injectable } from '@nestjs/common'; | ||||||
|  | import { InjectModel } from '@nestjs/mongoose'; | ||||||
|  | import { readFileSync } from 'fs'; | ||||||
|  | import * as yaml from 'js-yaml'; | ||||||
|  | import { Model } from 'mongoose'; | ||||||
|  | import { join } from 'path'; | ||||||
|  | import { SemanticVersionDto } from 'src/versioning/dto/semanticversion.dto'; | ||||||
|  | import { VersioningService } from '../versioning/versioning.service'; | ||||||
|  | import { PerformanceDocument } from './models/performance.model'; | ||||||
|  |  | ||||||
|  | const COMPONENT_NAME = 'performance'; | ||||||
|  |  | ||||||
|  | @Injectable() | ||||||
|  | export class PerformanceService { | ||||||
|  |   private static readPerformanceFile(): Record<string, any> { | ||||||
|  |     return yaml.load( | ||||||
|  |       readFileSync(join(process.cwd(), 'config/performance.yaml'), 'utf8'), | ||||||
|  |     ) as Record<string, any>; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private async updatePerformanceData( | ||||||
|  |     performanceData: Record<string, any>, | ||||||
|  |     version: SemanticVersionDto, | ||||||
|  |   ): Promise<boolean> { | ||||||
|  |     return this.performanceModel.deleteMany({}).then(async () => { | ||||||
|  |       for (const key in performanceData) { | ||||||
|  |         if (key !== 'FILEINFO') { | ||||||
|  |           await this.performanceModel.create({ | ||||||
|  |             icaoCode: key, | ||||||
|  |             aboveFL240: { | ||||||
|  |               speed: performanceData[key]['speedabovefl240'], | ||||||
|  |               rateOfDescend: performanceData[key]['rodabovefl240'], | ||||||
|  |             }, | ||||||
|  |             aboveFL100: { | ||||||
|  |               speed: performanceData[key]['speedabovefl100'], | ||||||
|  |               rateOfDescend: performanceData[key]['rodabovefl100'], | ||||||
|  |             }, | ||||||
|  |             belowFL100: { | ||||||
|  |               speed: performanceData[key]['speedbelowfl100'], | ||||||
|  |               rateOfDescend: performanceData[key]['rodbelowfl100'], | ||||||
|  |             }, | ||||||
|  |             minimalApproachSpeed: performanceData[key]['speedapproach'], | ||||||
|  |           }); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       await this.versioningService.updateComponent( | ||||||
|  |         COMPONENT_NAME, | ||||||
|  |         performanceData['FILEINFO']['createdAt'], | ||||||
|  |         version, | ||||||
|  |       ); | ||||||
|  |  | ||||||
|  |       return true; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private async validateAndUpdatePerformanceData(): Promise<boolean> { | ||||||
|  |     // read the performance file and validate the version length | ||||||
|  |     const data = PerformanceService.readPerformanceFile(); | ||||||
|  |     const versionParts = (data['FILEINFO']['version'] as string).split('.'); | ||||||
|  |     if (versionParts.length !== 3) return false; | ||||||
|  |  | ||||||
|  |     // create the fileversion | ||||||
|  |     const fileversion: SemanticVersionDto = { | ||||||
|  |       main: parseInt(versionParts[0]), | ||||||
|  |       major: parseInt(versionParts[1]), | ||||||
|  |       minor: parseInt(versionParts[2]), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return this.versioningService | ||||||
|  |       .findComponent(COMPONENT_NAME) | ||||||
|  |       .then((resp) => { | ||||||
|  |         if ( | ||||||
|  |           resp === null || | ||||||
|  |           VersioningService.newerVersion( | ||||||
|  |             { | ||||||
|  |               main: resp.versionMain, | ||||||
|  |               major: resp.versionMajor, | ||||||
|  |               minor: resp.versionMinor, | ||||||
|  |             }, | ||||||
|  |             fileversion, | ||||||
|  |           ) | ||||||
|  |         ) { | ||||||
|  |           return this.updatePerformanceData(data, fileversion); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |       }) | ||||||
|  |       .catch(() => this.updatePerformanceData(data, fileversion)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   constructor( | ||||||
|  |     @InjectModel(COMPONENT_NAME) | ||||||
|  |     private readonly performanceModel: Model<PerformanceDocument>, | ||||||
|  |     private readonly versioningService: VersioningService, | ||||||
|  |   ) { | ||||||
|  |     this.validateAndUpdatePerformanceData(); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								src/versioning/dto/semanticversion.dto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/versioning/dto/semanticversion.dto.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | import { IsNotEmpty } from 'class-validator'; | ||||||
|  | import { ApiProperty } from '@nestjs/swagger'; | ||||||
|  |  | ||||||
|  | export class SemanticVersionDto { | ||||||
|  |   @IsNotEmpty() | ||||||
|  |   @ApiProperty({ | ||||||
|  |     description: 'The main version to describe downwards compatibility issues', | ||||||
|  |     example: 1, | ||||||
|  |   }) | ||||||
|  |   main: number; | ||||||
|  |  | ||||||
|  |   @IsNotEmpty() | ||||||
|  |   @ApiProperty({ | ||||||
|  |     description: 'The major version to describe upwards compatibility issues', | ||||||
|  |     example: 1, | ||||||
|  |   }) | ||||||
|  |   major: number; | ||||||
|  |  | ||||||
|  |   @IsNotEmpty() | ||||||
|  |   @ApiProperty({ | ||||||
|  |     description: 'The minor version to describe API stable changes', | ||||||
|  |     example: 1, | ||||||
|  |   }) | ||||||
|  |   minor: number; | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/versioning/versioning.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/versioning/versioning.model.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | ||||||
|  | import { Document } from 'mongoose'; | ||||||
|  |  | ||||||
|  | export type VersioningDocument = Versioning & Document; | ||||||
|  |  | ||||||
|  | @Schema() | ||||||
|  | export class Versioning { | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   componentName: string; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   createdAt: string; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   versionMain: number; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   versionMajor: number; | ||||||
|  |  | ||||||
|  |   @Prop({ required: true }) | ||||||
|  |   versionMinor: number; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export const VersioningSchema = SchemaFactory.createForClass(Versioning); | ||||||
							
								
								
									
										15
									
								
								src/versioning/versioning.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/versioning/versioning.module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | import { Module } from '@nestjs/common'; | ||||||
|  | import { MongooseModule } from '@nestjs/mongoose'; | ||||||
|  | import { VersioningSchema } from './versioning.model'; | ||||||
|  | import { VersioningService } from './versioning.service'; | ||||||
|  |  | ||||||
|  | @Module({ | ||||||
|  |   imports: [ | ||||||
|  |     MongooseModule.forFeature([ | ||||||
|  |       { name: 'versioning', schema: VersioningSchema }, | ||||||
|  |     ]), | ||||||
|  |   ], | ||||||
|  |   providers: [VersioningService], | ||||||
|  |   exports: [MongooseModule, VersioningService], | ||||||
|  | }) | ||||||
|  | export class VersioningModule {} | ||||||
							
								
								
									
										18
									
								
								src/versioning/versioning.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/versioning/versioning.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | import { Test, TestingModule } from '@nestjs/testing'; | ||||||
|  | import { VersioningService } from './versioning.service'; | ||||||
|  |  | ||||||
|  | describe('VersioningService', () => { | ||||||
|  |   let service: VersioningService; | ||||||
|  |  | ||||||
|  |   beforeEach(async () => { | ||||||
|  |     const module: TestingModule = await Test.createTestingModule({ | ||||||
|  |       providers: [VersioningService], | ||||||
|  |     }).compile(); | ||||||
|  |  | ||||||
|  |     service = module.get<VersioningService>(VersioningService); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   it('should be defined', () => { | ||||||
|  |     expect(service).toBeDefined(); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
							
								
								
									
										51
									
								
								src/versioning/versioning.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/versioning/versioning.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | |||||||
|  | import { Injectable } from '@nestjs/common'; | ||||||
|  | import { InjectModel } from '@nestjs/mongoose'; | ||||||
|  | import { Model } from 'mongoose'; | ||||||
|  | import { SemanticVersionDto } from './dto/semanticversion.dto'; | ||||||
|  | import { Versioning, VersioningDocument } from './versioning.model'; | ||||||
|  |  | ||||||
|  | @Injectable() | ||||||
|  | export class VersioningService { | ||||||
|  |   constructor( | ||||||
|  |     @InjectModel('versioning') | ||||||
|  |     private readonly versioningModel: Model<VersioningDocument>, | ||||||
|  |   ) {} | ||||||
|  |  | ||||||
|  |   async findComponent(name: string): Promise<Versioning> { | ||||||
|  |     return this.versioningModel.findOne({ componentName: name }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async updateComponent( | ||||||
|  |     name: string, | ||||||
|  |     createdAt: string, | ||||||
|  |     version: SemanticVersionDto, | ||||||
|  |   ): Promise<void> { | ||||||
|  |     return this.versioningModel.deleteOne({ componentName: name }).then(() => { | ||||||
|  |       this.versioningModel.create({ | ||||||
|  |         componentName: name, | ||||||
|  |         createdAt, | ||||||
|  |         versionMain: version.main, | ||||||
|  |         versionMajor: version.major, | ||||||
|  |         versionMinor: version.minor, | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static newerVersion( | ||||||
|  |     reference: SemanticVersionDto, | ||||||
|  |     version: SemanticVersionDto, | ||||||
|  |   ): boolean { | ||||||
|  |     // check special cases for the main part | ||||||
|  |     if (reference.main < version.main) return true; | ||||||
|  |     if (reference.main > version.main) return false; | ||||||
|  |  | ||||||
|  |     // main versions are equal | ||||||
|  |     // check the special cases for the major part | ||||||
|  |     if (reference.major < version.major) return true; | ||||||
|  |     if (reference.major > version.major) return false; | ||||||
|  |  | ||||||
|  |     // major versions are equal | ||||||
|  |     // check if the minor versions increased | ||||||
|  |     return reference.minor < version.minor; | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user