added Serializer & Manager classes
This commit is contained in:
parent
d76110d06b
commit
2219ea93bf
24 changed files with 254 additions and 111 deletions
|
|
@ -2,23 +2,11 @@ import pgPromise from "pg-promise";
|
||||||
|
|
||||||
|
|
||||||
export abstract class Database {
|
export abstract class Database {
|
||||||
static db = null;
|
private static _db = null;
|
||||||
get db() {
|
static get db() {
|
||||||
if (Database.db == null) {
|
if (Database._db == null) {
|
||||||
Database.db = pgPromise({})('postgres://postgres:postgres@db:5432/rr')
|
Database._db = pgPromise({})('postgres://postgres:postgres@db:5432/rr')
|
||||||
}
|
}
|
||||||
return Database.db;
|
return Database._db;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async catcher(request): Promise<any> {
|
|
||||||
let data;
|
|
||||||
try {
|
|
||||||
data = await request();
|
|
||||||
} catch (e) {
|
|
||||||
console.log((e as Error).message)
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import {Database} from "./Database.js";
|
|
||||||
|
|
||||||
import helmet from "helmet";
|
import helmet from "helmet";
|
||||||
import bodyParser from "body-parser";
|
|
||||||
import morgan from 'morgan';
|
import morgan from 'morgan';
|
||||||
import {UserDataManager} from "./manager/UserDataManager.js";
|
import {leaderboardRoute} from "./leaderboardRoute.js";
|
||||||
import {UserDataPgPromiseSerializer} from "./manager/UserDataPgPromiseSerializer.js";
|
import {userRoute} from "./userRoute.js";
|
||||||
import {leaderboardRouter} from "./leaderboardRouter.js";
|
|
||||||
|
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
@ -18,31 +14,13 @@ app.use(helmet())
|
||||||
let morganFormatted = morgan('[:date[iso]] :method :url - :status')
|
let morganFormatted = morgan('[:date[iso]] :method :url - :status')
|
||||||
app.use(morganFormatted);
|
app.use(morganFormatted);
|
||||||
|
|
||||||
app.use('/leaderboard', leaderboardRouter)
|
app.use('/leaderboard', leaderboardRoute)
|
||||||
|
app.use('/user', userRoute)
|
||||||
|
|
||||||
app.get('/helloworld', (req, res) => {
|
app.get('/helloworld', (req, res) => {
|
||||||
res.json({message: "Hello World!"})
|
res.json({message: "Hello World!"})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/highscore', async (req, res) => {
|
|
||||||
let data = await Database.db.manyOrNone('SELECT * FROM lb_highscore;')
|
|
||||||
.catch((error) => console.log(error.message))
|
|
||||||
res.json(data)
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/user/:username', async (req, res) => {
|
|
||||||
let data = await Database.db.oneOrNone(
|
|
||||||
'SELECT * FROM user_data WHERE username = $1;',
|
|
||||||
[req.params.username])
|
|
||||||
.catch((error) => console.log(error.message)
|
|
||||||
)
|
|
||||||
let userDataManager: UserDataManager = new UserDataManager(data, new UserDataPgPromiseSerializer);
|
|
||||||
res.json(userDataManager.userData);
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server started at http://localhost:3000`);
|
console.log(`Server started at http://localhost:3000`);
|
||||||
|
|
|
||||||
23
backend/api/src/leaderboardRoute.ts
Normal file
23
backend/api/src/leaderboardRoute.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import express from 'express';
|
||||||
|
import {Database} from "./Database.js";
|
||||||
|
import {TimeLeaderboardManager} from "./manager/TimeLeaderboardManager.js";
|
||||||
|
import {HighscoreLeaderboardManager} from "./manager/HighscoreLeaderboardManager.js";
|
||||||
|
import {
|
||||||
|
HighscoreLeaderboardPgPromiseSerializer
|
||||||
|
} from "./serializer/pgpromise/HighscoreLeaderboardPgPromiseSerializer.js";
|
||||||
|
import {TimeLeaderboardPgPromiseSerializer} from "./serializer/pgpromise/TimeLeaderboardPgPromiseSerializer.js";
|
||||||
|
|
||||||
|
export const leaderboardRoute = express.Router()
|
||||||
|
|
||||||
|
|
||||||
|
leaderboardRoute.get('/highscore', async (req, res) => {
|
||||||
|
let data = await Database.db.manyOrNone('SELECT * FROM lb_highscore INNER JOIN "user" ON user_id = id ORDER BY RANK;')
|
||||||
|
const leaderboardManager = new HighscoreLeaderboardManager(data, new HighscoreLeaderboardPgPromiseSerializer);
|
||||||
|
res.send(leaderboardManager.content)
|
||||||
|
})
|
||||||
|
|
||||||
|
leaderboardRoute.get('/totalplaytime', async (req, res) => {
|
||||||
|
let data = await Database.db.manyOrNone('SELECT * FROM lb_total_playtime INNER JOIN "user" ON user_id = id ORDER BY RANK;')
|
||||||
|
const leaderboardManager = new TimeLeaderboardManager(data, new TimeLeaderboardPgPromiseSerializer);
|
||||||
|
res.send(leaderboardManager.content)
|
||||||
|
})
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import express from 'express';
|
|
||||||
export const leaderboardRouter = express.Router()
|
|
||||||
|
|
||||||
|
|
||||||
leaderboardRouter.get('/highscore', (req, res) => {
|
|
||||||
res.send('highscore')
|
|
||||||
})
|
|
||||||
|
|
||||||
leaderboardRouter.get('/totalplaytime', (req, res) => {
|
|
||||||
res.send('total play time')
|
|
||||||
})
|
|
||||||
32
backend/api/src/manager/HighscoreLeaderboardManager.ts
Normal file
32
backend/api/src/manager/HighscoreLeaderboardManager.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import {Leaderboard} from "../model/Leaderboard.js";
|
||||||
|
import {Manager} from "./Manager.js";
|
||||||
|
import {HighscoreLeaderboardSerializer} from "../serializer/HighscoreLeaderboardSerializer.js";
|
||||||
|
|
||||||
|
export class HighscoreLeaderboardManager implements Manager<Leaderboard<number>>{
|
||||||
|
private _content: Leaderboard<number>;
|
||||||
|
private _serializer: HighscoreLeaderboardSerializer;
|
||||||
|
|
||||||
|
constructor(rawData: any, serializer: HighscoreLeaderboardSerializer) {
|
||||||
|
this.serializer = serializer;
|
||||||
|
this._content = this.serializer.serialize(rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//region getter&setter
|
||||||
|
get content() {
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
|
||||||
|
set content(value: Leaderboard<number>) {
|
||||||
|
this._content = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get serializer() {
|
||||||
|
return this._serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
set serializer(value: HighscoreLeaderboardSerializer) {
|
||||||
|
this._serializer = value;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export interface LeaderBoardSerializer {
|
|
||||||
|
|
||||||
}
|
|
||||||
8
backend/api/src/manager/Manager.ts
Normal file
8
backend/api/src/manager/Manager.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import {Serializer} from "../serializer/Serializer.js";
|
||||||
|
|
||||||
|
export interface Manager<T> {
|
||||||
|
get content(),
|
||||||
|
set content(value: T),
|
||||||
|
get serializer(),
|
||||||
|
set serializer(value: Serializer<T>),
|
||||||
|
}
|
||||||
34
backend/api/src/manager/TimeLeaderboardManager.ts
Normal file
34
backend/api/src/manager/TimeLeaderboardManager.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import {Manager} from "./Manager.js";
|
||||||
|
import {Leaderboard} from "../model/Leaderboard.js";
|
||||||
|
import {Time} from "../model/Time.js";
|
||||||
|
import {TimeLeaderboardSerializer} from "../serializer/TimeLeaderboardSerializer.js";
|
||||||
|
import {TimeLeaderboardPgPromiseSerializer} from "../serializer/pgpromise/TimeLeaderboardPgPromiseSerializer.js";
|
||||||
|
|
||||||
|
export class TimeLeaderboardManager implements Manager<Leaderboard<Time>> {
|
||||||
|
private _content: Leaderboard<Time>;
|
||||||
|
private _serializer: TimeLeaderboardPgPromiseSerializer
|
||||||
|
|
||||||
|
constructor(data: any, serializer: TimeLeaderboardSerializer) {
|
||||||
|
this._serializer = serializer;
|
||||||
|
this._content = this._serializer.serialize(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//region getter&setter
|
||||||
|
get content() {
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
|
||||||
|
set content(value: Leaderboard<Time>) {
|
||||||
|
this._content = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get serializer(): TimeLeaderboardPgPromiseSerializer {
|
||||||
|
return this._serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
set serializer(value: TimeLeaderboardPgPromiseSerializer) {
|
||||||
|
this._serializer = value;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import {UserData} from "../model/UserData.js";
|
|
||||||
import {UserDataSerializer} from "./UserDataSerializer.js";
|
|
||||||
|
|
||||||
export class UserDataManager {
|
|
||||||
private _userData: UserData;
|
|
||||||
private serializer: UserDataSerializer;
|
|
||||||
|
|
||||||
constructor(data: any, serializer: UserDataSerializer) {
|
|
||||||
this.serializer = serializer;
|
|
||||||
this._userData = this.serializer.serialize(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
get userData(): UserData {
|
|
||||||
return this._userData;
|
|
||||||
}
|
|
||||||
|
|
||||||
set userData(value: UserData) {
|
|
||||||
this._userData = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import {UserData} from "../model/UserData.js";
|
|
||||||
import {UserDataSerializer} from "./UserDataSerializer.js";
|
|
||||||
|
|
||||||
export class UserDataPgPromiseSerializer implements UserDataSerializer {
|
|
||||||
deserialize(userData: UserData): any {
|
|
||||||
throw new Error("Method not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
serialize(data: any): UserData {
|
|
||||||
return {
|
|
||||||
username: data.username,
|
|
||||||
highscore: data.highscore,
|
|
||||||
totalScore: data.total_score,
|
|
||||||
totalPlaytime: data.total_playtime,
|
|
||||||
averageScore: data.averageScore,
|
|
||||||
gamesPlayed: data.games_played,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
import {UserData} from "../model/UserData.js";
|
|
||||||
|
|
||||||
export interface UserDataSerializer {
|
|
||||||
serialize(data: any): UserData,
|
|
||||||
deserialize(userData: UserData): any,
|
|
||||||
}
|
|
||||||
33
backend/api/src/manager/UserScoresManager.ts
Normal file
33
backend/api/src/manager/UserScoresManager.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import {UserScores} from "../model/UserScores.js";
|
||||||
|
import { Serializer } from "../serializer/Serializer.js";
|
||||||
|
import {UserScoresSerializer} from "../serializer/UserScoresSerializer.js";
|
||||||
|
import {Manager} from "./Manager.js";
|
||||||
|
|
||||||
|
export class UserScoresManager implements Manager<UserScores> {
|
||||||
|
private _content: UserScores;
|
||||||
|
private _serializer: UserScoresSerializer;
|
||||||
|
|
||||||
|
constructor(rawData: any, serializer: UserScoresSerializer) {
|
||||||
|
this.serializer = serializer;
|
||||||
|
this._content = this.serializer.serialize(rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//region getter&setter
|
||||||
|
get content() {
|
||||||
|
return this._content;
|
||||||
|
}
|
||||||
|
|
||||||
|
set content(value: UserScores) {
|
||||||
|
this._content = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get serializer() {
|
||||||
|
return this._serializer
|
||||||
|
}
|
||||||
|
|
||||||
|
set serializer(value: Serializer<UserScores>) {
|
||||||
|
this._serializer = value
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import {LeaderboardEntry} from "./LeaderboardEntry.js";
|
export type Leaderboard<T> = LeaderboardEntry<T>[];
|
||||||
|
|
||||||
export class Leaderboard<T> {
|
export interface LeaderboardEntry<T> {
|
||||||
content: LeaderboardEntry<T>[];
|
rank: number,
|
||||||
|
username: string,
|
||||||
|
score: T,
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export interface LeaderboardEntry<T> {
|
|
||||||
rank: number,
|
|
||||||
username: string,
|
|
||||||
score: T,
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export interface UserData {
|
export interface UserScores {
|
||||||
username: string,
|
username: string,
|
||||||
highscore: number,
|
highscore: number,
|
||||||
totalScore: number,
|
totalScore: number,
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import {Serializer} from "./Serializer.js";
|
||||||
|
import {Leaderboard} from "../model/Leaderboard.js";
|
||||||
|
|
||||||
|
export interface HighscoreLeaderboardSerializer extends Serializer<Leaderboard<number>> {}
|
||||||
4
backend/api/src/serializer/Serializer.ts
Normal file
4
backend/api/src/serializer/Serializer.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface Serializer<T> {
|
||||||
|
serialize(rawData: any): T,
|
||||||
|
deserialize(parsedData: T): any,
|
||||||
|
}
|
||||||
5
backend/api/src/serializer/TimeLeaderboardSerializer.ts
Normal file
5
backend/api/src/serializer/TimeLeaderboardSerializer.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {Serializer} from "./Serializer.js";
|
||||||
|
import {Leaderboard} from "../model/Leaderboard.js";
|
||||||
|
import {Time} from "../model/Time.js";
|
||||||
|
|
||||||
|
export interface TimeLeaderboardSerializer extends Serializer<Leaderboard<Time>> {}
|
||||||
4
backend/api/src/serializer/UserScoresSerializer.ts
Normal file
4
backend/api/src/serializer/UserScoresSerializer.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
import {UserScores} from "../model/UserScores.js";
|
||||||
|
import {Serializer} from "./Serializer.js";
|
||||||
|
|
||||||
|
export interface UserScoresSerializer extends Serializer<UserScores>{}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import {HighscoreLeaderboardSerializer} from "../HighscoreLeaderboardSerializer.js";
|
||||||
|
import {Leaderboard, LeaderboardEntry} from "../../model/Leaderboard.js";
|
||||||
|
|
||||||
|
export class HighscoreLeaderboardPgPromiseSerializer implements HighscoreLeaderboardSerializer {
|
||||||
|
deserialize(parsedData: Leaderboard<number>): any {
|
||||||
|
throw new Error("Method not implemented.")
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(rawData: any): Leaderboard<number> {
|
||||||
|
return rawData.map((item) => {
|
||||||
|
let newItem: LeaderboardEntry<number> = {
|
||||||
|
rank: item.rank,
|
||||||
|
username: item.name,
|
||||||
|
score: item.highscore,
|
||||||
|
}
|
||||||
|
return newItem
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import {TimeLeaderboardSerializer} from "../TimeLeaderboardSerializer.js";
|
||||||
|
import {Leaderboard, LeaderboardEntry} from "../../model/Leaderboard.js";
|
||||||
|
import {Time} from "../../model/Time.js";
|
||||||
|
|
||||||
|
export class TimeLeaderboardPgPromiseSerializer implements TimeLeaderboardSerializer {
|
||||||
|
deserialize(parsedData: Leaderboard<Time>): any {
|
||||||
|
throw new Error("Method not implemented.")
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(rawData: any): Leaderboard<Time> {
|
||||||
|
return rawData.map((item) => {
|
||||||
|
let newItem: LeaderboardEntry<Time> = {
|
||||||
|
rank: item.rank,
|
||||||
|
username: item.name,
|
||||||
|
score: item.total_playtime,
|
||||||
|
}
|
||||||
|
return newItem
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import {UserScores} from "../../model/UserScores.js";
|
||||||
|
import {UserScoresSerializer} from "../UserScoresSerializer.js";
|
||||||
|
|
||||||
|
export class UserScoresPgPromiseSerializer implements UserScoresSerializer {
|
||||||
|
deserialize(parsedData: UserScores): any {
|
||||||
|
throw new Error("Method not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(rawData: any): UserScores {
|
||||||
|
return {
|
||||||
|
username: rawData.name,
|
||||||
|
highscore: rawData.highscore,
|
||||||
|
totalScore: rawData.total_score,
|
||||||
|
totalPlaytime: rawData.total_playtime,
|
||||||
|
averageScore: rawData.averageScore,
|
||||||
|
gamesPlayed: rawData.games_played,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
backend/api/src/userRoute.ts
Normal file
30
backend/api/src/userRoute.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import express from "express";
|
||||||
|
import {Database} from "./Database.js";
|
||||||
|
import {UserScoresManager} from "./manager/UserScoresManager.js";
|
||||||
|
import {UserScoresPgPromiseSerializer} from "./serializer/pgpromise/UserScoresPgPromiseSerializer.js";
|
||||||
|
import bodyParser from "body-parser";
|
||||||
|
|
||||||
|
export const userRoute = express.Router()
|
||||||
|
|
||||||
|
userRoute.use(bodyParser.json)
|
||||||
|
|
||||||
|
userRoute.get('/:username/scores', async (req, res) => {
|
||||||
|
let data = await Database.db.oneOrNone(
|
||||||
|
'SELECT * FROM user_scores INNER JOIN "user" ON user_scores.user_id = "user".id WHERE "user".name = $1;',
|
||||||
|
[req.params.username])
|
||||||
|
.catch((error) => console.log(error.message)
|
||||||
|
)
|
||||||
|
let userDataManager: UserScoresManager = new UserScoresManager(data, new UserScoresPgPromiseSerializer);
|
||||||
|
res.json(userDataManager.content);
|
||||||
|
})
|
||||||
|
|
||||||
|
userRoute.post('/register', async (req, res) => {
|
||||||
|
if (req.body.name == undefined) {
|
||||||
|
res.status(400).send("'name' was not defined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await Database.db.none(
|
||||||
|
'INSERT INTO "user" (name) VALUES ($1);', [req.body.name]
|
||||||
|
);
|
||||||
|
res.status(200).send();
|
||||||
|
})
|
||||||
|
|
@ -15,6 +15,8 @@ services:
|
||||||
|
|
||||||
api:
|
api:
|
||||||
build: backend/api
|
build: backend/api
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
container_name: express-api
|
container_name: express-api
|
||||||
ports:
|
ports:
|
||||||
- "${EXPRESS_PORT}:3000"
|
- "${EXPRESS_PORT}:3000"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue