Skip to content

Commit 8ae2369

Browse files
Merge #1339
1339: Add support to the pagination setting customization at the index level r=bidoubiwa a=vishalsodani # Pull Request ## What does this PR do? Fixes #1298 <!-- Please link the issue you're trying to fix with this PR, if none then please create an issue first. --> ## PR checklist Please check if your PR fulfills the following requirements: - [x] Does this PR fix an existing issue? - [x] Have you read the contributing guidelines? - [x] Have you made sure that the title is accurate and descriptive of the changes? Thank you so much for contributing to Meilisearch! Co-authored-by: vishalsodani <[email protected]> Co-authored-by: Vishal Sodani <[email protected]>
2 parents 3586193 + 61490c7 commit 8ae2369

File tree

5 files changed

+282
-1
lines changed

5 files changed

+282
-1
lines changed

.code-samples.meilisearch.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,9 +550,11 @@ update_sortable_attributes_1: |-
550550
reset_sortable_attributes_1: |-
551551
client.index('books').resetSortableAttributes()
552552
get_pagination_settings_1: |-
553+
client.index('books').getPagination()
553554
update_pagination_settings_1: |-
554555
client.index('books').updateSettings({ pagination: { maxTotalHits: 100 }})
555556
reset_pagination_settings_1: |-
557+
client.index('books').resetPagination()
556558
get_faceting_settings_1: |-
557559
client.index('books').getFaceting()
558560
update_faceting_settings_1: |-
@@ -562,7 +564,7 @@ reset_faceting_settings_1: |-
562564
settings_guide_faceting_1: |-
563565
client.index('movies').updateSettings({ faceting: { maxValuesPerFacet: 5 }})
564566
settings_guide_pagination_1: |-
565-
client.index('books').updateSettings({ pagination: { maxTotalHits: 50 }})
567+
client.index('movies').updateSettings({ pagination: { maxTotalHits: 50 }})
566568
search_parameter_guide_sort_1: |-
567569
client.index('books').search('science fiction', {
568570
sort: ['price:asc'],

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,26 @@ client.index('myIndex').updateSettings(settings: Settings): Promise<EnqueuedTask
591591
client.index('myIndex').resetSettings(): Promise<EnqueuedTask>
592592
```
593593

594+
### Pagination Settings
595+
596+
#### [Get pagination](https://docs.meilisearch.com/reference/api/settings.html#get-pagination-settings)
597+
598+
```ts
599+
client.index('myIndex').getPagination(): Promise<PaginationSettings>
600+
```
601+
602+
#### [Update pagination](https://docs.meilisearch.com/reference/api/settings.html#update-pagination-settings)
603+
604+
```ts
605+
client.index('myIndex').updatePagination(pagination: PaginationSettings): Promise<EnqueuedTask>
606+
```
607+
608+
#### [Reset pagination](https://docs.meilisearch.com/reference/api/settings.html#reset-pagination-settings)
609+
610+
```ts
611+
client.index('myIndex').resetPagination(): Promise<EnqueuedTask>
612+
```
613+
594614
### Synonyms <!-- omit in toc -->
595615

596616
#### [Get synonyms](https://docs.meilisearch.com/reference/api/synonyms.html#get-synonyms)

src/indexes.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
DocumentsResults,
3737
TasksQuery,
3838
TasksResults,
39+
PaginationSettings,
3940
Faceting,
4041
} from './types'
4142
import { removeUndefinedFromObject } from './utils'
@@ -558,6 +559,49 @@ class Index<T = Record<string, any>> {
558559
return task
559560
}
560561

562+
///
563+
/// PAGINATION SETTINGS
564+
///
565+
566+
/**
567+
* Get the pagination settings.
568+
* @memberof Index
569+
* @method getPagination
570+
* @returns {Promise<PaginationSetting>} Promise containing object of pagination settings
571+
*/
572+
async getPagination(): Promise<PaginationSettings> {
573+
const url = `indexes/${this.uid}/settings/pagination`
574+
return await this.httpRequest.get<object>(url)
575+
}
576+
577+
/**
578+
* Update the pagination settings.
579+
* @memberof Index
580+
* @method updatePagination
581+
* @param {PaginationSettings} pagination Pagination object
582+
* @returns {Promise<EnqueuedTask>} Promise containing object of the enqueued task
583+
*/
584+
async updatePagination(
585+
pagination: PaginationSettings
586+
): Promise<EnqueuedTask> {
587+
const url = `indexes/${this.uid}/settings/pagination`
588+
const task = await this.httpRequest.patch(url, pagination)
589+
590+
return new EnqueuedTask(task)
591+
}
592+
593+
/**
594+
* Reset the pagination settings.
595+
* @memberof Index
596+
* @method resetPagination
597+
* @returns {Promise<EnqueuedTask>} Promise containing object of the enqueued task
598+
*/
599+
async resetPagination(): Promise<EnqueuedTask> {
600+
const url = `indexes/${this.uid}/settings/pagination`
601+
const task = await this.httpRequest.delete(url)
602+
603+
return new EnqueuedTask(task)
604+
}
561605
///
562606
/// SYNONYMS
563607
///

tests/pagination.test.ts

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import { ErrorStatusCode } from '../src/types'
2+
import {
3+
clearAllIndexes,
4+
config,
5+
BAD_HOST,
6+
MeiliSearch,
7+
getClient,
8+
dataset,
9+
} from './utils/meilisearch-test-utils'
10+
11+
const index = {
12+
uid: 'movies_test',
13+
}
14+
15+
jest.setTimeout(100 * 1000)
16+
17+
afterAll(() => {
18+
return clearAllIndexes(config)
19+
})
20+
21+
describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
22+
'Test on pagination',
23+
({ permission }) => {
24+
beforeEach(async () => {
25+
await clearAllIndexes(config)
26+
const client = await getClient('Master')
27+
const { taskUid } = await client.index(index.uid).addDocuments(dataset)
28+
await client.waitForTask(taskUid)
29+
})
30+
31+
test(`${permission} key: Get default pagination settings`, async () => {
32+
const client = await getClient(permission)
33+
const response = await client.index(index.uid).getPagination()
34+
35+
expect(response).toEqual({ maxTotalHits: 1000 })
36+
})
37+
38+
test(`${permission} key: Update pagination`, async () => {
39+
const client = await getClient(permission)
40+
const newPagination = {
41+
maxTotalHits: 100,
42+
}
43+
const task = await client.index(index.uid).updatePagination(newPagination)
44+
await client.waitForTask(task.taskUid)
45+
46+
const response = await client.index(index.uid).getPagination()
47+
48+
expect(response).toEqual(newPagination)
49+
})
50+
51+
test(`${permission} key: Update pagination at null`, async () => {
52+
const client = await getClient(permission)
53+
const newPagination = {
54+
maxTotalHits: null,
55+
}
56+
const task = await client.index(index.uid).updatePagination(newPagination)
57+
await client.index(index.uid).waitForTask(task.taskUid)
58+
59+
const response = await client.index(index.uid).getPagination()
60+
61+
expect(response).toEqual({ maxTotalHits: 1000 })
62+
})
63+
64+
test(`${permission} key: Reset pagination`, async () => {
65+
const client = await getClient(permission)
66+
const newPagination = {
67+
maxTotalHits: 100,
68+
}
69+
const updateTask = await client
70+
.index(index.uid)
71+
.updatePagination(newPagination)
72+
await client.waitForTask(updateTask.taskUid)
73+
const task = await client.index(index.uid).resetPagination()
74+
await client.waitForTask(task.taskUid)
75+
76+
const response = await client.index(index.uid).getPagination()
77+
78+
expect(response).toEqual({ maxTotalHits: 1000 })
79+
})
80+
}
81+
)
82+
83+
describe.each([{ permission: 'Public' }])(
84+
'Test on pagination',
85+
({ permission }) => {
86+
beforeEach(async () => {
87+
const client = await getClient('Master')
88+
const { taskUid } = await client.createIndex(index.uid)
89+
await client.waitForTask(taskUid)
90+
})
91+
92+
test(`${permission} key: try to get pagination and be denied`, async () => {
93+
const client = await getClient(permission)
94+
await expect(
95+
client.index(index.uid).getPagination()
96+
).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY)
97+
})
98+
99+
test(`${permission} key: try to update pagination and be denied`, async () => {
100+
const client = await getClient(permission)
101+
await expect(
102+
client.index(index.uid).updatePagination({ maxTotalHits: 10 })
103+
).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY)
104+
})
105+
106+
test(`${permission} key: try to reset pagination and be denied`, async () => {
107+
const client = await getClient(permission)
108+
await expect(
109+
client.index(index.uid).resetPagination()
110+
).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY)
111+
})
112+
}
113+
)
114+
115+
describe.each([{ permission: 'No' }])(
116+
'Test on pagination',
117+
({ permission }) => {
118+
beforeAll(async () => {
119+
const client = await getClient('Master')
120+
const { taskUid } = await client.createIndex(index.uid)
121+
await client.waitForTask(taskUid)
122+
})
123+
124+
test(`${permission} key: try to get pagination and be denied`, async () => {
125+
const client = await getClient(permission)
126+
await expect(
127+
client.index(index.uid).getPagination()
128+
).rejects.toHaveProperty(
129+
'code',
130+
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
131+
)
132+
})
133+
134+
test(`${permission} key: try to update pagination and be denied`, async () => {
135+
const client = await getClient(permission)
136+
await expect(
137+
client.index(index.uid).updatePagination({ maxTotalHits: 10 })
138+
).rejects.toHaveProperty(
139+
'code',
140+
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
141+
)
142+
})
143+
144+
test(`${permission} key: try to reset pagination and be denied`, async () => {
145+
const client = await getClient(permission)
146+
await expect(
147+
client.index(index.uid).resetPagination()
148+
).rejects.toHaveProperty(
149+
'code',
150+
ErrorStatusCode.MISSING_AUTHORIZATION_HEADER
151+
)
152+
})
153+
}
154+
)
155+
156+
describe.each([
157+
{ host: BAD_HOST, trailing: false },
158+
{ host: `${BAD_HOST}/api`, trailing: false },
159+
{ host: `${BAD_HOST}/trailing/`, trailing: true },
160+
])('Tests on url construction', ({ host, trailing }) => {
161+
test(`Test getPagination route`, async () => {
162+
const route = `indexes/${index.uid}/settings/pagination`
163+
const client = new MeiliSearch({ host })
164+
const strippedHost = trailing ? host.slice(0, -1) : host
165+
await expect(
166+
client.index(index.uid).getPagination()
167+
).rejects.toHaveProperty(
168+
'message',
169+
`request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
170+
'http://',
171+
''
172+
)}`
173+
)
174+
})
175+
176+
test(`Test updatePagination route`, async () => {
177+
const route = `indexes/${index.uid}/settings/pagination`
178+
const client = new MeiliSearch({ host })
179+
const strippedHost = trailing ? host.slice(0, -1) : host
180+
await expect(
181+
client.index(index.uid).updatePagination({ maxTotalHits: null })
182+
).rejects.toHaveProperty(
183+
'message',
184+
`request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
185+
'http://',
186+
''
187+
)}`
188+
)
189+
})
190+
191+
test(`Test resetPagination route`, async () => {
192+
const route = `indexes/${index.uid}/settings/pagination`
193+
const client = new MeiliSearch({ host })
194+
const strippedHost = trailing ? host.slice(0, -1) : host
195+
await expect(
196+
client.index(index.uid).resetPagination()
197+
).rejects.toHaveProperty(
198+
'message',
199+
`request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace(
200+
'http://',
201+
''
202+
)}`
203+
)
204+
})
205+
})

tests/settings.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
9696
expect(response).toHaveProperty('stopWords', [])
9797
expect(response).toHaveProperty('synonyms', {})
9898
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
99+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
99100
})
100101

101102
test(`${permission} key: Get default settings of empty index with primary key`, async () => {
@@ -111,6 +112,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
111112
expect(response).toHaveProperty('stopWords', [])
112113
expect(response).toHaveProperty('synonyms', {})
113114
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
115+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
114116
})
115117

116118
test(`${permission} key: Update settings`, async () => {
@@ -174,6 +176,9 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
174176
faceting: {
175177
maxValuesPerFacet: null,
176178
},
179+
pagination: {
180+
maxTotalHits: null,
181+
},
177182
}
178183
// Add the settings
179184
const task = await client.index(index.uid).updateSettings(newSettings)
@@ -210,6 +215,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
210215
expect(response).toHaveProperty('stopWords', newSettings.stopWords)
211216
expect(response).toHaveProperty('synonyms', {})
212217
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
218+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
213219
})
214220

215221
test(`${permission} key: Reset settings`, async () => {
@@ -227,6 +233,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
227233
expect(response).toHaveProperty('stopWords', [])
228234
expect(response).toHaveProperty('synonyms', {})
229235
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
236+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
230237
})
231238

232239
test(`${permission} key: Reset settings of empty index`, async () => {
@@ -243,6 +250,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
243250
expect(response).toHaveProperty('stopWords', [])
244251
expect(response).toHaveProperty('synonyms', {})
245252
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
253+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
246254
})
247255

248256
test(`${permission} key: Update searchableAttributes settings on empty index`, async () => {
@@ -268,6 +276,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
268276
expect(response).toHaveProperty('stopWords', defaultSettings.stopWords)
269277
expect(response).toHaveProperty('synonyms', {})
270278
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
279+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
271280
})
272281

273282
test(`${permission} key: Update searchableAttributes settings on empty index with a primary key`, async () => {
@@ -303,6 +312,7 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])(
303312
expect(response).toHaveProperty('stopWords', defaultSettings.stopWords)
304313
expect(response).toHaveProperty('synonyms', {})
305314
expect(response).toHaveProperty('faceting', { maxValuesPerFacet: 100 })
315+
expect(response).toHaveProperty('pagination', { maxTotalHits: 1000 })
306316
})
307317
}
308318
)

0 commit comments

Comments
 (0)