Skip to content

Commit

Permalink
Merge pull request #60 from wearefuturegov/develop
Browse files Browse the repository at this point in the history
TOP-203 regular schedules #148
  • Loading branch information
apricot13 authored Sep 5, 2024
2 parents f8c3001 + fe719bc commit a7c0bc9
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 16 deletions.
91 changes: 91 additions & 0 deletions __tests__/unit/lib/filters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,94 @@ describe("filterDays", () => {
expect(filters.filterDays(days)).toEqual(expectedQuery)
})
})

describe("filterStartTimeEndTimeDay", () => {
it("should return a query object if start_time, end_time, and day are provided", () => {
const startTime = ["22:00"]
const endTime = ["22:30"]
const day = ["Monday"]
const expectedQuery = {
$or: [
{
"regular_schedules.opens_at": { $gte: "22:00" },
"regular_schedules.closes_at": { $lte: "22:30" },
"regular_schedules.weekday": "Monday",
},
],
}
expect(filters.filterStartTimeEndTimeDay(startTime, endTime, day)).toEqual(
expectedQuery
)
})

it("should return a query object if only start_time is provided", () => {
const startTime = ["22:00"]
const endTime = []
const day = []
const expectedQuery = {
$or: [
{
"regular_schedules.opens_at": { $gte: "22:00" },
},
],
}
expect(filters.filterStartTimeEndTimeDay(startTime, endTime, day)).toEqual(
expectedQuery
)
})

it("should return a query object if only end_time is provided", () => {
const startTime = []
const endTime = ["22:30"]
const day = []
const expectedQuery = {
$or: [
{
"regular_schedules.closes_at": { $lte: "22:30" },
},
],
}
expect(filters.filterStartTimeEndTimeDay(startTime, endTime, day)).toEqual(
expectedQuery
)
})

it("should return a query object if only day is provided", () => {
const startTime = []
const endTime = []
const day = ["Monday"]
const expectedQuery = {
$or: [
{
"regular_schedules.weekday": "Monday",
},
],
}
expect(filters.filterStartTimeEndTimeDay(startTime, endTime, day)).toEqual(
expectedQuery
)
})

it("should return a query object if multiple sets of start_time, end_time, and day are provided", () => {
const startTime = ["22:00", "22:00"]
const endTime = ["22:30", "22:30"]
const day = ["Monday", "Monday"]
const expectedQuery = {
$or: [
{
"regular_schedules.opens_at": { $gte: "22:00" },
"regular_schedules.closes_at": { $lte: "22:30" },
"regular_schedules.weekday": "Monday",
},
{
"regular_schedules.opens_at": { $gte: "22:00" },
"regular_schedules.closes_at": { $lte: "22:30" },
"regular_schedules.weekday": "Monday",
},
],
}
expect(filters.filterStartTimeEndTimeDay(startTime, endTime, day)).toEqual(
expectedQuery
)
})
})
106 changes: 98 additions & 8 deletions __tests__/unit/v1/services/routes/get-services.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ describe("get-services", () => {
taxonomies: [],
needs: [],
suitabilities: [],
days: [],
daysDeprecated: [],
startTime: [],
endTime: [],
day: [],
accessibilities: [],
only: [],
minAge: undefined,
Expand Down Expand Up @@ -268,22 +271,109 @@ describe("get-services", () => {
})
})

describe("days", () => {
describe("daysDeprecated", () => {
it("should return undefined if days are not provided", async () => {
const { days } = await parseRequestParameters({})
expect(days).toEqual([])
const { daysDeprecated } = await parseRequestParameters({})
expect(daysDeprecated).toEqual([])
})
it("should return a unique array multiple targets are passed through", async () => {
const { days } = await parseRequestParameters({
const { daysDeprecated } = await parseRequestParameters({
days: ["a", "b,a"],
})
expect(new Set(days)).toEqual(new Set(["a", "b"]))
expect(new Set(daysDeprecated)).toEqual(new Set(["a", "b"]))
})
it("should return a unique array one target is passed through", async () => {
const { days } = await parseRequestParameters({
const { daysDeprecated } = await parseRequestParameters({
days: ["a,b"],
})
expect(new Set(days)).toEqual(new Set(["a", "b"]))
expect(new Set(daysDeprecated)).toEqual(new Set(["a", "b"]))
})
})

describe("startTime", () => {
it("should return undefined if days are not provided", async () => {
const { startTime } = await parseRequestParameters({})
expect(startTime).toEqual([])
})
it("should return a non unique array multiple targets are passed through", async () => {
const { startTime } = await parseRequestParameters({
start_time: ["10:00", "10:00,11:00"],
})
expect(startTime).toEqual(["10:00", "10:00", "11:00"])
})
it("should return a non unique array one target is passed through", async () => {
const { startTime } = await parseRequestParameters({
start_time: ["10:00,10:00,11:00"],
})
expect(startTime).toEqual(["10:00", "10:00", "11:00"])
})
})

describe("endTime", () => {
it("should return undefined if days are not provided", async () => {
const { endTime } = await parseRequestParameters({})
expect(endTime).toEqual([])
})
it("should return a non unique array multiple targets are passed through", async () => {
const { endTime } = await parseRequestParameters({
end_time: ["10:00", "10:00,11:00"],
})
expect(endTime).toEqual(["10:00", "10:00", "11:00"])
})
it("should return a non unique array one target is passed through", async () => {
const { endTime } = await parseRequestParameters({
end_time: ["10:00,10:00,11:00"],
})
expect(endTime).toEqual(["10:00", "10:00", "11:00"])
})
})

describe("day", () => {
it("should return undefined if day are not provided", async () => {
const { day } = await parseRequestParameters({})
expect(day).toEqual([])
})
it("should return a non unique array multiple targets are passed through", async () => {
const { day } = await parseRequestParameters({
day: ["MO", "MO,TU"],
})
expect(day).toEqual(["Monday", "Monday", "Tuesday"])
})
it("should return a non unique array one target is passed through", async () => {
const { day } = await parseRequestParameters({
day: ["MO,MO,TU"],
})
expect(day).toEqual(["Monday", "Monday", "Tuesday"])
})
})

describe("startTime, endTime, and day validation", () => {
it("should not throw an error if start_time and end_time are of equal lengths", async () => {
const params = {
start_time: ["10:00,11:00"],
end_time: ["12:00,13:00"],
}
await expect(parseRequestParameters(params)).resolves.not.toThrow()
})

it("should not throw an error if start_time, end_time, and day are of equal lengths", async () => {
const params = {
start_time: ["10:00,11:00"],
end_time: ["12:00,13:00"],
day: ["MO,TU"],
}
await expect(parseRequestParameters(params)).resolves.not.toThrow()
})

it("should throw an error if start_time, end_time, and day are of unequal lengths", async () => {
const params = {
start_time: ["10:00,11:00"],
end_time: ["12:00"],
day: ["MO,TU"],
}
await expect(parseRequestParameters(params)).rejects.toThrow(
"The number of start_time, end_time, and day parameters must be equal if more than one is provided"
)
})
})

Expand Down
39 changes: 35 additions & 4 deletions src/controllers/v1/services/routes/get-services.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const filters = require("../../../../lib/filters")
const queries = require("../../../../lib/queries")
const { calculateDistance, geocode, projection } = require("../../../../lib")
const {
calculateDistance,
geocode,
projection,
dayMapping,
} = require("../../../../lib")
const { db } = require("../../../../db")
const logger = require("../../../../../utils/logger")
const locations = require("../../../../lib/locations")
Expand Down Expand Up @@ -32,11 +37,18 @@ module.exports = {
let accessibilities = queryParams?.accessibilities
? [].concat(queryParams.accessibilities)
: []
let days = queryParams?.days ? [].concat(queryParams.days) : []
// days = days=Monday&days=Tuesday - deprecated
let daysDeprecated = queryParams?.days ? [].concat(queryParams.days) : []
let only = queryParams?.only ? [].concat(queryParams.only) : []
const minAge = parseInt(queryParams.min_age) || undefined
const maxAge = parseInt(queryParams.max_age) || undefined

let startTime = queryParams?.start_time
? [].concat(queryParams.start_time)
: []
let endTime = queryParams?.end_time ? [].concat(queryParams.end_time) : []
let day = queryParams?.day ? [].concat(queryParams.day) : []

// not a param but we want to save on requests
let interpreted_location

Expand All @@ -51,9 +63,25 @@ module.exports = {
accessibilities = [
...new Set(accessibilities.flatMap(str => str.split(","))),
]
days = [...new Set(days.flatMap(str => str.split(",")))]
daysDeprecated = [...new Set(daysDeprecated.flatMap(str => str.split(",")))]
only = [...new Set(only.flatMap(str => str.split(",")))]

// we dont de-dupe these as they are used in pairs
startTime = [...startTime.flatMap(str => str.split(","))]
endTime = [...endTime.flatMap(str => str.split(","))]
day = [...day.flatMap(str => str.split(","))]
// Convert day abbreviations to full names
day = day.map(d => dayMapping[d] || d)

const lengths = [startTime.length, endTime.length, day.length].filter(
len => len > 0
)
if (lengths.length > 1 && !lengths.every(len => len === lengths[0])) {
throw new Error(
"The number of start_time, end_time, and day parameters must be equal if more than one is provided"
)
}

// if we have a location then we can find lat lng
if (location && !(lat && lng)) {
try {
Expand All @@ -80,7 +108,10 @@ module.exports = {
taxonomies,
needs,
suitabilities,
days,
daysDeprecated,
startTime,
endTime,
day,
accessibilities,
only,
minAge,
Expand Down
44 changes: 41 additions & 3 deletions src/lib/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ module.exports = {

/**
* Days
* this has changed from previous iterations since the results returned wouldn't be accurate
* @TODO test http://localhost:3001/api/v1/services?accessibilities=accessible-toilet-facilities
* @TODO test http://localhost:3001/api/v1/services?accessibilities=accessible-toilet-facilities&accessibilities=wheelchair-accessible-entrance
* Returns the regular_schedules.weekday for the days
* @TODO test http://localhost:3001/api/v1/services?days=Monday
* @TODO test http://localhost:3001/api/v1/services?days=Monday&days=Tuesday
* @param {*} needs
* @returns
*/
Expand All @@ -195,4 +195,42 @@ module.exports = {
}
return {}
},

/**
* Filters by opens_at, closes_at and day
* @TODO test http://localhost:3002/api/v1/services?start_time=22:00&end_time=22:30&day=MO
* @TODO test http://localhost:3002/api/v1/services?start_time=22:00
* @TODO test http://localhost:3002/api/v1/services?end_time=22:30
* @TODO test http://localhost:3002/api/v1/services?day=MO
* @TODO test http://localhost:3002/api/v1/services?start_time=22:00&end_time=22:30&day=MO&start_time=22:00&end_time=22:30&day=MO
* @param {*} startTime
* @param {*} endTime
* @param {*} day
* @returns
*/
filterStartTimeEndTimeDay: (startTime, endTime, day) => {
let orConditions = []
const maxLength = Math.max(startTime.length, endTime.length, day.length)

for (let i = 0; i < maxLength; i++) {
let condition = {}
if (startTime[i]) {
condition["regular_schedules.opens_at"] = { $gte: startTime[i] }
}
if (endTime[i]) {
condition["regular_schedules.closes_at"] = { $lte: endTime[i] }
}
if (day[i]) {
condition["regular_schedules.weekday"] = day[i]
}
orConditions.push(condition)
}

let query = {}
if (orConditions.length > 0) {
query.$or = orConditions
}

return query
},
}
13 changes: 13 additions & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,17 @@ module.exports = {
visible_from: 0,
visible_to: 0,
},

/**
* Used to map the day abbreviation to the full day names
*/
dayMapping: {
SU: "Sunday",
MO: "Monday",
TU: "Tuesday",
WE: "Wednesday",
TH: "Thursday",
FR: "Friday",
SA: "Saturday",
},
}
7 changes: 6 additions & 1 deletion src/lib/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ module.exports = {
filters.filterNeeds(parameters.needs),
filters.filterSuitabilities(parameters.suitabilities),
filters.filterAccessibilities(parameters.accessibilities),
filters.filterDays(parameters.days)
filters.filterDays(parameters.daysDeprecated),
filters.filterStartTimeEndTimeDay(
parameters.startTime,
parameters.endTime,
parameters.day
)
)

// clear empty values
Expand Down

0 comments on commit a7c0bc9

Please sign in to comment.