From 352bff923a38754dac65de87197b55c0cdaed153 Mon Sep 17 00:00:00 2001 From: Albert Alises Date: Fri, 23 Oct 2020 17:05:36 +0200 Subject: [PATCH] feat(queries): add filter stations by line --- README.md | 12 ++++++- schema.graphql | 10 +++++- src/datasources/MetroDataSource.ts | 15 +++++--- .../__tests__/MetroDataSource.test.ts | 7 ++-- src/inputs/FilterByInput.ts | 15 ++++++++ src/queries/MetroStationsQuery.ts | 36 +++++++++++-------- types/index.d.ts | 7 ++++ 7 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 src/inputs/FilterByInput.ts diff --git a/README.md b/README.md index fe48ca9..7774f76 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,28 @@ It provides information about bus stops and lines, metro stations/lines, and pub ### Feature Roadmap / Checklist for v1.0.0 +#### Metro ✅ + - [x] `metroStation` query with information about one metro station (find by name or id) - [x] `metroStations` query with information about metro stations - [x] `metroLine` query with information about one metro line (find by name or id) - [x] `metroLines` query with information about metro lines +- [x] Add filtering of the stations by line ID or name + +#### Bus + - [ ] `busStops` query with information about bus stops - [ ] `busStop` query with information about one bus stop (find by name or id) - [ ] `busLines` query with information about bus lines - [ ] `busLine` query with information about a bus line (find by name or id) + +#### Bike + - [ ] `bikeStations` query with information about bike stations - [ ] `bikeStation` query with information about one bike station (find by name or id) - [ ] Add bike availability information to the `bikeStations` query -- [ ] Add filtering of the stations by line ID or name (cannot do it on BusStops) + +#### Tram ## GraphQL Playground 🚀 diff --git a/schema.graphql b/schema.graphql index ef00a6b..be92ccc 100644 --- a/schema.graphql +++ b/schema.graphql @@ -4,7 +4,7 @@ schema { """Root Query""" type RootQuery { - metroStations(after: String, first: Int, before: String, last: Int): MetroStations + metroStations(after: String, first: Int, before: String, last: Int, filterBy: FilterByInput): MetroStations metroStation(findBy: FindByInput!): MetroStation metroLine(findBy: FindByInput!): MetroLine metroLines(after: String, first: Int, before: String, last: Int): MetroLines @@ -74,6 +74,14 @@ type Coordinates { altitude: Float } +""" +Input for the filterBy argument of the queries, which allows filtering a connection by some parameters (e.g. lineName or lineId) +""" +input FilterByInput { + lineId: Int + lineName: String +} + """ Input for the FindBy argument of the queries, which allows finding an entity by some parameters (e.g. name or id) """ diff --git a/src/datasources/MetroDataSource.ts b/src/datasources/MetroDataSource.ts index c550316..7c85a16 100644 --- a/src/datasources/MetroDataSource.ts +++ b/src/datasources/MetroDataSource.ts @@ -1,6 +1,7 @@ import TmbApiDataSource from "./TmbApiDataSource"; import type { FindByInput, + FilterByInput, MetroStation as MetroStationType, MetroLine as MetroLineType, } from "../../types"; @@ -167,7 +168,10 @@ export default class MetroDataSource extends TmbApiDataSource { async getLineStations({ id, name, - }: FindByInput): Promise { + }: FindByInput): Promise<{ + numberOfStations: number | null; + stations: MetroStationType[]; + }> { const path = ["linies/metro", id, "estacions"].filter(Boolean).join("/"); const nameFilterParameter = name ? { filter: `NOM_LINIA='${name}'` } : {}; @@ -177,7 +181,10 @@ export default class MetroDataSource extends TmbApiDataSource { response?.features?.map((station) => this.metroStationReducer(station)) ?? []; - return stations; + return { + numberOfStations: response?.numberReturned ?? null, + stations, + }; } async getLine({ id, name }: FindByInput): Promise { @@ -209,7 +216,7 @@ export default class MetroDataSource extends TmbApiDataSource { return new ApolloError("The line object returned did not exist"); } - const stations = await this.getLineStations({ id, name }); + const { stations } = await this.getLineStations({ id, name }); return { ...line, @@ -232,7 +239,7 @@ export default class MetroDataSource extends TmbApiDataSource { const lines = await Promise.all( (response?.features ?? []).map(async (line: MetroLineAPIType) => { const reducedLine = this.metroLineReducer(line); - const stations = await this.getLineStations({ + const { stations } = await this.getLineStations({ id: reducedLine.id, name: reducedLine.name, }); diff --git a/src/datasources/__tests__/MetroDataSource.test.ts b/src/datasources/__tests__/MetroDataSource.test.ts index 10091ef..0589c61 100644 --- a/src/datasources/__tests__/MetroDataSource.test.ts +++ b/src/datasources/__tests__/MetroDataSource.test.ts @@ -15,9 +15,10 @@ describe("MetroDataSource", () => { const mockGet = jest.fn(); MetroDataSource.get = mockGet; - MetroDataSource.getLineStations = jest - .fn() - .mockReturnValue(mockMetroLinesResponse.lines[0].stations); + MetroDataSource.getLineStations = jest.fn().mockReturnValue({ + numberOfStations: 5, + stations: mockMetroLinesResponse.lines[0].stations, + }); describe("[getAllLines]", () => { it("Correctly looks up the lines from the API", async () => { diff --git a/src/inputs/FilterByInput.ts b/src/inputs/FilterByInput.ts new file mode 100644 index 0000000..5cf8f47 --- /dev/null +++ b/src/inputs/FilterByInput.ts @@ -0,0 +1,15 @@ +import { GraphQLInt, GraphQLInputObjectType, GraphQLString } from "graphql"; + +export default new GraphQLInputObjectType({ + name: "FilterByInput", + description: + "Input for the filterBy argument of the queries, which allows filtering a connection by some parameters (e.g. lineName or lineId)", + fields: { + lineId: { + type: GraphQLInt, + }, + lineName: { + type: GraphQLString, + }, + }, +}); diff --git a/src/queries/MetroStationsQuery.ts b/src/queries/MetroStationsQuery.ts index c0a0257..e74a37c 100644 --- a/src/queries/MetroStationsQuery.ts +++ b/src/queries/MetroStationsQuery.ts @@ -1,14 +1,11 @@ -import { - connectionArgs, - ConnectionArguments, - connectionFromArray, -} from "graphql-relay"; +import { connectionArgs, connectionFromArray } from "graphql-relay"; import type { MetroStations as MetroStationsType, MetroStationConnection as MetroStationConnectionType, } from "../../types"; import { MetroStationConnection } from "../outputs/MetroStation"; import { GraphQLObjectType, GraphQLInt } from "graphql"; +import filterByInput from "../inputs/FilterByInput"; const MetroStations = new GraphQLObjectType({ name: "MetroStations", @@ -27,16 +24,25 @@ const MetroStations = new GraphQLObjectType({ export default { type: MetroStations, - args: connectionArgs, - resolve: async ( - _, - args: ConnectionArguments, - { dataSources } - ): Promise => { - const { - numberOfStations, - stations, - } = await dataSources.metro.getAllStations(); + args: { + ...connectionArgs, + filterBy: { + type: filterByInput, + }, + }, + resolve: async (_, args, { dataSources }): Promise => { + const { filterBy } = args; + + const { numberOfStations, stations } = await (async () => { + //We get all the stations if no filter provided, if not we get the lines stations + if (!filterBy?.lineId && !filterBy?.lineName) { + return await dataSources.metro.getAllStations(); + } + return await dataSources.metro.getLineStations({ + id: filterBy?.lineId ?? null, + name: filterBy?.lineName ?? null, + }); + })(); return { numberOfStations, diff --git a/types/index.d.ts b/types/index.d.ts index c351064..2d1656e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -25,6 +25,7 @@ export type RootQueryMetroStationsArgs = { first?: Maybe; before?: Maybe; last?: Maybe; + filterBy?: Maybe; }; @@ -109,6 +110,12 @@ export type Coordinates = { altitude?: Maybe; }; +/** Input for the filterBy argument of the queries, which allows filtering a connection by some parameters (e.g. lineName or lineId) */ +export type FilterByInput = { + lineId?: Maybe; + lineName?: Maybe; +}; + /** Input for the FindBy argument of the queries, which allows finding an entity by some parameters (e.g. name or id) */ export type FindByInput = { id?: Maybe;