Skip to content

Commit

Permalink
refactor(be)data structure
Browse files Browse the repository at this point in the history
rename stops to platforms
add stops as a parent for platforms
update import script
update prisma schema
  • Loading branch information
krystxf committed Sep 29, 2024
1 parent 5ca536c commit 400cc34
Show file tree
Hide file tree
Showing 19 changed files with 681 additions and 341 deletions.
2 changes: 1 addition & 1 deletion backend-nest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"prisma:generate": "pnpm dlx prisma generate",
"prisma:migrate": "pnpm dlx dotenv-cli -e .env.local -- pnpm dlx prisma migrate dev",
"prisma:push": "pnpm dlx dotenv-cli -e .env.local -- pnpm dlx prisma db push",
"db:start":"docker compose -f compose.postgres.yaml up"
"db:start": "docker compose -f compose.postgres.yaml up"
},
"dependencies": {
"@nestjs/cache-manager": "^2.2.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Warnings:
- You are about to drop the `Stop` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the `StopsOnRoutes` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "StopsOnRoutes" DROP CONSTRAINT "StopsOnRoutes_routeId_fkey";

-- DropForeignKey
ALTER TABLE "StopsOnRoutes" DROP CONSTRAINT "StopsOnRoutes_stopId_fkey";

-- DropTable
DROP TABLE "Stop";

-- DropTable
DROP TABLE "StopsOnRoutes";

-- CreateTable
CREATE TABLE "Platform" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"isMetro" BOOLEAN NOT NULL,
"latitude" DOUBLE PRECISION NOT NULL,
"longitude" DOUBLE PRECISION NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Platform_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "PlatformsOnRoutes" (
"stopId" TEXT NOT NULL,
"routeId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "PlatformsOnRoutes_pkey" PRIMARY KEY ("stopId","routeId")
);

-- CreateIndex
CREATE INDEX "Platform_name_idx" ON "Platform"("name");

-- CreateIndex
CREATE INDEX "Platform_latitude_idx" ON "Platform"("latitude");

-- CreateIndex
CREATE INDEX "Platform_longitude_idx" ON "Platform"("longitude");

-- CreateIndex
CREATE INDEX "Platform_latitude_longitude_idx" ON "Platform"("latitude", "longitude");

-- AddForeignKey
ALTER TABLE "PlatformsOnRoutes" ADD CONSTRAINT "PlatformsOnRoutes_stopId_fkey" FOREIGN KEY ("stopId") REFERENCES "Platform"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "PlatformsOnRoutes" ADD CONSTRAINT "PlatformsOnRoutes_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-- DropIndex
DROP INDEX "Platform_latitude_idx";

-- DropIndex
DROP INDEX "Platform_latitude_longitude_idx";

-- DropIndex
DROP INDEX "Platform_longitude_idx";

-- DropIndex
DROP INDEX "Platform_name_idx";

-- DropIndex
DROP INDEX "Route_name_idx";

-- AlterTable
ALTER TABLE "Platform" ADD COLUMN "stopId" TEXT;

-- CreateTable
CREATE TABLE "Stop" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"avgLatitude" DOUBLE PRECISION NOT NULL,
"avgLongitude" DOUBLE PRECISION NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,

CONSTRAINT "Stop_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Platform" ADD CONSTRAINT "Platform_stopId_fkey" FOREIGN KEY ("stopId") REFERENCES "Stop"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
Warnings:
- The primary key for the `PlatformsOnRoutes` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `stopId` on the `PlatformsOnRoutes` table. All the data in the column will be lost.
- A unique constraint covering the columns `[platformId,routeId]` on the table `PlatformsOnRoutes` will be added. If there are existing duplicate values, this will fail.
- Added the required column `platformId` to the `PlatformsOnRoutes` table without a default value. This is not possible if the table is not empty.
*/
-- DropForeignKey
ALTER TABLE "PlatformsOnRoutes" DROP CONSTRAINT "PlatformsOnRoutes_stopId_fkey";

-- AlterTable
ALTER TABLE "PlatformsOnRoutes" DROP CONSTRAINT "PlatformsOnRoutes_pkey",
DROP COLUMN "stopId",
ADD COLUMN "platformId" TEXT NOT NULL;

-- CreateIndex
CREATE UNIQUE INDEX "PlatformsOnRoutes_platformId_routeId_key" ON "PlatformsOnRoutes"("platformId", "routeId");

-- AddForeignKey
ALTER TABLE "PlatformsOnRoutes" ADD CONSTRAINT "PlatformsOnRoutes_platformId_fkey" FOREIGN KEY ("platformId") REFERENCES "Platform"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
41 changes: 26 additions & 15 deletions backend-nest/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,20 @@ datasource db {
}

model Stop {
id String @id @map("id")
id String @id
name String
avgLatitude Float
avgLongitude Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
platforms Platform[]
}

model Platform {
id String @id
name String
isMetro Boolean
Expand All @@ -24,39 +37,37 @@ model Stop {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
routes StopsOnRoutes[]
routes PlatformsOnRoutes[]
@@index([name])
@@index([latitude])
@@index([longitude])
@@index([latitude, longitude])
stop Stop? @relation(fields: [stopId], references: [id])
stopId String?
}

model Route {
id String @id @map("id")
name String
id String @id
name String
vehicleType VehicleType?
isNight Boolean?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
stops StopsOnRoutes[]
@@index([name])
stops PlatformsOnRoutes[]
}

model StopsOnRoutes {
stop Stop @relation(fields: [stopId], references: [id])
stopId String
model PlatformsOnRoutes {
id String @id @default(uuid())
platform Platform @relation(fields: [platformId], references: [id])
platformId String
route Route @relation(fields: [routeId], references: [id])
routeId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@id([stopId, routeId])
@@unique([platformId, routeId])
}

enum VehicleType {
Expand Down
16 changes: 12 additions & 4 deletions backend-nest/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { ConfigModule } from "@nestjs/config";
import { TTL_DEFAULT } from "./constants/constants";
import { ScheduleModule } from "@nestjs/schedule";
import { PrismaService } from "./database/prisma.service";
import { StopController } from "./modules/stop/stop.controller";
import { PlatformController } from "./modules/platform/platform.controller";
import { APP_INTERCEPTOR } from "@nestjs/core";
import { StopService } from "./modules/stop/stop.service";
import { PlatformService } from "./modules/platform/platform.service";
import { DepartureController } from "./modules/departure/departure.controller";
import { DepartureService } from "./modules/departure/departure.service";
import { StopService } from "./modules/stop/stop.service";
import { StopController } from "./modules/stop/stop.controller";

@Module({
imports: [
Expand All @@ -21,12 +23,18 @@ import { DepartureService } from "./modules/departure/departure.service";
ttl: TTL_DEFAULT,
}),
],
controllers: [AppController, StopController, DepartureController],
controllers: [
AppController,
PlatformController,
DepartureController,
StopController,
],
providers: [
AppService,
PrismaService,
StopService,
PlatformService,
DepartureService,
StopService,
{
provide: APP_INTERCEPTOR,
useClass: CacheInterceptor,
Expand Down
5 changes: 5 additions & 0 deletions backend-nest/src/enums/metro.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { z } from "zod";

const METRO_LINES = ["A", "B", "C"] as const;

export const metroLine = z.enum(METRO_LINES);
21 changes: 14 additions & 7 deletions backend-nest/src/modules/departure/departure.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Controller, Get, HttpException, Query } from "@nestjs/common";
import {
Controller,
Get,
HttpException,
HttpStatus,
Query,
} from "@nestjs/common";
import { PrismaService } from "../../database/prisma.service";
import { DepartureService } from "./departure.service";
import { toArray } from "src/utils/array.utils";
Expand All @@ -15,15 +21,16 @@ export class DepartureController {
private readonly departureService: DepartureService,
) {}

@Get("/platform")
async getDeparturesByPlatform(
@Query("platform") platform,
): Promise<DepartureSchema[]> {
@Get("/stop")
async getDeparturesByPlatform(@Query("id") id): Promise<DepartureSchema[]> {
const platformSchema = z.string().array().min(1).max(20);
const parsed = platformSchema.safeParse(toArray(platform));
const parsed = platformSchema.safeParse(toArray(id));

if (!parsed.success) {
throw new HttpException("Invalid query params", 400);
throw new HttpException(
"Invalid query params",
HttpStatus.BAD_REQUEST,
);
}

const departures = await this.departureService.getDeparturesByPlatform(
Expand Down
82 changes: 67 additions & 15 deletions backend-nest/src/modules/departure/departure.service.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,56 @@
import { Injectable } from "@nestjs/common";
import { HttpException, HttpStatus, Inject, Injectable } from "@nestjs/common";
import { GOLEMIO_API } from "src/constants";
import type { DepartureSchema } from "./schema/departure.schema";
import { departureBoardsSchema } from "./schema/departure-boards.schema";
import { getDelayInSeconds } from "src/utils/delay";
import { PrismaService } from "src/database/prisma.service";
import { CACHE_MANAGER } from "@nestjs/cache-manager";

@Injectable()
export class DepartureService {
constructor() {}
constructor(
private prisma: PrismaService,
@Inject(CACHE_MANAGER) private cacheManager,
) {}

async getDeparturesByPlatform(
platforms: string[],
requestedIds: string[],
): Promise<DepartureSchema[]> {
const url = new URL("/v2/pid/departureboards", GOLEMIO_API);
url.searchParams.append("order", "real");
platforms.forEach((id) => {
url.searchParams.append("ids[]", id);
const databasePlatforms = await this.prisma.platform.findMany({
select: {
id: true,
},
where: {
id: {
in: requestedIds,
},
},
});
const databaseIDs = databasePlatforms.map((platform) => platform.id);
const allIdsInDb = requestedIds.every((requestedID) =>
databaseIDs.includes(requestedID),
);

if (!allIdsInDb) {
throw new HttpException(
"Invalid query params",
HttpStatus.BAD_REQUEST,
);
}

const searchParams = new URLSearchParams(
requestedIds
.map((id) => ["ids", id])
.concat([
["skip", "canceled"],
["mode", "departures"],
["order", "real"],
]),
);

const url = new URL(
`${GOLEMIO_API}/v2/pid/departureboards?${searchParams.toString()}`,
);

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

return parsed.data.departures.map((departure) => ({
departure: departure.departure_timestamp,
delay: getDelayInSeconds(departure.delay),
headsign: departure.trip.headsign,
route: departure.route.short_name,
platformId: departure.stop.id,
platformCode: departure.stop.platform_code,
}));
const parsedDepartures = parsed.data.departures.map((departure) => {
return {
departure: departure.departure_timestamp,
delay: getDelayInSeconds(departure.delay),
headsign: departure.trip.headsign,
route: departure.route.short_name,
platformId: departure.stop.id,
platformCode: departure.stop.platform_code,
};
});

// await this.cacheManager.mset(
// requestedIds
// .map((id) =>
// parsedDepartures.find(
// (departure) => departure.platformId === id,
// ),
// )
// .map((departure) => ({
// key: departure.platformId,
// value: JSON.stringify(departure),
// })),
// );

return parsedDepartures;
}
}
Loading

0 comments on commit 400cc34

Please sign in to comment.