TimetableAPI-Upgrade #64

Merged
fred.boniface merged 36 commits from TimetableAPI-Upgrade into main 2024-02-11 15:53:17 +00:00
5 changed files with 127 additions and 38 deletions
Showing only changes of commit 89043516ea - Show all commits

View File

@ -44,7 +44,10 @@ async function findByHeadcodeToday(headcode: string) {
} }
// Finds a train by its headcode value // Finds a train by its headcode value
async function findByHeadcode(date: string | Date, headcode: string): Promise<TrainServices[]> { async function findByHeadcode(
date: string | Date,
headcode: string
): Promise<TrainServices[]> {
const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase();
logger.debug( logger.debug(
`trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}` `trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}`
@ -88,7 +91,10 @@ async function findByHeadcode(date: string | Date, headcode: string): Promise<Tr
} }
// Finds a train by its trainUid value // Finds a train by its trainUid value
async function findByTrainUid(uid: string, date: Date | string = new Date()): Promise<TrainServices | null> { async function findByTrainUid(
uid: string,
date: Date | string = new Date()
): Promise<TrainServices | null> {
let queryDate; let queryDate;
if (date === "now") { if (date === "now") {
queryDate = new Date(); queryDate = new Date();

View File

@ -13,7 +13,7 @@ import {
} from "../utils/pis.utils"; } from "../utils/pis.utils";
import { Document } from "mongodb"; import { Document } from "mongodb";
const supported = ["GW", "UK"]; export const supported = ["GW", "UK"];
async function findPisByOrigDest(start: string, end: string) { async function findPisByOrigDest(start: string, end: string) {
logger.debug( logger.debug(

View File

@ -1,21 +1,36 @@
import { logger } from "../utils/logger.utils"; 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 { queryAggregate } from "./dbAccess.services";
import { getFindByHeadcodePipeline, getFindByTrainUidPipeline } from "../utils/trainService.utils" import {
import { removeNonAlphanumeric } from "../utils/sanitizer.utils" 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<SimpleService[]> { export async function findByHeadcode(
headcode: string,
date: Date | string
): Promise<SimpleService[]> {
const sanitizedHeadcode = removeNonAlphanumeric(headcode); 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. // 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); searchDate.setHours(12, 0, 0);
// Get the 'shortDay' // Get the 'shortDay'
const shortDay = getShortDay(searchDate) const shortDay = getShortDay(searchDate);
const query = { const query = {
headcode: sanitizedHeadcode, headcode: sanitizedHeadcode,
@ -23,16 +38,22 @@ export async function findByHeadcode(headcode: string, date: Date | string): Pro
scheduleEndDate: { $gte: searchDate }, scheduleEndDate: { $gte: searchDate },
daysRun: { $in: [shortDay] }, daysRun: { $in: [shortDay] },
}; };
const pipeline = getFindByHeadcodePipeline(query) const pipeline = getFindByHeadcodePipeline(query);
const result: SimpleService[] = await queryAggregate("timetable", pipeline) as SimpleService[] const result: SimpleService[] = (await queryAggregate(
"timetable",
pipeline
)) as SimpleService[];
const services = filterServices(result); const services = filterServices(result);
return services; 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 // Set the correct date - whether a date or "now" was passed to function
let queryDate: Date; let queryDate: Date;
if (date instanceof Date) { if (date instanceof Date) {
@ -46,41 +67,64 @@ export async function findByTrainUid(uid: string, date: Date | string = new Date
trainUid: uid, trainUid: uid,
scheduleStartDate: { $lte: queryDate }, scheduleStartDate: { $lte: queryDate },
scheduleEndDate: { $gte: 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) // TODO: Format and return data, the function called is not yet complete
return formatTimetableDetail(services[0], pis)
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.
} }
// Internal Functions: // 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<OB_Pis_SimpleObject | null> {
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. // Outputs the standard 'shortday' string from a Date.
function getShortDay(day: Date): string { function getShortDay(day: Date): string {
const dayMap = ["su", "m", "t", "w", "th", "f", "s"]; const dayMap = ["su", "m", "t", "w", "th", "f", "s"];
const shortDay = dayMap[day.getDay()]; const shortDay = dayMap[day.getDay()];
return shortDay return shortDay;
} }
// Filters services using their STP indicator so that over-riding entries are returned correctly // Filters services using their STP indicator so that over-riding entries are returned correctly
function filterServices(services: SimpleService[]): (SimpleService[]) { function filterServices(services: SimpleService[]): SimpleService[] {
let stpIndicators: Record<string, { hasC: boolean; hasN: boolean; hasO: boolean; hasP: boolean }> = {}; let stpIndicators: Record<
let filteredServices: SimpleService[] = [] string,
{ hasC: boolean; hasN: boolean; hasO: boolean; hasP: boolean }
> = {};
let filteredServices: SimpleService[] = [];
for (const service of services) { for (const service of services) {
const trainUid = service["trainUid"], stpIndicator = service["stpIndicator"] const trainUid = service["trainUid"],
stpIndicator = service["stpIndicator"];
// Creates the stpIndicators array: // Creates the stpIndicators array:
if (!stpIndicators[trainUid]) { if (!stpIndicators[trainUid]) {
stpIndicators[trainUid] = { stpIndicators[trainUid] = {
hasC: false, hasN: false, hasO: false, hasP: false, hasC: false,
} hasN: false,
hasO: false,
hasP: false,
};
} }
if (stpIndicator === "C") { if (stpIndicator === "C") {
@ -100,7 +144,7 @@ function filterServices(services: SimpleService[]): (SimpleService[]) {
// Iterate each service, and only output one service matching each trainUid, // 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. // C > N > O > P is the order, with C being prioritised over other STP types.
for (const service of services) { for (const service of services) {
const trainUid = service["trainUid"] const trainUid = service["trainUid"];
const thisStpIndicators = stpIndicators[trainUid]; const thisStpIndicators = stpIndicators[trainUid];
const stpIndicator = service["stpIndicator"]; const stpIndicator = service["stpIndicator"];

View File

@ -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
}
}

View File

@ -20,7 +20,10 @@ export function getFindByHeadcodePipeline(query: any) {
} }
export function getFindByTrainUidPipeline(query: any) { export function getFindByTrainUidPipeline(query: any) {
return [{ return [
'$match': query, {
},{'$project': {'_id': 0}}] $match: query,
} },
{ $project: { _id: 0 } },
];
}