diff --git a/src/services/.trainService.services.ts b/src/services/.trainService.services.ts index 413416f..5cd0d45 100644 --- a/src/services/.trainService.services.ts +++ b/src/services/.trainService.services.ts @@ -44,7 +44,10 @@ async function findByHeadcodeToday(headcode: string) { } // Finds a train by its headcode value -async function findByHeadcode(date: string | Date, headcode: string): Promise { +async function findByHeadcode( + date: string | Date, + headcode: string +): Promise { const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); logger.debug( `trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}` @@ -88,7 +91,10 @@ async function findByHeadcode(date: string | Date, headcode: string): Promise { +async function findByTrainUid( + uid: string, + date: Date | string = new Date() +): Promise { let queryDate; if (date === "now") { queryDate = new Date(); diff --git a/src/services/pis.services.ts b/src/services/pis.services.ts index 5d497a6..88b8d40 100644 --- a/src/services/pis.services.ts +++ b/src/services/pis.services.ts @@ -13,7 +13,7 @@ import { } from "../utils/pis.utils"; import { Document } from "mongodb"; -const supported = ["GW", "UK"]; +export const supported = ["GW", "UK"]; async function findPisByOrigDest(start: string, end: string) { logger.debug( diff --git a/src/services/trainService.services2.ts b/src/services/trainService.services2.ts index 1486cc4..6152a37 100644 --- a/src/services/trainService.services2.ts +++ b/src/services/trainService.services2.ts @@ -1,21 +1,36 @@ import { logger } from "../utils/logger.utils"; -import { findByTiplocArray } from "../services/pis.services" +import { findByTiplocArray, supported } from "../services/pis.services"; import { queryAggregate } from "./dbAccess.services"; -import { getFindByHeadcodePipeline, getFindByTrainUidPipeline } from "../utils/trainService.utils" -import { removeNonAlphanumeric } from "../utils/sanitizer.utils" +import { + getFindByHeadcodePipeline, + getFindByTrainUidPipeline, +} from "../utils/trainService.utils"; +import { removeNonAlphanumeric } from "../utils/sanitizer.utils"; +import { formatTimetableDetail } from "../utils/processors/timetable/timetableProcessor.utils"; -import type { TrainServices, Service, Stop, SimpleService } from "@owlboard/ts-types"; +import type { + TrainServices, + Service, + Stop, + SimpleService, + OB_Pis_SimpleObject, +} from "@owlboard/ts-types"; -export async function findByHeadcode(headcode: string, date: Date | string): Promise { +export async function findByHeadcode( + headcode: string, + date: Date | string +): Promise { const sanitizedHeadcode = removeNonAlphanumeric(headcode); - logger.debug(`trainServices.findByHeadcode: Searching for trains by headcode: ${headcode}`) - + logger.debug( + `trainServices.findByHeadcode: Searching for trains by headcode: ${headcode}` + ); + // If 'now' then generate a new Date now, else use the provided date, then set time to 1200. - const searchDate = (date === "now") ? new Date() : new Date(date); + const searchDate = date === "now" ? new Date() : new Date(date); searchDate.setHours(12, 0, 0); // Get the 'shortDay' - const shortDay = getShortDay(searchDate) + const shortDay = getShortDay(searchDate); const query = { headcode: sanitizedHeadcode, @@ -23,16 +38,22 @@ export async function findByHeadcode(headcode: string, date: Date | string): Pro scheduleEndDate: { $gte: searchDate }, daysRun: { $in: [shortDay] }, }; - const pipeline = getFindByHeadcodePipeline(query) - - const result: SimpleService[] = await queryAggregate("timetable", pipeline) as SimpleService[] + const pipeline = getFindByHeadcodePipeline(query); + + const result: SimpleService[] = (await queryAggregate( + "timetable", + pipeline + )) as SimpleService[]; const services = filterServices(result); return services; } -export async function findByTrainUid(uid: string, date: Date | string = new Date()) { +export async function findByTrainUid( + uid: string, + date: Date | string = new Date() +) { // Set the correct date - whether a date or "now" was passed to function let queryDate: Date; if (date instanceof Date) { @@ -46,41 +67,64 @@ export async function findByTrainUid(uid: string, date: Date | string = new Date trainUid: uid, scheduleStartDate: { $lte: queryDate }, scheduleEndDate: { $gte: queryDate }, - daysRun: { $in: [getShortDay(queryDate)] } + daysRun: { $in: [getShortDay(queryDate)] }, + }; + const pipeline = getFindByTrainUidPipeline(query); + + const result = (await queryAggregate("timetable", pipeline)) as Service[]; + + let services = filterServices(result) as Service[]; + + // Check if the operator is on the supported TOC list for PIS Codes - if so, call the fetchPisCode function. + let pis: OB_Pis_SimpleObject | null; + if (supported.includes(services[0]?.operator)) { + pis = await fetchPisCode(services[0]?.stops); } - const pipeline = getFindByTrainUidPipeline(query) - - const result = await queryAggregate("timetable", pipeline) as Service[] - - let services = filterServices(result) as Service[] - - // Next up is the public stops filter, the resulting array is used for a PIS search - // I can probably write a function that both builds the public stop array and returns - // a PIS object - or null. + // TODO: Format and return data, the function called is not yet complete + return formatTimetableDetail(services[0], pis) } // Internal Functions: +// Filters out non-passenger stops and then uses the stop array to request a PIS code for the service +async function fetchPisCode( + stops: Stop[] +): Promise { + let tiplocList: string[] = []; + for (const stop in stops) { + if (stops[stop]["isPublic"]) tiplocList.push(stops[stop]["tiploc"]); + } + const pisData = await findByTiplocArray(tiplocList); + return pisData; +} + // Outputs the standard 'shortday' string from a Date. function getShortDay(day: Date): string { const dayMap = ["su", "m", "t", "w", "th", "f", "s"]; const shortDay = dayMap[day.getDay()]; - return shortDay + return shortDay; } // Filters services using their STP indicator so that over-riding entries are returned correctly -function filterServices(services: SimpleService[]): (SimpleService[]) { - let stpIndicators: Record = {}; - let filteredServices: SimpleService[] = [] +function filterServices(services: SimpleService[]): SimpleService[] { + let stpIndicators: Record< + string, + { hasC: boolean; hasN: boolean; hasO: boolean; hasP: boolean } + > = {}; + let filteredServices: SimpleService[] = []; for (const service of services) { - const trainUid = service["trainUid"], stpIndicator = service["stpIndicator"] + const trainUid = service["trainUid"], + stpIndicator = service["stpIndicator"]; // Creates the stpIndicators array: if (!stpIndicators[trainUid]) { stpIndicators[trainUid] = { - hasC: false, hasN: false, hasO: false, hasP: false, - } + hasC: false, + hasN: false, + hasO: false, + hasP: false, + }; } if (stpIndicator === "C") { @@ -100,7 +144,7 @@ function filterServices(services: SimpleService[]): (SimpleService[]) { // Iterate each service, and only output one service matching each trainUid, // C > N > O > P is the order, with C being prioritised over other STP types. for (const service of services) { - const trainUid = service["trainUid"] + const trainUid = service["trainUid"]; const thisStpIndicators = stpIndicators[trainUid]; const stpIndicator = service["stpIndicator"]; diff --git a/src/utils/processors/timetable/timetableProcessor.utils.ts b/src/utils/processors/timetable/timetableProcessor.utils.ts index e69de29..4926334 100644 --- a/src/utils/processors/timetable/timetableProcessor.utils.ts +++ b/src/utils/processors/timetable/timetableProcessor.utils.ts @@ -0,0 +1,36 @@ +import type {Service, OB_TrainTT_service, OB_Pis_SimpleObject, OB_TrainTT_stopDetail, Stop} from "@owlboard/ts-types" + +export function formatTimetableDetail(service: Service, pis: OB_Pis_SimpleObject | null): OB_TrainTT_service { + const formattedService: OB_TrainTT_service = { + stpIndicator: service.stpIndicator, + operator: service.operator, + trainUid: service.trainUid, + headcode: service.headcode, + powerType: service.powerType, + planSpeed: convertStringToNumber(service.planSpeed), // Force convert from string to number. + scheduleStart: service.scheduleStartDate, + scheduleEnd: service.scheduleEndDate, + daysRun: service.daysRun, + stops: service.stops, // Need separate function to ensure type compatibility + vstp: service.vstp, // Need to ensure that ts-types is up to date. + } + + if (pis) { + formattedService.pis = pis; + } + + return formattedService +} + +function formatStops(stops: Stop[]): OB_TrainTT_stopDetail[] { + // Cleanly coerce Stop[] to OB_TrainTT_stopDetail[] +} + +function convertStringToNumber(str: string): number { + const number = parseFloat(str) + if (isNaN(number)) { + return 0; + } else { + return number + } +} \ No newline at end of file diff --git a/src/utils/trainService.utils.ts b/src/utils/trainService.utils.ts index 1920c0c..c34efb7 100644 --- a/src/utils/trainService.utils.ts +++ b/src/utils/trainService.utils.ts @@ -20,7 +20,10 @@ export function getFindByHeadcodePipeline(query: any) { } export function getFindByTrainUidPipeline(query: any) { - return [{ - '$match': query, -},{'$project': {'_id': 0}}] -} \ No newline at end of file + return [ + { + $match: query, + }, + { $project: { _id: 0 } }, + ]; +}