feature(database-connection): First implementation

This commit is contained in:
2021-01-08 17:15:50 +01:00
parent bce2c8964e
commit ceea2a7616
15 changed files with 276 additions and 181 deletions

View File

@@ -0,0 +1,3 @@
export interface Predicate<T, O> {
process(input: T): O;
}

13
backend/src/api/sort.ts Normal file
View File

@@ -0,0 +1,13 @@
export class Sort {
public static descending = (a: number, b: number) => {
if (a < b) {
return 1;
}
if (a > b) {
return -1;
}
return 0;
}
}

View File

@@ -0,0 +1,11 @@
export class TimeUtil {
public static humanize = (seconds: number) => {
const d = Math.floor(seconds / (3600 * 24));
const h = Math.floor(seconds % (3600 * 24) / 3600);
const m = Math.floor(seconds % 3600 / 60);
const s = Math.floor(seconds % 60);
return `${d}d ${h}h ${m}m ${s}s`;
}
}

View File

@@ -1,5 +1,7 @@
import { Controller, Get } from '@nestjs/common';
import { Controller, Get, HttpException, HttpStatus } from '@nestjs/common';
import { AppService } from './app.service';
import { DatabaseService } from './database/database.service';
import logger from './logger/Logger';
import { TableEntry } from "./models/TableEntry";
import { SinusBotService } from "./services/sinusbot.service";
@@ -7,7 +9,8 @@ import { SinusBotService } from "./services/sinusbot.service";
export class AppController {
constructor(
private readonly appService: AppService,
private readonly sinusBotService: SinusBotService
private readonly sinusBotService: SinusBotService,
private readonly databaseService: DatabaseService
) {}
@Get()
@@ -15,8 +18,21 @@ export class AppController {
return this.appService.getHello();
}
@Get('/stats')
async getStats(): Promise<TableEntry[]> {
@Get('/stats-old')
async getStatsOld(): Promise<TableEntry[]> {
return await this.sinusBotService.fetchStats();
}
@Get('/stats')
async getStats(): Promise<TableEntry[]> {
return this.databaseService.fetchStats()
.then(value => { return value; })
.catch(err => {
logger.error(`Error occured when fetching stats.`, err);
throw new HttpException(
'Error when fetching stats. Contact administrator or try again later!',
HttpStatus.INTERNAL_SERVER_ERROR
);
});
}
}

View File

@@ -2,10 +2,11 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { SinusBotService } from "./services/sinusbot.service";
import { DatabaseService } from './database/database.service';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService, SinusBotService],
providers: [AppService, SinusBotService, DatabaseService],
})
export class AppModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DatabaseService } from './database.service';
describe('DatabaseService', () => {
let service: DatabaseService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [DatabaseService],
}).compile();
service = module.get<DatabaseService>(DatabaseService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,35 @@
import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import logger from 'src/logger/Logger';
import { TableEntry } from 'src/models/TableEntry';
import { TimeTrackerPredicate } from './timetracking.predicate';
@Injectable()
export class DatabaseService {
// private host = process.env.MYSQL_HOST
// private port = process.env.MYSQL_PORT
// private credentials = {
// username: process.env.MYSQL_USERNAME,
// password: process.env.MYSQL_PASSWORD
// }
// private database = process.env.MYSQL_DATABASE
constructor(
private readonly prismaClient: PrismaClient,
private readonly timetrackerPredicate: TimeTrackerPredicate
) {}
public fetchStats(): Promise<TableEntry[]> {
return new Promise((resolve, reject) => {
this.prismaClient.timetracker.findMany({
include: {
user: true,
ranks: true
}
})
.then(this.timetrackerPredicate.process)
.then(result => resolve(result))
.catch(err => reject(err));
});
}
}

View File

@@ -0,0 +1,23 @@
import { ranks, seasons, timetracker, user } from "@prisma/client";
import { Predicate } from "src/api/predicate";
import { Sort } from "src/api/sort";
import { TimeUtil } from "src/api/timeutil";
import { TableEntry } from "src/models/TableEntry";
type UserStats = timetracker & { user: user, ranks: ranks; };
export class TimeTrackerPredicate implements Predicate<UserStats[], TableEntry[]> {
process(input: UserStats[]): TableEntry[] {
return input.filter((userStats: UserStats) => userStats.time != null)
.map((userStats: UserStats) => {
return {
name: userStats.user.name,
rawTime: userStats.time,
onlineTime: TimeUtil.humanize(userStats.time),
rank: userStats.ranks.rank_name
}
})
.sort((lhs, rhs) => Sort.descending(lhs.rawTime, rhs.rawTime));
}
}