mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-17 07:50:31 +00:00
Merge pull request #83 from brendan-ch/chore/sort-resolver-data
chore/sort-resolver-data
This commit is contained in:
@@ -12,7 +12,10 @@ export const ParkingSystemResolvers: Resolvers<ServerContext> = {
|
||||
if (!parkingRepository) return [];
|
||||
|
||||
const parkingStructures = await parkingRepository.getParkingStructures();
|
||||
return parkingStructures.map((structure) => {
|
||||
return parkingStructures
|
||||
.slice()
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((structure) => {
|
||||
return {
|
||||
...structure,
|
||||
systemId: parent.systemId
|
||||
|
||||
@@ -7,12 +7,15 @@ const GRAPHQL_SCHEMA_CURRENT_VERSION = 1;
|
||||
export const QueryResolvers: Resolvers<ServerContext> = {
|
||||
Query: {
|
||||
systems: async (_parent, args, contextValue, _info) => {
|
||||
return contextValue.systems.map((system) => {
|
||||
return {
|
||||
name: system.name,
|
||||
id: system.id,
|
||||
};
|
||||
})
|
||||
return contextValue.systems
|
||||
.slice()
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((system) => {
|
||||
return {
|
||||
name: system.name,
|
||||
id: system.id,
|
||||
};
|
||||
})
|
||||
},
|
||||
system: async (_parent, args, contextValue, _info) => {
|
||||
if (!args.id) return null;
|
||||
|
||||
@@ -9,7 +9,10 @@ export const RouteResolvers: Resolvers<ServerContext> = {
|
||||
|
||||
const shuttles = await system.shuttleRepository.getShuttlesByRouteId(parent.id);
|
||||
|
||||
return shuttles.map(({
|
||||
return shuttles
|
||||
.slice()
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map(({
|
||||
coordinates,
|
||||
name,
|
||||
id,
|
||||
@@ -51,7 +54,10 @@ export const RouteResolvers: Resolvers<ServerContext> = {
|
||||
if (!system) return null;
|
||||
|
||||
const orderedStops = await system.shuttleRepository.getOrderedStopsByRouteId(parent.id);
|
||||
return orderedStops.map(({ routeId, stopId, position, systemId, updatedTime }) => ({
|
||||
return orderedStops
|
||||
.slice()
|
||||
.sort((a, b) => a.position - b.position)
|
||||
.map(({ routeId, stopId, position, systemId, updatedTime }) => ({
|
||||
routeId,
|
||||
stopId,
|
||||
position,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ServerContext } from "../ServerContext";
|
||||
|
||||
export const ShuttleResolvers: Resolvers<ServerContext> = {
|
||||
Shuttle: {
|
||||
eta: async (parent, args, contextValue, info) => {
|
||||
eta: async (parent, args, contextValue, _) => {
|
||||
if (!args.forStopId) return null;
|
||||
|
||||
const system = contextValue.findSystemById(parent.systemId);
|
||||
@@ -21,7 +21,7 @@ export const ShuttleResolvers: Resolvers<ServerContext> = {
|
||||
updatedTimeMs: etaForStopId.updatedTime,
|
||||
};
|
||||
},
|
||||
etas: async (parent, args, contextValue, info) => {
|
||||
etas: async (parent, args, contextValue, _) => {
|
||||
const system = contextValue.findSystemById(parent.systemId);
|
||||
if (!system) return null;
|
||||
|
||||
@@ -45,12 +45,14 @@ export const ShuttleResolvers: Resolvers<ServerContext> = {
|
||||
}));
|
||||
|
||||
if (computedEtas.every((eta) => eta !== null)) {
|
||||
return computedEtas;
|
||||
return computedEtas
|
||||
.slice()
|
||||
.sort((a, b) => (a!.secondsRemaining - b!.secondsRemaining));
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
route: async (parent, args, contextValue, info) => {
|
||||
route: async (parent, args, contextValue, _) => {
|
||||
const system = contextValue.findSystemById(parent.systemId);
|
||||
if (!system) return null;
|
||||
|
||||
|
||||
@@ -8,14 +8,16 @@ export const StopResolvers: Resolvers<ServerContext> = {
|
||||
if (!system) {
|
||||
return [];
|
||||
}
|
||||
return await system.shuttleRepository.getOrderedStopsByStopId(parent.id);
|
||||
const orderedStops = await system.shuttleRepository.getOrderedStopsByStopId(parent.id);
|
||||
return orderedStops.slice().sort((a, b) => a.position - b.position);
|
||||
},
|
||||
etas: async (parent, args, contextValue, _info) => {
|
||||
const system = contextValue.findSystemById(parent.systemId);
|
||||
if (!system) {
|
||||
return [];
|
||||
}
|
||||
return await system.shuttleRepository.getEtasForStopId(parent.id);
|
||||
const etas = await system.shuttleRepository.getEtasForStopId(parent.id);
|
||||
return etas.slice().sort((a, b) => a.secondsRemaining - b.secondsRemaining);
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ export const SystemResolvers: Resolvers<ServerContext> = {
|
||||
return [];
|
||||
}
|
||||
|
||||
return await system.shuttleRepository.getRoutes();
|
||||
const routes = await system.shuttleRepository.getRoutes();
|
||||
return routes.slice().sort((a, b) => a.name.localeCompare(b.name));
|
||||
},
|
||||
stops: async (parent, _args, contextValue, _info) => {
|
||||
const system = contextValue.findSystemById(parent.id);
|
||||
@@ -17,7 +18,8 @@ export const SystemResolvers: Resolvers<ServerContext> = {
|
||||
return [];
|
||||
}
|
||||
|
||||
return await system.shuttleRepository.getStops();
|
||||
const stops = await system.shuttleRepository.getStops();
|
||||
return stops.slice().sort((a, b) => a.name.localeCompare(b.name));
|
||||
},
|
||||
stop: async (parent, args, contextValue, _info) => {
|
||||
if (!args.id) return null;
|
||||
@@ -78,7 +80,8 @@ export const SystemResolvers: Resolvers<ServerContext> = {
|
||||
return [];
|
||||
}
|
||||
|
||||
return await system.shuttleRepository.getShuttles();
|
||||
const shuttles = await system.shuttleRepository.getShuttles();
|
||||
return shuttles.slice().sort((a, b) => a.name.localeCompare(b.name));
|
||||
},
|
||||
parkingSystem: async (parent, _args, contextValue, _info) => {
|
||||
const system = contextValue.findSystemById(parent.id);
|
||||
|
||||
@@ -81,6 +81,49 @@ describe("ParkingSystemResolver", () => {
|
||||
|
||||
expect(parkingStructures).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns parking structures sorted by name", async () => {
|
||||
// Create two out-of-order structures by name
|
||||
const s1 = {
|
||||
id: "ps1",
|
||||
name: "Barrera",
|
||||
capacity: 100,
|
||||
spotsAvailable: 50,
|
||||
coordinates: { latitude: 0, longitude: 0 },
|
||||
address: "1 Anywhere",
|
||||
updatedTime: new Date(),
|
||||
};
|
||||
const s2 = {
|
||||
id: "ps2",
|
||||
name: "Anderson",
|
||||
capacity: 100,
|
||||
spotsAvailable: 50,
|
||||
coordinates: { latitude: 0, longitude: 0 },
|
||||
address: "2 Anywhere",
|
||||
updatedTime: new Date(),
|
||||
};
|
||||
await context.systems[0].parkingRepository?.addOrUpdateParkingStructure(s1);
|
||||
await context.systems[0].parkingRepository?.addOrUpdateParkingStructure(s2);
|
||||
|
||||
const minimalQuery = `
|
||||
query GetParkingStructuresBySystem($systemId: ID!) {
|
||||
system(id: $systemId) {
|
||||
parkingSystem {
|
||||
parkingStructures {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const response = await getResponseFromQueryNeedingSystemId(minimalQuery);
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const names = (response.body.singleResult.data as any).system.parkingSystem.parkingStructures.map((p: any) => p.name);
|
||||
expect(names).toEqual([s2.name, s1.name]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,41 @@ describe("QueryResolvers", () => {
|
||||
|
||||
expect(response.body.singleResult.data?.systems).toHaveLength(systems.length);
|
||||
});
|
||||
|
||||
it("returns systems sorted by name", async () => {
|
||||
const s1 = buildSystemForTesting();
|
||||
const s2 = buildSystemForTesting();
|
||||
const s3 = buildSystemForTesting();
|
||||
s1.name = "Chapman University";
|
||||
s1.id = "a";
|
||||
s2.name = "City of Monterey";
|
||||
s2.id = "b";
|
||||
s3.name = "Cal State Long Beach";
|
||||
s3.id = "c";
|
||||
|
||||
context.systems = [s1, s2, s3];
|
||||
|
||||
const query = `
|
||||
query GetSystems
|
||||
{
|
||||
systems {
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const response = await holder.testServer.executeOperation({
|
||||
query,
|
||||
}, {
|
||||
contextValue: context
|
||||
|
||||
});
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const names = (response.body.singleResult.data as any).systems.map((s: any) => s.name);
|
||||
expect(names).toEqual(["Cal State Long Beach", "Chapman University", "City of Monterey"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("system", () => {
|
||||
|
||||
@@ -79,6 +79,27 @@ describe("RouteResolvers", () => {
|
||||
any).system.route.shuttles;
|
||||
expect(shuttles.length).toEqual(0);
|
||||
});
|
||||
|
||||
it("returns shuttles sorted by name", async () => {
|
||||
const shuttles = generateMockShuttles();
|
||||
// use two shuttles for determinism
|
||||
const s1 = { ...shuttles[0], name: "Zed" };
|
||||
const s2 = { ...shuttles[1], name: "Alpha" };
|
||||
s1.systemId = mockSystem.id;
|
||||
s1.routeId = mockRoute.id;
|
||||
s2.systemId = mockSystem.id;
|
||||
s2.routeId = mockRoute.id;
|
||||
|
||||
await context.systems[0].shuttleRepository.addOrUpdateShuttle(s1);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateShuttle(s2);
|
||||
|
||||
const response = await getResponseForShuttlesQuery();
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined()
|
||||
const names = (response.body.singleResult.data as any).system.route.shuttles.map((s: any) => s.name);
|
||||
expect(names).toEqual(["Alpha", "Zed"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("orderedStop", () => {
|
||||
@@ -199,5 +220,22 @@ describe("RouteResolvers", () => {
|
||||
const retrievedOrderedStops = (response.body.singleResult.data as any).system.route.orderedStops;
|
||||
expect(retrievedOrderedStops).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns ordered stops sorted by position", async () => {
|
||||
const stops = generateMockOrderedStops().slice(0, 3).map((s) => ({ ...s }));
|
||||
// Force same routeId and distinct positions out of order
|
||||
stops[0].routeId = mockRoute.id; stops[0].position = 3; stops[0].stopId = "stA";
|
||||
stops[1].routeId = mockRoute.id; stops[1].position = 1; stops[1].stopId = "stB";
|
||||
stops[2].routeId = mockRoute.id; stops[2].position = 2; stops[2].stopId = "stC";
|
||||
await Promise.all(stops.map(s => context.systems[0].shuttleRepository.addOrUpdateOrderedStop(s)));
|
||||
|
||||
const response = await getResponseForOrderedStopsQuery();
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const stopIds = (response.body.singleResult.data as any).system.route.orderedStops.map((s: any) => s.stopId);
|
||||
const expectedOrder = [...stops].sort((a, b) => a.position - b.position).map(s => s.stopId);
|
||||
expect(stopIds).toEqual(expectedOrder);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -141,6 +141,31 @@ describe("ShuttleResolvers", () => {
|
||||
any).system.shuttle.etas).toHaveLength(0);
|
||||
|
||||
});
|
||||
|
||||
it("returns ETAs sorted by secondsRemaining", async () => {
|
||||
const e1 = { ...generateMockEtas()[0], shuttleId: mockShuttle.id, stopId: "stA", secondsRemaining: 300 };
|
||||
const e2 = { ...generateMockEtas()[0], shuttleId: mockShuttle.id, stopId: "stB", secondsRemaining: 30 };
|
||||
const e3 = { ...generateMockEtas()[0], shuttleId: mockShuttle.id, stopId: "stC", secondsRemaining: 120 };
|
||||
await context.systems[0].shuttleRepository.addOrUpdateEta(e1);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateEta(e2);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateEta(e3);
|
||||
|
||||
const response = await holder.testServer.executeOperation({
|
||||
query,
|
||||
variables: {
|
||||
systemId: mockSystem.id,
|
||||
shuttleId: mockShuttle.id,
|
||||
},
|
||||
}, {
|
||||
contextValue: context
|
||||
|
||||
});
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const seconds = (response.body.singleResult.data as any).system.shuttle.etas.map((e: any) => e.secondsRemaining);
|
||||
expect(seconds).toEqual([30, 120, 300]);
|
||||
});
|
||||
});
|
||||
describe("route", () => {
|
||||
const query = `
|
||||
|
||||
@@ -67,6 +67,25 @@ describe("StopResolvers", () => {
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
expect((response.body.singleResult.data as any).system.stop.orderedStops).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns ordered stops sorted by position", async () => {
|
||||
// Create three ordered stops with out-of-order positions and distinct routeIds
|
||||
const base = generateMockOrderedStops()[0];
|
||||
const o1 = { ...base, stopId: mockStop.id, routeId: "rA", position: 3 };
|
||||
const o2 = { ...base, stopId: mockStop.id, routeId: "rB", position: 1 };
|
||||
const o3 = { ...base, stopId: mockStop.id, routeId: "rC", position: 2 };
|
||||
await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(o1);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(o2);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(o3);
|
||||
|
||||
const response = await getResponseForQuery(query);
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const routeIds = (response.body.singleResult.data as any).system.stop.orderedStops.map((s: any) => s.routeId);
|
||||
const expectedOrder = [o2, o3, o1].map(s => s.routeId);
|
||||
expect(routeIds).toEqual(expectedOrder);
|
||||
});
|
||||
});
|
||||
|
||||
describe("etas", () => {
|
||||
@@ -104,5 +123,21 @@ describe("StopResolvers", () => {
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
expect((response.body.singleResult.data as any).system.stop.etas).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("returns ETAs sorted by secondsRemaining", async () => {
|
||||
const e1 = { ...generateMockEtas()[0], stopId: mockStop.id, shuttleId: "shA", secondsRemaining: 240 };
|
||||
const e2 = { ...generateMockEtas()[0], stopId: mockStop.id, shuttleId: "shB", secondsRemaining: 60 };
|
||||
const e3 = { ...generateMockEtas()[0], stopId: mockStop.id, shuttleId: "shC", secondsRemaining: 120 };
|
||||
await context.systems[0].shuttleRepository.addOrUpdateEta(e1);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateEta(e2);
|
||||
await context.systems[0].shuttleRepository.addOrUpdateEta(e3);
|
||||
|
||||
const response = await getResponseForQuery(query);
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const seconds = (response.body.singleResult.data as any).system.stop.etas.map((e: any) => e.secondsRemaining);
|
||||
expect(seconds).toEqual([60, 120, 240]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
generateMockRoutes,
|
||||
generateMockShuttles,
|
||||
generateMockStops,
|
||||
generateParkingStructures
|
||||
} from "../../../testHelpers/mockDataGenerators";
|
||||
import {
|
||||
addMockRouteToRepository,
|
||||
@@ -62,6 +61,23 @@ describe("SystemResolvers", () => {
|
||||
const routes = (response.body.singleResult.data as any).system.routes;
|
||||
expect(routes.length === expectedRoutes.length);
|
||||
});
|
||||
|
||||
it("returns routes sorted by name", async () => {
|
||||
const routes = generateMockRoutes();
|
||||
// Insert in reverse name order to verify sorting
|
||||
const reversed = [...routes].sort((a, b) => b.name.localeCompare(a.name));
|
||||
await Promise.all(reversed.map(async (route) => {
|
||||
route.systemId = mockSystem.id;
|
||||
await context.systems[0].shuttleRepository.addOrUpdateRoute(route);
|
||||
}));
|
||||
|
||||
const response = await getResponseFromQueryNeedingSystemId(query);
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const names = (response.body.singleResult.data as any).system.routes.map((r: any) => r.name);
|
||||
expect(names).toEqual([...routes].sort((a, b) => a.name.localeCompare(b.name)).map(r => r.name));
|
||||
});
|
||||
});
|
||||
|
||||
describe("stops", () => {
|
||||
@@ -90,6 +106,22 @@ describe("SystemResolvers", () => {
|
||||
const stops = (response.body.singleResult.data as any).system.stops;
|
||||
expect(stops.length === expectedStops.length);
|
||||
});
|
||||
|
||||
it("returns stops sorted by name", async () => {
|
||||
const stops = generateMockStops();
|
||||
const reversed = [...stops].sort((a, b) => b.name.localeCompare(a.name));
|
||||
await Promise.all(reversed.map(async (stop) => {
|
||||
stop.systemId = mockSystem.id;
|
||||
await context.systems[0].shuttleRepository.addOrUpdateStop(stop);
|
||||
}));
|
||||
|
||||
const response = await getResponseFromQueryNeedingSystemId(query);
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const names = (response.body.singleResult.data as any).system.stops.map((s: any) => s.name);
|
||||
expect(names).toEqual([...stops].sort((a, b) => a.name.localeCompare(b.name)).map(s => s.name));
|
||||
});
|
||||
});
|
||||
|
||||
describe("stop", () => {
|
||||
@@ -312,6 +344,22 @@ describe("SystemResolvers", () => {
|
||||
const shuttles = (response.body.singleResult.data as any).system.shuttles;
|
||||
expect(shuttles.length === expectedShuttles.length);
|
||||
});
|
||||
|
||||
it("returns shuttles sorted by name", async () => {
|
||||
const shuttles = generateMockShuttles();
|
||||
const reversed = [...shuttles].sort((a, b) => b.name.localeCompare(a.name));
|
||||
await Promise.all(reversed.map(async (shuttle) => {
|
||||
shuttle.systemId = mockSystem.id;
|
||||
await context.systems[0].shuttleRepository.addOrUpdateShuttle(shuttle);
|
||||
}));
|
||||
|
||||
const response = await getResponseFromQueryNeedingSystemId(query);
|
||||
|
||||
assert(response.body.kind === "single");
|
||||
expect(response.body.singleResult.errors).toBeUndefined();
|
||||
const names = (response.body.singleResult.data as any).system.shuttles.map((s: any) => s.name);
|
||||
expect(names).toEqual([...shuttles].sort((a, b) => a.name.localeCompare(b.name)).map(s => s.name));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user