Skip to content

Commit 19177f7

Browse files
authored
feat(javascript): add replaceAllObjects (#2768)
1 parent e798e31 commit 19177f7

File tree

4 files changed

+149
-6
lines changed

4 files changed

+149
-6
lines changed

templates/javascript/clients/client/api/helpers.mustache

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ generateSecuredApiKey({
286286
/**
287287
* Helper: Retrieves the remaining validity of the previous generated `secured_api_key`, the `ValidUntil` parameter must have been provided.
288288
*
289-
* @summary Helper: Generates a secured API key based on the given `parentApiKey` and given `restrictions`.
289+
* @summary Helper: Retrieves the remaining validity of the previous generated `secured_api_key`, the `ValidUntil` parameter must have been provided.
290290
* @param getSecuredApiKeyRemainingValidity - The `getSecuredApiKeyRemainingValidity` object.
291291
* @param getSecuredApiKeyRemainingValidity.securedApiKey - The secured API key generated with the `generateSecuredApiKey` method.
292292
*/
@@ -304,4 +304,90 @@ getSecuredApiKeyRemainingValidity({
304304
}
305305

306306
return parseInt(match[1], 10) - Math.round(new Date().getTime() / 1000);
307+
},
308+
309+
/**
310+
* Helper: Chunks the given `objects` list in subset of 1000 elements max in order to make it fit in `batch` requests.
311+
*
312+
* @summary Helper: Chunks the given `objects` list in subset of 1000 elements max in order to make it fit in `batch` requests. * @param getSecuredApiKeyRemainingValidity - The `getSecuredApiKeyRemainingValidity` object.
313+
* @param chunkedBatch - The `chunkedBatch` object.
314+
* @param chunkedBatch.indexName - The `indexName` to replace `objects` in.
315+
* @param chunkedBatch.objects - The array of `objects` to store in the given Algolia `indexName`.
316+
* @param chunkedBatch.action - The `batch` `action` to perform on the given array of `objects`, defaults to `addObject`.
317+
* @param chunkedBatch.waitForTasks - Whether or not we should wait until every `batch` tasks has been processed, this operation may slow the total execution time of this method but is more reliable.
318+
* @param chunkedBatch.batchSize - The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000.
319+
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `getTask` method and merged with the transporter requestOptions.
320+
*/
321+
async chunkedBatch({ indexName, objects, action = 'addObject', waitForTasks, batchSize = 1000 }: ChunkedBatchOptions, requestOptions?: RequestOptions): Promise<Array<BatchResponse>> {
322+
let requests: Array<BatchRequest> = [];
323+
const responses: Array<BatchResponse> = [];
324+
325+
for (const [i, obj] of objects.entries()) {
326+
requests.push({action, body: obj});
327+
if (i % batchSize === 0) {
328+
responses.push(await this.batch({indexName, batchWriteParams: {requests}}, requestOptions));
329+
requests = [];
330+
}
331+
}
332+
333+
if (waitForTasks) {
334+
for (const resp of responses) {
335+
await this.waitForTask({indexName, taskID: resp.taskID});
336+
}
337+
}
338+
339+
return responses;
340+
},
341+
342+
/**
343+
* Helper: Replaces all objects (records) in the given `index_name` with the given `objects`. A temporary index is created during this process in order to backup your data.
344+
*
345+
* @summary Helper: Replaces all objects (records) in the given `index_name` with the given `objects`. A temporary index is created during this process in order to backup your data.
346+
* @param replaceAllObjects - The `replaceAllObjects` object.
347+
* @param replaceAllObjects.indexName - The `indexName` to replace `objects` in.
348+
* @param replaceAllObjects.objects - The array of `objects` to store in the given Algolia `indexName`.
349+
* @param replaceAllObjects.batchSize - The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000.
350+
* @param requestOptions - The requestOptions to send along with the query, they will be forwarded to the `getTask` method and merged with the transporter requestOptions.
351+
*/
352+
async replaceAllObjects(
353+
{ indexName, objects, batchSize }: ReplaceAllObjectsOptions,
354+
requestOptions?: RequestOptions
355+
): Promise<ReplaceAllObjectsResponse> {
356+
const randomSuffix = Math.random().toString(36).substring(7);
357+
const tmpIndexName = `${indexName}_tmp_${randomSuffix}`;
358+
359+
const copyOperationResponse = await this.operationIndex(
360+
{
361+
indexName,
362+
operationIndexParams: {
363+
operation: 'copy',
364+
destination: tmpIndexName,
365+
scope: ['settings', 'rules', 'synonyms'],
366+
},
367+
},
368+
requestOptions
369+
);
370+
await this.waitForTask({
371+
indexName,
372+
taskID: copyOperationResponse.taskID,
373+
});
374+
375+
const batchResponses = await this.chunkedBatch(
376+
{ indexName: tmpIndexName, objects, waitForTasks: true, batchSize },
377+
requestOptions
378+
);
379+
380+
const moveOperationResponse = await this.operationIndex(
381+
{
382+
indexName: tmpIndexName,
383+
operationIndexParams: { operation: 'move', destination: indexName },
384+
},
385+
requestOptions
386+
);
387+
await this.waitForTask({
388+
indexName,
389+
taskID: moveOperationResponse.taskID,
390+
});
391+
392+
return { copyOperationResponse, batchResponses, moveOperationResponse };
307393
},

templates/javascript/clients/client/api/imports.mustache

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ import { {{classname}} } from '{{filename}}';
3131
import type {
3232
{{#isSearchClient}}
3333
BrowseOptions,
34+
ChunkedBatchOptions,
3435
GenerateSecuredApiKeyOptions,
3536
GetSecuredApiKeyRemainingValidityOptions,
37+
ReplaceAllObjectsOptions,
38+
ReplaceAllObjectsResponse,
3639
WaitForApiKeyOptions,
3740
WaitForTaskOptions,
3841
{{/isSearchClient}}
@@ -49,6 +52,10 @@ import type {
4952
} from '../model/clientMethodProps';
5053
{{/operations}}
5154

55+
{{#isSearchClient}}
56+
import type { BatchRequest } from '../model/batchRequest';
57+
{{/isSearchClient}}
58+
5259
{{#isIngestionClient}}
5360
import type { OnDemandTrigger } from '../model/onDemandTrigger';
5461
import type { ScheduleTrigger } from '../model/scheduleTrigger';

templates/javascript/clients/client/model/clientMethodProps.mustache

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import { {{classname}} } from '{{filename}}';
1010
{{#operations}}{{#operation}}{{#vendorExtensions.x-legacy-signature}}{{> client/api/operation/legacySearchCompatible/imports}}{{/vendorExtensions.x-legacy-signature}}{{/operation}}{{/operations}}
1111

1212
{{! Imports for the helpers method of the search client }}
13-
{{#isSearchClient}}import type { CreateIterablePromise } from '{{{npmNamespace}}}/client-common';{{/isSearchClient}}
13+
{{#isSearchClient}}
14+
import type { CreateIterablePromise } from '{{{npmNamespace}}}/client-common';
15+
import type { Action } from './action';
16+
import type { UpdatedAtResponse } from './updatedAtResponse';
17+
{{/isSearchClient}}
1418

1519
{{#operations}}
1620
{{#operation}}
@@ -138,6 +142,52 @@ export type SecuredApiKeyRestrictions = {
138142
139143
searchParams?: SearchParamsObject;
140144
};
145+
146+
export type ChunkedBatchOptions = ReplaceAllObjectsOptions & {
147+
/**
148+
* The `batch` `action` to perform on the given array of `objects`, defaults to `addObject`.
149+
*/
150+
action?: Action;
151+
152+
/**
153+
* Whether or not we should wait until every `batch` tasks has been processed, this operation may slow the total execution time of this method but is more reliable.
154+
*/
155+
waitForTasks?: boolean;
156+
157+
/**
158+
* The size of the chunk of `objects`. The number of `batch` calls will be equal to `length(objects) / batchSize`. Defaults to 1000.
159+
*/
160+
batchSize?: number;
161+
}
162+
163+
export type ReplaceAllObjectsOptions = {
164+
/**
165+
* The `indexName` to replace `objects` in.
166+
*/
167+
indexName: string;
168+
169+
/**
170+
* The array of `objects` to store in the given Algolia `indexName`.
171+
*/
172+
objects: Array<Record<string, any>>;
173+
}
174+
175+
export type ReplaceAllObjectsResponse = {
176+
/**
177+
* The response of the `operationIndex` request for the `copy` operation.
178+
*/
179+
copyOperationResponse: UpdatedAtResponse;
180+
181+
/**
182+
* The response of the `batch` request(s).
183+
*/
184+
batchResponses: BatchResponse[];
185+
186+
/**
187+
* The response of the `operationIndex` request for the `move` operation.
188+
*/
189+
moveOperationResponse: UpdatedAtResponse;
190+
}
141191
{{/isSearchClient}}
142192

143193
{{/apiInfo.apis.0}}

templates/python/search_helpers.mustache

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,9 @@
220220
"""
221221
requests: List[BatchRequest] = []
222222
responses: List[BatchResponse] = []
223-
for j, obj in enumerate(objects):
223+
for i, obj in enumerate(objects):
224224
requests.append(BatchRequest(action=action, body=obj))
225-
if j % 1000 == 0:
225+
if i % 1000 == 0:
226226
responses.append(
227227
await self.batch(
228228
index_name=index_name,
@@ -258,14 +258,14 @@
258258

259259
await self.wait_for_task(index_name=index_name, task_id=copy_resp.task_id)
260260

261-
save_resp = await self.chunked_batch(
261+
save_resps = await self.chunked_batch(
262262
index_name=tmp_index_name,
263263
objects=objects,
264264
wait_for_tasks=True,
265265
request_options=request_options,
266266
)
267267

268-
responses += save_resp
268+
responses += save_resps
269269

270270
move_resp = await self.operation_index(
271271
index_name=tmp_index_name,

0 commit comments

Comments
 (0)