Skip to content

Commit 3a7b03b

Browse files
authored
Add the filter field in getDocuments for Meilisearch v1.2 (#1493)
* Add filter parameter on getDocuments for Meilisearch v1.2
1 parent 6547f54 commit 3a7b03b

File tree

6 files changed

+105
-17
lines changed

6 files changed

+105
-17
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module.exports = {
55
es2020: true,
66
'jest/globals': true,
77
node: true,
8+
jasmine: true,
89
},
910
extends: [
1011
'eslint:recommended',

src/errors/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export * from './meilisearch-api-error'
33
export * from './meilisearch-communication-error'
44
export * from './meilisearch-error'
55
export * from './meilisearch-timeout-error'
6+
export * from './version-hint-message'

src/errors/version-hint-message.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function versionErrorHintMessage(message: string, method: string) {
2+
return `${message}\nHint: It might not be working because maybe you're not up to date with the Meilisearch version that ${method} call requires.`
3+
}

src/indexes.ts

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77

88
'use strict'
99

10-
import { MeiliSearchError } from './errors'
11-
10+
import {
11+
MeiliSearchError,
12+
MeiliSearchCommunicationError,
13+
versionErrorHintMessage,
14+
MeiliSearchApiError,
15+
} from './errors'
1216
import {
1317
Config,
1418
SearchResponse,
@@ -302,30 +306,49 @@ class Index<T extends Record<string, any> = Record<string, any>> {
302306
///
303307

304308
/**
305-
* Get documents of an index
309+
* Get documents of an index.
306310
*
307-
* @param parameters - Parameters to browse the documents
308-
* @returns Promise containing Document responses
311+
* @param parameters - Parameters to browse the documents. Parameters can
312+
* contain the `filter` field only available in Meilisearch v1.2 and newer
313+
* @returns Promise containing the returned documents
309314
*/
310315
async getDocuments<D extends Record<string, any> = T>(
311316
parameters: DocumentsQuery<D> = {}
312317
): Promise<ResourceResults<D[]>> {
313-
const url = `indexes/${this.uid}/documents`
314-
315-
const fields = (() => {
316-
if (Array.isArray(parameters?.fields)) {
317-
return parameters?.fields?.join(',')
318+
parameters = removeUndefinedFromObject(parameters)
319+
320+
// In case `filter` is provided, use `POST /documents/fetch`
321+
if (parameters.filter !== undefined) {
322+
try {
323+
const url = `indexes/${this.uid}/documents/fetch`
324+
325+
return await this.httpRequest.post<
326+
DocumentsQuery,
327+
Promise<ResourceResults<D[]>>
328+
>(url, parameters)
329+
} catch (e) {
330+
if (e instanceof MeiliSearchCommunicationError) {
331+
e.message = versionErrorHintMessage(e.message, 'getDocuments')
332+
} else if (e instanceof MeiliSearchApiError) {
333+
e.message = versionErrorHintMessage(e.message, 'getDocuments')
334+
}
335+
336+
throw e
318337
}
319-
return undefined
320-
})()
338+
// Else use `GET /documents` method
339+
} else {
340+
const url = `indexes/${this.uid}/documents`
321341

322-
return await this.httpRequest.get<Promise<ResourceResults<D[]>>>(
323-
url,
324-
removeUndefinedFromObject({
342+
// Transform fields to query parameter string format
343+
const fields = Array.isArray(parameters?.fields)
344+
? { fields: parameters?.fields?.join(',') }
345+
: {}
346+
347+
return await this.httpRequest.get<Promise<ResourceResults<D[]>>>(url, {
325348
...parameters,
326-
fields,
349+
...fields,
327350
})
328-
)
351+
}
329352
}
330353

331354
/**

src/types/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ export type RawDocumentAdditionOptions = DocumentOptions & {
218218

219219
export type DocumentsQuery<T = Record<string, any>> = ResourceQuery & {
220220
fields?: Fields<T>
221+
filter?: Filter
221222
}
222223

223224
export type DocumentQuery<T = Record<string, any>> = {
@@ -549,6 +550,12 @@ export const enum ErrorStatusCode {
549550
/** @see https://docs.meilisearch.com/errors/#invalid_document_offset */
550551
INVALID_DOCUMENT_OFFSET = 'invalid_document_offset',
551552

553+
/** @see https://docs.meilisearch.com/errors/#invalid_document_offset */
554+
INVALID_DOCUMENT_FILTER = 'invalid_document_filter',
555+
556+
/** @see https://docs.meilisearch.com/errors/#invalid_document_offset */
557+
MISSING_DOCUMENT_FILTER = 'missing_document_filter',
558+
552559
/** @see https://docs.meilisearch.com/errors/#payload_too_large */
553560
PAYLOAD_TOO_LARGE = 'payload_too_large',
554561

tests/documents.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
getClient,
88
dataset,
99
Book,
10+
getKey,
11+
HOST,
1012
} from './utils/meilisearch-test-utils'
1113

1214
const indexNoPk = {
@@ -140,6 +142,57 @@ describe('Documents tests', () => {
140142
expect(documents.offset).toEqual(2)
141143
})
142144

145+
test(`${permission} key: Get documents with filters`, async () => {
146+
const client = await getClient(permission)
147+
await client.index(indexPk.uid).updateFilterableAttributes(['id'])
148+
const { taskUid } = await client
149+
.index(indexPk.uid)
150+
.addDocuments(dataset)
151+
await client.waitForTask(taskUid)
152+
153+
const documents = await client.index(indexPk.uid).getDocuments<Book>({
154+
filter: [['id = 1', 'id = 2']],
155+
})
156+
157+
expect(documents.results.length).toEqual(2)
158+
})
159+
160+
test(`${permission} key: Get documents should trigger error with a MeilisearchCommunicationError`, async () => {
161+
const apiKey = await getKey(permission)
162+
const client = new MeiliSearch({ host: `${HOST}/indexes`, apiKey })
163+
164+
try {
165+
await client.index(indexPk.uid).getDocuments({ filter: '' })
166+
167+
fail(
168+
'getDocuments should have raised an error when the route does not exist'
169+
)
170+
} catch (e: any) {
171+
expect(e.message).toEqual(
172+
"Not Found\nHint: It might not be working because maybe you're not up to date with the Meilisearch version that getDocuments call requires."
173+
)
174+
}
175+
})
176+
177+
test(`${permission} key: Get documents should trigger error with a hint on a MeilisearchApiError`, async () => {
178+
const apiKey = await getKey(permission)
179+
const client = new MeiliSearch({ host: `${HOST}`, apiKey })
180+
181+
try {
182+
await client.index(indexPk.uid).getDocuments({ filter: 'id = 1' })
183+
184+
fail(
185+
'getDocuments should have raised an error when the filter is badly formatted'
186+
)
187+
} catch (e: any) {
188+
expect(e.message).toEqual(
189+
`Attribute \`id\` is not filterable. This index does not have configured filterable attributes.
190+
1:3 id = 1
191+
Hint: It might not be working because maybe you're not up to date with the Meilisearch version that getDocuments call requires.`
192+
)
193+
}
194+
})
195+
143196
test(`${permission} key: Get documents from index that has NO primary key`, async () => {
144197
const client = await getClient(permission)
145198
const { taskUid } = await client

0 commit comments

Comments
 (0)