Skip to content

Commit 42845f0

Browse files
committed
schedules: add a query to get the trips in time range
This query returns the trips in a given time range for a list of lines and services. It is all the trips that have a departure time before the range end and an arrival time after the range start.
1 parent 835a6b6 commit 42845f0

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-1
lines changed

packages/transition-backend/src/models/db/__tests__/TransitSchedule.db.test.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const agencyId = uuidV4();
2121
const lineId = uuidV4();
2222
const lineId2 = uuidV4();
2323
const serviceId = uuidV4();
24+
const serviceId2 = uuidV4();
2425
const pathId = uuidV4();
2526
const pathId2 = uuidV4();
2627

@@ -54,6 +55,9 @@ beforeAll(async () => {
5455
await servicesDbQueries.create({
5556
id: serviceId
5657
} as any);
58+
await servicesDbQueries.create({
59+
id: serviceId2
60+
} as any);
5761
});
5862

5963
afterAll(async () => {
@@ -1067,3 +1071,109 @@ describe('Schedules duplication', () => {
10671071
});
10681072

10691073
});
1074+
1075+
describe('getTripsInTimeRange', () => {
1076+
1077+
beforeEach(async () => {
1078+
// Empty the tables
1079+
await dbQueries.truncateSchedules();
1080+
await dbQueries.truncateSchedulePeriods();
1081+
await dbQueries.truncateScheduleTrips();
1082+
1083+
// Add a few schedules
1084+
const service1Line1 = _cloneDeep(scheduleForServiceId) as any;
1085+
service1Line1.line_id = lineId;
1086+
service1Line1.service_id = serviceId;
1087+
await dbQueries.save(service1Line1);
1088+
1089+
// duplicate schedule for the same line, different service
1090+
await dbQueries.duplicateSchedule({serviceIdMapping: { [serviceId]: serviceId2 } });
1091+
// duplicate the service1 service for another line
1092+
await dbQueries.duplicateSchedule({serviceIdMapping: { [serviceId]: serviceId }, lineIdMapping: { [lineId]: lineId2 } });
1093+
});
1094+
1095+
test('No trips in range', async() => {
1096+
const trips = await dbQueries.getTripsInTimeRange({
1097+
rangeStart: 0,
1098+
rangeEnd: 10000,
1099+
lineIds: [lineId, lineId2],
1100+
serviceIds: [serviceId, serviceId2]
1101+
});
1102+
expect(trips.length).toEqual(0);
1103+
});
1104+
1105+
test('Get trips in range for multiple service and line', async() => {
1106+
const trips = await dbQueries.getTripsInTimeRange({
1107+
rangeStart: 25000,
1108+
rangeEnd: 35000,
1109+
lineIds: [lineId, lineId2],
1110+
serviceIds: [serviceId, serviceId2]
1111+
});
1112+
// There should be 3 trips by line/service pairs
1113+
expect(trips.length).toEqual(3 * 3);
1114+
expect(trips.filter(trip => trip.line_id === lineId && trip.service_id === serviceId).length).toEqual(3);
1115+
expect(trips.filter(trip => trip.line_id === lineId2 && trip.service_id === serviceId).length).toEqual(3);
1116+
expect(trips.filter(trip => trip.line_id === lineId && trip.service_id === serviceId2).length).toEqual(3);
1117+
});
1118+
1119+
test('Get trips in range only for line', async() => {
1120+
const trips = await dbQueries.getTripsInTimeRange({
1121+
rangeStart: 25000,
1122+
rangeEnd: 35000,
1123+
lineIds: [lineId],
1124+
serviceIds: [serviceId, serviceId2]
1125+
});
1126+
// There should be 3 trips by line/service pairs
1127+
expect(trips.length).toEqual(2 * 3);
1128+
expect(trips.some(trip => trip.line_id === lineId2)).toBe(false);
1129+
});
1130+
1131+
test('Get trips in range only for service', async() => {
1132+
const trips = await dbQueries.getTripsInTimeRange({
1133+
rangeStart: 25000,
1134+
rangeEnd: 35000,
1135+
lineIds: [lineId, lineId2],
1136+
serviceIds: [serviceId]
1137+
});
1138+
// There should be 3 trips by line/service pairs
1139+
expect(trips.length).toEqual(2 * 3);
1140+
expect(trips.some(trip => trip.service_id === serviceId2)).toBe(false);
1141+
});
1142+
1143+
test('Trips ending at range start', async() => {
1144+
const trips = await dbQueries.getTripsInTimeRange({
1145+
rangeStart: 27015,
1146+
rangeEnd: 29000,
1147+
lineIds: [lineId],
1148+
serviceIds: [serviceId]
1149+
});
1150+
// There should be 1 trip, the one ending at 27015
1151+
expect(trips.length).toEqual(1);
1152+
expect(trips[0].arrival_time_seconds).toEqual(27015);
1153+
});
1154+
1155+
test('Trips starting at range end', async() => {
1156+
const trips = await dbQueries.getTripsInTimeRange({
1157+
rangeStart: 10000,
1158+
rangeEnd: 25200,
1159+
lineIds: [lineId],
1160+
serviceIds: [serviceId]
1161+
});
1162+
// There should be 1 trip, the one starting at 25200
1163+
expect(trips.length).toEqual(1);
1164+
console.log("trips", trips[0]);
1165+
expect(trips[0].departure_time_seconds).toEqual(25200);
1166+
});
1167+
1168+
test('Unexisting line for service', async() => {
1169+
const trips = await dbQueries.getTripsInTimeRange({
1170+
rangeStart: 25000,
1171+
rangeEnd: 35000,
1172+
lineIds: [lineId2],
1173+
serviceIds: [serviceId2]
1174+
});
1175+
// There should be no trip
1176+
expect(trips.length).toEqual(0);
1177+
});
1178+
1179+
});

packages/transition-backend/src/models/db/transitSchedules.db.queries.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,39 @@ const duplicateSchedule = async ({
800800
}
801801
};
802802

803+
const getTripsInTimeRange = async ({
804+
rangeStart,
805+
rangeEnd,
806+
lineIds,
807+
serviceIds
808+
}: {
809+
rangeStart: number;
810+
rangeEnd: number;
811+
lineIds: string[];
812+
serviceIds: string[];
813+
}): Promise<(SchedulePeriodTrip & { line_id: string; service_id: string })[]> => {
814+
try {
815+
const query = knex(tripTable)
816+
.select([`${tripTable}.*`, `${scheduleTable}.service_id`, `${scheduleTable}.line_id`])
817+
.join(periodTable, `${tripTable}.schedule_period_id`, `${periodTable}.id`)
818+
.join(scheduleTable, `${periodTable}.schedule_id`, `${scheduleTable}.id`)
819+
.whereIn(`${scheduleTable}.line_id`, lineIds)
820+
.whereIn(`${scheduleTable}.service_id`, serviceIds)
821+
.andWhere(`${tripTable}.departure_time_seconds`, '<=', rangeEnd)
822+
.andWhere(`${tripTable}.arrival_time_seconds`, '>=', rangeStart);
823+
824+
const rows = await query;
825+
const trips = rows.map(scheduleTripsAttributesParser);
826+
return trips as (SchedulePeriodTrip & { line_id: string; service_id: string })[];
827+
} catch (error) {
828+
throw new TrError(
829+
`Cannot get trips in time range ${rangeStart}-${rangeEnd} in database (knex error: ${error})`,
830+
'DBSCHED0004',
831+
'TransitScheduleCannotUpdateBecauseDatabaseError'
832+
);
833+
}
834+
};
835+
803836
export default {
804837
exists: exists.bind(null, knex, scheduleTable),
805838
read: readScheduleData,
@@ -828,5 +861,6 @@ export default {
828861
collection,
829862
/** Read the schedules for a list of lines */
830863
readForLines,
831-
duplicateSchedule
864+
duplicateSchedule,
865+
getTripsInTimeRange
832866
};

0 commit comments

Comments
 (0)