Skip to content

Commit e114d38

Browse files
Merge #1458 #1459
1458: Add multi search method of Meilisearch v1.1 r=bidoubiwa a=bidoubiwa Introduces the `client.multiSearch()` method as per the [specifications](meilisearch/specifications#225) SDK requirements: meilisearch/integration-guides#251 1459: Add facetStats type in searchResponse for MS v1.1.0 r=bidoubiwa a=bidoubiwa As per [the specification](meilisearch/specifications#224) SDK requirements: meilisearch/integration-guides#251 A new response field, `facetStats` is returned when `facets` is used in the search parameters. It contains the min max value of facets that contain numeric values. I added some test `@brunoocasali` to ensure my typing is correct Co-authored-by: cvermand <[email protected]> Co-authored-by: Charlotte Vermandel <[email protected]>
3 parents 4e10856 + 3e0d3cb + f65322d commit e114d38

File tree

4 files changed

+123
-1
lines changed

4 files changed

+123
-1
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,16 @@ client.index<T>('xxx').search(query: string, options: SearchParams = {}, config?
362362
client.index<T>('xxx').searchGet(query: string, options: SearchParams = {}, config?: Partial<Request>): Promise<SearchResponse<T>>
363363
```
364364

365+
### Multi Search
366+
367+
#### [Make multiple search requests](https://docs.meilisearch.com/reference/api/multi-search.html)
368+
369+
```ts
370+
client.multiSearch(queries?: MultiSearchParams, config?: Partial<Request>): Promise<Promise<MultiSearchResponse<T>>>
371+
```
372+
373+
`multiSearch` uses the `POST` method when performing its request to Meilisearch.
374+
365375
### Documents <!-- omit in toc -->
366376

367377
#### [Add or replace multiple documents](https://docs.meilisearch.com/reference/api/documents.html#add-or-replace-documents)

src/clients/client.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import {
3232
SwapIndexesParams,
3333
CancelTasksQuery,
3434
DeleteTasksQuery,
35+
MultiSearchParams,
36+
MultiSearchResponse,
3537
} from '../types'
3638
import { HttpRequests } from '../http-requests'
3739
import { TaskClient, Task } from '../task'
@@ -189,6 +191,40 @@ class Client {
189191
return await this.httpRequest.post(url, params)
190192
}
191193

194+
///
195+
/// Multi Search
196+
///
197+
198+
/**
199+
* Perform multiple search queries.
200+
*
201+
* It is possible to make multiple search queries on the same index or on
202+
* different ones
203+
*
204+
* @example
205+
*
206+
* ```ts
207+
* client.multiSearch({
208+
* queries: [
209+
* { indexUid: 'movies', q: 'wonder' },
210+
* { indexUid: 'books', q: 'flower' },
211+
* ],
212+
* })
213+
* ```
214+
*
215+
* @param queries - Search queries
216+
* @param config - Additional request configuration options
217+
* @returns Promise containing the search responses
218+
*/
219+
async multiSearch<T extends Record<string, any> = Record<string, any>>(
220+
queries?: MultiSearchParams,
221+
config?: Partial<Request>
222+
): Promise<MultiSearchResponse<T>> {
223+
const url = `/multi-search`
224+
225+
return await this.httpRequest.post(url, queries, undefined, config)
226+
}
227+
192228
///
193229
/// TASKS
194230
///

src/types/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ export type SearchRequestGET = Pagination &
106106
showMatchesPosition?: boolean
107107
}
108108

109+
export type MultiSearchParams = {
110+
queries: Array<SearchParams & { indexUid: string }>
111+
}
112+
109113
export type CategoriesDistribution = {
110114
[category: string]: number
111115
}
@@ -131,6 +135,7 @@ export type SearchResponse<
131135
processingTimeMs: number
132136
facetDistribution?: FacetDistribution
133137
query: string
138+
facetStats?: Record<string, { min?: number; max?: number }>
134139
} & (undefined extends S
135140
? Partial<FinitePagination & InfinitePagination>
136141
: true extends IsFinitePagination<NonNullable<S>>
@@ -168,6 +173,10 @@ type HasPage<S extends SearchParams> = undefined extends S['page']
168173
? false
169174
: true
170175

176+
export type MultiSearchResponse<T = Record<string, any>> = {
177+
results: Array<SearchResponse<T> & { indexUid: string }>
178+
}
179+
171180
export type FieldDistribution = {
172181
[field: string]: number
173182
}

tests/search.test.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ const emptyIndex = {
1717
uid: 'empty_test',
1818
}
1919

20+
type Books = {
21+
id: number
22+
title: string
23+
comment: string
24+
genre: string
25+
}
26+
2027
const dataset = [
2128
{
2229
id: 123,
@@ -85,6 +92,52 @@ describe.each([
8592
await client.waitForTask(task2)
8693
})
8794

95+
test(`${permission} key: Multi index search no queries`, async () => {
96+
const client = await getClient(permission)
97+
const response = await client.multiSearch({
98+
queries: [],
99+
})
100+
101+
expect(response.results.length).toEqual(0)
102+
})
103+
104+
test(`${permission} key: Multi index search with one query`, async () => {
105+
const client = await getClient(permission)
106+
const response = await client.multiSearch({
107+
queries: [{ indexUid: index.uid, q: 'prince' }],
108+
})
109+
110+
expect(response.results[0].hits.length).toEqual(2)
111+
})
112+
113+
test(`${permission} key: Multi index search with multiple queries`, async () => {
114+
const client = await getClient(permission)
115+
const response = await client.multiSearch({
116+
queries: [
117+
{ indexUid: index.uid, q: 'something' },
118+
{ indexUid: emptyIndex.uid, q: 'something' },
119+
],
120+
})
121+
122+
expect(response.results.length).toEqual(2)
123+
})
124+
125+
test(`${permission} key: Multi index search with one query`, async () => {
126+
const client = await getClient(permission)
127+
128+
type MyIndex = {
129+
id: 1
130+
}
131+
132+
const response = await client.multiSearch<MyIndex & Books>({
133+
queries: [{ indexUid: index.uid, q: 'prince' }],
134+
})
135+
136+
expect(response.results[0].hits.length).toEqual(2)
137+
expect(response.results[0].hits[0].id).toEqual(456)
138+
expect(response.results[0].hits[0].title).toEqual('Le Petit Prince')
139+
})
140+
88141
test(`${permission} key: Basic search`, async () => {
89142
const client = await getClient(permission)
90143
const response = await client.index(index.uid).search('prince', {})
@@ -94,6 +147,7 @@ describe.each([
94147
expect(response).toHaveProperty('offset', 0)
95148
expect(response).toHaveProperty('processingTimeMs', expect.any(Number))
96149
expect(response).toHaveProperty('query', 'prince')
150+
expect(response.facetStats).toBeUndefined()
97151
expect(response.hits.length).toEqual(2)
98152
// @ts-expect-error Not present in the SearchResponse type because neither `page` or `hitsPerPage` is provided in the search params.
99153
expect(response.hitsPerPage).toBeUndefined()
@@ -453,12 +507,17 @@ describe.each([
453507
const client = await getClient(permission)
454508
const response = await client.index(index.uid).search('a', {
455509
filter: ['genre = romance'],
456-
facets: ['genre'],
510+
facets: ['genre', 'id'],
457511
})
458512

459513
expect(response).toHaveProperty('facetDistribution', {
460514
genre: { romance: 2 },
515+
id: { '123': 1, '2': 1 },
461516
})
517+
518+
expect(response).toHaveProperty('facetStats', { id: { min: 2, max: 123 } })
519+
expect(response.facetStats?.['id']?.min).toBe(2)
520+
expect(response.facetStats?.['id']?.max).toBe(123)
462521
expect(response).toHaveProperty('hits', expect.any(Array))
463522
expect(response.hits.length).toEqual(2)
464523
})
@@ -739,6 +798,14 @@ describe.each([{ permission: 'No' }])(
739798
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
740799
)
741800
})
801+
802+
test(`${permission} key: Try multi search and be denied`, async () => {
803+
const client = await getClient(permission)
804+
await expect(client.multiSearch({ queries: [] })).rejects.toHaveProperty(
805+
'code',
806+
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
807+
)
808+
})
742809
}
743810
)
744811

0 commit comments

Comments
 (0)