From 298ceb3804d60486956e4dfc6551677380754699 Mon Sep 17 00:00:00 2001 From: Karen Shaw Date: Wed, 9 Oct 2024 19:59:24 +0000 Subject: [PATCH] Allow _source_includes and _source_excludes for GET search requests --- docs/docs/spec/types.yaml | 14 ++++++++ node/src/handlers/search-runner.js | 21 +++++++++++- node/test/integration/search.test.js | 50 ++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/docs/docs/spec/types.yaml b/docs/docs/spec/types.yaml index 41050ebb..119bdeea 100644 --- a/docs/docs/spec/types.yaml +++ b/docs/docs/spec/types.yaml @@ -60,6 +60,20 @@ components: description: Comma-delimited list of fields to sort search results (e.g. "create_date:asc,modified_date:desc") schema: type: string + _source_excludes: + name: _source_excludes + in: query + required: false + description: Comma-delimited list of fields to exclude from search results (e.g. "embedding,embedding_text_length") + schema: + type: string + _source_includes: + name: _source_includes + in: query + required: false + description: Comma-delimited list of fields to include in search results (e.g. "title,accession_number") + schema: + type: string as: name: as in: query diff --git a/node/src/handlers/search-runner.js b/node/src/handlers/search-runner.js index f7063214..c5b3a491 100644 --- a/node/src/handlers/search-runner.js +++ b/node/src/handlers/search-runner.js @@ -96,6 +96,26 @@ const constructSearchContext = async (event) => { searchContext.size = queryStringParameters.size || searchContext.size || 10; searchContext.from = queryStringParameters.from || searchContext.from || 0; + if ( + queryStringParameters?._source_excludes || + searchContext._source?.exclude + ) { + searchContext._source = searchContext._source || {}; + searchContext._source.exclude = + queryStringParameters?._source_excludes.split(",") || + searchContext._source.exclude; + } + + if ( + queryStringParameters?._source_includes || + searchContext._source?.include + ) { + searchContext._source = searchContext._source || {}; + searchContext._source.include = + queryStringParameters?._source_includes.split(",") || + searchContext._source.include; + } + if (queryStringParameters?.sort || searchContext.sort) searchContext.sort = parseSortParameter(queryStringParameters) || searchContext.sort; @@ -104,7 +124,6 @@ const constructSearchContext = async (event) => { const page = Number(queryStringParameters.page || 1); searchContext.from = (page - 1) * searchContext.size; } - return searchContext; }; diff --git a/node/test/integration/search.test.js b/node/test/integration/search.test.js index febe9576..1fbaa25d 100644 --- a/node/test/integration/search.test.js +++ b/node/test/integration/search.test.js @@ -206,5 +206,55 @@ describe("Search routes", () => { "?sort=create_date%3Aasc%2Cmodified_date%3Adesc" ); }); + + it("allows excluding fields via query string parameters for GET requests", async () => { + const originalQuery = { + query: { query_string: { query: "*" } }, + _source: { exclude: ["title"] }, + }; + const event = helpers + .mockEvent("GET", "/search") + .queryParams({ _source_excludes: "title" }) + .render(); + const authQuery = new RequestPipeline(originalQuery) + .authFilter(helpers.preprocess(event)) + .toJson(); + + mock + .post("/dc-v2-work/_search", authQuery) + .reply(200, helpers.testFixture("mocks/search.json")); + + const result = await handler(event); + expect(result.statusCode).to.eq(200); + const resultBody = JSON.parse(result.body); + expect(resultBody.pagination.query_url).to.contain( + "?_source_excludes=title" + ); + }); + + it("allows including fields via query string parameters for GET requests", async () => { + const originalQuery = { + query: { query_string: { query: "*" } }, + _source: { include: ["title", "accession_number"] }, + }; + const event = helpers + .mockEvent("GET", "/search") + .queryParams({ _source_includes: "title,accession_number" }) + .render(); + const authQuery = new RequestPipeline(originalQuery) + .authFilter(helpers.preprocess(event)) + .toJson(); + + mock + .post("/dc-v2-work/_search", authQuery) + .reply(200, helpers.testFixture("mocks/search.json")); + + const result = await handler(event); + expect(result.statusCode).to.eq(200); + const resultBody = JSON.parse(result.body); + expect(resultBody.pagination.query_url).to.contain( + "?_source_includes=title%2Caccession_number" + ); + }); }); });