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