mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 16:35:42 +00:00
Added optimization for search result and fix sea map
This commit is contained in:
@@ -146,6 +146,96 @@ export class SegmentsService {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch availability check for multiple seats on a single schedule.
|
||||
* Replaces N×isSeatFreeForLeg calls with 2 queries total.
|
||||
* Returns a Set of seat IDs that are free for [reqFrom, reqTo).
|
||||
*/
|
||||
async getFreeSeatIds(
|
||||
scheduleId: string,
|
||||
seatIds: string[],
|
||||
stopTimesForSeqLookup: ReadonlyArray<{ stationId: string; sequence: number }>,
|
||||
reqFrom: number,
|
||||
reqTo: number,
|
||||
): Promise<Set<string>> {
|
||||
if (seatIds.length === 0) return new Set();
|
||||
|
||||
const seqOf = (stationId: string) =>
|
||||
stopTimesForSeqLookup.find(s => s.stationId === stationId)?.sequence;
|
||||
|
||||
const seatIdSet = new Set(seatIds);
|
||||
const now = new Date();
|
||||
|
||||
const [allHolds, bookedLegs] = await Promise.all([
|
||||
this.prisma.seatHold.findMany({
|
||||
where: { scheduleId, expiresAt: { gt: now } },
|
||||
select: { seatIds: true, createdBy: true },
|
||||
}),
|
||||
this.prisma.journeySegment.findMany({
|
||||
where: {
|
||||
scheduleId,
|
||||
seatId: { in: seatIds },
|
||||
journey: { status: { in: ['CONFIRMED', 'PENDING_PAYMENT'] } },
|
||||
},
|
||||
select: { seatId: true, journeyId: true, departureStationId: true, arrivalStationId: true },
|
||||
}),
|
||||
]);
|
||||
|
||||
// Determine which seats are blocked by active holds
|
||||
const holdBlockedSeats = new Set<string>();
|
||||
for (const hold of allHolds) {
|
||||
let holdFrom: number | undefined;
|
||||
let holdTo: number | undefined;
|
||||
try {
|
||||
if (hold.createdBy) {
|
||||
const meta = JSON.parse(hold.createdBy as string);
|
||||
holdFrom = seqOf(meta.originStationId);
|
||||
holdTo = seqOf(meta.destinationStationId);
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
|
||||
for (const sid of hold.seatIds) {
|
||||
if (!seatIdSet.has(sid)) continue;
|
||||
// Conservative block if leg can't be resolved; otherwise check overlap
|
||||
if (holdFrom === undefined || holdTo === undefined || (holdFrom < reqTo && reqFrom < holdTo)) {
|
||||
holdBlockedSeats.add(sid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build full journey ranges per seat (group multi-leg journeys)
|
||||
const journeyRangesBySeat = new Map<string, Map<string, { from: number; to: number }>>();
|
||||
for (const leg of bookedLegs) {
|
||||
if (!leg.seatId || !leg.journeyId || !leg.departureStationId || !leg.arrivalStationId) continue;
|
||||
const depSeq = seqOf(leg.departureStationId);
|
||||
const arrSeq = seqOf(leg.arrivalStationId);
|
||||
if (depSeq === undefined || arrSeq === undefined) continue;
|
||||
|
||||
let rangeMap = journeyRangesBySeat.get(leg.seatId);
|
||||
if (!rangeMap) { rangeMap = new Map(); journeyRangesBySeat.set(leg.seatId, rangeMap); }
|
||||
|
||||
const existing = rangeMap.get(leg.journeyId);
|
||||
rangeMap.set(leg.journeyId, existing
|
||||
? { from: Math.min(existing.from, depSeq), to: Math.max(existing.to, arrSeq) }
|
||||
: { from: depSeq, to: arrSeq });
|
||||
}
|
||||
|
||||
const freeSeats = new Set<string>();
|
||||
for (const seatId of seatIds) {
|
||||
if (holdBlockedSeats.has(seatId)) continue;
|
||||
let blocked = false;
|
||||
const rangeMap = journeyRangesBySeat.get(seatId);
|
||||
if (rangeMap) {
|
||||
for (const { from, to } of rangeMap.values()) {
|
||||
if (from < reqTo && reqFrom < to) { blocked = true; break; }
|
||||
}
|
||||
}
|
||||
if (!blocked) freeSeats.add(seatId);
|
||||
}
|
||||
|
||||
return freeSeats;
|
||||
}
|
||||
|
||||
/** Legacy wrapper used by EnhancedSeatsService.getOverlappingReservations */
|
||||
async getOverlappingReservations(
|
||||
scheduleId: string,
|
||||
|
||||
Reference in New Issue
Block a user