diff --git a/README.md b/README.md index 0acbe8747..0e08568da 100644 --- a/README.md +++ b/README.md @@ -565,6 +565,20 @@ client.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }) client.index('myIndex').waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise ``` +### Batches + +#### [Get one batch](https://www.meilisearch.com/docs/reference/api/batches#get-one-batch) + +```ts +client.getBatch(uid: number): Promise +``` + +#### [Get all batches](https://www.meilisearch.com/docs/reference/api/batchess#get-batches) + +```ts +client.getBatches(parameters: BatchesQuery = {}): Promise +``` + ### Indexes #### [Get all indexes in Index instances](https://www.meilisearch.com/docs/reference/api/indexes#list-all-indexes) diff --git a/src/batch.ts b/src/batch.ts new file mode 100644 index 000000000..dafc23e1d --- /dev/null +++ b/src/batch.ts @@ -0,0 +1,68 @@ +import { + Config, + BatchObject, + BatchesQuery, + BatchesResults, + BatchesResultsObject, +} from "./types"; +import { HttpRequests, toQueryParams } from "./http-requests"; + +class Batch { + uid: BatchObject["uid"]; + details: BatchObject["details"]; + stats: BatchObject["stats"]; + startedAt: BatchObject["startedAt"]; + finishedAt: BatchObject["finishedAt"]; + duration: BatchObject["duration"]; + + constructor(batch: BatchObject) { + this.uid = batch.uid; + this.details = batch.details; + this.stats = batch.stats; + this.startedAt = batch.startedAt; + this.finishedAt = batch.finishedAt; + this.duration = batch.duration; + } +} + +class BatchClient { + httpRequest: HttpRequests; + + constructor(config: Config) { + this.httpRequest = new HttpRequests(config); + } + + /** + * Get one batch + * + * @param uid - Unique identifier of the batch + * @returns + */ + async getBatch(uid: number): Promise { + const url = `batches/${uid}`; + const batch = await this.httpRequest.get(url); + return new Batch(batch); + } + + /** + * Get batches + * + * @param parameters - Parameters to browse the batches + * @returns Promise containing all batches + */ + async getBatches(parameters: BatchesQuery = {}): Promise { + const url = `batches`; + + const batches = await this.httpRequest.get>( + url, + toQueryParams(parameters), + ); + + return { + ...batches, + results: batches.results.map((batch) => new Batch(batch)), + }; + } +} + +export { BatchClient, Batch }; diff --git a/src/meilisearch.ts b/src/meilisearch.ts index be82720d5..e3510c222 100644 --- a/src/meilisearch.ts +++ b/src/meilisearch.ts @@ -30,16 +30,20 @@ import { DeleteTasksQuery, MultiSearchParams, FederatedMultiSearchParams, + BatchesResults, + BatchesQuery, MultiSearchResponseOrSearchResponse, } from "./types"; import { HttpRequests } from "./http-requests"; import { TaskClient, Task } from "./task"; import { EnqueuedTask } from "./enqueued-task"; +import { Batch, BatchClient } from "./batch"; export class MeiliSearch { config: Config; httpRequest: HttpRequests; tasks: TaskClient; + batches: BatchClient; /** * Creates new MeiliSearch instance @@ -50,6 +54,7 @@ export class MeiliSearch { this.config = config; this.httpRequest = new HttpRequests(config); this.tasks = new TaskClient(config); + this.batches = new BatchClient(config); } /** @@ -303,6 +308,26 @@ export class MeiliSearch { return await this.tasks.deleteTasks(parameters); } + /** + * Get all the batches + * + * @param parameters - Parameters to browse the batches + * @returns Promise returning all batches + */ + async getBatches(parameters: BatchesQuery = {}): Promise { + return await this.batches.getBatches(parameters); + } + + /** + * Get one batch + * + * @param uid - Batch identifier + * @returns Promise returning a batch + */ + async getBatch(uid: number): Promise { + return await this.batches.getBatch(uid); + } + /// /// KEYS /// diff --git a/src/task.ts b/src/task.ts index de3388add..883524918 100644 --- a/src/task.ts +++ b/src/task.ts @@ -19,6 +19,7 @@ class Task { status: TaskObject["status"]; type: TaskObject["type"]; uid: TaskObject["uid"]; + batchUid: TaskObject["batchUid"]; canceledBy: TaskObject["canceledBy"]; details: TaskObject["details"]; error: TaskObject["error"]; @@ -32,6 +33,7 @@ class Task { this.status = task.status; this.type = task.type; this.uid = task.uid; + this.batchUid = task.batchUid; this.details = task.details; this.canceledBy = task.canceledBy; this.error = task.error; diff --git a/src/types/types.ts b/src/types/types.ts index 3c06b5762..f356c4f51 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -5,6 +5,7 @@ // TypeScript Version: ^3.8.3 import { Task } from "../task"; +import { Batch } from "../batch"; export type Config = { host: string; @@ -578,6 +579,8 @@ export type EnqueuedTaskObject = { export type TaskObject = Omit & { uid: number; + /** The UID of the batch that the task belongs to (`null` for enqueued tasks) */ + batchUid: number | null; details: { // Number of documents sent receivedDocuments?: number; @@ -659,6 +662,83 @@ export type WaitOptions = { intervalMs?: number; }; +/* + ** BATCHES + */ + +/** + * Represents a batch operation object containing information about tasks + * processing + */ +export type BatchObject = { + /** Unique identifier for the batch */ + uid: number; + + /** Details about document processing */ + details: { + /** Number of documents received in the batch */ + receivedDocuments?: number; + /** Number of documents successfully indexed */ + indexedDocuments?: number; + /** Number of documents deleted in the batch */ + deletedDocuments?: number; + }; + + /** Progress indicator (currently always null) */ + progress: null; + + /** Statistics about tasks within the batch */ + stats: { + /** Total number of tasks in the batch */ + totalNbTasks: number; + /** Count of tasks in each status */ + status: { + /** Number of successfully completed tasks */ + succeeded: number; + /** Number of failed tasks */ + failed: number; + /** Number of canceled tasks */ + canceled: number; + /** Number of tasks currently processing */ + processing: number; + /** Number of tasks waiting to be processed */ + enqueued: number; + }; + /** Count of tasks by type */ + types: Record; + /** Count of tasks by index UID */ + indexUids: Record; + }; + + /** Timestamp when the batch started processing (rfc3339 format) */ + startedAt: string; + /** Timestamp when the batch finished processing (rfc3339 format) */ + finishedAt: string; + /** Duration of batch processing */ + duration: string; +}; + +export type BatchesQuery = { + /** The batch should contain the specified task UIDs */ + uids?: number[]; + batchUids?: number[]; + types?: TaskTypes[]; + statuses?: TaskStatus[]; + indexUids?: string[]; + canceledBy?: number[]; + beforeEnqueuedAt?: Date; + afterEnqueuedAt?: Date; + beforeStartedAt?: Date; + afterStartedAt?: Date; + beforeFinishedAt?: Date; + afterFinishedAt?: Date; + limit?: number; + from?: number; +}; + +export type BatchesResults = CursorResults; +export type BatchesResultsObject = CursorResults; + /* *** HEALTH */ diff --git a/tests/batch.test.ts b/tests/batch.test.ts new file mode 100644 index 000000000..d3c149bf6 --- /dev/null +++ b/tests/batch.test.ts @@ -0,0 +1,47 @@ +import { afterAll, beforeEach, describe, expect, test } from "vitest"; +import { + config, + getClient, + clearAllIndexes, +} from "./utils/meilisearch-test-utils"; + +const index = { + uid: "batch-test", +}; + +afterAll(() => { + return clearAllIndexes(config); +}); + +describe.each([{ permission: "Master" }, { permission: "Admin" }])( + "Tests on batches", + ({ permission }) => { + beforeEach(async () => { + const client = await getClient("Master"); + const { taskUid } = await client.createIndex(index.uid); + await client.waitForTask(taskUid); + }); + + test(`${permission} key: Get all batches`, async () => { + const client = await getClient(permission); + const batches = await client.getBatches(); + expect(batches.results.length).toBeGreaterThan(0); + }); + + test(`${permission} key: Get one batch`, async () => { + const client = await getClient(permission); + + const batches = await client.getBatches(); + const batch = await client.getBatch(batches.results[0].uid); + expect(batch.uid).toEqual(batches.results[0].uid); + expect(batch.details).toBeDefined(); + expect(batch.stats).toHaveProperty("totalNbTasks"); + expect(batch.stats).toHaveProperty("status"); + expect(batch.stats).toHaveProperty("types"); + expect(batch.stats).toHaveProperty("indexUids"); + expect(batch.duration).toBeDefined(); + expect(batch.startedAt).toBeDefined(); + expect(batch.finishedAt).toBeDefined(); + }); + }, +); diff --git a/tests/task.test.ts b/tests/task.test.ts index 57cf700f3..1e0bfa126 100644 --- a/tests/task.test.ts +++ b/tests/task.test.ts @@ -56,6 +56,7 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])( const task = await client.getTask(enqueuedTask.taskUid); expect(task.indexUid).toEqual(index.uid); + expect(task.batchUid).toBeDefined(); expect(task.status).toEqual(TaskStatus.TASK_SUCCEEDED); expect(task.type).toEqual(TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE); expect(task.uid).toEqual(enqueuedTask.taskUid);