Skip to content

Commit 99c905f

Browse files
authored
Merge pull request #311 from meilisearch/wait_for_pending_update
Wait for pending update and error naming
2 parents 9d25d59 + 3561081 commit 99c905f

7 files changed

+216
-85
lines changed

src/meili-axios-error.ts renamed to src/errors/meilisearch-error.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { AxiosError } from 'axios'
2-
import * as Types from './types'
2+
import * as Types from '../types'
33

4-
const MeiliAxiosError: Types.MeiliAxiosErrorConstructor = class extends Error
5-
implements Types.MeiliAxiosErrorInterface {
6-
response?: Types.MeiliAxiosErrorResponse
7-
request?: Types.MeiliAxiosErrorRequest
4+
const MeiliSearchApiError: Types.MeiliSearchApiErrorConstructor = class
5+
extends Error
6+
implements Types.MeiliSearchApiErrorInterface {
7+
response?: Types.MeiliSearchApiErrorResponse
8+
request?: Types.MeiliSearchApiErrorRequest
9+
type: string
810

911
constructor(error: AxiosError, cachedStack?: string) {
1012
super(error.message)
11-
12-
this.name = 'MeiliSearch Error'
13+
this.type = this.constructor.name
14+
this.name = 'MeiliSearchApiError'
1315

1416
// Fetch the native error message but add our application name in front of it.
1517
// This means slicing the "Error" string at the start of the message.
@@ -40,8 +42,11 @@ const MeiliAxiosError: Types.MeiliAxiosErrorConstructor = class extends Error
4042
}
4143
// use cached Stack on error object to keep the call stack
4244
if (cachedStack && error.stack) {
43-
this.stack = cachedStack
45+
this.stack = `${this.name}: ${this.message}\n${cachedStack
46+
.split('\n')
47+
.slice(1)
48+
.join('\n')}`
4449
}
4550
}
4651
}
47-
export default MeiliAxiosError
52+
export default MeiliSearchApiError
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class MeiliSearchTimeOutError extends Error {
2+
type: string
3+
constructor(message: string) {
4+
super(message)
5+
this.name = 'MeiliSearchTimeOutError'
6+
this.type = this.constructor.name
7+
Error.captureStackTrace(this, MeiliSearchTimeOutError)
8+
}
9+
}
10+
11+
export { MeiliSearchTimeOutError }

src/indexes.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77

88
'use strict'
99

10+
import { MeiliSearchTimeOutError } from './errors/meilisearch-timeout-error'
1011
import MeiliAxiosWrapper from './meili-axios-wrapper'
1112
import * as Types from './types'
13+
import { sleep } from './utils'
1214

13-
class Indexes extends MeiliAxiosWrapper implements Types.Indexes{
15+
class Indexes extends MeiliAxiosWrapper implements Types.Indexes {
1416
indexUid: string
1517
constructor(config: Types.Config, indexUid: string) {
1618
super(config)
@@ -32,6 +34,24 @@ class Indexes extends MeiliAxiosWrapper implements Types.Indexes{
3234
return this.get(url)
3335
}
3436

37+
async waitForPendingUpdate(
38+
updateId: number,
39+
{
40+
timeOutMs = 5000,
41+
intervalMs = 50,
42+
}: { timeOutMs?: number; intervalMs?: number } = {}
43+
) {
44+
const startingTime = Date.now()
45+
while (Date.now() - startingTime < timeOutMs) {
46+
const response = await this.getUpdateStatus(updateId)
47+
if (response.status !== 'enqueued') return response
48+
await sleep(intervalMs)
49+
}
50+
throw new MeiliSearchTimeOutError(
51+
`timeout of ${timeOutMs}ms has exceeded on process ${updateId} when waiting for pending update to resolve.`
52+
)
53+
}
54+
3555
/**
3656
* Get the list of all updates
3757
* @memberof Indexes
@@ -319,7 +339,7 @@ class Indexes extends MeiliAxiosWrapper implements Types.Indexes{
319339
* @memberof Indexes
320340
* @method updateSynonyms
321341
*/
322-
updateSynonyms(synonyms: object): Promise<object> {
342+
updateSynonyms(synonyms: object): Promise<Types.EnqueuedUpdate> {
323343
const url = `/indexes/${this.indexUid}/settings/synonyms`
324344

325345
return this.post(url, synonyms)
@@ -330,7 +350,7 @@ class Indexes extends MeiliAxiosWrapper implements Types.Indexes{
330350
* @memberof Indexes
331351
* @method resetSynonyms
332352
*/
333-
resetSynonyms(): Promise<object> {
353+
resetSynonyms(): Promise<Types.EnqueuedUpdate> {
334354
const url = `/indexes/${this.indexUid}/settings/synonyms`
335355

336356
return this.delete(url)

src/meili-axios-wrapper.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import instance, {
1313
AxiosResponse,
1414
CancelTokenSource,
1515
} from 'axios'
16-
import MeiliAxiosError from './meili-axios-error'
16+
import MeiliSearchApiError from './errors/meilisearch-error'
1717
import * as Types from './types'
1818

1919
class MeiliAxiosWrapper {
@@ -57,7 +57,7 @@ class MeiliAxiosWrapper {
5757
.get(url, config)
5858
.then((response: any) => response)
5959
.catch((e) => {
60-
const meiliError = new MeiliAxiosError(e, cachedStack)
60+
const meiliError = new MeiliSearchApiError(e, cachedStack)
6161
throw meiliError
6262
})
6363
}
@@ -73,7 +73,7 @@ class MeiliAxiosWrapper {
7373
.post(url, data, config)
7474
.then((response: any) => response)
7575
.catch((e) => {
76-
throw new MeiliAxiosError(e, cachedStack)
76+
throw new MeiliSearchApiError(e, cachedStack)
7777
})
7878
}
7979

@@ -88,7 +88,7 @@ class MeiliAxiosWrapper {
8888
.put(url, data, config)
8989
.then((response: any) => response)
9090
.catch((e) => {
91-
const meiliError = new MeiliAxiosError(e, cachedStack)
91+
const meiliError = new MeiliSearchApiError(e, cachedStack)
9292
throw meiliError
9393
})
9494
}
@@ -103,7 +103,7 @@ class MeiliAxiosWrapper {
103103
.patch(url, data, config)
104104
.then((response: any) => response)
105105
.catch((e) => {
106-
const meiliError = new MeiliAxiosError(e, cachedStack)
106+
const meiliError = new MeiliSearchApiError(e, cachedStack)
107107
throw meiliError
108108
})
109109
}
@@ -117,7 +117,7 @@ class MeiliAxiosWrapper {
117117
.delete(url, config)
118118
.then((response: any) => response)
119119
.catch((e) => {
120-
const meiliError = new MeiliAxiosError(e, cachedStack)
120+
const meiliError = new MeiliSearchApiError(e, cachedStack)
121121
throw meiliError
122122
})
123123
}

src/types.ts

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { AxiosError, AxiosInstance, CancelTokenSource, AxiosRequestConfig, AxiosResponse } from 'axios'
1+
import {
2+
AxiosError,
3+
AxiosInstance,
4+
AxiosRequestConfig,
5+
AxiosResponse,
6+
CancelTokenSource,
7+
} from 'axios'
28

39
///
410
/// Global interfaces
@@ -203,127 +209,126 @@ export interface SysInfoPretty {
203209
** MeiliSearch Class
204210
*/
205211

206-
207-
export interface Indexes extends MeiliAxiosWrapper{
208-
indexUid: string;
209-
getUpdateStatus(updateId: number): Promise<Update>;
210-
getAllUpdateStatus(): Promise<Update[]>;
211-
search(query: string, options?: SearchParams): Promise<SearchResponse>;
212-
show(): Promise<Index>;
213-
updateIndex(data: UpdateIndexRequest): Promise<Index>;
214-
deleteIndex(): Promise<string>;
215-
getStats(): Promise<IndexStats>;
216-
getDocuments(options?: GetDocumentsParams): Promise<Document[]>;
217-
getDocument(documentId: string | number): Promise<Document>;
212+
export interface Indexes extends MeiliAxiosWrapper {
213+
indexUid: string
214+
getUpdateStatus(updateId: number): Promise<Update>
215+
getAllUpdateStatus(): Promise<Update[]>
216+
search(query: string, options?: SearchParams): Promise<SearchResponse>
217+
show(): Promise<Index>
218+
updateIndex(data: UpdateIndexRequest): Promise<Index>
219+
deleteIndex(): Promise<string>
220+
getStats(): Promise<IndexStats>
221+
getDocuments(options?: GetDocumentsParams): Promise<Document[]>
222+
getDocument(documentId: string | number): Promise<Document>
218223
addDocuments(
219224
documents: Document[],
220225
options?: AddDocumentParams
221-
): Promise<EnqueuedUpdate>;
226+
): Promise<EnqueuedUpdate>
222227
updateDocuments(
223228
documents: Document[],
224229
options?: AddDocumentParams
225-
): Promise<EnqueuedUpdate>;
226-
deleteDocument(documentId: string | number): Promise<EnqueuedUpdate>;
227-
deleteDocuments(documentsIds: string[] | number[]): Promise<EnqueuedUpdate>;
228-
deleteAllDocuments(): Promise<EnqueuedUpdate>;
229-
getSettings(): Promise<Settings>;
230-
updateSettings(settings: Settings): Promise<EnqueuedUpdate>;
231-
resetSettings(): Promise<EnqueuedUpdate>;
232-
getSynonyms(): Promise<object>;
233-
updateSynonyms(synonyms: object): Promise<object>;
234-
resetSynonyms(): Promise<object>;
235-
getStopWords(): Promise<string[]>;
236-
updateStopWords(stopWords: string[]): Promise<EnqueuedUpdate>;
237-
resetStopWords(): Promise<EnqueuedUpdate>;
238-
getRankingRules(): Promise<string[]>;
239-
updateRankingRules(rankingRules: string[]): Promise<EnqueuedUpdate>;
240-
resetRankingRules(): Promise<EnqueuedUpdate>;
241-
getDistinctAttribute(): Promise<string | void>;
242-
updateDistinctAttribute(distinctAttribute: string): Promise<EnqueuedUpdate>;
243-
resetDistinctAttribute(): Promise<EnqueuedUpdate>;
244-
getSearchableAttributes(): Promise<string[]>;
230+
): Promise<EnqueuedUpdate>
231+
deleteDocument(documentId: string | number): Promise<EnqueuedUpdate>
232+
deleteDocuments(documentsIds: string[] | number[]): Promise<EnqueuedUpdate>
233+
deleteAllDocuments(): Promise<EnqueuedUpdate>
234+
getSettings(): Promise<Settings>
235+
updateSettings(settings: Settings): Promise<EnqueuedUpdate>
236+
resetSettings(): Promise<EnqueuedUpdate>
237+
getSynonyms(): Promise<object>
238+
updateSynonyms(synonyms: object): Promise<object>
239+
resetSynonyms(): Promise<object>
240+
getStopWords(): Promise<string[]>
241+
updateStopWords(stopWords: string[]): Promise<EnqueuedUpdate>
242+
resetStopWords(): Promise<EnqueuedUpdate>
243+
getRankingRules(): Promise<string[]>
244+
updateRankingRules(rankingRules: string[]): Promise<EnqueuedUpdate>
245+
resetRankingRules(): Promise<EnqueuedUpdate>
246+
getDistinctAttribute(): Promise<string | void>
247+
updateDistinctAttribute(distinctAttribute: string): Promise<EnqueuedUpdate>
248+
resetDistinctAttribute(): Promise<EnqueuedUpdate>
249+
getSearchableAttributes(): Promise<string[]>
245250
updateSearchableAttributes(
246251
searchableAttributes: string[]
247-
): Promise<EnqueuedUpdate>;
248-
resetSearchableAttributes(): Promise<EnqueuedUpdate>;
249-
getDisplayedAttributes(): Promise<string[]>;
252+
): Promise<EnqueuedUpdate>
253+
resetSearchableAttributes(): Promise<EnqueuedUpdate>
254+
getDisplayedAttributes(): Promise<string[]>
250255
updateDisplayedAttributes(
251256
displayedAttributes: string[]
252-
): Promise<EnqueuedUpdate>;
253-
resetDisplayedAttributes(): Promise<EnqueuedUpdate>;
254-
getAcceptNewFields(): Promise<boolean>;
255-
updateAcceptNewFields(acceptNewFields: boolean): Promise<EnqueuedUpdate>;
257+
): Promise<EnqueuedUpdate>
258+
resetDisplayedAttributes(): Promise<EnqueuedUpdate>
259+
getAcceptNewFields(): Promise<boolean>
260+
updateAcceptNewFields(acceptNewFields: boolean): Promise<EnqueuedUpdate>
256261
}
257262

258-
export interface Meilisearch extends MeiliAxiosErrorInterface {
259-
config: Config;
260-
getIndex(indexUid: string): Indexes;
261-
listIndexes(): Promise<IndexResponse[]>;
262-
createIndex(data: IndexRequest): Promise<IndexResponse>;
263-
getKeys(): Promise<Keys>;
264-
isHealthy(): Promise<boolean>;
265-
setHealthy(): Promise<void>;
266-
setUnhealthy(): Promise<void>;
267-
changeHealthTo(health: boolean): Promise<void>;
268-
stats(): Promise<Stats>;
269-
version(): Promise<Version>;
270-
sysInfo(): Promise<SysInfo>;
271-
prettySysInfo(): Promise<SysInfoPretty>;
263+
export interface Meilisearch extends MeiliSearchApiErrorInterface {
264+
config: Config
265+
getIndex(indexUid: string): Indexes
266+
listIndexes(): Promise<IndexResponse[]>
267+
createIndex(data: IndexRequest): Promise<IndexResponse>
268+
getKeys(): Promise<Keys>
269+
isHealthy(): Promise<boolean>
270+
setHealthy(): Promise<void>
271+
setUnhealthy(): Promise<void>
272+
changeHealthTo(health: boolean): Promise<void>
273+
stats(): Promise<Stats>
274+
version(): Promise<Version>
275+
sysInfo(): Promise<SysInfo>
276+
prettySysInfo(): Promise<SysInfoPretty>
272277
}
273278

274279
export interface MeiliAxiosWrapper {
275-
instance: AxiosInstance;
276-
cancelTokenSource: CancelTokenSource;
280+
instance: AxiosInstance
281+
cancelTokenSource: CancelTokenSource
277282
get<T = any, R = AxiosResponse<T>>(
278283
url: string,
279284
config?: AxiosRequestConfig
280-
): Promise<R>;
285+
): Promise<R>
281286
post<T = any, R = AxiosResponse<T>>(
282287
url: string,
283288
data?: any,
284289
config?: AxiosRequestConfig
285-
): Promise<R>;
290+
): Promise<R>
286291
put<T = any, R = AxiosResponse<T>>(
287292
url: string,
288293
data?: any,
289294
config?: AxiosRequestConfig
290-
): Promise<R>;
295+
): Promise<R>
291296
patch<T = any, R = AxiosResponse<T>>(
292297
url: string,
293298
data?: any,
294299
config?: AxiosRequestConfig
295-
): Promise<R>;
300+
): Promise<R>
296301
delete<T = any, R = AxiosResponse<T>>(
297302
url: string,
298303
config?: AxiosRequestConfig
299-
): Promise<R>;
304+
): Promise<R>
300305
}
301306

302307
/*
303308
** ERROR HANDLER
304309
*/
305310

306-
export interface MeiliAxiosErrorInterface extends Error {
311+
export interface MeiliSearchApiErrorInterface extends Error {
307312
name: string
308313
message: string
309314
stack?: string
310315
}
311-
export interface MeiliAxiosErrorResponse {
316+
export interface MeiliSearchApiErrorResponse {
312317
status?: number
313318
statusText?: string
314319
path?: string
315320
method?: string
316321
body?: object
317322
}
318-
export interface MeiliAxiosErrorRequest {
323+
export interface MeiliSearchApiErrorRequest {
319324
url?: string
320325
path?: string
321326
method?: string
322327
}
323328

324-
export type MeiliAxiosErrorConstructor = new (
329+
export type MeiliSearchApiErrorConstructor = new (
325330
error: AxiosError,
326331
cachedStack?: string
327332
) => void
328333

329-
export default Indexes;
334+
export default Indexes

src/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function sleep(ms: number) {
2+
return new Promise((resolve) => setTimeout(resolve, ms))
3+
}
4+
5+
export { sleep }

0 commit comments

Comments
 (0)