-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
compute-connections as async generator 💥
- Loading branch information
Showing
4 changed files
with
93 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,108 +1,73 @@ | ||
'use strict' | ||
|
||
const recordSort = require('sort-array-by-another') | ||
|
||
const inMemoryStore = require('./lib/in-memory-store') | ||
const readStopTimes = require('./lib/read-stop-times') | ||
const parseRelativeTime = require('./lib/parse-relative-time') | ||
const errorsWithRow = require('./lib/errors-with-row') | ||
|
||
const isObj = o => 'object' === typeof o && o !== null && !Array.isArray(o) | ||
|
||
const computeConnections = async (readFile, timezone, filters = {}, opt = {}) => { | ||
// todo: respect stopover.stop_timezone & agency.agency_timezone | ||
const computeConnections = async function* (readFile, filters = {}, opt = {}) { | ||
if ('function' !== typeof readFile) { | ||
throw new Error('readFile must be a function.') | ||
} | ||
|
||
if (!isObj(filters)) throw new Error('filters must be an object.') | ||
filters = { | ||
trip: () => true, | ||
stopover: () => true, | ||
stopTime: () => true, | ||
frequenciesRow: () => true, | ||
...filters, | ||
} | ||
if ('function' !== typeof filters.trip) { | ||
throw new Error('filters.trip must be a function.') | ||
} | ||
if ('function' !== typeof filters.stopover) { | ||
throw new Error('filters.stopover must be a function.') | ||
if ('function' !== typeof filters.stopTime) { | ||
throw new Error('filters.stopTime must be a function.') | ||
} | ||
|
||
const { | ||
createStore, | ||
} = { | ||
createStore: inMemoryStore, | ||
...opt, | ||
if ('function' !== typeof filters.frequenciesRow) { | ||
throw new Error('filters.frequenciesRow must be a function.') | ||
} | ||
|
||
const { | ||
stopsByTripId, | ||
arrivalsByTripId, | ||
departuresByTripId, | ||
headwayBasedStarts, headwayBasedEnds, headwayBasedHeadways, | ||
closeStores, | ||
} = await readStopTimes(readFile, filters, {createStore}) | ||
for await (const _ of readStopTimes(readFile, filters)) { | ||
const { | ||
tripId, | ||
stops, arrivals, departures, | ||
headwayBasedStarts: hwStarts, | ||
headwayBasedEnds: hwEnds, | ||
headwayBasedHeadways: hwHeadways, | ||
} = _ | ||
|
||
const generateConnectionsByTripId = async function* () { | ||
for await (const tripId of stopsByTripId.keys()) { | ||
const [ | ||
stops, | ||
arrivals, | ||
departures, | ||
hwStarts, | ||
hwEnds, | ||
hwHeadways, | ||
] = await Promise.all([ | ||
stopsByTripId.get(tripId), | ||
arrivalsByTripId.get(tripId), | ||
departuresByTripId.get(tripId), | ||
headwayBasedStarts.get(tripId), | ||
headwayBasedEnds.get(tripId), | ||
headwayBasedHeadways.get(tripId), | ||
]) | ||
const connections = [] | ||
const connections = [] | ||
|
||
// scheduled connections | ||
for (let i = 1; i < stops.length; i++) { | ||
connections.push({ | ||
tripId, | ||
fromStop: stops[i - 1], | ||
departure: departures[i - 1], | ||
toStop: stops[i], | ||
arrival: arrivals[i], | ||
}) | ||
} | ||
// scheduled connections | ||
for (let i = 1; i < stops.length; i++) { | ||
connections.push({ | ||
tripId, | ||
fromStop: stops[i - 1], | ||
departure: departures[i - 1], | ||
toStop: stops[i], | ||
arrival: arrivals[i], | ||
headwayBased: false, // todo: pick a more helpful flag name? | ||
}) | ||
} | ||
|
||
// headway-based connections | ||
// todo: DRY with compute-stopovers | ||
if (hwStarts) { | ||
const t0 = arrivals[0] | ||
for (let i = 0; i < hwStarts.length; i++) { | ||
for (let t = hwStarts[i]; t < hwEnds[i]; t += hwHeadways[i]) { | ||
for (let j = 1; j < stops.length; j++) { | ||
connections.push({ | ||
tripId, | ||
fromStop: stops[j - 1], | ||
departure: t + departures[j - 1] - t0, | ||
toStop: stops[j], | ||
arrival: t + arrivals[j] - t0, | ||
headwayBased: true, // todo: pick a more helpful flag? | ||
}) | ||
} | ||
} | ||
// headway-based connections | ||
// todo: DRY with compute-stopover-times | ||
const t0 = arrivals[0] | ||
const hwStartsL = hwStarts ? hwStarts.length : 0 | ||
for (let h = 0; h < hwStartsL; h++) { | ||
for (let t = hwStarts[h]; t < hwEnds[h]; t += hwHeadways[h]) { | ||
for (let i = 1; i < stops.length; i++) { | ||
connections.push({ | ||
tripId, | ||
fromStop: stops[i - 1], | ||
departure: t + departures[i - 1] - t0, | ||
toStop: stops[i], | ||
arrival: t + arrivals[i] - t0, | ||
headwayBased: true, // todo: pick a more helpful flag name? | ||
}) | ||
} | ||
} | ||
|
||
yield connections | ||
} | ||
|
||
await closeStores() | ||
yield connections | ||
} | ||
|
||
const out = {} | ||
out[Symbol.asyncIterator] = generateConnectionsByTripId | ||
out.closeStores = closeStores | ||
return out | ||
} | ||
|
||
module.exports = computeConnections |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters