Skip to content

Commit 400cc34

Browse files
committed
refactor(be)data structure
rename stops to platforms add stops as a parent for platforms update import script update prisma schema
1 parent 5ca536c commit 400cc34

File tree

19 files changed

+681
-341
lines changed

19 files changed

+681
-341
lines changed

backend-nest/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"prisma:generate": "pnpm dlx prisma generate",
2020
"prisma:migrate": "pnpm dlx dotenv-cli -e .env.local -- pnpm dlx prisma migrate dev",
2121
"prisma:push": "pnpm dlx dotenv-cli -e .env.local -- pnpm dlx prisma db push",
22-
"db:start":"docker compose -f compose.postgres.yaml up"
22+
"db:start": "docker compose -f compose.postgres.yaml up"
2323
},
2424
"dependencies": {
2525
"@nestjs/cache-manager": "^2.2.2",
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
Warnings:
3+
4+
- You are about to drop the `Stop` table. If the table is not empty, all the data it contains will be lost.
5+
- You are about to drop the `StopsOnRoutes` table. If the table is not empty, all the data it contains will be lost.
6+
7+
*/
8+
-- DropForeignKey
9+
ALTER TABLE "StopsOnRoutes" DROP CONSTRAINT "StopsOnRoutes_routeId_fkey";
10+
11+
-- DropForeignKey
12+
ALTER TABLE "StopsOnRoutes" DROP CONSTRAINT "StopsOnRoutes_stopId_fkey";
13+
14+
-- DropTable
15+
DROP TABLE "Stop";
16+
17+
-- DropTable
18+
DROP TABLE "StopsOnRoutes";
19+
20+
-- CreateTable
21+
CREATE TABLE "Platform" (
22+
"id" TEXT NOT NULL,
23+
"name" TEXT NOT NULL,
24+
"isMetro" BOOLEAN NOT NULL,
25+
"latitude" DOUBLE PRECISION NOT NULL,
26+
"longitude" DOUBLE PRECISION NOT NULL,
27+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
28+
"updatedAt" TIMESTAMP(3) NOT NULL,
29+
30+
CONSTRAINT "Platform_pkey" PRIMARY KEY ("id")
31+
);
32+
33+
-- CreateTable
34+
CREATE TABLE "PlatformsOnRoutes" (
35+
"stopId" TEXT NOT NULL,
36+
"routeId" TEXT NOT NULL,
37+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
38+
"updatedAt" TIMESTAMP(3) NOT NULL,
39+
40+
CONSTRAINT "PlatformsOnRoutes_pkey" PRIMARY KEY ("stopId","routeId")
41+
);
42+
43+
-- CreateIndex
44+
CREATE INDEX "Platform_name_idx" ON "Platform"("name");
45+
46+
-- CreateIndex
47+
CREATE INDEX "Platform_latitude_idx" ON "Platform"("latitude");
48+
49+
-- CreateIndex
50+
CREATE INDEX "Platform_longitude_idx" ON "Platform"("longitude");
51+
52+
-- CreateIndex
53+
CREATE INDEX "Platform_latitude_longitude_idx" ON "Platform"("latitude", "longitude");
54+
55+
-- AddForeignKey
56+
ALTER TABLE "PlatformsOnRoutes" ADD CONSTRAINT "PlatformsOnRoutes_stopId_fkey" FOREIGN KEY ("stopId") REFERENCES "Platform"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
57+
58+
-- AddForeignKey
59+
ALTER TABLE "PlatformsOnRoutes" ADD CONSTRAINT "PlatformsOnRoutes_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- DropIndex
2+
DROP INDEX "Platform_latitude_idx";
3+
4+
-- DropIndex
5+
DROP INDEX "Platform_latitude_longitude_idx";
6+
7+
-- DropIndex
8+
DROP INDEX "Platform_longitude_idx";
9+
10+
-- DropIndex
11+
DROP INDEX "Platform_name_idx";
12+
13+
-- DropIndex
14+
DROP INDEX "Route_name_idx";
15+
16+
-- AlterTable
17+
ALTER TABLE "Platform" ADD COLUMN "stopId" TEXT;
18+
19+
-- CreateTable
20+
CREATE TABLE "Stop" (
21+
"id" TEXT NOT NULL,
22+
"name" TEXT NOT NULL,
23+
"avgLatitude" DOUBLE PRECISION NOT NULL,
24+
"avgLongitude" DOUBLE PRECISION NOT NULL,
25+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
26+
"updatedAt" TIMESTAMP(3) NOT NULL,
27+
28+
CONSTRAINT "Stop_pkey" PRIMARY KEY ("id")
29+
);
30+
31+
-- AddForeignKey
32+
ALTER TABLE "Platform" ADD CONSTRAINT "Platform_stopId_fkey" FOREIGN KEY ("stopId") REFERENCES "Stop"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
Warnings:
3+
4+
- The primary key for the `PlatformsOnRoutes` table will be changed. If it partially fails, the table could be left without primary key constraint.
5+
- You are about to drop the column `stopId` on the `PlatformsOnRoutes` table. All the data in the column will be lost.
6+
- A unique constraint covering the columns `[platformId,routeId]` on the table `PlatformsOnRoutes` will be added. If there are existing duplicate values, this will fail.
7+
- Added the required column `platformId` to the `PlatformsOnRoutes` table without a default value. This is not possible if the table is not empty.
8+
9+
*/
10+
-- DropForeignKey
11+
ALTER TABLE "PlatformsOnRoutes" DROP CONSTRAINT "PlatformsOnRoutes_stopId_fkey";
12+
13+
-- AlterTable
14+
ALTER TABLE "PlatformsOnRoutes" DROP CONSTRAINT "PlatformsOnRoutes_pkey",
15+
DROP COLUMN "stopId",
16+
ADD COLUMN "platformId" TEXT NOT NULL;
17+
18+
-- CreateIndex
19+
CREATE UNIQUE INDEX "PlatformsOnRoutes_platformId_routeId_key" ON "PlatformsOnRoutes"("platformId", "routeId");
20+
21+
-- AddForeignKey
22+
ALTER TABLE "PlatformsOnRoutes" ADD CONSTRAINT "PlatformsOnRoutes_platformId_fkey" FOREIGN KEY ("platformId") REFERENCES "Platform"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

backend-nest/prisma/schema.prisma

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,20 @@ datasource db {
1414
}
1515

1616
model Stop {
17-
id String @id @map("id")
17+
id String @id
18+
name String
19+
20+
avgLatitude Float
21+
avgLongitude Float
22+
23+
createdAt DateTime @default(now())
24+
updatedAt DateTime @updatedAt
25+
26+
platforms Platform[]
27+
}
28+
29+
model Platform {
30+
id String @id
1831
name String
1932
isMetro Boolean
2033
@@ -24,39 +37,37 @@ model Stop {
2437
createdAt DateTime @default(now())
2538
updatedAt DateTime @updatedAt
2639
27-
routes StopsOnRoutes[]
40+
routes PlatformsOnRoutes[]
2841
29-
@@index([name])
30-
@@index([latitude])
31-
@@index([longitude])
32-
@@index([latitude, longitude])
42+
stop Stop? @relation(fields: [stopId], references: [id])
43+
stopId String?
3344
}
3445

3546
model Route {
36-
id String @id @map("id")
37-
name String
47+
id String @id
48+
name String
49+
3850
vehicleType VehicleType?
3951
isNight Boolean?
4052
4153
createdAt DateTime @default(now())
4254
updatedAt DateTime @updatedAt
4355
44-
stops StopsOnRoutes[]
45-
46-
@@index([name])
56+
stops PlatformsOnRoutes[]
4757
}
4858

49-
model StopsOnRoutes {
50-
stop Stop @relation(fields: [stopId], references: [id])
51-
stopId String
59+
model PlatformsOnRoutes {
60+
id String @id @default(uuid())
61+
platform Platform @relation(fields: [platformId], references: [id])
62+
platformId String
5263
5364
route Route @relation(fields: [routeId], references: [id])
5465
routeId String
5566
5667
createdAt DateTime @default(now())
5768
updatedAt DateTime @updatedAt
5869
59-
@@id([stopId, routeId])
70+
@@unique([platformId, routeId])
6071
}
6172

6273
enum VehicleType {

backend-nest/src/app.module.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import { ConfigModule } from "@nestjs/config";
66
import { TTL_DEFAULT } from "./constants/constants";
77
import { ScheduleModule } from "@nestjs/schedule";
88
import { PrismaService } from "./database/prisma.service";
9-
import { StopController } from "./modules/stop/stop.controller";
9+
import { PlatformController } from "./modules/platform/platform.controller";
1010
import { APP_INTERCEPTOR } from "@nestjs/core";
11-
import { StopService } from "./modules/stop/stop.service";
11+
import { PlatformService } from "./modules/platform/platform.service";
1212
import { DepartureController } from "./modules/departure/departure.controller";
1313
import { DepartureService } from "./modules/departure/departure.service";
14+
import { StopService } from "./modules/stop/stop.service";
15+
import { StopController } from "./modules/stop/stop.controller";
1416

1517
@Module({
1618
imports: [
@@ -21,12 +23,18 @@ import { DepartureService } from "./modules/departure/departure.service";
2123
ttl: TTL_DEFAULT,
2224
}),
2325
],
24-
controllers: [AppController, StopController, DepartureController],
26+
controllers: [
27+
AppController,
28+
PlatformController,
29+
DepartureController,
30+
StopController,
31+
],
2532
providers: [
2633
AppService,
2734
PrismaService,
28-
StopService,
35+
PlatformService,
2936
DepartureService,
37+
StopService,
3038
{
3139
provide: APP_INTERCEPTOR,
3240
useClass: CacheInterceptor,

backend-nest/src/enums/metro.enum.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { z } from "zod";
2+
3+
const METRO_LINES = ["A", "B", "C"] as const;
4+
5+
export const metroLine = z.enum(METRO_LINES);

backend-nest/src/modules/departure/departure.controller.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { Controller, Get, HttpException, Query } from "@nestjs/common";
1+
import {
2+
Controller,
3+
Get,
4+
HttpException,
5+
HttpStatus,
6+
Query,
7+
} from "@nestjs/common";
28
import { PrismaService } from "../../database/prisma.service";
39
import { DepartureService } from "./departure.service";
410
import { toArray } from "src/utils/array.utils";
@@ -15,15 +21,16 @@ export class DepartureController {
1521
private readonly departureService: DepartureService,
1622
) {}
1723

18-
@Get("/platform")
19-
async getDeparturesByPlatform(
20-
@Query("platform") platform,
21-
): Promise<DepartureSchema[]> {
24+
@Get("/stop")
25+
async getDeparturesByPlatform(@Query("id") id): Promise<DepartureSchema[]> {
2226
const platformSchema = z.string().array().min(1).max(20);
23-
const parsed = platformSchema.safeParse(toArray(platform));
27+
const parsed = platformSchema.safeParse(toArray(id));
2428

2529
if (!parsed.success) {
26-
throw new HttpException("Invalid query params", 400);
30+
throw new HttpException(
31+
"Invalid query params",
32+
HttpStatus.BAD_REQUEST,
33+
);
2734
}
2835

2936
const departures = await this.departureService.getDeparturesByPlatform(
Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,56 @@
1-
import { Injectable } from "@nestjs/common";
1+
import { HttpException, HttpStatus, Inject, Injectable } from "@nestjs/common";
22
import { GOLEMIO_API } from "src/constants";
33
import type { DepartureSchema } from "./schema/departure.schema";
44
import { departureBoardsSchema } from "./schema/departure-boards.schema";
55
import { getDelayInSeconds } from "src/utils/delay";
6+
import { PrismaService } from "src/database/prisma.service";
7+
import { CACHE_MANAGER } from "@nestjs/cache-manager";
68

79
@Injectable()
810
export class DepartureService {
9-
constructor() {}
11+
constructor(
12+
private prisma: PrismaService,
13+
@Inject(CACHE_MANAGER) private cacheManager,
14+
) {}
1015

1116
async getDeparturesByPlatform(
12-
platforms: string[],
17+
requestedIds: string[],
1318
): Promise<DepartureSchema[]> {
14-
const url = new URL("/v2/pid/departureboards", GOLEMIO_API);
15-
url.searchParams.append("order", "real");
16-
platforms.forEach((id) => {
17-
url.searchParams.append("ids[]", id);
19+
const databasePlatforms = await this.prisma.platform.findMany({
20+
select: {
21+
id: true,
22+
},
23+
where: {
24+
id: {
25+
in: requestedIds,
26+
},
27+
},
1828
});
29+
const databaseIDs = databasePlatforms.map((platform) => platform.id);
30+
const allIdsInDb = requestedIds.every((requestedID) =>
31+
databaseIDs.includes(requestedID),
32+
);
33+
34+
if (!allIdsInDb) {
35+
throw new HttpException(
36+
"Invalid query params",
37+
HttpStatus.BAD_REQUEST,
38+
);
39+
}
40+
41+
const searchParams = new URLSearchParams(
42+
requestedIds
43+
.map((id) => ["ids", id])
44+
.concat([
45+
["skip", "canceled"],
46+
["mode", "departures"],
47+
["order", "real"],
48+
]),
49+
);
50+
51+
const url = new URL(
52+
`${GOLEMIO_API}/v2/pid/departureboards?${searchParams.toString()}`,
53+
);
1954

2055
const res = await fetch(url, {
2156
method: "GET",
@@ -32,13 +67,30 @@ export class DepartureService {
3267
throw new Error(parsed.error.message);
3368
}
3469

35-
return parsed.data.departures.map((departure) => ({
36-
departure: departure.departure_timestamp,
37-
delay: getDelayInSeconds(departure.delay),
38-
headsign: departure.trip.headsign,
39-
route: departure.route.short_name,
40-
platformId: departure.stop.id,
41-
platformCode: departure.stop.platform_code,
42-
}));
70+
const parsedDepartures = parsed.data.departures.map((departure) => {
71+
return {
72+
departure: departure.departure_timestamp,
73+
delay: getDelayInSeconds(departure.delay),
74+
headsign: departure.trip.headsign,
75+
route: departure.route.short_name,
76+
platformId: departure.stop.id,
77+
platformCode: departure.stop.platform_code,
78+
};
79+
});
80+
81+
// await this.cacheManager.mset(
82+
// requestedIds
83+
// .map((id) =>
84+
// parsedDepartures.find(
85+
// (departure) => departure.platformId === id,
86+
// ),
87+
// )
88+
// .map((departure) => ({
89+
// key: departure.platformId,
90+
// value: JSON.stringify(departure),
91+
// })),
92+
// );
93+
94+
return parsedDepartures;
4395
}
4496
}

0 commit comments

Comments
 (0)