refactoring journeysReq

This commit is contained in:
Traines 2024-12-21 15:51:25 +00:00
parent ec723b3414
commit 9f5e1fa6bd
3 changed files with 46 additions and 132 deletions

125
index.js
View file

@ -120,9 +120,6 @@ const createClient = (profile, userAgent, opt = {}) => {
};
const journeys = async (from, to, opt = {}) => {
from = profile.formatLocation(profile, from, 'from');
to = profile.formatLocation(profile, to, 'to');
if ('earlierThan' in opt && 'laterThan' in opt) {
throw new TypeError('opt.earlierThan and opt.laterThan are mutually exclusive.');
}
@ -168,9 +165,6 @@ const createClient = (profile, userAgent, opt = {}) => {
remarks: true, // parse & expose hints & warnings?
scheduledDays: false, // parse & expose dates each journey is valid on?
}, opt);
if (opt.via) {
opt.via = profile.formatLocation(profile, opt.via, 'opt.via');
}
if (opt.when !== undefined) {
throw new Error('opt.when is not supported anymore. Use opt.departure/opt.arrival.');
@ -192,38 +186,7 @@ const createClient = (profile, userAgent, opt = {}) => {
outFrwd = false;
}
const filters = profile.formatProductsFilter({profile}, opt.products || {});
// TODO opt.accessibility
const query = {
maxUmstiege: opt.transfers,
minUmstiegszeit: opt.transferTime,
deutschlandTicketVorhanden: false,
nurDeutschlandTicketVerbindungen: false,
reservierungsKontingenteVorhanden: false,
schnelleVerbindungen: true,
sitzplatzOnly: false,
abfahrtsHalt: from.lid,
zwischenhalte: opt.via
? [{id: opt.via.lid}]
: null,
ankunftsHalt: to.lid,
produktgattungen: filters,
bikeCarriage: opt.bike,
// TODO
// todo: this is actually "take additional stations nearby the given start and destination station into account"
// see rest.exe docs
// ushrp: Boolean(opt.startWithWalking),
};
query.anfrageZeitpunkt = profile.formatTime(profile, when);
if (journeysRef) {
query.pagingReference = journeysRef;
}
query.ankunftSuche = outFrwd ? 'ABFAHRT' : 'ANKUNFT';
if (opt.results !== null) {
// TODO query.numF = opt.results;
}
const req = profile.formatJourneysReq({profile, opt}, query);
const req = profile.formatJourneysReq({profile, opt}, from, to, when, outFrwd, journeysRef);
const {res} = await profile.request({profile, opt}, userAgent, req);
const ctx = {profile, opt, common, res};
const verbindungen = opt.results ? res.verbindungen.slice(0, opt.results) : res.verbindungen;
@ -373,90 +336,8 @@ const createClient = (profile, userAgent, opt = {}) => {
};
// todo [breaking]: rename to trips()?
const tripsByName = async (lineNameOrFahrtNr = '*', opt = {}) => {
if (!isNonEmptyString(lineNameOrFahrtNr)) {
throw new TypeError('lineNameOrFahrtNr must be a non-empty string.');
}
opt = Object.assign({
when: null,
fromWhen: null, untilWhen: null,
onlyCurrentlyRunning: true,
products: {},
currentlyStoppingAt: null,
lineName: null,
operatorNames: null,
additionalFilters: [], // undocumented
}, opt);
const req = {
// fields: https://github.com/marudor/BahnhofsAbfahrten/blob/f619e754f212980261eb7e2b151cd73ba0213da8/packages/types/HAFAS/JourneyMatch.ts#L4-L23
input: lineNameOrFahrtNr,
onlyCR: opt.onlyCurrentlyRunning,
jnyFltrL: [
profile.formatProductsFilter({profile}, opt.products),
],
// todo: passing `tripId` yields a `CGI_READ_FAILED` error
// todo: passing a stop ID as `extId` yields a `PARAMETER` error
// todo: `onlyRT: true` reduces the number of results, but filters recent trips 🤔
// todo: `onlyTN: true` yields a `NO_MATCH` error
// todo: useAeqi
};
if (opt.when !== null) {
req.date = profile.formatDate(profile, new Date(opt.when));
req.time = profile.formatTime(profile, new Date(opt.when));
}
// todo: fromWhen doesn't work yet, but untilWhen does
if (opt.fromWhen !== null) {
req.dateB = profile.formatDate(profile, new Date(opt.fromWhen));
req.timeB = profile.formatTime(profile, new Date(opt.fromWhen));
}
if (opt.untilWhen !== null) {
req.dateE = profile.formatDate(profile, new Date(opt.untilWhen));
req.timeE = profile.formatTime(profile, new Date(opt.untilWhen));
}
const filter = (mode, type, value) => ({mode, type, value});
if (opt.currentlyStoppingAt !== null) {
if (!isNonEmptyString(opt.currentlyStoppingAt)) {
throw new TypeError('opt.currentlyStoppingAt must be a non-empty string.');
}
req.jnyFltrL.push(filter('INC', 'STATIONS', opt.currentlyStoppingAt));
}
if (opt.lineName !== null) {
if (!isNonEmptyString(opt.lineName)) {
throw new TypeError('opt.lineName must be a non-empty string.');
}
// todo: does this target `line` or `lineId`?
req.jnyFltrL.push(filter('INC', 'LINE', opt.lineName));
}
if (opt.operatorNames !== null) {
if (
!Array.isArray(opt.operatorNames)
|| opt.operatorNames.length === 0
|| !opt.operatorNames.every(isNonEmptyString)
) {
throw new TypeError('opt.operatorNames must be an array of non-empty strings.');
}
// todo: is the an escaping mechanism for ","
req.jnyFltrL.push(filter('INC', 'OP', opt.operatorNames.join(',')));
}
req.jnyFltrL = [...req.jnyFltrL, ...opt.additionalFilters];
const {res} = await profile.request({profile, opt}, userAgent, {
cfg: {polyEnc: 'GPA'},
meth: 'JourneyMatch',
req,
});
// todo [breaking]: catch `NO_MATCH` errors, return []
const ctx = {profile, opt, common, res};
const trips = res.jnyL.map(t => profile.parseTrip(ctx, t));
return {
trips,
realtimeDataUpdatedAt: res.planrtTS && res.planrtTS !== '0'
? parseInt(res.planrtTS)
: null,
};
const tripsByName = async (_lineNameOrFahrtNr = '*', _opt = {}) => {
throw new Error('not implemented');
};
const client = {

View file

@ -1,4 +1,39 @@
const formatJourneysReq = (ctx, query) => {
const formatJourneysReq = (ctx, from, to, when, outFrwd, journeysRef) => {
const {profile, opt} = ctx;
from = profile.formatLocation(profile, from, 'from');
to = profile.formatLocation(profile, to, 'to');
const filters = profile.formatProductsFilter({profile}, opt.products || {});
// TODO opt.accessibility
let query = {
maxUmstiege: opt.transfers,
minUmstiegszeit: opt.transferTime,
deutschlandTicketVorhanden: false,
nurDeutschlandTicketVerbindungen: false,
reservierungsKontingenteVorhanden: false,
schnelleVerbindungen: true,
sitzplatzOnly: false,
abfahrtsHalt: from.lid,
zwischenhalte: opt.via
? [{id: profile.formatLocation(profile, opt.via, 'opt.via').lid}]
: null,
ankunftsHalt: to.lid,
produktgattungen: filters,
bikeCarriage: opt.bike,
// TODO
// todo: this is actually "take additional stations nearby the given start and destination station into account"
// see rest.exe docs
// ushrp: Boolean(opt.startWithWalking),
};
query.anfrageZeitpunkt = profile.formatTime(profile, when);
if (journeysRef) {
query.pagingReference = journeysRef;
}
query.ankunftSuche = outFrwd ? 'ABFAHRT' : 'ANKUNFT';
if (opt.results !== null) {
// TODO query.numF = opt.results;
}
query = Object.assign(query, ctx.profile.formatTravellers(ctx));
return {
endpoint: ctx.profile.journeysEndpoint,

View file

@ -11,8 +11,8 @@ const opt = {
results: null,
via: null,
stopovers: false,
transfers: -1,
transferTime: 0,
transfers: null,
transferTime: 0,
accessibility: 'none',
bike: false,
walkingSpeed: 'normal',
@ -59,6 +59,9 @@ const berlinWienQuery0 = Object.freeze(
reservierungsKontingenteVorhanden: false,
nurDeutschlandTicketVerbindungen: false,
deutschlandTicketVorhanden: false,
maxUmstiege: null,
zwischenhalte: null,
minUmstiegszeit: 0,
});
tap.test('formats a journeys() request correctly (DB)', (t) => {
@ -67,10 +70,7 @@ tap.test('formats a journeys() request correctly (DB)', (t) => {
delete _opt.age;
const ctx = {profile, opt: _opt};
// transformJourneysQuery() mutates its 2nd argument!
const query = {...berlinWienQuery0};
const req = profile.formatJourneysReq(ctx, query);
const req = profile.formatJourneysReq(ctx, '8098160', '8000284', new Date('2024-12-07T23:50:12+01:00'), true, null);
t.same(req.body, {
...berlinWienQuery0,
reisende: [
@ -94,9 +94,7 @@ tap.test('formats a journeys() request correctly (DB)', (t) => {
tap.test('formats a journeys() request with BC correctly (DB)', (t) => {
const ctx = {profile, opt};
// transformJourneysQuery() mutates its 2nd argument!
const query = {...berlinWienQuery0};
const req = profile.formatJourneysReq(ctx, query);
const req = profile.formatJourneysReq(ctx, '8098160', '8000284', new Date('2024-12-07T23:50:12+01:00'), true, null);
t.same(req.body, {
...berlinWienQuery0,