Merge pull request #13 from brendan-ch/chore/update-graphql-schema-to-include-ids

chore/update-graphql-schema-to-include-ids
This commit is contained in:
2025-01-23 16:18:00 -08:00
committed by GitHub
11 changed files with 279 additions and 280 deletions

19
src/MergedResolvers.ts Normal file
View File

@@ -0,0 +1,19 @@
import { Coordinates, Eta, OrderedStop, Resolvers } from "./generated/graphql";
import { ServerContext } from "./ServerContext";
import { QueryResolvers } from "./resolvers/QueryResolvers";
import { SystemResolvers } from "./resolvers/SystemResolvers";
import { EtaResolvers } from "./resolvers/EtaResolvers";
import { OrderedStopResolvers } from "./resolvers/OrderedStopResolvers";
import { StopResolvers } from "./resolvers/StopResolvers";
import { ShuttleResolvers } from "./resolvers/ShuttleResolvers";
import { RouteResolvers } from "./resolvers/RouteResolvers";
export const MergedResolvers: Resolvers<ServerContext> = {
...QueryResolvers,
...SystemResolvers,
...RouteResolvers,
...ShuttleResolvers,
...StopResolvers,
...OrderedStopResolvers,
...EtaResolvers,
};

View File

@@ -1,7 +1,7 @@
import { readFileSync } from "fs";
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { resolvers } from "./resolvers";
import { MergedResolvers } from "./MergedResolvers";
import { ServerContext } from "./ServerContext";
import { UnoptimizedInMemoryRepository } from "./repositories/UnoptimizedInMemoryRepository";
import { TimedApiBasedRepositoryLoader } from "./loaders/TimedApiBasedRepositoryLoader";
@@ -11,7 +11,7 @@ const typeDefs = readFileSync("./schema.graphqls", "utf8");
async function main() {
const server = new ApolloServer<ServerContext>({
typeDefs,
resolvers,
resolvers: MergedResolvers,
introspection: process.env.NODE_ENV !== "production",
});

View File

@@ -1,274 +0,0 @@
import { Coordinates, Eta, OrderedStop, Resolvers, Route, Shuttle, Stop, System } from "./generated/graphql";
import { ServerContext } from "./ServerContext";
export const resolvers: Resolvers<ServerContext> = {
Query: {
systems: async (parent, args, contextValue, info) => {
const systems = await contextValue.repository.getSystems();
return systems.map(({
name,
id
}) => ({
name,
id
}));
},
system: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const system = await contextValue.repository.getSystemById(args.id);
if (system === null) return null;
return {
name: system.name,
id: system.id,
};
}
},
System: {
routes: async (parent, args, contextValue, info) => {
const routes = await contextValue.repository.getRoutesBySystemId(parent.id);
return routes.map(({
color,
id,
name,
polylineCoordinates,
}) => ({
color,
id,
name,
polylineCoordinates,
}));
},
stops: async (parent, args, contextValue, info) => {
const stops = await contextValue.repository.getStopsBySystemId(parent.id);
return stops.map(({
id,
name,
coordinates
}) => ({
id,
name,
// Both ICoordinates and Coordinates have the same definition
coordinates: coordinates as Coordinates,
}));
},
stop: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const stop = await contextValue.repository.getStopById(args.id);
if (stop === null) return null;
return {
id: stop.id,
name: stop.name,
coordinates: stop.coordinates as Coordinates,
};
},
route: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const route = await contextValue.repository.getRouteById(args.id);
if (route === null) return null;
return {
color: route.color,
id: route.id,
name: route.name,
polylineCoordinates: route.polylineCoordinates as Coordinates[],
};
},
shuttle: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const shuttle = await contextValue.repository.getShuttleById(args.id);
if (shuttle === null) return null;
return {
coordinates: shuttle.coordinates as Coordinates,
id: shuttle.id,
name: shuttle.name,
};
},
shuttles: async (parent, args, contextValue, info) => {
const shuttles = await contextValue.repository.getShuttlesBySystemId(parent.id);
return shuttles.map(shuttle => ({
coordinates: shuttle.coordinates,
name: shuttle.name,
id: shuttle.id,
}));
}
},
Route: {
shuttles: async (parent, args, contextValue, info) => {
const shuttles = await contextValue.repository.getShuttlesByRouteId(parent.id);
return shuttles.map(({
coordinates,
name,
id,
}) => ({
coordinates: coordinates as Coordinates,
name,
route: parent,
id,
}));
},
orderedStop: async (parent, args, contextValue, info) => {
if (!args.forStopId) return null;
const orderedStop = await contextValue.repository.getOrderedStopByRouteAndStopId(parent.id, args.forStopId);
if (!orderedStop) return null;
const stop = await contextValue.repository.getStopById(orderedStop.stopId);
if (!stop) return null;
return {
stop: {
id: stop.id,
name: stop.name,
coordinates: stop.coordinates as Coordinates,
},
route: parent,
}
},
},
Shuttle: {
eta: async (parent, args, contextValue, info) => {
if (!args.forStopId) return null;
const etaForStopId = await contextValue.repository.getEtaForShuttleAndStopId(parent.id, args.forStopId);
if (etaForStopId === null) return null;
const stop = await contextValue.repository.getStopById(etaForStopId.stopId);
if (stop === null) return null;
return {
stop: {
coordinates: stop.coordinates,
id: stop.id,
name: stop.name,
},
secondsRemaining: etaForStopId.secondsRemaining,
shuttle: parent,
};
},
etas: async (parent, args, contextValue, info) => {
const etasForShuttle = await contextValue.repository.getEtasForShuttleId(parent.id);
if (!etasForShuttle) return null;
const computedEtas = await Promise.all(etasForShuttle.map(async ({
secondsRemaining,
stopId,
}): Promise<Eta | null> => {
const stop = await contextValue.repository.getStopById(stopId);
if (stop === null) return null;
return {
secondsRemaining,
stop: {
coordinates: stop.coordinates,
id: stop.id,
name: stop.name,
},
shuttle: parent,
}
}));
if (computedEtas.every((eta) => eta !== null)) {
return computedEtas;
}
return [];
},
route: async (parent, args, contextValue, info) => {
const shuttle = await contextValue.repository.getShuttleById(parent.id);
if (shuttle === null) return null;
const route = await contextValue.repository.getRouteById(shuttle?.routeId);
if (route === null) return null;
return {
color: route.color,
id: route.id,
name: route.name,
polylineCoordinates: route.polylineCoordinates,
}
}
},
Stop: {
orderedStops: async (parent, args, contextValue, info) => {
const orderedStops = await contextValue.repository.getOrderedStopsByStopId(parent.id);
const computedOrderedStops = await Promise.all(orderedStops.map(async ({
routeId,
stopId,
}): Promise<OrderedStop | null> => {
const stop = await contextValue.repository.getStopById(stopId);
const route = await contextValue.repository.getRouteById(routeId);
if (stop === null || route === null) return null;
return {
stop: {
coordinates: stop.coordinates,
id: stop.id,
name: stop.name,
},
route: {
name: route.name,
id: route.id,
polylineCoordinates: route.polylineCoordinates,
color: route.color,
},
};
}));
if (computedOrderedStops.every((value) => value !== null)) {
return computedOrderedStops as OrderedStop[];
}
return [];
}
},
OrderedStop: {
nextStop: async (parent, args, contextValue, info): Promise<OrderedStop | null> => {
const routeId = parent.route.id;
const stopId = parent.stop.id;
const currentOrderedStop = await contextValue.repository.getOrderedStopByRouteAndStopId(routeId, stopId);
if (!currentOrderedStop) return null;
const nextOrderedStop = currentOrderedStop.nextStop;
if (!nextOrderedStop) return null;
const nextStopObject = await contextValue.repository.getStopById(nextOrderedStop.stopId);
if (!nextStopObject) return null;
return {
route: parent.route,
stop: {
coordinates: nextStopObject.coordinates as Coordinates,
id: nextStopObject.id,
name: nextStopObject.name,
}
}
},
previousStop: async (parent, args, contextValue, info): Promise<OrderedStop | null> => {
const routeId = parent.route.id;
const stopId = parent.stop.id;
const currentOrderedStop = await contextValue.repository.getOrderedStopByRouteAndStopId(routeId, stopId);
if (!currentOrderedStop) return null;
const previousOrderedStop = currentOrderedStop.previousStop;
if (!previousOrderedStop) return null;
const nextStopObject = await contextValue.repository.getStopById(previousOrderedStop.stopId);
if (!nextStopObject) return null;
return {
route: parent.route,
stop: {
coordinates: nextStopObject.coordinates as Coordinates,
id: nextStopObject.id,
name: nextStopObject.name,
}
}
},
},
};

View File

@@ -0,0 +1,13 @@
import { Resolvers } from "../generated/graphql";
import { ServerContext } from "../ServerContext";
export const EtaResolvers: Resolvers<ServerContext> = {
ETA: {
stop: async (parent, args, contextValue, info) => {
return await contextValue.repository.getStopById(parent.stopId);
},
shuttle: async (parent, args, contextValue, info) => {
return await contextValue.repository.getShuttleById(parent.shuttleId);
},
},
}

View File

@@ -0,0 +1,52 @@
import { OrderedStop, Resolvers } from "../generated/graphql";
import { ServerContext } from "../ServerContext";
export const OrderedStopResolvers: Resolvers<ServerContext> = {
OrderedStop: {
nextStop: async (parent, args, contextValue, info): Promise<OrderedStop | null> => {
const routeId = parent.routeId;
const stopId = parent.stopId;
const currentOrderedStop = await contextValue.repository.getOrderedStopByRouteAndStopId(routeId, stopId);
if (!currentOrderedStop) return null;
const nextOrderedStop = currentOrderedStop.nextStop;
if (!nextOrderedStop) return null;
const nextOrderedStopObject = await contextValue.repository.getStopById(nextOrderedStop.stopId);
if (!nextOrderedStopObject) return null;
return {
route: parent.route,
routeId: parent.routeId,
stopId: nextOrderedStopObject.id,
}
},
previousStop: async (parent, args, contextValue, info): Promise<OrderedStop | null> => {
const routeId = parent.routeId;
const stopId = parent.stopId;
const currentOrderedStop = await contextValue.repository.getOrderedStopByRouteAndStopId(routeId, stopId);
if (!currentOrderedStop) return null;
const previousOrderedStop = currentOrderedStop.previousStop;
if (!previousOrderedStop) return null;
const previousOrderedStopObject = await contextValue.repository.getStopById(previousOrderedStop.stopId);
if (!previousOrderedStopObject) return null;
return {
route: parent.route,
routeId: parent.routeId,
stopId: previousOrderedStopObject.id,
}
},
stop: async (parent, args, contextValue, info) => {
return await contextValue.repository.getStopById(parent.stopId);
},
route: async (parent, args, contextValue, info) => {
return await contextValue.repository.getRouteById(parent.routeId);
},
},
}

View File

@@ -0,0 +1,20 @@
import { ServerContext } from "../ServerContext";
import { Resolvers } from "../generated/graphql";
export const QueryResolvers: Resolvers<ServerContext> = {
Query: {
systems: async (parent, args, contextValue, info) => {
return await contextValue.repository.getSystems();
},
system: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const system = await contextValue.repository.getSystemById(args.id);
if (system === null) return null;
return {
name: system.name,
id: system.id,
};
}
},
}

View File

@@ -0,0 +1,36 @@
import { Coordinates, Resolvers } from "../generated/graphql";
import { ServerContext } from "../ServerContext";
export const RouteResolvers: Resolvers<ServerContext> = {
Route: {
shuttles: async (parent, args, contextValue, info) => {
const shuttles = await contextValue.repository.getShuttlesByRouteId(parent.id);
return shuttles.map(({
coordinates,
name,
id,
}) => ({
coordinates: coordinates as Coordinates,
name,
route: parent,
routeId: parent.id,
id,
}));
},
orderedStop: async (parent, args, contextValue, info) => {
if (!args.forStopId) return null;
const orderedStop = await contextValue.repository.getOrderedStopByRouteAndStopId(parent.id, args.forStopId);
if (!orderedStop) return null;
const stop = await contextValue.repository.getStopById(orderedStop.stopId);
if (!stop) return null;
return {
stopId: args.forStopId,
routeId: parent.id,
route: parent,
}
},
},
}

View File

@@ -0,0 +1,52 @@
import { Eta, Resolvers } from "../generated/graphql";
import { ServerContext } from "../ServerContext";
export const ShuttleResolvers: Resolvers<ServerContext> = {
Shuttle: {
eta: async (parent, args, contextValue, info) => {
if (!args.forStopId) return null;
const etaForStopId = await contextValue.repository.getEtaForShuttleAndStopId(parent.id, args.forStopId);
if (etaForStopId === null) return null;
return {
stopId: args.forStopId,
secondsRemaining: etaForStopId.secondsRemaining,
shuttleId: parent.id,
shuttle: parent,
};
},
etas: async (parent, args, contextValue, info) => {
const etasForShuttle = await contextValue.repository.getEtasForShuttleId(parent.id);
if (!etasForShuttle) return null;
const computedEtas = await Promise.all(etasForShuttle.map(async ({
secondsRemaining,
stopId,
}): Promise<Eta | null> => {
return {
secondsRemaining,
stopId,
shuttle: parent,
shuttleId: parent.id,
}
}));
if (computedEtas.every((eta) => eta !== null)) {
return computedEtas;
}
return [];
},
route: async (parent, args, contextValue, info) => {
const route = await contextValue.repository.getRouteById(parent.routeId);
if (route === null) return null;
return {
color: route.color,
id: route.id,
name: route.name,
polylineCoordinates: route.polylineCoordinates,
}
}
},
}

View File

@@ -0,0 +1,13 @@
import { Resolvers } from "../generated/graphql";
import { ServerContext } from "../ServerContext";
export const StopResolvers: Resolvers<ServerContext> = {
Stop: {
orderedStops: async (parent, args, contextValue, info) => {
return await contextValue.repository.getOrderedStopsByStopId(parent.id);
},
etas: async (parent, args, contextValue, info) => {
return await contextValue.repository.getEtasForStopId(parent.id);
},
},
}

View File

@@ -0,0 +1,63 @@
import { Coordinates, Resolvers } from "../generated/graphql";
import { ServerContext } from "../ServerContext";
export const SystemResolvers: Resolvers<ServerContext> = {
System: {
routes: async (parent, args, contextValue, info) => {
return await contextValue.repository.getRoutesBySystemId(parent.id);
},
stops: async (parent, args, contextValue, info) => {
const stops = await contextValue.repository.getStopsBySystemId(parent.id);
return stops.map(({
id,
name,
coordinates
}) => ({
id,
name,
// Both ICoordinates and Coordinates have the same definition
coordinates: coordinates as Coordinates,
}));
},
stop: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const stop = await contextValue.repository.getStopById(args.id);
if (stop === null) return null;
return {
id: stop.id,
name: stop.name,
coordinates: stop.coordinates as Coordinates,
};
},
route: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const route = await contextValue.repository.getRouteById(args.id);
if (route === null) return null;
return {
color: route.color,
id: route.id,
name: route.name,
polylineCoordinates: route.polylineCoordinates as Coordinates[],
};
},
shuttle: async (parent, args, contextValue, info) => {
if (!args.id) return null;
const shuttle = await contextValue.repository.getShuttleById(args.id);
if (shuttle === null) return null;
return shuttle;
},
shuttles: async (parent, args, contextValue, info) => {
const shuttles = await contextValue.repository.getShuttlesBySystemId(parent.id);
return shuttles.map(shuttle => ({
coordinates: shuttle.coordinates,
name: shuttle.name,
id: shuttle.id,
routeId: shuttle.routeId,
}));
}
},
}