From ee395859f17443e7c0b9d5fd4a5b6f4ed4a99754 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 12 Nov 2024 15:34:29 +0000 Subject: [PATCH] Filter by service meta --- __tests__/unit/lib/filters.test.js | 47 +++++++++++++++++++ .../v1/services/routes/get-services.test.js | 28 +++++++++++ .../v1/services/routes/get-services.js | 5 ++ src/lib/filters.js | 21 +++++++++ src/lib/queries.js | 4 ++ src/routes/parameters.yml | 10 +++- src/routes/routes.js | 1 + 7 files changed, 115 insertions(+), 1 deletion(-) diff --git a/__tests__/unit/lib/filters.test.js b/__tests__/unit/lib/filters.test.js index 198135c..cae4dce 100644 --- a/__tests__/unit/lib/filters.test.js +++ b/__tests__/unit/lib/filters.test.js @@ -108,6 +108,53 @@ describe("filterOnly", () => { }) }) +describe("filterMeta", () => { + it("should return an empty array if meta is not provided", () => { + expect(filters.filterMeta()).toEqual([]) + }) + it("should return a query object with key and value if meta includes information", () => { + expect( + filters.filterMeta([ + { key: "service-meta-key", value: "service-meta-value" }, + ]) + ).toEqual([ + { + meta: { + $elemMatch: { + key: "service-meta-key", + value: "service-meta-value", + }, + }, + }, + ]) + }) + it("should return a query object with each key and value if meta includes information", () => { + expect( + filters.filterMeta([ + { key: "service-meta-key", value: "service-meta-value" }, + { key: "service-meta-key-2", value: "service-meta-value-2" }, + ]) + ).toEqual([ + { + meta: { + $elemMatch: { + key: "service-meta-key", + value: "service-meta-value", + }, + }, + }, + { + meta: { + $elemMatch: { + key: "service-meta-key-2", + value: "service-meta-value-2", + }, + }, + }, + ]) + }) +}) + describe("filterTaxonomies", () => { it("should return an empty object if taxonomies is not provided", () => { expect(filters.filterTaxonomies()).toEqual({}) diff --git a/__tests__/unit/v1/services/routes/get-services.test.js b/__tests__/unit/v1/services/routes/get-services.test.js index 6f33cfc..3dc3aa6 100644 --- a/__tests__/unit/v1/services/routes/get-services.test.js +++ b/__tests__/unit/v1/services/routes/get-services.test.js @@ -36,6 +36,7 @@ describe("get-services", () => { endDate: undefined, accessibilities: [], only: [], + meta: [], minAge: undefined, maxAge: undefined, interpreted_location: undefined, @@ -424,6 +425,33 @@ describe("get-services", () => { }) }) + describe("meta", () => { + it("should return undefined if only are not provided", async () => { + const { meta } = await parseRequestParameters({}) + expect(meta).toEqual([]) + }) + it("should return a unique array multiple targets are passed through", async () => { + const { meta } = await parseRequestParameters({ + "meta-service-meta-key": "service-meta-value", + }) + expect(new Set(meta)).toEqual( + new Set([{ key: "service-meta-key", value: "service-meta-value" }]) + ) + }) + it("should return a unique array one target is passed through", async () => { + const { meta } = await parseRequestParameters({ + "meta-service-meta-key": "service-meta-value", + "meta-service-meta-key-2": "service-meta-value-2", + }) + expect(new Set(meta)).toEqual( + new Set([ + { key: "service-meta-key", value: "service-meta-value" }, + { key: "service-meta-key-2", value: "service-meta-value-2" }, + ]) + ) + }) + }) + describe("minAge", () => { it("should return undefined if minAge is not provided", async () => { const { minAge } = await parseRequestParameters({}) diff --git a/src/controllers/v1/services/routes/get-services.js b/src/controllers/v1/services/routes/get-services.js index 7e52be7..99da3d7 100644 --- a/src/controllers/v1/services/routes/get-services.js +++ b/src/controllers/v1/services/routes/get-services.js @@ -44,6 +44,10 @@ module.exports = { // days = days=Monday&days=Tuesday - deprecated let daysDeprecated = queryParams?.days ? [].concat(queryParams.days) : [] let only = queryParams?.only ? [].concat(queryParams.only) : [] + let meta = Object.entries(queryParams) + .filter(([key]) => key.startsWith("meta-")) + .map(([key, value]) => ({ key: key.replace("meta-", ""), value })) + const minAge = parseInt(queryParams.min_age) || undefined const maxAge = parseInt(queryParams.max_age) || undefined @@ -123,6 +127,7 @@ module.exports = { endDate, accessibilities, only, + meta, minAge, maxAge, interpreted_location, diff --git a/src/lib/filters.js b/src/lib/filters.js index e63e06b..5862bb4 100644 --- a/src/lib/filters.js +++ b/src/lib/filters.js @@ -71,6 +71,27 @@ const filters = { return query }, + // filters by meta + // meta-service-meta-key=service-meta-value + filterMeta: meta => { + let query = [] + if (meta) { + meta.forEach(m => { + if (m.key && m.value) { + query.push({ + meta: { + $elemMatch: { + key: m.key, + value: m.value, + }, + }, + }) + } + }) + } + return query + }, + /** * Specify the taxonomies to search for services * We are using $in to match any of the taxonomies diff --git a/src/lib/queries.js b/src/lib/queries.js index 1b6cc34..63ef299 100644 --- a/src/lib/queries.js +++ b/src/lib/queries.js @@ -65,6 +65,10 @@ module.exports = { const only = filters.filterOnly(parameters.only) query.$and.push(...only) + // apply meta filters + const meta = filters.filterMeta(parameters.meta) + query.$and.push(...meta) + // apply visibility filtering const visibleNow = filters.visibleNow() query.$and.push(...visibleNow) diff --git a/src/routes/parameters.yml b/src/routes/parameters.yml index eb45eb6..cbf17aa 100644 --- a/src/routes/parameters.yml +++ b/src/routes/parameters.yml @@ -133,7 +133,7 @@ parameters: only: name: only in: query - description: Find services that are only x. Currently only free is supported. eg/ "free" + description: Find services that are only x. Currently only free, needs-referral and local-offer are supported. eg/ "free" required: false schema: type: enum @@ -142,6 +142,14 @@ parameters: - "needs-referral" - "local-offer" + meta: + name: meta + in: query + description: Prefix the key with meta- to filter by meta data. eg/ "meta-foo=bar" + required: false + schema: + type: string + min_age: name: min_age in: query diff --git a/src/routes/routes.js b/src/routes/routes.js index 4873ddb..87ebe8c 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -25,6 +25,7 @@ module.exports.setup = app => { * - $ref: '#/parameters/accessibilities' * - $ref: '#/parameters/days' * - $ref: '#/parameters/only' + * - $ref: '#/parameters/meta' * - $ref: '#/parameters/min_age' * - $ref: '#/parameters/max_age' * - $ref: '#/parameters/start_time'