nextbus-graphql
Version:
A GraphQL interface to the NextBus XML Feed
71 lines (63 loc) • 1.98 kB
JavaScript
// @flow
import DataLoader from 'dataloader';
import memoize from 'memoize-id';
import nextbus from 'nextbus';
import type {
Agency as NBAgency,
Route as NBRoute,
RouteConfig as NBRouteConfig,
} from 'nextbus';
export type Agency = NBAgency;
export type Route = NBRoute & {
agencyTag: string,
};
export type RouteConfig = NBRouteConfig & {
agencyTag: string,
};
const nb = nextbus({
onRequest(uri) {
console.info('Request to NextBus:', uri);
},
});
export default function () {
const getAgencies = memoize(nb.getAgencies);
const agencyLoader = new DataLoader(async (agencyTags: string[]): Promise<Agency[]> => {
const agencies = await getAgencies();
return agencyTags.map(
tag => (
agencies.find(agency => agency.tag === tag) ||
new Error(`No agency with tag: "${tag}"`)
),
);
});
const routeLoader = new DataLoader(
(agencyTags: string[]): Promise<Array<Route[]>> => Promise.all(agencyTags.map(
async (agencyTag) => {
const routes = await nb.getRoutes(agencyTag);
return routes.map(route => ({ ...route, agencyTag }));
},
)),
);
const routeConfigLoader = new DataLoader((compositeKeys: string[]) => Promise.all(
compositeKeys.map(async (compositeKey: string) => {
const [agencyTag, routeTag] = compositeKey.split(':');
return { ...(await nb.getRoute(agencyTag, routeTag)), agencyTag };
}),
));
return {
async getAgencies(): Promise<Agency[]> {
const agencies = await getAgencies();
agencies.forEach(agency => agencyLoader.prime(agency.tag, agency));
return agencies;
},
getAgency(tag: string): Promise<Agency> {
return agencyLoader.load(tag);
},
getRoutes(agencyTag: string): Promise<Route[]> {
return routeLoader.load(agencyTag);
},
getRoute(agencyTag: string, routeTag: string): Promise<RouteConfig> {
return routeConfigLoader.load(`${agencyTag}:${routeTag}`);
},
};
}