From 75d7f3433b4d657ca73016a3de871ef4d7f5e8d9 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Mon, 5 Jun 2023 17:11:22 +0200 Subject: [PATCH 01/12] Add the searchForFacetValue method --- README.md | 8 +++ src/indexes.ts | 23 ++++++++ src/types/types.ts | 23 ++++++++ tests/facet_search.test.ts | 108 +++++++++++++++++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 tests/facet_search.test.ts diff --git a/README.md b/README.md index 3e1ca706f..cb030ec49 100644 --- a/README.md +++ b/README.md @@ -412,6 +412,14 @@ client.multiSearch(queries?: MultiSearchParams, config?: Partial): Prom `multiSearch` uses the `POST` method when performing its request to Meilisearch. +### Search For Facet Value + +#### [Search for facet value](#) + +```ts +client.index('xxx').searchForFacetValue(params: SearchForFacetValuesParams, config?: Partial): Promise +``` + ### Documents #### [Add or replace multiple documents](https://www.meilisearch.com/docs/reference/api/documents#add-or-replace-documents) diff --git a/src/indexes.ts b/src/indexes.ts index b4f2431c5..e816ea02a 100644 --- a/src/indexes.ts +++ b/src/indexes.ts @@ -45,6 +45,8 @@ import { ContentType, DocumentsIds, DocumentsDeletionQuery, + SearchForFacetValuesParams, + SearchForFacetValuesResponse, } from './types' import { removeUndefinedFromObject } from './utils' import { HttpRequests } from './http-requests' @@ -146,6 +148,27 @@ class Index = Record> { ) } + /** + * Search for facet values + * + * @param params - Parameters used to search on the facets + * @param config - Additional request configuration options + * @returns Promise containing the search response + */ + async searchForFacetValue( + params: SearchForFacetValuesParams, + config?: Partial + ): Promise { + const url = `indexes/${this.uid}/facet-search` + + return await this.httpRequest.post( + url, + removeUndefinedFromObject(params), + undefined, + config + ) + } + /// /// INDEX /// diff --git a/src/types/types.ts b/src/types/types.ts index f24ecfabb..31498e9fa 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -189,6 +189,29 @@ export type FieldDistribution = { [field: string]: number } +/* + * Facet search + */ + +export type SearchForFacetValuesParams = SearchParams & { + facetName: string + facetQuery?: string + q?: string + filter?: Filter + matchingStrategy?: MatchingStrategies +} + +export type FacetHit = { + value: string + count: number +} + +export type SearchForFacetValuesResponse = { + hits: FacetHit[] + query: string | null + processingTimeMs: number +} + /* ** Documents */ diff --git a/tests/facet_search.test.ts b/tests/facet_search.test.ts new file mode 100644 index 000000000..3b820ad41 --- /dev/null +++ b/tests/facet_search.test.ts @@ -0,0 +1,108 @@ +import { + clearAllIndexes, + config, + getClient, +} from './utils/meilisearch-test-utils' + +const index = { + uid: 'movies_test', +} + +const dataset = [ + { + id: 123, + title: 'Pride and Prejudice', + genres: ['romance', 'action'], + }, + { + id: 456, + title: 'Le Petit Prince', + genres: ['adventure', 'comedy'], + }, + { + id: 2, + title: 'Le Rouge et le Noir', + genres: 'romance', + }, + { + id: 1, + title: 'Alice In Wonderland', + genres: ['adventure'], + }, +] + +describe.each([ + { permission: 'Master' }, + { permission: 'Admin' }, + { permission: 'Search' }, +])('Test on POST search', ({ permission }) => { + beforeAll(async () => { + await clearAllIndexes(config) + const client = await getClient('Master') + const newFilterableAttributes = ['genres', 'title'] + + await client.createIndex(index.uid) + await client.index(index.uid).updateSettings({ + filterableAttributes: newFilterableAttributes, + }) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) + }) + + test(`${permission} key: basic facet value search`, async () => { + const client = await getClient(permission) + + const params = { + facetQuery: 'a', + facetName: 'genres', + } + const response = await client.index(index.uid).searchForFacetValue(params) + + expect(response.hits.length).toEqual(2) + expect(response.query).toEqual('a') + }) + + test(`${permission} key: facet value search with no facet query`, async () => { + const client = await getClient(permission) + + const params = { + facetName: 'genres', + } + const response = await client.index(index.uid).searchForFacetValue(params) + + expect(response.hits.length).toEqual(4) + expect(response.query).toEqual(null) + }) + + test(`${permission} key: facet value search with filter`, async () => { + const client = await getClient(permission) + + const params = { + facetName: 'genres', + facetQuery: 'a', + filter: ['genres = action'], + } + const response = await client.index(index.uid).searchForFacetValue(params) + + expect(response.hits.length).toEqual(1) + }) + + test(`${permission} key: facet value search with search query`, async () => { + const client = await getClient(permission) + + const params = { + facetName: 'genres', + facetQuery: 'a', + q: 'Alice', + } + const response = await client.index(index.uid).searchForFacetValue(params) + + expect(response.hits.length).toEqual(1) + }) +}) + +jest.setTimeout(100 * 1000) + +afterAll(() => { + return clearAllIndexes(config) +}) From e4341e755fc5d7d7e37075daf9e6633796f54f16 Mon Sep 17 00:00:00 2001 From: meili-bot <74670311+meili-bot@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:52:31 -0300 Subject: [PATCH 02/12] Update version for the next release (v0.33.0-prototype-search-for-facet-values.0) (#1514) * Update package.json * Update src/package-version.ts --- package.json | 2 +- src/package-version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 33ed8e38f..100f51ec3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meilisearch", - "version": "0.33.0", + "version": "0.33.0-prototype-search-for-facet-values.0", "description": "The Meilisearch JS client for Node.js and the browser.", "keywords": [ "meilisearch", diff --git a/src/package-version.ts b/src/package-version.ts index 03c87af97..532e6003d 100644 --- a/src/package-version.ts +++ b/src/package-version.ts @@ -1 +1 @@ -export const PACKAGE_VERSION = '0.33.0' +export const PACKAGE_VERSION = '0.33.0-prototype-search-for-facet-values.0' From 07b3860222219a00817f7108039ea76825037522 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 17:24:44 +0200 Subject: [PATCH 03/12] Change name of searchForFacetValue to searchForFacetValues --- README.md | 6 +++--- src/indexes.ts | 2 +- tests/facet_search.test.ts | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cb030ec49..cd6ab705e 100644 --- a/README.md +++ b/README.md @@ -412,12 +412,12 @@ client.multiSearch(queries?: MultiSearchParams, config?: Partial): Prom `multiSearch` uses the `POST` method when performing its request to Meilisearch. -### Search For Facet Value +### Search For Facet Values -#### [Search for facet value](#) +#### [Search for facet values](#) ```ts -client.index('xxx').searchForFacetValue(params: SearchForFacetValuesParams, config?: Partial): Promise +client.index('xxx').searchForFacetValues(params: SearchForFacetValuesParams, config?: Partial): Promise ``` ### Documents diff --git a/src/indexes.ts b/src/indexes.ts index e816ea02a..f1331bc76 100644 --- a/src/indexes.ts +++ b/src/indexes.ts @@ -155,7 +155,7 @@ class Index = Record> { * @param config - Additional request configuration options * @returns Promise containing the search response */ - async searchForFacetValue( + async searchForFacetValues( params: SearchForFacetValuesParams, config?: Partial ): Promise { diff --git a/tests/facet_search.test.ts b/tests/facet_search.test.ts index 3b820ad41..9976b8000 100644 --- a/tests/facet_search.test.ts +++ b/tests/facet_search.test.ts @@ -40,7 +40,6 @@ describe.each([ await clearAllIndexes(config) const client = await getClient('Master') const newFilterableAttributes = ['genres', 'title'] - await client.createIndex(index.uid) await client.index(index.uid).updateSettings({ filterableAttributes: newFilterableAttributes, @@ -49,14 +48,14 @@ describe.each([ await client.waitForTask(taskUid) }) - test(`${permission} key: basic facet value search`, async () => { + test.only(`${permission} key: basic facet value search`, async () => { const client = await getClient(permission) const params = { facetQuery: 'a', facetName: 'genres', } - const response = await client.index(index.uid).searchForFacetValue(params) + const response = await client.index('games').searchForFacetValues(params) expect(response.hits.length).toEqual(2) expect(response.query).toEqual('a') @@ -68,7 +67,7 @@ describe.each([ const params = { facetName: 'genres', } - const response = await client.index(index.uid).searchForFacetValue(params) + const response = await client.index(index.uid).searchForFacetValues(params) expect(response.hits.length).toEqual(4) expect(response.query).toEqual(null) @@ -82,7 +81,8 @@ describe.each([ facetQuery: 'a', filter: ['genres = action'], } - const response = await client.index(index.uid).searchForFacetValue(params) + + const response = await client.index(index.uid).searchForFacetValues(params) expect(response.hits.length).toEqual(1) }) @@ -95,7 +95,7 @@ describe.each([ facetQuery: 'a', q: 'Alice', } - const response = await client.index(index.uid).searchForFacetValue(params) + const response = await client.index(index.uid).searchForFacetValues(params) expect(response.hits.length).toEqual(1) }) From 49a16e3a7848333432b4fa3ae0000eaf545c1924 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 17:43:46 +0200 Subject: [PATCH 04/12] Add error codes --- src/types/types.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/types/types.ts b/src/types/types.ts index 31498e9fa..0951a209f 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -839,6 +839,21 @@ export const enum ErrorStatusCode { /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_api_key_offset */ INVALID_API_KEY_OFFSET = 'invalid_api_key_offset', + + /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_facet_search_facet_name */ + INVALID_FACET_SEARCH_FACET_NAME = 'invalid_facet_search_facet_name', + + /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_facet_search_query */ + INVALID_FACET_SEARCH_QUERY = 'invalid_facet_search_query', + + /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_facet_search_name */ + INVALID_FACET_SEARCH_NAME = 'invalid_facet_search_name', + + /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_facet */ + INVALID_SEARCH_FACET = 'invalid_search_facet', + + /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_facet_search_facet_name */ + MISSING_FACET_SEARCH_FACET_NAME = 'missing_facet_search_facet_name', } export type TokenIndexRules = { From a72d8963116662ff8e7c62ad003c4a040fd712f8 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 17:44:04 +0200 Subject: [PATCH 05/12] Remove only label on test --- tests/facet_search.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/facet_search.test.ts b/tests/facet_search.test.ts index 9976b8000..4011944ef 100644 --- a/tests/facet_search.test.ts +++ b/tests/facet_search.test.ts @@ -48,7 +48,7 @@ describe.each([ await client.waitForTask(taskUid) }) - test.only(`${permission} key: basic facet value search`, async () => { + test(`${permission} key: basic facet value search`, async () => { const client = await getClient(permission) const params = { From 9398299945cfd667d3ad6a6a248b51a627f8d0bb Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 17:56:12 +0200 Subject: [PATCH 06/12] Fix the typing of the search parameters --- src/types/types.ts | 48 ++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index 0951a209f..de4cce90b 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -78,6 +78,28 @@ export type Crop = { cropMarker?: string } +export const SortFacetValuesBy = { + COUNT: 'error', + ALPHA: 'alpha', +} + +export type SortFacetValuesBy = typeof SortFacetValuesBy[keyof typeof SortFacetValuesBy] + +export type SearchForFacetValuesParams = Omit & { + facetName: string +} + +export type FacetHit = { + value: string + count: number +} + +export type SearchForFacetValuesResponse = { + hits: FacetHit[] + query: string | null + processingTimeMs: number +} + export type SearchParams = Query & Pagination & Highlight & @@ -90,6 +112,9 @@ export type SearchParams = Query & matchingStrategy?: MatchingStrategies hitsPerPage?: number page?: number + sortFacetValuesBy?: SortFacetValuesBy + facetName?: string + facetQuery?: string } // Search parameters for searches made with the GET method @@ -189,29 +214,6 @@ export type FieldDistribution = { [field: string]: number } -/* - * Facet search - */ - -export type SearchForFacetValuesParams = SearchParams & { - facetName: string - facetQuery?: string - q?: string - filter?: Filter - matchingStrategy?: MatchingStrategies -} - -export type FacetHit = { - value: string - count: number -} - -export type SearchForFacetValuesResponse = { - hits: FacetHit[] - query: string | null - processingTimeMs: number -} - /* ** Documents */ From 73c8c547c50d8446a837ada7b69e0caf6f0399e6 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 17:58:01 +0200 Subject: [PATCH 07/12] Remove unecessary INVALID_SEARCH_FACET error --- src/types/types.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index de4cce90b..960d9fc16 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -851,9 +851,6 @@ export const enum ErrorStatusCode { /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_facet_search_name */ INVALID_FACET_SEARCH_NAME = 'invalid_facet_search_name', - /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#invalid_search_facet */ - INVALID_SEARCH_FACET = 'invalid_search_facet', - /** @see https://www.meilisearch.com/docs/reference/errors/error_codes#missing_facet_search_facet_name */ MISSING_FACET_SEARCH_FACET_NAME = 'missing_facet_search_facet_name', } From 501895bde5cd5738bf524c094c2531935ee693be Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 18:14:17 +0200 Subject: [PATCH 08/12] Fix tests --- tests/facet_search.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/facet_search.test.ts b/tests/facet_search.test.ts index 4011944ef..5027ed51c 100644 --- a/tests/facet_search.test.ts +++ b/tests/facet_search.test.ts @@ -55,7 +55,7 @@ describe.each([ facetQuery: 'a', facetName: 'genres', } - const response = await client.index('games').searchForFacetValues(params) + const response = await client.index(index.uid).searchForFacetValues(params) expect(response.hits.length).toEqual(2) expect(response.query).toEqual('a') From 9378f4d850a9dbe0f85a5f527eaf22dbed44ee78 Mon Sep 17 00:00:00 2001 From: Charlotte Vermandel Date: Wed, 7 Jun 2023 18:19:44 +0200 Subject: [PATCH 09/12] Update returned fields from hits to facetHits and query to facetQuery --- src/types/types.ts | 4 ++-- tests/facet_search.test.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/types/types.ts b/src/types/types.ts index 960d9fc16..0b8cc70d8 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -95,8 +95,8 @@ export type FacetHit = { } export type SearchForFacetValuesResponse = { - hits: FacetHit[] - query: string | null + facetHits: FacetHit[] + facetQuery: string | null processingTimeMs: number } diff --git a/tests/facet_search.test.ts b/tests/facet_search.test.ts index 5027ed51c..394e692c3 100644 --- a/tests/facet_search.test.ts +++ b/tests/facet_search.test.ts @@ -57,8 +57,8 @@ describe.each([ } const response = await client.index(index.uid).searchForFacetValues(params) - expect(response.hits.length).toEqual(2) - expect(response.query).toEqual('a') + expect(response.facetHits.length).toEqual(2) + expect(response.facetQuery).toEqual('a') }) test(`${permission} key: facet value search with no facet query`, async () => { @@ -69,8 +69,8 @@ describe.each([ } const response = await client.index(index.uid).searchForFacetValues(params) - expect(response.hits.length).toEqual(4) - expect(response.query).toEqual(null) + expect(response.facetHits.length).toEqual(4) + expect(response.facetQuery).toEqual(null) }) test(`${permission} key: facet value search with filter`, async () => { @@ -84,7 +84,7 @@ describe.each([ const response = await client.index(index.uid).searchForFacetValues(params) - expect(response.hits.length).toEqual(1) + expect(response.facetHits.length).toEqual(1) }) test(`${permission} key: facet value search with search query`, async () => { @@ -97,7 +97,7 @@ describe.each([ } const response = await client.index(index.uid).searchForFacetValues(params) - expect(response.hits.length).toEqual(1) + expect(response.facetHits.length).toEqual(1) }) }) From 6ddc9f20703cfa1110ef969f87be3dbc2ceb3fb9 Mon Sep 17 00:00:00 2001 From: meili-bot <74670311+meili-bot@users.noreply.github.com> Date: Thu, 8 Jun 2023 09:16:48 -0300 Subject: [PATCH 10/12] Update version for the next release (vv0.33.0-prototype-search-for-facet-values.1) (#1515) * Update package.json * Update src/package-version.ts --------- Co-authored-by: cvermand <33010418+bidoubiwa@users.noreply.github.com> --- package.json | 2 +- src/package-version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 100f51ec3..540a4d1f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meilisearch", - "version": "0.33.0-prototype-search-for-facet-values.0", + "version": "v0.33.0-prototype-search-for-facet-values.1", "description": "The Meilisearch JS client for Node.js and the browser.", "keywords": [ "meilisearch", diff --git a/src/package-version.ts b/src/package-version.ts index 532e6003d..a6b51057e 100644 --- a/src/package-version.ts +++ b/src/package-version.ts @@ -1 +1 @@ -export const PACKAGE_VERSION = '0.33.0-prototype-search-for-facet-values.0' +export const PACKAGE_VERSION = 'v0.33.0-prototype-search-for-facet-values.1' From 60fbebce749229624dca34d0fd0b5cba1687882d Mon Sep 17 00:00:00 2001 From: cvermand <33010418+bidoubiwa@users.noreply.github.com> Date: Thu, 8 Jun 2023 14:42:24 +0200 Subject: [PATCH 11/12] Apply suggestions from code review --- package.json | 2 +- src/package-version.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 540a4d1f9..31f0ff083 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meilisearch", - "version": "v0.33.0-prototype-search-for-facet-values.1", + "version": "0.33.0-prototype-search-for-facet-values.1", "description": "The Meilisearch JS client for Node.js and the browser.", "keywords": [ "meilisearch", diff --git a/src/package-version.ts b/src/package-version.ts index a6b51057e..4061ee1c7 100644 --- a/src/package-version.ts +++ b/src/package-version.ts @@ -1 +1 @@ -export const PACKAGE_VERSION = 'v0.33.0-prototype-search-for-facet-values.1' +export const PACKAGE_VERSION = '0.33.0-prototype-search-for-facet-values.1' From cbf0ca8662528a5d7de944f9bf6c8823ef61624e Mon Sep 17 00:00:00 2001 From: cvermand <33010418+bidoubiwa@users.noreply.github.com> Date: Tue, 13 Jun 2023 11:46:09 +0200 Subject: [PATCH 12/12] Update README.md Co-authored-by: Bruno Casali --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cd6ab705e..a6353b77d 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,7 @@ client.multiSearch(queries?: MultiSearchParams, config?: Partial): Prom #### [Search for facet values](#) ```ts -client.index('xxx').searchForFacetValues(params: SearchForFacetValuesParams, config?: Partial): Promise +client.index('myIndex').searchForFacetValues(params: SearchForFacetValuesParams, config?: Partial): Promise ``` ### Documents